Update Fluidsynth to 2.0.1
[ardour.git] / libs / fluidsynth / src / fluid_sys.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 Lesser General Public License
7  * as published by the Free Software Foundation; either version 2.1 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  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free
17  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  * 02110-1301, USA
19  */
20
21 #include "fluid_sys.h"
22
23
24 #if WITH_READLINE
25 #include <readline/readline.h>
26 #include <readline/history.h>
27 #endif
28
29 #ifdef DBUS_SUPPORT
30 #include "fluid_rtkit.h"
31 #endif
32
33 /* WIN32 HACK - Flag used to differentiate between a file descriptor and a socket.
34  * Should work, so long as no SOCKET or file descriptor ends up with this bit set. - JG */
35 #ifdef _WIN32
36 #define FLUID_SOCKET_FLAG      0x40000000
37 #else
38 #define FLUID_SOCKET_FLAG      0x00000000
39 #define SOCKET_ERROR           -1
40 #define INVALID_SOCKET         -1
41 #endif
42
43 /* SCHED_FIFO priority for high priority timer threads */
44 #define FLUID_SYS_TIMER_HIGH_PRIO_LEVEL         10
45
46
47 typedef struct
48 {
49     fluid_thread_func_t func;
50     void *data;
51     int prio_level;
52 } fluid_thread_info_t;
53
54 struct _fluid_timer_t
55 {
56     long msec;
57     fluid_timer_callback_t callback;
58     void *data;
59     fluid_thread_t *thread;
60     int cont;
61     int auto_destroy;
62 };
63
64 struct _fluid_server_socket_t
65 {
66     fluid_socket_t socket;
67     fluid_thread_t *thread;
68     int cont;
69     fluid_server_func_t func;
70     void *data;
71 };
72
73
74 static int fluid_istream_gets(fluid_istream_t in, char *buf, int len);
75
76
77 static char fluid_errbuf[512];  /* buffer for error message */
78
79 static fluid_log_function_t fluid_log_function[LAST_LOG_LEVEL] =
80 {
81     fluid_default_log_function,
82     fluid_default_log_function,
83     fluid_default_log_function,
84     fluid_default_log_function,
85     fluid_default_log_function
86 };
87 static void *fluid_log_user_data[LAST_LOG_LEVEL] = { NULL };
88
89 static const char fluid_libname[] = "fluidsynth";
90
91 /**
92  * Installs a new log function for a specified log level.
93  * @param level Log level to install handler for.
94  * @param fun Callback function handler to call for logged messages
95  * @param data User supplied data pointer to pass to log function
96  * @return The previously installed function.
97  */
98 fluid_log_function_t
99 fluid_set_log_function(int level, fluid_log_function_t fun, void *data)
100 {
101     fluid_log_function_t old = NULL;
102
103     if((level >= 0) && (level < LAST_LOG_LEVEL))
104     {
105         old = fluid_log_function[level];
106         fluid_log_function[level] = fun;
107         fluid_log_user_data[level] = data;
108     }
109
110     return old;
111 }
112
113 /**
114  * Default log function which prints to the stderr.
115  * @param level Log level
116  * @param message Log message
117  * @param data User supplied data (not used)
118  */
119 void
120 fluid_default_log_function(int level, const char *message, void *data)
121 {
122     FILE *out;
123
124 #if defined(WIN32)
125     out = stdout;
126 #else
127     out = stderr;
128 #endif
129
130     switch(level)
131     {
132     case FLUID_PANIC:
133         FLUID_FPRINTF(out, "%s: panic: %s\n", fluid_libname, message);
134         break;
135
136     case FLUID_ERR:
137         FLUID_FPRINTF(out, "%s: error: %s\n", fluid_libname, message);
138         break;
139
140     case FLUID_WARN:
141         FLUID_FPRINTF(out, "%s: warning: %s\n", fluid_libname, message);
142         break;
143
144     case FLUID_INFO:
145         FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
146         break;
147
148     case FLUID_DBG:
149 #if DEBUG
150         FLUID_FPRINTF(out, "%s: debug: %s\n", fluid_libname, message);
151 #endif
152         break;
153
154     default:
155         FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
156         break;
157     }
158
159     fflush(out);
160 }
161
162 /**
163  * Print a message to the log.
164  * @param level Log level (#fluid_log_level).
165  * @param fmt Printf style format string for log message
166  * @param ... Arguments for printf 'fmt' message string
167  * @return Always returns #FLUID_FAILED
168  */
169 int
170 fluid_log(int level, const char *fmt, ...)
171 {
172     fluid_log_function_t fun = NULL;
173
174     va_list args;
175     va_start(args, fmt);
176     FLUID_VSNPRINTF(fluid_errbuf, sizeof(fluid_errbuf), fmt, args);
177     va_end(args);
178
179     if((level >= 0) && (level < LAST_LOG_LEVEL))
180     {
181         fun = fluid_log_function[level];
182
183         if(fun != NULL)
184         {
185             (*fun)(level, fluid_errbuf, fluid_log_user_data[level]);
186         }
187     }
188
189     return FLUID_FAILED;
190 }
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, const char *delim)
206 {
207     char *s,  *token;
208                 const char *d;
209     char c;
210
211     if(str == NULL || delim == NULL || !*delim)
212     {
213         FLUID_LOG(FLUID_ERR, "Null pointer");
214         return NULL;
215     }
216
217     s = *str;
218
219     if(!s)
220     {
221         return NULL;    /* str points to a NULL pointer? (tokenize already ended) */
222     }
223
224     /* skip delimiter chars at beginning of token */
225     do
226     {
227         c = *s;
228
229         if(!c)  /* end of source string? */
230         {
231             *str = NULL;
232             return NULL;
233         }
234
235         for(d = delim; *d; d++) /* is source char a token char? */
236         {
237             if(c == *d) /* token char match? */
238             {
239                 s++;            /* advance to next source char */
240                 break;
241             }
242         }
243     }
244     while(*d);          /* while token char match */
245
246     token = s;          /* start of token found */
247
248     /* search for next token char or end of source string */
249     for(s = s + 1; *s; s++)
250     {
251         c = *s;
252
253         for(d = delim; *d; d++) /* is source char a token char? */
254         {
255             if(c == *d) /* token char match? */
256             {
257                 *s = '\0';      /* overwrite token char with zero byte to terminate token */
258                 *str = s + 1;   /* update str to point to beginning of next token */
259                 return token;
260             }
261         }
262     }
263
264     /* we get here only if source string ended */
265     *str = NULL;
266     return token;
267 }
268
269 /*
270  * fluid_error
271  */
272 char *
273 fluid_error()
274 {
275     return fluid_errbuf;
276 }
277
278 /**
279  * Check if a file is a MIDI file.
280  * @param filename Path to the file to check
281  * @return TRUE if it could be a MIDI file, FALSE otherwise
282  *
283  * The current implementation only checks for the "MThd" header in the file.
284  * It is useful only to distinguish between SoundFont and MIDI files.
285  */
286 int
287 fluid_is_midifile(const char *filename)
288 {
289     FILE *fp = fopen(filename, "rb");
290     char id[4];
291
292     if(fp == NULL)
293     {
294         return 0;
295     }
296
297     if(fread((void *) id, 1, 4, fp) != 4)
298     {
299         fclose(fp);
300         return 0;
301     }
302
303     fclose(fp);
304
305     return FLUID_STRNCMP(id, "MThd", 4) == 0;
306 }
307
308 /**
309  * Check if a file is a SoundFont file.
310  * @param filename Path to the file to check
311  * @return TRUE if it could be a SoundFont, FALSE otherwise
312  *
313  * @note The current implementation only checks for the "RIFF" and "sfbk" headers in
314  * the file. It is useful to distinguish between SoundFont and other (e.g. MIDI) files.
315  */
316 int
317 fluid_is_soundfont(const char *filename)
318 {
319     FILE *fp = fopen(filename, "rb");
320     char riff_id[4], sfbk_id[4];
321
322     if(fp == NULL)
323     {
324         return 0;
325     }
326
327     if((fread((void *) riff_id, 1, sizeof(riff_id), fp) != sizeof(riff_id)) ||
328             (fseek(fp, 4, SEEK_CUR) != 0) ||
329             (fread((void *) sfbk_id, 1, sizeof(sfbk_id), fp) != sizeof(sfbk_id)))
330     {
331         goto error_rec;
332     }
333
334     fclose(fp);
335     return (FLUID_STRNCMP(riff_id, "RIFF", sizeof(riff_id)) == 0) &&
336            (FLUID_STRNCMP(sfbk_id, "sfbk", sizeof(sfbk_id)) == 0);
337
338 error_rec:
339     fclose(fp);
340     return 0;
341 }
342
343 /**
344  * Suspend the execution of the current thread for the specified amount of time.
345  * @param milliseconds to wait.
346  */
347 void fluid_msleep(unsigned int msecs)
348 {
349     g_usleep(msecs * 1000);
350 }
351
352 /**
353  * Get time in milliseconds to be used in relative timing operations.
354  * @return Unix time in milliseconds.
355  */
356 unsigned int fluid_curtime(void)
357 {
358     static glong initial_seconds = 0;
359     GTimeVal timeval;
360
361     if(initial_seconds == 0)
362     {
363         g_get_current_time(&timeval);
364         initial_seconds = timeval.tv_sec;
365     }
366
367     g_get_current_time(&timeval);
368
369     return (unsigned int)((timeval.tv_sec - initial_seconds) * 1000.0 + timeval.tv_usec / 1000.0);
370 }
371
372 /**
373  * Get time in microseconds to be used in relative timing operations.
374  * @return time in microseconds.
375  * Note: When used for profiling we need high precision clock given
376  * by g_get_monotonic_time()if available (glib version >= 2.53.3).
377  * If glib version is too old and in the case of Windows the function
378  * uses high precision performance counter instead of g_getmonotic_time().
379  */
380 double
381 fluid_utime(void)
382 {
383     double utime;
384
385 #if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 28
386     /* use high precision monotonic clock if available (g_monotonic_time().
387      * For Winfdows, if this clock is actually implemented as low prec. clock
388      * (i.e. in case glib is too old), high precision performance counter are
389      * used instead.
390      * see: https://bugzilla.gnome.org/show_bug.cgi?id=783340
391      */
392 #if defined(WITH_PROFILING) &&  defined(WIN32) &&\
393         /* glib < 2.53.3 */\
394         (GLIB_MINOR_VERSION <= 53 && (GLIB_MINOR_VERSION < 53 || GLIB_MICRO_VERSION < 3))
395     /* use high precision performance counter. */
396     static LARGE_INTEGER freq_cache = {0, 0};   /* Performance Frequency */
397     LARGE_INTEGER perf_cpt;
398
399     if(! freq_cache.QuadPart)
400     {
401         QueryPerformanceFrequency(&freq_cache);  /* Frequency value */
402     }
403
404     QueryPerformanceCounter(&perf_cpt); /* Counter value */
405     utime = perf_cpt.QuadPart * 1000000.0 / freq_cache.QuadPart; /* time in micros */
406 #else
407     utime = g_get_monotonic_time();
408 #endif
409 #else
410     /* fallback to less precise clock */
411     GTimeVal timeval;
412     g_get_current_time(&timeval);
413     utime = (timeval.tv_sec * 1000000.0 + timeval.tv_usec);
414 #endif
415
416     return utime;
417 }
418
419
420
421 #if defined(WIN32)      /* Windoze specific stuff */
422
423 void
424 fluid_thread_self_set_prio(int prio_level)
425 {
426     if(prio_level > 0)
427     {
428         SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
429     }
430 }
431
432
433 #elif defined(__OS2__)  /* OS/2 specific stuff */
434
435 void
436 fluid_thread_self_set_prio(int prio_level)
437 {
438     if(prio_level > 0)
439     {
440         DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0);
441     }
442 }
443
444 #else   /* POSIX stuff..  Nice POSIX..  Good POSIX. */
445
446 void
447 fluid_thread_self_set_prio(int prio_level)
448 {
449     struct sched_param priority;
450
451     if(prio_level > 0)
452     {
453
454         memset(&priority, 0, sizeof(priority));
455         priority.sched_priority = prio_level;
456
457         if(pthread_setschedparam(pthread_self(), SCHED_FIFO, &priority) == 0)
458         {
459             return;
460         }
461
462 #ifdef DBUS_SUPPORT
463         /* Try to gain high priority via rtkit */
464
465         if(fluid_rtkit_make_realtime(0, prio_level) == 0)
466         {
467             return;
468         }
469
470 #endif
471         FLUID_LOG(FLUID_WARN, "Failed to set thread to high priority");
472     }
473 }
474
475 #ifdef FPE_CHECK
476
477 /***************************************************************
478  *
479  *               Floating point exceptions
480  *
481  *  The floating point exception functions were taken from Ircam's
482  *  jMax source code. http://www.ircam.fr/jmax
483  *
484  *  FIXME: check in config for i386 machine
485  *
486  *  Currently not used. I leave the code here in case we want to pick
487  *  this up again some time later.
488  */
489
490 /* Exception flags */
491 #define _FPU_STATUS_IE    0x001  /* Invalid Operation */
492 #define _FPU_STATUS_DE    0x002  /* Denormalized Operand */
493 #define _FPU_STATUS_ZE    0x004  /* Zero Divide */
494 #define _FPU_STATUS_OE    0x008  /* Overflow */
495 #define _FPU_STATUS_UE    0x010  /* Underflow */
496 #define _FPU_STATUS_PE    0x020  /* Precision */
497 #define _FPU_STATUS_SF    0x040  /* Stack Fault */
498 #define _FPU_STATUS_ES    0x080  /* Error Summary Status */
499
500 /* Macros for accessing the FPU status word.  */
501
502 /* get the FPU status */
503 #define _FPU_GET_SW(sw) __asm__ ("fnstsw %0" : "=m" (*&sw))
504
505 /* clear the FPU status */
506 #define _FPU_CLR_SW() __asm__ ("fnclex" : : )
507
508 /* Purpose:
509  * Checks, if the floating point unit has produced an exception, print a message
510  * if so and clear the exception.
511  */
512 unsigned int fluid_check_fpe_i386(char *explanation)
513 {
514     unsigned int s;
515
516     _FPU_GET_SW(s);
517     _FPU_CLR_SW();
518
519     s &= _FPU_STATUS_IE | _FPU_STATUS_DE | _FPU_STATUS_ZE | _FPU_STATUS_OE | _FPU_STATUS_UE;
520
521     if(s)
522     {
523         FLUID_LOG(FLUID_WARN, "FPE exception (before or in %s): %s%s%s%s%s", explanation,
524                   (s & _FPU_STATUS_IE) ? "Invalid operation " : "",
525                   (s & _FPU_STATUS_DE) ? "Denormal number " : "",
526                   (s & _FPU_STATUS_ZE) ? "Zero divide " : "",
527                   (s & _FPU_STATUS_OE) ? "Overflow " : "",
528                   (s & _FPU_STATUS_UE) ? "Underflow " : "");
529     }
530
531     return s;
532 }
533
534 /* Purpose:
535  * Clear floating point exception.
536  */
537 void fluid_clear_fpe_i386(void)
538 {
539     _FPU_CLR_SW();
540 }
541
542 #endif  // ifdef FPE_CHECK
543
544
545 #endif  // #else    (its POSIX)
546
547
548 /***************************************************************
549  *
550  *               Profiling (Linux, i586 only)
551  *
552  */
553
554 #if WITH_PROFILING
555 /* Profiling interface beetween profiling command shell and audio rendering API
556   (FluidProfile_0004.pdf- 3.2.2).
557   Macros are in defined in fluid_sys.h.
558 */
559
560 /*
561   -----------------------------------------------------------------------------
562   Shell task side |    Profiling interface              |  Audio task side
563   -----------------------------------------------------------------------------
564   profiling       |    Internal    |      |             |      Audio
565   command   <---> |<-- profling -->| Data |<--macros -->| <--> rendering
566   shell           |    API         |      |             |      API
567
568 */
569 /* default parameters for shell command "prof_start" in fluid_sys.c */
570 unsigned short fluid_profile_notes = 0; /* number of generated notes */
571 /* preset bank:0 prog:16 (organ) */
572 unsigned char fluid_profile_bank = FLUID_PROFILE_DEFAULT_BANK;
573 unsigned char fluid_profile_prog = FLUID_PROFILE_DEFAULT_PROG;
574
575 /* print mode */
576 unsigned char fluid_profile_print = FLUID_PROFILE_DEFAULT_PRINT;
577 /* number of measures */
578 unsigned short fluid_profile_n_prof = FLUID_PROFILE_DEFAULT_N_PROF;
579 /* measure duration in ms */
580 unsigned short fluid_profile_dur = FLUID_PROFILE_DEFAULT_DURATION;
581 /* lock between multiple-shell */
582 fluid_atomic_int_t fluid_profile_lock = 0;
583 /**/
584
585 /*----------------------------------------------
586   Profiling Data
587 -----------------------------------------------*/
588 unsigned char fluid_profile_status = PROFILE_STOP; /* command and status */
589 unsigned int fluid_profile_end_ticks = 0;          /* ending position (in ticks) */
590 fluid_profile_data_t fluid_profile_data[] =        /* Data duration */
591 {
592     {"synth_write_* ------------>", 1e10, 0.0, 0.0, 0, 0, 0},
593     {"synth_one_block ---------->", 1e10, 0.0, 0.0, 0, 0, 0},
594     {"synth_one_block:clear ---->", 1e10, 0.0, 0.0, 0, 0, 0},
595     {"synth_one_block:one voice->", 1e10, 0.0, 0.0, 0, 0, 0},
596     {"synth_one_block:all voices>", 1e10, 0.0, 0.0, 0, 0, 0},
597     {"synth_one_block:reverb --->", 1e10, 0.0, 0.0, 0, 0, 0},
598     {"synth_one_block:chorus --->", 1e10, 0.0, 0.0, 0, 0, 0},
599     {"voice:note --------------->", 1e10, 0.0, 0.0, 0, 0, 0},
600     {"voice:release ------------>", 1e10, 0.0, 0.0, 0, 0, 0}
601 };
602
603
604 /*----------------------------------------------
605   Internal profiling API
606 -----------------------------------------------*/
607 /* logging profiling data (used on synthesizer instance deletion) */
608 void fluid_profiling_print(void)
609 {
610     int i;
611
612     printf("fluid_profiling_print\n");
613
614     FLUID_LOG(FLUID_INFO, "Estimated times: min/avg/max (micro seconds)");
615
616     for(i = 0; i < FLUID_PROFILE_NBR; i++)
617     {
618         if(fluid_profile_data[i].count > 0)
619         {
620             FLUID_LOG(FLUID_INFO, "%s: %.3f/%.3f/%.3f",
621                       fluid_profile_data[i].description,
622                       fluid_profile_data[i].min,
623                       fluid_profile_data[i].total / fluid_profile_data[i].count,
624                       fluid_profile_data[i].max);
625         }
626         else
627         {
628             FLUID_LOG(FLUID_DBG, "%s: no profiling available",
629                       fluid_profile_data[i].description);
630         }
631     }
632 }
633
634 /* Macro that returns cpu load in percent (%)
635  * @dur: duration (micro second).
636  * @sample_rate: sample_rate used in audio driver (Hz).
637  * @n_amples: number of samples collected during 'dur' duration.
638 */
639 #define fluid_profile_load(dur,sample_rate,n_samples) \
640         (dur * sample_rate / n_samples / 10000.0)
641
642
643 /* prints cpu loads only
644 *
645 * @param sample_rate the sample rate of audio output.
646 * @param out output stream device.
647 *
648 * ------------------------------------------------------------------------------
649 * Cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond) and maximum voices
650 * ------------------------------------------------------------------------------
651 * nVoices| total(%)|voices(%)| reverb(%)|chorus(%)| voice(%)|estimated maxVoices
652 * -------|---------|---------|----------|---------|---------|-------------------
653 *     250|   41.544|   41.544|     0.000|    0.000|    0.163|              612
654 */
655 static void fluid_profiling_print_load(double sample_rate, fluid_ostream_t out)
656 {
657     unsigned int n_voices; /* voices number */
658     static const char max_voices_not_available[] = "      not available";
659     const char *pmax_voices;
660     char max_voices_available[20];
661
662     /* First computes data to be printed */
663     double  total, voices, reverb, chorus, all_voices, voice;
664     /* voices number */
665     n_voices = fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].count ?
666                fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].n_voices /
667                fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].count : 0;
668
669     /* total load (%) */
670     total =  fluid_profile_data[FLUID_PROF_WRITE].count ?
671              fluid_profile_load(fluid_profile_data[FLUID_PROF_WRITE].total, sample_rate,
672                                 fluid_profile_data[FLUID_PROF_WRITE].n_samples) : 0;
673
674     /* reverb load (%) */
675     reverb = fluid_profile_data[FLUID_PROF_ONE_BLOCK_REVERB].count ?
676              fluid_profile_load(fluid_profile_data[FLUID_PROF_ONE_BLOCK_REVERB].total,
677                                 sample_rate,
678                                 fluid_profile_data[FLUID_PROF_ONE_BLOCK_REVERB].n_samples) : 0;
679
680     /* chorus load (%) */
681     chorus = fluid_profile_data[FLUID_PROF_ONE_BLOCK_CHORUS].count ?
682              fluid_profile_load(fluid_profile_data[FLUID_PROF_ONE_BLOCK_CHORUS].total,
683                                 sample_rate,
684                                 fluid_profile_data[FLUID_PROF_ONE_BLOCK_CHORUS].n_samples) : 0;
685
686     /* total voices load: total - reverb - chorus (%) */
687     voices = total - reverb - chorus;
688
689     /* One voice load (%): all_voices / n_voices. */
690     all_voices = fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].count ?
691                  fluid_profile_load(fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].total,
692                                     sample_rate,
693                                     fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].n_samples) : 0;
694
695     voice = n_voices ?  all_voices / n_voices : 0;
696
697     /* estimated maximum voices number */
698     if(voice > 0)
699     {
700         FLUID_SNPRINTF(max_voices_available, sizeof(max_voices_available),
701                        "%17d", (unsigned int)((100.0 - reverb - chorus) / voice));
702         pmax_voices = max_voices_available;
703     }
704     else
705     {
706         pmax_voices = max_voices_not_available;
707     }
708
709     /* Now prints data */
710     fluid_ostream_printf(out,
711                          " ------------------------------------------------------------------------------\n");
712     fluid_ostream_printf(out,
713                          " Cpu loads(%%) (sr:%6.0f Hz, sp:%6.2f microsecond) and maximum voices\n",
714                          sample_rate, 1000000.0 / sample_rate);
715     fluid_ostream_printf(out,
716                          " ------------------------------------------------------------------------------\n");
717     fluid_ostream_printf(out,
718                          " nVoices| total(%%)|voices(%%)| reverb(%%)|chorus(%%)| voice(%%)|estimated maxVoices\n");
719     fluid_ostream_printf(out,
720                          " -------|---------|---------|----------|---------|---------|-------------------\n");
721     fluid_ostream_printf(out,
722                          "%8d|%9.3f|%9.3f|%10.3f|%9.3f|%9.3f|%s\n", n_voices, total, voices,
723                          reverb, chorus, voice, pmax_voices);
724 }
725
726 /*
727 * prints profiling data (used by profile shell command: prof_start).
728 * The function is an internal profiling API between the "profile" command
729 * prof_start and audio rendering API (see FluidProfile_0004.pdf - 3.2.2).
730 *
731 * @param sample_rate the sample rate of audio output.
732 * @param out output stream device.
733 *
734 * When print mode is 1, the function prints all the informations (see below).
735 * When print mode is 0, the fonction prints only the cpu loads.
736 *
737 * ------------------------------------------------------------------------------
738 * Duration(microsecond) and cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond)
739 * ------------------------------------------------------------------------------
740 * Code under profiling       |Voices|       Duration (microsecond)   |  Load(%)
741 *                            |   nbr|       min|       avg|       max|
742 * ---------------------------|------|--------------------------------|----------
743 * synth_write_* ------------>|   250|      3.91|   2188.82|   3275.00|  41.544
744 * synth_one_block ---------->|   250|   1150.70|   2273.56|   3241.47|  41.100
745 * synth_one_block:clear ---->|   250|      3.07|      4.62|     61.18|   0.084
746 * synth_one_block:one voice->|     1|      4.19|      9.02|   1044.27|   0.163
747 * synth_one_block:all voices>|   250|   1138.41|   2259.11|   3217.73|  40.839
748 * synth_one_block:reverb --->| no profiling available
749 * synth_one_block:chorus --->| no profiling available
750 * voice:note --------------->| no profiling available
751 * voice:release ------------>| no profiling available
752 * ------------------------------------------------------------------------------
753 * Cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond) and maximum voices
754 * ------------------------------------------------------------------------------
755 * nVoices| total(%)|voices(%)| reverb(%)|chorus(%)| voice(%)|estimated maxVoices
756 * -------|---------|---------|----------|---------|---------|-------------------
757 *     250|   41.544|   41.544|     0.000|    0.000|    0.163|              612
758 */
759 void fluid_profiling_print_data(double sample_rate, fluid_ostream_t out)
760 {
761     int i;
762
763     if(fluid_profile_print)
764     {
765         /* print all details: Duration(microsecond) and cpu loads(%) */
766         fluid_ostream_printf(out,
767                              " ------------------------------------------------------------------------------\n");
768         fluid_ostream_printf(out,
769                              " Duration(microsecond) and cpu loads(%%) (sr:%6.0f Hz, sp:%6.2f microsecond)\n",
770                              sample_rate, 1000000.0 / sample_rate);
771         fluid_ostream_printf(out,
772                              " ------------------------------------------------------------------------------\n");
773         fluid_ostream_printf(out,
774                              " Code under profiling       |Voices|       Duration (microsecond)   |  Load(%%)\n");
775         fluid_ostream_printf(out,
776                              "                            |   nbr|       min|       avg|       max|\n");
777         fluid_ostream_printf(out,
778                              " ---------------------------|------|--------------------------------|----------\n");
779
780         for(i = 0; i < FLUID_PROFILE_NBR; i++)
781         {
782             unsigned int count = fluid_profile_data[i].count;
783
784             if(count > 0)
785             {
786                 /* data are available */
787
788                 if(FLUID_PROF_WRITE <= i && i <= FLUID_PROF_ONE_BLOCK_CHORUS)
789                 {
790                     double load = fluid_profile_load(fluid_profile_data[i].total, sample_rate,
791                                                      fluid_profile_data[i].n_samples);
792                     fluid_ostream_printf(out, " %s|%6d|%10.2f|%10.2f|%10.2f|%8.3f\n",
793                                          fluid_profile_data[i].description, /* code under profiling */
794                                          fluid_profile_data[i].n_voices / count, /* voices number */
795                                          fluid_profile_data[i].min,              /* minimum duration */
796                                          fluid_profile_data[i].total / count,    /* average duration */
797                                          fluid_profile_data[i].max,              /* maximum duration */
798                                          load);                                  /* cpu load */
799                 }
800                 else
801                 {
802                     /* note and release duration */
803                     fluid_ostream_printf(out, " %s|%6d|%10.0f|%10.0f|%10.0f|\n",
804                                          fluid_profile_data[i].description, /* code under profiling */
805                                          fluid_profile_data[i].n_voices / count,
806                                          fluid_profile_data[i].min,              /* minimum duration */
807                                          fluid_profile_data[i].total / count,    /* average duration */
808                                          fluid_profile_data[i].max);             /* maximum duration */
809                 }
810             }
811             else
812             {
813                 /* data aren't available */
814                 fluid_ostream_printf(out,
815                                      " %s| no profiling available\n", fluid_profile_data[i].description);
816             }
817         }
818     }
819
820     /* prints cpu loads only */
821     fluid_profiling_print_load(sample_rate, out);/* prints cpu loads */
822 }
823
824 /*
825  Returns true if the user cancels the current profiling measurement.
826  Actually this is implemented using the <ENTER> key. To add this functionality:
827  1) Adds #define FLUID_PROFILE_CANCEL in fluid_sys.h.
828  2) Adds the necessary code inside fluid_profile_is_cancel().
829
830  When FLUID_PROFILE_CANCEL is not defined, the function return FALSE.
831 */
832 int fluid_profile_is_cancel_req(void)
833 {
834 #ifdef FLUID_PROFILE_CANCEL
835
836 #if defined(WIN32)      /* Windows specific stuff */
837     /* Profile cancellation is supported for Windows */
838     /* returns TRUE if key <ENTER> is depressed */
839     return(GetAsyncKeyState(VK_RETURN) & 0x1);
840
841 #elif defined(__OS2__)  /* OS/2 specific stuff */
842     /* Profile cancellation isn't yet supported for OS2 */
843     /* For OS2, replaces the following  line with the function that returns
844     true when the keyboard key <ENTER> is depressed */
845     return FALSE; /* default value */
846
847 #else   /* POSIX stuff */
848     /* Profile cancellation is supported for Linux */
849     /* returns true is <ENTER> is depressed */
850     {
851         /* Here select() is used to poll the standard input to see if an input
852          is ready. As the standard input is usually buffered, the user
853          needs to depress <ENTER> to set the input to a "ready" state.
854         */
855         struct timeval tv;
856         fd_set fds;    /* just one fds need to be polled */
857         tv.tv_sec = 0; /* Setting both values to 0, means a 0 timeout */
858         tv.tv_usec = 0;
859         FD_ZERO(&fds); /* reset fds */
860         FD_SET(STDIN_FILENO, &fds); /* sets fds to poll standard input only */
861         select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv); /* polling */
862         return (FD_ISSET(0, &fds)); /* returns true if standard input is ready */
863     }
864 #endif /* OS stuff */
865
866 #else /* FLUID_PROFILE_CANCEL not defined */
867     return FALSE; /* default value */
868 #endif /* FLUID_PROFILE_CANCEL */
869 }
870
871 /**
872 * Returns status used in shell command "prof_start".
873 * The function is an internal profiling API between the "profile" command
874 * prof_start and audio rendering API (see FluidProfile_0004.pdf - 3.2.2).
875 *
876 * @return status
877 * - PROFILE_READY profiling data are ready.
878 * - PROFILE_RUNNING, profiling data are still under acquisition.
879 * - PROFILE_CANCELED, acquisition has been cancelled by the user.
880 * - PROFILE_STOP, no acquisition in progress.
881 *
882 * When status is PROFILE_RUNNING, the caller can do passive waiting, or other
883 * work before recalling the function later.
884 */
885 int fluid_profile_get_status(void)
886 {
887     /* Checks if user has requested to cancel the current measurement */
888     /* Cancellation must have precedence over other status */
889     if(fluid_profile_is_cancel_req())
890     {
891         fluid_profile_start_stop(0, 0); /* stops the measurement */
892         return PROFILE_CANCELED;
893     }
894
895     switch(fluid_profile_status)
896     {
897     case PROFILE_READY:
898         return PROFILE_READY; /* profiling data are ready */
899
900     case PROFILE_START:
901         return PROFILE_RUNNING;/* profiling data are under acquisition */
902
903     default:
904         return PROFILE_STOP;
905     }
906 }
907
908 /**
909 *  Starts or stops profiling measurement.
910 *  The function is an internal profiling API between the "profile" command
911 *  prof_start and audio rendering API (see FluidProfile_0004.pdf - 3.2.2).
912 *
913 *  @param end_tick end position of the measure (in ticks).
914 *  - If end_tick is greater then 0, the function starts a measure if a measure
915 *    isn't running. If a measure is already running, the function does nothing
916 *    and returns.
917 *  - If end_tick is 0, the function stops a measure.
918 *  @param clear_data,
919 *  - If clear_data is 0, the function clears fluid_profile_data before starting
920 *    a measure, otherwise, the data from the started measure will be accumulated
921 *    within fluid_profile_data.
922 */
923 void fluid_profile_start_stop(unsigned int end_ticks, short clear_data)
924 {
925     if(end_ticks)    /* This is a "start" request */
926     {
927         /* Checks if a measure is already running */
928         if(fluid_profile_status != PROFILE_START)
929         {
930             short i;
931             fluid_profile_end_ticks = end_ticks;
932
933             /* Clears profile data */
934             if(clear_data == 0)
935                 for(i = 0; i < FLUID_PROFILE_NBR; i++)
936                 {
937                     fluid_profile_data[i].min = 1e10;/* min sets to max value */
938                     fluid_profile_data[i].max = 0;   /* maximum sets to min value */
939                     fluid_profile_data[i].total = 0; /* total duration microsecond */
940                     fluid_profile_data[i].count = 0;    /* data count */
941                     fluid_profile_data[i].n_voices = 0; /* voices number */
942                     fluid_profile_data[i].n_samples = 0;/* audio samples number */
943                 }
944
945             fluid_profile_status = PROFILE_START;       /* starts profiling */
946         }
947
948         /* else do nothing when profiling is already started */
949     }
950     else /* This is a "stop" request */
951     {
952         /* forces the current running profile (if any) to stop */
953         fluid_profile_status = PROFILE_STOP;    /* stops profiling */
954     }
955 }
956
957 #endif /* WITH_PROFILING */
958
959 /***************************************************************
960  *
961  *               Threads
962  *
963  */
964
965 #if OLD_GLIB_THREAD_API
966
967 /* Rather than inline this one, we just declare it as a function, to prevent
968  * GCC warning about inline failure. */
969 fluid_cond_t *
970 new_fluid_cond(void)
971 {
972     if(!g_thread_supported())
973     {
974         g_thread_init(NULL);
975     }
976
977     return g_cond_new();
978 }
979
980 #endif
981
982 static gpointer
983 fluid_thread_high_prio(gpointer data)
984 {
985     fluid_thread_info_t *info = data;
986
987     fluid_thread_self_set_prio(info->prio_level);
988
989     info->func(info->data);
990     FLUID_FREE(info);
991
992     return NULL;
993 }
994
995 /**
996  * Create a new thread.
997  * @param func Function to execute in new thread context
998  * @param data User defined data to pass to func
999  * @param prio_level Priority level.  If greater than 0 then high priority scheduling will
1000  *   be used, with the given priority level (used by pthreads only).  0 uses normal scheduling.
1001  * @param detach If TRUE, 'join' does not work and the thread destroys itself when finished.
1002  * @return New thread pointer or NULL on error
1003  */
1004 fluid_thread_t *
1005 new_fluid_thread(const char *name, fluid_thread_func_t func, void *data, int prio_level, int detach)
1006 {
1007     GThread *thread;
1008     fluid_thread_info_t *info;
1009     GError *err = NULL;
1010
1011     g_return_val_if_fail(func != NULL, NULL);
1012
1013 #if OLD_GLIB_THREAD_API
1014
1015     /* Make sure g_thread_init has been called.
1016      * FIXME - Probably not a good idea in a shared library,
1017      * but what can we do *and* remain backwards compatible? */
1018     if(!g_thread_supported())
1019     {
1020         g_thread_init(NULL);
1021     }
1022
1023 #endif
1024
1025     if(prio_level > 0)
1026     {
1027         info = FLUID_NEW(fluid_thread_info_t);
1028
1029         if(!info)
1030         {
1031             FLUID_LOG(FLUID_ERR, "Out of memory");
1032             return NULL;
1033         }
1034
1035         info->func = func;
1036         info->data = data;
1037         info->prio_level = prio_level;
1038 #if NEW_GLIB_THREAD_API
1039         thread = g_thread_try_new(name, fluid_thread_high_prio, info, &err);
1040 #else
1041         thread = g_thread_create(fluid_thread_high_prio, info, detach == FALSE, &err);
1042 #endif
1043     }
1044
1045 #if NEW_GLIB_THREAD_API
1046     else
1047     {
1048         thread = g_thread_try_new(name, (GThreadFunc)func, data, &err);
1049     }
1050
1051 #else
1052     else
1053     {
1054         thread = g_thread_create((GThreadFunc)func, data, detach == FALSE, &err);
1055     }
1056
1057 #endif
1058
1059     if(!thread)
1060     {
1061         FLUID_LOG(FLUID_ERR, "Failed to create the thread: %s",
1062                   fluid_gerror_message(err));
1063         g_clear_error(&err);
1064         return NULL;
1065     }
1066
1067 #if NEW_GLIB_THREAD_API
1068
1069     if(detach)
1070     {
1071         g_thread_unref(thread);    // Release thread reference, if caller wants to detach
1072     }
1073
1074 #endif
1075
1076     return thread;
1077 }
1078
1079 /**
1080  * Frees data associated with a thread (does not actually stop thread).
1081  * @param thread Thread to free
1082  */
1083 void
1084 delete_fluid_thread(fluid_thread_t *thread)
1085 {
1086     /* Threads free themselves when they quit, nothing to do */
1087 }
1088
1089 /**
1090  * Join a thread (wait for it to terminate).
1091  * @param thread Thread to join
1092  * @return FLUID_OK
1093  */
1094 int
1095 fluid_thread_join(fluid_thread_t *thread)
1096 {
1097     g_thread_join(thread);
1098
1099     return FLUID_OK;
1100 }
1101
1102
1103 static fluid_thread_return_t
1104 fluid_timer_run(void *data)
1105 {
1106     fluid_timer_t *timer;
1107     int count = 0;
1108     int cont;
1109     long start;
1110     long delay;
1111
1112     timer = (fluid_timer_t *)data;
1113
1114     /* keep track of the start time for absolute positioning */
1115     start = fluid_curtime();
1116
1117     while(timer->cont)
1118     {
1119         cont = (*timer->callback)(timer->data, fluid_curtime() - start);
1120
1121         count++;
1122
1123         if(!cont)
1124         {
1125             break;
1126         }
1127
1128         /* to avoid incremental time errors, calculate the delay between
1129            two callbacks bringing in the "absolute" time (count *
1130            timer->msec) */
1131         delay = (count * timer->msec) - (fluid_curtime() - start);
1132
1133         if(delay > 0)
1134         {
1135             fluid_msleep(delay);
1136         }
1137     }
1138
1139     FLUID_LOG(FLUID_DBG, "Timer thread finished");
1140
1141     if(timer->auto_destroy)
1142     {
1143         FLUID_FREE(timer);
1144     }
1145
1146     return FLUID_THREAD_RETURN_VALUE;
1147 }
1148
1149 fluid_timer_t *
1150 new_fluid_timer(int msec, fluid_timer_callback_t callback, void *data,
1151                 int new_thread, int auto_destroy, int high_priority)
1152 {
1153     fluid_timer_t *timer;
1154
1155     timer = FLUID_NEW(fluid_timer_t);
1156
1157     if(timer == NULL)
1158     {
1159         FLUID_LOG(FLUID_ERR, "Out of memory");
1160         return NULL;
1161     }
1162
1163     timer->msec = msec;
1164     timer->callback = callback;
1165     timer->data = data;
1166     timer->cont = TRUE ;
1167     timer->thread = NULL;
1168     timer->auto_destroy = auto_destroy;
1169
1170     if(new_thread)
1171     {
1172         timer->thread = new_fluid_thread("timer", fluid_timer_run, timer, high_priority
1173                                          ? FLUID_SYS_TIMER_HIGH_PRIO_LEVEL : 0, FALSE);
1174
1175         if(!timer->thread)
1176         {
1177             FLUID_FREE(timer);
1178             return NULL;
1179         }
1180     }
1181     else
1182     {
1183         fluid_timer_run(timer);   /* Run directly, instead of as a separate thread */
1184
1185         if(auto_destroy)
1186         {
1187             /* do NOT return freed memory */
1188             return NULL;
1189         }
1190     }
1191
1192     return timer;
1193 }
1194
1195 void
1196 delete_fluid_timer(fluid_timer_t *timer)
1197 {
1198     int auto_destroy;
1199     fluid_return_if_fail(timer != NULL);
1200
1201     auto_destroy = timer->auto_destroy;
1202
1203     timer->cont = 0;
1204     fluid_timer_join(timer);
1205
1206     /* Shouldn't access timer now if auto_destroy enabled, since it has been destroyed */
1207
1208     if(!auto_destroy)
1209     {
1210         FLUID_FREE(timer);
1211     }
1212 }
1213
1214 int
1215 fluid_timer_join(fluid_timer_t *timer)
1216 {
1217     int auto_destroy;
1218
1219     if(timer->thread)
1220     {
1221         auto_destroy = timer->auto_destroy;
1222         fluid_thread_join(timer->thread);
1223
1224         if(!auto_destroy)
1225         {
1226             timer->thread = NULL;
1227         }
1228     }
1229
1230     return FLUID_OK;
1231 }
1232
1233
1234 /***************************************************************
1235  *
1236  *               Sockets and I/O
1237  *
1238  */
1239
1240 /**
1241  * Get standard in stream handle.
1242  * @return Standard in stream.
1243  */
1244 fluid_istream_t
1245 fluid_get_stdin(void)
1246 {
1247     return STDIN_FILENO;
1248 }
1249
1250 /**
1251  * Get standard output stream handle.
1252  * @return Standard out stream.
1253  */
1254 fluid_ostream_t
1255 fluid_get_stdout(void)
1256 {
1257     return STDOUT_FILENO;
1258 }
1259
1260 /**
1261  * Read a line from an input stream.
1262  * @return 0 if end-of-stream, -1 if error, non zero otherwise
1263  */
1264 int
1265 fluid_istream_readline(fluid_istream_t in, fluid_ostream_t out, char *prompt,
1266                        char *buf, int len)
1267 {
1268 #if WITH_READLINE
1269
1270     if(in == fluid_get_stdin())
1271     {
1272         char *line;
1273
1274         line = readline(prompt);
1275
1276         if(line == NULL)
1277         {
1278             return -1;
1279         }
1280
1281         FLUID_SNPRINTF(buf, len, "%s", line);
1282         buf[len - 1] = 0;
1283
1284         free(line);
1285         return 1;
1286     }
1287     else
1288 #endif
1289     {
1290         fluid_ostream_printf(out, "%s", prompt);
1291         return fluid_istream_gets(in, buf, len);
1292     }
1293 }
1294
1295 /**
1296  * Reads a line from an input stream (socket).
1297  * @param in The input socket
1298  * @param buf Buffer to store data to
1299  * @param len Maximum length to store to buf
1300  * @return 1 if a line was read, 0 on end of stream, -1 on error
1301  */
1302 static int
1303 fluid_istream_gets(fluid_istream_t in, char *buf, int len)
1304 {
1305     char c;
1306     int n;
1307
1308     buf[len - 1] = 0;
1309
1310     while(--len > 0)
1311     {
1312 #ifndef WIN32
1313         n = read(in, &c, 1);
1314
1315         if(n == -1)
1316         {
1317             return -1;
1318         }
1319
1320 #else
1321
1322         /* Handle read differently depending on if its a socket or file descriptor */
1323         if(!(in & FLUID_SOCKET_FLAG))
1324         {
1325             n = read(in, &c, 1);
1326
1327             if(n == -1)
1328             {
1329                 return -1;
1330             }
1331         }
1332         else
1333         {
1334             n = recv(in & ~FLUID_SOCKET_FLAG, &c, 1, 0);
1335
1336             if(n == SOCKET_ERROR)
1337             {
1338                 return -1;
1339             }
1340         }
1341
1342 #endif
1343
1344         if(n == 0)
1345         {
1346             *buf = 0;
1347             return 0;
1348         }
1349
1350         if(c == '\n')
1351         {
1352             *buf = 0;
1353             return 1;
1354         }
1355
1356         /* Store all characters excluding CR */
1357         if(c != '\r')
1358         {
1359             *buf++ = c;
1360         }
1361     }
1362
1363     return -1;
1364 }
1365
1366 /**
1367  * Send a printf style string with arguments to an output stream (socket).
1368  * @param out Output stream
1369  * @param format printf style format string
1370  * @param ... Arguments for the printf format string
1371  * @return Number of bytes written or -1 on error
1372  */
1373 int
1374 fluid_ostream_printf(fluid_ostream_t out, const char *format, ...)
1375 {
1376     char buf[4096];
1377     va_list args;
1378     int len;
1379
1380     va_start(args, format);
1381     len = FLUID_VSNPRINTF(buf, 4095, format, args);
1382     va_end(args);
1383
1384     if(len == 0)
1385     {
1386         return 0;
1387     }
1388
1389     if(len < 0)
1390     {
1391         printf("fluid_ostream_printf: buffer overflow");
1392         return -1;
1393     }
1394
1395     buf[4095] = 0;
1396
1397 #ifndef WIN32
1398     return write(out, buf, FLUID_STRLEN(buf));
1399 #else
1400     {
1401         int retval;
1402
1403         /* Handle write differently depending on if its a socket or file descriptor */
1404         if(!(out & FLUID_SOCKET_FLAG))
1405         {
1406             return write(out, buf, FLUID_STRLEN(buf));
1407         }
1408
1409         /* Socket */
1410         retval = send(out & ~FLUID_SOCKET_FLAG, buf, FLUID_STRLEN(buf), 0);
1411
1412         return retval != SOCKET_ERROR ? retval : -1;
1413     }
1414 #endif
1415 }
1416
1417 #ifdef NETWORK_SUPPORT
1418
1419 int fluid_server_socket_join(fluid_server_socket_t *server_socket)
1420 {
1421     return fluid_thread_join(server_socket->thread);
1422 }
1423
1424 static int fluid_socket_init(void)
1425 {
1426 #ifdef _WIN32
1427     WSADATA wsaData;
1428     int res = WSAStartup(MAKEWORD(2, 2), &wsaData);
1429
1430     if(res != 0)
1431     {
1432         FLUID_LOG(FLUID_ERR, "Server socket creation error: WSAStartup failed: %d", res);
1433         return FLUID_FAILED;
1434     }
1435
1436 #endif
1437
1438     return FLUID_OK;
1439 }
1440
1441 static void fluid_socket_cleanup(void)
1442 {
1443 #ifdef _WIN32
1444     WSACleanup();
1445 #endif
1446 }
1447
1448 static int fluid_socket_get_error(void)
1449 {
1450 #ifdef _WIN32
1451     return (int)WSAGetLastError();
1452 #else
1453     return errno;
1454 #endif
1455 }
1456
1457 fluid_istream_t fluid_socket_get_istream(fluid_socket_t sock)
1458 {
1459     return sock | FLUID_SOCKET_FLAG;
1460 }
1461
1462 fluid_ostream_t fluid_socket_get_ostream(fluid_socket_t sock)
1463 {
1464     return sock | FLUID_SOCKET_FLAG;
1465 }
1466
1467 void fluid_socket_close(fluid_socket_t sock)
1468 {
1469     if(sock != INVALID_SOCKET)
1470     {
1471 #ifdef _WIN32
1472         closesocket(sock);
1473
1474 #else
1475         close(sock);
1476 #endif
1477     }
1478 }
1479
1480 static fluid_thread_return_t fluid_server_socket_run(void *data)
1481 {
1482     fluid_server_socket_t *server_socket = (fluid_server_socket_t *)data;
1483     fluid_socket_t client_socket;
1484 #ifdef IPV6_SUPPORT
1485     struct sockaddr_in6 addr;
1486 #else
1487     struct sockaddr_in addr;
1488 #endif
1489
1490 #ifdef HAVE_INETNTOP
1491 #ifdef IPV6_SUPPORT
1492     char straddr[INET6_ADDRSTRLEN];
1493 #else
1494     char straddr[INET_ADDRSTRLEN];
1495 #endif /* IPV6_SUPPORT */
1496 #endif /* HAVE_INETNTOP */
1497
1498     socklen_t addrlen = sizeof(addr);
1499     int r;
1500     FLUID_MEMSET((char *)&addr, 0, sizeof(addr));
1501
1502     FLUID_LOG(FLUID_DBG, "Server listening for connections");
1503
1504     while(server_socket->cont)
1505     {
1506         client_socket = accept(server_socket->socket, (struct sockaddr *)&addr, &addrlen);
1507
1508         FLUID_LOG(FLUID_DBG, "New client connection");
1509
1510         if(client_socket == INVALID_SOCKET)
1511         {
1512             if(server_socket->cont)
1513             {
1514                 FLUID_LOG(FLUID_ERR, "Failed to accept connection: %ld", fluid_socket_get_error());
1515             }
1516
1517             server_socket->cont = 0;
1518             return FLUID_THREAD_RETURN_VALUE;
1519         }
1520         else
1521         {
1522 #ifdef HAVE_INETNTOP
1523
1524 #ifdef IPV6_SUPPORT
1525             inet_ntop(AF_INET6, &addr.sin6_addr, straddr, sizeof(straddr));
1526 #else
1527             inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr));
1528 #endif
1529
1530             r = server_socket->func(server_socket->data, client_socket,
1531                                     straddr);
1532 #else
1533             r = server_socket->func(server_socket->data, client_socket,
1534                                     inet_ntoa(addr.sin_addr));
1535 #endif
1536
1537             if(r != 0)
1538             {
1539                 fluid_socket_close(client_socket);
1540             }
1541         }
1542     }
1543
1544     FLUID_LOG(FLUID_DBG, "Server closing");
1545
1546     return FLUID_THREAD_RETURN_VALUE;
1547 }
1548
1549 fluid_server_socket_t *
1550 new_fluid_server_socket(int port, fluid_server_func_t func, void *data)
1551 {
1552     fluid_server_socket_t *server_socket;
1553 #ifdef IPV6_SUPPORT
1554     struct sockaddr_in6 addr;
1555 #else
1556     struct sockaddr_in addr;
1557 #endif
1558
1559     fluid_socket_t sock;
1560
1561     fluid_return_val_if_fail(func != NULL, NULL);
1562
1563     if(fluid_socket_init() != FLUID_OK)
1564     {
1565         return NULL;
1566     }
1567
1568 #ifdef IPV6_SUPPORT
1569     sock = socket(AF_INET6, SOCK_STREAM, 0);
1570
1571     if(sock == INVALID_SOCKET)
1572     {
1573         FLUID_LOG(FLUID_ERR, "Failed to create server socket: %ld", fluid_socket_get_error());
1574         fluid_socket_cleanup();
1575         return NULL;
1576     }
1577
1578     FLUID_MEMSET(&addr, 0, sizeof(addr));
1579     addr.sin6_family = AF_INET6;
1580     addr.sin6_port = htons((uint16_t)port);
1581     addr.sin6_addr = in6addr_any;
1582 #else
1583
1584     sock = socket(AF_INET, SOCK_STREAM, 0);
1585
1586     if(sock == INVALID_SOCKET)
1587     {
1588         FLUID_LOG(FLUID_ERR, "Failed to create server socket: %ld", fluid_socket_get_error());
1589         fluid_socket_cleanup();
1590         return NULL;
1591     }
1592
1593     FLUID_MEMSET(&addr, 0, sizeof(addr));
1594     addr.sin_family = AF_INET;
1595     addr.sin_port = htons((uint16_t)port);
1596     addr.sin_addr.s_addr = htonl(INADDR_ANY);
1597 #endif
1598
1599     if(bind(sock, (const struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR)
1600     {
1601         FLUID_LOG(FLUID_ERR, "Failed to bind server socket: %ld", fluid_socket_get_error());
1602         fluid_socket_close(sock);
1603         fluid_socket_cleanup();
1604         return NULL;
1605     }
1606
1607     if(listen(sock, SOMAXCONN) == SOCKET_ERROR)
1608     {
1609         FLUID_LOG(FLUID_ERR, "Failed to listen on server socket: %ld", fluid_socket_get_error());
1610         fluid_socket_close(sock);
1611         fluid_socket_cleanup();
1612         return NULL;
1613     }
1614
1615     server_socket = FLUID_NEW(fluid_server_socket_t);
1616
1617     if(server_socket == NULL)
1618     {
1619         FLUID_LOG(FLUID_ERR, "Out of memory");
1620         fluid_socket_close(sock);
1621         fluid_socket_cleanup();
1622         return NULL;
1623     }
1624
1625     server_socket->socket = sock;
1626     server_socket->func = func;
1627     server_socket->data = data;
1628     server_socket->cont = 1;
1629
1630     server_socket->thread = new_fluid_thread("server", fluid_server_socket_run, server_socket,
1631                             0, FALSE);
1632
1633     if(server_socket->thread == NULL)
1634     {
1635         FLUID_FREE(server_socket);
1636         fluid_socket_close(sock);
1637         fluid_socket_cleanup();
1638         return NULL;
1639     }
1640
1641     return server_socket;
1642 }
1643
1644 void delete_fluid_server_socket(fluid_server_socket_t *server_socket)
1645 {
1646     fluid_return_if_fail(server_socket != NULL);
1647
1648     server_socket->cont = 0;
1649
1650     if(server_socket->socket != INVALID_SOCKET)
1651     {
1652         fluid_socket_close(server_socket->socket);
1653     }
1654
1655     if(server_socket->thread)
1656     {
1657         fluid_thread_join(server_socket->thread);
1658         delete_fluid_thread(server_socket->thread);
1659     }
1660
1661     FLUID_FREE(server_socket);
1662
1663     // Should be called the same number of times as fluid_socket_init()
1664     fluid_socket_cleanup();
1665 }
1666
1667 #endif // NETWORK_SUPPORT