From: Fredrik Tolf Date: Wed, 8 Aug 2012 17:19:24 +0000 (+0200) Subject: Added the `httimed' program. X-Git-Tag: 0.11~3 X-Git-Url: http://www.dolda2000.com/gitweb/?p=ashd.git;a=commitdiff_plain;h=c1fc98261011ee0758a49da491cf4bd4e47eb8eb Added the `httimed' program. --- diff --git a/doc/Makefile.am b/doc/Makefile.am index e018ed8..dc88692 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,6 +1,6 @@ dist_man1_MANS = callcgi.1 dirplex.1 htparser.1 patplex.1 sendfile.1 \ userplex.1 htls.1 callscgi.1 accesslog.1 htextauth.1 \ - callfcgi.1 multifscgi.1 errlogger.1 + callfcgi.1 multifscgi.1 errlogger.1 httimed.1 dist_man7_MANS = ashd.7 diff --git a/doc/httimed.doc b/doc/httimed.doc new file mode 100644 index 0000000..d34f474 --- /dev/null +++ b/doc/httimed.doc @@ -0,0 +1,49 @@ +httimed(1) +========== + +NAME +---- +httimed - Ashd handler expiration pipe + +SYNOPSIS +-------- +*httimed* [*-h*] [*-t* 'TIMEOUT'] 'CHILD' ['ARGS'...] + +DESCRIPTION +----------- + +The *httimed* handler starts a single child handler which it passes +all request it receives unmodified, and in addition keeps track of +time and simply exits if no requests are received in a certain +interval, which might be useful for handlers which are only rarely +used and waste unproportionally much system resources if kept beyond +their usefulness. + +*httimed* is a persistent handler, as defined in *ashd*(7), and the +specified child handler must also be a persistent handler. + +By default, *httimed* exits if it receives no requests in five +minutes, but the time interval can be specified using the *-t* option. + +If the child handler exits, *httimed* exits as well. + +OPTIONS +------- + +*-h*:: + + Print a brief help message to standard output and exit. + +*-t* 'TIMEOUT':: + + Exit if no requests are received after 'TIMEOUT' seconds since + the last one. If *-t* is not specified, 'TIMEOUT' is five + minutes by default. + +AUTHOR +------ +Fredrik Tolf + +SEE ALSO +-------- +*ashd*(7) diff --git a/src/.gitignore b/src/.gitignore index 4a9153f..582f3e7 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -11,3 +11,4 @@ /multifscgi /errlogger /psendfile +/httimed diff --git a/src/Makefile.am b/src/Makefile.am index 394e353..8a08744 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,7 +2,7 @@ SUBDIRS = dirplex bin_PROGRAMS = htparser sendfile callcgi patplex userplex htls \ callscgi accesslog htextauth callfcgi multifscgi \ - errlogger + errlogger httimed noinst_PROGRAMS=psendfile diff --git a/src/httimed.c b/src/httimed.c new file mode 100644 index 0000000..2c939c5 --- /dev/null +++ b/src/httimed.c @@ -0,0 +1,106 @@ +/* + ashd - A Sane HTTP Daemon + Copyright (C) 2008 Fredrik Tolf + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include + +static void usage(FILE *out) +{ + fprintf(out, "usage: httimed [-h] [-t TIMEOUT] CHILD [ARGS...]\n"); +} + +int main(int argc, char **argv) +{ + int c, t, ret; + int ch, fd; + struct hthead *req; + struct pollfd pfd[2]; + time_t lreq, now; + + t = 300; + while((c = getopt(argc, argv, "+ht:")) >= 0) { + switch(c) { + case 'h': + usage(stdout); + exit(0); + case 't': + t = atoi(optarg); + if(t < 1) { + fprintf(stderr, "httimed: timeout must be positive\n"); + exit(1); + } + break; + } + } + if(argc - optind < 1) { + usage(stderr); + exit(1); + } + if((ch = stdmkchild(argv + optind, NULL, NULL)) < 0) { + flog(LOG_ERR, "httimed: could not fork child: %s", strerror(errno)); + exit(1); + } + lreq = time(NULL); + while(1) { + memset(pfd, 0, sizeof(pfd)); + pfd[0].fd = 0; + pfd[0].events = POLLIN; + pfd[1].fd = ch; + pfd[1].events = POLLHUP; + if((ret = poll(pfd, 2, (t + 1 - (time(NULL) - lreq)) * 1000)) < 0) { + if(errno != EINTR) { + flog(LOG_ERR, "httimed: error in poll: %s", strerror(errno)); + exit(1); + } + } + now = time(NULL); + if(pfd[0].revents) { + if((fd = recvreq(0, &req)) < 0) { + if(errno == 0) + break; + flog(LOG_ERR, "httimed: error in recvreq: %s", strerror(errno)); + exit(1); + } + if(sendreq(ch, req, fd)) { + flog(LOG_ERR, "httimed: could not pass request to child: %s", strerror(errno)); + exit(1); + } + freehthead(req); + close(fd); + } + if(pfd[1].revents & POLLHUP) + break; + if(now - lreq > t) + break; + lreq = now; + } + return(0); +}