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  * 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 /* WIN32 HACK - Flag used to differentiate between a file descriptor and a socket.
30  * Should work, so long as no SOCKET or file descriptor ends up with this bit set. - JG */
31 #define WIN32_SOCKET_FLAG       0x40000000
32 
33 /* SCHED_FIFO priority for high priority timer threads */
34 #define FLUID_SYS_TIMER_HIGH_PRIO_LEVEL         10
35 
36 typedef struct
37 {
38   fluid_thread_func_t func;
39   void *data;
40   int prio_level;
41 } fluid_thread_info_t;
42 
43 struct _fluid_timer_t
44 {
45   long msec;
46   fluid_timer_callback_t callback;
47   void *data;
48   fluid_thread_t *thread;
49   int cont;
50   int auto_destroy;
51 };
52 
53 struct _fluid_server_socket_t
54 {
55   fluid_socket_t socket;
56   fluid_thread_t *thread;
57   int cont;
58   fluid_server_func_t func;
59   void *data;
60 };
61 
62 
63 static int fluid_istream_gets(fluid_istream_t in, char* buf, int len);
64 
65 
66 static char fluid_errbuf[512];  /* buffer for error message */
67 
68 static fluid_log_function_t fluid_log_function[LAST_LOG_LEVEL];
69 static void* fluid_log_user_data[LAST_LOG_LEVEL];
70 static int fluid_log_initialized = 0;
71 
72 static char* fluid_libname = "fluidsynth";
73 
74 
fluid_sys_config()75 void fluid_sys_config()
76 {
77   fluid_log_config();
78 }
79 
80 
81 unsigned int fluid_debug_flags = 0;
82 
83 #if DEBUG
84 /*
85  * fluid_debug
86  */
fluid_debug(int level,char * fmt,...)87 int fluid_debug(int level, char * fmt, ...)
88 {
89   if (fluid_debug_flags & level) {
90     fluid_log_function_t fun;
91     va_list args;
92 
93     va_start (args, fmt);
94     vsnprintf(fluid_errbuf, sizeof (fluid_errbuf), fmt, args);
95     va_end (args);
96 
97     fun = fluid_log_function[FLUID_DBG];
98     if (fun != NULL) {
99       (*fun)(level, fluid_errbuf, fluid_log_user_data[FLUID_DBG]);
100     }
101   }
102   return 0;
103 }
104 #endif
105 
106 /**
107  * Installs a new log function for a specified log level.
108  * @param level Log level to install handler for.
109  * @param fun Callback function handler to call for logged messages
110  * @param data User supplied data pointer to pass to log function
111  * @return The previously installed function.
112  */
113 fluid_log_function_t
fluid_set_log_function(int level,fluid_log_function_t fun,void * data)114 fluid_set_log_function(int level, fluid_log_function_t fun, void* data)
115 {
116   fluid_log_function_t old = NULL;
117 
118   if ((level >= 0) && (level < LAST_LOG_LEVEL)) {
119     old = fluid_log_function[level];
120     fluid_log_function[level] = fun;
121     fluid_log_user_data[level] = data;
122   }
123   return old;
124 }
125 
126 /**
127  * Default log function which prints to the stderr.
128  * @param level Log level
129  * @param message Log message
130  * @param data User supplied data (not used)
131  */
132 void
fluid_default_log_function(int level,char * message,void * data)133 fluid_default_log_function(int level, char* message, void* data)
134 {
135   FILE* out;
136 
137 #if defined(WIN32)
138   out = stdout;
139 #else
140   out = stderr;
141 #endif
142 
143   if (fluid_log_initialized == 0) {
144     fluid_log_config();
145   }
146 
147   switch (level) {
148   case FLUID_PANIC:
149     FLUID_FPRINTF(out, "%s: panic: %s\n", fluid_libname, message);
150     break;
151   case FLUID_ERR:
152     FLUID_FPRINTF(out, "%s: error: %s\n", fluid_libname, message);
153     break;
154   case FLUID_WARN:
155     FLUID_FPRINTF(out, "%s: warning: %s\n", fluid_libname, message);
156     break;
157   case FLUID_INFO:
158     FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
159     break;
160   case FLUID_DBG:
161 #if DEBUG
162     FLUID_FPRINTF(out, "%s: debug: %s\n", fluid_libname, message);
163 #endif
164     break;
165   default:
166     FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
167     break;
168   }
169   fflush(out);
170 }
171 
172 /*
173  * fluid_init_log
174  */
175 void
fluid_log_config(void)176 fluid_log_config(void)
177 {
178   if (fluid_log_initialized == 0) {
179 
180     fluid_log_initialized = 1;
181 
182     if (fluid_log_function[FLUID_PANIC] == NULL) {
183       fluid_set_log_function(FLUID_PANIC, fluid_default_log_function, NULL);
184     }
185 
186     if (fluid_log_function[FLUID_ERR] == NULL) {
187       fluid_set_log_function(FLUID_ERR, fluid_default_log_function, NULL);
188     }
189 
190     if (fluid_log_function[FLUID_WARN] == NULL) {
191       fluid_set_log_function(FLUID_WARN, fluid_default_log_function, NULL);
192     }
193 
194     if (fluid_log_function[FLUID_INFO] == NULL) {
195       fluid_set_log_function(FLUID_INFO, fluid_default_log_function, NULL);
196     }
197 
198     if (fluid_log_function[FLUID_DBG] == NULL) {
199       fluid_set_log_function(FLUID_DBG, fluid_default_log_function, NULL);
200     }
201   }
202 }
203 
204 /**
205  * Print a message to the log.
206  * @param level Log level (#fluid_log_level).
207  * @param fmt Printf style format string for log message
208  * @param ... Arguments for printf 'fmt' message string
209  * @return Always returns #FLUID_FAILED
210  */
211 int
fluid_log(int level,const char * fmt,...)212 fluid_log(int level, const char* fmt, ...)
213 {
214   fluid_log_function_t fun = NULL;
215 
216   va_list args;
217   va_start (args, fmt);
218   vsnprintf(fluid_errbuf, sizeof (fluid_errbuf), fmt, args);
219   va_end (args);
220 
221   if ((level >= 0) && (level < LAST_LOG_LEVEL)) {
222     fun = fluid_log_function[level];
223     if (fun != NULL) {
224       (*fun)(level, fluid_errbuf, fluid_log_user_data[level]);
225     }
226   }
227   return FLUID_FAILED;
228 }
229 
230 /**
231  * An improved strtok, still trashes the input string, but is portable and
232  * thread safe.  Also skips token chars at beginning of token string and never
233  * returns an empty token (will return NULL if source ends in token chars though).
234  * NOTE: NOT part of public API
235  * @internal
236  * @param str Pointer to a string pointer of source to tokenize.  Pointer gets
237  *   updated on each invocation to point to beginning of next token.  Note that
238  *   token char get's overwritten with a 0 byte.  String pointer is set to NULL
239  *   when final token is returned.
240  * @param delim String of delimiter chars.
241  * @return Pointer to the next token or NULL if no more tokens.
242  */
fluid_strtok(char ** str,char * delim)243 char *fluid_strtok (char **str, char *delim)
244 {
245   char *s, *d, *token;
246   char c;
247 
248   if (str == NULL || delim == NULL || !*delim)
249   {
250     FLUID_LOG(FLUID_ERR, "Null pointer");
251     return NULL;
252   }
253 
254   s = *str;
255   if (!s) return NULL;	/* str points to a NULL pointer? (tokenize already ended) */
256 
257   /* skip delimiter chars at beginning of token */
258   do
259   {
260     c = *s;
261     if (!c)	/* end of source string? */
262     {
263       *str = NULL;
264       return NULL;
265     }
266 
267     for (d = delim; *d; d++)	/* is source char a token char? */
268     {
269       if (c == *d)	/* token char match? */
270       {
271 	s++;		/* advance to next source char */
272 	break;
273       }
274     }
275   } while (*d);		/* while token char match */
276 
277   token = s;		/* start of token found */
278 
279   /* search for next token char or end of source string */
280   for (s = s+1; *s; s++)
281   {
282     c = *s;
283 
284     for (d = delim; *d; d++)	/* is source char a token char? */
285     {
286       if (c == *d)	/* token char match? */
287       {
288 	*s = '\0';	/* overwrite token char with zero byte to terminate token */
289 	*str = s+1;	/* update str to point to beginning of next token */
290 	return token;
291       }
292     }
293   }
294 
295   /* we get here only if source string ended */
296   *str = NULL;
297   return token;
298 }
299 
300 /*
301  * fluid_error
302  */
303 char*
fluid_error()304 fluid_error()
305 {
306   return fluid_errbuf;
307 }
308 
309 /**
310  * Check if a file is a MIDI file.
311  * @param filename Path to the file to check
312  * @return TRUE if it could be a MIDI file, FALSE otherwise
313  *
314  * The current implementation only checks for the "MThd" header in the file.
315  * It is useful only to distinguish between SoundFont and MIDI files.
316  */
317 int
fluid_is_midifile(const char * filename)318 fluid_is_midifile(const char *filename)
319 {
320   FILE* fp = fopen(filename, "rb");
321   char id[4];
322 
323   if (fp == NULL) {
324     return 0;
325   }
326   if (fread((void*) id, 1, 4, fp) != 4) {
327     fclose(fp);
328     return 0;
329   }
330   fclose(fp);
331 
332   return strncmp(id, "MThd", 4) == 0;
333 }
334 
335 /**
336  * Check if a file is a SoundFont file.
337  * @param filename Path to the file to check
338  * @return TRUE if it could be a SoundFont, FALSE otherwise
339  *
340  * The current implementation only checks for the "RIFF" header in the file.
341  * It is useful only to distinguish between SoundFont and MIDI files.
342  */
343 int
fluid_is_soundfont(const char * filename)344 fluid_is_soundfont(const char *filename)
345 {
346   FILE* fp = fopen(filename, "rb");
347   char id[4];
348 
349   if (fp == NULL) {
350     return 0;
351   }
352   if (fread((void*) id, 1, 4, fp) != 4) {
353     fclose(fp);
354     return 0;
355   }
356   fclose(fp);
357 
358   return strncmp(id, "RIFF", 4) == 0;
359 }
360 
361 /**
362  * Get time in milliseconds to be used in relative timing operations.
363  * @return Unix time in milliseconds.
364  */
365 unsigned int fluid_curtime(void);
366 
367 /**
368  * Get time in microseconds to be used in relative timing operations.
369  * @return Unix time in microseconds.
370  */
371 double
372 fluid_utime (void);
373 
374 #if HAVE_WINDOWS_H
375 
fluid_utime(void)376 double fluid_utime(void) {
377   LARGE_INTEGER freq;
378   if (QueryPerformanceFrequency(&freq)) {
379     LARGE_INTEGER time;
380     QueryPerformanceCounter(&time);
381     return (double)time.QuadPart / freq.QuadPart;
382   } else {
383     return (double)GetTickCount() / 1000.0;
384   }
385 }
386 
fluid_curtime(void)387 unsigned int fluid_curtime(void) { return fluid_utime() * 1000; }
388 
389 #else /* HAVE_WINDOWS_H */
390 
391 #ifdef __MACH__
392 #include <mach/clock.h>
393 #include <mach/mach.h>
394 
395 typedef mach_timespec_t timespec_type;
396 
get_timespec(timespec_type * tm)397 FLUID_INLINE void get_timespec(timespec_type* tm)
398 {
399   clock_serv_t cclock;
400   host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
401   clock_get_time(cclock, tm);
402   mach_port_deallocate(mach_task_self(), cclock);
403 }
404 
405 #else /* ifdef __MACH__ */
406 
407 typedef struct timespec timespec_type;
408 
get_timespec(timespec_type * tm)409 FLUID_INLINE void get_timespec(timespec_type* tm)
410 {
411   clock_gettime(CLOCK_MONOTONIC, tm);
412 }
413 
414 #endif /* ifdef __MACH__ */
415 
416 #define USEC(tm) ((tm).tv_nsec / 1000)
417 
fluid_curtime(void)418 unsigned int fluid_curtime(void)
419 {
420   static long initial_seconds = 0;
421   timespec_type timeval;
422 
423   if (initial_seconds == 0) {
424     get_timespec(&timeval);
425     initial_seconds = timeval.tv_sec;
426   }
427 
428   get_timespec(&timeval);
429 
430   return (unsigned int)((timeval.tv_sec - initial_seconds) * 1000.0 + USEC(timeval) / 1000.0);
431 }
432 
fluid_utime(void)433 double fluid_utime(void)
434 {
435   timespec_type timeval;
436 
437   get_timespec(&timeval);
438 
439   return (timeval.tv_sec * 1000000.0 + USEC(timeval));
440 }
441 
442 #endif /* HAVE_WINDOWS_H */
443 
444 
445 #if defined(WIN32)      /* Windoze specific stuff */
446 
447 void
fluid_thread_self_set_prio(int prio_level)448 fluid_thread_self_set_prio (int prio_level)
449 {
450   if (prio_level > 0)
451     SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
452 }
453 
454 
455 #elif defined(__OS2__)  /* OS/2 specific stuff */
456 
457 void
fluid_thread_self_set_prio(int prio_level)458 fluid_thread_self_set_prio (int prio_level)
459 {
460   if (prio_level > 0)
461     DosSetPriority (PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0);
462 }
463 
464 #else   /* POSIX stuff..  Nice POSIX..  Good POSIX. */
465 
466 void
fluid_thread_self_set_prio(int prio_level)467 fluid_thread_self_set_prio (int prio_level)
468 {
469   struct sched_param priority;
470 
471   if (prio_level > 0)
472   {
473 
474     memset(&priority, 0, sizeof(priority));
475     priority.sched_priority = prio_level;
476 
477     if (pthread_setschedparam (pthread_self (), SCHED_FIFO, &priority) == 0) {
478       return;
479     }
480     FLUID_LOG(FLUID_WARN, "Failed to set thread to high priority");
481   }
482 }
483 
484 #ifdef FPE_CHECK
485 
486 /***************************************************************
487  *
488  *               Floating point exceptions
489  *
490  *  The floating point exception functions were taken from Ircam's
491  *  jMax source code. http://www.ircam.fr/jmax
492  *
493  *  FIXME: check in config for i386 machine
494  *
495  *  Currently not used. I leave the code here in case we want to pick
496  *  this up again some time later.
497  */
498 
499 /* Exception flags */
500 #define _FPU_STATUS_IE    0x001  /* Invalid Operation */
501 #define _FPU_STATUS_DE    0x002  /* Denormalized Operand */
502 #define _FPU_STATUS_ZE    0x004  /* Zero Divide */
503 #define _FPU_STATUS_OE    0x008  /* Overflow */
504 #define _FPU_STATUS_UE    0x010  /* Underflow */
505 #define _FPU_STATUS_PE    0x020  /* Precision */
506 #define _FPU_STATUS_SF    0x040  /* Stack Fault */
507 #define _FPU_STATUS_ES    0x080  /* Error Summary Status */
508 
509 /* Macros for accessing the FPU status word.  */
510 
511 /* get the FPU status */
512 #define _FPU_GET_SW(sw) __asm__ ("fnstsw %0" : "=m" (*&sw))
513 
514 /* clear the FPU status */
515 #define _FPU_CLR_SW() __asm__ ("fnclex" : : )
516 
517 /* Purpose:
518  * Checks, if the floating point unit has produced an exception, print a message
519  * if so and clear the exception.
520  */
fluid_check_fpe_i386(char * explanation)521 unsigned int fluid_check_fpe_i386(char* explanation)
522 {
523   unsigned int s;
524 
525   _FPU_GET_SW(s);
526   _FPU_CLR_SW();
527 
528   s &= _FPU_STATUS_IE | _FPU_STATUS_DE | _FPU_STATUS_ZE | _FPU_STATUS_OE | _FPU_STATUS_UE;
529 
530   if (s)
531   {
532       FLUID_LOG(FLUID_WARN, "FPE exception (before or in %s): %s%s%s%s%s", explanation,
533 	       (s & _FPU_STATUS_IE) ? "Invalid operation " : "",
534 	       (s & _FPU_STATUS_DE) ? "Denormal number " : "",
535 	       (s & _FPU_STATUS_ZE) ? "Zero divide " : "",
536 	       (s & _FPU_STATUS_OE) ? "Overflow " : "",
537 	       (s & _FPU_STATUS_UE) ? "Underflow " : "");
538   }
539 
540   return s;
541 }
542 
543 /* Purpose:
544  * Clear floating point exception.
545  */
fluid_clear_fpe_i386(void)546 void fluid_clear_fpe_i386 (void)
547 {
548   _FPU_CLR_SW();
549 }
550 
551 #endif	// ifdef FPE_CHECK
552 
553 
554 #endif	// #else    (its POSIX)
555 
556 
557 /***************************************************************
558  *
559  *               Profiling (Linux, i586 only)
560  *
561  */
562 
563 #if WITH_PROFILING
564 
565 fluid_profile_data_t fluid_profile_data[] =
566 {
567   { FLUID_PROF_WRITE,            "fluid_synth_write_*             ", 1e10, 0.0, 0.0, 0},
568   { FLUID_PROF_ONE_BLOCK,        "fluid_synth_one_block           ", 1e10, 0.0, 0.0, 0},
569   { FLUID_PROF_ONE_BLOCK_CLEAR,  "fluid_synth_one_block:clear     ", 1e10, 0.0, 0.0, 0},
570   { FLUID_PROF_ONE_BLOCK_VOICE,  "fluid_synth_one_block:one voice ", 1e10, 0.0, 0.0, 0},
571   { FLUID_PROF_ONE_BLOCK_VOICES, "fluid_synth_one_block:all voices", 1e10, 0.0, 0.0, 0},
572   { FLUID_PROF_ONE_BLOCK_REVERB, "fluid_synth_one_block:reverb    ", 1e10, 0.0, 0.0, 0},
573   { FLUID_PROF_ONE_BLOCK_CHORUS, "fluid_synth_one_block:chorus    ", 1e10, 0.0, 0.0, 0},
574   { FLUID_PROF_VOICE_NOTE,       "fluid_voice:note                ", 1e10, 0.0, 0.0, 0},
575   { FLUID_PROF_VOICE_RELEASE,    "fluid_voice:release             ", 1e10, 0.0, 0.0, 0},
576   { FLUID_PROF_LAST, "last", 1e100, 0.0, 0.0, 0}
577 };
578 
579 
fluid_profiling_print(void)580 void fluid_profiling_print(void)
581 {
582   int i;
583 
584   printf("fluid_profiling_print\n");
585 
586   FLUID_LOG(FLUID_INFO, "Estimated times: min/avg/max (micro seconds)");
587 
588   for (i = 0; i < FLUID_PROF_LAST; i++) {
589     if (fluid_profile_data[i].count > 0) {
590       FLUID_LOG(FLUID_INFO, "%s: %.3f/%.3f/%.3f",
591 	       fluid_profile_data[i].description,
592 	       fluid_profile_data[i].min,
593 	       fluid_profile_data[i].total / fluid_profile_data[i].count,
594 	       fluid_profile_data[i].max);
595     } else {
596       FLUID_LOG(FLUID_DBG, "%s: no profiling available", fluid_profile_data[i].description);
597     }
598   }
599 }
600 
601 
602 #endif /* WITH_PROFILING */
603 
604 
605 
606 /***************************************************************
607  *
608  *               Threads
609  *
610  */
611 
612 static
613 #if HAVE_WINDOWS_H
614 DWORD __stdcall
615 #else
616 void*
617 #endif
fluid_thread_func(void * data)618 fluid_thread_func (void* data)
619 {
620   fluid_thread_info_t *info = data;
621 
622   info->func (info->data);
623   FLUID_FREE (info);
624 
625 #if HAVE_WINDOWS_H
626   return 0;
627 #else
628   return NULL;
629 #endif
630 }
631 
632 /**
633  * Create a new thread.
634  * @param func Function to execute in new thread context
635  * @param data User defined data to pass to func
636  * @param prio_level Priority level.  If greater than 0 then high priority scheduling will
637  *   be used, with the given priority level (used by pthreads only).  0 uses normal scheduling.
638  * @param detach If TRUE, 'join' does not work and the thread destroys itself when finished.
639  * @return New thread pointer or NULL on error
640  */
641 fluid_thread_t *
new_fluid_thread(const char * name,fluid_thread_func_t func,void * data,int prio_level,int detach)642 new_fluid_thread (const char *name, fluid_thread_func_t func, void *data, int prio_level, int detach)
643 {
644   fluid_thread_t *thread;
645   fluid_thread_info_t *info;
646   int err;
647 
648   fluid_return_val_if_fail (func != NULL, NULL);
649 
650   info = FLUID_NEW (fluid_thread_info_t);
651 
652   if (!info)
653   {
654     FLUID_LOG(FLUID_ERR, "Out of memory");
655     return NULL;
656   }
657 
658   info->func = func;
659   info->data = data;
660 
661 #if HAVE_WINDOWS_H
662 
663   thread = FLUID_NEW(HANDLE);
664   if (thread == NULL) {
665     FLUID_LOG(FLUID_ERR, "Memory allocation failed");
666     return NULL;
667   }
668 
669   *thread = CreateThread(NULL, 0, fluid_thread_func, info, CREATE_SUSPENDED, NULL);
670   if (*thread == NULL)
671   {
672     FLUID_LOG(FLUID_ERR, "Failed to create thread");
673     return NULL;
674   }
675 
676   err = SetThreadPriority(*thread, THREAD_PRIORITY_ABOVE_NORMAL);
677   if (err == 0) {
678     FLUID_LOG(FLUID_ERR, "Failed to set thread priority");
679   }
680 
681   err = ResumeThread(*thread);
682   if (err == -1) {
683     FLUID_LOG(FLUID_ERR, "Failed to resume thread after creation");
684     return NULL;
685   }
686 
687   if (detach) {
688     err = CloseHandle(*thread);
689     if (err == 0)
690       FLUID_LOG(FLUID_ERR, "Failed to detach thread after creation");
691   }
692 
693 #else
694 
695   pthread_attr_t attr;
696   struct sched_param sched_param;
697 
698   err = pthread_attr_init (&attr);
699   if (err)
700   {
701     FLUID_LOG(FLUID_ERR, "Failed to initialize pthread attributes: %s", strerror(err));
702     return NULL;
703   }
704 
705   err = pthread_attr_setschedpolicy (&attr, SCHED_FIFO);
706 
707   pthread_attr_getschedparam (&attr, &sched_param);
708   sched_param.sched_priority = prio_level > 0 ? 1 : 0;
709 
710   if (!err)
711   {
712     err = pthread_attr_setschedparam (&attr, &sched_param);
713   }
714 
715   if (err)
716   {
717     FLUID_LOG(FLUID_ERR, "Failed to set pthread attributes: %s", strerror(err));
718     return NULL;
719   }
720 
721   thread = FLUID_NEW (fluid_thread_t);
722 
723   err = pthread_create (thread, &attr, fluid_thread_func, info);
724   if (err)
725   {
726     FLUID_LOG(FLUID_ERR, "Failed to create the thread: %s", strerror(err));
727     return NULL;
728   }
729 
730   if (detach)
731   {
732     err = pthread_detach (*thread);
733     if (err) {
734       FLUID_LOG(FLUID_ERR, "Failed to detach the thread: %s", strerror(err));
735       return NULL;
736     }
737   }
738 
739 #endif
740 
741   return thread;
742 }
743 
744 /**
745  * Frees data associated with a thread (does not actually stop thread).
746  * @param thread Thread to free
747  */
748 void
delete_fluid_thread(fluid_thread_t * thread)749 delete_fluid_thread(fluid_thread_t* thread)
750 {
751 #if HAVE_WINDOWS_H
752   WaitForSingleObject(*thread, INFINITE);
753 #else
754   pthread_join (*thread, NULL);
755 #endif
756 
757   free(thread);
758 }
759 
760 /**
761  * Join a thread (wait for it to terminate).
762  * @param thread Thread to join
763  * @return FLUID_OK
764  */
765 int
fluid_thread_join(fluid_thread_t * thread)766 fluid_thread_join(fluid_thread_t* thread)
767 {
768 #if HAVE_WINDOWS_H
769 
770   if (WaitForSingleObject (*thread, INFINITE) == WAIT_FAILED)
771   {
772     return FLUID_FAILED;
773   }
774   else
775   {
776     return FLUID_OK;
777   }
778 
779 #else
780 
781   if (pthread_join (*thread, NULL))
782   {
783     return FLUID_FAILED;
784   }
785   else {
786     return FLUID_OK;
787   }
788 
789 #endif
790 }
791 
792 
793 void
fluid_timer_run(void * data)794 fluid_timer_run (void *data)
795 {
796   fluid_timer_t *timer;
797   int count = 0;
798   int cont;
799   long start;
800   long delay;
801 
802   timer = (fluid_timer_t *)data;
803 
804   /* keep track of the start time for absolute positioning */
805   start = fluid_curtime ();
806 
807   while (timer->cont)
808   {
809     cont = (*timer->callback)(timer->data, fluid_curtime() - start);
810 
811     count++;
812     if (!cont) break;
813 
814     /* to avoid incremental time errors, calculate the delay between
815        two callbacks bringing in the "absolute" time (count *
816        timer->msec) */
817     delay = (count * timer->msec) - (fluid_curtime() - start);
818     if (delay > 0) fluid_sleep (delay);
819   }
820 
821   FLUID_LOG (FLUID_DBG, "Timer thread finished");
822 
823   if (timer->auto_destroy)
824     FLUID_FREE (timer);
825 
826   return;
827 }
828 
829 fluid_timer_t*
new_fluid_timer(int msec,fluid_timer_callback_t callback,void * data,int new_thread,int auto_destroy,int high_priority)830 new_fluid_timer (int msec, fluid_timer_callback_t callback, void* data,
831                  int new_thread, int auto_destroy, int high_priority)
832 {
833   fluid_timer_t *timer;
834 
835   timer = FLUID_NEW (fluid_timer_t);
836 
837   if (timer == NULL)
838   {
839     FLUID_LOG (FLUID_ERR, "Out of memory");
840     return NULL;
841   }
842 
843   timer->msec = msec;
844   timer->callback = callback;
845   timer->data = data;
846   timer->cont = TRUE ;
847   timer->thread = NULL;
848   timer->auto_destroy = auto_destroy;
849 
850   if (new_thread)
851   {
852     timer->thread = new_fluid_thread ("timer", fluid_timer_run, timer, high_priority
853                                       ? FLUID_SYS_TIMER_HIGH_PRIO_LEVEL : 0, FALSE);
854     if (!timer->thread)
855     {
856       FLUID_FREE (timer);
857       return NULL;
858     }
859   }
860   else fluid_timer_run (timer);  /* Run directly, instead of as a separate thread */
861 
862   return timer;
863 }
864 
865 int
delete_fluid_timer(fluid_timer_t * timer)866 delete_fluid_timer (fluid_timer_t *timer)
867 {
868   int auto_destroy = timer->auto_destroy;
869 
870   timer->cont = 0;
871   fluid_timer_join (timer);
872 
873   /* Shouldn't access timer now if auto_destroy enabled, since it has been destroyed */
874 
875   if (!auto_destroy) FLUID_FREE (timer);
876 
877   return FLUID_OK;
878 }
879 
880 int
fluid_timer_join(fluid_timer_t * timer)881 fluid_timer_join (fluid_timer_t *timer)
882 {
883   int auto_destroy;
884 
885   if (timer->thread)
886   {
887     auto_destroy = timer->auto_destroy;
888     fluid_thread_join (timer->thread);
889 
890     if (!auto_destroy) timer->thread = NULL;
891   }
892 
893   return FLUID_OK;
894 }
895 
896 
897 /***************************************************************
898  *
899  *               Sockets and I/O
900  *
901  */
902 
903 /**
904  * Get standard in stream handle.
905  * @return Standard in stream.
906  */
907 fluid_istream_t
fluid_get_stdin(void)908 fluid_get_stdin (void)
909 {
910   return STDIN_FILENO;
911 }
912 
913 /**
914  * Get standard output stream handle.
915  * @return Standard out stream.
916  */
917 fluid_ostream_t
fluid_get_stdout(void)918 fluid_get_stdout (void)
919 {
920   return STDOUT_FILENO;
921 }
922 
923 /**
924  * Read a line from an input stream.
925  * @return 0 if end-of-stream, -1 if error, non zero otherwise
926  */
927 int
fluid_istream_readline(fluid_istream_t in,fluid_ostream_t out,char * prompt,char * buf,int len)928 fluid_istream_readline (fluid_istream_t in, fluid_ostream_t out, char* prompt,
929                         char* buf, int len)
930 {
931 #if WITH_READLINE
932   if (in == fluid_get_stdin ())
933   {
934     char *line;
935 
936     line = readline (prompt);
937 
938     if (line == NULL)
939       return -1;
940 
941     snprintf(buf, len, "%s", line);
942     buf[len - 1] = 0;
943 
944     free(line);
945     return 1;
946   }
947   else
948 #endif
949   {
950     fluid_ostream_printf (out, "%s", prompt);
951     return fluid_istream_gets (in, buf, len);
952   }
953 }
954 
955 /**
956  * Reads a line from an input stream (socket).
957  * @param in The input socket
958  * @param buf Buffer to store data to
959  * @param len Maximum length to store to buf
960  * @return 1 if a line was read, 0 on end of stream, -1 on error
961  */
962 static int
fluid_istream_gets(fluid_istream_t in,char * buf,int len)963 fluid_istream_gets (fluid_istream_t in, char* buf, int len)
964 {
965   char c;
966   int n;
967 
968   buf[len - 1] = 0;
969 
970   while (--len > 0)
971   {
972 #ifndef WIN32
973     n = read(in, &c, 1);
974     if (n == -1) return -1;
975 #else
976     /* Handle read differently depending on if its a socket or file descriptor */
977     if (!(in & WIN32_SOCKET_FLAG))
978     {
979       n = read(in, &c, 1);
980       if (n == -1) return -1;
981     }
982     else
983     {
984       n = recv(in & ~WIN32_SOCKET_FLAG, &c, 1, 0);
985       if (n == SOCKET_ERROR) return -1;
986     }
987 #endif
988 
989     if (n == 0)
990     {
991       *buf++ = 0;
992       return 0;
993     }
994 
995     if ((c == '\n'))
996     {
997       *buf++ = 0;
998       return 1;
999     }
1000 
1001     /* Store all characters excluding CR */
1002     if (c != '\r') *buf++ = c;
1003   }
1004 
1005   return -1;
1006 }
1007 
1008 /**
1009  * Send a printf style string with arguments to an output stream (socket).
1010  * @param out Output stream
1011  * @param format printf style format string
1012  * @param ... Arguments for the printf format string
1013  * @return Number of bytes written or -1 on error
1014  */
1015 int
fluid_ostream_printf(fluid_ostream_t out,char * format,...)1016 fluid_ostream_printf (fluid_ostream_t out, char* format, ...)
1017 {
1018   char buf[4096];
1019   va_list args;
1020   int len;
1021 
1022   va_start (args, format);
1023   len = vsnprintf (buf, 4095, format, args);
1024   va_end (args);
1025 
1026   if (len == 0)
1027   {
1028     return 0;
1029   }
1030 
1031   if (len < 0)
1032   {
1033     printf("fluid_ostream_printf: buffer overflow");
1034     return -1;
1035   }
1036 
1037   buf[4095] = 0;
1038 
1039 #ifndef WIN32
1040   return write (out, buf, strlen (buf));
1041 #else
1042   {
1043     int retval;
1044 
1045     /* Handle write differently depending on if its a socket or file descriptor */
1046     if (!(out & WIN32_SOCKET_FLAG))
1047       return write(out, buf, strlen (buf));
1048 
1049     /* Socket */
1050     retval = send (out & ~WIN32_SOCKET_FLAG, buf, strlen (buf), 0);
1051 
1052     return retval != SOCKET_ERROR ? retval : -1;
1053   }
1054 #endif
1055 }
1056 
fluid_server_socket_join(fluid_server_socket_t * server_socket)1057 int fluid_server_socket_join(fluid_server_socket_t *server_socket)
1058 {
1059   return fluid_thread_join (server_socket->thread);
1060 }
1061 
1062 
1063 #ifndef WIN32           // Not win32?
1064 
1065 #define SOCKET_ERROR -1
1066 
fluid_socket_get_istream(fluid_socket_t sock)1067 fluid_istream_t fluid_socket_get_istream (fluid_socket_t sock)
1068 {
1069   return sock;
1070 }
1071 
fluid_socket_get_ostream(fluid_socket_t sock)1072 fluid_ostream_t fluid_socket_get_ostream (fluid_socket_t sock)
1073 {
1074   return sock;
1075 }
1076 
fluid_socket_close(fluid_socket_t sock)1077 void fluid_socket_close(fluid_socket_t sock)
1078 {
1079   if (sock != INVALID_SOCKET)
1080     close (sock);
1081 }
1082 
1083 static void
fluid_server_socket_run(void * data)1084 fluid_server_socket_run (void *data)
1085 {
1086   fluid_server_socket_t *server_socket = (fluid_server_socket_t *)data;
1087   fluid_socket_t client_socket;
1088 #ifdef IPV6
1089   struct sockaddr_in6 addr;
1090   char straddr[INET6_ADDRSTRLEN];
1091 #else
1092   struct sockaddr_in addr;
1093   char straddr[INET_ADDRSTRLEN];
1094 #endif
1095   socklen_t addrlen = sizeof (addr);
1096   int retval;
1097   FLUID_MEMSET((char *)&addr, 0, sizeof(addr));
1098 
1099   FLUID_LOG (FLUID_DBG, "Server listening for connections");
1100 
1101   while (server_socket->cont)
1102   {
1103     client_socket = accept (server_socket->socket, (struct sockaddr *)&addr, &addrlen);
1104 
1105     FLUID_LOG (FLUID_DBG, "New client connection");
1106 
1107     if (client_socket == INVALID_SOCKET)
1108     {
1109       if (server_socket->cont)
1110 	FLUID_LOG(FLUID_ERR, "Failed to accept connection");
1111 
1112       server_socket->cont = 0;
1113       return;
1114     } else {
1115 #ifdef IPV6
1116       inet_ntop(AF_INET6, &addr.sin6_addr, straddr, sizeof(straddr));
1117 #else
1118       inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr));
1119 #endif
1120       retval = server_socket->func (server_socket->data, client_socket,
1121                                     straddr);
1122 
1123       if (retval != 0)
1124 	fluid_socket_close(client_socket);
1125     }
1126   }
1127 
1128   FLUID_LOG(FLUID_DBG, "Server closing");
1129 }
1130 
1131 fluid_server_socket_t*
new_fluid_server_socket(int port,fluid_server_func_t func,void * data)1132 new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
1133 {
1134   fluid_server_socket_t* server_socket;
1135 #ifdef IPV6
1136   struct sockaddr_in6 addr;
1137 #else
1138   struct sockaddr_in addr;
1139 #endif
1140   fluid_socket_t sock;
1141 
1142   fluid_return_val_if_fail (func != NULL, NULL);
1143 #ifdef IPV6
1144   sock = socket(AF_INET6, SOCK_STREAM, 0);
1145   if (sock == INVALID_SOCKET) {
1146     FLUID_LOG(FLUID_ERR, "Failed to create server socket");
1147     return NULL;
1148   }
1149 
1150   FLUID_MEMSET((char *)&addr, 0, sizeof(struct sockaddr_in6));
1151   addr.sin6_family = AF_INET6;
1152   addr.sin6_addr = in6addr_any;
1153   addr.sin6_port = htons(port);
1154 #else
1155 
1156   sock = socket(AF_INET, SOCK_STREAM, 0);
1157   if (sock == INVALID_SOCKET) {
1158     FLUID_LOG(FLUID_ERR, "Failed to create server socket");
1159     return NULL;
1160   }
1161 
1162   FLUID_MEMSET((char *)&addr, 0, sizeof(struct sockaddr_in));
1163   addr.sin_family = AF_INET;
1164   addr.sin_addr.s_addr = htonl(INADDR_ANY);
1165   addr.sin_port = htons(port);
1166 #endif
1167   if (bind(sock, (const struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR) {
1168     FLUID_LOG(FLUID_ERR, "Failed to bind server socket");
1169     fluid_socket_close(sock);
1170     return NULL;
1171   }
1172 
1173   if (listen(sock, 10) == SOCKET_ERROR) {
1174     FLUID_LOG(FLUID_ERR, "Failed listen on server socket");
1175     fluid_socket_close(sock);
1176     return NULL;
1177   }
1178 
1179   server_socket = FLUID_NEW(fluid_server_socket_t);
1180   if (server_socket == NULL) {
1181     FLUID_LOG(FLUID_ERR, "Out of memory");
1182     fluid_socket_close(sock);
1183     return NULL;
1184   }
1185 
1186   server_socket->socket = sock;
1187   server_socket->func = func;
1188   server_socket->data = data;
1189   server_socket->cont = 1;
1190 
1191   server_socket->thread = new_fluid_thread("server", fluid_server_socket_run, server_socket,
1192                                            0, FALSE);
1193   if (server_socket->thread == NULL) {
1194     FLUID_FREE(server_socket);
1195     fluid_socket_close(sock);
1196     return NULL;
1197   }
1198 
1199   return server_socket;
1200 }
1201 
delete_fluid_server_socket(fluid_server_socket_t * server_socket)1202 int delete_fluid_server_socket(fluid_server_socket_t* server_socket)
1203 {
1204   server_socket->cont = 0;
1205   if (server_socket->socket != INVALID_SOCKET) {
1206     fluid_socket_close(server_socket->socket);
1207   }
1208   if (server_socket->thread) {
1209     delete_fluid_thread(server_socket->thread);
1210   }
1211   FLUID_FREE(server_socket);
1212   return FLUID_OK;
1213 }
1214 
1215 
1216 #else           // Win32 is "special"
1217 
1218 
1219 #ifndef WIN32_LEAN_AND_MEAN
1220 #define WIN32_LEAN_AND_MEAN
1221 #endif
1222 
fluid_socket_get_istream(fluid_socket_t sock)1223 fluid_istream_t fluid_socket_get_istream (fluid_socket_t sock)
1224 {
1225   return sock | WIN32_SOCKET_FLAG;
1226 }
1227 
fluid_socket_get_ostream(fluid_socket_t sock)1228 fluid_ostream_t fluid_socket_get_ostream (fluid_socket_t sock)
1229 {
1230   return sock | WIN32_SOCKET_FLAG;
1231 }
1232 
fluid_socket_close(fluid_socket_t sock)1233 void fluid_socket_close (fluid_socket_t sock)
1234 {
1235   if (sock != INVALID_SOCKET)
1236     closesocket (sock);
1237 }
1238 
fluid_server_socket_run(void * data)1239 static void fluid_server_socket_run (void *data)
1240 {
1241   fluid_server_socket_t *server_socket = (fluid_server_socket_t *)data;
1242   fluid_socket_t client_socket;
1243 #ifdef IPV6
1244   struct sockaddr_in6 addr;
1245   char straddr[INET6_ADDRSTRLEN];
1246 #else
1247   struct sockaddr_in addr;
1248   char straddr[INET_ADDRSTRLEN];
1249 #endif
1250   socklen_t addrlen = sizeof (addr);
1251   int r;
1252   FLUID_MEMSET((char *)&addr, 0, sizeof(addr));
1253 
1254   FLUID_LOG(FLUID_DBG, "Server listening for connections");
1255 
1256   while (server_socket->cont)
1257   {
1258     client_socket = accept (server_socket->socket, (struct sockaddr *)&addr, &addrlen);
1259 
1260     FLUID_LOG (FLUID_DBG, "New client connection");
1261 
1262     if (client_socket == INVALID_SOCKET)
1263     {
1264       if (server_socket->cont)
1265 	FLUID_LOG (FLUID_ERR, "Failed to accept connection: %ld", WSAGetLastError ());
1266 
1267       server_socket->cont = 0;
1268       return;
1269     }
1270     else
1271     {
1272 #ifdef IPV6
1273       inet_ntop(AF_INET6, &addr.sin6_addr, straddr, sizeof(straddr));
1274 #else
1275       inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr));
1276 #endif
1277       r = server_socket->func (server_socket->data, client_socket,
1278                                straddr);
1279       if (r != 0)
1280 	fluid_socket_close (client_socket);
1281     }
1282   }
1283 
1284   FLUID_LOG (FLUID_DBG, "Server closing");
1285 }
1286 
1287 fluid_server_socket_t*
new_fluid_server_socket(int port,fluid_server_func_t func,void * data)1288 new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
1289 {
1290   fluid_server_socket_t* server_socket;
1291 #ifdef IPV6
1292   struct sockaddr_in6 addr;
1293 #else
1294   struct sockaddr_in addr;
1295 #endif
1296 
1297   fluid_socket_t sock;
1298   WSADATA wsaData;
1299   int retval;
1300 
1301   fluid_return_val_if_fail (func != NULL, NULL);
1302 
1303   // Win32 requires initialization of winsock
1304   retval = WSAStartup (MAKEWORD (2,2), &wsaData);
1305 
1306   if (retval != 0)
1307   {
1308     FLUID_LOG(FLUID_ERR, "Server socket creation error: WSAStartup failed: %d", retval);
1309     return NULL;
1310   }
1311 #ifdef IPV6
1312   sock = socket (AF_INET6, SOCK_STREAM, 0);
1313   if (sock == INVALID_SOCKET)
1314   {
1315     FLUID_LOG (FLUID_ERR, "Failed to create server socket: %ld", WSAGetLastError ());
1316     WSACleanup ();
1317     return NULL;
1318   }
1319   addr.sin6_family = AF_INET6;
1320   addr.sin6_port = htons (port);
1321   addr.sin6_addr = in6addr_any;
1322 #else
1323 
1324   sock = socket (AF_INET, SOCK_STREAM, 0);
1325 
1326   if (sock == INVALID_SOCKET)
1327   {
1328     FLUID_LOG (FLUID_ERR, "Failed to create server socket: %ld", WSAGetLastError ());
1329     WSACleanup ();
1330     return NULL;
1331   }
1332 
1333   addr.sin_family = AF_INET;
1334   addr.sin_port = htons (port);
1335   addr.sin_addr.s_addr = htonl (INADDR_ANY);
1336 #endif
1337   retval = bind (sock, (struct sockaddr *)&addr, sizeof (addr));
1338 
1339   if (retval == SOCKET_ERROR)
1340   {
1341     FLUID_LOG (FLUID_ERR, "Failed to bind server socket: %ld", WSAGetLastError ());
1342     fluid_socket_close (sock);
1343     WSACleanup ();
1344     return NULL;
1345   }
1346 
1347   if (listen (sock, SOMAXCONN) == SOCKET_ERROR)
1348   {
1349     FLUID_LOG (FLUID_ERR, "Failed to listen on server socket: %ld", WSAGetLastError ());
1350     fluid_socket_close (sock);
1351     WSACleanup ();
1352     return NULL;
1353   }
1354 
1355   server_socket = FLUID_NEW (fluid_server_socket_t);
1356 
1357   if (server_socket == NULL)
1358   {
1359     FLUID_LOG (FLUID_ERR, "Out of memory");
1360     fluid_socket_close (sock);
1361     WSACleanup ();
1362     return NULL;
1363   }
1364 
1365   server_socket->socket = sock;
1366   server_socket->func = func;
1367   server_socket->data = data;
1368   server_socket->cont = 1;
1369 
1370   server_socket->thread = new_fluid_thread("server", fluid_server_socket_run, server_socket,
1371                                            0, FALSE);
1372   if (server_socket->thread == NULL)
1373   {
1374     FLUID_FREE (server_socket);
1375     fluid_socket_close (sock);
1376     WSACleanup ();
1377     return NULL;
1378   }
1379 
1380   return server_socket;
1381 }
1382 
delete_fluid_server_socket(fluid_server_socket_t * server_socket)1383 int delete_fluid_server_socket(fluid_server_socket_t *server_socket)
1384 {
1385   server_socket->cont = 0;
1386 
1387   if (server_socket->socket != INVALID_SOCKET)
1388     fluid_socket_close (server_socket->socket);
1389 
1390   if (server_socket->thread)
1391     delete_fluid_thread (server_socket->thread);
1392 
1393   FLUID_FREE (server_socket);
1394 
1395   WSACleanup ();        // Should be called the same number of times as WSAStartup
1396 
1397   return FLUID_OK;
1398 }
1399 
1400 #endif
1401