From 27fb06b4c8af02ac764589845931449083c6f4fc Mon Sep 17 00:00:00 2001 From: reyk Date: Tue, 6 Jan 2015 14:07:48 +0000 Subject: [PATCH] Only open a socket once for each unique "listen on" statement. This prevents running out of file descriptors when loading a configuration with many aliases. OK florian@ --- usr.sbin/httpd/config.c | 17 ++++++++++------- usr.sbin/httpd/parse.y | 7 ++++++- usr.sbin/httpd/server.c | 21 +++++++++++++++++++-- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/usr.sbin/httpd/config.c b/usr.sbin/httpd/config.c index 14fe63e001c..4077d34898a 100644 --- a/usr.sbin/httpd/config.c +++ b/usr.sbin/httpd/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.27 2015/01/03 15:49:18 reyk Exp $ */ +/* $OpenBSD: config.c,v 1.28 2015/01/06 14:07:48 reyk Exp $ */ /* * Copyright (c) 2011 - 2014 Reyk Floeter @@ -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/usr.sbin/httpd/parse.y b/usr.sbin/httpd/parse.y index 5a9616c88dc..c7a536c967c 100644 --- a/usr.sbin/httpd/parse.y +++ b/usr.sbin/httpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.50 2015/01/04 22:23:58 chrisz Exp $ */ +/* $OpenBSD: parse.y,v 1.51 2015/01/06 14:07:48 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; @@ -484,6 +485,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; @@ -1760,6 +1762,8 @@ server_inherit(struct server *src, const char *name, dst->srv_conf.tls_key = NULL; 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); @@ -1824,6 +1828,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/usr.sbin/httpd/server.c b/usr.sbin/httpd/server.c index 1d30f352413..cc237ca06d2 100644 --- a/usr.sbin/httpd/server.c +++ b/usr.sbin/httpd/server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server.c,v 1.49 2014/12/21 00:54:49 guenther Exp $ */ +/* $OpenBSD: server.c,v 1.50 2015/01/06 14:07:48 reyk Exp $ */ /* * Copyright (c) 2006 - 2014 Reyk Floeter @@ -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 */ -- 2.20.1