Package: git-daemon-run
Version: 1:1.7.2.3-2.2
Severity: important
Justification: bad behavior, especially re ipv6 support
Hi,
Was playing around with git-daemon-run to compare it with the proposed
sysvinit support. See [1] for the war story.
Okay, finished? The upshot is, as ip(7) explains,
A TCP local socket address that has been bound is unavailable
for some time after closing, unless the SO_REUSEADDR flag
has been set. Care should be taken when using this flag as it
makes TCP less reliable.
More precisely:
1. server closes connection, for example by exiting.
2. kernel places connection in TIME-WAIT state. The address is in use.
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.
Analysis:
- The ideal would be to disallow connections _from the same client
address and port_ until the TIME-WAIT state ends. Is that easy to
achieve?
- A workaround, even though it violates the spirit of TCP, is to just
forget about TIME-WAIT in the case of restarting the daemon. I
_suspect_ that this is what the git daemon --reuseaddr flag does
but of course it is hard to check.
- The fourth best behavior would be to convince git daemon that
EADDRINUSE is fatal so runit keeps on trying to relaunch the daemon
until all its addresses are available.
- Of course better is to run separate daemons for ipv4 and ipv6.
Thoughts?
Jonathan
[1] In one terminal I start the daemon and clear its log:
# sv stop git-daemon
ok: down: git-daemon: 1s, normally up
# sh -c '>/var/log/git-daemon/current'
# sv start git-daemon
ok: run: git-daemon: (pid 6070) 0s
Great. Now in another terminal I start a connection:
$ git clone git://localhost/git/git.git
Cloning into git...
remote: Counting objects: 113028, done.
Back in the first terminal, I brutally interrupt the daemon, to see
how the supervision copes.
# killall -9 git-daemon
Great, it seems! The clone continues unhindered (I think the process
actually transmitting data is git upload-pack). The log informs me
that all is well.
# cat /var/log/git-daemon/run
2011-01-09_06:29:43.06660 git-daemon starting.
2011-01-09_06:30:01.26329 [6074] Connection from [::1]:33407
2011-01-09_06:30:01.26340 [6074] Extended attributes (16 bytes) exist
<host=localhost>
2011-01-09_06:30:01.26429 [6074] Request upload-pack for '/git/git.git'
2011-01-09_06:30:05.41074 git-daemon starting.
Now again.
$ rm -fr git; git clone git://localhost/git/git.git
Cloning into git...
localhost[0: ::1]: errno=Connection refused
remote: Counting objects: 19469
Interrupting the daemon:
# killall -9 git-daemon
The clone continues unhindered. Log:
# sudo cat /var/log/git-daemon/current
2011-01-09_06:29:43.06660 git-daemon starting.
2011-01-09_06:30:01.26329 [6074] Connection from [::1]:33407
2011-01-09_06:30:01.26340 [6074] Extended attributes (16 bytes) exist
<host=localhost>
2011-01-09_06:30:01.26429 [6074] Request upload-pack for '/git/git.git'
2011-01-09_06:30:05.41074 git-daemon starting.
2011-01-09_06:31:19.83078 [6091] Connection from 127.0.0.1:39196
2011-01-09_06:31:19.83095 [6091] Extended attributes (16 bytes) exist
<host=localhost>
2011-01-09_06:31:19.83206 [6091] Request upload-pack for '/git/git.git'
2011-01-09_06:31:29.42557 git-daemon starting.
2011-01-09_06:31:29.43869 fatal: unable to allocate any listen sockets
on port 9418
2011-01-09_06:31:30.44277 git-daemon starting.
2011-01-09_06:31:30.44796 fatal: unable to allocate any listen sockets
on port 9418
[3 more failures before it succeeds]
--
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]