Commit fba233bb authored by Yang Tse's avatar Yang Tse
Browse files

signal handling to cleanup on SIGINT and SIGTERM

parent 8b494282
Loading
Loading
Loading
Loading
+167 −30
Original line number Original line Diff line number Diff line
@@ -183,16 +183,116 @@ static const char *doc404 = "HTTP/1.1 404 Not Found\r\n"
    "The requested URL was not found on this server.\n"
    "The requested URL was not found on this server.\n"
    "<P><HR><ADDRESS>" SWSVERSION "</ADDRESS>\n" "</BODY></HTML>\n";
    "<P><HR><ADDRESS>" SWSVERSION "</ADDRESS>\n" "</BODY></HTML>\n";


#ifndef WIN32
/* do-nothing macro replacement for systems which lack siginterrupt() */
#  if defined(SIGPIPE) && defined(HAVE_SIGNAL)

static volatile int sigpipe;  /* Why? It's not used */
#ifndef HAVE_SIGINTERRUPT
static void sigpipe_handler(int sig)
#define siginterrupt(x,y) do {} while(0)
#endif

/* vars used to keep around previous signal handlers */

typedef RETSIGTYPE (*SIGHANDLER_T)(int);

#ifdef SIGHUP
static SIGHANDLER_T old_sighup_handler  = SIG_ERR;
#endif

#ifdef SIGPIPE
static SIGHANDLER_T old_sigpipe_handler = SIG_ERR;
#endif

#ifdef SIGALRM
static SIGHANDLER_T old_sigalrm_handler = SIG_ERR;
#endif

#ifdef SIGINT
static SIGHANDLER_T old_sigint_handler  = SIG_ERR;
#endif

#ifdef SIGTERM
static SIGHANDLER_T old_sigterm_handler = SIG_ERR;
#endif

/* var which if set indicates that the program should finish execution */

SIG_ATOMIC_T got_exit_signal = 0;

/* if next is set indicates the first signal handled in exit_signal_handler */

static volatile int exit_signal = 0;

/* signal handler that will be triggered to indicate that the program
  should finish its execution in a controlled manner as soon as possible.
  The first time this is called it will set got_exit_signal to one and
  store in exit_signal the signal that triggered its execution. */

static RETSIGTYPE exit_signal_handler(int signum)
{
{
  (void)sig; /* prevent warning */
  int old_errno = ERRNO;
  sigpipe = 1;
  if(got_exit_signal == 0) {
    got_exit_signal = 1;
    exit_signal = signum;
  }
  }
  (void)signal(signum, exit_signal_handler);
  SET_ERRNO(old_errno);
}

static void install_signal_handlers(void)
{
#ifdef SIGHUP
  /* ignore SIGHUP signal */
  if((old_sighup_handler = signal(SIGHUP, SIG_IGN)) == SIG_ERR)
    logmsg("cannot install SIGHUP handler: %s", strerror(ERRNO));
#endif
#endif
#ifdef SIGPIPE
  /* ignore SIGPIPE signal */
  if((old_sigpipe_handler = signal(SIGPIPE, SIG_IGN)) == SIG_ERR)
    logmsg("cannot install SIGPIPE handler: %s", strerror(ERRNO));
#endif
#ifdef SIGALRM
  /* ignore SIGALRM signal */
  if((old_sigalrm_handler = signal(SIGALRM, SIG_IGN)) == SIG_ERR)
    logmsg("cannot install SIGALRM handler: %s", strerror(ERRNO));
#endif
#endif
#ifdef SIGINT
  /* handle SIGINT signal with our exit_signal_handler */
  if((old_sigint_handler = signal(SIGINT, exit_signal_handler)) == SIG_ERR)
    logmsg("cannot install SIGINT handler: %s", strerror(ERRNO));
  else
    siginterrupt(SIGINT, 1);
#endif
#ifdef SIGTERM
  /* handle SIGTERM signal with our exit_signal_handler */
  if((old_sigterm_handler = signal(SIGTERM, exit_signal_handler)) == SIG_ERR)
    logmsg("cannot install SIGTERM handler: %s", strerror(ERRNO));
  else
    siginterrupt(SIGTERM, 1);
#endif
}

static void restore_signal_handlers(void)
{
#ifdef SIGHUP
  if(SIG_ERR != old_sighup_handler)
    (void)signal(SIGHUP, old_sighup_handler);
#endif
#ifdef SIGPIPE
  if(SIG_ERR != old_sigpipe_handler)
    (void)signal(SIGPIPE, old_sigpipe_handler);
#endif
#ifdef SIGALRM
  if(SIG_ERR != old_sigalrm_handler)
    (void)signal(SIGALRM, old_sigalrm_handler);
#endif
#ifdef SIGINT
  if(SIG_ERR != old_sigint_handler)
    (void)signal(SIGINT, old_sigint_handler);
#endif
#ifdef SIGTERM
  if(SIG_ERR != old_sigterm_handler)
    (void)signal(SIGTERM, old_sigterm_handler);
#endif
}


