default tcp host

Daniel P. Berrange dan at berrange.com
Wed Jun 13 15:37:50 PDT 2007


On Wed, Jun 13, 2007 at 09:42:47PM +0100, Daniel P. Berrange wrote:
> There is only one minor problem with the patch I'm attaching. A given
> hostname record may resolve to multiple IP addresses. On the client
> side this works fine - the addresses are sorted in order most likely
> to succeed, so we just try connect() in order until we establish a
> connection.  On the server side though there's a small irritating
> issue:
> 
>   - it is implementation defined whether you can accept an IPv4
>     connection over an IPv6 bound socket. eg if you listen on
>     the IPv6 any address :: you may or may not be able to accept 
>     connections to IPv4 addresses. So you may need to bind to the 
>     same port several times - once per address family. In Linux
>     this behaviour is toggled by net.ipv6.bindv6only, other OS
>     have it hardcoded.
> 
>   - a name may well resolve to multiple addresses - eg an IPv4 and
>     IPv6 address. 
> 
>   - a machine can have multiple interfaces with different IPs and
>     all mapping to a single name
> 
> The crux of the matter is that for correctness & portability when doing
> the TCP server setup we may need to open & bind to multiple sockets.
> The DBusTransportSocket struct currently only has a single fd. So I
> still need to adapt this such that it opens & deals with multiple fds
> on the server side of things. A little unpleasant, but certainly 
> doable
> 
> One other point - getaddrinfo will do service lookups to convert from
> a named port number to a numeric port number. I still need to change
> several functions to pass about char * for port instead of an int.

The attached patch adds support for listening on multiple FDs, using
named ports, fixes error reporting for getnameinfo/getaddrinfo calls
to use gai_strerror instead. 

I did a quick build & run of the test suite however, it is not at all
clear that there's any tests against this code in the first place.
Nor is it really very easy to write a reliable & generic test case 
for code doing lots of DNS lookups. Thoughts on this ?

Regards,
Dan.
-- 
|=-            GPG key: http://www.berrange.com/~dan/gpgkey.txt       -=|
|=-       Perl modules: http://search.cpan.org/~danberr/              -=|
|=-           Projects: http://freshmeat.net/~danielpb/               -=|
|=-   berrange at redhat.com  -  Daniel Berrange  -  dan at berrange.com    -=|
-------------- next part --------------
Index: dbus/dbus-server-socket.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-server-socket.c,v
retrieving revision 1.5
diff -u -p -r1.5 dbus-server-socket.c
--- dbus/dbus-server-socket.c	13 Jun 2007 20:52:58 -0000	1.5
+++ dbus/dbus-server-socket.c	14 Jun 2007 04:04:09 -0000
@@ -44,26 +44,31 @@ typedef struct DBusServerSocket DBusServ
  * Implementation details of DBusServerSocket. All members
  * are private.
  */
