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

📄 server-core.c

📁 Serveez是一个服务器框架
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * server-core.c - server core implementation * * Copyright (C) 2000, 2001 Stefan Jahn <stefan@lkcc.org> * Copyright (C) 2000 Raimund Jacob <raimi@lkcc.org> * Copyright (C) 1999 Martin Grabmueller <mgrabmue@cs.tu-berlin.de> * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. *  * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. *  * You should have received a copy of the GNU General Public License * along with this package; see the file COPYING.  If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA.   * * $Id: server-core.c,v 1.30 2001/09/29 01:05:02 ela Exp $ * */#if HAVE_CONFIG_H# include <config.h>#endif#define _GNU_SOURCE#include <stdio.h>#include <stdlib.h>/* Some Unices define the strsignal() function depending on    this definition. */#define __EXTENSIONS__#include <string.h>#include <errno.h>#include <fcntl.h>#include <sys/types.h>#include <signal.h>#include <time.h>#if HAVE_UNISTD_H# include <unistd.h>#endif#if HAVE_SYS_TIME_H# include <sys/time.h>#endif#if HAVE_SYS_RESOURCE_H && !defined (__MINGW32__)# include <sys/resource.h>#endif#ifdef __MINGW32__# include <winsock2.h>#endif#ifdef __MINGW32__# include <process.h>#else# include <sys/types.h># include <sys/socket.h># include <netinet/in.h># include <netdb.h># if HAVE_WAIT_H#  include <wait.h># endif# if HAVE_SYS_WAIT_H#  include <sys/wait.h># endif# if HAVE_STRINGS_H#  include <strings.h># endif#endif#include "libserveez/alloc.h"#include "libserveez/util.h"#include "libserveez/snprintf.h"#include "libserveez/array.h"#include "libserveez/vector.h"#include "libserveez/socket.h"#include "libserveez/core.h"#include "libserveez/pipe-socket.h"#include "libserveez/server-loop.h"#include "libserveez/portcfg.h"#include "libserveez/coserver/coserver.h"#include "libserveez/server.h"#include "libserveez/server-core.h"/*  * When @var{svz_nuke_happened} is set to a non-zero value, the server * will terminate its main loop. */int svz_nuke_happened;/* * When @var{svz_reset_happened} gets set to a non-zero value, the server * will try to re-initialize itself on the next execution of the main * loop. */static int svz_reset_happened;/* * The variable @var{svz_pipe_broke} is set to a non-zero value whenever  * the server receives a SIGPIPE signal. */static int svz_pipe_broke;/* * @var{svz_child_died} is set to a non-zero value whenever the server * receives a SIGCHLD signal. */HANDLE svz_child_died;/*  * This holds the time on which the next call to @code{svz_periodic_tasks()} * should occur. */long svz_notify;/* * @var{svz_sock_root} is the pointer to the head of the list of sockets,  * which are handled by the server loop. */svz_socket_t *svz_sock_root = NULL;/* * @var{svz_sock_last} always points to the last structure in the socket queue * and is @var{NULL} when the queue is empty. */svz_socket_t *svz_sock_last = NULL;/* * The @var{svz_sock_lookup_table} array is used to speed up references to  * socket structures by socket's id. */static svz_socket_t **svz_sock_lookup_table = NULL;static int svz_sock_id = 0;static int svz_sock_version = 0;static int svz_sock_limit = 1024; /* Must be binary size ! *//* Pointer to argv[0]. */static char *svz_executable_file = NULL;/* * Set the name of the executable file which uses the core library. This * is usually @code{argv[0]}. */voidsvz_executable (char *file){  svz_executable_file = file;}#ifdef SIGSEGV#define SIGSEGV_TEXT                                                          \  "\nFatal error (access violation)."                                         \  "\nPlease report this bug to <bug-serveez@gnu.org>."                        \  "\nIf possible, please try to obtain a C stack backtrace via\n"             \  "\n  $ gdb %s core"                                                         \  "\n  $ (gdb) where\n"                                                       \  "\nand include this info into your bug report. If you do not have gdb"      \  "\ninstalled you can also try dbx. Also tell us your architecture and"      \  "\noperating system you are currently working on.\n\n"#endif#if defined (SIGSEGV)/* * Segmentation fault exception handler. */RETSIGTYPEsvz_segfault_exception (int sig){#if HAVE_GETRLIMIT  struct rlimit rlim;  rlim.rlim_max = RLIM_INFINITY;  rlim.rlim_cur = RLIM_INFINITY;  setrlimit (RLIMIT_CORE, &rlim);#endif /* HAVE_GETRLIMIT */  signal (sig, SIG_DFL);  fprintf (stderr, SIGSEGV_TEXT,	   svz_executable_file ? svz_executable_file : "binary");  raise (sig);}#endif /* SIGSEGV *//* * Handle some signals to handle server resets (SIGHUP), to ignore * broken pipes (SIGPIPE) and to exit gracefully if requested by the * user (SIGINT, SIGTERM). */RETSIGTYPE svz_signal_handler (int sig){  switch (sig)    {#ifdef SIGHUP    case SIGHUP:      svz_reset_happened = 1;      signal (SIGHUP, svz_signal_handler);      break;#endif#ifdef SIGPIPE    case SIGPIPE:      svz_pipe_broke = 1;      signal (SIGPIPE, svz_signal_handler);      break;#endif#ifdef SIGCHLD    case SIGCHLD:#if HAVE_WAITPID      {	int status, pid;	/* check if the child has been just stopped */	if ((pid = waitpid (-1, &status, WNOHANG | WUNTRACED)) != -1)	  {	    if (!WIFSTOPPED (status))	      svz_child_died = pid;	  }      }#else /* HAVE_WAITPID */      if ((svz_child_died = wait (NULL)) == -1)	svz_child_died = 0;#endif /* not HAVE_WAITPID */      signal (SIGCHLD, svz_signal_handler);      break;#endif#ifdef SIGBREAK    case SIGBREAK:      /*       * reset signal handlers to the default, so the server       * can get killed on second try       */      svz_nuke_happened = 1;      signal (SIGBREAK, SIG_DFL);      break;#endif#ifdef SIGTERM    case SIGTERM:      svz_nuke_happened = 1;      signal (SIGTERM, SIG_DFL);      break;#endif#ifdef SIGINT    case SIGINT:      svz_nuke_happened = 1;      signal (SIGINT, SIG_DFL);      break;#endif#ifdef SIGQUIT    case SIGQUIT:      svz_nuke_happened = 1;      signal (SIGQUIT, SIG_DFL);      break;#endif    default:      svz_log (LOG_DEBUG, "uncaught signal %d\n", sig);      break;    }  svz_log (LOG_WARNING, "signal: %s\n", svz_strsignal (sig));#ifdef NONVOID_SIGNAL  return 0;#endif}/* 65 is hopefully a safe bet, kill(1) accepts 0..64, *sigh* */#define SVZ_NUMBER_OF_SIGNALS 65/* Cached results of strsignal calls. */static svz_array_t *svz_signal_strings = NULL;/* On some platforms strsignal() can be resolved but is nowhere declared. */#if defined (HAVE_STRSIGNAL) && !defined (DECLARED_STRSIGNAL)extern char * strsignal (int);#endif/* * Prepare library so that @code{svz_strsignal()} works. Called * from @code{svz_boot()}. */voidsvz_strsignal_init (void){  int i;  char *str;  const char *format = "Signal %d";  if (svz_signal_strings != NULL)    return;  svz_signal_strings = svz_array_create (SVZ_NUMBER_OF_SIGNALS);  for (i = 0; i < SVZ_NUMBER_OF_SIGNALS; i++)    {#if HAVE_STRSIGNAL      if (NULL == (str = (char *) strsignal (i)))	{	  str = svz_malloc (128);	  svz_snprintf (str, 128, format, i);	  svz_array_add (svz_signal_strings, svz_strdup (str));	  svz_free (str);	}      else	{	  svz_array_add (svz_signal_strings, svz_strdup (str));	}#else /* not HAVE_STRSIGNAL */      str = svz_malloc (128);      svz_snprintf (str, 128, format, i);      svz_array_add (svz_signal_strings, svz_strdup (str));      svz_free (str);#endif /* HAVE_STRSIGNAL */    }}/* * The function @code{svz_strsignal()} does not work afterwards anymore. * Called from @code{svz_halt()}. */voidsvz_strsignal_destroy (void){  int i;  char *value;  svz_array_foreach (svz_signal_strings, value, i)    svz_free (value);  svz_array_destroy (svz_signal_strings);  svz_signal_strings = NULL;}/* * Resolve the given signal number to form a describing string. * This function is reentrant, use it from the signal handler. * It does not return NULL. The returned pointer is shared amongst * all users. For unknown signals (which is not supposed to happen) * the returned string points to a statically allocated buffer (which * destroys the reentrance, of course) [who cares :-]. */char *svz_strsignal (int sig){  static char fallback[128];  if (sig >= 0 && sig < SVZ_NUMBER_OF_SIGNALS)    return (char *) svz_array_get (svz_signal_strings, sig);  else    {      svz_snprintf (fallback, 128, "Impossible signal %d", sig);      return fallback;    }}/* * Abort the process, printing the error message @var{msg} first. */static intsvz_abort (char *msg){  svz_log (LOG_FATAL, "list validation failed: %s\n", msg);  abort ();  return 0;}#if ENABLE_DEBUG/* * This function is for debugging purposes only. It shows a text  * representation of the current socket list. */static voidsvz_sock_print_list (void){  svz_socket_t *sock = svz_sock_root;  while (sock)    {      fprintf (stdout, "id: %04d, sock: %p == %p, prev: %p, next: %p\n",	       sock->id, (void *) sock, 	       (void *) svz_sock_lookup_table[sock->id], 	       (void *) sock->prev, (void *) sock->next);      sock = sock->next;    }  fprintf (stdout, "\n");}/* * Go through the socket list and check if it is still consistent. * Abort the program with an error message, if it is not. */static intsvz_sock_validate_list (void){  svz_socket_t *sock, *prev;  #if 0  svz_sock_print_list ();#endif  prev = NULL;  sock = svz_sock_root;  while (sock)    {      /* check if the descriptors are valid */      if (sock->flags & SOCK_FLAG_SOCK)	{	  if (svz_sock_valid (sock) == -1)	    {	      svz_abort ("invalid socket descriptor");	    }	}      if (sock->flags & SOCK_FLAG_PIPE)	{	  if (svz_pipe_valid (sock) == -1)	    {	      svz_abort ("invalid pipe descriptor");	    }	}            /* check socket list structure */      if (svz_sock_lookup_table[sock->id] != sock)	{	  svz_abort ("lookup table corrupted");	}      if (prev != sock->prev)	{	  svz_abort ("list structure invalid (sock->prev)");	}      prev = sock;      sock = sock->next;    }  if (prev != svz_sock_last)    {      svz_abort ("list structure invalid (last socket)");    }  return 0;}#endif /* ENABLE_DEBUG *//* * Rechain the socket list to prevent sockets from starving at the end * of this list. We will call it every time when a @code{select()} or  * @code{poll()} has returned. Listeners are kept at the beginning of the  * chain anyway. */static voidsvz_sock_rechain_list (void){  svz_socket_t *sock;  svz_socket_t *last_listen;  svz_socket_t *end_socket;  sock = svz_sock_last;  if (sock && sock->prev)    {      end_socket = sock->prev;      for (last_listen = svz_sock_root; last_listen && last_listen != sock && 	     last_listen->flags & (SOCK_FLAG_LISTENING | SOCK_FLAG_PRIORITY) &&	     !(sock->flags & SOCK_FLAG_LISTENING);	   last_listen = last_listen->next);      /* just listeners in the list, return */      if (!last_listen)	return;      /* sock is the only non-listening (connected) socket */      if (sock == last_listen)	return;      /* one step back unless we are at the socket root */      if (last_listen->prev)	{	  last_listen = last_listen->prev;	  /* put sock in front of chain behind listeners */	  sock->next = last_listen->next;	  sock->next->prev = sock;	  /* put sock behind last listener */	  last_listen->next = sock;	  sock->prev = last_listen;	}      else 	{	  /* enqueue at root */	  sock->next = svz_sock_root;	  sock->prev = NULL;	  sock->next->prev = sock;	  svz_sock_root = sock;	}            /* mark the new end of chain */      end_socket->next = NULL;      svz_sock_last = end_socket;    }}/* * Enqueue the socket @var{sock} into the list of sockets handled by * the server loop. */intsvz_sock_enqueue (svz_socket_t *sock){  /* check for validity of pipe descriptors */  if (sock->flags & SOCK_FLAG_PIPE)    {      if (svz_pipe_valid (sock) == -1)	{	  svz_log (LOG_FATAL, "cannot enqueue invalid pipe\n");	  return -1;	}    }  /* check for validity of socket descriptors */  if (sock->flags & SOCK_FLAG_SOCK)    {      if (svz_sock_valid (sock) == -1)	{	  svz_log (LOG_FATAL, "cannot enqueue invalid socket\n");	  return -1;	}    }  /* check lookup table */  if (svz_sock_lookup_table[sock->id] || sock->flags & SOCK_FLAG_ENQUEUED)    {      svz_log (LOG_FATAL, "socket id %d has been already enqueued\n", 	       sock->id);      return -1;    }  /* really enqueue socket */  sock->next = NULL;  sock->prev = NULL;  if (!svz_sock_root)    {      svz_sock_root = sock;    }  else    {      svz_sock_last->next = sock;      sock->prev = svz_sock_last;    }  svz_sock_last = sock;  sock->flags |= SOCK_FLAG_ENQUEUED;  svz_sock_lookup_table[sock->id] = sock;  return 0;}/* * Remove the socket @var{sock} from the list of sockets handled by * the server loop. */intsvz_sock_dequeue (svz_socket_t *sock){  /* check for validity of pipe descriptors */  if (sock->flags & SOCK_FLAG_PIPE)    {      if (svz_pipe_valid (sock) == -1)	{	  svz_log (LOG_FATAL, "cannot dequeue invalid pipe\n");	  return -1;	}    }  /* check for validity of socket descriptors */  if (sock->flags & SOCK_FLAG_SOCK)    {      if (svz_sock_valid (sock) == -1)	{	  svz_log (LOG_FATAL, "cannot dequeue invalid socket\n");	  return -1;	}    }  /* check lookup table */  if (!svz_sock_lookup_table[sock->id] || !(sock->flags & SOCK_FLAG_ENQUEUED))    {      svz_log (LOG_FATAL, "socket id %d has been already dequeued\n", 	       sock->id);      return -1;    }  /* really dequeue socket */  if (sock->next)    sock->next->prev = sock->prev;  else    svz_sock_last = sock->prev;  if (sock->prev)    sock->prev->next = sock->next;  else    svz_sock_root = sock->next;  sock->flags &= ~SOCK_FLAG_ENQUEUED;  svz_sock_lookup_table[sock->id] = NULL;  return 0;}/* * This routine checks the connection frequency of the socket structure * @var{child} for the port configuration of the listener socket structure * @var{parent}. Returns zero if the connection frequency is valid, * otherwise non-zero. */intsvz_sock_check_frequency (svz_socket_t *parent, svz_socket_t *child){  svz_portcfg_t *port = parent->port;  char *ip = svz_inet_ntoa (child->remote_addr);  time_t *t, current;

⌨️ 快捷键说明

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