static int ProcessRequest(struct httprequest *req)
static int ProcessRequest(struct httprequest *req)
{
{
@@ -525,6 +625,10 @@ static void storerequest(char *reqbuf, ssize_t totalsize)
  do {
  do {
    written = (ssize_t)fwrite((void *) &reqbuf[totalsize-writeleft],
    written = (ssize_t)fwrite((void *) &reqbuf[totalsize-writeleft],
                              1, (size_t)writeleft, dump);
                              1, (size_t)writeleft, dump);
    if(got_exit_signal) {
      res = fclose(dump);
      return;
    }
    if (written > 0)
    if (written > 0)
      writeleft -= written;
      writeleft -= written;
  } while ((writeleft > 0) && ((error = ERRNO) == EINTR));
  } while ((writeleft > 0) && ((error = ERRNO) == EINTR));
@@ -598,6 +702,8 @@ static int get_request(curl_socket_t sock, struct httprequest *req)
      else
      else
        got = sread(sock, reqbuf + req->offset, REQBUFSIZ-1 - req->offset);
        got = sread(sock, reqbuf + req->offset, REQBUFSIZ-1 - req->offset);
    }
    }
    if(got_exit_signal)
      return 1;
    if (got <= 0) {
    if (got <= 0) {
      if (got < 0) {
      if (got < 0) {
        logmsg("recv() returned error: %d", SOCKERRNO);
        logmsg("recv() returned error: %d", SOCKERRNO);
@@ -643,6 +749,9 @@ static int get_request(curl_socket_t sock, struct httprequest *req)
  /* dump the request to an external file */
  /* dump the request to an external file */
  storerequest(reqbuf, req->pipelining ? req->checkindex : req->offset);
  storerequest(reqbuf, req->pipelining ? req->checkindex : req->offset);


  if(got_exit_signal)
    return 1;

  return fail; /* return 0 on success */
  return fail; /* return 0 on success */
}
}


@@ -678,6 +787,8 @@ static int send_doc(curl_socket_t sock, struct httprequest *req)
    count = strlen(STREAMTHIS);
    count = strlen(STREAMTHIS);
    for (;;) {
    for (;;) {
      written = swrite(sock, STREAMTHIS, count);
      written = swrite(sock, STREAMTHIS, count);
      if(got_exit_signal)
        break;
      if(written != (ssize_t)count) {
      if(written != (ssize_t)count) {
        logmsg("Stopped streaming");
        logmsg("Stopped streaming");
        break;
        break;
@@ -877,6 +988,7 @@ int main(int argc, char *argv[])
#endif /* ENABLE_IPV6 */
#endif /* ENABLE_IPV6 */
  curl_socket_t sock = CURL_SOCKET_BAD;
  curl_socket_t sock = CURL_SOCKET_BAD;
  curl_socket_t msgsock = CURL_SOCKET_BAD;
  curl_socket_t msgsock = CURL_SOCKET_BAD;
  int wrotepidfile = 0;
  int flag;
  int flag;
  unsigned short port = DEFAULT_PORT;
  unsigned short port = DEFAULT_PORT;
  char *pidname= (char *)".http.pid";
  char *pidname= (char *)".http.pid";
@@ -935,18 +1047,10 @@ int main(int argc, char *argv[])
#ifdef WIN32
#ifdef WIN32
  win32_init();
  win32_init();
  atexit(win32_cleanup);
  atexit(win32_cleanup);
#else

#ifdef SIGPIPE
#ifdef HAVE_SIGNAL
  signal(SIGPIPE, sigpipe_handler);
#endif
#ifdef HAVE_SIGINTERRUPT
  siginterrupt(SIGPIPE, 1);
#endif
#endif
#endif
#endif


  install_signal_handlers();

#ifdef ENABLE_IPV6
#ifdef ENABLE_IPV6
  if(!use_ipv6)
  if(!use_ipv6)
#endif
#endif
@@ -960,7 +1064,7 @@ int main(int argc, char *argv[])
    error = SOCKERRNO;
    error = SOCKERRNO;
    logmsg("Error creating socket: (%d) %s",
    logmsg("Error creating socket: (%d) %s",
           error, strerror(error));
           error, strerror(error));
    return 1;
    goto sws_cleanup;
  }
  }


  flag = 1;
  flag = 1;
@@ -969,8 +1073,7 @@ int main(int argc, char *argv[])
    error = SOCKERRNO;
    error = SOCKERRNO;
    logmsg("setsockopt(SO_REUSEADDR) failed with error: (%d) %s",
    logmsg("setsockopt(SO_REUSEADDR) failed with error: (%d) %s",
           error, strerror(error));
           error, strerror(error));
    sclose(sock);
    goto sws_cleanup;
    return 1;
  }
  }


#ifdef ENABLE_IPV6
#ifdef ENABLE_IPV6
@@ -995,13 +1098,7 @@ int main(int argc, char *argv[])
    error = SOCKERRNO;
    error = SOCKERRNO;
    logmsg("Error binding socket on port %hu: (%d) %s",
    logmsg("Error binding socket on port %hu: (%d) %s",
           port, error, strerror(error));
           port, error, strerror(error));
    sclose(sock);
    goto sws_cleanup;
    return 1;
  }

  if(!write_pidfile(pidname)) {
    sclose(sock);
    return 1;
  }
  }


  logmsg("Running %s version on port %d", ipv_inuse, (int)port);
  logmsg("Running %s version on port %d", ipv_inuse, (int)port);
