#include <stdio.h>
#include <errno.h>
+#include <poll.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
struct sess *sp;
socklen_t l;
struct sockaddr addr[2]; /* XXX: IPv6 hack */
- int i;
+ int i, j;
+ struct pollfd *pfd;
+ struct listen_sock *ls;
(void)arg;
+
+ /* Set up the poll argument */
+ pfd = calloc(sizeof *pfd, heritage.nsocks);
+ AN(pfd);
+ i = 0;
+ TAILQ_FOREACH(ls, &heritage.socks, list) {
+ AZ(setsockopt(ls->sock, SOL_SOCKET, SO_LINGER,
+ &linger, sizeof linger));
+ pfd[i].events = POLLIN;
+ pfd[i++].fd = ls->sock;
+ }
+
need_test = 1;
- AZ(setsockopt(heritage.socket, SOL_SOCKET, SO_LINGER,
- &linger, sizeof linger));
while (1) {
if (params->send_timeout != tv_sndtimeo.tv_sec) {
need_test = 1;
tv_sndtimeo.tv_sec = params->send_timeout;
- AZ(setsockopt(heritage.socket, SOL_SOCKET,
- SO_SNDTIMEO, &tv_sndtimeo, sizeof tv_sndtimeo));
+ TAILQ_FOREACH(ls, &heritage.socks, list)
+ AZ(setsockopt(ls->sock, SOL_SOCKET,
+ SO_SNDTIMEO, &tv_sndtimeo, sizeof tv_sndtimeo));
}
if (params->sess_timeout != tv_rcvtimeo.tv_sec) {
need_test = 1;
tv_rcvtimeo.tv_sec = params->sess_timeout;
- AZ(setsockopt(heritage.socket, SOL_SOCKET,
- SO_RCVTIMEO, &tv_rcvtimeo, sizeof tv_rcvtimeo));
+ TAILQ_FOREACH(ls, &heritage.socks, list)
+ AZ(setsockopt(ls->sock, SOL_SOCKET,
+ SO_RCVTIMEO, &tv_rcvtimeo, sizeof tv_rcvtimeo));
}
- VSL_stats->client_conn++;
-
- l = sizeof addr;
- i = accept(heritage.socket, addr, &l);
- if (i < 0) {
- if (errno != EAGAIN) {
- VSL(SLT_Debug, heritage.socket,
- "Accept failed errno=%d", errno);
- /* XXX: stats ? */
+ i = poll(pfd, heritage.nsocks, 1000);
+ for (j = 0; j < heritage.nsocks; j++) {
+ if (pfd[j].revents == 0)
+ continue;
+ VSL_stats->client_conn++;
+ l = sizeof addr;
+ i = accept(pfd[j].fd, addr, &l);
+ if (i < 0) {
+ if (errno != EAGAIN) {
+ VSL(SLT_Debug, pfd[j].fd,
+ "Accept failed errno=%d", errno);
+ /* XXX: stats ? */
+ }
+ continue;
}
- continue;
- }
- sp = SES_New(addr, l);
- XXXAN(sp);
+ sp = SES_New(addr, l);
+ XXXAN(sp);
- sp->fd = i;
- sp->id = i;
- (void)clock_gettime(CLOCK_REALTIME, &sp->t_open);
+ sp->fd = i;
+ sp->id = i;
+ (void)clock_gettime(CLOCK_REALTIME, &sp->t_open);
- http_RecvPrep(sp->http);
- sp->step = STP_FIRST;
- WRK_QueueSession(sp);
+ http_RecvPrep(sp->http);
+ sp->step = STP_FIRST;
+ WRK_QueueSession(sp);
+ }
}
}
* This file contains the heritage passed when mgt forks cache
*/
+#include "queue.h"
+
+struct listen_sock {
+ TAILQ_ENTRY(listen_sock) list;
+ int sock;
+ char *host;
+ char *port;
+};
+
+TAILQ_HEAD(listen_sock_head, listen_sock);
+
struct heritage {
/*
* Two pipe(2)'s for CLI connection between cache and mgt.
* cache reads [2] and writes [1]. Mgt reads [0] and writes [3].
*/
- int fds[4];
+ int fds[4];
- /* Socket from which to accept connections */
- int socket;
+ /* Sockets from which to accept connections */
+ struct listen_sock_head socks;
+ int nsocks;
/* Share memory log fd and size (incl header) */
- int vsl_fd;
- unsigned vsl_size;
+ int vsl_fd;
+ unsigned vsl_size;
/* Storage method */
- struct stevedore *stevedore;
+ struct stevedore *stevedore;
/* Hash method */
- struct hash_slinger *hash;
-
+ struct hash_slinger *hash;
};
struct params {
/* Listen address */
char *listen_address;
- char *listen_host;
- char *listen_port;
/* Listen depth */
unsigned listen_depth;
/*--------------------------------------------------------------------*/
+static int
+open_sockets(void)
+{
+ struct listen_sock *ls;
+
+ TAILQ_FOREACH(ls, &heritage.socks, list) {
+ if (ls->sock >= 0)
+ continue;
+ ls->sock = TCP_open(ls->host, ls->port, 1);
+ if (ls->sock < 0)
+ return (1);
+ }
+ return (0);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+close_sockets(void)
+{
+ struct listen_sock *ls;
+
+ TAILQ_FOREACH(ls, &heritage.socks, list) {
+ if (ls->sock < 0)
+ continue;
+ close(ls->sock);
+ ls->sock = -1;
+ }
+}
+
+/*--------------------------------------------------------------------*/
+
static void
start_child(void)
{
if (child_state != CH_STOPPED && child_state != CH_DIED)
return;
- if (heritage.socket < 0) {
- heritage.socket =
- TCP_open(params->listen_host, params->listen_port, 1);
- if (heritage.socket < 0)
- return;
- }
+ if (open_sockets())
+ return; /* XXX ?? */
child_state = CH_STARTING;
if (child_state != CH_RUNNING)
return;
- close(heritage.socket);
- heritage.socket = -1;
+ close_sockets();
child_state = CH_STOPPING;
if (ev_poker != NULL) {
if (child_state == CH_DIED && params->auto_restart)
start_child();
else if (child_state == CH_DIED) {
- close(heritage.socket);
- heritage.socket = -1;
+ close_sockets();
child_state = CH_STOPPED;
}
else if (child_state == CH_STOPPING)
/*--------------------------------------------------------------------*/
+static void
+clean_listen_sock_head(struct listen_sock_head *lsh)
+{
+ struct listen_sock *ls, *ls2;
+
+ TAILQ_FOREACH_SAFE(ls, lsh, list, ls2) {
+ TAILQ_REMOVE(lsh, ls, list);
+ free(ls->host);
+ free(ls->port);
+ free(ls);
+ }
+}
+
static void
tweak_listen_address(struct cli *cli, struct parspec *par, const char *arg)
{
- char *a, *p;
+ char **av;
+ int i;
+ struct listen_sock *ls;
+ struct listen_sock_head lsh;
(void)par;
- if (arg != NULL) {
- if (TCP_parse(arg, &a, &p) != 0) {
- cli_out(cli, "Invalid listen address");
+ if (arg == NULL) {
+ /* Quote the string if we have more than one socket */
+ if (heritage.nsocks > 1)
+ cli_out(cli, "\"%s\"", params->listen_address);
+ else
+ cli_out(cli, "%s", params->listen_address);
+ return;
+ }
+
+ av = ParseArgv(arg, 0);
+ if (av[0] != NULL) {
+ cli_out(cli, "Parse error: %s", av[0]);
+ cli_result(cli, CLIS_PARAM);
+ FreeArgv(av);
+ return;
+ }
+ if (av[1] == NULL) {
+ cli_out(cli, "Empty listen address");
+ cli_result(cli, CLIS_PARAM);
+ FreeArgv(av);
+ return;
+ }
+ TAILQ_INIT(&lsh);
+ for (i = 1; av[i] != NULL; i++) {
+ ls = calloc(sizeof *ls, 1);
+ AN(ls);
+ ls->sock = -1;
+ TAILQ_INSERT_TAIL(&lsh, ls, list);
+ if (TCP_parse(av[i], &ls->host, &ls->port) != 0) {
+ cli_out(cli, "Invalid listen address \"%s\"", av[i]);
cli_result(cli, CLIS_PARAM);
- return;
+ break;
}
- if (p == NULL) {
- p = strdup("http");
- AN(p);
- }
- TCP_check(cli, a, p);
+ if (ls->port == NULL)
+ ls->port = strdup("http");
+ AN(ls->port);
+ TCP_check(cli, ls->host, ls->port);
if (cli->result != CLIS_OK)
- return;
- free(params->listen_address);
- free(params->listen_host);
- free(params->listen_port);
- params->listen_address = strdup(arg);
- AN(params->listen_address);
- params->listen_host = a;
- params->listen_port = p;
- } else
- cli_out(cli, "%s", params->listen_address);
+ break;
+ }
+ FreeArgv(av);
+ if (cli->result != CLIS_OK) {
+ clean_listen_sock_head(&lsh);
+ return;
+ }
+
+ free(params->listen_address);
+ params->listen_address = strdup(arg);
+ AN(params->listen_address);
+
+ clean_listen_sock_head(&heritage.socks);
+ heritage.nsocks = 0;
+
+ while (!TAILQ_EMPTY(&lsh)) {
+ ls = TAILQ_FIRST(&lsh);
+ TAILQ_REMOVE(&lsh, ls, list);
+ TAILQ_INSERT_TAIL(&heritage.socks, ls, list);
+ heritage.nsocks++;
+ }
}
/*--------------------------------------------------------------------*/
"default. ",
"off", "bool" },
{ "listen_address", tweak_listen_address,
- "The network address/port where Varnish services requests.\n"
+ "Whitespace separated list of network endpoints where "
+ "Varnish will accept requests.\n"
+ "Possible formats: host, host:port, :port\n"
MUST_RESTART,
- "0.0.0.0:80" },
+ ":80" },
{ "listen_depth", tweak_listen_depth,
"Listen(2) queue depth.\n"
#if defined(__FreeBSD__)
XXXAN(cli[0].sb);
cli[0].result = CLIS_OK;
- heritage.socket = -1;
-
/*
* Set up a temporary param block until VSL_MgtInit() can
* replace with shmem backed structure version.
* XXX: 'param' to static
*/
+ TAILQ_INIT(&heritage.socks);
memset(¶m, 0, sizeof param);
params = ¶m;
mgt_vcc_init();