On Sat, Jan 03, 2015 at 05:19:16PM +0100, Reyk Floeter wrote: > My tests show that memory usage is not the problem but that there's > indeed a problem with the pre-opened file descriptors for servers; > something that is not necessary with aliases. A simple fix will follow. >
Here is a fix for the previous: in the parent, only open a socket once per unique listen statement. This allows to specify many aliases and listen statements. Reyk Index: config.c =================================================================== RCS file: /cvs/src/usr.sbin/httpd/config.c,v retrieving revision 1.27 diff -u -p -u -p -r1.27 config.c --- config.c 3 Jan 2015 15:49:18 -0000 1.27 +++ config.c 3 Jan 2015 19:32:00 -0000 @@ -200,7 +200,9 @@ config_setserver(struct httpd *env, stru 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, stru } } - close(srv->srv_s); - srv->srv_s = -1; - return (0); } @@ -356,8 +355,12 @@ config_getserver(struct httpd *env, stru 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)); } Index: parse.y =================================================================== RCS file: /cvs/src/usr.sbin/httpd/parse.y,v retrieving revision 1.48 diff -u -p -u -p -r1.48 parse.y --- parse.y 3 Jan 2015 16:20:31 -0000 1.48 +++ parse.y 3 Jan 2015 19:32:01 -0000 @@ -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 po /* 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,6 +1744,8 @@ server_inherit(struct server *src, const 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); @@ -1806,6 +1810,7 @@ server_inherit(struct server *src, const 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, Index: server.c =================================================================== RCS file: /cvs/src/usr.sbin/httpd/server.c,v retrieving revision 1.49 diff -u -p -u -p -r1.49 server.c --- server.c 21 Dec 2014 00:54:49 -0000 1.49 +++ server.c 3 Jan 2015 19:32:01 -0000 @@ -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 */