@@ -1012,13 +1109,18 @@ int main(int argc, char *argv[])
    error = SOCKERRNO;
    error = SOCKERRNO;
    logmsg("listen() failed with error: (%d) %s",
    logmsg("listen() failed with error: (%d) %s",
           error, strerror(error));
           error, strerror(error));
    sclose(sock);
    goto sws_cleanup;
    return 1;
  }
  }


  wrotepidfile = write_pidfile(pidname);
  if(!wrotepidfile)
    goto sws_cleanup;

  for (;;) {
  for (;;) {
    msgsock = accept(sock, NULL, NULL);
    msgsock = accept(sock, NULL, NULL);


    if(got_exit_signal)
      break;
    if (CURL_SOCKET_BAD == msgsock) {
    if (CURL_SOCKET_BAD == msgsock) {
      error = SOCKERRNO;
      error = SOCKERRNO;
      logmsg("MAJOR ERROR: accept() failed with error: (%d) %s",
      logmsg("MAJOR ERROR: accept() failed with error: (%d) %s",
@@ -1066,6 +1168,9 @@ int main(int argc, char *argv[])
    req.pipelining = FALSE;
    req.pipelining = FALSE;


    do {
    do {
      if(got_exit_signal)
        break;

      if(get_request(msgsock, &req))
      if(get_request(msgsock, &req))
        /* non-zero means error, break out of loop */
        /* non-zero means error, break out of loop */
        break;
        break;
@@ -1086,6 +1191,9 @@ int main(int argc, char *argv[])


      send_doc(msgsock, &req);
      send_doc(msgsock, &req);


      if(got_exit_signal)
        break;

      if((req.testno < 0) && (req.testno != DOCNUMBER_CONNECT)) {
      if((req.testno < 0) && (req.testno != DOCNUMBER_CONNECT)) {
        logmsg("special request received, no persistency");
        logmsg("special request received, no persistency");
        break;
        break;
@@ -1100,8 +1208,12 @@ int main(int argc, char *argv[])
      /* if we got a CONNECT, loop and get another request as well! */
      /* if we got a CONNECT, loop and get another request as well! */
    } while(req.open || (req.testno == DOCNUMBER_CONNECT));
    } while(req.open || (req.testno == DOCNUMBER_CONNECT));


    if(got_exit_signal)
      break;

    logmsg("====> Client disconnect");
    logmsg("====> Client disconnect");
    sclose(msgsock);
    sclose(msgsock);
    msgsock = CURL_SOCKET_BAD;


    clear_advisor_read_lock(SERVERLOGS_LOCK);
    clear_advisor_read_lock(SERVERLOGS_LOCK);


@@ -1112,10 +1224,35 @@ int main(int argc, char *argv[])
#endif
#endif
  }
  }


sws_cleanup:

  if((msgsock != sock) && (msgsock != CURL_SOCKET_BAD))
    sclose(msgsock);

  if(sock != CURL_SOCKET_BAD)
    sclose(sock);
    sclose(sock);


  if(got_exit_signal)
    logmsg("signalled to die");

  if(wrotepidfile)
    unlink(pidname);

  clear_advisor_read_lock(SERVERLOGS_LOCK);
  clear_advisor_read_lock(SERVERLOGS_LOCK);


  restore_signal_handlers();

  if(got_exit_signal) {
    logmsg("========> sws exits with signal (%d)", exit_signal);
    /*
     * To properly set the return status of the process we
     * must raise the same signal SIGINT or SIGTERM that we
     * caught and let the old handler take care of it.
     */
    raise(exit_signal);
  }

  logmsg("========> sws quits");
  return 0;
  return 0;
}
}