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