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);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.