2016-03-19 15:14:35 +00:00
|
|
|
#include "first.h"
|
|
|
|
|
2017-11-01 04:16:38 +00:00
|
|
|
#include "fdevent_impl.h"
|
2017-03-28 04:04:31 +00:00
|
|
|
#include "fdevent.h"
|
2017-11-01 04:16:38 +00:00
|
|
|
#include "base.h"
|
2017-06-22 01:41:59 +00:00
|
|
|
#include "buffer.h"
|
2010-08-06 21:57:15 +00:00
|
|
|
#include "log.h"
|
2005-02-20 14:27:00 +00:00
|
|
|
|
2009-10-11 14:31:42 +00:00
|
|
|
#include <sys/types.h>
|
2017-07-17 04:52:14 +00:00
|
|
|
#include <sys/wait.h>
|
2017-04-15 21:38:15 +00:00
|
|
|
#include "sys-socket.h"
|
2005-02-20 14:27:00 +00:00
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
2017-07-17 04:52:14 +00:00
|
|
|
#include <time.h>
|
2005-02-20 14:27:00 +00:00
|
|
|
|
2017-06-10 17:22:48 +00:00
|
|
|
#ifdef SOCK_CLOEXEC
|
2017-04-15 21:38:15 +00:00
|
|
|
static int use_sock_cloexec;
|
2017-06-10 17:22:48 +00:00
|
|
|
#endif
|
2018-04-11 01:37:39 +00:00
|
|
|
#ifdef SOCK_NONBLOCK
|
|
|
|
static int use_sock_nonblock;
|
|
|
|
#endif
|
2017-04-15 21:38:15 +00:00
|
|
|
|
2017-11-01 04:16:38 +00:00
|
|
|
int fdevent_config(server *srv) {
|
|
|
|
static const struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
|
|
|
|
{
|
|
|
|
/* - epoll is most reliable
|
|
|
|
* - select works everywhere
|
|
|
|
*/
|
|
|
|
#ifdef FDEVENT_USE_LINUX_EPOLL
|
|
|
|
{ FDEVENT_HANDLER_LINUX_SYSEPOLL, "linux-sysepoll" },
|
|
|
|
{ FDEVENT_HANDLER_LINUX_SYSEPOLL, "epoll" },
|
|
|
|
#endif
|
|
|
|
#ifdef FDEVENT_USE_SOLARIS_PORT
|
|
|
|
{ FDEVENT_HANDLER_SOLARIS_PORT, "solaris-eventports" },
|
|
|
|
#endif
|
|
|
|
#ifdef FDEVENT_USE_SOLARIS_DEVPOLL
|
|
|
|
{ FDEVENT_HANDLER_SOLARIS_DEVPOLL,"solaris-devpoll" },
|
|
|
|
#endif
|
|
|
|
#ifdef FDEVENT_USE_FREEBSD_KQUEUE
|
|
|
|
{ FDEVENT_HANDLER_FREEBSD_KQUEUE, "freebsd-kqueue" },
|
|
|
|
{ FDEVENT_HANDLER_FREEBSD_KQUEUE, "kqueue" },
|
|
|
|
#endif
|
|
|
|
#ifdef FDEVENT_USE_POLL
|
|
|
|
{ FDEVENT_HANDLER_POLL, "poll" },
|
|
|
|
#endif
|
|
|
|
#ifdef FDEVENT_USE_SELECT
|
|
|
|
{ FDEVENT_HANDLER_SELECT, "select" },
|
|
|
|
#endif
|
|
|
|
#ifdef FDEVENT_USE_LIBEV
|
|
|
|
{ FDEVENT_HANDLER_LIBEV, "libev" },
|
|
|
|
#endif
|
|
|
|
{ FDEVENT_HANDLER_UNSET, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
if (buffer_string_is_empty(srv->srvconf.event_handler)) {
|
|
|
|
/* choose a good default
|
|
|
|
*
|
|
|
|
* the event_handler list is sorted by 'goodness'
|
|
|
|
* taking the first available should be the best solution
|
|
|
|
*/
|
|
|
|
srv->event_handler = event_handlers[0].et;
|
|
|
|
|
|
|
|
if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s",
|
|
|
|
"sorry, there is no event handler for this system");
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer_copy_string(srv->srvconf.event_handler, event_handlers[0].name);
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* User override
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (size_t i = 0; event_handlers[i].name; i++) {
|
|
|
|
if (0 == strcmp(event_handlers[i].name, srv->srvconf.event_handler->ptr)) {
|
|
|
|
srv->event_handler = event_handlers[i].et;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sb",
|
|
|
|
"the selected event-handler in unknown or not supported:",
|
|
|
|
srv->srvconf.event_handler );
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef FDEVENT_USE_SELECT
|
|
|
|
if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
|
|
|
|
/* select limits itself
|
|
|
|
*
|
|
|
|
* as it is a hard limit and will lead to a segfault we add some safety
|
|
|
|
* */
|
|
|
|
srv->max_fds = FD_SETSIZE - 200;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
srv->max_fds = 4096;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char * fdevent_show_event_handlers(void) {
|
|
|
|
return
|
|
|
|
"\nEvent Handlers:\n\n"
|
|
|
|
#ifdef FDEVENT_USE_SELECT
|
|
|
|
"\t+ select (generic)\n"
|
|
|
|
#else
|
|
|
|
"\t- select (generic)\n"
|
|
|
|
#endif
|
|
|
|
#ifdef FDEVENT_USE_POLL
|
|
|
|
"\t+ poll (Unix)\n"
|
|
|
|
#else
|
|
|
|
"\t- poll (Unix)\n"
|
|
|
|
#endif
|
|
|
|
#ifdef FDEVENT_USE_LINUX_EPOLL
|
|
|
|
"\t+ epoll (Linux)\n"
|
|
|
|
#else
|
|
|
|
"\t- epoll (Linux)\n"
|
|
|
|
#endif
|
|
|
|
#ifdef FDEVENT_USE_SOLARIS_DEVPOLL
|
|
|
|
"\t+ /dev/poll (Solaris)\n"
|
|
|
|
#else
|
|
|
|
"\t- /dev/poll (Solaris)\n"
|
|
|
|
#endif
|
|
|
|
#ifdef FDEVENT_USE_SOLARIS_PORT
|
|
|
|
"\t+ eventports (Solaris)\n"
|
|
|
|
#else
|
|
|
|
"\t- eventports (Solaris)\n"
|
|
|
|
#endif
|
|
|
|
#ifdef FDEVENT_USE_FREEBSD_KQUEUE
|
|
|
|
"\t+ kqueue (FreeBSD)\n"
|
|
|
|
#else
|
|
|
|
"\t- kqueue (FreeBSD)\n"
|
|
|
|
#endif
|
|
|
|
#ifdef FDEVENT_USE_LIBEV
|
|
|
|
"\t+ libev (generic)\n"
|
|
|
|
#else
|
|
|
|
"\t- libev (generic)\n"
|
|
|
|
#endif
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
fdevents *fdevent_init(server *srv) {
|
2005-02-20 14:27:00 +00:00
|
|
|
fdevents *ev;
|
2017-11-01 04:16:38 +00:00
|
|
|
int type = srv->event_handler;
|
|
|
|
size_t maxfds;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2017-04-15 21:38:15 +00:00
|
|
|
#ifdef SOCK_CLOEXEC
|
|
|
|
/* Test if SOCK_CLOEXEC is supported by kernel.
|
|
|
|
* Linux kernels < 2.6.27 might return EINVAL if SOCK_CLOEXEC used
|
|
|
|
* https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=529929
|
2018-04-11 01:37:39 +00:00
|
|
|
* http://www.linksysinfo.org/index.php?threads/lighttpd-no-longer-starts-toastman-1-28-0510-7.73132/
|
|
|
|
* Test if SOCK_NONBLOCK is ignored by kernel on sockets.
|
|
|
|
* (reported on Android running a custom ROM)
|
|
|
|
* https://redmine.lighttpd.net/issues/2883
|
|
|
|
*/
|
|
|
|
int fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
|
2017-04-15 21:38:15 +00:00
|
|
|
if (fd >= 0) {
|
2018-04-11 01:37:39 +00:00
|
|
|
int flags = fcntl(fd, F_GETFL, 0);
|
|
|
|
use_sock_nonblock = (-1 != flags && (flags & O_NONBLOCK));
|
2017-04-15 21:38:15 +00:00
|
|
|
use_sock_cloexec = 1;
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-11-01 04:16:38 +00:00
|
|
|
#ifdef FDEVENT_USE_SELECT
|
|
|
|
if (type == FDEVENT_HANDLER_SELECT) {
|
|
|
|
if (srv->max_fds > (int)FD_SETSIZE - 200) {
|
|
|
|
srv->max_fds = (int)FD_SETSIZE - 200;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
maxfds = srv->max_fds + 1; /*(+1 for event-handler fd)*/
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
ev = calloc(1, sizeof(*ev));
|
2016-01-30 13:59:07 +00:00
|
|
|
force_assert(NULL != ev);
|
2010-08-06 21:57:15 +00:00
|
|
|
ev->srv = srv;
|
2005-02-20 14:27:00 +00:00
|
|
|
ev->fdarray = calloc(maxfds, sizeof(*ev->fdarray));
|
2017-02-13 19:24:53 +00:00
|
|
|
if (NULL == ev->fdarray) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "SDS",
|
2017-02-28 16:32:28 +00:00
|
|
|
"server.max-fds too large? (", maxfds-1, ")");
|
2017-02-13 19:24:53 +00:00
|
|
|
free(ev);
|
|
|
|
return NULL;
|
|
|
|
}
|
2005-02-20 14:27:00 +00:00
|
|
|
ev->maxfds = maxfds;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
switch(type) {
|
2019-02-23 06:35:58 +00:00
|
|
|
#ifdef FDEVENT_USE_POLL
|
2005-02-20 14:27:00 +00:00
|
|
|
case FDEVENT_HANDLER_POLL:
|
2019-02-23 06:35:58 +00:00
|
|
|
if (0 == fdevent_poll_init(ev)) return ev;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#ifdef FDEVENT_USE_SELECT
|
2005-02-20 14:27:00 +00:00
|
|
|
case FDEVENT_HANDLER_SELECT:
|
2019-02-23 06:35:58 +00:00
|
|
|
if (0 == fdevent_select_init(ev)) return ev;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#ifdef FDEVENT_USE_LINUX_EPOLL
|
2005-02-20 14:27:00 +00:00
|
|
|
case FDEVENT_HANDLER_LINUX_SYSEPOLL:
|
2019-02-23 06:35:58 +00:00
|
|
|
if (0 == fdevent_linux_sysepoll_init(ev)) return ev;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#ifdef FDEVENT_USE_SOLARIS_DEVPOLL
|
2005-02-20 14:27:00 +00:00
|
|
|
case FDEVENT_HANDLER_SOLARIS_DEVPOLL:
|
2019-02-23 06:35:58 +00:00
|
|
|
if (0 == fdevent_solaris_devpoll_init(ev)) return ev;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#ifdef FDEVENT_USE_SOLARIS_PORT
|
2011-06-13 17:34:57 +00:00
|
|
|
case FDEVENT_HANDLER_SOLARIS_PORT:
|
2019-02-23 06:35:58 +00:00
|
|
|
if (0 == fdevent_solaris_port_init(ev)) return ev;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#ifdef FDEVENT_USE_FREEBSD_KQUEUE
|
2005-02-20 14:27:00 +00:00
|
|
|
case FDEVENT_HANDLER_FREEBSD_KQUEUE:
|
2019-02-23 06:35:58 +00:00
|
|
|
if (0 == fdevent_freebsd_kqueue_init(ev)) return ev;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#ifdef FDEVENT_USE_LIBEV
|
2010-08-07 10:46:34 +00:00
|
|
|
case FDEVENT_HANDLER_LIBEV:
|
2019-02-23 06:35:58 +00:00
|
|
|
if (0 == fdevent_libev_init(ev)) return ev;
|
|
|
|
break;
|
|
|
|
#endif
|
2010-08-07 10:46:34 +00:00
|
|
|
case FDEVENT_HANDLER_UNSET:
|
2017-03-28 04:04:31 +00:00
|
|
|
default:
|
2005-02-20 14:27:00 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-11-13 11:43:26 +00:00
|
|
|
free(ev->fdarray);
|
|
|
|
free(ev);
|
|
|
|
|
2019-02-23 06:35:58 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sBS",
|
|
|
|
"event-handler failed:", srv->srvconf.event_handler, "; try to set server.event-handler = \"poll\" or \"select\"");
|
2010-08-07 10:46:34 +00:00
|
|
|
return NULL;
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void fdevent_free(fdevents *ev) {
|
|
|
|
size_t i;
|
|
|
|
if (!ev) return;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
if (ev->free) ev->free(ev);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
for (i = 0; i < ev->maxfds; i++) {
|
2017-10-21 16:20:27 +00:00
|
|
|
/* (fdevent_sched_run() should already have been run,
|
|
|
|
* but take reasonable precautions anyway) */
|
|
|
|
if (ev->fdarray[i])
|
|
|
|
free((fdnode *)((uintptr_t)ev->fdarray[i] & ~0x3));
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
free(ev->fdarray);
|
|
|
|
free(ev);
|
|
|
|
}
|
|
|
|
|
|
|
|
int fdevent_reset(fdevents *ev) {
|
2019-02-23 06:35:58 +00:00
|
|
|
int rc = (NULL != ev->reset) ? ev->reset(ev) : 0;
|
|
|
|
if (-1 == rc) {
|
|
|
|
log_error_write(ev->srv, __FILE__, __LINE__, "sBS",
|
|
|
|
"event-handler failed:", ev->srv->srvconf.event_handler, "; try to set server.event-handler = \"poll\" or \"select\"");
|
|
|
|
}
|
|
|
|
return rc;
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
|
|
|
|
2012-08-31 14:11:41 +00:00
|
|
|
static fdnode *fdnode_init(void) {
|
2019-02-23 06:35:58 +00:00
|
|
|
return calloc(1, sizeof(fdnode));
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
|
|
|
|
2009-03-07 21:05:37 +00:00
|
|
|
static void fdnode_free(fdnode *fdn) {
|
2005-02-20 14:27:00 +00:00
|
|
|
free(fdn);
|
|
|
|
}
|
|
|
|
|
2019-02-23 06:35:58 +00:00
|
|
|
void fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx) {
|
|
|
|
fdnode *fdn = ev->fdarray[fd] = fdnode_init();
|
|
|
|
force_assert(NULL != fdn);
|
2005-02-20 14:27:00 +00:00
|
|
|
fdn->handler = handler;
|
|
|
|
fdn->fd = fd;
|
|
|
|
fdn->ctx = ctx;
|
2010-08-17 09:54:42 +00:00
|
|
|
fdn->events = 0;
|
2019-02-23 06:35:58 +00:00
|
|
|
fdn->fde_ndx = -1;
|
2019-02-17 23:35:05 +00:00
|
|
|
#ifdef FDEVENT_USE_LIBEV
|
|
|
|
fdn->handler_ctx = NULL;
|
|
|
|
#endif
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
|
|
|
|
2019-02-23 06:35:58 +00:00
|
|
|
void fdevent_unregister(fdevents *ev, int fd) {
|
|
|
|
fdnode *fdn = ev->fdarray[fd];
|
|
|
|
if ((uintptr_t)fdn & 0x3) return; /*(should not happen)*/
|
2005-02-20 14:27:00 +00:00
|
|
|
ev->fdarray[fd] = NULL;
|
2019-02-23 06:35:58 +00:00
|
|
|
fdnode_free(fdn);
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
|
|
|
|
2016-08-24 19:30:11 +00:00
|
|
|
void fdevent_sched_close(fdevents *ev, int fd, int issock) {
|
2019-02-23 06:35:58 +00:00
|
|
|
fdnode *fdn = ev->fdarray[fd];
|
2017-10-21 16:20:27 +00:00
|
|
|
if ((uintptr_t)fdn & 0x3) return;
|
|
|
|
ev->fdarray[fd] = (fdnode *)((uintptr_t)fdn | (issock ? 0x1 : 0x2));
|
|
|
|
fdn->ctx = ev->pendclose;
|
|
|
|
ev->pendclose = fdn;
|
2016-08-24 19:30:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void fdevent_sched_run(server *srv, fdevents *ev) {
|
2017-10-21 16:20:27 +00:00
|
|
|
for (fdnode *fdn = ev->pendclose; fdn; ) {
|
|
|
|
int fd, rc;
|
|
|
|
fdnode *fdn_tmp;
|
2016-08-24 19:30:11 +00:00
|
|
|
#ifdef _WIN32
|
2017-10-21 16:20:27 +00:00
|
|
|
rc = (uintptr_t)fdn & 0x3;
|
|
|
|
#endif
|
|
|
|
fdn = (fdnode *)((uintptr_t)fdn & ~0x3);
|
|
|
|
fd = fdn->fd;
|
|
|
|
#ifdef _WIN32
|
|
|
|
if (rc == 0x1) {
|
2016-08-24 19:30:11 +00:00
|
|
|
rc = closesocket(fd);
|
|
|
|
}
|
2017-10-21 16:20:27 +00:00
|
|
|
else if (rc == 0x2) {
|
2016-08-24 19:30:11 +00:00
|
|
|
rc = close(fd);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
rc = close(fd);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (0 != rc) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sds", "close failed ", fd, strerror(errno));
|
|
|
|
}
|
2017-10-21 16:20:27 +00:00
|
|
|
else {
|
|
|
|
--srv->cur_fds;
|
|
|
|
}
|
2016-08-24 19:30:11 +00:00
|
|
|
|
2017-10-21 16:20:27 +00:00
|
|
|
fdn_tmp = fdn;
|
|
|
|
fdn = (fdnode *)fdn->ctx; /* next */
|
|
|
|
/*(fdevent_unregister)*/
|
|
|
|
fdnode_free(fdn_tmp);
|
2016-08-24 19:30:11 +00:00
|
|
|
ev->fdarray[fd] = NULL;
|
|
|
|
}
|
2017-10-21 16:20:27 +00:00
|
|
|
ev->pendclose = NULL;
|
2016-08-24 19:30:11 +00:00
|
|
|
}
|
|
|
|
|
2017-11-01 04:16:38 +00:00
|
|
|
int fdevent_event_get_interest(const fdevents *ev, int fd) {
|
|
|
|
return fd >= 0 ? ev->fdarray[fd]->events : 0;
|
|
|
|
}
|
|
|
|
|
2019-02-23 06:35:58 +00:00
|
|
|
static void fdevent_fdnode_event_del(fdevents *ev, fdnode *fdn) {
|
|
|
|
if (-1 == fdn->fde_ndx) return;
|
|
|
|
if (0 == ev->event_del(ev, fdn)) {
|
|
|
|
fdn->fde_ndx = -1;
|
|
|
|
fdn->events = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
log_error_write(ev->srv, __FILE__, __LINE__, "SS",
|
|
|
|
"fdevent event_del failed: ", strerror(errno));
|
|
|
|
}
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
|
|
|
|
2019-02-23 06:35:58 +00:00
|
|
|
static void fdevent_fdnode_event_set(fdevents *ev, fdnode *fdn, int events) {
|
|
|
|
/*(Note: skips registering with kernel if initial events is 0,
|
|
|
|
* so caller should pass non-zero events for initial registration.
|
|
|
|
* If never registered due to never being called with non-zero events,
|
|
|
|
* then FDEVENT_HUP or FDEVENT_ERR will never be returned.) */
|
|
|
|
if (fdn->events == events) return;/*(no change; nothing to do)*/
|
|
|
|
|
|
|
|
if (0 == ev->event_set(ev, fdn, events))
|
|
|
|
fdn->events = events;
|
|
|
|
else
|
|
|
|
log_error_write(ev->srv, __FILE__, __LINE__, "SS",
|
|
|
|
"fdevent event_set failed: ", strerror(errno));
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2019-02-23 19:57:21 +00:00
|
|
|
void fdevent_event_del(fdevents *ev, int fd) {
|
2019-02-23 06:35:58 +00:00
|
|
|
if (-1 != fd) {
|
|
|
|
fdnode *fdn = ev->fdarray[fd];
|
|
|
|
if ((uintptr_t)fdn & 0x3) return;
|
|
|
|
fdevent_fdnode_event_del(ev, fdn);
|
|
|
|
}
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2019-02-23 19:57:21 +00:00
|
|
|
void fdevent_event_set(fdevents *ev, int fd, int events) {
|
2019-02-23 06:35:58 +00:00
|
|
|
if (-1 != fd) fdevent_fdnode_event_set(ev, ev->fdarray[fd], events);
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
|
|
|
|
2019-02-23 19:57:21 +00:00
|
|
|
void fdevent_event_add(fdevents *ev, int fd, int event) {
|
2019-02-23 06:35:58 +00:00
|
|
|
if (-1 != fd) {
|
|
|
|
fdnode *fdn = ev->fdarray[fd];
|
|
|
|
fdevent_fdnode_event_set(ev, fdn, (fdn->events | event));
|
|
|
|
}
|
[core] option to stream response body to client (fixes #949, #760, #1283, #1387)
Set server.stream-response-body = 1 or server.stream-response-body = 2
to have lighttpd stream response body to client as it arrives from the
backend (CGI, FastCGI, SCGI, proxy).
default: buffer entire response body before sending response to client.
(This preserves existing behavior for now, but may in the future be
changed to stream response to client, which is the behavior more
commonly expected.)
x-ref:
"fastcgi, cgi, flush, php5 problem."
https://redmine.lighttpd.net/issues/949
"Random crashing on FreeBSD 6.1"
https://redmine.lighttpd.net/issues/760
"Memory usage increases when proxy+ssl+large file"
https://redmine.lighttpd.net/issues/1283
"lighttpd+fastcgi memory problem"
https://redmine.lighttpd.net/issues/1387
2016-06-11 15:04:01 +00:00
|
|
|
}
|
|
|
|
|
2019-02-23 19:57:21 +00:00
|
|
|
void fdevent_event_clr(fdevents *ev, int fd, int event) {
|
2019-02-23 06:35:58 +00:00
|
|
|
if (-1 != fd) {
|
|
|
|
fdnode *fdn = ev->fdarray[fd];
|
|
|
|
fdevent_fdnode_event_set(ev, fdn, (fdn->events & ~event));
|
|
|
|
}
|
[core] option to stream response body to client (fixes #949, #760, #1283, #1387)
Set server.stream-response-body = 1 or server.stream-response-body = 2
to have lighttpd stream response body to client as it arrives from the
backend (CGI, FastCGI, SCGI, proxy).
default: buffer entire response body before sending response to client.
(This preserves existing behavior for now, but may in the future be
changed to stream response to client, which is the behavior more
commonly expected.)
x-ref:
"fastcgi, cgi, flush, php5 problem."
https://redmine.lighttpd.net/issues/949
"Random crashing on FreeBSD 6.1"
https://redmine.lighttpd.net/issues/760
"Memory usage increases when proxy+ssl+large file"
https://redmine.lighttpd.net/issues/1283
"lighttpd+fastcgi memory problem"
https://redmine.lighttpd.net/issues/1387
2016-06-11 15:04:01 +00:00
|
|
|
}
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
int fdevent_poll(fdevents *ev, int timeout_ms) {
|
|
|
|
return ev->poll(ev, timeout_ms);
|
|
|
|
}
|
|
|
|
|
2017-04-15 21:38:15 +00:00
|
|
|
void fdevent_setfd_cloexec(int fd) {
|
2005-02-20 14:27:00 +00:00
|
|
|
#ifdef FD_CLOEXEC
|
2014-02-16 13:08:29 +00:00
|
|
|
if (fd < 0) return;
|
|
|
|
force_assert(-1 != fcntl(fd, F_SETFD, FD_CLOEXEC));
|
|
|
|
#else
|
|
|
|
UNUSED(fd);
|
2005-02-20 14:27:00 +00:00
|
|
|
#endif
|
2014-02-16 13:08:29 +00:00
|
|
|
}
|
|
|
|
|
2017-04-15 21:38:15 +00:00
|
|
|
void fdevent_clrfd_cloexec(int fd) {
|
|
|
|
#ifdef FD_CLOEXEC
|
|
|
|
if (fd >= 0) force_assert(-1 != fcntl(fd, F_SETFD, 0));
|
|
|
|
#else
|
|
|
|
UNUSED(fd);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-12-24 04:28:44 +00:00
|
|
|
int fdevent_fcntl_set_nb(fdevents *ev, int fd) {
|
2017-07-29 04:30:53 +00:00
|
|
|
UNUSED(ev);
|
2006-10-04 13:26:23 +00:00
|
|
|
#ifdef O_NONBLOCK
|
2005-02-20 14:27:00 +00:00
|
|
|
return fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
|
|
|
|
#else
|
2017-07-29 04:30:53 +00:00
|
|
|
UNUSED(fd);
|
2005-02-20 14:27:00 +00:00
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-12-24 04:28:44 +00:00
|
|
|
int fdevent_fcntl_set_nb_cloexec(fdevents *ev, int fd) {
|
2017-06-20 03:25:39 +00:00
|
|
|
fdevent_setfd_cloexec(fd);
|
2013-12-24 04:28:44 +00:00
|
|
|
return fdevent_fcntl_set_nb(ev, fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
int fdevent_fcntl_set_nb_cloexec_sock(fdevents *ev, int fd) {
|
|
|
|
#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
|
2018-04-11 01:37:39 +00:00
|
|
|
if (use_sock_cloexec && use_sock_nonblock)
|
2017-07-29 04:30:53 +00:00
|
|
|
return 0;
|
2013-12-24 04:28:44 +00:00
|
|
|
#endif
|
2017-04-15 21:38:15 +00:00
|
|
|
return fdevent_fcntl_set_nb_cloexec(ev, fd);
|
2013-12-24 04:28:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int fdevent_socket_cloexec(int domain, int type, int protocol) {
|
|
|
|
int fd;
|
2017-04-15 21:38:15 +00:00
|
|
|
#ifdef SOCK_CLOEXEC
|
|
|
|
if (use_sock_cloexec)
|
|
|
|
return socket(domain, type | SOCK_CLOEXEC, protocol);
|
|
|
|
#endif
|
2013-12-24 04:28:44 +00:00
|
|
|
if (-1 != (fd = socket(domain, type, protocol))) {
|
|
|
|
#ifdef FD_CLOEXEC
|
2017-05-16 03:59:22 +00:00
|
|
|
force_assert(-1 != fcntl(fd, F_SETFD, FD_CLOEXEC));
|
2013-12-24 04:28:44 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
int fdevent_socket_nb_cloexec(int domain, int type, int protocol) {
|
|
|
|
int fd;
|
2017-04-15 21:38:15 +00:00
|
|
|
#ifdef SOCK_CLOEXEC
|
2018-04-11 01:37:39 +00:00
|
|
|
if (use_sock_cloexec && use_sock_nonblock)
|
2017-04-15 21:38:15 +00:00
|
|
|
return socket(domain, type | SOCK_CLOEXEC | SOCK_NONBLOCK, protocol);
|
|
|
|
#endif
|
2013-12-24 04:28:44 +00:00
|
|
|
if (-1 != (fd = socket(domain, type, protocol))) {
|
|
|
|
#ifdef FD_CLOEXEC
|
2017-05-16 03:59:22 +00:00
|
|
|
force_assert(-1 != fcntl(fd, F_SETFD, FD_CLOEXEC));
|
2013-12-24 04:28:44 +00:00
|
|
|
#endif
|
|
|
|
#ifdef O_NONBLOCK
|
2017-05-16 03:59:22 +00:00
|
|
|
force_assert(-1 != fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR));
|
2013-12-24 04:28:44 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef O_NOCTTY
|
|
|
|
#define O_NOCTTY 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int fdevent_open_cloexec(const char *pathname, int flags, mode_t mode) {
|
|
|
|
#ifdef O_CLOEXEC
|
|
|
|
return open(pathname, flags | O_CLOEXEC | O_NOCTTY, mode);
|
|
|
|
#else
|
|
|
|
int fd = open(pathname, flags | O_NOCTTY, mode);
|
|
|
|
#ifdef FD_CLOEXEC
|
|
|
|
if (fd != -1)
|
2017-05-16 03:59:22 +00:00
|
|
|
force_assert(-1 != fcntl(fd, F_SETFD, FD_CLOEXEC));
|
2013-12-24 04:28:44 +00:00
|
|
|
#endif
|
|
|
|
return fd;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
|
2017-06-20 03:00:45 +00:00
|
|
|
int fdevent_open_devnull(void) {
|
|
|
|
#if defined(_WIN32)
|
|
|
|
return fdevent_open_cloexec("nul", O_RDWR, 0);
|
|
|
|
#else
|
|
|
|
return fdevent_open_cloexec("/dev/null", O_RDWR, 0);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int fdevent_open_dirname(char *path) {
|
|
|
|
/*(handle special cases of no dirname or dirname is root directory)*/
|
|
|
|
char * const c = strrchr(path, '/');
|
|
|
|
const char * const dname = (NULL != c ? c == path ? "/" : path : ".");
|
|
|
|
int dfd;
|
|
|
|
int flags = O_RDONLY;
|
|
|
|
#ifdef O_DIRECTORY
|
|
|
|
flags |= O_DIRECTORY;
|
|
|
|
#endif
|
|
|
|
if (NULL != c) *c = '\0';
|
|
|
|
dfd = fdevent_open_cloexec(dname, flags, 0);
|
|
|
|
if (NULL != c) *c = '/';
|
|
|
|
return dfd;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-04-15 21:38:15 +00:00
|
|
|
int fdevent_accept_listenfd(int listenfd, struct sockaddr *addr, size_t *addrlen) {
|
|
|
|
int fd;
|
|
|
|
socklen_t len = (socklen_t) *addrlen;
|
|
|
|
|
|
|
|
#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
|
|
|
|
#if defined(__NetBSD__)
|
2018-03-25 04:57:38 +00:00
|
|
|
const int sock_cloexec = 1;
|
2017-04-15 21:38:15 +00:00
|
|
|
fd = paccept(listenfd, addr, &len, NULL, SOCK_CLOEXEC | SOCK_NONBLOCK);
|
|
|
|
#else
|
2018-03-25 04:57:38 +00:00
|
|
|
int sock_cloexec = use_sock_cloexec;
|
|
|
|
if (sock_cloexec) {
|
|
|
|
fd = accept4(listenfd, addr, &len, SOCK_CLOEXEC | SOCK_NONBLOCK);
|
2018-04-11 01:37:39 +00:00
|
|
|
if (fd >= 0) {
|
|
|
|
if (!use_sock_nonblock) {
|
|
|
|
if (0 != fdevent_fcntl_set_nb(NULL, fd)) {
|
|
|
|
close(fd);
|
|
|
|
fd = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (errno == ENOSYS || errno == ENOTSUP) {
|
2018-03-25 04:57:38 +00:00
|
|
|
fd = accept(listenfd, addr, &len);
|
|
|
|
sock_cloexec = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
fd = accept(listenfd, addr, &len);
|
|
|
|
}
|
2017-04-15 21:38:15 +00:00
|
|
|
#endif
|
|
|
|
#else
|
2018-03-25 04:57:38 +00:00
|
|
|
const int sock_cloexec = 0;
|
2017-04-15 21:38:15 +00:00
|
|
|
fd = accept(listenfd, addr, &len);
|
|
|
|
#endif
|
|
|
|
|
2018-03-25 04:57:38 +00:00
|
|
|
if (fd >= 0) {
|
|
|
|
*addrlen = (size_t)len;
|
|
|
|
if (!sock_cloexec && 0 != fdevent_fcntl_set_nb_cloexec(NULL, fd)) {
|
|
|
|
close(fd);
|
|
|
|
fd = -1;
|
|
|
|
}
|
|
|
|
}
|
2017-04-15 21:38:15 +00:00
|
|
|
return fd;
|
|
|
|
}
|
2005-02-20 14:27:00 +00:00
|
|
|
|
2016-08-06 08:11:16 +00:00
|
|
|
|
2018-03-25 07:45:05 +00:00
|
|
|
#ifdef __APPLE__
|
|
|
|
#include <crt_externs.h>
|
|
|
|
#define environ (* _NSGetEnviron())
|
|
|
|
#else
|
|
|
|
extern char **environ;
|
|
|
|
#endif
|
|
|
|
char ** fdevent_environ (void) { return environ; }
|
|
|
|
|
|
|
|
|
2017-06-20 03:00:45 +00:00
|
|
|
#ifdef FD_CLOEXEC
|
|
|
|
static int fdevent_dup2_close_clrfd_cloexec(int oldfd, int newfd) {
|
|
|
|
if (oldfd >= 0) {
|
|
|
|
if (oldfd != newfd) {
|
|
|
|
force_assert(oldfd > STDERR_FILENO);
|
|
|
|
if (newfd != dup2(oldfd, newfd)) return -1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
fdevent_clrfd_cloexec(newfd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return newfd;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static int fdevent_dup2_close_clrfd_cloexec(int oldfd, int newfd, int reuse) {
|
|
|
|
if (oldfd >= 0) {
|
|
|
|
if (oldfd != newfd) {
|
|
|
|
force_assert(oldfd > STDERR_FILENO);
|
|
|
|
if (newfd != dup2(oldfd, newfd)) return -1;
|
|
|
|
if (!reuse) close(oldfd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return newfd;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
int fdevent_set_stdin_stdout_stderr(int fdin, int fdout, int fderr) {
|
|
|
|
#ifdef FD_CLOEXEC
|
|
|
|
if (STDIN_FILENO != fdevent_dup2_close_clrfd_cloexec(fdin, STDIN_FILENO))
|
|
|
|
return -1;
|
|
|
|
if (STDOUT_FILENO != fdevent_dup2_close_clrfd_cloexec(fdout, STDOUT_FILENO))
|
|
|
|
return -1;
|
|
|
|
if (STDERR_FILENO != fdevent_dup2_close_clrfd_cloexec(fderr, STDERR_FILENO))
|
|
|
|
return -1;
|
|
|
|
#else
|
|
|
|
if (STDIN_FILENO != fdevent_dup2_close_clrfd_cloexec(fdin, STDIN_FILENO,
|
|
|
|
fdin == fdout
|
|
|
|
|| fdin == fderr))
|
|
|
|
return -1;
|
|
|
|
if (STDOUT_FILENO != fdevent_dup2_close_clrfd_cloexec(fdout, STDOUT_FILENO,
|
|
|
|
fdout == fderr))
|
|
|
|
return -1;
|
|
|
|
if (STDERR_FILENO != fdevent_dup2_close_clrfd_cloexec(fderr, STDERR_FILENO,
|
|
|
|
0))
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdio.h> /* perror() */
|
|
|
|
#include <signal.h> /* signal() */
|
|
|
|
|
|
|
|
pid_t fdevent_fork_execve(const char *name, char *argv[], char *envp[], int fdin, int fdout, int fderr, int dfd) {
|
|
|
|
#ifdef HAVE_FORK
|
|
|
|
|
|
|
|
pid_t pid = fork();
|
|
|
|
if (0 != pid) return pid; /* parent (pid > 0) or fork() error (-1 == pid) */
|
|
|
|
|
|
|
|
/* child (0 == pid) */
|
|
|
|
|
|
|
|
if (-1 != dfd) {
|
|
|
|
if (0 != fchdir(dfd))
|
|
|
|
_exit(errno);
|
|
|
|
close(dfd);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (0 != fdevent_set_stdin_stdout_stderr(fdin, fdout, fderr)) _exit(errno);
|
|
|
|
#ifdef FD_CLOEXEC
|
|
|
|
/*(might not be sufficient for open fds, but modern OS have FD_CLOEXEC)*/
|
|
|
|
for (int i = 3; i < 256; ++i) close(i);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* reset_signals which may have been ignored (SIG_IGN) */
|
|
|
|
#ifdef SIGTTOU
|
|
|
|
signal(SIGTTOU, SIG_DFL);
|
|
|
|
#endif
|
|
|
|
#ifdef SIGTTIN
|
|
|
|
signal(SIGTTIN, SIG_DFL);
|
|
|
|
#endif
|
|
|
|
#ifdef SIGTSTP
|
|
|
|
signal(SIGTSTP, SIG_DFL);
|
|
|
|
#endif
|
|
|
|
signal(SIGPIPE, SIG_DFL);
|
|
|
|
|
|
|
|
execve(name, argv, envp ? envp : environ);
|
|
|
|
|
|
|
|
if (0 == memcmp(argv[0], "/bin/sh", sizeof("/bin/sh")-1)
|
|
|
|
&& argv[1] && 0 == memcmp(argv[1], "-c", sizeof("-c")-1))
|
|
|
|
perror(argv[2]);
|
|
|
|
else
|
|
|
|
perror(argv[0]);
|
|
|
|
_exit(errno);
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
UNUSED(name);
|
|
|
|
UNUSED(argv);
|
|
|
|
UNUSED(envp);
|
|
|
|
UNUSED(fdin);
|
|
|
|
UNUSED(fdout);
|
|
|
|
UNUSED(fderr);
|
|
|
|
UNUSED(dfd);
|
|
|
|
return (pid_t)-1;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-17 04:52:14 +00:00
|
|
|
typedef struct fdevent_cmd_pipe {
|
|
|
|
pid_t pid;
|
|
|
|
int fds[2];
|
|
|
|
const char *cmd;
|
|
|
|
time_t start;
|
|
|
|
} fdevent_cmd_pipe;
|
|
|
|
|
|
|
|
typedef struct fdevent_cmd_pipes {
|
|
|
|
fdevent_cmd_pipe *ptr;
|
|
|
|
size_t used;
|
|
|
|
size_t size;
|
|
|
|
} fdevent_cmd_pipes;
|
|
|
|
|
|
|
|
static fdevent_cmd_pipes cmd_pipes;
|
|
|
|
|
|
|
|
|
|
|
|
static pid_t fdevent_open_logger_pipe_spawn(const char *logger, int rfd) {
|
2017-06-20 03:00:45 +00:00
|
|
|
char *args[4];
|
|
|
|
int devnull = fdevent_open_devnull();
|
|
|
|
pid_t pid;
|
|
|
|
|
|
|
|
if (-1 == devnull) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*(const char **)&args[0] = "/bin/sh";
|
|
|
|
*(const char **)&args[1] = "-c";
|
|
|
|
*(const char **)&args[2] = logger;
|
|
|
|
args[3] = NULL;
|
|
|
|
|
2017-07-17 04:52:14 +00:00
|
|
|
pid = fdevent_fork_execve(args[0], args, NULL, rfd, devnull, devnull, -1);
|
2017-06-20 03:00:45 +00:00
|
|
|
|
|
|
|
if (pid > 0) {
|
|
|
|
close(devnull);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int errnum = errno;
|
|
|
|
close(devnull);
|
2017-07-17 04:52:14 +00:00
|
|
|
errno = errnum;
|
|
|
|
}
|
|
|
|
return pid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-09-10 19:28:51 +00:00
|
|
|
static void fdevent_restart_logger_pipe(fdevent_cmd_pipe *fcp, time_t ts) {
|
|
|
|
if (fcp->pid > 0) return; /* assert */
|
2017-07-17 04:52:14 +00:00
|
|
|
if (fcp->start + 5 < ts) { /* limit restart to once every 5 sec */
|
|
|
|
/* restart child process using existing pipe fds */
|
|
|
|
fcp->start = ts;
|
|
|
|
fcp->pid = fdevent_open_logger_pipe_spawn(fcp->cmd, fcp->fds[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-09-10 19:28:51 +00:00
|
|
|
void fdevent_restart_logger_pipes(time_t ts) {
|
|
|
|
for (size_t i = 0; i < cmd_pipes.used; ++i) {
|
|
|
|
fdevent_cmd_pipe * const fcp = cmd_pipes.ptr+i;
|
|
|
|
if (fcp->pid > 0) continue;
|
|
|
|
fdevent_restart_logger_pipe(fcp, ts);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int fdevent_waitpid_logger_pipe_pid(pid_t pid, time_t ts) {
|
2017-07-17 04:52:14 +00:00
|
|
|
for (size_t i = 0; i < cmd_pipes.used; ++i) {
|
2017-09-10 19:28:51 +00:00
|
|
|
fdevent_cmd_pipe * const fcp = cmd_pipes.ptr+i;
|
|
|
|
if (pid != fcp->pid) continue;
|
|
|
|
fcp->pid = -1;
|
|
|
|
fdevent_restart_logger_pipe(fcp, ts);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void fdevent_clr_logger_pipe_pids(void) {
|
|
|
|
for (size_t i = 0; i < cmd_pipes.used; ++i) {
|
|
|
|
fdevent_cmd_pipe *fcp = cmd_pipes.ptr+i;
|
|
|
|
fcp->pid = -1;
|
2017-07-17 04:52:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int fdevent_reaped_logger_pipe(pid_t pid) {
|
|
|
|
for (size_t i = 0; i < cmd_pipes.used; ++i) {
|
|
|
|
fdevent_cmd_pipe *fcp = cmd_pipes.ptr+i;
|
|
|
|
if (fcp->pid == pid) {
|
|
|
|
time_t ts = time(NULL);
|
|
|
|
if (fcp->start + 5 < ts) { /* limit restart to once every 5 sec */
|
|
|
|
fcp->start = ts;
|
|
|
|
fcp->pid = fdevent_open_logger_pipe_spawn(fcp->cmd,fcp->fds[0]);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
fcp->pid = -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void fdevent_close_logger_pipes(void) {
|
|
|
|
for (size_t i = 0; i < cmd_pipes.used; ++i) {
|
|
|
|
fdevent_cmd_pipe *fcp = cmd_pipes.ptr+i;
|
|
|
|
close(fcp->fds[0]);
|
|
|
|
if (fcp->fds[1] != STDERR_FILENO) close(fcp->fds[1]);
|
|
|
|
}
|
|
|
|
free(cmd_pipes.ptr);
|
|
|
|
cmd_pipes.ptr = NULL;
|
|
|
|
cmd_pipes.used = 0;
|
|
|
|
cmd_pipes.size = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void fdevent_breakagelog_logger_pipe(int fd) {
|
|
|
|
for (size_t i = 0; i < cmd_pipes.used; ++i) {
|
|
|
|
fdevent_cmd_pipe *fcp = cmd_pipes.ptr+i;
|
|
|
|
if (fcp->fds[1] != fd) continue;
|
|
|
|
fcp->fds[1] = STDERR_FILENO;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void fdevent_init_logger_pipe(const char *cmd, int fds[2], pid_t pid) {
|
|
|
|
fdevent_cmd_pipe *fcp;
|
|
|
|
if (cmd_pipes.used == cmd_pipes.size) {
|
|
|
|
cmd_pipes.size += 4;
|
|
|
|
cmd_pipes.ptr =
|
|
|
|
realloc(cmd_pipes.ptr, cmd_pipes.size * sizeof(fdevent_cmd_pipe));
|
|
|
|
force_assert(cmd_pipes.ptr);
|
|
|
|
}
|
|
|
|
fcp = cmd_pipes.ptr + cmd_pipes.used++;
|
|
|
|
fcp->cmd = cmd; /* note: cmd must persist in memory (or else copy here) */
|
|
|
|
fcp->fds[0] = fds[0];
|
|
|
|
fcp->fds[1] = fds[1];
|
|
|
|
fcp->pid = pid;
|
|
|
|
fcp->start = time(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int fdevent_open_logger_pipe(const char *logger) {
|
|
|
|
int fds[2];
|
|
|
|
pid_t pid;
|
|
|
|
if (pipe(fds)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
fdevent_setfd_cloexec(fds[0]);
|
|
|
|
fdevent_setfd_cloexec(fds[1]);
|
2018-01-03 01:58:20 +00:00
|
|
|
/*(nonblocking write() from lighttpd)*/
|
|
|
|
if (0 != fdevent_fcntl_set_nb(NULL, fds[1])) { /*(ignore)*/ }
|
2017-07-17 04:52:14 +00:00
|
|
|
|
|
|
|
pid = fdevent_open_logger_pipe_spawn(logger, fds[0]);
|
|
|
|
|
|
|
|
if (pid > 0) {
|
|
|
|
fdevent_init_logger_pipe(logger, fds, pid);
|
|
|
|
return fds[1];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int errnum = errno;
|
|
|
|
close(fds[0]);
|
|
|
|
close(fds[1]);
|
2017-06-20 03:00:45 +00:00
|
|
|
errno = errnum;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef O_LARGEFILE
|
|
|
|
#define O_LARGEFILE 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int fdevent_open_logger(const char *logger) {
|
|
|
|
if (logger[0] != '|') {
|
|
|
|
int flags = O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE;
|
|
|
|
return fdevent_open_cloexec(logger, flags, 0644);
|
|
|
|
}
|
|
|
|
else {
|
|