Re: dbus-daemon on Windows: Failed to bind socket "localhost:59367": Address already in use
Ralf Habacker <ralf-aVxs2ipq/[email protected]>
| Newsgroups | gmane.comp.freedesktop.dbus |
|---|---|
| Message-ID | <[email protected]> |
Am 03.01.2015 um 01:43 schrieb Thomas Sondergaard: > On 2015-01-02 23:17, Thomas Sondergaard wrote: >> When I run the attached test programs I get a handful or so of cases >> where the dbus-daemon fails to start with a message like >> >> Failed to bind socket "localhost:59367": Address already in use >> >> This surprises me. First I thought it was some kind of race condition >> when starting multiple buses at the same time (dbus-test.cc), but it >> also fails a handful of times out of a thousand when only one process is >> started at a time (dbus-test-nothreads.cc). >> >> This is using D-Bus Message Bus Daemon 1.8.10 on Windows. >> >> Steps to reproduce: >> >> 1. Compile the small test program on Windows >> 2. Make sure dbus-daemon is in the path >> 3. Run the test program >> >> The nothreads version takes about 4 minutes to run. >> >> Regards, >> Thomas > > I've digged a little further and I think I see a bug in > _dbus_server_new_for_tcp_socket() in dbus-sysdeps-win.c. If I > understand _dbus_server_new_for_tcp_socket() it is working hard to > bind the same port on both IPv4 and IPv6. If it starts with port=0 it > will do a bind with that and then extract the port number with > getsockname(), and then it will goto redo_lookup_with_port and do the > same binds again. > > The bug that I'm seeing is that it is not correctly extracting the > port number that the first bind with port=0 produces. It is doing: > > snprintf( portbuf, sizeof( portbuf ) - 1, "%d", addr.AddressIn.sin_port); > > which fails to account for sin_port being in network byte order. The > effect is that subsequent binds will be to another "arbitrary" port > that may or may not be available. > > Just adding ntohs() around addr.AddressIn.sin_port will make the > function find the correct port, but it wont work as the next bind() > will then fail with EADDRINUSE. > > I compared the Windows and the Unix version of > _dbus_server_new_for_tcp_socket() and it seems that the two versions > of the functions have grown apart over time. Perhaps the unix version > has some tricks that the Windows version needs to learn? The difference in _dbus_listen_tcp_socket is that the unix version uses getnameinfo() to fetch the port, which is implemented in the appended patch for windows too. Can you check if this works ? Regards Ralf
0001-Keep-fetching-of-tcp-port-in-sync-with-unix-part.patch
(text/x-patch, 2.1 KB)
From 2c490e405e7cb2b42047f9c771ef74407b2c429d Mon Sep 17 00:00:00 2001 From: Ralf Habacker <[email protected]> Date: Sat, 3 Jan 2015 10:08:22 +0100 Subject: [PATCH] Keep fetching of tcp port in sync with unix part. --- dbus/dbus-sysdeps-win.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/dbus/dbus-sysdeps-win.c b/dbus/dbus-sysdeps-win.c index 208e852..d05890e 100644 --- a/dbus/dbus-sysdeps-win.c +++ b/dbus/dbus-sysdeps-win.c @@ -1752,19 +1752,24 @@ _dbus_listen_tcp_socket (const char *host, to use the same port */ if (!port || !strcmp(port, "0")) { - mysockaddr_gen addr; - socklen_t addrlen = sizeof(addr); - char portbuf[10]; - - if (getsockname(fd, &addr.Address, &addrlen) == SOCKET_ERROR) + int result; + struct sockaddr_storage addr; + socklen_t addrlen; + char portbuf[50]; + + addrlen = sizeof(addr); + result = getsockname(fd, (struct sockaddr*) &addr, &addrlen); + + if (result == -1 || + (res = getnameinfo ((struct sockaddr*)&addr, addrlen, NULL, 0, + portbuf, sizeof(portbuf), + NI_NUMERICHOST)) != 0) { - DBUS_SOCKET_SET_ERRNO (); dbus_set_error (error, _dbus_error_from_errno (errno), - "Failed to resolve port \"%s:%s\": %s", - host ? host : "*", port, _dbus_strerror_from_errno()); + "Failed to resolve port \"%s:%s\": %s (%s)", + host ? host : "*", port, gai_strerror(res), res); goto failed; } - snprintf( portbuf, sizeof( portbuf ) - 1, "%d", addr.AddressIn.sin_port ); if (!_dbus_string_append(retport, portbuf)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);