⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 coserver.c

📁 Serveez是一个服务器框架
💻 C
📖 第 1 页 / 共 2 页
字号:
	  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 + -