Commit accd6878 authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Make Varnish able to accept connections from multiple sockets by

specifying a whitespace separated list of addresses to -a (or
param.set listen_address).

I'm not sure about the error handling, for instance, what is the
desirable behaviour if one of multiple sockets fail to open ?

Suggested by: <darryl.dixon@winterhouseconsulting.com>



git-svn-id: http://www.varnish-cache.org/svn/trunk/varnish-cache@1280 d4fa192b-c00b-0410-8231-f00ffab90ce4
parent 1a4eb815
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
#include <poll.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
...@@ -137,47 +138,65 @@ vca_acct(void *arg) ...@@ -137,47 +138,65 @@ vca_acct(void *arg)
struct sess *sp; struct sess *sp;
socklen_t l; socklen_t l;
struct sockaddr addr[2]; /* XXX: IPv6 hack */ struct sockaddr addr[2]; /* XXX: IPv6 hack */
int i; int i, j;
struct pollfd *pfd;
struct listen_sock *ls;
(void)arg; (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; need_test = 1;
AZ(setsockopt(heritage.socket, SOL_SOCKET, SO_LINGER,
&linger, sizeof linger));
while (1) { while (1) {
if (params->send_timeout != tv_sndtimeo.tv_sec) { if (params->send_timeout != tv_sndtimeo.tv_sec) {
need_test = 1; need_test = 1;
tv_sndtimeo.tv_sec = params->send_timeout; tv_sndtimeo.tv_sec = params->send_timeout;
AZ(setsockopt(heritage.socket, SOL_SOCKET, TAILQ_FOREACH(ls, &heritage.socks, list)
SO_SNDTIMEO, &tv_sndtimeo, sizeof tv_sndtimeo)); AZ(setsockopt(ls->sock, SOL_SOCKET,
SO_SNDTIMEO, &tv_sndtimeo, sizeof tv_sndtimeo));
} }
if (params->sess_timeout != tv_rcvtimeo.tv_sec) { if (params->sess_timeout != tv_rcvtimeo.tv_sec) {
need_test = 1; need_test = 1;
tv_rcvtimeo.tv_sec = params->sess_timeout; tv_rcvtimeo.tv_sec = params->sess_timeout;
AZ(setsockopt(heritage.socket, SOL_SOCKET, TAILQ_FOREACH(ls, &heritage.socks, list)
SO_RCVTIMEO, &tv_rcvtimeo, sizeof tv_rcvtimeo)); AZ(setsockopt(ls->sock, SOL_SOCKET,
SO_RCVTIMEO, &tv_rcvtimeo, sizeof tv_rcvtimeo));
} }
VSL_stats->client_conn++; i = poll(pfd, heritage.nsocks, 1000);
for (j = 0; j < heritage.nsocks; j++) {
l = sizeof addr; if (pfd[j].revents == 0)
i = accept(heritage.socket, addr, &l); continue;
if (i < 0) { VSL_stats->client_conn++;
if (errno != EAGAIN) { l = sizeof addr;
VSL(SLT_Debug, heritage.socket, i = accept(pfd[j].fd, addr, &l);
"Accept failed errno=%d", errno); if (i < 0) {
/* XXX: stats ? */ 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->fd = i;
sp->id = i; sp->id = i;
(void)clock_gettime(CLOCK_REALTIME, &sp->t_open); (void)clock_gettime(CLOCK_REALTIME, &sp->t_open);
http_RecvPrep(sp->http); http_RecvPrep(sp->http);
sp->step = STP_FIRST; sp->step = STP_FIRST;
WRK_QueueSession(sp); WRK_QueueSession(sp);
}
} }
} }
......
...@@ -31,27 +31,38 @@ ...@@ -31,27 +31,38 @@
* This file contains the heritage passed when mgt forks cache * 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 { struct heritage {
/* /*
* Two pipe(2)'s for CLI connection between cache and mgt. * Two pipe(2)'s for CLI connection between cache and mgt.
* cache reads [2] and writes [1]. Mgt reads [0] and writes [3]. * cache reads [2] and writes [1]. Mgt reads [0] and writes [3].
*/ */
int fds[4]; int fds[4];
/* Socket from which to accept connections */ /* Sockets from which to accept connections */
int socket; struct listen_sock_head socks;
int nsocks;
/* Share memory log fd and size (incl header) */ /* Share memory log fd and size (incl header) */
int vsl_fd; int vsl_fd;
unsigned vsl_size; unsigned vsl_size;
/* Storage method */ /* Storage method */
struct stevedore *stevedore; struct stevedore *stevedore;
/* Hash method */ /* Hash method */
struct hash_slinger *hash; struct hash_slinger *hash;
}; };
struct params { struct params {
...@@ -89,8 +100,6 @@ struct params { ...@@ -89,8 +100,6 @@ struct params {
/* Listen address */ /* Listen address */
char *listen_address; char *listen_address;
char *listen_host;
char *listen_port;
/* Listen depth */ /* Listen depth */
unsigned listen_depth; unsigned listen_depth;
......
...@@ -122,6 +122,38 @@ child_poker(struct ev *e, int what) ...@@ -122,6 +122,38 @@ child_poker(struct ev *e, int what)
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
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 static void
start_child(void) start_child(void)
{ {
...@@ -133,12 +165,8 @@ start_child(void) ...@@ -133,12 +165,8 @@ start_child(void)
if (child_state != CH_STOPPED && child_state != CH_DIED) if (child_state != CH_STOPPED && child_state != CH_DIED)
return; return;
if (heritage.socket < 0) { if (open_sockets())
heritage.socket = return; /* XXX ?? */
TCP_open(params->listen_host, params->listen_port, 1);
if (heritage.socket < 0)
return;
}
child_state = CH_STARTING; child_state = CH_STARTING;
...@@ -219,8 +247,7 @@ stop_child(void) ...@@ -219,8 +247,7 @@ stop_child(void)
if (child_state != CH_RUNNING) if (child_state != CH_RUNNING)
return; return;
close(heritage.socket); close_sockets();
heritage.socket = -1;
child_state = CH_STOPPING; child_state = CH_STOPPING;
if (ev_poker != NULL) { if (ev_poker != NULL) {
...@@ -295,8 +322,7 @@ mgt_sigchld(struct ev *e, int what) ...@@ -295,8 +322,7 @@ mgt_sigchld(struct ev *e, int what)
if (child_state == CH_DIED && params->auto_restart) if (child_state == CH_DIED && params->auto_restart)
start_child(); start_child();
else if (child_state == CH_DIED) { else if (child_state == CH_DIED) {
close(heritage.socket); close_sockets();
heritage.socket = -1;
child_state = CH_STOPPED; child_state = CH_STOPPED;
} }
else if (child_state == CH_STOPPING) else if (child_state == CH_STOPPING)
......
...@@ -277,34 +277,87 @@ tweak_vcl_trace(struct cli *cli, struct parspec *par, const char *arg) ...@@ -277,34 +277,87 @@ tweak_vcl_trace(struct cli *cli, struct parspec *par, const char *arg)
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
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 static void
tweak_listen_address(struct cli *cli, struct parspec *par, const char *arg) 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; (void)par;
if (arg != NULL) { if (arg == NULL) {
if (TCP_parse(arg, &a, &p) != 0) { /* Quote the string if we have more than one socket */
cli_out(cli, "Invalid listen address"); 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); cli_result(cli, CLIS_PARAM);
return; break;
} }
if (p == NULL) { if (ls->port == NULL)
p = strdup("http"); ls->port = strdup("http");
AN(p); AN(ls->port);
} TCP_check(cli, ls->host, ls->port);
TCP_check(cli, a, p);
if (cli->result != CLIS_OK) if (cli->result != CLIS_OK)
return; break;
free(params->listen_address); }
free(params->listen_host); FreeArgv(av);
free(params->listen_port); if (cli->result != CLIS_OK) {
params->listen_address = strdup(arg); clean_listen_sock_head(&lsh);
AN(params->listen_address); return;
params->listen_host = a; }
params->listen_port = p;
} else free(params->listen_address);
cli_out(cli, "%s", 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++;
}
} }
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
...@@ -477,9 +530,11 @@ static struct parspec parspec[] = { ...@@ -477,9 +530,11 @@ static struct parspec parspec[] = {
"default. ", "default. ",
"off", "bool" }, "off", "bool" },
{ "listen_address", tweak_listen_address, { "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, MUST_RESTART,
"0.0.0.0:80" }, ":80" },
{ "listen_depth", tweak_listen_depth, { "listen_depth", tweak_listen_depth,
"Listen(2) queue depth.\n" "Listen(2) queue depth.\n"
#if defined(__FreeBSD__) #if defined(__FreeBSD__)
......
...@@ -410,8 +410,6 @@ main(int argc, char *argv[]) ...@@ -410,8 +410,6 @@ main(int argc, char *argv[])
XXXAN(cli[0].sb); XXXAN(cli[0].sb);
cli[0].result = CLIS_OK; cli[0].result = CLIS_OK;
heritage.socket = -1;
/* /*
* Set up a temporary param block until VSL_MgtInit() can * Set up a temporary param block until VSL_MgtInit() can
* replace with shmem backed structure version. * replace with shmem backed structure version.
...@@ -426,6 +424,7 @@ main(int argc, char *argv[]) ...@@ -426,6 +424,7 @@ main(int argc, char *argv[])
* XXX: 'param' to static * XXX: 'param' to static
*/ */
TAILQ_INIT(&heritage.socks);
memset(&param, 0, sizeof param); memset(&param, 0, sizeof param);
params = &param; params = &param;
mgt_vcc_init(); mgt_vcc_init();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment