doc: Documented htpipe.
[ashd.git] / src / httimed.c
1 /*
2     ashd - A Sane HTTP Daemon
3     Copyright (C) 2008  Fredrik Tolf <fredrik@dolda2000.com>
4
5     This program is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <time.h>
25 #include <sys/poll.h>
26 #include <sys/socket.h>
27
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 #include <utils.h>
32 #include <log.h>
33 #include <req.h>
34 #include <proc.h>
35
36 static void usage(FILE *out)
37 {
38     fprintf(out, "usage: httimed [-h] [-t TIMEOUT] CHILD [ARGS...]\n");
39 }
40
41 int main(int argc, char **argv)
42 {
43     int c, timeout, ret;
44     int ch, fd;
45     struct hthead *req;
46     struct pollfd pfd[2];
47     time_t lreq, now;
48     
49     timeout = 300;
50     while((c = getopt(argc, argv, "+ht:")) >= 0) {
51         switch(c) {
52         case 'h':
53             usage(stdout);
54             exit(0);
55         case 't':
56             timeout = atoi(optarg);
57             if(timeout < 1) {
58                 fprintf(stderr, "httimed: timeout must be positive\n");
59                 exit(1);
60             }
61             break;
62         }
63     }
64     if(argc - optind < 1) {
65         usage(stderr);
66         exit(1);
67     }
68     if((ch = stdmkchild(argv + optind, NULL, NULL)) < 0) {
69         flog(LOG_ERR, "httimed: could not fork child: %s", strerror(errno));
70         exit(1);
71     }
72     lreq = time(NULL);
73     while(1) {
74         memset(pfd, 0, sizeof(pfd));
75         pfd[0].fd = 0;
76         pfd[0].events = POLLIN;
77         pfd[1].fd = ch;
78         pfd[1].events = POLLHUP;
79         if((ret = poll(pfd, 2, (timeout < 0)?-1:((timeout + 1 - (time(NULL) - lreq)) * 1000))) < 0) {
80             if(errno != EINTR) {
81                 flog(LOG_ERR, "httimed: error in poll: %s", strerror(errno));
82                 exit(1);
83             }
84         }
85         now = time(NULL);
86         if(pfd[0].revents) {
87             if((fd = recvreq(0, &req)) < 0) {
88                 if(errno == 0)
89                     break;
90                 flog(LOG_ERR, "httimed: error in recvreq: %s", strerror(errno));
91                 exit(1);
92             }
93             if(sendreq(ch, req, fd)) {
94                 flog(LOG_ERR, "httimed: could not pass request to child: %s", strerror(errno));
95                 exit(1);
96             }
97             freehthead(req);
98             close(fd);
99         }
100         if((pfd[1].revents & POLLHUP) || (now - lreq > timeout)) {
101             timeout = -1;
102             shutdown(0, SHUT_RDWR);
103         }
104         lreq = now;
105     }
106     return(0);
107 }