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

📄 server.c

📁 快速开发
💻 C
📖 第 1 页 / 共 2 页
字号:
    err_sys_quit(errfd, "ERROR: can't change user id: setuid");  err_report(errfd, "INFO: changed process user id to '%s'", username);}/******************************************************************/static void open_log_files(void){  int fd;  char str[32];  if (interactive_mode)    return;  /* Open access log */  if (log_access)    logbuf_open();  /* Open and write pid to pid file */  if ((fd = open(PID_FILE, O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0)    err_sys_quit(errfd, "ERROR: can't open pid file: open");  sprintf(str, "%d\n", (int)getpid());  if (write(fd, str, strlen(str)) != strlen(str))    err_sys_quit(errfd, "ERROR: can't write to pid file: write");  close(fd);  /* Open error log file */  if ((fd = open(ERRORS_FILE, O_CREAT | O_WRONLY | O_APPEND, 0644)) < 0)    err_sys_quit(errfd, "ERROR: can't open error log file: open");  errfd = fd;  err_report(errfd, "INFO: starting the server...");}/******************************************************************/static void start_processes(void){  int i, status;  pid_t pid;  sigset_t mask, omask;  if (interactive_mode) {    my_index = 0;    my_pid = getpid();    return;  }  for (i = 0; i < vp_count; i++) {    if ((pid = fork()) < 0) {      err_sys_report(errfd, "ERROR: can't create process: fork");      if (i == 0)	exit(1);      err_report(errfd, "WARN: started only %d processes out of %d", i,		 vp_count);      vp_count = i;      break;    }    if (pid == 0) {      my_index = i;      my_pid = getpid();      /* Child returns to continue in main() */      return;    }    vp_pids[i] = pid;  }  /*   * Parent process becomes a "watchdog" and never returns to main().   */  /* Install signal handlers */  Signal(SIGTERM, wdog_sighandler);  /* terminate */  Signal(SIGHUP,  wdog_sighandler);  /* restart   */  Signal(SIGUSR1, wdog_sighandler);  /* dump info */  /* Now go to sleep waiting for a child termination or a signal */  for ( ; ; ) {    if ((pid = wait(&status)) < 0) {      if (errno == EINTR)	continue;      err_sys_quit(errfd, "ERROR: watchdog: wait");    }    /* Find index of the exited child */    for (i = 0; i < vp_count; i++) {      if (vp_pids[i] == pid)	break;    }    /* Block signals while printing and forking */    sigemptyset(&mask);    sigaddset(&mask, SIGTERM);    sigaddset(&mask, SIGHUP);    sigaddset(&mask, SIGUSR1);    sigprocmask(SIG_BLOCK, &mask, &omask);    if (WIFEXITED(status))      err_report(errfd, "WARN: watchdog: process %d (pid %d) exited"		 " with status %d", i, pid, WEXITSTATUS(status));    else if (WIFSIGNALED(status))      err_report(errfd, "WARN: watchdog: process %d (pid %d) terminated"		 " by signal %d", i, pid, WTERMSIG(status));    else if (WIFSTOPPED(status))      err_report(errfd, "WARN: watchdog: process %d (pid %d) stopped"		 " by signal %d", i, pid, WSTOPSIG(status));    else      err_report(errfd, "WARN: watchdog: process %d (pid %d) terminated:"		 " unknown termination reason", i, pid);    /* Fork another VP */    if ((pid = fork()) < 0) {      err_sys_report(errfd, "ERROR: watchdog: can't create process: fork");    } else if (pid == 0) {      my_index = i;      my_pid = getpid();      /* Child returns to continue in main() */      return;    }    vp_pids[i] = pid;    /* Restore the signal mask */    sigprocmask(SIG_SETMASK, &omask, NULL);  }}/******************************************************************/static void wdog_sighandler(int signo){  int i, err;  /* Save errno */  err = errno;  /* Forward the signal to all children */  for (i = 0; i < vp_count; i++) {    if (vp_pids[i] > 0)      kill(vp_pids[i], signo);  }  /*   * It is safe to do pretty much everything here because process is   * sleeping in wait() which is async-safe.   */  switch (signo) {  case SIGHUP:    err_report(errfd, "INFO: watchdog: caught SIGHUP");    /* Reopen log files - needed for log rotation */    if (log_access) {      logbuf_close();      logbuf_open();    }    close(errfd);    if ((errfd = open(ERRORS_FILE, O_CREAT | O_WRONLY | O_APPEND, 0644)) < 0)      err_sys_quit(STDERR_FILENO, "ERROR: watchdog: open");    break;  case SIGTERM:    /* Non-graceful termination */    err_report(errfd, "INFO: watchdog: caught SIGTERM, terminating");    unlink(PID_FILE);    exit(0);  case SIGUSR1:    err_report(errfd, "INFO: watchdog: caught SIGUSR1");    break;  default:    err_report(errfd, "INFO: watchdog: caught signal %d", signo);  }  /* Restore errno */  errno = err;}/******************************************************************/static void install_sighandlers(void){  sigset_t mask;  int p[2];  /* Create signal pipe */  if (pipe(p) < 0)    err_sys_quit(errfd, "ERROR: process %d (pid %d): can't create"		 " signal pipe: pipe", my_index, my_pid);  if ((sig_pipe[0] = st_netfd_open(p[0])) == NULL ||      (sig_pipe[1] = st_netfd_open(p[1])) == NULL)    err_sys_quit(errfd, "ERROR: process %d (pid %d): can't create"		 " signal pipe: st_netfd_open", my_index, my_pid);  /* Install signal handlers */  Signal(SIGTERM, child_sighandler);  /* terminate */  Signal(SIGHUP,  child_sighandler);  /* restart   */  Signal(SIGUSR1, child_sighandler);  /* dump info */  /* Unblock signals */  sigemptyset(&mask);  sigaddset(&mask, SIGTERM);  sigaddset(&mask, SIGHUP);  sigaddset(&mask, SIGUSR1);  sigprocmask(SIG_UNBLOCK, &mask, NULL);}/******************************************************************/static void child_sighandler(int signo){  int err, fd;  err = errno;  fd = st_netfd_fileno(sig_pipe[1]);  /* write() is async-safe */  if (write(fd, &signo, sizeof(int)) != sizeof(int))    err_sys_quit(errfd, "ERROR: process %d (pid %d): child's signal"		 " handler: write", my_index, my_pid);  errno = err;}/****************************************************************** * The "main" function of the signal processing thread. *//* ARGSUSED */static void *process_signals(void *arg){  int signo;  for ( ; ; ) {    /* Read the next signal from the signal pipe */    if (st_read(sig_pipe[0], &signo, sizeof(int),     ST_UTIME_NO_TIMEOUT) != sizeof(int))      err_sys_quit(errfd, "ERROR: process %d (pid %d): signal processor:"		   " st_read", my_index, my_pid);    switch (signo) {    case SIGHUP:      err_report(errfd, "INFO: process %d (pid %d): caught SIGHUP,"		 " reloading configuration", my_index, my_pid);      if (interactive_mode) {	load_configs();	break;      }      /* Reopen log files - needed for log rotation */      if (log_access) {	logbuf_flush();	logbuf_close();	logbuf_open();      }      close(errfd);      if ((errfd = open(ERRORS_FILE, O_CREAT | O_WRONLY | O_APPEND, 0644)) < 0)	err_sys_quit(STDERR_FILENO, "ERROR: process %d (pid %d): signal"		     " processor: open", my_index, my_pid);      /* Reload configuration */      load_configs();      break;    case SIGTERM:      /*       * Terminate ungracefully since it is generally not known how long       * it will take to gracefully complete all client sessions.       */      err_report(errfd, "INFO: process %d (pid %d): caught SIGTERM,"		 " terminating", my_index, my_pid);      if (log_access)	logbuf_flush();      exit(0);    case SIGUSR1:      err_report(errfd, "INFO: process %d (pid %d): caught SIGUSR1",		 my_index, my_pid);      /* Print server info to stderr */      dump_server_info();      break;    default:      err_report(errfd, "INFO: process %d (pid %d): caught signal %d",		 my_index, my_pid, signo);    }  }  /* NOTREACHED */  return NULL;}/****************************************************************** * The "main" function of the access log flushing thread. *//* ARGSUSED */static void *flush_acclog_buffer(void *arg){  for ( ; ; ) {    st_sleep(ACCLOG_FLUSH_INTERVAL);    logbuf_flush();  }  /* NOTREACHED */  return NULL;}/******************************************************************/static void start_threads(void){  long i, n;  /* Create access log flushing thread */  if (log_access && st_thread_create(flush_acclog_buffer, NULL, 0, 0) == NULL)    err_sys_quit(errfd, "ERROR: process %d (pid %d): can't create"		 " log flushing thread", my_index, my_pid);  /* Create connections handling threads */  for (i = 0; i < sk_count; i++) {    err_report(errfd, "INFO: process %d (pid %d): starting %d threads"	       " on %s:%d", my_index, my_pid, max_wait_threads,	       srv_socket[i].addr, srv_socket[i].port);    WAIT_THREADS(i) = 0;    BUSY_THREADS(i) = 0;    RQST_COUNT(i) = 0;    for (n = 0; n < max_wait_threads; n++) {      if (st_thread_create(handle_connections, (void *)i, 0, 0) != NULL)	WAIT_THREADS(i)++;      else	err_sys_report(errfd, "ERROR: process %d (pid %d): can't create"		       " thread", my_index, my_pid);    }    if (WAIT_THREADS(i) == 0)      exit(1);  }}/******************************************************************/static void *handle_connections(void *arg){  st_netfd_t srv_nfd, cli_nfd;  struct sockaddr_in from;  int fromlen;  long i = (long) arg;  srv_nfd = srv_socket[i].nfd;  fromlen = sizeof(from);  while (WAIT_THREADS(i) <= max_wait_threads) {    cli_nfd = st_accept(srv_nfd, (struct sockaddr *)&from, &fromlen,     ST_UTIME_NO_TIMEOUT);    if (cli_nfd == NULL) {      err_sys_report(errfd, "ERROR: can't accept connection: st_accept");      continue;    }    /* Save peer address, so we can retrieve it later */    st_netfd_setspecific(cli_nfd, &from.sin_addr, NULL);    WAIT_THREADS(i)--;    BUSY_THREADS(i)++;    if (WAIT_THREADS(i) < min_wait_threads && TOTAL_THREADS(i) < max_threads) {      /* Create another spare thread */      if (st_thread_create(handle_connections, (void *)i, 0, 0) != NULL)	WAIT_THREADS(i)++;      else	err_sys_report(errfd, "ERROR: process %d (pid %d): can't create"		       " thread", my_index, my_pid);    }    handle_session(i, cli_nfd);    st_netfd_close(cli_nfd);    WAIT_THREADS(i)++;    BUSY_THREADS(i)--;  }  WAIT_THREADS(i)--;  return NULL;}/******************************************************************/static void dump_server_info(void){  char *buf;  int i, len;  if ((buf = malloc(sk_count * 512)) == NULL) {    err_sys_report(errfd, "ERROR: malloc failed");    return;  }  len = sprintf(buf, "\n\nProcess #%d (pid %d):\n", my_index, (int)my_pid);  for (i = 0; i < sk_count; i++) {    len += sprintf(buf + len, "\nListening Socket #%d:\n"		   "-------------------------\n"		   "Address                    %s:%d\n"		   "Thread limits (min/max)    %d/%d\n"		   "Waiting threads            %d\n"		   "Busy threads               %d\n"		   "Requests served            %d\n",		   i, srv_socket[i].addr, srv_socket[i].port,		   max_wait_threads, max_threads,		   WAIT_THREADS(i), BUSY_THREADS(i), RQST_COUNT(i));  }  write(STDERR_FILENO, buf, len);  free(buf);}/****************************************************************** * Stubs *//* * Session handling function stub. Just dumps small HTML page. */void handle_session(long srv_socket_index, st_netfd_t cli_nfd){  static char resp[] = "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n"                       "Connection: close\r\n\r\n<H2>It worked!</H2>\n";  char buf[512];  int n = sizeof(resp) - 1;  struct in_addr *from = st_netfd_getspecific(cli_nfd);  if (st_read(cli_nfd, buf, sizeof(buf), SEC2USEC(REQUEST_TIMEOUT)) < 0) {    err_sys_report(errfd, "WARN: can't read request from %s: st_read",		   inet_ntoa(*from));    return;  }  if (st_write(cli_nfd, resp, n, ST_UTIME_NO_TIMEOUT) != n) {    err_sys_report(errfd, "WARN: can't write response to %s: st_write",		   inet_ntoa(*from));    return;  }  RQST_COUNT(srv_socket_index)++;}/* * Configuration loading function stub. */void load_configs(void){  err_report(errfd, "INFO: process %d (pid %d): configuration loaded",	     my_index, my_pid);}/* * Buffered access logging methods. * Note that stdio functions (fopen(3), fprintf(3), fflush(3), etc.) cannot * be used if multiple VPs are created since these functions can flush buffer * at any point and thus write only partial log record to disk. * Also, it is completely safe for all threads of the same VP to write to * the same log buffer without any mutex protection (one buffer per VP, of * course). */void logbuf_open(void){}void logbuf_flush(void){}void logbuf_close(void){}/****************************************************************** * Small utility functions */static void Signal(int sig, void (*handler)(int)){  struct sigaction sa;  sa.sa_handler = handler;  sigemptyset(&sa.sa_mask);  sa.sa_flags = 0;  sigaction(sig, &sa, NULL);}static int cpu_count(void){  int n;#if defined (_SC_NPROCESSORS_ONLN)  n = (int) sysconf(_SC_NPROCESSORS_ONLN);#elif defined (_SC_NPROC_ONLN)  n = (int) sysconf(_SC_NPROC_ONLN);#elif defined (HPUX)#include <sys/mpctl.h>  n = mpctl(MPC_GETNUMSPUS, 0, 0);#else  n = -1;  errno = ENOSYS;#endif  return n;}/******************************************************************/

⌨️ 快捷键说明

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