📄 coserver.c
字号:
svz_log (LOG_WARNING, "coserver: invalid character in id (0x%02X)\n", *p); return -1; } id *= 10; id += *p - '0'; p++; } if (p == end) { svz_log (LOG_WARNING, "coserver: invalid coserver response (no id)\n"); return -1; } data = ++p; /* Search for packet end. */ while (*p != COSERVER_PACKET_BOUNDARY && p < end) p++; if (p == end) { svz_log (LOG_WARNING, "coserver: invalid coserver response (no data)\n"); return -1; } *p = '\0'; /* Have a look at the coserver callback hash. */ if (NULL == (cb = svz_hash_get (svz_coserver_callbacks, svz_itoa (id)))) { svz_log (LOG_ERROR, "coserver: invalid callback for id %u\n", id); return -1; } /* * Run the callback inclusive its arg. Second arg is either NULL for * error detection or the actual result string. Afterwards free the * callback structure and delete it from the coserver callback hash. */ ret = cb->handle_result (*data ? data : NULL, cb->arg[0], cb->arg[1]); svz_hash_delete (svz_coserver_callbacks, svz_itoa (id)); svz_free (cb); return ret;}#ifndef __MINGW32__/* * This function closes the pipes (incoming and outgoing) of all coservers * inherited to a newly instantiated coserver. These pipe descriptors are * part of server process and are inherited when we call @code{fork()} in * order to create another coserver sub process. Since this coserver process * should not access these pipes we are closing them. */static voidsvz_coserver_close_pipes (svz_coserver_t *self){ int n; svz_coserver_t *coserver; /* go through all coservers except itself */ svz_array_foreach (svz_coservers, coserver, n) { if (coserver != self) { close (coserver->sock->pipe_desc[READ]); close (coserver->sock->pipe_desc[WRITE]); } }}/* * Iterate each socket object and close its file/socket/pipe * descriptors. */static voidsvz_coserver_closeall (void){ svz_socket_t *sock; svz_sock_foreach (sock) { if (sock->flags & SOCK_FLAG_SOCK) close (sock->sock_desc); if (sock->flags & SOCK_FLAG_FILE) close (sock->file_desc); if (sock->flags & SOCK_FLAG_PIPE) { if (sock->pipe_desc[READ] >= 2) close (sock->pipe_desc[READ]); if (sock->pipe_desc[WRITE] >= 2) close (sock->pipe_desc[WRITE]); } } svz_file_closeall ();}/* * Setup signaling for a coserver process. This is necessary since * the original signal handlers get confused about signals raised by its * children. */static voidsvz_coserver_signals (void){#ifdef SIGTERM signal (SIGTERM, SIG_IGN);#endif#ifdef SIGINT signal (SIGINT, SIG_IGN);#endif#ifdef SIGHUP signal (SIGHUP, SIG_IGN);#endif#ifdef SIGPIPE signal (SIGPIPE, SIG_IGN);#endif#ifdef SIGQUIT signal (SIGQUIT, SIG_IGN);#endif}#endif /* not __MINGW32__ *//* * Destroy specific coservers with the type @var{type}. This works for * Win32 and Unices. All instances of this coserver type will be stopped. */voidsvz_coserver_destroy (int type){ int n, count = 0; svz_coserver_t *coserver; svz_array_foreach (svz_coservers, coserver, n) { if (coserver->type == type) {#ifdef __MINGW32__ /* stop the thread and close its handle */ if (!TerminateThread (coserver->thread, 0)) svz_log (LOG_ERROR, "TerminateThread: %s\n", SYS_ERROR); if (!CloseHandle (coserver->thread)) svz_log (LOG_ERROR, "CloseHandle: %s\n", SYS_ERROR); DeleteCriticalSection (&coserver->sync); /* free all data reserved by the coserver */ svz_sock_free (coserver->sock);#else /* not __MINGW32__ */ if (kill (coserver->pid, SIGKILL) == -1) svz_log (LOG_ERROR, "kill: %s\n", SYS_ERROR);#if HAVE_WAITPID /* cleanup coserver child process */ else if (waitpid (coserver->pid, NULL, WNOHANG) == -1) svz_log (LOG_ERROR, "waitpid: %s\n", SYS_ERROR);#endif /* HAVE_WAITPID */#endif /* not __MINGW32__ */ svz_coserver_delete (n); n--; count++; } }#ifdef ENABLE_DEBUG if (count > 0) { svz_log (LOG_DEBUG, "%d internal %s coserver destroyed\n", count, svz_coservertypes[type].name); }#endif /* ENABLE_DEBUG */}/* * Start a specific internal coserver. This works for Win32 and * Unices. Whereas in Unix a process is @code{fork()}ed and in Win32 * a thread gets started. */static svz_socket_t *svz_coserver_start (int type) { svz_socket_t *sock; svz_coserver_t *coserver; #ifndef __MINGW32__ int s2c[2]; int c2s[2]; int pid;#else /* not __MINGW32__ */ HANDLE thread; DWORD tid;#endif /* not __MINGW32__ */ svz_log (LOG_NOTICE, "starting internal %s coserver\n", svz_coservertypes[type].name); coserver = svz_malloc (sizeof (svz_coserver_t)); coserver->type = type; coserver->busy = 0; if (svz_coservers == NULL) svz_coservers = svz_array_create (MAX_COSERVER_TYPES); svz_array_add (svz_coservers, coserver); /* fill in the actual coserver callback */ coserver->callback = svz_coservertypes[type].callback;#ifdef __MINGW32__ if ((sock = svz_sock_alloc ()) == NULL) return NULL; InitializeCriticalSection (&coserver->sync); sock->write_socket = NULL; sock->read_socket = NULL; coserver->sock = sock; coserver->thread = INVALID_HANDLE_VALUE; if ((thread = CreateThread( (LPSECURITY_ATTRIBUTES) NULL, /* ignore security attributes */ (DWORD) 0, /* default stack size */ (LPTHREAD_START_ROUTINE) svz_coserver_thread, /* thread routine */ (LPVOID) coserver, /* thread argument */ (DWORD) CREATE_SUSPENDED, /* creation flags */ (LPDWORD) &tid)) == INVALID_HANDLE_VALUE) /* thread id */ { svz_log (LOG_ERROR, "CreateThread: %s\n", SYS_ERROR); DeleteCriticalSection (&coserver->sync); svz_sock_free (sock); return NULL; } /* fill in thread access variables */ coserver->tid = tid; coserver->thread = thread; /* set thread priority */ if (!SetThreadPriority (thread, COSERVER_THREAD_PRIORITY)) svz_log (LOG_ERROR, "SetThreadPriority: %s\n", SYS_ERROR);#ifdef ENABLE_DEBUG svz_log (LOG_DEBUG, "coserver thread id is 0x%08X\n", tid);#endif#else /* not __MINGW32__ */ /* create pipes for process communication */ if (pipe (s2c) < 0) { svz_log (LOG_ERROR, "pipe server-coserver: %s\n", SYS_ERROR); svz_coserver_delete (svz_array_size (svz_coservers) - 1); return NULL; } if (pipe (c2s) < 0) { close (s2c[READ]); close (s2c[WRITE]); svz_log (LOG_ERROR, "pipe coserver-server: %s\n", SYS_ERROR); svz_coserver_delete (svz_array_size (svz_coservers) - 1); return NULL; } /* fork() us here */ if ((pid = fork ()) == 0) { int in = s2c[READ], out = c2s[WRITE]; /* close the servers pipe descriptors */ if (close (s2c[WRITE]) < 0) svz_log (LOG_ERROR, "close: %s\n", SYS_ERROR); if (close (c2s[READ]) < 0) svz_log (LOG_ERROR, "close: %s\n", SYS_ERROR);#if ENABLE_DEBUG svz_log (LOG_DEBUG, "coserver pipes: %d-%d\n", in, out);#endif /* check if the pipes are 0, 1 or 2 already */ if (in > 2 && out > 2) { /* reassign the pipes to stdout and stdin */ if (dup2 (in, 0) != 0) svz_log (LOG_ERROR, "dup2: %s\n", SYS_ERROR); if (dup2 (out, 1) != 1) svz_log (LOG_ERROR, "dup2: %s\n", SYS_ERROR); /* close the old pipe descriptors */ close (in); close (out); close (2); in = 0; out = 1; } else { if (in != 2 && out != 2) close (2); if (in != 1 && out != 1) close (1); if (in != 0 && out != 0) close (0); } /* close all other coserver pipes except its own */ svz_coserver_close_pipes (coserver); svz_coserver_closeall (); svz_coserver_signals (); /* start the internal coserver */ svz_coserver_loop (coserver, in, out); exit (0); } else if (pid == -1) { svz_log (LOG_ERROR, "fork: %s\n", SYS_ERROR); close (s2c[READ]); close (s2c[WRITE]); close (c2s[READ]); close (c2s[WRITE]); svz_coserver_delete (svz_array_size (svz_coservers) - 1); return NULL; } /* the old server process continues here */ #ifdef ENABLE_DEBUG svz_log (LOG_DEBUG, "coserver process id is %d\n", pid);#endif /* close the coservers pipe descriptors */ if (close (s2c[READ]) < 0) svz_log (LOG_ERROR, "close: %s\n", SYS_ERROR); if (close (c2s[WRITE]) < 0) svz_log (LOG_ERROR, "close: %s\n", SYS_ERROR); if ((sock = svz_pipe_create (c2s[READ], s2c[WRITE])) == NULL) { if (close (c2s[READ]) < 0) svz_log (LOG_ERROR, "close: %s\n", SYS_ERROR); if (close (s2c[WRITE]) < 0) svz_log (LOG_ERROR, "close: %s\n", SYS_ERROR); svz_coserver_delete (svz_array_size (svz_coservers) - 1); return NULL; } coserver->pid = pid; coserver->sock = sock; sock->disconnected_socket = svz_coserver_disconnect; sock->write_socket = svz_pipe_write_socket; sock->read_socket = svz_pipe_read_socket; svz_sock_enqueue (sock);#endif /* __MINGW32__ and Unices */ svz_coservertypes[coserver->type].last_start = (long) time (NULL); sock->data = coserver; sock->check_request = svz_coserver_check_request; sock->handle_request = svz_coserver_handle_request; sock->flags |= (SOCK_FLAG_NOFLOOD | SOCK_FLAG_COSERVER); return sock;}/* * Call this routine whenever there is time, e.g. within the timeout of * the @code{select()} statement. Indeed I built it in the * @code{svz_periodic_tasks()} statement. Under Wind32 the routine checks * if there was any response from an active coserver. Moreover it keeps * the coserver threads/processes alive. If one of the coservers dies due * to buffer overrun or might be overloaded this function starts a new one. */voidsvz_coserver_check (void){ svz_coserver_t *coserver; svz_coservertype_t *ctype; svz_socket_t *sock; int n; #ifdef __MINGW32__ /* go through all coservers */ svz_array_foreach (svz_coservers, coserver, n) { sock = coserver->sock; while (sock->recv_buffer_fill > 0) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "%s: coserver response detected\n", svz_coservertypes[coserver->type].name);#endif /* find a full response within the receive buffer */ if (sock->check_request) { EnterCriticalSection (&coserver->sync); sock->check_request (sock); LeaveCriticalSection (&coserver->sync); } } }#endif /* __MINGW32__ */ /* check the number of coserver instances of each coserver type */ for (n = 0; n < MAX_COSERVER_TYPES; n++) { ctype = &svz_coservertypes[n]; if (svz_coserver_count (ctype->type) < ctype->instances && ((long) time (NULL)) - ctype->last_start >= 3) svz_coserver_start (ctype->type); } /* restart coserver instances if buffer overrun is in sight (send buffer fill >= 75 percent) */ svz_array_foreach (svz_coservers, coserver, n) { ctype = &svz_coservertypes[coserver->type]; sock = coserver->sock; if (sock->send_buffer_fill * 100 / sock->send_buffer_size >= 75 && ((long) time (NULL)) - ctype->last_start >= 3) svz_coserver_start (coserver->type); }}/* * Create a single coserver with the given type @var{type}. */void svz_coserver_create (int type){ if (svz_coservertypes[type].init) svz_coservertypes[type].init (); svz_coserver_start (type);}/* * Global coserver initialization. Here you should start all the internal * coservers you want to use later. */intsvz_coserver_init (void){ int i, n; svz_coservertype_t *coserver; svz_coserver_callbacks = svz_hash_create (4); svz_coserver_callback_id = 1; for (n = 0; n < MAX_COSERVER_TYPES; n++) { coserver = &svz_coservertypes[n]; if (coserver->init) coserver->init (); for (i = 0; i < coserver->instances; i++) svz_coserver_start (coserver->type); } return 0;}/* * Global coserver finalization. */intsvz_coserver_finalize (void){ int n; svz_coserver_callback_t **cb; svz_coservertype_t *coserver; for (n = 0; n < MAX_COSERVER_TYPES; n++) { coserver = &svz_coservertypes[n]; svz_coserver_destroy (coserver->type); } /* @code{svz_free()} all callbacks left so far. */ svz_hash_foreach_value (svz_coserver_callbacks, cb, n) svz_free (cb[n]);#if ENABLE_DEBUG svz_log (LOG_DEBUG, "coserver: %d callback(s) left\n", svz_hash_size (svz_coserver_callbacks));#endif svz_hash_destroy (svz_coserver_callbacks); return 0;}/* * Invoke a @var{request} for one of the running internal coservers * with type @var{type}. @var{handle_result} and @var{arg} specify what * should happen if the coserver delivers a result. */voidsvz_coserver_send_request (int type, char *request, svz_coserver_handle_result_t handle_result, svz_coserver_args_t){ int n, busy; svz_coserver_t *coserver, *current; svz_coserver_callback_t *cb; /* * Go through all coservers and find out which coserver * type TYPE is the least busiest. */ coserver = NULL; svz_array_foreach (svz_coservers, current, n) { if (current->type == type) { if (coserver == NULL) { coserver = current; busy = coserver->busy; } else if (current->busy <= coserver->busy) { coserver = current; busy = coserver->busy; } } } /* found an appropriate coserver */ if (coserver) { /* * Create new callback hash entry for this coserver request and * put it into the global coserver callback hash. */ cb = svz_malloc (sizeof (svz_coserver_callback_t)); cb->handle_result = handle_result; cb->arg[0] = arg0; cb->arg[1] = arg1; svz_hash_put (svz_coserver_callbacks, svz_itoa (svz_coserver_callback_id), cb); coserver->busy++;#ifdef __MINGW32__ EnterCriticalSection (&coserver->sync);#endif /* __MINGW32__ */ if (svz_sock_printf (coserver->sock, "%u:%s\n", svz_coserver_callback_id, request)) { svz_sock_schedule_for_shutdown (coserver->sock); } svz_coserver_callback_id++;#ifdef __MINGW32__ LeaveCriticalSection (&coserver->sync); svz_coserver_activate (coserver->type);#endif /* __MINGW32__ */ }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -