aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReyk Floeter <reyk@esdenera.com>2015-01-03 21:06:57 +0100
committerReyk Floeter <reyk@esdenera.com>2015-01-03 21:06:57 +0100
commit4f5dd228f08c132afdef71c1a5a124595905d8ae (patch)
tree653146e322b074f6a796a7b247b8113edcc943df
parent461ae7b2ed14e4c38ecf78d791138922a6c050f3 (diff)
downloadhttpd-4f5dd228f08c132afdef71c1a5a124595905d8ae.tar.gz
httpd-4f5dd228f08c132afdef71c1a5a124595905d8ae.zip
In the parent, only open a socket once per unique listen statement.
Fixes possible file descriptor exhaustion on configuration load time.
-rw-r--r--config.c15
-rw-r--r--parse.y8
-rw-r--r--server.c19
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 <reyk@openbsd.org>
@@ -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 */