1 /* $NetBSD: daemon-bozo.c,v 1.6 2009/04/18 21:22:03 mrg Exp $ */
3 /* $eterna: daemon-bozo.c,v 1.17 2009/05/22 21:51:38 mrg Exp $ */
6 * Copyright (c) 1997-2009 Matthew R. Green
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer and
16 * dedication in the documentation and/or other materials provided
17 * with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 /* this code implements daemon mode for bozohttpd */
35 #ifndef NO_DAEMON_MODE
37 #include <sys/param.h>
38 #include <sys/socket.h>
41 #include <netinet/in.h>
50 #include "bozohttpd.h"
52 char *iflag
; /* bind address; default INADDR_ANY */
53 static int *sock
; /* bound sockets */
54 static int nsock
; /* number of above */
55 static struct pollfd
*fds
; /* current poll fd set */
56 static int request_times
; /* how many times this proc has processed
59 static void daemon_runchild(int);
60 static void sigchild(int); /* SIGCHLD handler */
77 while (waitpid(-1, NULL
, WNOHANG
) > 0)
84 struct addrinfo h
, *r
, *r0
;
93 warning("started in daemon mode as `%s' port `%s' root `%s'",
94 myname
, Iflag
, slashdir
);
96 memset(&h
, 0, sizeof h
);
97 h
.ai_family
= PF_UNSPEC
;
98 h
.ai_socktype
= SOCK_STREAM
;
99 h
.ai_flags
= AI_PASSIVE
;
100 e
= getaddrinfo(iflag
, Iflag
, &h
, &r0
);
102 error(1, "getaddrinfo([%s]:%s): %s",
103 iflag
? iflag
: "*", Iflag
, gai_strerror(e
));
104 for (r
= r0
; r
!= NULL
; r
= r
->ai_next
)
106 sock
= bozomalloc(nsock
* sizeof *sock
);
107 fds
= bozomalloc(nsock
* sizeof *fds
);
108 for (i
= 0, r
= r0
; r
!= NULL
; r
= r
->ai_next
) {
109 sock
[i
] = socket(r
->ai_family
, SOCK_STREAM
, 0);
112 if (setsockopt(sock
[i
], SOL_SOCKET
, SO_REUSEADDR
, &on
,
114 warning("setsockopt SO_REUSEADDR: %s",
116 if (bind(sock
[i
], r
->ai_addr
, r
->ai_addrlen
) == -1)
118 if (listen(sock
[i
], SOMAXCONN
) == -1)
120 fds
[i
].events
= POLLIN
| POLLPRI
| POLLRDNORM
|
121 POLLRDBAND
| POLLERR
;
126 error(1, "could not find any addresses to bind");
130 signal(SIGCHLD
, sigchild
);
134 daemon_closefds(void)
138 for (i
= 0; i
< nsock
; i
++)
143 daemon_runchild(int fd
)
148 /* setup stdin/stdout/stderr */
156 * the parent never returns from this function, only children that
157 * are ready to run... XXXMRG - still true in fork-lesser bozo?
164 debug((DEBUG_FAT
, "%s: pid %u request_times %d", __func__
, getpid(),
166 /* if we've handled 5 files, exit and let someone else work */
167 if (request_times
> 5 || (bflag
== 2 && request_times
> 0))
171 struct sockaddr_storage ss
;
179 * wait for a connection, then fork() and return NULL in
180 * the parent, who will come back here waiting for another
181 * connection. read the request in in the child, and return
182 * it, for processing.
185 if (poll(fds
, nsock
, INFTIM
) == -1) {
186 /* fail on programmer errors */
187 if (errno
== EFAULT
||
189 error(1, "poll: %s", strerror(errno
));
191 /* sleep on some temporary kernel failures */
192 if (errno
== ENOMEM
||
199 for (i
= 0; i
< nsock
; i
++) {
200 if (fds
[i
].revents
& (POLLNVAL
|POLLERR
|POLLHUP
)) {
201 warning("poll on fd %d pid %d revents %d: %s",
202 fds
[i
].fd
, getpid(), fds
[i
].revents
,
204 warning("nsock = %d", nsock
);
207 warning("nsock now = %d", nsock
);
208 /* no sockets left */
211 /* last socket; easy case */
214 memmove(&fds
[i
], &fds
[i
+i
],
215 (nsock
- i
) * sizeof(*fds
));
216 memmove(&sock
[i
], &sock
[i
+i
],
217 (nsock
- i
) * sizeof(*sock
));
220 if (fds
[i
].revents
== 0)
224 fd
= accept(fds
[i
].fd
, (struct sockaddr
*)&ss
, &slen
);
226 if (errno
== EFAULT
||
228 error(1, "accept: %s", strerror(errno
));
230 if (errno
== ENOMEM
||
237 if (request_times
> 0) {
243 case -1: /* eep, failure */
244 warning("fork() failed, sleeping for "
245 "10 seconds: %s", strerror(errno
));
254 default: /* parent */
262 #endif /* NO_DAEMON_MODE */