summaryrefslogtreecommitdiff
path: root/usr.sbin/unbound/util/netevent.c
diff options
context:
space:
mode:
authorStuart Henderson <sthen@cvs.openbsd.org>2012-05-16 08:57:22 +0000
committerStuart Henderson <sthen@cvs.openbsd.org>2012-05-16 08:57:22 +0000
commit096815990943e7237e8fd06a1d29b5f185bb417c (patch)
tree9d036599d3a64c5afc8ea1e1db77c3e4253e19c5 /usr.sbin/unbound/util/netevent.c
parent2d0265882a16694c42b396ac0b2598691875b4dc (diff)
Don't spin accept() when hitting ENFILE/EMFILE. Upstream r2663.
Diffstat (limited to 'usr.sbin/unbound/util/netevent.c')
-rw-r--r--usr.sbin/unbound/util/netevent.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/usr.sbin/unbound/util/netevent.c b/usr.sbin/unbound/util/netevent.c
index c6f5279f6a7..cb47352afa9 100644
--- a/usr.sbin/unbound/util/netevent.c
+++ b/usr.sbin/unbound/util/netevent.c
@@ -115,6 +115,10 @@ struct internal_base {
uint32_t secs;
/** timeval with current time */
struct timeval now;
+ /** the event used for slow_accept timeouts */
+ struct event slow_accept;
+ /** true if slow_accept is enabled */
+ int slow_accept_enabled;
};
/**
@@ -225,6 +229,11 @@ comm_base_delete(struct comm_base* b)
{
if(!b)
return;
+ if(b->eb->slow_accept_enabled) {
+ if(event_del(&b->eb->slow_accept) != 0) {
+ log_err("could not event_del slow_accept");
+ }
+ }
#ifdef USE_MINI_EVENT
event_base_free(b->eb->base);
#elif defined(HAVE_EVENT_BASE_FREE) && defined(HAVE_EVENT_BASE_ONCE)
@@ -263,6 +272,14 @@ void comm_base_exit(struct comm_base* b)
}
}
+void comm_base_set_slow_accept_handlers(struct comm_base* b,
+ void (*stop_acc)(void*), void (*start_acc)(void*), void* arg)
+{
+ b->stop_accept = stop_acc;
+ b->start_accept = start_acc;
+ b->cb_arg = arg;
+}
+
struct event_base* comm_base_internal(struct comm_base* b)
{
return b->eb->base;
@@ -646,6 +663,18 @@ setup_tcp_handler(struct comm_point* c, int fd)
comm_point_start_listening(c, fd, TCP_QUERY_TIMEOUT);
}
+void comm_base_handle_slow_accept(int fd, short event, void* arg)
+{
+ struct comm_base* b = (struct comm_base*)arg;
+ /* timeout for the slow accept, re-enable accepts again */
+ if(b->start_accept) {
+ verbose(VERB_ALGO, "wait is over, slow accept disabled");
+ fptr_ok(fptr_whitelist_start_accept(b->start_accept));
+ (*b->start_accept)(b->cb_arg);
+ b->eb->slow_accept_enabled = 0;
+ }
+}
+
int comm_point_perform_accept(struct comm_point* c,
struct sockaddr_storage* addr, socklen_t* addrlen)
{
@@ -667,6 +696,38 @@ int comm_point_perform_accept(struct comm_point* c,
#endif /* EPROTO */
)
return -1;
+#if defined(ENFILE) && defined(EMFILE)
+ if(errno == ENFILE || errno == EMFILE) {
+ /* out of file descriptors, likely outside of our
+ * control. stop accept() calls for some time */
+ if(c->ev->base->stop_accept) {
+ struct comm_base* b = c->ev->base;
+ struct timeval tv;
+ verbose(VERB_ALGO, "out of file descriptors: "
+ "slow accept");
+ b->eb->slow_accept_enabled = 1;
+ fptr_ok(fptr_whitelist_stop_accept(
+ b->stop_accept));
+ (*b->stop_accept)(b->cb_arg);
+ /* set timeout, no mallocs */
+ tv.tv_sec = NETEVENT_SLOW_ACCEPT_TIME/1000;
+ tv.tv_usec = NETEVENT_SLOW_ACCEPT_TIME%1000;
+ event_set(&b->eb->slow_accept, -1, EV_TIMEOUT,
+ comm_base_handle_slow_accept, b);
+ if(event_base_set(b->eb->base,
+ &b->eb->slow_accept) != 0) {
+ /* we do not want to log here, because
+ * that would spam the logfiles.
+ * error: "event_base_set failed." */
+ }
+ if(event_add(&b->eb->slow_accept, &tv) != 0) {
+ /* we do not want to log here,
+ * error: "event_add failed." */
+ }
+ }
+ return -1;
+ }
+#endif
log_err("accept failed: %s", strerror(errno));
#else /* USE_WINSOCK */
if(WSAGetLastError() == WSAEINPROGRESS ||