From 4f5dd228f08c132afdef71c1a5a124595905d8ae Mon Sep 17 00:00:00 2001 From: Reyk Floeter Date: Sat, 3 Jan 2015 21:06:57 +0100 Subject: In the parent, only open a socket once per unique listen statement. Fixes possible file descriptor exhaustion on configuration load time. --- config.c | 15 +++++++++------ parse.y | 8 +++++++- server.c | 19 ++++++++++++++++++- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/config.c b/config.c index 14fe63e..8fb9b7d 100644 --- a/config.c +++ b/config.c @@ -200,7 +200,9 @@ config_setserver(struct httpd *env, struct server *srv) n = -1; proc_range(ps, id, &n, &m); for (n = 0; n < m; n++) { - if ((fd = dup(srv->srv_s)) == -1) + if (srv->srv_s == -1) + fd = -1; + else if ((fd = dup(srv->srv_s)) == -1) return (-1); proc_composev_imsg(ps, id, n, IMSG_CFG_SERVER, fd, iov, c); @@ -211,9 +213,6 @@ config_setserver(struct httpd *env, struct server *srv) } } - close(srv->srv_s); - srv->srv_s = -1; - return (0); } @@ -356,8 +355,12 @@ config_getserver(struct httpd *env, struct imsg *imsg) if ((srv = server_byaddr((struct sockaddr *) &srv_conf.ss, srv_conf.port)) != NULL) { /* Add "host" to existing listening server */ - if (imsg->fd != -1) - close(imsg->fd); + if (imsg->fd != -1) { + if (srv->srv_s == -1) + srv->srv_s = imsg->fd; + else + close(imsg->fd); + } return (config_getserver_config(env, srv, imsg)); } diff --git a/parse.y b/parse.y index 145d99c..f787863 100644 --- a/parse.y +++ b/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.47 2015/01/03 15:49:18 reyk Exp $ */ +/* $OpenBSD: parse.y,v 1.48 2015/01/03 16:20:31 reyk Exp $ */ /* * Copyright (c) 2007 - 2014 Reyk Floeter @@ -226,6 +226,7 @@ server : SERVER STRING { strlcpy(s->srv_conf.errorlog, HTTPD_ERROR_LOG, sizeof(s->srv_conf.errorlog)); s->srv_conf.id = ++last_server_id; + s->srv_s = -1; s->srv_conf.timeout.tv_sec = SERVER_TIMEOUT; s->srv_conf.maxrequests = SERVER_MAXREQUESTS; s->srv_conf.maxrequestbody = SERVER_MAXREQUESTBODY; @@ -493,6 +494,7 @@ serveroptsl : LISTEN ON STRING opttls port { /* A location entry uses the parent id */ s->srv_conf.id = srv->srv_conf.id; s->srv_conf.flags = SRVFLAG_LOCATION; + s->srv_s = -1; memcpy(&s->srv_conf.ss, &srv->srv_conf.ss, sizeof(s->srv_conf.ss)); s->srv_conf.port = srv->srv_conf.port; @@ -1742,8 +1744,11 @@ server_inherit(struct server *src, const char *name, fatal("out of memory"); dst->srv_conf.id = ++last_server_id; + dst->srv_s = -1; + if (last_server_id == INT_MAX) { yyerror("too many servers defined"); + serverconfig_free(&dst->srv_conf); free(dst); return (NULL); } @@ -1805,6 +1810,7 @@ server_inherit(struct server *src, const char *name, sizeof(dstl->srv_conf.ss)); dstl->srv_conf.port = addr->port; dstl->srv_conf.prefixlen = addr->prefixlen; + dstl->srv_s = -1; DPRINTF("adding location \"%s\" for \"%s[%u]\"", dstl->srv_conf.location, diff --git a/server.c b/server.c index 1d30f35..3b4c0dc 100644 --- a/server.c +++ b/server.c @@ -101,11 +101,27 @@ server_shutdown(void) int server_privinit(struct server *srv) { + struct server *s; + if (srv->srv_conf.flags & SRVFLAG_LOCATION) return (0); log_debug("%s: adding server %s", __func__, srv->srv_conf.name); + /* + * There's no need to open a new socket if a server with the + * same address already exists. + */ + TAILQ_FOREACH(s, env->sc_servers, srv_entry) { + if (s != srv && s->srv_s != -1 && + s->srv_conf.port == srv->srv_conf.port && + sockaddr_cmp((struct sockaddr *)&s->srv_conf.ss, + (struct sockaddr *)&srv->srv_conf.ss, + s->srv_conf.prefixlen) == 0) + return (0); + } + + /* Open listening socket in the privileged process */ if ((srv->srv_s = server_socket_listen(&srv->srv_conf.ss, srv->srv_conf.port, &srv->srv_conf)) == -1) return (-1); @@ -277,7 +293,8 @@ server_purge(struct server *srv) if (evtimer_initialized(&srv->srv_evt)) evtimer_del(&srv->srv_evt); - close(srv->srv_s); + if (srv->srv_s != -1) + close(srv->srv_s); TAILQ_REMOVE(env->sc_servers, srv, srv_entry); /* cleanup sessions */ -- cgit v1.2.3-54-g00ecf