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

📄 server-core.c

📁 Serveez是一个服务器框架
💻 C
📖 第 1 页 / 共 2 页
字号:
  int nr, n, ret = 0;  svz_vector_t *accepted = NULL;  /* Check connect frequency. */  if (port->accepted)    accepted = (svz_vector_t *) svz_hash_get (port->accepted, ip);  else    port->accepted = svz_hash_create (4);  current = time (NULL);  if (accepted != NULL)    {      /* Delete older entries and count valid entries. */      nr = 0;      svz_vector_foreach (accepted, t, n)	{	  if (*t < current - 4)	    {	      svz_vector_del (accepted, n);	      n--;	    }	  else	    nr++;	}      /* Check the connection frequency. */      if ((nr /= 4) > port->connect_freq)	{	  svz_log (LOG_NOTICE, "connect frequency reached: %s: %d/%d\n", 		   ip, nr, port->connect_freq);	  ret = -1;	}    }  /* Not yet connected. */  else    {      accepted = svz_vector_create (sizeof (time_t));    }  svz_vector_add (accepted, &current);  svz_hash_put (port->accepted, ip, accepted);  return ret;}/* * This function returns zero if the @var{child} socket is allowed to  * connect to the port configuration of the @var{parent} socket structure * which needs to be a listener therefore. */intsvz_sock_check_access (svz_socket_t *parent, svz_socket_t *child){  svz_portcfg_t *port;  char *ip;  int n, ret;  char *remote;  /* Check arguments and return if this function cannot work. */  if (parent == NULL || child == NULL || parent->port == NULL)    return 0;  /* Get port configuration and remote address. */  port = parent->port;  remote = svz_inet_ntoa (child->remote_addr);  /* Check the deny IP addresses. */  if (port->deny)    {      svz_array_foreach (port->deny, ip, n)	{	  if (!strcmp (ip, remote))	    {	      svz_log (LOG_NOTICE, "denying access from %s\n", ip);	      return -1;	    }	}    }  /* Check allow IP addresses. */  if (port->allow)    {      ret = -1;      svz_array_foreach (port->allow, ip, n)	{	  if (!strcmp (ip, remote))	    {	      svz_log (LOG_NOTICE, "allowing access from %s\n", ip);	      ret = 0;	    }	}      if (ret)	{	  svz_log (LOG_NOTICE, "denying unallowed access from %s\n", remote);	  return ret;	}    }  return 0;}/* * Return the parents port configuration of the socket structure @var{sock} * or @code{NULL} if the given socket has no parent, i.e. is a listener. */svz_portcfg_t *svz_sock_portcfg (svz_socket_t *sock){  svz_portcfg_t *port = NULL;  svz_socket_t *parent;  if ((parent = svz_sock_getparent (sock)) != NULL)    port = parent->port;  return port;}/* * Set the sockets @var{child} parent to the given socket structure * @var{parent}. This should be called whenever a listener accepts a * connection and creates a new child socket. */voidsvz_sock_setparent (svz_socket_t *child, svz_socket_t *parent){  if (parent != NULL && child != NULL)    {      child->parent_id = parent->id;      child->parent_version = parent->version;    }}/* * Return the sockets @var{child} parent socket structure or @code{NULL} * if this socket does not exist anymore. This might happen if a listener * dies for some reason. */svz_socket_t *svz_sock_getparent (svz_socket_t *child){  if (!child)    return NULL;  return svz_sock_find (child->parent_id, child->parent_version);}/* * Set the referring socket structure of @var{sock} to the given socket * @var{referrer}. This can be used to create some relationship between * two socket structures. If @var{referrer} is @code{NULL} the reference * will be invalidated. */voidsvz_sock_setreferrer (svz_socket_t *sock, svz_socket_t *referrer){  if (referrer == NULL)    {      sock->referrer_version = sock->referrer_id = -1;    }  else    {      sock->referrer_id = referrer->id;      sock->referrer_version = referrer->version;    }}/* * Get the referrer of the socket structure @var{sock}. Return @code{NULL} * if there is no such socket. */svz_socket_t *svz_sock_getreferrer (svz_socket_t *sock){  if (!sock)    return NULL;  return svz_sock_find (sock->referrer_id, sock->referrer_version);}/* * Return the socket structure for the socket id @var{id} and the version  * @var{version} or @code{NULL} if no such socket exists. If @var{version} * is -1 it is not checked. */svz_socket_t *svz_sock_find (int id, int version){  svz_socket_t *sock;  if (id & ~(svz_sock_limit - 1))    {      svz_log (LOG_FATAL, "socket id %d is invalid\n", id);      return NULL;    }  sock = svz_sock_lookup_table[id];  if (version != -1 && sock && sock->version != version)    {      svz_log (LOG_WARNING, "socket version %d (id %d) is invalid\n", 	       version, id);      return NULL;    }  return svz_sock_lookup_table[id];}/* * Create the socket lookup table initially. Must be called from  * @code{svz_boot()}. */voidsvz_sock_table_create (void){  svz_sock_lookup_table = svz_calloc (svz_sock_limit * 				      sizeof (svz_socket_t *));}/* * Destroy the socket lookup table finally. Must be called from  * @code{svz_halt()}. */voidsvz_sock_table_destroy (void){  svz_free_and_zero (svz_sock_lookup_table);}/* * Calculate unique socket structure id and assign a version for a  * given @var{sock}. The version is for validating socket structures. It is  * currently used in the coserver callbacks. */intsvz_sock_unique_id (svz_socket_t *sock){  int i;  for (i = 0; i < svz_sock_limit; i++)     {      svz_sock_id++;      svz_sock_id &= (svz_sock_limit - 1);      if (NULL == svz_sock_lookup_table[svz_sock_id])	break;    }  /* ensure global limit, resize the lookup table if necessary */  if (i == svz_sock_limit)    {      svz_sock_lookup_table = svz_realloc (svz_sock_lookup_table,					   svz_sock_limit * 2 * 					   sizeof (svz_socket_t *));      memset (&svz_sock_lookup_table[svz_sock_limit], 0,	      svz_sock_limit * sizeof (svz_socket_t *));      svz_sock_id = svz_sock_limit;      svz_sock_limit *= 2;      svz_log (LOG_NOTICE, "lookup table enlarged to %d\n", svz_sock_limit);    }  sock->id = svz_sock_id;  sock->version = svz_sock_version++;    return svz_sock_id;}/* * This gets called when the server receives a SIGHUP, which means * that the server should be reset. */static intsvz_reset (void){  /* FIXME: Maybe `server_t' reset callback ? */  return 0;}/* * Do everything to shut down the socket @var{sock}. The socket structure * gets removed from the socket queue, the file descriptor is closed  * and all memory used by the socket gets freed. Note that this * function calls the @var{sock}'s disconnect handler if defined. */static intsvz_sock_shutdown (svz_socket_t *sock){#if ENABLE_DEBUG  svz_log (LOG_DEBUG, "shutting down socket id %d\n", sock->id);#endif  if (sock->disconnected_socket)    sock->disconnected_socket (sock);  svz_sock_dequeue (sock);  if (sock->flags & SOCK_FLAG_SOCK)    svz_sock_disconnect (sock);  if (sock->flags & SOCK_FLAG_PIPE)    svz_pipe_disconnect (sock);  svz_sock_free (sock);  return 0;}/* * Shutdown all sockets within the socket list no matter if it was * scheduled for shutdown or not. */voidsvz_sock_shutdown_all (void){  svz_socket_t *sock;  sock = svz_sock_root;  while (sock)    {      svz_sock_shutdown (sock);      sock = svz_sock_root;    }  svz_sock_root = svz_sock_last = NULL;}/* * Mark socket @var{sock} as killed.  That means that no operations except * disconnecting and freeing are allowed anymore.  All marked sockets * will be deleted once the server loop is through.   */intsvz_sock_schedule_for_shutdown (svz_socket_t *sock){  if (!(sock->flags & SOCK_FLAG_KILLED))    {#if ENABLE_DEBUG      svz_log (LOG_DEBUG, "scheduling socket id %d for shutdown\n", sock->id);#endif /* ENABLE_DEBUG */      sock->flags |= SOCK_FLAG_KILLED;      /* Shutdown each child for listeners. */      if (sock->flags & SOCK_FLAG_LISTENING)	{	  svz_socket_t *child;	  svz_sock_foreach (child)	    if (svz_sock_getparent (child) == sock)	      svz_sock_schedule_for_shutdown (child);	}    }  return 0;}/* * This routine gets called once a second and is supposed to perform any  * task that has to get scheduled periodically. It checks all sockets'  * timers and calls their timer functions when necessary. */intsvz_periodic_tasks (void){  svz_socket_t *sock;  svz_notify += 1;  sock = svz_sock_root;   while (sock)    {#if ENABLE_FLOOD_PROTECTION      if (sock->flood_points > 0)	{	  sock->flood_points--;	}#endif /* ENABLE_FLOOD_PROTECTION */      if (sock->idle_func && sock->idle_counter > 0)	{	  if (--sock->idle_counter <= 0)	    {	      if (sock->idle_func (sock))		{		  svz_log (LOG_ERROR, 			   "idle function for socket id %d "			   "returned error\n", sock->id);		  svz_sock_schedule_for_shutdown (sock);		}	    }	}      sock = sock->next;    }  /* check regularly for internal coserver responses and keep coservers     alive */  svz_coserver_check ();  /* run the server instance timer routines */  svz_server_notifiers ();  return 0;}/* * Goes through all socket and shuts invalid ones down. */voidsvz_sock_check_bogus (void){#ifdef __MINGW32__  unsigned long readBytes;#endif  svz_socket_t *sock;#if ENABLE_DEBUG  svz_log (LOG_DEBUG, "checking for bogus sockets\n");#endif /* ENABLE_DEBUG */  svz_sock_foreach (sock)    {      if (sock->flags & SOCK_FLAG_SOCK)	{#ifdef __MINGW32__	  if (ioctlsocket (sock->sock_desc, FIONREAD, &readBytes) == 	      SOCKET_ERROR)	    {#else /* not __MINGW32__ */	  if (fcntl (sock->sock_desc, F_GETFL) < 0)	    {#endif /* not __MINGW32__ */	      svz_log (LOG_ERROR, "socket %d has gone\n", sock->sock_desc);	      svz_sock_schedule_for_shutdown (sock);	    }	}#ifndef __MINGW32__      if (sock->flags & SOCK_FLAG_RECV_PIPE)	{	  if (fcntl (sock->pipe_desc[READ], F_GETFL) < 0)	    {	      svz_log (LOG_ERROR, "pipe %d has gone\n",		       sock->pipe_desc[READ]);	      svz_sock_schedule_for_shutdown (sock);	    }	}      if (sock->flags & SOCK_FLAG_SEND_PIPE)	{	  if (fcntl (sock->pipe_desc[WRITE], F_GETFL) < 0)	    {	      svz_log (LOG_ERROR, "pipe %d has gone\n",		       sock->pipe_desc[WRITE]);	      svz_sock_schedule_for_shutdown (sock);	    }	}#endif /* not __MINGW32__ */    }}  /* * Setup signaling for the core library. */voidsvz_signal_up (void){#ifdef SIGTERM  signal (SIGTERM, svz_signal_handler);#endif#ifdef SIGQUIT  signal (SIGQUIT, svz_signal_handler);#endif#ifdef SIGINT  signal (SIGINT, svz_signal_handler);#endif#ifdef SIGBREAK  signal (SIGBREAK, svz_signal_handler);#endif#ifdef SIGCHLD  signal (SIGCHLD, svz_signal_handler);#endif#ifdef SIGHUP  signal (SIGHUP, svz_signal_handler);#endif#ifdef SIGPIPE  signal (SIGPIPE, svz_signal_handler);#endif#ifdef SIGSEGV  signal (SIGSEGV, svz_segfault_exception);#endif}/* * Deinstall signaling for the core library. */voidsvz_signal_dn (void){#ifdef SIGTERM  signal (SIGTERM, SIG_DFL);#endif#ifdef SIGQUIT  signal (SIGQUIT, SIG_DFL);#endif#ifdef SIGINT  signal (SIGINT, SIG_DFL);#endif#ifdef SIGBREAK  signal (SIGBREAK, SIG_DFL);#endif#ifdef SIGCHLD  signal (SIGCHLD, SIG_DFL);#endif#ifdef SIGHUP  signal (SIGHUP, SIG_DFL);#endif#ifdef SIGPIPE  signal (SIGPIPE, SIG_DFL);#endif#ifdef SIGSEGV  signal (SIGSEGV, SIG_DFL);#endif}/* * This routine handles all things once and is called regularly in the * below @code{svz_loop()} routine. */voidsvz_loop_one (void){  svz_socket_t *sock, *next;  static int rechain = 0;  /*   * FIXME: Remove this once the server is stable.   */#if ENABLE_DEBUG  svz_sock_validate_list ();#endif /* ENABLE_DEBUG */  if (svz_reset_happened)    {      /* SIGHUP received. */      svz_log (LOG_NOTICE, "resetting server\n");      svz_reset ();      svz_reset_happened = 0;    }  if (svz_pipe_broke)    {      /* SIGPIPE received. */       svz_log (LOG_ERROR, "broken pipe, continuing\n");      svz_pipe_broke = 0;    }  if (svz_child_died)    {      /* SIGCHLD received. */      svz_log (LOG_ERROR, "child pid %d died\n", (int) svz_child_died);      svz_child_died = 0;    }  /*   * Check for new connections on server port, incoming data from   * clients and process queued output data.   */  svz_check_sockets ();  /*   * Reorder the socket chain every 16 select loops. We do not do it   * every time for performance reasons.   */  if (rechain++ & 16)    svz_sock_rechain_list ();  /*   * Shut down all sockets that have been scheduled for closing.   */  sock = svz_sock_root;   while (sock)    {      next = sock->next;      if (sock->flags & SOCK_FLAG_KILLED)	svz_sock_shutdown (sock);      sock = next;    }}/* * Call this function once before using @code{svz_loop_one()}. */voidsvz_loop_pre (void){  /*    * Setting up control variables. These get set either in the signal    * handler or from a command processing routine.   */  svz_nuke_happened = 0;  svz_reset_happened = 0;  svz_child_died = 0;  svz_pipe_broke = 0;  svz_notify = time (NULL);  /* Run the server loop. */  svz_log (LOG_NOTICE, "entering server loop\n");}/* * Call this function once after using @code{svz_loop_one()}. */voidsvz_loop_post (void){  svz_log (LOG_NOTICE, "leaving server loop\n");  /* Shutdown all socket structures. */  svz_sock_shutdown_all ();}/* * Main server loop. Handle all signals, incoming and outgoing connections  * and listening server sockets. */voidsvz_loop (void){  svz_loop_pre ();  while (!svz_nuke_happened)    {      svz_loop_one ();    }  svz_loop_post ();}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -