lib: Reimplemented mtio-epoll timeout checking as a bin-heap.
[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
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30 #include <utils.h>
31 #include <log.h>
32 #include <req.h>
33 #include <proc.h>
34
35 static void usage(FILE *out)
36 {
37     fprintf(out, "usage: httimed [-h] [-t TIMEOUT] CHILD [ARGS...]\n");
38 }
39
40 int main(int argc, char **argv)
41 {
42     int c, t, ret;
43     int ch, fd;
44     struct hthead *req;
45     struct pollfd pfd[2];
46     time_t lreq, now;
47     
48     t = 300;
49     while((c = getopt(argc, argv, "+ht:")) >= 0) {
50         switch(c) {
51         case 'h':
52             usage(stdout);
53             exit(0);
54         case 't':
55             t = atoi(optarg);
56             if(t < 1) {
57                 fprintf(stderr, "httimed: timeout must be positive\n");
58                 exit(1);
59             }
60             break;
61         }
62     }
63     if(argc - optind < 1) {
64         usage(stderr);
65         exit(1);
66     }
67     if((ch = stdmkchild(argv + optind, NULL, NULL)) < 0) {
68         flog(LOG_ERR, "httimed: could not fork child: %s", strerror(errno));
69         exit(1);
70     }
71     lreq = time(NULL);
72     while(1) {
73         memset(pfd, 0, sizeof(pfd));
74         pfd[0].fd = 0;
75         pfd[0].events = POLLIN;
76         pfd[1].fd = ch;
77         pfd[1].events = POLLHUP;
78         if((ret = poll(pfd, 2, (t + 1 - (time(NULL) - lreq)) * 1000)) < 0) {
79             if(errno != EINTR) {
80                 flog(LOG_ERR, "httimed: error in poll: %s", strerror(errno));
81                 exit(1);
82             }
83         }
84         now = time(NULL);
85         if(pfd[0].revents) {
86             if((fd = recvreq(0, &req)) < 0) {
87                 if(errno == 0)
88                     break;
89                 flog(LOG_ERR, "httimed: error in recvreq: %s", strerror(errno));
90                 exit(1);
91             }
92             if(sendreq(ch, req, fd)) {
93                 flog(LOG_ERR, "httimed: could not pass request to child: %s", strerror(errno));
94                 exit(1);
95             }
96             freehthead(req);
97             close(fd);
98         }
99         if(pfd[1].revents & POLLHUP)
100             break;
101         if(now - lreq > t)
102             break;
103         lreq = now;
104     }
105     return(0);
106 }