2016-03-19 15:14:35 +00:00
|
|
|
#include "first.h"
|
|
|
|
|
2010-08-06 21:57:15 +00:00
|
|
|
#include "base.h"
|
|
|
|
#include "log.h"
|
2005-02-20 14:27:00 +00:00
|
|
|
|
2009-10-11 14:31:42 +00:00
|
|
|
#include <sys/types.h>
|
2005-02-20 14:27:00 +00:00
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <fcntl.h>
|
2010-08-17 09:54:42 +00:00
|
|
|
#include <assert.h>
|
2005-02-20 14:27:00 +00:00
|
|
|
|
|
|
|
|
2010-08-06 21:57:15 +00:00
|
|
|
fdevents *fdevent_init(server *srv, size_t maxfds, fdevent_handler_t type) {
|
2005-02-20 14:27:00 +00:00
|
|
|
fdevents *ev;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
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));
|
2016-01-30 13:59:07 +00:00
|
|
|
force_assert(NULL != ev->fdarray);
|
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) {
|
|
|
|
case FDEVENT_HANDLER_POLL:
|
|
|
|
if (0 != fdevent_poll_init(ev)) {
|
2013-11-13 11:43:26 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "S",
|
2010-08-06 21:57:15 +00:00
|
|
|
"event-handler poll failed");
|
2013-11-13 11:43:26 +00:00
|
|
|
goto error;
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2010-08-07 10:46:34 +00:00
|
|
|
return ev;
|
2005-02-20 14:27:00 +00:00
|
|
|
case FDEVENT_HANDLER_SELECT:
|
|
|
|
if (0 != fdevent_select_init(ev)) {
|
2013-11-13 11:43:26 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "S",
|
2010-08-06 21:57:15 +00:00
|
|
|
"event-handler select failed");
|
2013-11-13 11:43:26 +00:00
|
|
|
goto error;
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2010-08-07 10:46:34 +00:00
|
|
|
return ev;
|
2005-02-20 14:27:00 +00:00
|
|
|
case FDEVENT_HANDLER_LINUX_SYSEPOLL:
|
|
|
|
if (0 != fdevent_linux_sysepoll_init(ev)) {
|
2013-11-13 11:43:26 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "S",
|
2010-08-06 21:57:15 +00:00
|
|
|
"event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"");
|
2013-11-13 11:43:26 +00:00
|
|
|
goto error;
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2010-08-07 10:46:34 +00:00
|
|
|
return ev;
|
2005-02-20 14:27:00 +00:00
|
|
|
case FDEVENT_HANDLER_SOLARIS_DEVPOLL:
|
|
|
|
if (0 != fdevent_solaris_devpoll_init(ev)) {
|
2013-11-13 11:43:26 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "S",
|
2010-08-06 21:57:15 +00:00
|
|
|
"event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"");
|
2013-11-13 11:43:26 +00:00
|
|
|
goto error;
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2010-08-07 10:46:34 +00:00
|
|
|
return ev;
|
2011-06-13 17:34:57 +00:00
|
|
|
case FDEVENT_HANDLER_SOLARIS_PORT:
|
|
|
|
if (0 != fdevent_solaris_port_init(ev)) {
|
2013-11-13 11:43:26 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "S",
|
2011-06-13 17:34:57 +00:00
|
|
|
"event-handler solaris-eventports failed, try to set server.event-handler = \"poll\" or \"select\"");
|
2013-11-13 11:43:26 +00:00
|
|
|
goto error;
|
2011-06-13 17:34:57 +00:00
|
|
|
}
|
|
|
|
return ev;
|
2005-02-20 14:27:00 +00:00
|
|
|
case FDEVENT_HANDLER_FREEBSD_KQUEUE:
|
|
|
|
if (0 != fdevent_freebsd_kqueue_init(ev)) {
|
2013-11-13 11:43:26 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "S",
|
2010-08-06 21:57:15 +00:00
|
|
|
"event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"");
|
2013-11-13 11:43:26 +00:00
|
|
|
goto error;
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
2010-08-07 10:46:34 +00:00
|
|
|
return ev;
|
|
|
|
case FDEVENT_HANDLER_LIBEV:
|
|
|
|
if (0 != fdevent_libev_init(ev)) {
|
2013-11-13 11:43:26 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "S",
|
2010-08-07 10:46:34 +00:00
|
|
|
"event-handler libev failed, try to set server.event-handler = \"poll\" or \"select\"");
|
2013-11-13 11:43:26 +00:00
|
|
|
goto error;
|
2010-08-07 10:46:34 +00:00
|
|
|
}
|
|
|
|
return ev;
|
|
|
|
case FDEVENT_HANDLER_UNSET:
|
2005-02-20 14:27:00 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-11-13 11:43:26 +00:00
|
|
|
error:
|
|
|
|
free(ev->fdarray);
|
|
|
|
free(ev);
|
|
|
|
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "S",
|
2010-08-07 10:46:34 +00:00
|
|
|
"event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"");
|
|
|
|
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++) {
|
|
|
|
if (ev->fdarray[i]) free(ev->fdarray[i]);
|
|
|
|
}
|
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) {
|
|
|
|
if (ev->reset) return ev->reset(ev);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-31 14:11:41 +00:00
|
|
|
static fdnode *fdnode_init(void) {
|
2005-02-20 14:27:00 +00:00
|
|
|
fdnode *fdn;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
fdn = calloc(1, sizeof(*fdn));
|
2016-01-30 13:59:07 +00:00
|
|
|
force_assert(NULL != fdn);
|
2005-02-20 14:27:00 +00:00
|
|
|
fdn->fd = -1;
|
|
|
|
return fdn;
|
|
|
|
}
|
|
|
|
|
2009-03-07 21:05:37 +00:00
|
|
|
static void fdnode_free(fdnode *fdn) {
|
2005-02-20 14:27:00 +00:00
|
|
|
free(fdn);
|
|
|
|
}
|
|
|
|
|
|
|
|
int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx) {
|
|
|
|
fdnode *fdn;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
fdn = fdnode_init();
|
|
|
|
fdn->handler = handler;
|
|
|
|
fdn->fd = fd;
|
|
|
|
fdn->ctx = ctx;
|
2010-08-07 10:46:34 +00:00
|
|
|
fdn->handler_ctx = NULL;
|
2010-08-17 09:54:42 +00:00
|
|
|
fdn->events = 0;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
ev->fdarray[fd] = fdn;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int fdevent_unregister(fdevents *ev, int fd) {
|
|
|
|
fdnode *fdn;
|
2010-08-17 09:54:42 +00:00
|
|
|
|
|
|
|
if (!ev) return 0;
|
2005-02-20 14:27:00 +00:00
|
|
|
fdn = ev->fdarray[fd];
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
fdnode_free(fdn);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
ev->fdarray[fd] = NULL;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-11 03:20:54 +00:00
|
|
|
void fdevent_event_del(fdevents *ev, int *fde_ndx, int fd) {
|
|
|
|
if (-1 == fd) return;
|
|
|
|
if (NULL == ev->fdarray[fd]) return;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2016-04-11 03:20:54 +00:00
|
|
|
if (ev->event_del) *fde_ndx = ev->event_del(ev, *fde_ndx, fd);
|
2010-08-17 09:54:42 +00:00
|
|
|
ev->fdarray[fd]->events = 0;
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
|
|
|
|
2016-04-11 03:20:54 +00:00
|
|
|
void fdevent_event_set(fdevents *ev, int *fde_ndx, int fd, int events) {
|
|
|
|
if (-1 == fd) return;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2016-04-11 03:20:54 +00:00
|
|
|
/*(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 (ev->fdarray[fd]->events == events) return;/*(no change; nothing to do)*/
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2016-04-11 03:20:54 +00:00
|
|
|
if (ev->event_set) *fde_ndx = ev->event_set(ev, *fde_ndx, fd, events);
|
|
|
|
ev->fdarray[fd]->events = events;
|
2005-02-20 14:27:00 +00:00
|
|
|
}
|
|
|
|
|
[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
|
|
|
void fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int event) {
|
|
|
|
int events;
|
|
|
|
if (-1 == fd) return;
|
|
|
|
|
|
|
|
events = ev->fdarray[fd]->events;
|
|
|
|
if ((events & event) || 0 == event) return; /*(no change; nothing to do)*/
|
|
|
|
|
|
|
|
events |= event;
|
|
|
|
if (ev->event_set) *fde_ndx = ev->event_set(ev, *fde_ndx, fd, events);
|
|
|
|
ev->fdarray[fd]->events = events;
|
|
|
|
}
|
|
|
|
|
|
|
|
void fdevent_event_clr(fdevents *ev, int *fde_ndx, int fd, int event) {
|
|
|
|
int events;
|
|
|
|
if (-1 == fd) return;
|
|
|
|
|
|
|
|
events = ev->fdarray[fd]->events;
|
|
|
|
if (!(events & event)) return; /*(no change; nothing to do)*/
|
|
|
|
|
|
|
|
events &= ~event;
|
|
|
|
if (ev->event_set) *fde_ndx = ev->event_set(ev, *fde_ndx, fd, events);
|
|
|
|
ev->fdarray[fd]->events = events;
|
|
|
|
}
|
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
int fdevent_poll(fdevents *ev, int timeout_ms) {
|
|
|
|
if (ev->poll == NULL) SEGFAULT();
|
|
|
|
return ev->poll(ev, timeout_ms);
|
|
|
|
}
|
|
|
|
|
|
|
|
int fdevent_event_get_revent(fdevents *ev, size_t ndx) {
|
|
|
|
if (ev->event_get_revent == NULL) SEGFAULT();
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return ev->event_get_revent(ev, ndx);
|
|
|
|
}
|
|
|
|
|
|
|
|
int fdevent_event_get_fd(fdevents *ev, size_t ndx) {
|
|
|
|
if (ev->event_get_fd == NULL) SEGFAULT();
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return ev->event_get_fd(ev, ndx);
|
|
|
|
}
|
|
|
|
|
|
|
|
fdevent_handler fdevent_get_handler(fdevents *ev, int fd) {
|
|
|
|
if (ev->fdarray[fd] == NULL) SEGFAULT();
|
|
|
|
if (ev->fdarray[fd]->fd != fd) SEGFAULT();
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return ev->fdarray[fd]->handler;
|
|
|
|
}
|
|
|
|
|
|
|
|
void * fdevent_get_context(fdevents *ev, int fd) {
|
|
|
|
if (ev->fdarray[fd] == NULL) SEGFAULT();
|
|
|
|
if (ev->fdarray[fd]->fd != fd) SEGFAULT();
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return ev->fdarray[fd]->ctx;
|
|
|
|
}
|
|
|
|
|
2014-02-16 13:08:29 +00:00
|
|
|
void fd_close_on_exec(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
|
|
|
}
|
|
|
|
|
|
|
|
int fdevent_fcntl_set(fdevents *ev, int fd) {
|
|
|
|
fd_close_on_exec(fd);
|
2005-11-15 09:24:55 +00:00
|
|
|
if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, fd);
|
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
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int fdevent_event_next_fdndx(fdevents *ev, int ndx) {
|
|
|
|
if (ev->event_next_fdndx) return ev->event_next_fdndx(ev, ndx);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-20 14:27:00 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-08-06 08:11:16 +00:00
|
|
|
|
|
|
|
#include <netinet/tcp.h>
|
|
|
|
#if (defined(__APPLE__) && defined(__MACH__)) \
|
|
|
|
|| defined(__FreeBSD__) || defined(__NetBSD__) \
|
2016-08-20 18:15:14 +00:00
|
|
|
|| defined(__OpenBSD__) || defined(__DragonFly__)
|
2016-08-06 08:11:16 +00:00
|
|
|
#include <netinet/tcp_fsm.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* fd must be TCP socket (AF_INET, AF_INET6), end-of-stream recv() 0 bytes */
|
|
|
|
int fdevent_is_tcp_half_closed(int fd) {
|
|
|
|
#ifdef TCP_CONNECTION_INFO /* Darwin */
|
|
|
|
struct tcp_connection_info tcpi;
|
|
|
|
socklen_t tlen = sizeof(tcpi);
|
|
|
|
return (0 == getsockopt(fd, IPPROTO_TCP, TCP_CONNECTION_INFO, &tcpi, &tlen)
|
|
|
|
&& tcpi.tcpi_state == TCPS_CLOSE_WAIT);
|
2016-08-20 18:15:14 +00:00
|
|
|
#elif defined(TCP_INFO) && defined(TCPS_CLOSE_WAIT)
|
|
|
|
/* FreeBSD, NetBSD (not present in OpenBSD or DragonFlyBSD) */
|
2016-08-06 08:11:16 +00:00
|
|
|
struct tcp_info tcpi;
|
|
|
|
socklen_t tlen = sizeof(tcpi);
|
|
|
|
return (0 == getsockopt(fd, IPPROTO_TCP, TCP_INFO, &tcpi, &tlen)
|
|
|
|
&& tcpi.tcpi_state == TCPS_CLOSE_WAIT);
|
2016-08-20 18:15:14 +00:00
|
|
|
#elif defined(TCP_INFO) && defined(__linux__)
|
|
|
|
/* Linux (TCP_CLOSE_WAIT is enum, so can not #ifdef TCP_CLOSE_WAIT) */
|
2016-08-06 08:11:16 +00:00
|
|
|
struct tcp_info tcpi;
|
|
|
|
socklen_t tlen = sizeof(tcpi);/*SOL_TCP == IPPROTO_TCP*/
|
|
|
|
return (0 == getsockopt(fd, SOL_TCP, TCP_INFO, &tcpi, &tlen)
|
|
|
|
&& tcpi.tcpi_state == TCP_CLOSE_WAIT);
|
|
|
|
#else
|
|
|
|
UNUSED(fd);
|
|
|
|
/*(0 != getpeername() error might indicate TCP RST, but success
|
|
|
|
* would not differentiate between half-close and full-close)*/
|
|
|
|
return 0; /* false (not half-closed) or TCP state unknown */
|
|
|
|
#endif
|
|
|
|
}
|