Skip to content
Snippets Groups Projects
Commit fba233bb authored by Yang Tse's avatar Yang Tse
Browse files

signal handling to cleanup on SIGINT and SIGTERM

parent 8b494282
No related branches found
No related tags found
No related merge requests found
......@@ -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"
"<P><HR><ADDRESS>" SWSVERSION "</ADDRESS>\n" "</BODY></HTML>\n";
#ifndef WIN32
# if defined(SIGPIPE) && defined(HAVE_SIGNAL)
static volatile int sigpipe; /* Why? It's not used */
static void sigpipe_handler(int sig)
/* do-nothing macro replacement for systems which lack siginterrupt() */
#ifndef HAVE_SIGINTERRUPT
#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 */
sigpipe = 1;
int old_errno = ERRNO;
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
#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
#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
}
# 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)
{
......@@ -525,6 +625,10 @@ static void storerequest(char *reqbuf, ssize_t totalsize)
do {
written = (ssize_t)fwrite((void *) &reqbuf[totalsize-writeleft],
1, (size_t)writeleft, dump);
if(got_exit_signal) {
res = fclose(dump);
return;
}
if (written > 0)
writeleft -= written;
} while ((writeleft > 0) && ((error = ERRNO) == EINTR));
......@@ -598,6 +702,8 @@ static int get_request(curl_socket_t sock, struct httprequest *req)
else
got = sread(sock, reqbuf + req->offset, REQBUFSIZ-1 - req->offset);
}
if(got_exit_signal)
return 1;
if (got <= 0) {
if (got < 0) {
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 */
storerequest(reqbuf, req->pipelining ? req->checkindex : req->offset);
if(got_exit_signal)
return 1;
return fail; /* return 0 on success */
}
......@@ -678,6 +787,8 @@ static int send_doc(curl_socket_t sock, struct httprequest *req)
count = strlen(STREAMTHIS);
for (;;) {
written = swrite(sock, STREAMTHIS, count);
if(got_exit_signal)
break;
if(written != (ssize_t)count) {
logmsg("Stopped streaming");
break;
......@@ -877,6 +988,7 @@ int main(int argc, char *argv[])
#endif /* ENABLE_IPV6 */
curl_socket_t sock = CURL_SOCKET_BAD;
curl_socket_t msgsock = CURL_SOCKET_BAD;
int wrotepidfile = 0;
int flag;
unsigned short port = DEFAULT_PORT;
char *pidname= (char *)".http.pid";
......@@ -935,18 +1047,10 @@ int main(int argc, char *argv[])
#ifdef WIN32
win32_init();
atexit(win32_cleanup);
#else
#ifdef SIGPIPE
#ifdef HAVE_SIGNAL
signal(SIGPIPE, sigpipe_handler);
#endif
#ifdef HAVE_SIGINTERRUPT
siginterrupt(SIGPIPE, 1);
#endif
#endif
#endif
install_signal_handlers();
#ifdef ENABLE_IPV6
if(!use_ipv6)
#endif
......@@ -960,7 +1064,7 @@ int main(int argc, char *argv[])
error = SOCKERRNO;
logmsg("Error creating socket: (%d) %s",
error, strerror(error));
return 1;
goto sws_cleanup;
}
flag = 1;
......@@ -969,8 +1073,7 @@ int main(int argc, char *argv[])
error = SOCKERRNO;
logmsg("setsockopt(SO_REUSEADDR) failed with error: (%d) %s",
error, strerror(error));
sclose(sock);
return 1;
goto sws_cleanup;
}
#ifdef ENABLE_IPV6
......@@ -995,13 +1098,7 @@ int main(int argc, char *argv[])
error = SOCKERRNO;
logmsg("Error binding socket on port %hu: (%d) %s",
port, error, strerror(error));
sclose(sock);
return 1;
}
if(!write_pidfile(pidname)) {
sclose(sock);
return 1;
goto sws_cleanup;
}
logmsg("Running %s version on port %d", ipv_inuse, (int)port);
......@@ -1012,13 +1109,18 @@ int main(int argc, char *argv[])
error = SOCKERRNO;
logmsg("listen() failed with error: (%d) %s",
error, strerror(error));
sclose(sock);
return 1;
goto sws_cleanup;
}
wrotepidfile = write_pidfile(pidname);
if(!wrotepidfile)
goto sws_cleanup;
for (;;) {
msgsock = accept(sock, NULL, NULL);
if(got_exit_signal)
break;
if (CURL_SOCKET_BAD == msgsock) {
error = SOCKERRNO;
logmsg("MAJOR ERROR: accept() failed with error: (%d) %s",
......@@ -1066,6 +1168,9 @@ int main(int argc, char *argv[])
req.pipelining = FALSE;
do {
if(got_exit_signal)
break;
if(get_request(msgsock, &req))
/* non-zero means error, break out of loop */
break;
......@@ -1086,6 +1191,9 @@ int main(int argc, char *argv[])
send_doc(msgsock, &req);
if(got_exit_signal)
break;
if((req.testno < 0) && (req.testno != DOCNUMBER_CONNECT)) {
logmsg("special request received, no persistency");
break;
......@@ -1100,8 +1208,12 @@ int main(int argc, char *argv[])
/* if we got a CONNECT, loop and get another request as well! */
} while(req.open || (req.testno == DOCNUMBER_CONNECT));
if(got_exit_signal)
break;
logmsg("====> Client disconnect");
sclose(msgsock);
msgsock = CURL_SOCKET_BAD;
clear_advisor_read_lock(SERVERLOGS_LOCK);
......@@ -1112,10 +1224,35 @@ int main(int argc, char *argv[])
#endif
}
sclose(sock);
sws_cleanup:
if((msgsock != sock) && (msgsock != CURL_SOCKET_BAD))
sclose(msgsock);
if(sock != CURL_SOCKET_BAD)
sclose(sock);
if(got_exit_signal)
logmsg("signalled to die");
if(wrotepidfile)
unlink(pidname);
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;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment