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 @@
#include <stdio.h>
#include <errno.h>
#include <poll.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
......@@ -137,47 +138,65 @@ vca_acct(void *arg)
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);
}
}
}
......
......@@ -31,27 +31,38 @@
* 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 {
......@@ -89,8 +100,6 @@ struct params {
/* Listen address */
char *listen_address;
char *listen_host;
char *listen_port;
/* Listen depth */
unsigned listen_depth;
......
......@@ -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
start_child(void)
{
......@@ -133,12 +165,8 @@ 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;
......@@ -219,8 +247,7 @@ stop_child(void)
if (child_state != CH_RUNNING)
return;
close(heritage.socket);
heritage.socket = -1;
close_sockets();
child_state = CH_STOPPING;
if (ev_poker != NULL) {
......@@ -295,8 +322,7 @@ mgt_sigchld(struct ev *e, int what)
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)
......
......@@ -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
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++;
}
}
/*--------------------------------------------------------------------*/
......@@ -477,9 +530,11 @@ static struct parspec parspec[] = {
"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__)
......
......@@ -410,8 +410,6 @@ main(int argc, char *argv[])
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.
......@@ -426,6 +424,7 @@ main(int argc, char *argv[])
* XXX: 'param' to static
*/
TAILQ_INIT(&heritage.socks);
memset(&param, 0, sizeof param);
params = &param;
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