Merge branch 'as/daemon-multi-listen'
authorJunio C Hamano <gitster@pobox.com>
Wed, 27 Oct 2010 04:50:03 +0000 (21:50 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 27 Oct 2010 04:50:03 +0000 (21:50 -0700)
* as/daemon-multi-listen:
daemon: allow more than one host address given via --listen
daemon: add helper function named_sock_setup

1  2 
Documentation/git-daemon.txt
daemon.c
index 2f0ddf6fe817ab7b59fb5f5276ba688447661ee3,685aa58cec823e69acc8f247e019ebdb8e9415ce..5054f790a140b43640d1e4d68a032d95da3daaca
@@@ -9,15 -9,15 +9,15 @@@ SYNOPSI
  --------
  [verse]
  'git daemon' [--verbose] [--syslog] [--export-all]
 -           [--timeout=n] [--init-timeout=n] [--max-connections=n]
 -           [--strict-paths] [--base-path=path] [--base-path-relaxed]
 -           [--user-path | --user-path=path]
 -           [--interpolated-path=pathtemplate]
 -           [--reuseaddr] [--detach] [--pid-file=file]
 -           [--enable=service] [--disable=service]
 -           [--allow-override=service] [--forbid-override=service]
 -           [--inetd | [--listen=host_or_ipaddr] [--port=n] [--user=user [--group=group]]
 -           [directory...]
 +           [--timeout=<n>] [--init-timeout=<n>] [--max-connections=<n>]
 +           [--strict-paths] [--base-path=<path>] [--base-path-relaxed]
 +           [--user-path | --user-path=<path>]
 +           [--interpolated-path=<pathtemplate>]
 +           [--reuseaddr] [--detach] [--pid-file=<file>]
 +           [--enable=<service>] [--disable=<service>]
 +           [--allow-override=<service>] [--forbid-override=<service>]
 +           [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>] [--user=<user> [--group=<group>]]
 +           [<directory>...]
  
  DESCRIPTION
  -----------
@@@ -48,7 -48,7 +48,7 @@@ OPTION
        'git daemon' will refuse to start when this option is enabled and no
        whitelist is specified.
  
 ---base-path=path::
 +--base-path=<path>::
        Remap all the path requests as relative to the given path.
        This is sort of "GIT root" - if you run 'git daemon' with
        '--base-path=/srv/git' on example.com, then if you later try to pull
@@@ -61,7 -61,7 +61,7 @@@
        This is useful for switching to --base-path usage, while still
        allowing the old paths.
  
 ---interpolated-path=pathtemplate::
 +--interpolated-path=<pathtemplate>::
        To support virtual hosting, an interpolated path template can be
        used to dynamically construct alternate paths.  The template
        supports %H for the target hostname as supplied by the client but
        Have the server run as an inetd service. Implies --syslog.
        Incompatible with --port, --listen, --user and --group options.
  
 ---listen=host_or_ipaddr::
 +--listen=<host_or_ipaddr>::
        Listen on a specific IP address or hostname.  IP addresses can
        be either an IPv4 address or an IPv6 address if supported.  If IPv6
        is not supported, then --listen=hostname is also not supported and
        --listen must be given an IPv4 address.
+       Can be given more than once.
        Incompatible with '--inetd' option.
  
 ---port=n::
 +--port=<n>::
        Listen on an alternative port.  Incompatible with '--inetd' option.
  
 ---init-timeout=n::
 +--init-timeout=<n>::
        Timeout between the moment the connection is established and the
        client request is received (typically a rather low value, since
        that should be basically immediate).
  
 ---timeout=n::
 +--timeout=<n>::
        Timeout for specific client sub-requests. This includes the time
        it takes for the server to process the sub-request and the time spent
        waiting for the next client's request.
  
 ---max-connections=n::
 +--max-connections=<n>::
        Maximum number of concurrent clients, defaults to 32.  Set it to
        zero for no limit.
  
        --verbose, thus by default only error conditions will be logged.
  
  --user-path::
 ---user-path=path::
 +--user-path=<path>::
        Allow {tilde}user notation to be used in requests.  When
        specified with no parameter, requests to
        git://host/{tilde}alice/foo is taken as a request to access
  --detach::
        Detach from the shell. Implies --syslog.
  
 ---pid-file=file::
 +--pid-file=<file>::
        Save the process id in 'file'.  Ignored when the daemon
        is run under `--inetd`.
  
 ---user=user::
 ---group=group::
 +--user=<user>::
 +--group=<group>::
        Change daemon's uid and gid before entering the service loop.
        When only `--user` is given without `--group`, the
        primary group ID for the user is used.  The values of
@@@ -145,16 -146,16 +146,16 @@@ Giving these options is an error when u
  the facility of inet daemon to achieve the same before spawning
  'git daemon' if needed.
  
 ---enable=service::
 ---disable=service::
 +--enable=<service>::
 +--disable=<service>::
        Enable/disable the service site-wide per default.  Note
        that a service disabled site-wide can still be enabled
        per repository if it is marked overridable and the
        repository enables the service with a configuration
        item.
  
 ---allow-override=service::
 ---forbid-override=service::
 +--allow-override=<service>::
 +--forbid-override=<service>::
        Allow/forbid overriding the site-wide default with per
        repository configuration.  By default, all the services
        are overridable.
diff --combined daemon.c
index 9326d3a1fa05f4878a21b58a623d07428f7230fe,d6e20c6771104203be143f9bdda2e68b570d0328..7ccd097e1d1234d06316e8b7f271e86127750f85
+++ b/daemon.c
@@@ -3,6 -3,7 +3,7 @@@
  #include "exec_cmd.h"
  #include "run-command.h"
  #include "strbuf.h"
+ #include "string-list.h"
  
  #include <syslog.h>
  
@@@ -20,15 -21,15 +21,15 @@@ static int reuseaddr
  
  static const char daemon_usage[] =
  "git daemon [--verbose] [--syslog] [--export-all]\n"
 -"           [--timeout=n] [--init-timeout=n] [--max-connections=n]\n"
 -"           [--strict-paths] [--base-path=path] [--base-path-relaxed]\n"
 -"           [--user-path | --user-path=path]\n"
 -"           [--interpolated-path=path]\n"
 -"           [--reuseaddr] [--detach] [--pid-file=file]\n"
 -"           [--[enable|disable|allow-override|forbid-override]=service]\n"
 -"           [--inetd | [--listen=host_or_ipaddr] [--port=n]\n"
 -"                      [--user=user [--group=group]]\n"
 -"           [directory...]";
 +"           [--timeout=<n>] [--init-timeout=<n>] [--max-connections=<n>]\n"
 +"           [--strict-paths] [--base-path=<path>] [--base-path-relaxed]\n"
 +"           [--user-path | --user-path=<path>]\n"
 +"           [--interpolated-path=<path>]\n"
 +"           [--reuseaddr] [--detach] [--pid-file=<file>]\n"
 +"           [--(enable|disable|allow-override|forbid-override)=<service>]\n"
 +"           [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]\n"
 +"                      [--user=<user> [--group=<group>]]\n"
 +"           [<directory>...]";
  
  /* List of acceptable pathname prefixes */
  static char **ok_paths;
@@@ -734,11 -735,17 +735,17 @@@ static int set_reuse_addr(int sockfd
                          &on, sizeof(on));
  }
  
+ struct socketlist {
+       int *list;
+       size_t nr;
+       size_t alloc;
+ };
  #ifndef NO_IPV6
  
- static int socksetup(char *listen_addr, int listen_port, int **socklist_p)
+ static int setup_named_sock(char *listen_addr, int listen_port, struct socketlist *socklist)
  {
-       int socknum = 0, *socklist = NULL;
+       int socknum = 0;
        int maxfd = -1;
        char pbuf[NI_MAXSERV];
        struct addrinfo hints, *ai0, *ai;
        hints.ai_flags = AI_PASSIVE;
  
        gai = getaddrinfo(listen_addr, pbuf, &hints, &ai0);
-       if (gai)
-               die("getaddrinfo() failed: %s", gai_strerror(gai));
+       if (gai) {
+               logerror("getaddrinfo() for %s failed: %s", listen_addr, gai_strerror(gai));
+               return 0;
+       }
  
        for (ai = ai0; ai; ai = ai->ai_next) {
                int sockfd;
                if (flags >= 0)
                        fcntl(sockfd, F_SETFD, flags | FD_CLOEXEC);
  
-               socklist = xrealloc(socklist, sizeof(int) * (socknum + 1));
-               socklist[socknum++] = sockfd;
+               ALLOC_GROW(socklist->list, socklist->nr + 1, socklist->alloc);
+               socklist->list[socklist->nr++] = sockfd;
+               socknum++;
  
                if (maxfd < sockfd)
                        maxfd = sockfd;
  
        freeaddrinfo(ai0);
  
-       *socklist_p = socklist;
        return socknum;
  }
  
  #else /* NO_IPV6 */
  
- static int socksetup(char *listen_addr, int listen_port, int **socklist_p)
+ static int setup_named_sock(char *listen_addr, int listen_port, struct socketlist *socklist)
  {
        struct sockaddr_in sin;
        int sockfd;
        if (flags >= 0)
                fcntl(sockfd, F_SETFD, flags | FD_CLOEXEC);
  
-       *socklist_p = xmalloc(sizeof(int));
-       **socklist_p = sockfd;
+       ALLOC_GROW(socklist->list, socklist->nr + 1, socklist->alloc);
+       socklist->list[socklist->nr++] = sockfd;
        return 1;
  }
  
  #endif
  
- static int service_loop(int socknum, int *socklist)
+ static void socksetup(struct string_list *listen_addr, int listen_port, struct socketlist *socklist)
+ {
+       if (!listen_addr->nr)
+               setup_named_sock(NULL, listen_port, socklist);
+       else {
+               int i, socknum;
+               for (i = 0; i < listen_addr->nr; i++) {
+                       socknum = setup_named_sock(listen_addr->items[i].string,
+                                                  listen_port, socklist);
+                       if (socknum == 0)
+                               logerror("unable to allocate any listen sockets for host %s on port %u",
+                                        listen_addr->items[i].string, listen_port);
+               }
+       }
+ }
+ static int service_loop(struct socketlist *socklist)
  {
        struct pollfd *pfd;
        int i;
  
-       pfd = xcalloc(socknum, sizeof(struct pollfd));
+       pfd = xcalloc(socklist->nr, sizeof(struct pollfd));
  
-       for (i = 0; i < socknum; i++) {
-               pfd[i].fd = socklist[i];
+       for (i = 0; i < socklist->nr; i++) {
+               pfd[i].fd = socklist->list[i];
                pfd[i].events = POLLIN;
        }
  
  
                check_dead_children();
  
-               if (poll(pfd, socknum, -1) < 0) {
+               if (poll(pfd, socklist->nr, -1) < 0) {
                        if (errno != EINTR) {
                                logerror("Poll failed, resuming: %s",
                                      strerror(errno));
                        continue;
                }
  
-               for (i = 0; i < socknum; i++) {
+               for (i = 0; i < socklist->nr; i++) {
                        if (pfd[i].revents & POLLIN) {
                                struct sockaddr_storage ss;
                                unsigned int sslen = sizeof(ss);
@@@ -946,27 -972,27 +972,27 @@@ static void store_pid(const char *path
                die_errno("failed to write pid file '%s'", path);
  }
  
- static int serve(char *listen_addr, int listen_port, struct passwd *pass, gid_t gid)
+ static int serve(struct string_list *listen_addr, int listen_port, struct passwd *pass, gid_t gid)
  {
-       int socknum, *socklist;
+       struct socketlist socklist = { NULL, 0, 0 };
  
-       socknum = socksetup(listen_addr, listen_port, &socklist);
-       if (socknum == 0)
-               die("unable to allocate any listen sockets on host %s port %u",
-                   listen_addr, listen_port);
+       socksetup(listen_addr, listen_port, &socklist);
+       if (socklist.nr == 0)
+               die("unable to allocate any listen sockets on port %u",
+                   listen_port);
  
        if (pass && gid &&
            (initgroups(pass->pw_name, gid) || setgid (gid) ||
             setuid(pass->pw_uid)))
                die("cannot drop privileges");
  
-       return service_loop(socknum, socklist);
+       return service_loop(&socklist);
  }
  
  int main(int argc, char **argv)
  {
        int listen_port = 0;
-       char *listen_addr = NULL;
+       struct string_list listen_addr = STRING_LIST_INIT_NODUP;
        int inetd_mode = 0;
        const char *pid_file = NULL, *user_name = NULL, *group_name = NULL;
        int detach = 0;
                char *arg = argv[i];
  
                if (!prefixcmp(arg, "--listen=")) {
-                       listen_addr = xstrdup_tolower(arg + 9);
+                       string_list_append(&listen_addr, xstrdup_tolower(arg + 9));
                        continue;
                }
                if (!prefixcmp(arg, "--port=")) {
        if (inetd_mode && (group_name || user_name))
                die("--user and --group are incompatible with --inetd");
  
-       if (inetd_mode && (listen_port || listen_addr))
+       if (inetd_mode && (listen_port || (listen_addr.nr > 0)))
                die("--listen= and --port= are incompatible with --inetd");
        else if (listen_port == 0)
                listen_port = DEFAULT_GIT_PORT;
        if (pid_file)
                store_pid(pid_file);
  
-       return serve(listen_addr, listen_port, pass, gid);
+       return serve(&listen_addr, listen_port, pass, gid);
  }