default tcp host
Daniel P. Berrange
dan at berrange.com
Wed Jun 20 02:10:30 PDT 2007
On Fri, Jun 15, 2007 at 12:40:06PM -0400, Havoc Pennington wrote:
> >Another option is to have a separate some separate XML element where you
> >detail what hostnames to advertise <advertise>foo.example.com</advertise>
> >if no explicit host is provided (the INADDR_ANY case).
> >
> >Or perhaps add an extra field to the <listen> tag listing hostnames
> >that should be used after binding. eg. So some example <listen> tags
> >and the corresponding output by --print-address
>
> Something along the lines of your suggestions here is probably right. I
> think the default bind should probably be INADDR_ANY and the default
> advertise should probably be localhost, with both possible to override
> separately.
>
> There is some back compat concern though, and right now the address
> format is screwy where host is overloaded to be both the bind and the
> advertise.
>
> We could introduce bind= and advertise= for the server listen address,
> and if they are missing each is taken from the host= instead; and client
> connect addresses still use host=
>
> If we do that though, if you just say "host=localhost" or omit the host
> (which currently means "host=localhost") then it will bind only to
> localhost, not INADDR_ANY. So we need a syntax other than omitting bind=
> to mean INADDR_ANY, perhaps bind=* or bind=any or something.
Attaching an updated version of my patch which adds support for an
explicit 'bind=' option. For back-compatability, if 'bind' is omimtted
it will take the value of the 'host=' option, and if that's omitted
both default to localhost. I also added support for bind=* to indicate
all addresses - I also made '*' a valid character for address strings
so users don't need to hex-escape it. I also add support for an optional
family=ipv4 or family=ipv6 option to restrict which addresses are used
in a multi-protocol environment.
The following data outlines the various combinations I'm in the process
of testing. The first value is the config file setting, the second
is what --print-address displays, and the 3rd is what is actually
bound to. I'm going to see if can find a way to automate some testing
of this.
# Binding to various forms of localhost
<listen>tcp:</listen>
tcp:host=localhost,port=NNNN
127.0.0.1 at NNNN, ::1 at NNNN
<listen>tcp:host=localhost</listen>
tcp:host=localhost,port=NNNN
127.0.0.1 at NNNN, ::1 at NNNN
<listen>tcp:host=localhost,family=ipv4</listen>
tcp:host=localhost,port=NNNN,family=ipv4
127.0.0.1 at NNNN
<listen>tcp:host=localhost,family=ipv6</listen>
tcp:host=localhost,port=NNNN,family=ipv6
::1 at NNNN
<listen>tcp:host=127.0.0.1</listen>
tcp:host=127.0.0.1,port=NNNN
127.0.0.1 at NNNN
<listen>tcp:host=%3e%3e1</listen>
tcp:host=%3e%3e1
::1 at NNNN
# Binding to all addresses, reporting localhost
<listen>tcp:host=localhost,bind=*</listen>
tcp:host=localhost,port=NNNN
::@NNNN (if bindv6only=0)
0.0.0.0 at NNNN, ::@NNNN (if bindv6only=1)
<listen>tcp:host=localhost,bind=*,family=ipv4</listen>
tcp:host=localhost,port=NNNN,family=ipv4
0.0.0.0 at NNNN
<listen>tcp:host=localhost,bind=*,family=ipv6</listen>
tcp:host=localhost,port=NNNN,family=ipv6
::@NNNN
<listen>tcp:host=localhost,bind=0.0.0.0</listen>
tcp:host=localhost,port=NNNN
0.0.0.0 at NNNN
<listen>tcp:host=localhost,bind=%3e%3e</listen>
tcp:host=localhost,port=NNNN
::@NNNN
# Binding to a hostname, but reporting localhost
<listen>tcp:host=localhost,bind=server.example.com</listen>
tcp:host=localhost,port=NNNN
192.168.254.138 at NNNN, fec0::9:ef:5678:abcd:1234 at NNNN
<listen>tcp:host=localhost,bind=server.example.com,family=ipv4</listen>
tcp:host=localhost,port=NNNN,family=ipv4
192.168.254.138 at NNNN
<listen>tcp:host=localhost,bind=server.example.com,family=ipv6</listen>
tcp:host=localhost,port=NNNN,family=ipv6
fec0::9:ef:5678:abcd:1234 at NNNN
..same again with explicit ports...
# Binding to various forms of localhost
<listen>tcp:port=9999</listen>
tcp:host=localhost,port=9999
127.0.0.1 at 9999, ::1 at 9999
<listen>tcp:host=localhost,port=9999</listen>
tcp:host=localhost,port=9999
127.0.0.1 at 9999, ::1 at 9999
<listen>tcp:host=localhost,family=ipv4,port=9999</listen>
tcp:host=localhost,port=9999,family=ipv4
127.0.0.1 at 9999
<listen>tcp:host=localhost,family=ipv6,port=9999</listen>
tcp:host=localhost,port=9999,family=ipv6
::1 at 9999
<listen>tcp:host=127.0.0.1,port=9999</listen>
tcp:host=127.0.0.1,port=9999
127.0.0.1 at 9999
<listen>tcp:host=%3e%3e1,port=9999</listen>
tcp:host=%3e%3e1,port=9999
::1 at 9999
# Binding to all addresses, reporting localhost
<listen>tcp:host=localhost,bind=*,port=9999</listen>
tcp:host=localhost,port=9999
::@9999 (if bindv6only=0)
0.0.0.0 at 9999, ::@9999 (if bindv6only=1)
<listen>tcp:host=localhost,bind=*,family=ipv4,port=9999</listen>
tcp:host=localhost,port=9999,family=ipv4
0.0.0.0 at 9999
<listen>tcp:host=localhost,bind=*,family=ipv6,port=9999</listen>
tcp:host=localhost,port=9999,family=ipv6
::@9999
<listen>tcp:host=localhost,bind=0.0.0.0,port=9999</listen>
tcp:host=localhost,port=9999
0.0.0.0 at 9999
<listen>tcp:host=localhost,bind=%3e%3e,port=9999</listen>
tcp:host=localhost,port=9999
::@9999
# Binding to a hostname, but reporting localhost
<listen>tcp:host=localhost,bind=server.example.com,port=9999</listen>
tcp:host=localhost,port=9999
192.168.254.138 at 9999, fec0::9:ef:5678:abcd:1234 at 9999
<listen>tcp:host=localhost,bind=server.example.com,family=ipv4,port=9999</listen>
tcp:host=localhost,port=9999,family=ipv4
192.168.254.138 at 9999
<listen>tcp:host=localhost,bind=server.example.com,family=ipv6,port=9999</listen>
tcp:host=localhost,port=9999,family=ipv6
fec0::9:ef:5678:abcd:1234 at 9999
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-address.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-address.c,v
retrieving revision 1.24
diff -u -p -r1.24 dbus-address.c
--- dbus/dbus-address.c 3 Apr 2007 18:53:25 -0000 1.24
+++ dbus/dbus-address.c 20 Jun 2007 14:35:51 -0000
@@ -89,6 +89,7 @@ _dbus_set_bad_address (DBusError *error
(b) == '_' || \
(b) == '/' || \
(b) == '\\' || \
+ (b) == '*' || \
(b) == '.')
/**
Index: dbus/dbus-server-socket.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-server-socket.c,v
retrieving revision 1.7
diff -u -p -r1.7 dbus-server-socket.c
--- dbus/dbus-server-socket.c 18 Jun 2007 16:24:03 -0000 1.7
+++ dbus/dbus-server-socket.c 20 Jun 2007 14:35:51 -0000
@@ -44,26 +44,38 @@ typedef struct DBusServerSocket DBusServ
* Implementation details of DBusServerSocket. All members
* are private.
*/
+
+/*
+ * getaddrinfo can return many addresses per hostname
+ * looked up, and we must listen on all of them. Even
+ * with IPv4 & IPv6 dual stack & multiple NICs, this
+ * ought to be enough sockets.
+ */
+#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 +161,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 +217,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->nfd ; 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->fd[i], NULL);
+ socket_server->fd[i] = -1;
}
-
- _dbus_close_socket (socket_server->fd, NULL);
- socket_server->fd = -1;
if (socket_server->socket_name != NULL)
{
@@ -236,58 +258,98 @@ 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)
+
+ for (i = 0 ; i < nfd ; i++)
{
- dbus_free (socket_server);
- return NULL;
+ 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_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_watch_unref (socket_server->watch[i]);
+ socket_server->watch[i] = NULL;
+ }
+ }
dbus_free (socket_server);
return NULL;
}
- server = (DBusServer*) socket_server;
+
+ server = (DBusServer *)socket_server;
SERVER_LOCK (server);
- if (!_dbus_server_add_watch (&socket_server->base,
- watch))
+ for (i = 0 ; i < nfd ; 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 < nfd ; j++)
+ {
+ if (socket_server->watch[j] != NULL)
+ {
+ if (j < i)
+ _dbus_server_remove_watch (server,
+ socket_server->watch[j]);
+ _dbus_watch_unref (socket_server->watch[j]);
+ socket_server->watch[j] = NULL;
+ }
+ }
+
+ SERVER_UNLOCK (server);
+ _dbus_server_finalize_base (&socket_server->base);
+ dbus_free (socket_server);
+ return NULL;
+ }
}
-
- socket_server->fd = fd;
- socket_server->watch = watch;
SERVER_UNLOCK (server);
@@ -296,29 +358,35 @@ _dbus_server_new_for_socket (int
/**
* 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_fd[MAX_SOCKET];
+ int nlisten_fd = MAX_SOCKET, i;
DBusString address;
DBusString host_str;
+ char retport[50];
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
@@ -330,21 +398,45 @@ _dbus_server_new_for_tcp_socket (const c
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, "*"))
+ bind = NULL;
+
+ nlisten_fd =_dbus_listen_tcp_socket (bind, port, family,
+ retport, sizeof(retport),
+ listen_fd, nlisten_fd, error);
+ if (nlisten_fd <= 0)
+ {
+ _DBUS_ASSERT_ERROR_IS_SET(error);
+ return NULL;
+ }
+
+ for (i = 0 ; i < nlisten_fd ; i++)
+ _dbus_fd_set_close_on_exec (listen_fd[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, retport))
+ {
+ _dbus_string_free (&address);
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ return NULL;
+ }
+ if (family &&
+ (!_dbus_string_append (&address, ",family=") ||
+ !_dbus_string_append (&address, family)))
{
_dbus_string_free (&address);
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return NULL;
}
-
if (listen_fd < 0)
{
@@ -352,11 +444,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 +488,16 @@ _dbus_server_listen_socket (DBusAddressE
{
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)
{
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 20 Jun 2007 14:35:51 -0000
@@ -28,11 +28,13 @@
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 *bind,
+ const char *port,
+ const char *family,
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 20 Jun 2007 14:35:51 -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.34
diff -u -p -r1.34 dbus-sysdeps-unix.c
--- dbus/dbus-sysdeps-unix.c 18 Jun 2007 18:05:21 -0000 1.34
+++ dbus/dbus-sysdeps-unix.c 20 Jun 2007 14:35:51 -0000
@@ -737,65 +737,94 @@ _dbus_listen_unix_socket (const char
* 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);
+ _dbus_error_from_errno (errno),
+ "Unknown address family %s", family);
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));
+ 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 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:%d %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
* 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 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,
+ const char *family,
+ 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 nlisten_fd = 0, res, i;
+ 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_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;
+
+ retport[0] = '\0';
+
+ 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 listen_fd = -1;
+ if (nlisten_fd >= nretfd)
+ {
+ dbus_set_error (error, _dbus_error_from_errno(EINVAL),
+ "Too many sockets to listen on: \"%s:%s\"",
+ host ? host : "*", port);
+ 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]);
-
- memcpy (&addr.sin_addr, haddr, sizeof (struct in_addr));
+ listen_fd = -1;
+ 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);
+
+ if (bind (listen_fd, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) < 0)
+ {
+ _dbus_close(listen_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));
+ 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:%s\": %s",
+ host ? 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;
+ }
+
+
+ retfd[nlisten_fd] = listen_fd;
+ nlisten_fd++;
+
+ if (!retport[0])
+ {
+ /* 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;
+
+ 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 ? host : "*", port, gai_strerror(res), res);
+ for (i = 0 ; i < nlisten_fd ; i++)
+ _dbus_close(retfd[i], NULL);
+ return -1;
+ }
+
+ /* Release current address list & redo lookup */
+ port = retport;
+ freeaddrinfo(ai);
+ goto redo_lookup_with_port;
+ }
+ else
+ {
+ strncpy(retport, port, retportlen-1);
+ retport[retportlen-1] = '\0';
+ }
+ }
+
+ tmp = tmp->ai_next;
}
-
- addr.sin_family = AF_INET;
- addr.sin_port = htons (*port);
+ freeaddrinfo(ai);
- 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 (retfd[i], error))
+ {
+ int j;
+ for (j = 0 ; j < nlisten_fd ; j++)
+ _dbus_close(retfd[j], NULL);
+ return -1;
+ }
}
- getsockname(listen_fd, (struct sockaddr*) &addr, &len);
- *port = (dbus_uint32_t) ntohs(addr.sin_port);
-
- if (!_dbus_set_fd_nonblocking (listen_fd, error))
- {
- _dbus_close (listen_fd, NULL);
- return -1;
- }
-
- return listen_fd;
+ return nlisten_fd;
}
static dbus_bool_t
@@ -1089,7 +1216,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.82
diff -u -p -r1.82 dbus-sysdeps.h
--- dbus/dbus-sysdeps.h 15 Jun 2007 20:10:09 -0000 1.82
+++ dbus/dbus-sysdeps.h 20 Jun 2007 14:35:51 -0000
@@ -143,11 +143,16 @@ 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,
+ 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,
+ 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.8
diff -u -p -r1.8 dbus-transport-socket.c
--- dbus/dbus-transport-socket.c 18 Jun 2007 18:05:21 -0000 1.8
+++ dbus/dbus-transport-socket.c 20 Jun 2007 14:35:51 -0000
@@ -1204,15 +1204,18 @@ _dbus_transport_new_for_socket (int
/**
* 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 (cons
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;
+
+ if (family != NULL &&
+ (!_dbus_string_append (&address, "family=") ||
+ !_dbus_string_append (&address, family)))
goto error;
- fd = _dbus_connect_tcp_socket (host, port, 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 (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);
@@ -1293,28 +1303,15 @@ _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;
-
+ 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);
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 20 Jun 2007 14:35:51 -0000
@@ -31,7 +31,8 @@ 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,
+ const char *family,
DBusError *error);
DBusTransportOpenResult _dbus_transport_open_socket (DBusAddressEntry *entry,
DBusTransport **transport_p,
Index: bus/dbus-daemon.1.in
===================================================================
RCS file: /cvs/dbus/dbus/bus/dbus-daemon.1.in,v
retrieving revision 1.9
diff -u -p -r1.9 dbus-daemon.1.in
--- bus/dbus-daemon.1.in 13 Jun 2007 20:52:58 -0000 1.9
+++ bus/dbus-daemon.1.in 20 Jun 2007 14:35:51 -0000
@@ -221,6 +221,15 @@ the last address given in <listen> first
apps will try to connect to the last <listen> address first.
.PP
+tcp sockets can accept IPv4 addresses, IPv6 addresses or hostnames.
+If a hostname resolves to multiple addresses, the server will bind
+to all of them. The family=ipv4 or family=ipv6 options can be used
+to force it to bind to a subset of addresses
+
+.PP
+Example: <listen>tcp:host=localhost,port=0,family=ipv4</listen>
+
+.PP
A special case is using a port number of zero (or omitting the port),
which means to choose an available port selected by the operating
system. The port number chosen can be with the --print-address command
@@ -231,11 +240,15 @@ reports its own address, such as when DB
Example: <listen>tcp:host=localhost,port=0</listen>
.PP
-tcp addresses also allow an all_interfaces=true option, which will
-cause the bus to listen on all local address (INADDR_ANY) and not only
-the specified host. However, the specified host will still be used as
-the reported address of the server. The specified host should be a
-valid name of the local machine or weird stuff will happen.
+tcp addresses also allow a bind=hostname option, which will override
+the host option specifying what address to bind to, without changing
+the address reported by the bus. The bind option can also take a
+special name '*' to cause the bus to listen on all local address
+(INADDR_ANY). The specified host should be a valid name of the local
+machine or weird stuff will happen.
+
+.PP
+Example: <listen>tcp:host=localhost,bind=*,port=0</listen>
.TP
.I "<auth>"
-------------- 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/20070620/ed360f74/attachment-0001.pgp
More information about the dbus
mailing list