summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYang Tse <yangsita@gmail.com>2009-11-26 04:38:29 +0000
committerYang Tse <yangsita@gmail.com>2009-11-26 04:38:29 +0000
commitfba233bb34d768f41e8ff35af54ba637f61eef2b (patch)
tree0e66a96b857c26ba1823ce391cc2a18c125fd143
parent8b494282989bf34dc8596a9b2338afa58e1eb68b (diff)
downloadgnurl-fba233bb34d768f41e8ff35af54ba637f61eef2b.tar.gz
gnurl-fba233bb34d768f41e8ff35af54ba637f61eef2b.tar.bz2
gnurl-fba233bb34d768f41e8ff35af54ba637f61eef2b.zip
signal handling to cleanup on SIGINT and SIGTERM
-rw-r--r--tests/server/sws.c197
1 files changed, 167 insertions, 30 deletions
diff --git a/tests/server/sws.c b/tests/server/sws.c
index 0e17d6ebd..fab7ae59a 100644
--- a/tests/server/sws.c
+++ b/tests/server/sws.c
@@ -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;
}