diff options
Diffstat (limited to 'dbus')
| -rw-r--r-- | dbus/dbus-address.c | 2 | ||||
| -rw-r--r-- | dbus/dbus-server-socket.c | 287 | ||||
| -rw-r--r-- | dbus/dbus-server-socket.h | 8 | ||||
| -rw-r--r-- | dbus/dbus-server-unix.c | 2 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps-unix.c | 301 | ||||
| -rw-r--r-- | dbus/dbus-sysdeps.h | 9 | ||||
| -rw-r--r-- | dbus/dbus-transport-socket.c | 45 | ||||
| -rw-r--r-- | dbus/dbus-transport-socket.h | 3 | 
8 files changed, 420 insertions, 237 deletions
diff --git a/dbus/dbus-address.c b/dbus/dbus-address.c index 97f8882f..0b87b8e6 100644 --- a/dbus/dbus-address.c +++ b/dbus/dbus-address.c @@ -89,6 +89,7 @@ _dbus_set_bad_address (DBusError  *error,            (b) == '_' ||                                 \            (b) == '/' ||                                 \            (b) == '\\' ||                                \ +          (b) == '*' ||                                \            (b) == '.')  /** @@ -691,7 +692,6 @@ static const char* invalid_escaped_values[] = {    "%",    "$",    " ", -  "*"  };  dbus_bool_t diff --git a/dbus/dbus-server-socket.c b/dbus/dbus-server-socket.c index c414bd1c..c8ae38a7 100644 --- a/dbus/dbus-server-socket.c +++ b/dbus/dbus-server-socket.c @@ -47,8 +47,9 @@ typedef struct DBusServerSocket DBusServerSocket;  struct DBusServerSocket  {    DBusServer base;   /**< Parent class members. */ -  int fd;            /**< File descriptor or -1 if disconnected. */ -  DBusWatch *watch;  /**< File descriptor watch. */ +  int n_fds;         /**< Number of active file handles */ +  int *fds;          /**< File descriptor or -1 if disconnected. */ +  DBusWatch **watch; /**< File descriptor watch. */    char *socket_name; /**< Name of domain socket, to unlink if appropriate */  }; @@ -56,15 +57,19 @@ 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->n_fds ; i++) +    if (socket_server->watch[i]) +      { +        _dbus_watch_unref (socket_server->watch[i]); +        socket_server->watch[i] = NULL; +      } +  dbus_free (socket_server->fds); +  dbus_free (socket_server->watch);    dbus_free (socket_server->socket_name);    dbus_free (server);  } @@ -149,10 +154,21 @@ socket_handle_watch (DBusWatch    *watch,  {    DBusServer *server = data;    DBusServerSocket *socket_server = data; +#ifndef DBUS_DISABLE_ASSERT +  int i; +  dbus_bool_t found = FALSE; +#endif    SERVER_LOCK (server); -  _dbus_assert (watch == socket_server->watch); +#ifndef DBUS_DISABLE_ASSERT +  for (i = 0 ; i < socket_server->n_fds ; i++) +    { +      if (socket_server->watch[i] == watch) +        found = TRUE; +    } +  _dbus_assert (found); +#endif    _dbus_verbose ("Handling client connection, flags 0x%x\n", flags); @@ -199,19 +215,23 @@ static void  socket_disconnect (DBusServer *server)  {    DBusServerSocket *socket_server = (DBusServerSocket*) server; +  int i;    HAVE_LOCK_CHECK (server); -  if (socket_server->watch) +  for (i = 0 ; i < socket_server->n_fds ; i++)      { -      _dbus_server_remove_watch (server, -                                 socket_server->watch); -      _dbus_watch_unref (socket_server->watch); -      socket_server->watch = NULL; +      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->fds[i], NULL); +      socket_server->fds[i] = -1;      } -   -  _dbus_close_socket (socket_server->fd, NULL); -  socket_server->fd = -1;    if (socket_server->socket_name != NULL)      { @@ -236,89 +256,128 @@ static const DBusServerVTable socket_vtable = {   * been successfully invoked on it. The server will use accept() to   * accept new client connections.   * - * @param fd the file descriptor. + * @param fds list of file descriptors. + * @param n_fds 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              *fds, +                             int               n_fds,                               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) + +  socket_server->fds = dbus_new (int, n_fds); +  if (!socket_server->fds) +    goto failed_0; + +  socket_server->watch = dbus_new0 (DBusWatch *, n_fds); +  if (!socket_server->watch) +    goto failed_1; + +  for (i = 0 ; i < n_fds ; i++)      { -      dbus_free (socket_server); -      return NULL; +      DBusWatch *watch; + +      watch = _dbus_watch_new (fds[i], +                               DBUS_WATCH_READABLE, +                               TRUE, +                               socket_handle_watch, socket_server, +                               NULL); +      if (watch == NULL) +        goto failed_2; + +      socket_server->n_fds++; +      socket_server->fds[i] = fds[i]; +      socket_server->watch[i] = watch;      } -   +    if (!_dbus_server_init_base (&socket_server->base,                                 &socket_vtable, address)) -    { -      _dbus_watch_unref (watch); -      dbus_free (socket_server); -      return NULL; -    } +    goto failed_2; -  server = (DBusServer*) socket_server; +  server = (DBusServer*)socket_server;    SERVER_LOCK (server); -  if (!_dbus_server_add_watch (&socket_server->base, -                               watch)) +  for (i = 0 ; i < n_fds ; i++)      { -      SERVER_UNLOCK (server); -      _dbus_server_finalize_base (&socket_server->base); -      _dbus_watch_unref (watch); -      dbus_free (socket_server); -      return NULL; +      if (!_dbus_server_add_watch (&socket_server->base, +                                   socket_server->watch[i])) +        { +          int j; +          for (j = 0 ; j < i ; j++) +            _dbus_server_remove_watch (server, +                                       socket_server->watch[j]); + +          SERVER_UNLOCK (server); +          _dbus_server_finalize_base (&socket_server->base); +          goto failed_2; +        }      } -   -  socket_server->fd = fd; -  socket_server->watch = watch;    SERVER_UNLOCK (server);    return (DBusServer*) socket_server; + + failed_2: +  for (i = 0 ; i < n_fds ; i++) +    { +      if (socket_server->watch[i] != NULL) +        { +          _dbus_watch_unref (socket_server->watch[i]); +          socket_server->watch[i] = NULL; +        } +    } +  dbus_free (socket_server->watch); + + failed_1: +  dbus_free (socket_server->fds); + + failed_0: +  dbus_free (socket_server); +  return NULL;  }  /**   * Creates a new server listening on TCP. - * If inaddr_any is TRUE, 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. + * If host is NULL, it will default to localhost. + * If bind is NULL, it will default to the value for the host + * parameter, and if that is NULL, then localhost + * If bind is a hostname, it will be resolved and will listen + * on all returned addresses. + * If family is NULL, hostname resolution will try all address + * families, otherwise it can be ipv4 or ipv6 to restrict the + * addresses considered.   * - * @param host the hostname to listen on. + * @param host the hostname to report for the listen address + * @param bind 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 family    * @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     *bind, +                                 const char     *port, +                                 const char     *family,                                   DBusError      *error)  {    DBusServer *server; -  int listen_fd; +  int *listen_fds = NULL; +  int nlisten_fds = 0, i;    DBusString address;    DBusString host_str; +  DBusString port_str;    _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -328,44 +387,77 @@ _dbus_server_new_for_tcp_socket (const char     *host,        return NULL;      } +  if (!_dbus_string_init (&port_str)) +    { +      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); +      goto failed_0; +    } +    if (host == NULL)      host = "localhost"; -   -  listen_fd = _dbus_listen_tcp_socket (host, &port, inaddr_any, error); -  _dbus_fd_set_close_on_exec (listen_fd); + +  if (port == NULL) +    port = "0"; + +  if (bind == NULL) +    bind = host; +  else if (strcmp (bind, "*") == 0) +    bind = NULL; + +  nlisten_fds =_dbus_listen_tcp_socket (bind, port, family, +                                        &port_str, +                                        &listen_fds, error); +  if (nlisten_fds <= 0) +    { +      _DBUS_ASSERT_ERROR_IS_SET(error); +      goto failed_1; +    } + +  for (i = 0 ; i < nlisten_fds ; i++) +    _dbus_fd_set_close_on_exec (listen_fds[i]);    _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_append (&address, _dbus_string_get_const_data(&port_str)))      { -      _dbus_string_free (&address);        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); -      return NULL; +      goto failed_2;      } - -   -  if (listen_fd < 0) +  if (family && +      (!_dbus_string_append (&address, ",family=") || +       !_dbus_string_append (&address, family)))      { -      _dbus_string_free (&address); -      return NULL; +      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); +      goto failed_2;      } -  server = _dbus_server_new_for_socket (listen_fd, &address); +  server = _dbus_server_new_for_socket (listen_fds, nlisten_fds, &address);    if (server == NULL)      {        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); -      _dbus_close_socket (listen_fd, NULL); -      _dbus_string_free (&address); -      return NULL; +      goto failed_2;      } +  _dbus_string_free (&port_str);    _dbus_string_free (&address); -   +  dbus_free(listen_fds); +    return server; + failed_2: +  for (i = 0 ; i < nlisten_fds ; i++) +    _dbus_close_socket (listen_fds[i], NULL); +  dbus_free(listen_fds); + + failed_1: +  _dbus_string_free (&port_str); + + failed_0: +  _dbus_string_free (&address); +  return NULL;  }  /** @@ -395,55 +487,16 @@ _dbus_server_listen_socket (DBusAddressEntry *entry,      {        const char *host;        const char *port; -      const char *all_interfaces; -      dbus_bool_t inaddr_any; -      long lport; +      const char *bind; +      const char *family;        host = dbus_address_entry_get_value (entry, "host"); +      bind = dbus_address_entry_get_value (entry, "bind");        port = dbus_address_entry_get_value (entry, "port"); -      all_interfaces = dbus_address_entry_get_value (entry, "all_interfaces"); +      family = dbus_address_entry_get_value (entry, "family"); -      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; -            } -        } -           -      *server_p = _dbus_server_new_for_tcp_socket (host, lport, inaddr_any, error); +      *server_p = _dbus_server_new_for_tcp_socket (host, bind, port, +                                                   family, error);        if (*server_p)          { diff --git a/dbus/dbus-server-socket.h b/dbus/dbus-server-socket.h index 2023220b..34900b43 100644 --- a/dbus/dbus-server-socket.h +++ b/dbus/dbus-server-socket.h @@ -28,11 +28,13 @@  DBUS_BEGIN_DECLS -DBusServer* _dbus_server_new_for_socket           (int               fd, +DBusServer* _dbus_server_new_for_socket           (int              *fds, +                                                   int               n_fds,                                                     const DBusString *address);  DBusServer* _dbus_server_new_for_tcp_socket       (const char       *host, -                                                   dbus_uint32_t     port, -                                                   dbus_bool_t       inaddr_any, +                                                   const char       *bind, +                                                   const char       *port, +                                                   const char       *family,                                                     DBusError        *error);  DBusServerListenResult _dbus_server_listen_socket (DBusAddressEntry  *entry,                                                     DBusServer       **server_p, diff --git a/dbus/dbus-server-unix.c b/dbus/dbus-server-unix.c index d765bee3..1dda5d19 100644 --- a/dbus/dbus-server-unix.c +++ b/dbus/dbus-server-unix.c @@ -209,7 +209,7 @@ _dbus_server_new_for_domain_socket (const char     *path,        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); diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c index 2ea83df2..0ab5e730 100644 --- a/dbus/dbus-sysdeps-unix.c +++ b/dbus/dbus-sysdeps-unix.c @@ -737,65 +737,94 @@ _dbus_listen_unix_socket (const char     *path,   * nonblocking.   *   * @param host the host name to connect to - * @param port the prot to connect to + * @param port the port to connect to + * @param family the address family to listen on, NULL for all   * @param error return location for error code   * @returns connection file descriptor or -1 on error   */  int  _dbus_connect_tcp_socket (const char     *host, -                          dbus_uint32_t   port, +                          const char     *port, +                          const char     *family,                            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); -  -   +    if (!_dbus_open_tcp_socket (&fd, error))      {        _DBUS_ASSERT_ERROR_IS_SET(error); -              return -1;      } +    _DBUS_ASSERT_ERROR_IS_CLEAR(error); -       -  if (host == NULL) -    host = "localhost"; -  he = gethostbyname (host); -  if (he == NULL)  +  _DBUS_ZERO (hints); + +  if (!family) +    hints.ai_family = AF_UNSPEC; +  else if (!strcmp(family, "ipv4")) +    hints.ai_family = AF_INET; +  else if (!strcmp(family, "ipv6")) +    hints.ai_family = AF_INET6; +  else      {        dbus_set_error (error,                        _dbus_error_from_errno (errno), -                      "Failed to lookup hostname: %s", -                      host); -      _dbus_close (fd, NULL); +                      "Unknown address family %s", family);        return -1;      } -   -  haddr = ((struct in_addr *) (he->h_addr_list)[0]); +  fprintf(stderr, "Family %s\n", family ? family : "none"); +  hints.ai_protocol = IPPROTO_TCP; +  hints.ai_socktype = SOCK_STREAM; +  hints.ai_flags = AI_ADDRCONFIG; -  _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) -    {       +  if ((res = getaddrinfo(host, port, &hints, &ai)) != 0) +    {        dbus_set_error (error, -                       _dbus_error_from_errno (errno), -                      "Failed to connect to socket %s:%d %s", -                      host, port, _dbus_strerror (errno)); - +                      _dbus_error_from_errno (errno), +                      "Failed to lookup host/port: \"%s:%s\": %s (%d)", +                      host, port, gai_strerror(res), res);        _dbus_close (fd, NULL); -      fd = -1; -              return -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:%s\" %s", +                      host, port, _dbus_strerror(errno)); +      return -1; +    } + +    if (!_dbus_set_fd_nonblocking (fd, error))      {        _dbus_close (fd, NULL); @@ -814,88 +843,186 @@ _dbus_connect_tcp_socket (const char     *host,   * If inaddr_any is specified, the hostname is ignored.   *   * @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 port the port to listen on, if zero a free port will be used + * @param family the address family to listen on, NULL for all + * @param retport string to return the actual port listened on + * @param fds_p location to store returned 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, +                         const char     *family, +                         DBusString     *retport, +                         int           **fds_p,                           DBusError      *error)  { -  int listen_fd; -  struct sockaddr_in addr; -  socklen_t len = (socklen_t) sizeof (struct sockaddr); +  int nlisten_fd = 0, *listen_fd = NULL, res, i; +  struct addrinfo hints; +  struct addrinfo *ai, *tmp; -  _DBUS_ASSERT_ERROR_IS_CLEAR (error);   -   -  if (!_dbus_open_tcp_socket (&listen_fd, error)) +  *fds_p = NULL; +  _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +  _DBUS_ZERO (hints); + +  if (!family) +    hints.ai_family = AF_UNSPEC; +  else if (!strcmp(family, "ipv4")) +    hints.ai_family = AF_INET; +  else if (!strcmp(family, "ipv6")) +    hints.ai_family = AF_INET6; +  else      { -      _DBUS_ASSERT_ERROR_IS_SET(error); +      dbus_set_error (error, +                      _dbus_error_from_errno (errno), +                      "Unknown address family %s", family);        return -1;      } -  _DBUS_ASSERT_ERROR_IS_CLEAR(error); -  _DBUS_ZERO (addr); -   -  if (inaddr_any) +  hints.ai_protocol = IPPROTO_TCP; +  hints.ai_socktype = SOCK_STREAM; +  hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE; + + redo_lookup_with_port: +  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 ? host : "*", port, gai_strerror(res), res); +      return -1;      } -  else + +  tmp = ai; +  while (tmp)      { -      struct hostent *he; -      struct in_addr *haddr;       +      int fd = -1, *newlisten_fd; +      if (!_dbus_open_socket (&fd, tmp->ai_family, SOCK_STREAM, 0, error)) +        { +          _DBUS_ASSERT_ERROR_IS_SET(error); +          goto failed; +        } +      _DBUS_ASSERT_ERROR_IS_CLEAR(error); -      he = gethostbyname (host); -      if (he == NULL)  +      if (bind (fd, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) < 0)          { -          dbus_set_error (error, -                          _dbus_error_from_errno (errno), -                          "Failed to lookup hostname: %s", -                          host); -          _dbus_close (listen_fd, NULL); -          return -1; +          _dbus_close(fd, NULL); +          if (errno == EADDRINUSE) +            { +              /* Depending on kernel policy, it may or may not +                 be neccessary to bind to both IPv4 & 6 addresses +                 so ignore EADDRINUSE here */ +              tmp = tmp->ai_next; +              continue; +            } +          dbus_set_error (error, _dbus_error_from_errno (errno), +                          "Failed to bind socket \"%s:%s\": %s", +                          host ? host : "*", port, _dbus_strerror (errno)); +          goto failed;          } -   -      haddr = ((struct in_addr *) (he->h_addr_list)[0]); -       -      memcpy (&addr.sin_addr, haddr, sizeof (struct in_addr)); + +      if (listen (fd, 30 /* backlog */) < 0) +        { +          _dbus_close (fd, NULL); +          dbus_set_error (error, _dbus_error_from_errno (errno), +                          "Failed to listen on socket \"%s:%s\": %s", +                          host ? host : "*", port, _dbus_strerror (errno)); +          goto failed; +        } + +      newlisten_fd = dbus_realloc(listen_fd, sizeof(int)*(nlisten_fd+1)); +      if (!newlisten_fd) +        { +          _dbus_close (fd, NULL); +          dbus_set_error (error, _dbus_error_from_errno (errno), +                          "Failed to allocate file handle array: %s", +                          _dbus_strerror (errno)); +          goto failed; +        } +      listen_fd = newlisten_fd; +      listen_fd[nlisten_fd] = fd; +      nlisten_fd++; + +      if (!_dbus_string_get_length(retport)) +        { +          /* If the user didn't specify a port, or used 0, then +             the kernel chooses a port. After the first address +             is bound to, we need to force all remaining addresses +             to use the same port */ +          if (!port || !strcmp(port, "0")) +            { +              struct sockaddr_storage addr; +              socklen_t addrlen; +              char portbuf[50]; + +              addrlen = sizeof(addr); +              getsockname(fd, (struct sockaddr*) &addr, &addrlen); + +              if ((res = getnameinfo((struct sockaddr*)&addr, addrlen, NULL, 0, +                                     portbuf, sizeof(portbuf), +                                     NI_NUMERICHOST)) != 0) +                { +                  dbus_set_error (error, _dbus_error_from_errno (errno), +                                  "Failed to resolve port \"%s:%s\": %s (%s)", +                                  host ? host : "*", port, gai_strerror(res), res); +                  goto failed; +                } +              if (!_dbus_string_append(retport, portbuf)) +                { +                  dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); +                  goto failed; +                } + +              /* Release current address list & redo lookup */ +              port = _dbus_string_get_const_data(retport); +              freeaddrinfo(ai); +              goto redo_lookup_with_port; +            } +          else +            { +              if (!_dbus_string_append(retport, port)) +                { +                    dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); +                    goto failed; +                } +            } +        } + +      tmp = tmp->ai_next;      } -   -  addr.sin_family = AF_INET; -  addr.sin_port = htons (*port); +  freeaddrinfo(ai); +  ai = NULL; -  if (bind (listen_fd, (struct sockaddr*) &addr, sizeof (struct sockaddr))) +  if (!nlisten_fd)      { +      errno = EADDRINUSE;        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); +                      "Failed to bind socket \"%s:%s\": %s", +                      host ? host : "*", port, _dbus_strerror (errno));        return -1;      } -  if (listen (listen_fd, 30 /* backlog */) < 0) +  for (i = 0 ; i < nlisten_fd ; i++)      { -      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; +      if (!_dbus_set_fd_nonblocking (listen_fd[i], error)) +        { +          goto failed; +        }      } -  getsockname(listen_fd, (struct sockaddr*) &addr, &len); -  *port = (dbus_uint32_t) ntohs(addr.sin_port); +  *fds_p = listen_fd; -  if (!_dbus_set_fd_nonblocking (listen_fd, error)) -    { -      _dbus_close (listen_fd, NULL); -      return -1; -    } -   -  return listen_fd; +  return nlisten_fd; + + failed: +  if (ai) +    freeaddrinfo(ai); +  for (i = 0 ; i < nlisten_fd ; i++) +    _dbus_close(listen_fd[i], NULL); +  dbus_free(listen_fd); +  return -1;  }  static dbus_bool_t @@ -1089,7 +1216,7 @@ _dbus_read_credentials_socket  (int              client_fd,  #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))        { diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index ab0119ab..ab1631b8 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -144,11 +144,14 @@ int         _dbus_write_socket_two (int               fd,                                      int               start2,                                      int               len2);  int _dbus_connect_tcp_socket  (const char     *host, -                               dbus_uint32_t   port, +                               const char     *port, +                               const char     *family,                                 DBusError      *error);  int _dbus_listen_tcp_socket   (const char     *host, -                               dbus_uint32_t  *port, -                               dbus_bool_t     inaddr_any, +                               const char     *port, +                               const char     *family, +                               DBusString     *retport, +                               int           **fds_p,                                 DBusError      *error);  int _dbus_accept              (int             listen_fd); diff --git a/dbus/dbus-transport-socket.c b/dbus/dbus-transport-socket.c index 8ec69d8d..a31c1597 100644 --- a/dbus/dbus-transport-socket.c +++ b/dbus/dbus-transport-socket.c @@ -1204,15 +1204,18 @@ _dbus_transport_new_for_socket (int               fd,  /**   * Creates a new transport for the given hostname and port. + * If host is NULL, it will default to localhost   *   * @param host the host to connect to   * @param port the port to connect to + * @param family the address family to connect to   * @param error location to store reason for failure.   * @returns a new transport, or #NULL on failure.   */  DBusTransport*  _dbus_transport_new_for_tcp_socket (const char     *host, -                                    dbus_int32_t    port, +                                    const char     *port, +                                    const char     *family,                                      DBusError      *error)  {    int fd; @@ -1226,20 +1229,27 @@ _dbus_transport_new_for_tcp_socket (const char     *host,        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);        return NULL;      } -   + +  if (host == NULL) +    host = "localhost"; +    if (!_dbus_string_append (&address, "tcp:"))      goto error; -  if (host != NULL &&  -       (!_dbus_string_append (&address, "host=") || -        !_dbus_string_append (&address, host))) +  if (!_dbus_string_append (&address, "host=") || +      !_dbus_string_append (&address, host))      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); +  if (family != NULL && +      (!_dbus_string_append (&address, "family=") || +       !_dbus_string_append (&address, family))) +    goto error; + +  fd = _dbus_connect_tcp_socket (host, port, family, error);    if (fd < 0)      {        _DBUS_ASSERT_ERROR_IS_SET (error); @@ -1249,7 +1259,7 @@ _dbus_transport_new_for_tcp_socket (const char     *host,    _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); @@ -1293,28 +1303,15 @@ _dbus_transport_open_socket(DBusAddressEntry  *entry,      {        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; -           +      const char *family = dbus_address_entry_get_value (entry, "family"); +        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, family, error);        if (*transport_p == NULL)          {            _DBUS_ASSERT_ERROR_IS_SET (error); diff --git a/dbus/dbus-transport-socket.h b/dbus/dbus-transport-socket.h index 8cfc543c..8a00ab58 100644 --- a/dbus/dbus-transport-socket.h +++ b/dbus/dbus-transport-socket.h @@ -31,7 +31,8 @@ DBusTransport*          _dbus_transport_new_for_socket     (int                f                                                              const DBusString  *server_guid,                                                              const DBusString  *address);  DBusTransport*          _dbus_transport_new_for_tcp_socket (const char        *host, -                                                            dbus_int32_t       port, +                                                            const char        *port, +                                                            const char        *family,                                                              DBusError         *error);  DBusTransportOpenResult _dbus_transport_open_socket        (DBusAddressEntry  *entry,                                                              DBusTransport    **transport_p,  | 
