version 1.1.1.5, 2009/05/23 02:21:19 |
version 1.1.1.6, 2010/05/10 03:30:04 |
|
|
/* $eterna: daemon-bozo.c,v 1.17 2009/05/22 21:51:38 mrg Exp $ */ |
/* $eterna: daemon-bozo.c,v 1.19 2010/05/10 02:51:28 mrg Exp $ */ |
|
|
/* |
/* |
* Copyright (c) 1997-2009 Matthew R. Green |
* Copyright (c) 1997-2010 Matthew R. Green |
* All rights reserved. |
* All rights reserved. |
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
|
|
|
|
#include "bozohttpd.h" |
#include "bozohttpd.h" |
|
|
char *iflag; /* bind address; default INADDR_ANY */ |
|
static int *sock; /* bound sockets */ |
|
static int nsock; /* number of above */ |
|
static struct pollfd *fds; /* current poll fd set */ |
|
static int request_times; /* how many times this proc has processed |
|
a request */ |
|
|
|
static void daemon_runchild(int); |
|
static void sigchild(int); /* SIGCHLD handler */ |
static void sigchild(int); /* SIGCHLD handler */ |
|
|
#ifndef POLLRDNORM |
#ifndef POLLRDNORM |
Line 69 static void sigchild(int); /* SIGCHLD ha |
|
Line 61 static void sigchild(int); /* SIGCHLD ha |
|
|
|
/* ARGSUSED */ |
/* ARGSUSED */ |
static void |
static void |
sigchild(signo) |
sigchild(int signo) |
int signo; |
|
{ |
{ |
while (waitpid(-1, NULL, WNOHANG) > 0) |
while (waitpid(-1, NULL, WNOHANG) > 0) { |
; |
} |
} |
} |
|
|
void |
void |
daemon_init() |
bozo_daemon_init(bozohttpd_t *httpd) |
{ |
{ |
struct addrinfo h, *r, *r0; |
struct addrinfo h, *r, *r0; |
|
const char *portnum; |
int e, i, on = 1; |
int e, i, on = 1; |
|
|
if (!bflag) |
if (!httpd->background) |
return; |
return; |
|
|
if (fflag == 0) |
if (httpd->foreground == 0) |
daemon(1, 0); |
daemon(1, 0); |
|
|
warning("started in daemon mode as `%s' port `%s' root `%s'", |
portnum = (httpd->bindport) ? httpd->bindport : "http"; |
myname, Iflag, slashdir); |
bozo_warn(httpd, "started in daemon mode as `%s' port `%s' root `%s'", |
|
httpd->virthostname, portnum, httpd->slashdir); |
|
|
memset(&h, 0, sizeof h); |
memset(&h, 0, sizeof(h)); |
h.ai_family = PF_UNSPEC; |
h.ai_family = PF_UNSPEC; |
h.ai_socktype = SOCK_STREAM; |
h.ai_socktype = SOCK_STREAM; |
h.ai_flags = AI_PASSIVE; |
h.ai_flags = AI_PASSIVE; |
e = getaddrinfo(iflag, Iflag, &h, &r0); |
e = getaddrinfo(httpd->bindaddress, portnum, &h, &r0); |
if (e) |
if (e) |
error(1, "getaddrinfo([%s]:%s): %s", |
bozo_err(httpd, 1, "getaddrinfo([%s]:%s): %s", |
iflag ? iflag : "*", Iflag, gai_strerror(e)); |
httpd->bindaddress ? httpd->bindaddress : "*", |
|
portnum, gai_strerror(e)); |
for (r = r0; r != NULL; r = r->ai_next) |
for (r = r0; r != NULL; r = r->ai_next) |
nsock++; |
httpd->nsock++; |
sock = bozomalloc(nsock * sizeof *sock); |
httpd->sock = bozomalloc(httpd, httpd->nsock * sizeof(*httpd->sock)); |
fds = bozomalloc(nsock * sizeof *fds); |
httpd->fds = bozomalloc(httpd, httpd->nsock * sizeof(*httpd->fds)); |
for (i = 0, r = r0; r != NULL; r = r->ai_next) { |
for (i = 0, r = r0; r != NULL; r = r->ai_next) { |
sock[i] = socket(r->ai_family, SOCK_STREAM, 0); |
httpd->sock[i] = socket(r->ai_family, SOCK_STREAM, 0); |
if (sock[i] == -1) |
if (httpd->sock[i] == -1) |
continue; |
continue; |
if (setsockopt(sock[i], SOL_SOCKET, SO_REUSEADDR, &on, |
if (setsockopt(httpd->sock[i], SOL_SOCKET, SO_REUSEADDR, &on, |
sizeof(on)) == -1) |
sizeof(on)) == -1) |
warning("setsockopt SO_REUSEADDR: %s", |
bozo_warn(httpd, "setsockopt SO_REUSEADDR: %s", |
strerror(errno)); |
strerror(errno)); |
if (bind(sock[i], r->ai_addr, r->ai_addrlen) == -1) |
if (bind(httpd->sock[i], r->ai_addr, r->ai_addrlen) == -1) |
continue; |
continue; |
if (listen(sock[i], SOMAXCONN) == -1) |
if (listen(httpd->sock[i], SOMAXCONN) == -1) |
continue; |
continue; |
fds[i].events = POLLIN | POLLPRI | POLLRDNORM | |
httpd->fds[i].events = POLLIN | POLLPRI | POLLRDNORM | |
POLLRDBAND | POLLERR; |
POLLRDBAND | POLLERR; |
fds[i].fd = sock[i]; |
httpd->fds[i].fd = httpd->sock[i]; |
i++; |
i++; |
} |
} |
if (i == 0) |
if (i == 0) |
error(1, "could not find any addresses to bind"); |
bozo_err(httpd, 1, "could not find any addresses to bind"); |
nsock = i; |
httpd->nsock = i; |
freeaddrinfo(r0); |
freeaddrinfo(r0); |
|
|
signal(SIGCHLD, sigchild); |
signal(SIGCHLD, sigchild); |
} |
} |
|
|
void |
void |
daemon_closefds(void) |
bozo_daemon_closefds(bozohttpd_t *httpd) |
{ |
{ |
int i; |
int i; |
|
|
for (i = 0; i < nsock; i++) |
for (i = 0; i < httpd->nsock; i++) |
close(sock[i]); |
close(httpd->sock[i]); |
} |
} |
|
|
static void |
static void |
daemon_runchild(int fd) |
daemon_runchild(bozohttpd_t *httpd, int fd) |
{ |
{ |
|
|
request_times++; |
httpd->request_times++; |
|
|
/* setup stdin/stdout/stderr */ |
/* setup stdin/stdout/stderr */ |
dup2(fd, 0); |
dup2(fd, 0); |
Line 155 daemon_runchild(int fd) |
|
Line 149 daemon_runchild(int fd) |
|
* are ready to run... XXXMRG - still true in fork-lesser bozo? |
* are ready to run... XXXMRG - still true in fork-lesser bozo? |
*/ |
*/ |
void |
void |
daemon_fork() |
bozo_daemon_fork(bozohttpd_t *httpd) |
{ |
{ |
int i; |
int i; |
|
|
debug((DEBUG_FAT, "%s: pid %u request_times %d", __func__, getpid(), |
debug((httpd, DEBUG_FAT, "%s: pid %u request_times %d", |
request_times)); |
__func__, getpid(), |
|
httpd->request_times)); |
/* if we've handled 5 files, exit and let someone else work */ |
/* if we've handled 5 files, exit and let someone else work */ |
if (request_times > 5 || (bflag == 2 && request_times > 0)) |
if (httpd->request_times > 5 || |
|
(httpd->background == 2 && httpd->request_times > 0)) |
exit(0); |
exit(0); |
|
|
while (bflag) { |
while (httpd->background) { |
struct sockaddr_storage ss; |
struct sockaddr_storage ss; |
socklen_t slen; |
socklen_t slen; |
int fd; |
int fd; |
|
|
if (nsock == 0) |
if (httpd->nsock == 0) |
exit(0); |
exit(0); |
|
|
/* |
/* |
|
|
* it, for processing. |
* it, for processing. |
*/ |
*/ |
again: |
again: |
if (poll(fds, nsock, INFTIM) == -1) { |
if (poll(httpd->fds, (unsigned)httpd->nsock, INFTIM) == -1) { |
/* fail on programmer errors */ |
/* fail on programmer errors */ |
if (errno == EFAULT || |
if (errno == EFAULT || |
errno == EINVAL) |
errno == EINVAL) |
error(1, "poll: %s", strerror(errno)); |
bozo_err(httpd, 1, "poll: %s", |
|
strerror(errno)); |
|
|
/* sleep on some temporary kernel failures */ |
/* sleep on some temporary kernel failures */ |
if (errno == ENOMEM || |
if (errno == ENOMEM || |
|
|
goto again; |
goto again; |
} |
} |
|
|
for (i = 0; i < nsock; i++) { |
for (i = 0; i < httpd->nsock; i++) { |
if (fds[i].revents & (POLLNVAL|POLLERR|POLLHUP)) { |
if (httpd->fds[i].revents & (POLLNVAL|POLLERR|POLLHUP)) { |
warning("poll on fd %d pid %d revents %d: %s", |
bozo_warn(httpd, |
fds[i].fd, getpid(), fds[i].revents, |
"poll on fd %d pid %d revents %d: %s", |
strerror(errno)); |
httpd->fds[i].fd, getpid(), |
warning("nsock = %d", nsock); |
httpd->fds[i].revents, |
close(sock[i]); |
strerror(errno)); |
nsock--; |
bozo_warn(httpd, "nsock = %d", httpd->nsock); |
warning("nsock now = %d", nsock); |
close(httpd->sock[i]); |
|
httpd->nsock--; |
|
bozo_warn(httpd, "nsock now = %d", httpd->nsock); |
/* no sockets left */ |
/* no sockets left */ |
if (nsock == 0) |
if (httpd->nsock == 0) |
exit(0); |
exit(0); |
/* last socket; easy case */ |
/* last socket; easy case */ |
if (nsock == i) |
if (httpd->nsock == i) |
break; |
break; |
memmove(&fds[i], &fds[i+i], |
memmove(&httpd->fds[i], &httpd->fds[i+i], |
(nsock - i) * sizeof(*fds)); |
(httpd->nsock - i) * |
memmove(&sock[i], &sock[i+i], |
sizeof(*httpd->fds)); |
(nsock - i) * sizeof(*sock)); |
memmove(&httpd->sock[i], &httpd->sock[i+i], |
|
(httpd->nsock - i) * |
|
sizeof(*httpd->sock)); |
break; |
break; |
} |
} |
if (fds[i].revents == 0) |
if (httpd->fds[i].revents == 0) |
continue; |
continue; |
|
|
slen = sizeof(ss); |
slen = sizeof(ss); |
fd = accept(fds[i].fd, (struct sockaddr *)&ss, &slen); |
fd = accept(httpd->fds[i].fd, |
|
(struct sockaddr *)(void *)&ss, &slen); |
if (fd == -1) { |
if (fd == -1) { |
if (errno == EFAULT || |
if (errno == EFAULT || |
errno == EINVAL) |
errno == EINVAL) |
error(1, "accept: %s", strerror(errno)); |
bozo_err(httpd, 1, "accept: %s", |
|
strerror(errno)); |
|
|
if (errno == ENOMEM || |
if (errno == ENOMEM || |
errno == EAGAIN) |
errno == EAGAIN) |
|
|
continue; |
continue; |
} |
} |
|
|
if (request_times > 0) { |
if (httpd->request_times > 0) { |
daemon_runchild(fd); |
daemon_runchild(httpd, fd); |
return; |
return; |
} |
} |
|
|
switch (fork()) { |
switch (fork()) { |
case -1: /* eep, failure */ |
case -1: /* eep, failure */ |
warning("fork() failed, sleeping for " |
bozo_warn(httpd, "fork() failed, sleeping for " |
"10 seconds: %s", strerror(errno)); |
"10 seconds: %s", strerror(errno)); |
close(fd); |
close(fd); |
sleep(10); |
sleep(10); |
break; |
break; |
|
|
case 0: /* child */ |
case 0: /* child */ |
daemon_runchild(fd); |
daemon_runchild(httpd, fd); |
return; |
return; |
|
|
default: /* parent */ |
default: /* parent */ |