From: Fredrik Tolf Date: Fri, 28 Dec 2012 06:20:28 +0000 (+0100) Subject: Merge branch 'master' of git.dolda2000.com:/srv/git/r/ashd X-Git-Tag: 0.12~15 X-Git-Url: http://www.dolda2000.com/gitweb/?p=ashd.git;a=commitdiff_plain;h=1fb1c61484cfd92fb9d11cf0b68e98e7d0e6a75f;hp=328d1dbcd801cd602fb245642bede234a7726c0c Merge branch 'master' of git.dolda2000.com:/srv/git/r/ashd --- diff --git a/doc/htparser.doc b/doc/htparser.doc index 9bace5b..08a182d 100644 --- a/doc/htparser.doc +++ b/doc/htparser.doc @@ -80,6 +80,16 @@ OPTIONS After having daemonized, write the PID of the new process to 'PIDFILE'. +SIGNALS +------- + +SIGTERM, SIGINT:: + + Upon first reception, `htparser` closes all listening ports + and the socket to the root handler, but continues to serve all + currently ongoing requests until none remain. Upon second + reception, `htparser` shuts down completely. + EXAMPLES -------- diff --git a/lib/mtio-epoll.c b/lib/mtio-epoll.c index 85ee4a1..72468e0 100644 --- a/lib/mtio-epoll.c +++ b/lib/mtio-epoll.c @@ -43,6 +43,7 @@ struct blocker { }; static int epfd = -1, fdln = 0; +static int exitstatus; static struct blocker **fdlist; static int regfd(struct blocker *bl) @@ -125,6 +126,7 @@ static void remfd(struct blocker *bl) flog(LOG_ERR, "epoll_mod on fd %i: %s", bl->fd, strerror(errno)); } } + bl->reg = 0; } int block(int fd, int ev, time_t to) @@ -158,13 +160,14 @@ int block(int fd, int ev, time_t to) return(rv); } -void ioloop(void) +int ioloop(void) { struct blocker *bl, *nbl; struct epoll_event evr[16]; int i, fd, nev, ev, toval; time_t now, timeout; + exitstatus = 0; epfd = epoll_create(128); fcntl(epfd, F_SETFD, FD_CLOEXEC); for(bl = blockers; bl; bl = nbl) { @@ -185,6 +188,8 @@ void ioloop(void) toval = (timeout - now) * 1000; else toval = 1000; + if(exitstatus) + break; nev = epoll_wait(epfd, evr, sizeof(evr) / sizeof(*evr), toval); if(nev < 0) { if(errno != EINTR) { @@ -217,6 +222,14 @@ void ioloop(void) resume(bl->th, 0); } } + for(bl = blockers; bl; bl = bl->n) + remfd(bl); close(epfd); epfd = -1; + return(exitstatus); +} + +void exitioloop(int status) +{ + exitstatus = status; } diff --git a/lib/mtio-select.c b/lib/mtio-select.c index 6536c95..26e6785 100644 --- a/lib/mtio-select.c +++ b/lib/mtio-select.c @@ -32,6 +32,7 @@ #include static struct blocker *blockers; +static int exitstatus; struct blocker { struct blocker *n, *p; @@ -72,7 +73,7 @@ int block(int fd, int ev, time_t to) return(rv); } -void ioloop(void) +int ioloop(void) { int ret; fd_set rfds, wfds, efds; @@ -82,6 +83,7 @@ void ioloop(void) int maxfd; int ev; + exitstatus = 0; while(blockers != NULL) { FD_ZERO(&rfds); FD_ZERO(&wfds); @@ -100,6 +102,8 @@ void ioloop(void) if((bl->to != 0) && ((timeout == 0) || (timeout > bl->to))) timeout = bl->to; } + if(exitstatus) + return(exitstatus); toval.tv_sec = timeout - now; toval.tv_usec = 0; ret = select(maxfd + 1, &rfds, &wfds, &efds, timeout?(&toval):NULL); @@ -110,21 +114,28 @@ void ioloop(void) * probably is. */ sleep(1); } - } - now = time(NULL); - for(bl = blockers; bl; bl = nbl) { - nbl = bl->n; - ev = 0; - if(FD_ISSET(bl->fd, &rfds)) - ev |= EV_READ; - if(FD_ISSET(bl->fd, &wfds)) - ev |= EV_WRITE; - if(FD_ISSET(bl->fd, &efds)) - ev = -1; - if((ev < 0) || (ev & bl->ev)) - resume(bl->th, ev); - else if((bl->to != 0) && (bl->to <= now)) - resume(bl->th, 0); + } else { + now = time(NULL); + for(bl = blockers; bl; bl = nbl) { + nbl = bl->n; + ev = 0; + if(FD_ISSET(bl->fd, &rfds)) + ev |= EV_READ; + if(FD_ISSET(bl->fd, &wfds)) + ev |= EV_WRITE; + if(FD_ISSET(bl->fd, &efds)) + ev = -1; + if((ev < 0) || (ev & bl->ev)) + resume(bl->th, ev); + else if((bl->to != 0) && (bl->to <= now)) + resume(bl->th, 0); + } } } + return(0); +} + +void exitioloop(int status) +{ + exitstatus = status; } diff --git a/lib/mtio.h b/lib/mtio.h index 874eec6..2ea0eb5 100644 --- a/lib/mtio.h +++ b/lib/mtio.h @@ -7,7 +7,8 @@ #define EV_WRITE 2 int block(int fd, int ev, time_t to); -void ioloop(void); +int ioloop(void); +void exitioloop(int status); FILE *mtstdopen(int fd, int issock, int timeout, char *mode); #endif diff --git a/lib/utils.h b/lib/utils.h index 2de1df6..2066918 100644 --- a/lib/utils.h +++ b/lib/utils.h @@ -16,6 +16,7 @@ #define bufinit(buf) memset(&(buf), 0, sizeof(buf)) #define buffree(buf) do { if((buf).b != NULL) {free((buf).b);} bufinit(buf); } while(0) #define sizebuf(buf, wanted) (_sizebuf((struct buffer *)&(buf), (wanted), sizeof(*((buf).b)))) +#define bufdel(buf, i) (memmove((buf).b + (i), (buf).b + (i) + 1, (--((buf).d) - (i)) * sizeof(*((buf).b)))) #define bufadd(buf, new) \ do { \ _sizebuf((struct buffer *)&(buf), (buf).d + 1, sizeof(*((buf).b))); \ diff --git a/src/htparser.c b/src/htparser.c index e6f545a..8d0b515 100644 --- a/src/htparser.c +++ b/src/htparser.c @@ -41,6 +41,7 @@ static int plex; static char *pidfile = NULL; static int daemonize, usesyslog; +struct mtbuf listeners; static void trimx(struct hthead *req) { @@ -290,7 +291,7 @@ void serve(FILE *in, struct conn *conn) out = NULL; req = resp = NULL; - while(1) { + while(plex >= 0) { if((req = parsereq(in)) == NULL) break; if(!canonreq(req)) @@ -299,7 +300,7 @@ void serve(FILE *in, struct conn *conn) if((conn->initreq != NULL) && conn->initreq(conn, req)) break; - if(block(plex, EV_WRITE, 60) <= 0) + if((plex < 0) || block(plex, EV_WRITE, 60) <= 0) break; if(socketpair(PF_UNIX, SOCK_STREAM, 0, pfds)) break; @@ -404,22 +405,33 @@ static void plexwatch(struct muth *muth, va_list args) { vavar(int, fd); char *buf; - int ret; + int i, ret; while(1) { - block(fd, EV_READ, 0); + if(block(fd, EV_READ, 0) == 0) + break; buf = smalloc(65536); ret = recv(fd, buf, 65536, 0); if(ret < 0) { flog(LOG_WARNING, "received error on rootplex read channel: %s", strerror(errno)); exit(1); } else if(ret == 0) { - exit(0); + free(buf); + break; } /* Maybe I'd like to implement some protocol in this direction * some day... */ free(buf); } + close(plex); + plex = -1; + for(i = 0; i < listeners.d; i++) { + if(listeners.b[i] == muth) + bufdel(listeners, i); + } + flog(LOG_INFO, "root handler exited, so shutting down listening..."); + while(listeners.d > 0) + resume(listeners.b[0], 0); } static void initroot(void *uu) @@ -494,9 +506,14 @@ static void addport(char *spec) buffree(vals); } +static void sighandler(int sig) +{ + exitioloop(1); +} + int main(int argc, char **argv) { - int c; + int c, d; int i, s1; char *root; FILE *pidout; @@ -548,7 +565,7 @@ int main(int argc, char **argv) flog(LOG_ERR, "could not spawn root multiplexer: %s", strerror(errno)); return(1); } - mustart(plexwatch, plex); + bufadd(listeners, mustart(plexwatch, plex)); pidout = NULL; if(pidfile != NULL) { if((pidout = fopen(pidfile, "w")) == NULL) { @@ -575,6 +592,9 @@ int main(int argc, char **argv) } } signal(SIGPIPE, SIG_IGN); + signal(SIGCHLD, SIG_IGN); + signal(SIGINT, sighandler); + signal(SIGTERM, sighandler); if(daemonize) { daemon(0, 0); } @@ -582,6 +602,22 @@ int main(int argc, char **argv) fprintf(pidout, "%i\n", getpid()); fclose(pidout); } - ioloop(); + d = 0; + while(!d) { + switch(ioloop()) { + case 0: + d = 1; + break; + case 1: + if(listeners.d > 0) { + while(listeners.d > 0) + resume(listeners.b[0], 0); + flog(LOG_INFO, "no longer listening"); + } else { + d = 1; + } + break; + } + } return(0); } diff --git a/src/htparser.h b/src/htparser.h index 88bfb6e..7bd60a0 100644 --- a/src/htparser.h +++ b/src/htparser.h @@ -6,6 +6,11 @@ struct conn { void *pdata; }; +struct mtbuf { + struct muth **b; + size_t s, d; +}; + void serve(FILE *in, struct conn *conn); int listensock4(int port); @@ -16,4 +21,6 @@ void handleplain(int argc, char **argp, char **argv); void handlegnussl(int argc, char **argp, char **argv); #endif +extern struct mtbuf listeners; + #endif diff --git a/src/plaintcp.c b/src/plaintcp.c index b898e37..7d36a1d 100644 --- a/src/plaintcp.c +++ b/src/plaintcp.c @@ -168,13 +168,14 @@ void servetcp(struct muth *muth, va_list args) static void listenloop(struct muth *muth, va_list args) { vavar(struct tcpport *, tcp); - int ns; + int i, ns; struct sockaddr_storage name; socklen_t namelen; while(1) { namelen = sizeof(name); - block(tcp->fd, EV_READ, 0); + if(block(tcp->fd, EV_READ, 0) == 0) + goto out; ns = accept(tcp->fd, (struct sockaddr *)&name, &namelen); if(ns < 0) { flog(LOG_ERR, "accept: %s", strerror(errno)); @@ -186,6 +187,10 @@ static void listenloop(struct muth *muth, va_list args) out: close(tcp->fd); free(tcp); + for(i = 0; i < listeners.d; i++) { + if(listeners.b[i] == muth) + bufdel(listeners, i); + } } void handleplain(int argc, char **argp, char **argv) @@ -215,7 +220,7 @@ void handleplain(int argc, char **argp, char **argv) omalloc(tcp); tcp->fd = fd; tcp->sport = port; - mustart(listenloop, tcp); + bufadd(listeners, mustart(listenloop, tcp)); if((fd = listensock4(port)) < 0) { if(errno != EADDRINUSE) { flog(LOG_ERR, "could not listen on IPv4 (port %i): %s", port, strerror(errno)); @@ -225,6 +230,6 @@ void handleplain(int argc, char **argp, char **argv) omalloc(tcp); tcp->fd = fd; tcp->sport = port; - mustart(listenloop, tcp); + bufadd(listeners, mustart(listenloop, tcp)); } } diff --git a/src/ssl-gnutls.c b/src/ssl-gnutls.c index d4862d4..0d4dd22 100644 --- a/src/ssl-gnutls.c +++ b/src/ssl-gnutls.c @@ -359,13 +359,14 @@ out: static void listenloop(struct muth *muth, va_list args) { vavar(struct sslport *, pd); - int ns; + int i, ns; struct sockaddr_storage name; socklen_t namelen; while(1) { namelen = sizeof(name); - block(pd->fd, EV_READ, 0); + if(block(pd->fd, EV_READ, 0) == 0) + goto out; ns = accept(pd->fd, (struct sockaddr *)&name, &namelen); if(ns < 0) { flog(LOG_ERR, "accept: %s", strerror(errno)); @@ -377,6 +378,10 @@ static void listenloop(struct muth *muth, va_list args) out: close(pd->fd); free(pd); + for(i = 0; i < listeners.d; i++) { + if(listeners.b[i] == muth) + bufdel(listeners, i); + } } static gnutls_dh_params_t dhparams(void) @@ -606,7 +611,7 @@ void handlegnussl(int argc, char **argp, char **argv) pd->sport = port; pd->creds = creds; pd->ncreds = ncreds.b; - mustart(listenloop, pd); + bufadd(listeners, mustart(listenloop, pd)); if((fd = listensock4(port)) < 0) { if(errno != EADDRINUSE) { flog(LOG_ERR, "could not listen on IPv4 port (port %i): %s", port, strerror(errno)); @@ -617,7 +622,7 @@ void handlegnussl(int argc, char **argp, char **argv) pd->fd = fd; pd->sport = port; pd->creds = creds; - mustart(listenloop, pd); + bufadd(listeners, mustart(listenloop, pd)); } }