From ee71e1ff6033ad1eb2385f11d4f3678259b8397b Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 25 Jul 2007 02:46:52 +0000 Subject: Switch over to using getaddrinfo for TCP clients & servers to enable IPv6 --- dbus/dbus-address.c | 2 +- dbus/dbus-server-socket.c | 287 ++++++++++++++++++++++++----------------- dbus/dbus-server-socket.h | 8 +- dbus/dbus-server-unix.c | 2 +- dbus/dbus-sysdeps-unix.c | 301 ++++++++++++++++++++++++++++++------------- dbus/dbus-sysdeps.h | 9 +- dbus/dbus-transport-socket.c | 45 +++---- dbus/dbus-transport-socket.h | 3 +- 8 files changed, 420 insertions(+), 237 deletions(-) (limited to 'dbus') 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, -- cgit