From 888e542be30fcede9ed10058269a53b975dc677c Mon Sep 17 00:00:00 2001 From: Art Cancro Date: Sun, 13 Dec 1998 23:52:55 +0000 Subject: [PATCH] * Ignore SIGPIPE; this seems to magically make the program bulletproof against broken HTTP connections. * Added a housekeeping thread to periodically remove dead sessions and kill idle sessions. --- webcit/ChangeLog | 4 ++ webcit/context_loop.c | 139 +++++++++++++++++++++++++++--------------- webcit/webcit.h | 2 + webcit/webserver.c | 15 +++++ 4 files changed, 112 insertions(+), 48 deletions(-) diff --git a/webcit/ChangeLog b/webcit/ChangeLog index 505f9eb88..a50432d5c 100644 --- a/webcit/ChangeLog +++ b/webcit/ChangeLog @@ -1,6 +1,10 @@ Sun Dec 13 13:35:12 EST 1998 Art Cancro * context_loop.c: Moved "remove session" into its own function. Check for dead webcit child process before each transaction. + * Ignore SIGPIPE; this seems to magically make the program bulletproof + against broken HTTP connections. + * Added a housekeeping thread to periodically remove dead sessions + and kill idle sessions. Fri Dec 11 21:14:36 EST 1998 Art Cancro * Brought over message reading and entry functions from old WebCit diff --git a/webcit/context_loop.c b/webcit/context_loop.c index ba5160f46..b91a7c204 100644 --- a/webcit/context_loop.c +++ b/webcit/context_loop.c @@ -48,6 +48,7 @@ struct wc_session { int inpipe[2]; /* Data from webserver to session */ int outpipe[2]; /* Data from session to webserver */ pthread_mutex_t critter; /* Critical section uses pipes */ + time_t lastreq; /* Timestamp of most recent http */ }; struct wc_session *SessionList = NULL; @@ -57,6 +58,93 @@ extern const char *defaultport; /* Only one thread may manipulate SessionList at a time... */ pthread_mutex_t MasterCritter; + +/* + * Grab a lock on the session, so other threads don't try to access + * the pipes at the same time. + */ +static void lock_session(struct wc_session *session) { + printf("Locking session %d...\n", session->session_id); + pthread_mutex_lock(&session->critter); + printf(" ...got lock\n"); + } + +/* + * Let go of the lock. + */ +static void unlock_session(struct wc_session *session) { + printf("Unlocking.\n"); + pthread_mutex_unlock(&session->critter); + } + +/* + * Remove a session context from the list + */ +void remove_session(struct wc_session *TheSession, int do_lock) { + struct wc_session *sptr; + + printf("Removing session.\n"); + if (do_lock) pthread_mutex_lock(&MasterCritter); + + if (SessionList==TheSession) { + SessionList = SessionList->next; + } + else { + for (sptr=SessionList; sptr!=NULL; sptr=sptr->next) { + if (sptr->next == TheSession) { + sptr->next = TheSession->next; + } + } + } + + close(TheSession->inpipe[1]); + close(TheSession->outpipe[0]); + if (do_lock) unlock_session(TheSession); + free(TheSession); + + pthread_mutex_unlock(&MasterCritter); + } + + + + +void do_housekeeping(void) { + struct wc_session *sptr; + + pthread_mutex_lock(&MasterCritter); + + /* Kill idle sessions */ + for (sptr=SessionList; sptr!=NULL; sptr=sptr->next) { + if ((time(NULL) - (sptr->lastreq)) > (time_t)WEBCIT_TIMEOUT) { + kill(sptr->webcit_pid, 15); + } + } + + /* Remove dead sessions */ + for (sptr=SessionList; sptr!=NULL; sptr=sptr->next) { + if (kill(sptr->webcit_pid, 0)) { + remove_session(sptr, 0); + } + } + + pthread_mutex_unlock(&MasterCritter); + } + + +/* + * Wake up occasionally and clean house + */ +void housekeeping_loop(void) { + while(1) { + sleep(HOUSEKEEPING); + do_housekeeping(); + } + } + + + + + int GenerateSessionID(void) { return getpid(); } @@ -96,24 +184,6 @@ void req_gets(int sock, char *buf, char *hold) { } } -/* - * Grab a lock on the session, so other threads don't try to access - * the pipes at the same time. - */ -static void lock_session(struct wc_session *session) { - printf("Locking session %d...\n", session->session_id); - pthread_mutex_lock(&session->critter); - printf(" ...got lock\n"); - } - -/* - * Let go of the lock. - */ -static void unlock_session(struct wc_session *session) { - printf("Unlocking.\n"); - pthread_mutex_unlock(&session->critter); - } - /* * lingering_close() a`la Apache. see * http://www.apache.org/docs/misc/fin_wait_2.html for rationale @@ -151,34 +221,6 @@ static int lingering_close(int fd) { return close(fd); } -/* - * Remove a session context from the list - */ -void remove_session(struct wc_session *TheSession) { - struct wc_session *sptr; - - printf("Removing session.\n"); - pthread_mutex_lock(&MasterCritter); - - if (SessionList==TheSession) { - SessionList = SessionList->next; - } - else { - for (sptr=SessionList; sptr!=NULL; sptr=sptr->next) { - if (sptr->next == TheSession) { - sptr->next = TheSession->next; - } - } - } - - close(TheSession->inpipe[1]); - close(TheSession->outpipe[0]); - unlock_session(TheSession); - free(TheSession); - - pthread_mutex_unlock(&MasterCritter); - } - /* * This loop gets called once for every HTTP connection made to WebCit. */ @@ -242,7 +284,7 @@ void *context_loop(int sock) { if (TheSession != NULL) { if (kill(TheSession->webcit_pid, 0)) { printf(" Session is *DEAD* !!\n"); - remove_session(TheSession); + remove_session(TheSession, 1); TheSession = NULL; } } @@ -306,6 +348,7 @@ void *context_loop(int sock) { /* * Send the request to the appropriate session... */ + TheSession->lastreq = time(NULL); printf(" Writing %d lines of command\n", num_lines); printf("%s\n", &req[0][0]); for (a=0; a #include #include +#include #include "webcit.h" #ifndef HAVE_SNPRINTF @@ -42,6 +43,7 @@ int vsnprintf (char *buf, size_t max, const char *fmt, va_list argp); int msock; /* master listening socket */ extern void *context_loop(int); +extern void *housekeeping_loop(void); extern pthread_mutex_t MasterCritter; /* @@ -279,9 +281,22 @@ int main(int argc, char **argv) printf("Attempting to bind to port %d...\n", port); msock = ig_tcp_server(port, 5); printf("Listening on socket %d\n", msock); + signal(SIGPIPE, SIG_IGN); pthread_mutex_init(&MasterCritter, NULL); + + + /* + * Start up the housekeeping thread + */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_create(&SessThread, &attr, + (void* (*)(void*)) housekeeping_loop, NULL); + + + /* * Endless loop. Listen on the master socket. When a connection * comes in, create a socket, a context, and a thread. -- 2.39.2