]> err.no Git - varnish/commitdiff
Make Varnish able to accept connections from multiple sockets by
authorphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Thu, 8 Mar 2007 10:09:18 +0000 (10:09 +0000)
committerphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Thu, 8 Mar 2007 10:09:18 +0000 (10:09 +0000)
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: svn+ssh://projects.linpro.no/svn/varnish/trunk@1280 d4fa192b-c00b-0410-8231-f00ffab90ce4

varnish-cache/bin/varnishd/cache_acceptor.c
varnish-cache/bin/varnishd/heritage.h
varnish-cache/bin/varnishd/mgt_child.c
varnish-cache/bin/varnishd/mgt_param.c
varnish-cache/bin/varnishd/varnishd.c

index ddddaaacc612ec61d7ba9da00508d27a76de759e..3d267e7bdc7c6b63184c4aa9817ad37313c4e3a0 100644 (file)
@@ -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);
+               }
        }
 }
 
index 98bd3009f434c1fcce38c008389a547c3e37144b..4197b16bafc07013652ac91b6d4de09457a1bf50 100644 (file)
  * 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;
index 4e85bbda4e240f6d64d791c4f19ea28a53e6ac49..45a84669497953f5692f4e71c40e3b3f737976f5 100644 (file)
@@ -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)
index 69298cc244c44cb2126528c94f6a9000ddd1e193..0287346f2e46aac2b08c4c80d856ef32e088cd62 100644 (file)
@@ -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__)
index 48c23ba1fe4958f2497ca977b7fcdd4d1c2865a7..db1b6ed258e1ca069edbea1468d6002b60107913 100644 (file)
@@ -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();