found 627268 git/1:1.7.9.5-1
tags 627268 + patch
quit

Jonathan Nieder wrote:

> 3. git-daemon gets EADDRINUSE when it tries to use that address, since
>    the SO_REUSEADDR flag is not set.  If all (usually meaning "both")
>    addresses to be bound to are "in use", the daemon dies with
>
>       fatal: unable to allocate any listen sockets on port 9418
>
>    and gets launched again by runit when an address is free.
>
>    If only _some_ of the addresses to be bound to are "in use" in this
>    way, the daemon does not get launched again, and it is bound only
>    to the remaining ones.

Here's a patch that makes it possible to use

    --listen=0.0.0.0 --listen=::0 --listen-strict

in the "git daemon" arguments in /etc/sv/git-daemon/run to avoid that
problem.

-- >8 --
Subject: daemon: optionally treat failure to listen as a fatal error

Asking the git daemon to listen over multiple protocols is currently
somewhat error prone.  For example, suppose I perform the following
steps:

 1. Launch the git daemon:

        git daemon --verbose --listen=0.0.0.0 --listen=::0 \
                --base-path=/srv/git /srv/git

 2. Start a connection:

        git clone git://127.0.0.1/git.git

 3. While it is transferring objects, interrupt the daemon and launch
    it again:

        killall -9 git-daemon
        git daemon --verbose --listen=0.0.0.0 --listen=::0 ...

 4. Start another connection:

        git clone git://127.0.0.1/git.git

Then although the second launch of the "git daemon" server (step 3)
succeeds, the second client (step 4) fails with "Connection refused".

The cause is that because we did not pass --reuseaddr to the daemon,
it receives EADDRINUSE when it tries to bind to the ipv4 wildcard
address which is in use.  (--reuseaddr should probably be enabled by
default, but that's not what this patch is about.)  This is a common
cause of bind(2) failure in daemons and it is not entirely unexpected
that listening to INADDR_ANY fails.

What is surprising is that "git daemon" only logs the event and does
not exit to signal the error.  The logic is that as long as the daemon
binds to _some_ address (in this example the ipv6 one) it has in some
sense succeeded.

It would be better to error out when the daemon is not able to fulfill
the administrator's request by listening to all of the addresses
requested on the command line.  Do so when requested by passing
--listen-strict on the command line.  Making the improvement opt-in
means configurations that relied on the existing, more permissive
behavior will not be broken by this change.

Signed-off-by: Jonathan Nieder <jrnie...@gmail.com>
---
 Documentation/git-daemon.txt |    7 ++++++-
 daemon.c                     |   20 +++++++++++++++-----
 2 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt
index 31b28fc2..bd061b7f 100644
--- a/Documentation/git-daemon.txt
+++ b/Documentation/git-daemon.txt
@@ -16,7 +16,8 @@ SYNOPSIS
             [--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>]]
+            [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]
+                       [--listen-strict] [--user=<user> [--group=<group>]]]
             [<directory>...]
 
 DESCRIPTION
@@ -92,6 +93,10 @@ OPTIONS
 --port=<n>::
        Listen on an alternative port.  Incompatible with '--inetd' option.
 
+--listen-strict::
+       Exit if listening to one of the addresses specified using the
+       '--listen' option fails.
+
 --init-timeout=<n>::
        Timeout (in seconds) between the moment the connection is established
        and the client request is received (typically a rather low value, since
diff --git a/daemon.c b/daemon.c
index ab21e66b..7e1a18ed 100644
--- a/daemon.c
+++ b/daemon.c
@@ -20,6 +20,7 @@
 static int log_syslog;
 static int verbose;
 static int reuseaddr;
+static int listen_failure_is_fatal;
 static int informative_errors;
 
 static const char daemon_usage[] =
@@ -913,12 +914,17 @@ static void socksetup(struct string_list *listen_addr, 
int listen_port, struct s
        else {
                int i, socknum;
                for (i = 0; i < listen_addr->nr; i++) {
-                       socknum = setup_named_sock(listen_addr->items[i].string,
-                                                  listen_port, socklist);
+                       char *addr = listen_addr->items[i].string;
 
-                       if (socknum == 0)
-                               logerror("unable to allocate any listen sockets 
for host %s on port %u",
-                                        listen_addr->items[i].string, 
listen_port);
+                       socknum = setup_named_sock(addr, listen_port, socklist);
+                       if (socknum)
+                               continue;
+
+                       logerror("unable to allocate any listen sockets for 
host %s on port %u",
+                                addr, listen_port);
+                       if (listen_failure_is_fatal)
+                               die("unable to allocate any listen sockets for 
host %s on port %u",
+                                   addr, listen_port);
                }
        }
 }
@@ -1121,6 +1127,10 @@ int main(int argc, char **argv)
                                continue;
                        }
                }
+               if (!strcmp(arg, "--listen-strict")) {
+                       listen_failure_is_fatal = 1;
+                       continue;
+               }
                if (!strcmp(arg, "--serve")) {
                        serve_mode = 1;
                        continue;
-- 
1.7.10.rc3




-- 
To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org

Reply via email to