+#define MAX_SOCKET 10
+
 struct DBusServerSocket
 {
-  DBusServer base;   /**< Parent class members. */
-  int fd;            /**< File descriptor or -1 if disconnected. */
-  DBusWatch *watch;  /**< File descriptor watch. */
-  char *socket_name; /**< Name of domain socket, to unlink if appropriate */
+  DBusServer base;               /**< Parent class members. */
+  int nfd;                       /**< Number of active file handles */
+  int fd[MAX_SOCKET];            /**< File descriptor or -1 if disconnected. */
+  DBusWatch *watch[MAX_SOCKET];  /**< File descriptor watch. */
+  char *socket_name;             /**< Name of domain socket, to unlink if appropriate */
 };
 
 static void
 socket_finalize (DBusServer *server)
 {
   DBusServerSocket *socket_server = (DBusServerSocket*) server;
+  int i;
   
   _dbus_server_finalize_base (server);
 
-  if (socket_server->watch)
-    {
-      _dbus_watch_unref (socket_server->watch);
-      socket_server->watch = NULL;
-    }
+  for (i = 0 ; i < socket_server->nfd ; i++)
+    if (socket_server->watch[i])
+      {
+	_dbus_watch_unref (socket_server->watch[i]);
+	socket_server->watch[i] = NULL;
+      }
   
   dbus_free (socket_server->socket_name);
   dbus_free (server);
@@ -149,10 +154,16 @@ socket_handle_watch (DBusWatch    *watch
 {
   DBusServer *server = data;
   DBusServerSocket *socket_server = data;
+  int found = 0, i;
 
   SERVER_LOCK (server);
   
-  _dbus_assert (watch == socket_server->watch);
+  for (i = 0 ; i < socket_server->nfd ; i++)
+    {
+      if (socket_server->watch[i] == watch)
+	found = 1;
+    }
+  _dbus_assert (found);
 
   _dbus_verbose ("Handling client connection, flags 0x%x\n", flags);
   
@@ -199,19 +210,22 @@ static void
 socket_disconnect (DBusServer *server)
 {
   DBusServerSocket *socket_server = (DBusServerSocket*) server;
+  int i;
 
   HAVE_LOCK_CHECK (server);
   
-  if (socket_server->watch)
-    {
-      _dbus_server_remove_watch (server,
-                                 socket_server->watch);
-      _dbus_watch_unref (socket_server->watch);
-      socket_server->watch = NULL;
-    }
-  
-  _dbus_close_socket (socket_server->fd, NULL);
-  socket_server->fd = -1;
+  for (i = 0 ; i < socket_server->nfd ; i++) {
+    if (socket_server->watch[i])
+      {
+	_dbus_server_remove_watch (server,
+				   socket_server->watch[i]);
+	_dbus_watch_unref (socket_server->watch[i]);
+	socket_server->watch[i] = NULL;
+      }
+
+    _dbus_close_socket (socket_server->fd[i], NULL);
+    socket_server->fd[i] = -1;
+  }
 
   if (socket_server->socket_name != NULL)
     {
@@ -236,58 +250,101 @@ static const DBusServerVTable socket_vta
  * been successfully invoked on it. The server will use accept() to
  * accept new client connections.
  *
- * @param fd the file descriptor.
+ * @param fd list of file descriptors.
+ * @param nfd number of file descriptors
  * @param address the server's address
  * @returns the new server, or #NULL if no memory.
  * 
  */
 DBusServer*
-_dbus_server_new_for_socket (int               fd,
+_dbus_server_new_for_socket (int              *fd,
+			     int               nfd,
                              const DBusString *address)
 {
   DBusServerSocket *socket_server;
   DBusServer *server;
-  DBusWatch *watch;
+  int i;
   
   socket_server = dbus_new0 (DBusServerSocket, 1);
   if (socket_server == NULL)
     return NULL;
   
-  watch = _dbus_watch_new (fd,
-                           DBUS_WATCH_READABLE,
-                           TRUE,
-                           socket_handle_watch, socket_server,
-                           NULL);
-  if (watch == NULL)
-    {
-      dbus_free (socket_server);
-      return NULL;
-    }
-  
+
+  for (i = 0 ; i < nfd ; i++) {
+    DBusWatch *watch;
+
+    watch = _dbus_watch_new (fd[i],
+			     DBUS_WATCH_READABLE,
+			     TRUE,
+			     socket_handle_watch, socket_server,
+			     NULL);
+    if (watch == NULL)
+      {
+	int j;
+	for (j = 0 ; j < nfd ; j++)
+	  {
+	    if (socket_server->watch[j] != NULL)
+	      {
+		_dbus_server_remove_watch (server,
+					   socket_server->watch[j]);
+		_dbus_watch_unref (socket_server->watch[j]);
+		socket_server->watch[j] = NULL;
+	      }
+	  }
+	dbus_free (socket_server);
+	return NULL;
+      }
+
+    socket_server->nfd++;
+    socket_server->fd[i] = fd[i];
+    socket_server->watch[i] = watch;
+  }
+
   if (!_dbus_server_init_base (&socket_server->base,
                                &socket_vtable, address))
     {
-      _dbus_watch_unref (watch);
+      for (i = 0 ; i < nfd ; i++)
+	{
+	  if (socket_server->watch[i] != NULL)
+	    {
+	      _dbus_server_remove_watch (server,
+					 socket_server->watch[i]);
+	      _dbus_watch_unref (socket_server->watch[i]);
+	      socket_server->watch[i] = NULL;
+	    }
+	}
       dbus_free (socket_server);
       return NULL;
     }
 
+
   server = (DBusServer*) socket_server;
 
   SERVER_LOCK (server);
   
-  if (!_dbus_server_add_watch (&socket_server->base,
-                               watch))
-    {
-      SERVER_UNLOCK (server);
-      _dbus_server_finalize_base (&socket_server->base);
-      _dbus_watch_unref (watch);
-      dbus_free (socket_server);
-      return NULL;
-    }
-  
-  socket_server->fd = fd;
-  socket_server->watch = watch;
+  for (i = 0 ; i < nfd ; i++) {
+    if (!_dbus_server_add_watch (&socket_server->base,
+				 socket_server->watch[i]))
+      {
+	int j;
+	for (j = 0 ; j < i ; j++)
+	  {
+	    if (socket_server->watch[j] != NULL)
+	      {
+		_dbus_server_remove_watch (server,
+					   socket_server->watch[j]);
+		_dbus_watch_unref (socket_server->watch[j]);
+		socket_server->watch[j] = NULL;
+	      }
+	  }
+	_dbus_watch_unref (socket_server->watch[i]);
+
+	SERVER_UNLOCK (server);
+	_dbus_server_finalize_base (&socket_server->base);
+	dbus_free (socket_server);
+	return NULL;
+      }
+  }
 
   SERVER_UNLOCK (server);
   
@@ -296,29 +353,26 @@ _dbus_server_new_for_socket (int        
 
 /**
  * Creates a new server listening on TCP.
- * If inaddr_any is TRUE, listens on all local interfaces.
+ * If host is NULL, listens on all local interfaces.
  * Otherwise, it resolves the hostname and listens only on
- * the resolved address of the hostname. The hostname is used
- * even if inaddr_any is TRUE, as the hostname to report when
- * dbus_server_get_address() is called. If the hostname is #NULL,
- * localhost is used.
+ * the resolved address of the hostname.
  *
  * @param host the hostname to listen on.
  * @param port the port to listen on or 0 to let the OS choose
- * @param inaddr_any #TRUE to listen on all local interfaces
  * @param error location to store reason for failure.
  * @returns the new server, or #NULL on failure.
  */
 DBusServer*
 _dbus_server_new_for_tcp_socket (const char     *host,
-                                 dbus_uint32_t   port,
-                                 dbus_bool_t     inaddr_any,
+                                 const char     *port,
                                  DBusError      *error)
 {
   DBusServer *server;
-  int listen_fd;
+  int listen_fd[MAX_SOCKET];
+  int nlisten_fd = MAX_SOCKET, i;
   DBusString address;
   DBusString host_str;
+  char retport[50];
   
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
@@ -328,22 +382,36 @@ _dbus_server_new_for_tcp_socket (const c
       return NULL;
     }
 
-  if (host == NULL)
-    host = "localhost";
-  
-  listen_fd = _dbus_listen_tcp_socket (host, &port, inaddr_any, error);
-  _dbus_fd_set_close_on_exec (listen_fd);
+  nlisten_fd =_dbus_listen_tcp_socket (host, port, retport, sizeof(retport), listen_fd, nlisten_fd, error);
+  if (nlisten_fd < 0) {
+    _DBUS_ASSERT_ERROR_IS_SET(error);
+    return NULL;
+  }
 
-  _dbus_string_init_const (&host_str, host);
-  if (!_dbus_string_append (&address, "tcp:host=") ||
-      !_dbus_address_append_escaped (&address, &host_str) ||
-      !_dbus_string_append (&address, ",port=") ||
-      !_dbus_string_append_int (&address, port))
-    {
-      _dbus_string_free (&address);
-      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-      return NULL;
-    }
+  for (i = 0 ; i < nlisten_fd ; i++)
+    _dbus_fd_set_close_on_exec (listen_fd[i]);
+
+  if (host) {
+    _dbus_string_init_const (&host_str, host);
+    if (!_dbus_string_append (&address, "tcp:host=") ||
+	!_dbus_address_append_escaped (&address, &host_str) ||
+	!_dbus_string_append (&address, ",port=") ||
+	!_dbus_string_append (&address, retport))
+      {
+	_dbus_string_free (&address);
+	dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+	return NULL;
+      }
+  } else {
+    if (!_dbus_string_append (&address, "tcp:") ||
+	!_dbus_string_append (&address, "port=") ||
+	!_dbus_string_append (&address, retport))
+      {
+	_dbus_string_free (&address);
+	dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+	return NULL;
+      }
+  }
 
   
   if (listen_fd < 0)
@@ -352,11 +420,12 @@ _dbus_server_new_for_tcp_socket (const c
       return NULL;
     }
   
-  server = _dbus_server_new_for_socket (listen_fd, &address);
+  server = _dbus_server_new_for_socket (listen_fd, nlisten_fd, &address);
   if (server == NULL)
     {
       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-      _dbus_close_socket (listen_fd, NULL);
+      for (i = 0 ; i < nlisten_fd ; i++)
+	_dbus_close_socket (listen_fd[i], NULL);
       _dbus_string_free (&address);
       return NULL;
     }
@@ -395,55 +464,14 @@ _dbus_server_listen_socket (DBusAddressE
     {
       const char *host;
       const char *port;
-      const char *all_interfaces;
-      dbus_bool_t inaddr_any;
-      long lport;
 
       host = dbus_address_entry_get_value (entry, "host");
       port = dbus_address_entry_get_value (entry, "port");
-      all_interfaces = dbus_address_entry_get_value (entry, "all_interfaces");
 
-      inaddr_any = FALSE;
-      if (all_interfaces != NULL)
-        {
-          if (strcmp (all_interfaces, "true") == 0)
-            {
-              inaddr_any = TRUE;
-            }
-          else if (strcmp (all_interfaces, "false") == 0)
-            {
-              inaddr_any = FALSE;
-            }
-          else
-            {
-              _dbus_set_bad_address(error, NULL, NULL, 
-                                    "all_interfaces flag in tcp: address should be 'true' or 'false'");
-              return DBUS_SERVER_LISTEN_BAD_ADDRESS;
-            }
-        }
-      
       if (port == NULL)
-        {
-          lport = 0;
-        }
-      else
-        {
-          dbus_bool_t sresult;
-          DBusString  str;
-          
-          _dbus_string_init_const (&str, port);
-          sresult = _dbus_string_parse_int (&str, 0, &lport, NULL);
-          _dbus_string_free (&str);
-          
-          if (sresult == FALSE || lport < 0 || lport > 65535)
-            {
-              _dbus_set_bad_address(error, NULL, NULL, 
-                                    "Port is not an integer between 0 and 65535");
-              return DBUS_SERVER_LISTEN_BAD_ADDRESS;
-            }
-        }
+          port = "0";
           
-      *server_p = _dbus_server_new_for_tcp_socket (host, lport, inaddr_any, error);
+      *server_p = _dbus_server_new_for_tcp_socket (host, port, error);
 
       if (*server_p)
         {
Index: dbus/dbus-server-socket.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-server-socket.h,v
retrieving revision 1.2
diff -u -p -r1.2 dbus-server-socket.h
--- dbus/dbus-server-socket.h	13 Jun 2007 20:52:58 -0000	1.2
+++ dbus/dbus-server-socket.h	14 Jun 2007 04:04:09 -0000
@@ -28,11 +28,11 @@
 
 DBUS_BEGIN_DECLS
 
-DBusServer* _dbus_server_new_for_socket           (int               fd,
+DBusServer* _dbus_server_new_for_socket           (int              *fd,
+						   int               nfd,
                                                    const DBusString *address);
 DBusServer* _dbus_server_new_for_tcp_socket       (const char       *host,
-                                                   dbus_uint32_t     port,
-                                                   dbus_bool_t       inaddr_any,
+                                                   const char       *port,
                                                    DBusError        *error);
 DBusServerListenResult _dbus_server_listen_socket (DBusAddressEntry  *entry,
                                                    DBusServer       **server_p,
Index: dbus/dbus-server-unix.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-server-unix.c,v
retrieving revision 1.34
diff -u -p -r1.34 dbus-server-unix.c
--- dbus/dbus-server-unix.c	20 Oct 2006 03:04:59 -0000	1.34
+++ dbus/dbus-server-unix.c	14 Jun 2007 04:04:10 -0000
@@ -209,7 +209,7 @@ _dbus_server_new_for_domain_socket (cons
       goto failed_1;
     }
   
-  server = _dbus_server_new_for_socket (listen_fd, &address);
+  server = _dbus_server_new_for_socket (&listen_fd, 1, &address);
   if (server == NULL)
     {
       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
Index: dbus/dbus-sysdeps-unix.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-sysdeps-unix.c,v
retrieving revision 1.29
diff -u -p -r1.29 dbus-sysdeps-unix.c
--- dbus/dbus-sysdeps-unix.c	13 Jun 2007 20:52:58 -0000	1.29
+++ dbus/dbus-sysdeps-unix.c	14 Jun 2007 04:04:11 -0000
@@ -742,13 +742,12 @@ _dbus_listen_unix_socket (const char    
  */
 int
 _dbus_connect_tcp_socket (const char     *host,
-                          dbus_uint32_t   port,
+                          const char     *port,
                           DBusError      *error)
 {
-  int fd;
-  struct sockaddr_in addr;
-  struct hostent *he;
-  struct in_addr *haddr;
+  int fd = -1, res;
+  struct addrinfo hints;
+  struct addrinfo *ai, *tmp;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
  
@@ -761,45 +760,61 @@ _dbus_connect_tcp_socket (const char    
     }
   _DBUS_ASSERT_ERROR_IS_CLEAR(error);
       
-  if (host == NULL)
-    host = "localhost";
+  _DBUS_ZERO (hints);
 
-  he = gethostbyname (host);
-  if (he == NULL) 
+  hints.ai_family = AF_UNSPEC;
+  hints.ai_protocol = IPPROTO_TCP;
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_flags = AI_ADDRCONFIG;
+  
+  if ((res = getaddrinfo(host, port, &hints, &ai)) != 0)
     {
       dbus_set_error (error,
-                      _dbus_error_from_errno (errno),
-                      "Failed to lookup hostname: %s",
-                      host);
+		      _dbus_error_from_errno (errno),
+		      "Failed to lookup host/port: %s:%s: %s (%d)",
+		      host, port, gai_strerror(res), res);
       _dbus_close (fd, NULL);
       return -1;
     }
-  
-  haddr = ((struct in_addr *) (he->h_addr_list)[0]);
 
-  _DBUS_ZERO (addr);
-  memcpy (&addr.sin_addr, haddr, sizeof(struct in_addr));
-  addr.sin_family = AF_INET;
-  addr.sin_port = htons (port);
-  
-  if (connect (fd, (struct sockaddr*) &addr, sizeof (addr)) < 0)
-    {      
-      dbus_set_error (error,
-                       _dbus_error_from_errno (errno),
-                      "Failed to connect to socket %s:%d %s",
-                      host, port, _dbus_strerror (errno));
-
-      _dbus_close (fd, NULL);
-      fd = -1;
+  tmp = ai;
+  while (tmp)
+    {
+      if (!_dbus_open_socket (&fd, tmp->ai_family, SOCK_STREAM, 0, error))
+	{
+	  freeaddrinfo(ai);
+	  _DBUS_ASSERT_ERROR_IS_SET(error);
+	  return -1;
+	}
+      _DBUS_ASSERT_ERROR_IS_CLEAR(error);
+      
+      if (connect (fd, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) < 0)
+	{
+	  _dbus_close(fd, NULL);
+	  fd = -1;
+	  tmp = tmp->ai_next;
+	  continue;
+	}
       
+      break;
+    }
+  freeaddrinfo(ai);
+
+  if (fd == -1)
+    {
+      dbus_set_error (error,
+		      _dbus_error_from_errno (errno),
+		      "Failed to connect to socket %s:%d %s",
+		      host, port, _dbus_strerror(errno));
       return -1;
     }
 
+
   if (!_dbus_set_fd_nonblocking (fd, error))
     {
       _dbus_close (fd, NULL);
       fd = -1;
-
+      
       return -1;
     }
 
@@ -814,87 +829,159 @@ _dbus_connect_tcp_socket (const char    
  *
  * @param host the host name to listen on
  * @param port the prot to listen on, if zero a free port will be used
- * @param inaddr_any TRUE to listen on all local interfaces instead of on the host name
+ * @param retport buffer to write in actual port bind to
+ * @param retportlen size of retport in bytes
+ * @param retfd location to store returned file descriptors
+ * @param nretfd maximum number of returnable file descriptors
  * @param error return location for errors
- * @returns the listening file descriptor or -1 on error
+ * @returns the number of listening file descriptors or -1 on error
  */
 int
 _dbus_listen_tcp_socket (const char     *host,
-                         dbus_uint32_t  *port,
-                         dbus_bool_t     inaddr_any,
+                         const char     *port,
+			 char           *retport,
+			 dbus_uint32_t   retportlen,
+			 int            *retfd,
+			 int            nretfd,
                          DBusError      *error)
 {
-  int listen_fd;
-  struct sockaddr_in addr;
-  socklen_t len = (socklen_t) sizeof (struct sockaddr);
+  int listen_fd, res, nlisten_fd = 0, i, portval = -1;
+  struct addrinfo hints;
+  struct addrinfo *ai, *tmp;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);  
   
-  if (!_dbus_open_tcp_socket (&listen_fd, error))
-    {
-      _DBUS_ASSERT_ERROR_IS_SET(error);
-      return -1;
-    }
-  _DBUS_ASSERT_ERROR_IS_CLEAR(error);
+  _DBUS_ZERO (hints);
 
-  _DBUS_ZERO (addr);
+  hints.ai_family = AF_UNSPEC;
+  hints.ai_protocol = IPPROTO_TCP;
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
   
-  if (inaddr_any)
+  if ((res = getaddrinfo(host, port, &hints, &ai)) != 0 || !ai)
     {
-      addr.sin_addr.s_addr = INADDR_ANY;
+      dbus_set_error (error,
+		      _dbus_error_from_errno (errno),
+		      "Failed to lookup host/port: %s:%s: %s (%d)",
+		      host, port, gai_strerror(res), res);
+      _dbus_close (listen_fd, NULL);
+      return -1;
     }
-  else
+
+  tmp = ai;
+  while (tmp)
     {
-      struct hostent *he;
-      struct in_addr *haddr;      
+      if (nlisten_fd >= nretfd)
+	{
+	  dbus_set_error (error, _dbus_error_from_errno(EINVAL),
+			  "Too many sockets to listen on: %s", host);
+	  for (i = 0 ; i < nlisten_fd ; i++)
+	    _dbus_close(retfd[i], NULL);
+	  return -1;
+	}
 
-      he = gethostbyname (host);
-      if (he == NULL) 
-        {
-          dbus_set_error (error,
-                          _dbus_error_from_errno (errno),
-                          "Failed to lookup hostname: %s",
-                          host);
-          _dbus_close (listen_fd, NULL);
-          return -1;
-        }
-  
-      haddr = ((struct in_addr *) (he->h_addr_list)[0]);
+      if (!_dbus_open_socket (&listen_fd, tmp->ai_family, SOCK_STREAM, 0, error))
+	{
+	  _DBUS_ASSERT_ERROR_IS_SET(error);
+	  for (i = 0 ; i < nlisten_fd ; i++)
+	    _dbus_close(retfd[i], NULL);
+	  return -1;
+	}
+      _DBUS_ASSERT_ERROR_IS_CLEAR(error);
       
-      memcpy (&addr.sin_addr, haddr, sizeof (struct in_addr));
-    }
-  
-  addr.sin_family = AF_INET;
-  addr.sin_port = htons (*port);
+      
+      if (bind (listen_fd, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) < 0)
+	{
+	  _dbus_close(listen_fd, NULL);
+	  if (errno == EADDRINUSE)
+	    {
+	      tmp = tmp->ai_next;
+	      continue;
+	    }
+	  dbus_set_error (error, _dbus_error_from_errno (errno),
+			  "Failed to bind socket \"%s:%s\": %s",
+			  host, port, _dbus_strerror (errno));
+	  freeaddrinfo(ai);
+	  for (i = 0 ; i < nlisten_fd ; i++)
+	    _dbus_close(retfd[i], NULL);
+	  return -1;
+	}
 
-  if (bind (listen_fd, (struct sockaddr*) &addr, sizeof (struct sockaddr)))
-    {
-      dbus_set_error (error, _dbus_error_from_errno (errno),
-                      "Failed to bind socket \"%s:%d\": %s",
-                      host, *port, _dbus_strerror (errno));
-      _dbus_close (listen_fd, NULL);
-      return -1;
-    }
+      if (listen (listen_fd, 30 /* backlog */) < 0)
+	{
+	  dbus_set_error (error, _dbus_error_from_errno (errno),  
+			  "Failed to listen on socket \"%s:%s\": %s",
+			  host, port, _dbus_strerror (errno));
+	  _dbus_close (listen_fd, NULL);
+	  freeaddrinfo(ai);
+	  for (i = 0 ; i < nlisten_fd ; i++)
+	    _dbus_close(retfd[i], NULL);
+	  return -1;
+	}
 
-  if (listen (listen_fd, 30 /* backlog */) < 0)
-    {
-      dbus_set_error (error, _dbus_error_from_errno (errno),  
-                      "Failed to listen on socket \"%s:%d\": %s",
-                      host, *port, _dbus_strerror (errno));
-      _dbus_close (listen_fd, NULL);
-      return -1;
-    }
 
-  getsockname(listen_fd, (struct sockaddr*) &addr, &len);
-  *port = (dbus_uint32_t) ntohs(addr.sin_port);
+      retfd[nlisten_fd] = listen_fd;
+      nlisten_fd++;
+
+      /* Force remaining addresses to use same port if we're the
+	 first IPv4/IPv6 socket to be bound successfully */
+      /* XXX Perhaps a better way is to return multiple named ports to
+	 caller to expand the address string ? */
+      if (portval == -1 &&
+	  (tmp->ai_family == AF_INET ||
+	   tmp->ai_family == AF_INET6)) {
+	struct addrinfo *t2;
+	struct sockaddr_storage addr;
+	socklen_t addrlen;
+
+	addrlen = sizeof(addr);
+	getsockname(listen_fd, (struct sockaddr*) &addr, &addrlen);
+
+	if ((res = getnameinfo((struct sockaddr*)&addr, addrlen, NULL, 0,
+			       retport, retportlen,
+			       NI_NUMERICHOST)) != 0)
+	  {
+	    dbus_set_error (error, _dbus_error_from_errno (errno),
+			    "Failed to resolve port \"%s:%s\": %s (%s)",
+			    host, port, gai_strerror(res), res);
+	    for (i = 0 ; i < nlisten_fd ; i++)
+	      _dbus_close(retfd[i], NULL);
+	    return -1;
+	  }
+
+
+	if (tmp->ai_family == AF_INET)
+	  portval = ((struct sockaddr_in*)&addr)->sin_port;
+	else if (tmp->ai_family == AF_INET6)
+	  portval = ((struct sockaddr_in6*)&addr)->sin6_port;
+
+	t2 = tmp->ai_next;
+	while (t2) {
+	  if (t2->ai_family == AF_INET)
+	    ((struct sockaddr_in*)(t2->ai_addr))->sin_port = portval;
+	  else if (t2->ai_family == AF_INET6)
+	    ((struct sockaddr_in6*)(t2->ai_addr))->sin6_port = portval;
+
+	  t2 = t2->ai_next;
+	}
+      }
+
+      tmp = tmp->ai_next;
+    }
+  freeaddrinfo(ai);
 
-  if (!_dbus_set_fd_nonblocking (listen_fd, error))
+  for (i = 0 ; i < nlisten_fd ; i++)
     {
-      _dbus_close (listen_fd, NULL);
-      return -1;
+      if (!_dbus_set_fd_nonblocking (retfd[i], error))
+	{
+	  int j;
+	  for (j = 0 ; j < nlisten_fd ; j++)
+	    _dbus_close(retfd[j], NULL);
+	  return -1;
+	}
     }
-  
-  return listen_fd;
+
+  return nlisten_fd;
 }
 
 static dbus_bool_t
@@ -1072,7 +1159,7 @@ _dbus_read_credentials_socket  (int     
 #ifdef SO_PEERCRED
     struct ucred cr;   
     int cr_len = sizeof (cr);
-   
+    
     if (getsockopt (client_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 &&
 	cr_len == sizeof (cr))
       {
Index: dbus/dbus-sysdeps.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-sysdeps.h,v
retrieving revision 1.76
diff -u -p -r1.76 dbus-sysdeps.h
--- dbus/dbus-sysdeps.h	13 Jun 2007 20:52:58 -0000	1.76
+++ dbus/dbus-sysdeps.h	14 Jun 2007 04:04:12 -0000
@@ -147,11 +147,14 @@ int         _dbus_write_socket_two (int 
                                     int               start2,
                                     int               len2);
 int _dbus_connect_tcp_socket  (const char     *host,
-                               dbus_uint32_t   port,
+                               const char     *port,
                                DBusError      *error);
 int _dbus_listen_tcp_socket   (const char     *host,
-                               dbus_uint32_t  *port,
-                               dbus_bool_t     inaddr_any,
+                               const char     *port,
+			       char           *retport,
+			       dbus_uint32_t   retportlen,
+			       int            *retfd,
+			       int            nretfd,
                                DBusError      *error);
 int _dbus_accept              (int             listen_fd);
 
Index: dbus/dbus-transport-socket.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-transport-socket.c,v
retrieving revision 1.5
diff -u -p -r1.5 dbus-transport-socket.c
--- dbus/dbus-transport-socket.c	9 Jun 2007 21:53:20 -0000	1.5
+++ dbus/dbus-transport-socket.c	14 Jun 2007 04:04:12 -0000
@@ -1210,7 +1210,7 @@ _dbus_transport_new_for_socket (int     
  */
 DBusTransport*
 _dbus_transport_new_for_tcp_socket (const char     *host,
-                                    dbus_int32_t    port,
+                                    const char     *port,
                                     DBusError      *error)
 {
   int fd;
@@ -1234,7 +1234,7 @@ _dbus_transport_new_for_tcp_socket (cons
     goto error;
 
   if (!_dbus_string_append (&address, ",port=") ||
-      !_dbus_string_append_int (&address, port))
+      !_dbus_string_append (&address, port))
     goto error;
 
   fd = _dbus_connect_tcp_socket (host, port, error);
@@ -1247,7 +1247,7 @@ _dbus_transport_new_for_tcp_socket (cons
 
   _dbus_fd_set_close_on_exec (fd);
   
-  _dbus_verbose ("Successfully connected to tcp socket %s:%d\n",
+  _dbus_verbose ("Successfully connected to tcp socket %s:%s\n",
                  host, port);
   
   transport = _dbus_transport_new_for_socket (fd, NULL, &address);
@@ -1291,28 +1291,14 @@ _dbus_transport_open_socket(DBusAddressE
     {
       const char *host = dbus_address_entry_get_value (entry, "host");
       const char *port = dbus_address_entry_get_value (entry, "port");
-      DBusString  str;
-      long lport;
-      dbus_bool_t sresult;
-          
+
       if (port == NULL)
         {
           _dbus_set_bad_address (error, "tcp", "port", NULL);
           return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
         }
 
-      _dbus_string_init_const (&str, port);
-      sresult = _dbus_string_parse_int (&str, 0, &lport, NULL);
-      _dbus_string_free (&str);
-          
-      if (sresult == FALSE || lport <= 0 || lport > 65535)
-        {
-          _dbus_set_bad_address (error, NULL, NULL,
-                                 "Port is not an integer between 0 and 65535");
-          return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
-        }
-          
-      *transport_p = _dbus_transport_new_for_tcp_socket (host, lport, error);
+      *transport_p = _dbus_transport_new_for_tcp_socket (host, port, error);
       if (*transport_p == NULL)
         {
           _DBUS_ASSERT_ERROR_IS_SET (error);
Index: dbus/dbus-transport-socket.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-transport-socket.h,v
retrieving revision 1.2
diff -u -p -r1.2 dbus-transport-socket.h
--- dbus/dbus-transport-socket.h	16 Sep 2006 19:24:08 -0000	1.2
+++ dbus/dbus-transport-socket.h	14 Jun 2007 04:04:12 -0000
@@ -31,7 +31,7 @@ DBusTransport*          _dbus_transport_
                                                             const DBusString  *server_guid,
                                                             const DBusString  *address);
 DBusTransport*          _dbus_transport_new_for_tcp_socket (const char        *host,
-                                                            dbus_int32_t       port,
+                                                            const char        *port,
                                                             DBusError         *error);
 DBusTransportOpenResult _dbus_transport_open_socket        (DBusAddressEntry  *entry,
                                                             DBusTransport    **transport_p,
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
Url : http://lists.freedesktop.org/archives/dbus/attachments/20070613/24ef5d69/attachment-0001.pgp 


More information about the dbus mailing list