fluid_sys.c
上传用户:tjmskj2
上传日期:2020-08-17
资源大小:577k
文件大小:27k
源码类别:

midi

开发平台:

C/C++

  1. /* FluidSynth - A Software Synthesizer
  2.  *
  3.  * Copyright (C) 2003  Peter Hanappe and others.
  4.  *
  5.  * This library is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU Library General Public License
  7.  * as published by the Free Software Foundation; either version 2 of
  8.  * the License, or (at your option) any later version.
  9.  *
  10.  * This library is distributed in the hope that it will be useful, but
  11.  * WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.  * Library General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU Library General Public
  16.  * License along with this library; if not, write to the Free
  17.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  18.  * 02111-1307, USA
  19.  */
  20. #include "fluid_sys.h"
  21. #if WITH_READLINE
  22. #include <readline/readline.h>
  23. #include <readline/history.h>
  24. #endif
  25. /* WIN32 HACK - Flag used to differentiate between a file descriptor and a socket.
  26.  * Should work, so long as no SOCKET or file descriptor ends up with this bit set. - JG */
  27. #define WIN32_SOCKET_FLAG       0x40000000
  28. /* SCHED_FIFO priority for high priority timer threads */
  29. #define FLUID_SYS_TIMER_HIGH_PRIO_LEVEL         10
  30. typedef struct
  31. {
  32.   fluid_thread_func_t func;
  33.   void *data;
  34.   int prio_level;
  35. } fluid_thread_info_t;
  36. struct _fluid_timer_t
  37. {
  38.   long msec;
  39.   fluid_timer_callback_t callback;
  40.   void *data;
  41.   fluid_thread_t *thread;
  42.   int cont;
  43.   int auto_destroy;
  44. };
  45. struct _fluid_server_socket_t
  46. {
  47.   fluid_socket_t socket;
  48.   fluid_thread_t *thread;
  49.   int cont;
  50.   fluid_server_func_t func;
  51.   void *data;
  52. };
  53. static int fluid_istream_gets(fluid_istream_t in, char* buf, int len);
  54. static char fluid_errbuf[512];  /* buffer for error message */
  55. static fluid_log_function_t fluid_log_function[LAST_LOG_LEVEL];
  56. static void* fluid_log_user_data[LAST_LOG_LEVEL];
  57. static int fluid_log_initialized = 0;
  58. static char* fluid_libname = "fluidsynth";
  59. void fluid_sys_config()
  60. {
  61.   fluid_log_config();
  62. }
  63. unsigned int fluid_debug_flags = 0;
  64. #if DEBUG
  65. /*
  66.  * fluid_debug
  67.  */
  68. int fluid_debug(int level, char * fmt, ...)
  69. {
  70.   if (fluid_debug_flags & level) {
  71.     fluid_log_function_t fun;
  72.     va_list args;
  73.     va_start (args, fmt);
  74.     vsnprintf(fluid_errbuf, sizeof (fluid_errbuf), fmt, args);
  75.     va_end (args);
  76.     fun = fluid_log_function[FLUID_DBG];
  77.     if (fun != NULL) {
  78.       (*fun)(level, fluid_errbuf, fluid_log_user_data[FLUID_DBG]);
  79.     }
  80.   }
  81.   return 0;
  82. }
  83. #endif
  84. /**
  85.  * Installs a new log function for a specified log level.
  86.  * @param level Log level to install handler for.
  87.  * @param fun Callback function handler to call for logged messages
  88.  * @param data User supplied data pointer to pass to log function
  89.  * @return The previously installed function.
  90.  */
  91. fluid_log_function_t
  92. fluid_set_log_function(int level, fluid_log_function_t fun, void* data)
  93. {
  94.   fluid_log_function_t old = NULL;
  95.   if ((level >= 0) && (level < LAST_LOG_LEVEL)) {
  96.     old = fluid_log_function[level];
  97.     fluid_log_function[level] = fun;
  98.     fluid_log_user_data[level] = data;
  99.   }
  100.   return old;
  101. }
  102. /**
  103.  * Default log function which prints to the stderr.
  104.  * @param level Log level
  105.  * @param message Log message
  106.  * @param data User supplied data (not used)
  107.  */
  108. void
  109. fluid_default_log_function(int level, char* message, void* data)
  110. {
  111.   FILE* out;
  112. #if defined(WIN32)
  113.   out = stdout;
  114. #else
  115.   out = stderr;
  116. #endif
  117.   if (fluid_log_initialized == 0) {
  118.     fluid_log_config();
  119.   }
  120.   switch (level) {
  121.   case FLUID_PANIC:
  122.     FLUID_FPRINTF(out, "%s: panic: %sn", fluid_libname, message);
  123.     break;
  124.   case FLUID_ERR:
  125.     FLUID_FPRINTF(out, "%s: error: %sn", fluid_libname, message);
  126.     break;
  127.   case FLUID_WARN:
  128.     FLUID_FPRINTF(out, "%s: warning: %sn", fluid_libname, message);
  129.     break;
  130.   case FLUID_INFO:
  131.     FLUID_FPRINTF(out, "%s: %sn", fluid_libname, message);
  132.     break;
  133.   case FLUID_DBG:
  134. #if DEBUG
  135.     FLUID_FPRINTF(out, "%s: debug: %sn", fluid_libname, message);
  136. #endif
  137.     break;
  138.   default:
  139.     FLUID_FPRINTF(out, "%s: %sn", fluid_libname, message);
  140.     break;
  141.   }
  142.   fflush(out);
  143. }
  144. /*
  145.  * fluid_init_log
  146.  */
  147. void
  148. fluid_log_config(void)
  149. {
  150.   if (fluid_log_initialized == 0) {
  151.     fluid_log_initialized = 1;
  152.     if (fluid_log_function[FLUID_PANIC] == NULL) {
  153.       fluid_set_log_function(FLUID_PANIC, fluid_default_log_function, NULL);
  154.     }
  155.     if (fluid_log_function[FLUID_ERR] == NULL) {
  156.       fluid_set_log_function(FLUID_ERR, fluid_default_log_function, NULL);
  157.     }
  158.     if (fluid_log_function[FLUID_WARN] == NULL) {
  159.       fluid_set_log_function(FLUID_WARN, fluid_default_log_function, NULL);
  160.     }
  161.     if (fluid_log_function[FLUID_INFO] == NULL) {
  162.       fluid_set_log_function(FLUID_INFO, fluid_default_log_function, NULL);
  163.     }
  164.     if (fluid_log_function[FLUID_DBG] == NULL) {
  165.       fluid_set_log_function(FLUID_DBG, fluid_default_log_function, NULL);
  166.     }
  167.   }
  168. }
  169. /**
  170.  * Print a message to the log.
  171.  * @param level Log level (#fluid_log_level).
  172.  * @param fmt Printf style format string for log message
  173.  * @param ... Arguments for printf 'fmt' message string
  174.  * @return Always returns #FLUID_FAILED
  175.  */
  176. int
  177. fluid_log(int level, const char* fmt, ...)
  178. {
  179.   fluid_log_function_t fun = NULL;
  180.   va_list args;
  181.   va_start (args, fmt);
  182.   vsnprintf(fluid_errbuf, sizeof (fluid_errbuf), fmt, args);
  183.   va_end (args);
  184.   if ((level >= 0) && (level < LAST_LOG_LEVEL)) {
  185.     fun = fluid_log_function[level];
  186.     if (fun != NULL) {
  187.       (*fun)(level, fluid_errbuf, fluid_log_user_data[level]);
  188.     }
  189.   }
  190.   return FLUID_FAILED;
  191. }
  192. /**
  193.  * An improved strtok, still trashes the input string, but is portable and
  194.  * thread safe.  Also skips token chars at beginning of token string and never
  195.  * returns an empty token (will return NULL if source ends in token chars though).
  196.  * NOTE: NOT part of public API
  197.  * @internal
  198.  * @param str Pointer to a string pointer of source to tokenize.  Pointer gets
  199.  *   updated on each invocation to point to beginning of next token.  Note that
  200.  *   token char get's overwritten with a 0 byte.  String pointer is set to NULL
  201.  *   when final token is returned.
  202.  * @param delim String of delimiter chars.
  203.  * @return Pointer to the next token or NULL if no more tokens.
  204.  */
  205. char *fluid_strtok (char **str, char *delim)
  206. {
  207.   char *s, *d, *token;
  208.   char c;
  209.   if (str == NULL || delim == NULL || !*delim)
  210.   {
  211.     FLUID_LOG(FLUID_ERR, "Null pointer");
  212.     return NULL;
  213.   }
  214.   s = *str;
  215.   if (!s) return NULL; /* str points to a NULL pointer? (tokenize already ended) */
  216.   /* skip delimiter chars at beginning of token */
  217.   do
  218.   {
  219.     c = *s;
  220.     if (!c) /* end of source string? */
  221.     {
  222.       *str = NULL;
  223.       return NULL;
  224.     }
  225.     for (d = delim; *d; d++) /* is source char a token char? */
  226.     {
  227.       if (c == *d) /* token char match? */
  228.       {
  229. s++; /* advance to next source char */
  230. break;
  231.       }
  232.     }
  233.   } while (*d); /* while token char match */
  234.   token = s; /* start of token found */
  235.   /* search for next token char or end of source string */
  236.   for (s = s+1; *s; s++)
  237.   {
  238.     c = *s;
  239.     for (d = delim; *d; d++) /* is source char a token char? */
  240.     {
  241.       if (c == *d) /* token char match? */
  242.       {
  243. *s = ''; /* overwrite token char with zero byte to terminate token */
  244. *str = s+1; /* update str to point to beginning of next token */
  245. return token;
  246.       }
  247.     }
  248.   }
  249.   /* we get here only if source string ended */
  250.   *str = NULL;
  251.   return token;
  252. }
  253. /*
  254.  * fluid_error
  255.  */
  256. char*
  257. fluid_error()
  258. {
  259.   return fluid_errbuf;
  260. }
  261. /**
  262.  * Check if a file is a MIDI file.
  263.  * @param filename Path to the file to check
  264.  * @return TRUE if it could be a MIDI file, FALSE otherwise
  265.  *
  266.  * The current implementation only checks for the "MThd" header in the file.
  267.  * It is useful only to distinguish between SoundFont and MIDI files.
  268.  */
  269. int
  270. fluid_is_midifile(const char *filename)
  271. {
  272.   FILE* fp = fopen(filename, "rb");
  273.   char id[4];
  274.   if (fp == NULL) {
  275.     return 0;
  276.   }
  277.   if (fread((void*) id, 1, 4, fp) != 4) {
  278.     fclose(fp);
  279.     return 0;
  280.   }
  281.   fclose(fp);
  282.   return strncmp(id, "MThd", 4) == 0;
  283. }
  284. /**
  285.  * Check if a file is a SoundFont file.
  286.  * @param filename Path to the file to check
  287.  * @return TRUE if it could be a SoundFont, FALSE otherwise
  288.  *
  289.  * The current implementation only checks for the "RIFF" header in the file.
  290.  * It is useful only to distinguish between SoundFont and MIDI files.
  291.  */
  292. int
  293. fluid_is_soundfont(const char *filename)
  294. {
  295.   FILE* fp = fopen(filename, "rb");
  296.   char id[4];
  297.   if (fp == NULL) {
  298.     return 0;
  299.   }
  300.   if (fread((void*) id, 1, 4, fp) != 4) {
  301.     fclose(fp);
  302.     return 0;
  303.   }
  304.   fclose(fp);
  305.   return strncmp(id, "RIFF", 4) == 0;
  306. }
  307. /**
  308.  * Get time in milliseconds to be used in relative timing operations.
  309.  * @return Unix time in milliseconds.
  310.  */
  311. unsigned int fluid_curtime(void)
  312. {
  313.   GTimeVal timeval;
  314.   g_get_current_time (&timeval);
  315.   return (timeval.tv_sec * 1000.0 + timeval.tv_usec / 1000.0);
  316. }
  317. /**
  318.  * Get time in microseconds to be used in relative timing operations.
  319.  * @return Unix time in microseconds.
  320.  */
  321. double
  322. fluid_utime (void)
  323. {
  324.   GTimeVal timeval;
  325.   g_get_current_time (&timeval);
  326.   return (timeval.tv_sec * 1000000.0 + timeval.tv_usec);
  327. }
  328. #if defined(WIN32)      /* Windoze specific stuff */
  329. void
  330. fluid_thread_self_set_prio (int prio_level)
  331. {
  332.   if (prio_level > 0)
  333.     SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
  334. }
  335. #elif defined(__OS2__)  /* OS/2 specific stuff */
  336. void
  337. fluid_thread_self_set_prio (int prio_level)
  338. {
  339.   if (prio_level > 0)
  340.     DosSetPriority (PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0);
  341. }
  342. #else   /* POSIX stuff..  Nice POSIX..  Good POSIX. */
  343. void
  344. fluid_thread_self_set_prio (int prio_level)
  345. {
  346.   struct sched_param priority;
  347.   if (prio_level > 0)
  348.   {
  349.     priority.sched_priority = prio_level;
  350.     if (pthread_setschedparam (pthread_self (), SCHED_FIFO, &priority) != 0)
  351.       FLUID_LOG(FLUID_WARN, "Failed to set thread to high priority");
  352.   }
  353. }
  354. #ifdef FPE_CHECK
  355. /***************************************************************
  356.  *
  357.  *               Floating point exceptions
  358.  *
  359.  *  The floating point exception functions were taken from Ircam's
  360.  *  jMax source code. http://www.ircam.fr/jmax
  361.  *
  362.  *  FIXME: check in config for i386 machine
  363.  *
  364.  *  Currently not used. I leave the code here in case we want to pick
  365.  *  this up again some time later.
  366.  */
  367. /* Exception flags */
  368. #define _FPU_STATUS_IE    0x001  /* Invalid Operation */
  369. #define _FPU_STATUS_DE    0x002  /* Denormalized Operand */
  370. #define _FPU_STATUS_ZE    0x004  /* Zero Divide */
  371. #define _FPU_STATUS_OE    0x008  /* Overflow */
  372. #define _FPU_STATUS_UE    0x010  /* Underflow */
  373. #define _FPU_STATUS_PE    0x020  /* Precision */
  374. #define _FPU_STATUS_SF    0x040  /* Stack Fault */
  375. #define _FPU_STATUS_ES    0x080  /* Error Summary Status */
  376. /* Macros for accessing the FPU status word.  */
  377. /* get the FPU status */
  378. #define _FPU_GET_SW(sw) __asm__ ("fnstsw %0" : "=m" (*&sw))
  379. /* clear the FPU status */
  380. #define _FPU_CLR_SW() __asm__ ("fnclex" : : )
  381. /* Purpose:
  382.  * Checks, if the floating point unit has produced an exception, print a message
  383.  * if so and clear the exception.
  384.  */
  385. unsigned int fluid_check_fpe_i386(char* explanation)
  386. {
  387.   unsigned int s;
  388.   _FPU_GET_SW(s);
  389.   _FPU_CLR_SW();
  390.   s &= _FPU_STATUS_IE | _FPU_STATUS_DE | _FPU_STATUS_ZE | _FPU_STATUS_OE | _FPU_STATUS_UE;
  391.   if (s)
  392.   {
  393.       FLUID_LOG(FLUID_WARN, "FPE exception (before or in %s): %s%s%s%s%s", explanation,
  394.        (s & _FPU_STATUS_IE) ? "Invalid operation " : "",
  395.        (s & _FPU_STATUS_DE) ? "Denormal number " : "",
  396.        (s & _FPU_STATUS_ZE) ? "Zero divide " : "",
  397.        (s & _FPU_STATUS_OE) ? "Overflow " : "",
  398.        (s & _FPU_STATUS_UE) ? "Underflow " : "");
  399.   }
  400.   return s;
  401. }
  402. /* Purpose:
  403.  * Clear floating point exception.
  404.  */
  405. void fluid_clear_fpe_i386 (void)
  406. {
  407.   _FPU_CLR_SW();
  408. }
  409. #endif // ifdef FPE_CHECK
  410. #endif // #else    (its POSIX)
  411. /***************************************************************
  412.  *
  413.  *               Profiling (Linux, i586 only)
  414.  *
  415.  */
  416. #if WITH_PROFILING
  417. fluid_profile_data_t fluid_profile_data[] =
  418. {
  419.   { FLUID_PROF_WRITE_S16,        "fluid_synth_write_s16           ", 1e10, 0.0, 0.0, 0},
  420.   { FLUID_PROF_ONE_BLOCK,        "fluid_synth_one_block           ", 1e10, 0.0, 0.0, 0},
  421.   { FLUID_PROF_ONE_BLOCK_CLEAR,  "fluid_synth_one_block:clear     ", 1e10, 0.0, 0.0, 0},
  422.   { FLUID_PROF_ONE_BLOCK_VOICE,  "fluid_synth_one_block:one voice ", 1e10, 0.0, 0.0, 0},
  423.   { FLUID_PROF_ONE_BLOCK_VOICES, "fluid_synth_one_block:all voices", 1e10, 0.0, 0.0, 0},
  424.   { FLUID_PROF_ONE_BLOCK_REVERB, "fluid_synth_one_block:reverb    ", 1e10, 0.0, 0.0, 0},
  425.   { FLUID_PROF_ONE_BLOCK_CHORUS, "fluid_synth_one_block:chorus    ", 1e10, 0.0, 0.0, 0},
  426.   { FLUID_PROF_VOICE_NOTE,       "fluid_voice:note                ", 1e10, 0.0, 0.0, 0},
  427.   { FLUID_PROF_VOICE_RELEASE,    "fluid_voice:release             ", 1e10, 0.0, 0.0, 0},
  428.   { FLUID_PROF_LAST, "last", 1e100, 0.0, 0.0, 0}
  429. };
  430. void fluid_profiling_print(void)
  431. {
  432.   int i;
  433.   printf("fluid_profiling_printn");
  434.   FLUID_LOG(FLUID_INFO, "Estimated times: min/avg/max (micro seconds)");
  435.   for (i = 0; i < FLUID_PROF_LAST; i++) {
  436.     if (fluid_profile_data[i].count > 0) {
  437.       FLUID_LOG(FLUID_INFO, "%s: %.3f/%.3f/%.3f",
  438.        fluid_profile_data[i].description,
  439.        fluid_profile_data[i].min,
  440.        fluid_profile_data[i].total / fluid_profile_data[i].count,
  441.        fluid_profile_data[i].max);
  442.     } else {
  443.       FLUID_LOG(FLUID_DBG, "%s: no profiling available", fluid_profile_data[i].description);
  444.     }
  445.   }
  446. }
  447. #endif /* WITH_PROFILING */
  448. /***************************************************************
  449.  *
  450.  *               Threads
  451.  *
  452.  */
  453. /* Rather than inline this one, we just declare it as a function, to prevent
  454.  * GCC warning about inline failure. */
  455. fluid_cond_t *
  456. new_fluid_cond (void)
  457. {
  458.   if (!g_thread_supported ()) g_thread_init (NULL);
  459.   return g_cond_new ();
  460. }
  461. static gpointer
  462. fluid_thread_high_prio (gpointer data)
  463. {
  464.   fluid_thread_info_t *info = data;
  465.   fluid_thread_self_set_prio (info->prio_level);
  466.   info->func (info->data);
  467.   FLUID_FREE (info);
  468.   return NULL;
  469. }
  470. /**
  471.  * Create a new thread.
  472.  * @param func Function to execute in new thread context
  473.  * @param data User defined data to pass to func
  474.  * @param prio_level Priority level.  If greater than 0 then high priority scheduling will
  475.  *   be used, with the given priority level (used by pthreads only).  0 uses normal scheduling.
  476.  * @param detach If TRUE, 'join' does not work and the thread destroys itself when finished.
  477.  * @return New thread pointer or NULL on error
  478.  */
  479. fluid_thread_t *
  480. new_fluid_thread (fluid_thread_func_t func, void *data, int prio_level, int detach)
  481. {
  482.   GThread *thread;
  483.   fluid_thread_info_t *info;
  484.   GError *err = NULL;
  485.   g_return_val_if_fail (func != NULL, NULL);
  486.   /* Make sure g_thread_init has been called.
  487.    * FIXME - Probably not a good idea in a shared library,
  488.    * but what can we do *and* remain backwards compatible? */
  489.   if (!g_thread_supported ()) g_thread_init (NULL);
  490.   if (prio_level > 0)
  491.   {
  492.     info = FLUID_NEW (fluid_thread_info_t);
  493.     if (!info)
  494.     {
  495.       FLUID_LOG(FLUID_ERR, "Out of memory");
  496.       return NULL;
  497.     }
  498.     info->func = func;
  499.     info->data = data;
  500.     info->prio_level = prio_level;
  501.     thread = g_thread_create (fluid_thread_high_prio, info, detach == FALSE, &err);
  502.   }
  503.   else thread = g_thread_create ((GThreadFunc)func, data, detach == FALSE, &err);
  504.   if (!thread)
  505.   {
  506.     FLUID_LOG(FLUID_ERR, "Failed to create the thread: %s",
  507.               fluid_gerror_message (err));
  508.     g_clear_error (&err);
  509.   }
  510.   return thread;
  511. }
  512. /**
  513.  * Frees data associated with a thread (does not actually stop thread).
  514.  * @param thread Thread to free
  515.  */
  516. void
  517. delete_fluid_thread(fluid_thread_t* thread)
  518. {
  519.   /* Threads free themselves when they quit, nothing to do */
  520. }
  521. /**
  522.  * Join a thread (wait for it to terminate).
  523.  * @param thread Thread to join
  524.  * @return FLUID_OK
  525.  */
  526. int
  527. fluid_thread_join(fluid_thread_t* thread)
  528. {
  529.   g_thread_join (thread);
  530.   return FLUID_OK;
  531. }
  532. void
  533. fluid_timer_run (void *data)
  534. {
  535.   fluid_timer_t *timer;
  536.   int count = 0;
  537.   int cont;
  538.   long start;
  539.   long delay;
  540.   timer = (fluid_timer_t *)data;
  541.   /* keep track of the start time for absolute positioning */
  542.   start = fluid_curtime ();
  543.   while (timer->cont)
  544.   {
  545.     cont = (*timer->callback)(timer->data, fluid_curtime() - start);
  546.     count++;
  547.     if (!cont) break;
  548.     /* to avoid incremental time errors, calculate the delay between
  549.        two callbacks bringing in the "absolute" time (count *
  550.        timer->msec) */
  551.     delay = (count * timer->msec) - (fluid_curtime() - start);
  552.     if (delay > 0) g_usleep (delay * 1000);
  553.   }
  554.   FLUID_LOG (FLUID_DBG, "Timer thread finished");
  555.   if (timer->auto_destroy)
  556.     FLUID_FREE (timer);
  557.   return;
  558. }
  559. fluid_timer_t*
  560. new_fluid_timer (int msec, fluid_timer_callback_t callback, void* data,
  561.                  int new_thread, int auto_destroy, int high_priority)
  562. {
  563.   fluid_timer_t *timer;
  564.   timer = FLUID_NEW (fluid_timer_t);
  565.   if (timer == NULL)
  566.   {
  567.     FLUID_LOG (FLUID_ERR, "Out of memory");
  568.     return NULL;
  569.   }
  570.   timer->msec = msec;
  571.   timer->callback = callback;
  572.   timer->data = data;
  573.   timer->cont = TRUE ;
  574.   timer->thread = NULL;
  575.   timer->auto_destroy = auto_destroy;
  576.   if (new_thread)
  577.   {
  578.     timer->thread = new_fluid_thread (fluid_timer_run, timer, high_priority
  579.                                       ? FLUID_SYS_TIMER_HIGH_PRIO_LEVEL : 0, FALSE);
  580.     if (!timer->thread)
  581.     {
  582.       FLUID_FREE (timer);
  583.       return NULL;
  584.     }
  585.   }
  586.   else fluid_timer_run (timer);  /* Run directly, instead of as a separate thread */
  587.   return timer;
  588. }
  589. int
  590. delete_fluid_timer (fluid_timer_t *timer)
  591. {
  592.   int auto_destroy = timer->auto_destroy;
  593.   timer->cont = 0;
  594.   fluid_timer_join (timer);
  595.   /* Shouldn't access timer now if auto_destroy enabled, since it has been destroyed */
  596.   if (!auto_destroy) FLUID_FREE (timer);
  597.   return FLUID_OK;
  598. }
  599. int
  600. fluid_timer_join (fluid_timer_t *timer)
  601. {
  602.   int auto_destroy;
  603.   if (timer->thread)
  604.   {
  605.     auto_destroy = timer->auto_destroy;
  606.     fluid_thread_join (timer->thread);
  607.     if (!auto_destroy) timer->thread = NULL;
  608.   }
  609.   return FLUID_OK;
  610. }
  611. /***************************************************************
  612.  *
  613.  *               Sockets and I/O
  614.  *
  615.  */
  616. /**
  617.  * Get standard in stream handle.
  618.  * @return Standard in stream.
  619.  */
  620. fluid_istream_t
  621. fluid_get_stdin (void)
  622. {
  623.   return STDIN_FILENO;
  624. }
  625. /**
  626.  * Get standard output stream handle.
  627.  * @return Standard out stream.
  628.  */
  629. fluid_ostream_t
  630. fluid_get_stdout (void)
  631. {
  632.   return STDOUT_FILENO;
  633. }
  634. /**
  635.  * Read a line from an input stream.
  636.  * @return 0 if end-of-stream, -1 if error, non zero otherwise
  637.  */
  638. int
  639. fluid_istream_readline (fluid_istream_t in, fluid_ostream_t out, char* prompt,
  640.                         char* buf, int len)
  641. {
  642. #if WITH_READLINE
  643.   if (in == fluid_get_stdin ())
  644.   {
  645.     char *line;
  646.     line = readline (prompt);
  647.     if (line == NULL)
  648.       return -1;
  649.     snprintf(buf, len, "%s", line);
  650.     buf[len - 1] = 0;
  651.     free(line);
  652.     return 1;
  653.   }
  654.   else
  655. #endif
  656.   {
  657.     fluid_ostream_printf (out, "%s", prompt);
  658.     return fluid_istream_gets (in, buf, len);
  659.   }
  660. }
  661. /**
  662.  * Reads a line from an input stream (socket).
  663.  * @param in The input socket
  664.  * @param buf Buffer to store data to
  665.  * @param len Maximum length to store to buf
  666.  * @return 1 if a line was read, 0 on end of stream, -1 on error
  667.  */
  668. static int
  669. fluid_istream_gets (fluid_istream_t in, char* buf, int len)
  670. {
  671.   char c;
  672.   int n;
  673.   buf[len - 1] = 0;
  674.   while (--len > 0)
  675.   {
  676. #ifndef WIN32
  677.     n = read(in, &c, 1);
  678.     if (n == -1) return -1;
  679. #else
  680.     /* Handle read differently depending on if its a socket or file descriptor */
  681.     if (!(in & WIN32_SOCKET_FLAG))
  682.     {
  683.       n = read(in, &c, 1);
  684.       if (n == -1) return -1;
  685.     }
  686.     else
  687.     {
  688.       n = recv(in & ~WIN32_SOCKET_FLAG, &c, 1, 0);
  689.       if (n == SOCKET_ERROR) return -1;
  690.     }
  691. #endif
  692.     if (n == 0)
  693.     {
  694.       *buf++ = 0;
  695.       return 0;
  696.     }
  697.     if ((c == 'n'))
  698.     {
  699.       *buf++ = 0;
  700.       return 1;
  701.     }
  702.     /* Store all characters excluding CR */
  703.     if (c != 'r') *buf++ = c;
  704.   }
  705.   return -1;
  706. }
  707. /**
  708.  * Send a printf style string with arguments to an output stream (socket).
  709.  * @param out Output stream
  710.  * @param format printf style format string
  711.  * @param ... Arguments for the printf format string
  712.  * @return Number of bytes written or -1 on error
  713.  */
  714. int
  715. fluid_ostream_printf (fluid_ostream_t out, char* format, ...)
  716. {
  717.   char buf[4096];
  718.   va_list args;
  719.   int len;
  720.   va_start (args, format);
  721.   len = vsnprintf (buf, 4095, format, args);
  722.   va_end (args);
  723.   if (len <= 0)
  724.   {
  725.     printf("fluid_ostream_printf: buffer overflow");
  726.     return -1;
  727.   }
  728.   buf[4095] = 0;
  729. #ifndef WIN32
  730.   return write (out, buf, strlen (buf));
  731. #else
  732.   {
  733.     int retval;
  734.     /* Handle write differently depending on if its a socket or file descriptor */
  735.     if (!(out & WIN32_SOCKET_FLAG))
  736.       return write(out, buf, strlen (buf));
  737.     /* Socket */
  738.     retval = send (out & ~WIN32_SOCKET_FLAG, buf, strlen (buf), 0);
  739.     return retval != SOCKET_ERROR ? retval : -1;
  740.   }
  741. #endif
  742. }
  743. int fluid_server_socket_join(fluid_server_socket_t *server_socket)
  744. {
  745.   return fluid_thread_join (server_socket->thread);
  746. }
  747. #ifndef WIN32           // Not win32?
  748. #define SOCKET_ERROR -1
  749. fluid_istream_t fluid_socket_get_istream (fluid_socket_t sock)
  750. {
  751.   return sock;
  752. }
  753. fluid_ostream_t fluid_socket_get_ostream (fluid_socket_t sock)
  754. {
  755.   return sock;
  756. }
  757. void fluid_socket_close(fluid_socket_t sock)
  758. {
  759.   if (sock != INVALID_SOCKET)
  760.     close (sock);
  761. }
  762. static void
  763. fluid_server_socket_run (void *data)
  764. {
  765.   fluid_server_socket_t *server_socket = (fluid_server_socket_t *)data;
  766.   fluid_socket_t client_socket;
  767.   struct sockaddr_in addr;
  768.   socklen_t addrlen = sizeof (addr);
  769.   int retval;
  770.   FLUID_LOG (FLUID_DBG, "Server listening for connections");
  771.   while (server_socket->cont)
  772.   {
  773.     client_socket = accept (server_socket->socket, (struct sockaddr *)&addr, &addrlen);
  774.     FLUID_LOG (FLUID_DBG, "New client connection");
  775.     if (client_socket == INVALID_SOCKET)
  776.     {
  777.       if (server_socket->cont)
  778. FLUID_LOG(FLUID_ERR, "Failed to accept connection");
  779.       server_socket->cont = 0;
  780.       return;
  781.     } else {
  782.       retval = server_socket->func (server_socket->data, client_socket,
  783.                                     inet_ntoa (addr.sin_addr));  // FIXME - inet_ntoa is not thread safe
  784.       if (retval != 0)
  785. fluid_socket_close(client_socket);
  786.     }
  787.   }
  788.   FLUID_LOG(FLUID_DBG, "Server closing");
  789. }
  790. fluid_server_socket_t*
  791. new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
  792. {
  793.   fluid_server_socket_t* server_socket;
  794.   struct sockaddr_in addr;
  795.   fluid_socket_t sock;
  796.   g_return_val_if_fail (func != NULL, NULL);
  797.   sock = socket(AF_INET, SOCK_STREAM, 0);
  798.   if (sock == INVALID_SOCKET) {
  799.     FLUID_LOG(FLUID_ERR, "Failed to create server socket");
  800.     return NULL;
  801.   }
  802.   FLUID_MEMSET((char *)&addr, 0, sizeof(struct sockaddr_in));
  803.   addr.sin_family = AF_INET;
  804.   addr.sin_addr.s_addr = htonl(INADDR_ANY);
  805.   addr.sin_port = htons(port);
  806.   if (bind(sock, (const struct sockaddr *) &addr, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
  807.     FLUID_LOG(FLUID_ERR, "Failed to bind server socket");
  808.     fluid_socket_close(sock);
  809.     return NULL;
  810.   }
  811.   if (listen(sock, 10) == SOCKET_ERROR) {
  812.     FLUID_LOG(FLUID_ERR, "Failed listen on server socket");
  813.     fluid_socket_close(sock);
  814.     return NULL;
  815.   }
  816.   server_socket = FLUID_NEW(fluid_server_socket_t);
  817.   if (server_socket == NULL) {
  818.     FLUID_LOG(FLUID_ERR, "Out of memory");
  819.     fluid_socket_close(sock);
  820.     return NULL;
  821.   }
  822.   server_socket->socket = sock;
  823.   server_socket->func = func;
  824.   server_socket->data = data;
  825.   server_socket->cont = 1;
  826.   server_socket->thread = new_fluid_thread(fluid_server_socket_run, server_socket,
  827.                                            0, FALSE);
  828.   if (server_socket->thread == NULL) {
  829.     FLUID_FREE(server_socket);
  830.     fluid_socket_close(sock);
  831.     return NULL;
  832.   }
  833.   return server_socket;
  834. }
  835. int delete_fluid_server_socket(fluid_server_socket_t* server_socket)
  836. {
  837.   server_socket->cont = 0;
  838.   if (server_socket->socket != INVALID_SOCKET) {
  839.     fluid_socket_close(server_socket->socket);
  840.   }
  841.   if (server_socket->thread) {
  842.     delete_fluid_thread(server_socket->thread);
  843.   }
  844.   FLUID_FREE(server_socket);
  845.   return FLUID_OK;
  846. }
  847. #else           // Win32 is "special"
  848. #ifndef WIN32_LEAN_AND_MEAN
  849. #define WIN32_LEAN_AND_MEAN
  850. #endif
  851. fluid_istream_t fluid_socket_get_istream (fluid_socket_t sock)
  852. {
  853.   return sock | WIN32_SOCKET_FLAG;
  854. }
  855. fluid_ostream_t fluid_socket_get_ostream (fluid_socket_t sock)
  856. {
  857.   return sock | WIN32_SOCKET_FLAG;
  858. }
  859. void fluid_socket_close (fluid_socket_t sock)
  860. {
  861.   if (sock != INVALID_SOCKET)
  862.     closesocket (sock);
  863. }
  864. static void fluid_server_socket_run (void *data)
  865. {
  866.   fluid_server_socket_t *server_socket = (fluid_server_socket_t *)data;
  867.   fluid_socket_t client_socket;
  868.   struct sockaddr_in addr;
  869.   socklen_t addrlen = sizeof (addr);
  870.   int r;
  871.   FLUID_LOG(FLUID_DBG, "Server listening for connections");
  872.   while (server_socket->cont)
  873.   {
  874.     client_socket = accept (server_socket->socket, (struct sockaddr *)&addr, &addrlen);
  875.     FLUID_LOG (FLUID_DBG, "New client connection");
  876.     if (client_socket == INVALID_SOCKET)
  877.     {
  878.       if (server_socket->cont)
  879. FLUID_LOG (FLUID_ERR, "Failed to accept connection: %ld", WSAGetLastError ());
  880.       server_socket->cont = 0;
  881.       return;
  882.     }
  883.     else
  884.     {
  885.       r = server_socket->func (server_socket->data, client_socket,
  886.                                inet_ntoa (addr.sin_addr));  // FIXME - inet_ntoa is not thread safe
  887.       if (r != 0)
  888. fluid_socket_close (client_socket);
  889.     }
  890.   }
  891.   FLUID_LOG (FLUID_DBG, "Server closing");
  892. }
  893. fluid_server_socket_t*
  894. new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
  895. {
  896.   fluid_server_socket_t* server_socket;
  897.   struct sockaddr_in addr;
  898.   fluid_socket_t sock;
  899.   WSADATA wsaData;
  900.   int retval;
  901.   g_return_val_if_fail (func != NULL, NULL);
  902.   // Win32 requires initialization of winsock
  903.   retval = WSAStartup (MAKEWORD (2,2), &wsaData);
  904.   if (retval != 0)
  905.   {
  906.     FLUID_LOG(FLUID_ERR, "Server socket creation error: WSAStartup failed: %d", retval);
  907.     return NULL;
  908.   }
  909.   sock = socket (AF_INET, SOCK_STREAM, 0);
  910.   if (sock == INVALID_SOCKET)
  911.   {
  912.     FLUID_LOG (FLUID_ERR, "Failed to create server socket: %ld", WSAGetLastError ());
  913.     WSACleanup ();
  914.     return NULL;
  915.   }
  916.   addr.sin_family = AF_INET;
  917.   addr.sin_port = htons (port);
  918.   addr.sin_addr.s_addr = htonl (INADDR_ANY);
  919.   retval = bind (sock, (struct sockaddr *)&addr, sizeof (addr));
  920.   if (retval == SOCKET_ERROR)
  921.   {
  922.     FLUID_LOG (FLUID_ERR, "Failed to bind server socket: %ld", WSAGetLastError ());
  923.     fluid_socket_close (sock);
  924.     WSACleanup ();
  925.     return NULL;
  926.   }
  927.   if (listen (sock, SOMAXCONN) == SOCKET_ERROR)
  928.   {
  929.     FLUID_LOG (FLUID_ERR, "Failed to listen on server socket: %ld", WSAGetLastError ());
  930.     fluid_socket_close (sock);
  931.     WSACleanup ();
  932.     return NULL;
  933.   }
  934.   server_socket = FLUID_NEW (fluid_server_socket_t);
  935.   if (server_socket == NULL)
  936.   {
  937.     FLUID_LOG (FLUID_ERR, "Out of memory");
  938.     fluid_socket_close (sock);
  939.     WSACleanup ();
  940.     return NULL;
  941.   }
  942.   server_socket->socket = sock;
  943.   server_socket->func = func;
  944.   server_socket->data = data;
  945.   server_socket->cont = 1;
  946.   server_socket->thread = new_fluid_thread(fluid_server_socket_run, server_socket,
  947.                                            0, FALSE);
  948.   if (server_socket->thread == NULL)
  949.   {
  950.     FLUID_FREE (server_socket);
  951.     fluid_socket_close (sock);
  952.     WSACleanup ();
  953.     return NULL;
  954.   }
  955.   return server_socket;
  956. }
  957. int delete_fluid_server_socket(fluid_server_socket_t *server_socket)
  958. {
  959.   server_socket->cont = 0;
  960.   if (server_socket->socket != INVALID_SOCKET)
  961.     fluid_socket_close (server_socket->socket);
  962.   if (server_socket->thread)
  963.     delete_fluid_thread (server_socket->thread);
  964.   FLUID_FREE (server_socket);
  965.   WSACleanup ();        // Should be called the same number of times as WSAStartup
  966.   return FLUID_OK;
  967. }
  968. #endif