1 /* FluidSynth - A Software Synthesizer
3 * Copyright (C) 2003 Peter Hanappe and others.
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.
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.
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
21 #include "fluid_sys.h"
25 #include <readline/readline.h>
26 #include <readline/history.h>
30 #include "fluid_rtkit.h"
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 #define WIN32_SOCKET_FLAG 0x40000000
37 /* SCHED_FIFO priority for high priority timer threads */
38 #define FLUID_SYS_TIMER_HIGH_PRIO_LEVEL 10
43 fluid_thread_func_t func;
46 } fluid_thread_info_t;
51 fluid_timer_callback_t callback;
53 fluid_thread_t *thread;
58 struct _fluid_server_socket_t
60 fluid_socket_t socket;
61 fluid_thread_t *thread;
63 fluid_server_func_t func;
68 static int fluid_istream_gets(fluid_istream_t in, char* buf, int len);
71 static char fluid_errbuf[512]; /* buffer for error message */
73 static fluid_log_function_t fluid_log_function[LAST_LOG_LEVEL];
74 static void* fluid_log_user_data[LAST_LOG_LEVEL];
75 static int fluid_log_initialized = 0;
77 static char* fluid_libname = "fluidsynth";
80 void fluid_sys_config()
86 unsigned int fluid_debug_flags = 0;
92 int fluid_debug(int level, char * fmt, ...)
94 if (fluid_debug_flags & level) {
95 fluid_log_function_t fun;
99 vsnprintf(fluid_errbuf, sizeof (fluid_errbuf), fmt, args);
102 fun = fluid_log_function[FLUID_DBG];
104 (*fun)(level, fluid_errbuf, fluid_log_user_data[FLUID_DBG]);
112 * Installs a new log function for a specified log level.
113 * @param level Log level to install handler for.
114 * @param fun Callback function handler to call for logged messages
115 * @param data User supplied data pointer to pass to log function
116 * @return The previously installed function.
119 fluid_set_log_function(int level, fluid_log_function_t fun, void* data)
121 fluid_log_function_t old = NULL;
123 if ((level >= 0) && (level < LAST_LOG_LEVEL)) {
124 old = fluid_log_function[level];
125 fluid_log_function[level] = fun;
126 fluid_log_user_data[level] = data;
132 * Default log function which prints to the stderr.
133 * @param level Log level
134 * @param message Log message
135 * @param data User supplied data (not used)
138 fluid_default_log_function(int level, char* message, void* data)
148 if (fluid_log_initialized == 0) {
154 FLUID_FPRINTF(out, "%s: panic: %s\n", fluid_libname, message);
157 FLUID_FPRINTF(out, "%s: error: %s\n", fluid_libname, message);
160 FLUID_FPRINTF(out, "%s: warning: %s\n", fluid_libname, message);
163 FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
167 FLUID_FPRINTF(out, "%s: debug: %s\n", fluid_libname, message);
171 FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
181 fluid_log_config(void)
183 if (fluid_log_initialized == 0) {
185 fluid_log_initialized = 1;
187 if (fluid_log_function[FLUID_PANIC] == NULL) {
188 fluid_set_log_function(FLUID_PANIC, fluid_default_log_function, NULL);
191 if (fluid_log_function[FLUID_ERR] == NULL) {
192 fluid_set_log_function(FLUID_ERR, fluid_default_log_function, NULL);
195 if (fluid_log_function[FLUID_WARN] == NULL) {
196 fluid_set_log_function(FLUID_WARN, fluid_default_log_function, NULL);
199 if (fluid_log_function[FLUID_INFO] == NULL) {
200 fluid_set_log_function(FLUID_INFO, fluid_default_log_function, NULL);
203 if (fluid_log_function[FLUID_DBG] == NULL) {
204 fluid_set_log_function(FLUID_DBG, fluid_default_log_function, NULL);
210 * Print a message to the log.
211 * @param level Log level (#fluid_log_level).
212 * @param fmt Printf style format string for log message
213 * @param ... Arguments for printf 'fmt' message string
214 * @return Always returns #FLUID_FAILED
217 fluid_log(int level, const char* fmt, ...)
219 fluid_log_function_t fun = NULL;
222 va_start (args, fmt);
223 vsnprintf(fluid_errbuf, sizeof (fluid_errbuf), fmt, args);
226 if ((level >= 0) && (level < LAST_LOG_LEVEL)) {
227 fun = fluid_log_function[level];
229 (*fun)(level, fluid_errbuf, fluid_log_user_data[level]);
236 * An improved strtok, still trashes the input string, but is portable and
237 * thread safe. Also skips token chars at beginning of token string and never
238 * returns an empty token (will return NULL if source ends in token chars though).
239 * NOTE: NOT part of public API
241 * @param str Pointer to a string pointer of source to tokenize. Pointer gets
242 * updated on each invocation to point to beginning of next token. Note that
243 * token char get's overwritten with a 0 byte. String pointer is set to NULL
244 * when final token is returned.
245 * @param delim String of delimiter chars.
246 * @return Pointer to the next token or NULL if no more tokens.
248 char *fluid_strtok (char **str, char *delim)
253 if (str == NULL || delim == NULL || !*delim)
255 FLUID_LOG(FLUID_ERR, "Null pointer");
260 if (!s) return NULL; /* str points to a NULL pointer? (tokenize already ended) */
262 /* skip delimiter chars at beginning of token */
266 if (!c) /* end of source string? */
272 for (d = delim; *d; d++) /* is source char a token char? */
274 if (c == *d) /* token char match? */
276 s++; /* advance to next source char */
280 } while (*d); /* while token char match */
282 token = s; /* start of token found */
284 /* search for next token char or end of source string */
285 for (s = s+1; *s; s++)
289 for (d = delim; *d; d++) /* is source char a token char? */
291 if (c == *d) /* token char match? */
293 *s = '\0'; /* overwrite token char with zero byte to terminate token */
294 *str = s+1; /* update str to point to beginning of next token */
300 /* we get here only if source string ended */
315 * Check if a file is a MIDI file.
316 * @param filename Path to the file to check
317 * @return TRUE if it could be a MIDI file, FALSE otherwise
319 * The current implementation only checks for the "MThd" header in the file.
320 * It is useful only to distinguish between SoundFont and MIDI files.
323 fluid_is_midifile(const char *filename)
325 FILE* fp = fopen(filename, "rb");
331 if (fread((void*) id, 1, 4, fp) != 4) {
337 return strncmp(id, "MThd", 4) == 0;
341 * Check if a file is a SoundFont file.
342 * @param filename Path to the file to check
343 * @return TRUE if it could be a SoundFont, FALSE otherwise
345 * The current implementation only checks for the "RIFF" header in the file.
346 * It is useful only to distinguish between SoundFont and MIDI files.
349 fluid_is_soundfont(const char *filename)
351 FILE* fp = fopen(filename, "rb");
357 if (fread((void*) id, 1, 4, fp) != 4) {
363 return strncmp(id, "RIFF", 4) == 0;
367 * Get time in milliseconds to be used in relative timing operations.
368 * @return Unix time in milliseconds.
370 unsigned int fluid_curtime(void)
372 static glong initial_seconds = 0;
375 if (initial_seconds == 0) {
376 g_get_current_time (&timeval);
377 initial_seconds = timeval.tv_sec;
380 g_get_current_time (&timeval);
382 return (unsigned int)((timeval.tv_sec - initial_seconds) * 1000.0 + timeval.tv_usec / 1000.0);
386 * Get time in microseconds to be used in relative timing operations.
387 * @return Unix time in microseconds.
394 g_get_current_time (&timeval);
396 return (timeval.tv_sec * 1000000.0 + timeval.tv_usec);
400 #if defined(WIN32) /* Windoze specific stuff */
403 fluid_thread_self_set_prio (int prio_level)
406 SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
410 #elif defined(__OS2__) /* OS/2 specific stuff */
413 fluid_thread_self_set_prio (int prio_level)
416 DosSetPriority (PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0);
419 #else /* POSIX stuff.. Nice POSIX.. Good POSIX. */
422 fluid_thread_self_set_prio (int prio_level)
424 struct sched_param priority;
429 memset(&priority, 0, sizeof(priority));
430 priority.sched_priority = prio_level;
432 if (pthread_setschedparam (pthread_self (), SCHED_FIFO, &priority) == 0) {
436 /* Try to gain high priority via rtkit */
438 if (fluid_rtkit_make_realtime(0, prio_level) == 0) {
442 FLUID_LOG(FLUID_WARN, "Failed to set thread to high priority");
448 /***************************************************************
450 * Floating point exceptions
452 * The floating point exception functions were taken from Ircam's
453 * jMax source code. http://www.ircam.fr/jmax
455 * FIXME: check in config for i386 machine
457 * Currently not used. I leave the code here in case we want to pick
458 * this up again some time later.
461 /* Exception flags */
462 #define _FPU_STATUS_IE 0x001 /* Invalid Operation */
463 #define _FPU_STATUS_DE 0x002 /* Denormalized Operand */
464 #define _FPU_STATUS_ZE 0x004 /* Zero Divide */
465 #define _FPU_STATUS_OE 0x008 /* Overflow */
466 #define _FPU_STATUS_UE 0x010 /* Underflow */
467 #define _FPU_STATUS_PE 0x020 /* Precision */
468 #define _FPU_STATUS_SF 0x040 /* Stack Fault */
469 #define _FPU_STATUS_ES 0x080 /* Error Summary Status */
471 /* Macros for accessing the FPU status word. */
473 /* get the FPU status */
474 #define _FPU_GET_SW(sw) __asm__ ("fnstsw %0" : "=m" (*&sw))
476 /* clear the FPU status */
477 #define _FPU_CLR_SW() __asm__ ("fnclex" : : )
480 * Checks, if the floating point unit has produced an exception, print a message
481 * if so and clear the exception.
483 unsigned int fluid_check_fpe_i386(char* explanation)
490 s &= _FPU_STATUS_IE | _FPU_STATUS_DE | _FPU_STATUS_ZE | _FPU_STATUS_OE | _FPU_STATUS_UE;
494 FLUID_LOG(FLUID_WARN, "FPE exception (before or in %s): %s%s%s%s%s", explanation,
495 (s & _FPU_STATUS_IE) ? "Invalid operation " : "",
496 (s & _FPU_STATUS_DE) ? "Denormal number " : "",
497 (s & _FPU_STATUS_ZE) ? "Zero divide " : "",
498 (s & _FPU_STATUS_OE) ? "Overflow " : "",
499 (s & _FPU_STATUS_UE) ? "Underflow " : "");
506 * Clear floating point exception.
508 void fluid_clear_fpe_i386 (void)
513 #endif // ifdef FPE_CHECK
516 #endif // #else (its POSIX)
519 /***************************************************************
521 * Profiling (Linux, i586 only)
527 fluid_profile_data_t fluid_profile_data[] =
529 { FLUID_PROF_WRITE, "fluid_synth_write_* ", 1e10, 0.0, 0.0, 0},
530 { FLUID_PROF_ONE_BLOCK, "fluid_synth_one_block ", 1e10, 0.0, 0.0, 0},
531 { FLUID_PROF_ONE_BLOCK_CLEAR, "fluid_synth_one_block:clear ", 1e10, 0.0, 0.0, 0},
532 { FLUID_PROF_ONE_BLOCK_VOICE, "fluid_synth_one_block:one voice ", 1e10, 0.0, 0.0, 0},
533 { FLUID_PROF_ONE_BLOCK_VOICES, "fluid_synth_one_block:all voices", 1e10, 0.0, 0.0, 0},
534 { FLUID_PROF_ONE_BLOCK_REVERB, "fluid_synth_one_block:reverb ", 1e10, 0.0, 0.0, 0},
535 { FLUID_PROF_ONE_BLOCK_CHORUS, "fluid_synth_one_block:chorus ", 1e10, 0.0, 0.0, 0},
536 { FLUID_PROF_VOICE_NOTE, "fluid_voice:note ", 1e10, 0.0, 0.0, 0},
537 { FLUID_PROF_VOICE_RELEASE, "fluid_voice:release ", 1e10, 0.0, 0.0, 0},
538 { FLUID_PROF_LAST, "last", 1e100, 0.0, 0.0, 0}
542 void fluid_profiling_print(void)
546 printf("fluid_profiling_print\n");
548 FLUID_LOG(FLUID_INFO, "Estimated times: min/avg/max (micro seconds)");
550 for (i = 0; i < FLUID_PROF_LAST; i++) {
551 if (fluid_profile_data[i].count > 0) {
552 FLUID_LOG(FLUID_INFO, "%s: %.3f/%.3f/%.3f",
553 fluid_profile_data[i].description,
554 fluid_profile_data[i].min,
555 fluid_profile_data[i].total / fluid_profile_data[i].count,
556 fluid_profile_data[i].max);
558 FLUID_LOG(FLUID_DBG, "%s: no profiling available", fluid_profile_data[i].description);
564 #endif /* WITH_PROFILING */
568 /***************************************************************
574 #if OLD_GLIB_THREAD_API
576 /* Rather than inline this one, we just declare it as a function, to prevent
577 * GCC warning about inline failure. */
579 new_fluid_cond (void)
581 if (!g_thread_supported ()) g_thread_init (NULL);
582 return g_cond_new ();
588 fluid_thread_high_prio (gpointer data)
590 fluid_thread_info_t *info = data;
592 fluid_thread_self_set_prio (info->prio_level);
594 info->func (info->data);
601 * Create a new thread.
602 * @param func Function to execute in new thread context
603 * @param data User defined data to pass to func
604 * @param prio_level Priority level. If greater than 0 then high priority scheduling will
605 * be used, with the given priority level (used by pthreads only). 0 uses normal scheduling.
606 * @param detach If TRUE, 'join' does not work and the thread destroys itself when finished.
607 * @return New thread pointer or NULL on error
610 new_fluid_thread (const char *name, fluid_thread_func_t func, void *data, int prio_level, int detach)
613 fluid_thread_info_t *info;
616 g_return_val_if_fail (func != NULL, NULL);
618 #if OLD_GLIB_THREAD_API
619 /* Make sure g_thread_init has been called.
620 * FIXME - Probably not a good idea in a shared library,
621 * but what can we do *and* remain backwards compatible? */
622 if (!g_thread_supported ()) g_thread_init (NULL);
627 info = FLUID_NEW (fluid_thread_info_t);
631 FLUID_LOG(FLUID_ERR, "Out of memory");
637 info->prio_level = prio_level;
638 #if NEW_GLIB_THREAD_API
639 thread = g_thread_try_new (name, fluid_thread_high_prio, info, &err);
641 thread = g_thread_create (fluid_thread_high_prio, info, detach == FALSE, &err);
644 #if NEW_GLIB_THREAD_API
645 else thread = g_thread_try_new (name, (GThreadFunc)func, data, &err);
647 else thread = g_thread_create ((GThreadFunc)func, data, detach == FALSE, &err);
652 FLUID_LOG(FLUID_ERR, "Failed to create the thread: %s",
653 fluid_gerror_message (err));
654 g_clear_error (&err);
658 #if NEW_GLIB_THREAD_API
659 if (detach) g_thread_unref (thread); // Release thread reference, if caller wants to detach
666 * Frees data associated with a thread (does not actually stop thread).
667 * @param thread Thread to free
670 delete_fluid_thread(fluid_thread_t* thread)
672 /* Threads free themselves when they quit, nothing to do */
676 * Join a thread (wait for it to terminate).
677 * @param thread Thread to join
681 fluid_thread_join(fluid_thread_t* thread)
683 g_thread_join (thread);
690 fluid_timer_run (void *data)
692 fluid_timer_t *timer;
698 timer = (fluid_timer_t *)data;
700 /* keep track of the start time for absolute positioning */
701 start = fluid_curtime ();
705 cont = (*timer->callback)(timer->data, fluid_curtime() - start);
710 /* to avoid incremental time errors, calculate the delay between
711 two callbacks bringing in the "absolute" time (count *
713 delay = (count * timer->msec) - (fluid_curtime() - start);
714 if (delay > 0) g_usleep (delay * 1000);
717 FLUID_LOG (FLUID_DBG, "Timer thread finished");
719 if (timer->auto_destroy)
726 new_fluid_timer (int msec, fluid_timer_callback_t callback, void* data,
727 int new_thread, int auto_destroy, int high_priority)
729 fluid_timer_t *timer;
731 timer = FLUID_NEW (fluid_timer_t);
735 FLUID_LOG (FLUID_ERR, "Out of memory");
740 timer->callback = callback;
743 timer->thread = NULL;
744 timer->auto_destroy = auto_destroy;
748 timer->thread = new_fluid_thread ("timer", fluid_timer_run, timer, high_priority
749 ? FLUID_SYS_TIMER_HIGH_PRIO_LEVEL : 0, FALSE);
756 else fluid_timer_run (timer); /* Run directly, instead of as a separate thread */
762 delete_fluid_timer (fluid_timer_t *timer)
764 int auto_destroy = timer->auto_destroy;
767 fluid_timer_join (timer);
769 /* Shouldn't access timer now if auto_destroy enabled, since it has been destroyed */
771 if (!auto_destroy) FLUID_FREE (timer);
777 fluid_timer_join (fluid_timer_t *timer)
783 auto_destroy = timer->auto_destroy;
784 fluid_thread_join (timer->thread);
786 if (!auto_destroy) timer->thread = NULL;
793 /***************************************************************
800 * Get standard in stream handle.
801 * @return Standard in stream.
804 fluid_get_stdin (void)
810 * Get standard output stream handle.
811 * @return Standard out stream.
814 fluid_get_stdout (void)
816 return STDOUT_FILENO;
820 * Read a line from an input stream.
821 * @return 0 if end-of-stream, -1 if error, non zero otherwise
824 fluid_istream_readline (fluid_istream_t in, fluid_ostream_t out, char* prompt,
828 if (in == fluid_get_stdin ())
832 line = readline (prompt);
837 snprintf(buf, len, "%s", line);
846 fluid_ostream_printf (out, "%s", prompt);
847 return fluid_istream_gets (in, buf, len);
852 * Reads a line from an input stream (socket).
853 * @param in The input socket
854 * @param buf Buffer to store data to
855 * @param len Maximum length to store to buf
856 * @return 1 if a line was read, 0 on end of stream, -1 on error
859 fluid_istream_gets (fluid_istream_t in, char* buf, int len)
870 if (n == -1) return -1;
872 /* Handle read differently depending on if its a socket or file descriptor */
873 if (!(in & WIN32_SOCKET_FLAG))
876 if (n == -1) return -1;
880 n = recv(in & ~WIN32_SOCKET_FLAG, &c, 1, 0);
881 if (n == SOCKET_ERROR) return -1;
897 /* Store all characters excluding CR */
898 if (c != '\r') *buf++ = c;
905 * Send a printf style string with arguments to an output stream (socket).
906 * @param out Output stream
907 * @param format printf style format string
908 * @param ... Arguments for the printf format string
909 * @return Number of bytes written or -1 on error
912 fluid_ostream_printf (fluid_ostream_t out, char* format, ...)
918 va_start (args, format);
919 len = vsnprintf (buf, 4095, format, args);
929 printf("fluid_ostream_printf: buffer overflow");
936 return write (out, buf, strlen (buf));
941 /* Handle write differently depending on if its a socket or file descriptor */
942 if (!(out & WIN32_SOCKET_FLAG))
943 return write(out, buf, strlen (buf));
946 retval = send (out & ~WIN32_SOCKET_FLAG, buf, strlen (buf), 0);
948 return retval != SOCKET_ERROR ? retval : -1;
953 int fluid_server_socket_join(fluid_server_socket_t *server_socket)
955 return fluid_thread_join (server_socket->thread);
959 #ifndef WIN32 // Not win32?
961 #define SOCKET_ERROR -1
963 fluid_istream_t fluid_socket_get_istream (fluid_socket_t sock)
968 fluid_ostream_t fluid_socket_get_ostream (fluid_socket_t sock)
973 void fluid_socket_close(fluid_socket_t sock)
975 if (sock != INVALID_SOCKET)
980 fluid_server_socket_run (void *data)
982 fluid_server_socket_t *server_socket = (fluid_server_socket_t *)data;
983 fluid_socket_t client_socket;
985 struct sockaddr_in6 addr;
986 char straddr[INET6_ADDRSTRLEN];
988 struct sockaddr_in addr;
989 char straddr[INET_ADDRSTRLEN];
991 socklen_t addrlen = sizeof (addr);
993 FLUID_MEMSET((char *)&addr, 0, sizeof(addr));
995 FLUID_LOG (FLUID_DBG, "Server listening for connections");
997 while (server_socket->cont)
999 client_socket = accept (server_socket->socket, (struct sockaddr *)&addr, &addrlen);
1001 FLUID_LOG (FLUID_DBG, "New client connection");
1003 if (client_socket == INVALID_SOCKET)
1005 if (server_socket->cont)
1006 FLUID_LOG(FLUID_ERR, "Failed to accept connection");
1008 server_socket->cont = 0;
1012 inet_ntop(AF_INET6, &addr.sin6_addr, straddr, sizeof(straddr));
1014 inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr));
1016 retval = server_socket->func (server_socket->data, client_socket,
1020 fluid_socket_close(client_socket);
1024 FLUID_LOG(FLUID_DBG, "Server closing");
1027 fluid_server_socket_t*
1028 new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
1030 fluid_server_socket_t* server_socket;
1032 struct sockaddr_in6 addr;
1034 struct sockaddr_in addr;
1036 fluid_socket_t sock;
1038 g_return_val_if_fail (func != NULL, NULL);
1040 sock = socket(AF_INET6, SOCK_STREAM, 0);
1041 if (sock == INVALID_SOCKET) {
1042 FLUID_LOG(FLUID_ERR, "Failed to create server socket");
1046 FLUID_MEMSET((char *)&addr, 0, sizeof(struct sockaddr_in6));
1047 addr.sin6_family = AF_INET6;
1048 addr.sin6_addr = in6addr_any;
1049 addr.sin6_port = htons(port);
1052 sock = socket(AF_INET, SOCK_STREAM, 0);
1053 if (sock == INVALID_SOCKET) {
1054 FLUID_LOG(FLUID_ERR, "Failed to create server socket");
1058 FLUID_MEMSET((char *)&addr, 0, sizeof(struct sockaddr_in));
1059 addr.sin_family = AF_INET;
1060 addr.sin_addr.s_addr = htonl(INADDR_ANY);
1061 addr.sin_port = htons(port);
1063 if (bind(sock, (const struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR) {
1064 FLUID_LOG(FLUID_ERR, "Failed to bind server socket");
1065 fluid_socket_close(sock);
1069 if (listen(sock, 10) == SOCKET_ERROR) {
1070 FLUID_LOG(FLUID_ERR, "Failed listen on server socket");
1071 fluid_socket_close(sock);
1075 server_socket = FLUID_NEW(fluid_server_socket_t);
1076 if (server_socket == NULL) {
1077 FLUID_LOG(FLUID_ERR, "Out of memory");
1078 fluid_socket_close(sock);
1082 server_socket->socket = sock;
1083 server_socket->func = func;
1084 server_socket->data = data;
1085 server_socket->cont = 1;
1087 server_socket->thread = new_fluid_thread("server", fluid_server_socket_run, server_socket,
1089 if (server_socket->thread == NULL) {
1090 FLUID_FREE(server_socket);
1091 fluid_socket_close(sock);
1095 return server_socket;
1098 int delete_fluid_server_socket(fluid_server_socket_t* server_socket)
1100 server_socket->cont = 0;
1101 if (server_socket->socket != INVALID_SOCKET) {
1102 fluid_socket_close(server_socket->socket);
1104 if (server_socket->thread) {
1105 delete_fluid_thread(server_socket->thread);
1107 FLUID_FREE(server_socket);
1112 #else // Win32 is "special"
1115 #ifndef WIN32_LEAN_AND_MEAN
1116 #define WIN32_LEAN_AND_MEAN
1119 fluid_istream_t fluid_socket_get_istream (fluid_socket_t sock)
1121 return sock | WIN32_SOCKET_FLAG;
1124 fluid_ostream_t fluid_socket_get_ostream (fluid_socket_t sock)
1126 return sock | WIN32_SOCKET_FLAG;
1129 void fluid_socket_close (fluid_socket_t sock)
1131 if (sock != INVALID_SOCKET)
1135 static void fluid_server_socket_run (void *data)
1137 fluid_server_socket_t *server_socket = (fluid_server_socket_t *)data;
1138 fluid_socket_t client_socket;
1140 struct sockaddr_in6 addr;
1141 char straddr[INET6_ADDRSTRLEN];
1143 struct sockaddr_in addr;
1144 char straddr[INET_ADDRSTRLEN];
1146 socklen_t addrlen = sizeof (addr);
1148 FLUID_MEMSET((char *)&addr, 0, sizeof(addr));
1150 FLUID_LOG(FLUID_DBG, "Server listening for connections");
1152 while (server_socket->cont)
1154 client_socket = accept (server_socket->socket, (struct sockaddr *)&addr, &addrlen);
1156 FLUID_LOG (FLUID_DBG, "New client connection");
1158 if (client_socket == INVALID_SOCKET)
1160 if (server_socket->cont)
1161 FLUID_LOG (FLUID_ERR, "Failed to accept connection: %ld", WSAGetLastError ());
1163 server_socket->cont = 0;
1169 inet_ntop(AF_INET6, &addr.sin6_addr, straddr, sizeof(straddr));
1171 inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr));
1173 r = server_socket->func (server_socket->data, client_socket,
1176 fluid_socket_close (client_socket);
1180 FLUID_LOG (FLUID_DBG, "Server closing");
1183 fluid_server_socket_t*
1184 new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
1186 fluid_server_socket_t* server_socket;
1188 struct sockaddr_in6 addr;
1190 struct sockaddr_in addr;
1193 fluid_socket_t sock;
1197 g_return_val_if_fail (func != NULL, NULL);
1199 // Win32 requires initialization of winsock
1200 retval = WSAStartup (MAKEWORD (2,2), &wsaData);
1204 FLUID_LOG(FLUID_ERR, "Server socket creation error: WSAStartup failed: %d", retval);
1208 sock = socket (AF_INET6, SOCK_STREAM, 0);
1209 if (sock == INVALID_SOCKET)
1211 FLUID_LOG (FLUID_ERR, "Failed to create server socket: %ld", WSAGetLastError ());
1215 addr.sin6_family = AF_INET6;
1216 addr.sin6_port = htons (port);
1217 addr.sin6_addr = in6addr_any;
1220 sock = socket (AF_INET, SOCK_STREAM, 0);
1222 if (sock == INVALID_SOCKET)
1224 FLUID_LOG (FLUID_ERR, "Failed to create server socket: %ld", WSAGetLastError ());
1229 addr.sin_family = AF_INET;
1230 addr.sin_port = htons (port);
1231 addr.sin_addr.s_addr = htonl (INADDR_ANY);
1233 retval = bind (sock, (struct sockaddr *)&addr, sizeof (addr));
1235 if (retval == SOCKET_ERROR)
1237 FLUID_LOG (FLUID_ERR, "Failed to bind server socket: %ld", WSAGetLastError ());
1238 fluid_socket_close (sock);
1243 if (listen (sock, SOMAXCONN) == SOCKET_ERROR)
1245 FLUID_LOG (FLUID_ERR, "Failed to listen on server socket: %ld", WSAGetLastError ());
1246 fluid_socket_close (sock);
1251 server_socket = FLUID_NEW (fluid_server_socket_t);
1253 if (server_socket == NULL)
1255 FLUID_LOG (FLUID_ERR, "Out of memory");
1256 fluid_socket_close (sock);
1261 server_socket->socket = sock;
1262 server_socket->func = func;
1263 server_socket->data = data;
1264 server_socket->cont = 1;
1266 server_socket->thread = new_fluid_thread("server", fluid_server_socket_run, server_socket,
1268 if (server_socket->thread == NULL)
1270 FLUID_FREE (server_socket);
1271 fluid_socket_close (sock);
1276 return server_socket;
1279 int delete_fluid_server_socket(fluid_server_socket_t *server_socket)
1281 server_socket->cont = 0;
1283 if (server_socket->socket != INVALID_SOCKET)
1284 fluid_socket_close (server_socket->socket);
1286 if (server_socket->thread)
1287 delete_fluid_thread (server_socket->thread);
1289 FLUID_FREE (server_socket);
1291 WSACleanup (); // Should be called the same number of times as WSAStartup