From 8027efc97b4bec85f674570f878919cb72456745 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sat, 16 Sep 2006 17:38:24 +0000 Subject: [PATCH] voc Pennington * dbus/dbus-server.c (dbus_server_listen): change how this works to be able to delegate to a set of handlers that can succeed, fail, or choose not to handle. Allows us to have dbus_server_listen_platform_specific. * dbus/dbus-server-socket.c (_dbus_server_new_for_tcp_socket): factor out the tcp socket stuff to be used on windows, leaving unix domain socket only in dbus-socket-unix.c * dbus/dbus-transport-socket.c (_dbus_transport_new_for_tcp_socket): factor out the tcp socket stuff to be used on windows, leaving unix domain socket only in dbus-transport-unix.c * dbus/dbus-connection.c (dbus_connection_get_unix_user): insert temporary hack to be sure this fails on windows (dbus_connection_get_unix_process_id): ditto --- ChangeLog | 20 + dbus/Makefile.am | 4 + dbus/dbus-connection.c | 23 +- dbus/dbus-internals.c | 3 - dbus/dbus-server-debug-pipe.c | 62 +- dbus/dbus-server-debug-pipe.h | 12 +- dbus/dbus-server-protected.h | 17 + dbus/dbus-server-socket.c | 458 ++++++++++++++ dbus/dbus-server-socket.h | 46 ++ dbus/dbus-server-unix.c | 418 ++++--------- dbus/dbus-server-unix.h | 6 - dbus/dbus-server.c | 271 ++++----- dbus/dbus-sysdeps-unix.h | 13 + dbus/dbus-sysdeps.h | 14 +- dbus/dbus-transport-protected.h | 6 +- dbus/dbus-transport-socket.c | 1255 +++++++++++++++++++++++++++++++++++++++ dbus/dbus-transport-socket.h | 40 ++ dbus/dbus-transport-unix.c | 1220 +------------------------------------ dbus/dbus-transport-unix.h | 6 - dbus/dbus-transport.c | 13 +- dbus/dbus-transport.h | 5 +- 21 files changed, 2186 insertions(+), 1726 deletions(-) create mode 100644 dbus/dbus-server-socket.c create mode 100644 dbus/dbus-server-socket.h create mode 100644 dbus/dbus-transport-socket.c create mode 100644 dbus/dbus-transport-socket.h diff --git a/ChangeLog b/ChangeLog index 96eed11..1d3ca4b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,25 @@ 2006-09-16 Havoc Pennington + * dbus/dbus-server.c (dbus_server_listen): change how this works + to be able to delegate to a set of handlers that can succeed, + fail, or choose not to handle. Allows us to have + dbus_server_listen_platform_specific. + + * dbus/dbus-server-socket.c (_dbus_server_new_for_tcp_socket): + factor out the tcp socket stuff to be used on windows, leaving + unix domain socket only in dbus-socket-unix.c + + * dbus/dbus-transport-socket.c + (_dbus_transport_new_for_tcp_socket): factor out the tcp socket + stuff to be used on windows, leaving unix domain socket only + in dbus-transport-unix.c + + * dbus/dbus-connection.c (dbus_connection_get_unix_user): insert + temporary hack to be sure this fails on windows + (dbus_connection_get_unix_process_id): ditto + +2006-09-16 Havoc Pennington + * dbus/dbus-sysdeps-unix.c (_dbus_open_tcp_socket) (_dbus_open_unix_socket, _dbus_open_socket): change API for _dbus_open_socket so the domain/type/protocol from system headers diff --git a/dbus/Makefile.am b/dbus/Makefile.am index 996abe8..84ee560 100644 --- a/dbus/Makefile.am +++ b/dbus/Makefile.am @@ -62,6 +62,8 @@ DBUS_LIB_SOURCES= \ dbus-server-debug-pipe.c \ dbus-server-debug-pipe.h \ dbus-server-protected.h \ + dbus-server-socket.c \ + dbus-server-socket.h \ dbus-server-unix.c \ dbus-server-unix.h \ dbus-sha.c \ @@ -74,6 +76,8 @@ DBUS_LIB_SOURCES= \ dbus-transport.c \ dbus-transport.h \ dbus-transport-protected.h \ + dbus-transport-socket.c \ + dbus-transport-socket.h \ dbus-transport-unix.c \ dbus-transport-unix.h \ dbus-watch.c \ diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index a975513..be88e32 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -4224,6 +4224,9 @@ dbus_connection_set_dispatch_status_function (DBusConnection *connec * connections will have a file descriptor. So for adding descriptors * to the main loop, use dbus_watch_get_fd() and so forth. * + * @todo this function should be called get_socket_fd or something; + * there's no reason it can't work on Windows sockets also. + * * @param connection the connection * @param fd return location for the file descriptor. * @returns #TRUE if fd is successfully obtained. @@ -4239,8 +4242,8 @@ dbus_connection_get_unix_fd (DBusConnection *connection, CONNECTION_LOCK (connection); - retval = _dbus_transport_get_unix_fd (connection->transport, - fd); + retval = _dbus_transport_get_socket_fd (connection->transport, + fd); CONNECTION_UNLOCK (connection); @@ -4266,6 +4269,14 @@ dbus_connection_get_unix_user (DBusConnection *connection, _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (uid != NULL, FALSE); + +#ifdef DBUS_WIN + /* FIXME this should be done at a lower level, but it's kind of hard, + * just want to be sure we don't ship with this API returning + * some weird internal fake uid for 1.0 + */ + return FALSE; +#endif CONNECTION_LOCK (connection); @@ -4297,6 +4308,14 @@ dbus_connection_get_unix_process_id (DBusConnection *connection, _dbus_return_val_if_fail (connection != NULL, FALSE); _dbus_return_val_if_fail (pid != NULL, FALSE); + +#ifdef DBUS_WIN + /* FIXME this should be done at a lower level, but it's kind of hard, + * just want to be sure we don't ship with this API returning + * some weird internal fake uid for 1.0 + */ + return FALSE; +#endif CONNECTION_LOCK (connection); diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c index 75eb8ce..8567ebb 100644 --- a/dbus/dbus-internals.c +++ b/dbus/dbus-internals.c @@ -26,9 +26,6 @@ #include #include #include -#include -#include -#include #include /** diff --git a/dbus/dbus-server-debug-pipe.c b/dbus/dbus-server-debug-pipe.c index 20c68a8..62cae0a 100644 --- a/dbus/dbus-server-debug-pipe.c +++ b/dbus/dbus-server-debug-pipe.c @@ -24,7 +24,7 @@ #include "dbus-internals.h" #include "dbus-server-debug-pipe.h" -#include "dbus-transport-unix.h" +#include "dbus-transport-socket.h" #include "dbus-connection-internal.h" #include "dbus-hash.h" #include "dbus-string.h" @@ -256,8 +256,8 @@ _dbus_transport_debug_pipe_new (const char *server_name, _dbus_fd_set_close_on_exec (client_fd); _dbus_fd_set_close_on_exec (server_fd); - client_transport = _dbus_transport_new_for_fd (client_fd, - NULL, &address); + client_transport = _dbus_transport_new_for_socket (client_fd, + NULL, &address); if (client_transport == NULL) { _dbus_close_socket (client_fd, NULL); @@ -271,8 +271,8 @@ _dbus_transport_debug_pipe_new (const char *server_name, client_fd = -1; - server_transport = _dbus_transport_new_for_fd (server_fd, - &server->guid_hex, NULL); + server_transport = _dbus_transport_new_for_socket (server_fd, + &server->guid_hex, NULL); if (server_transport == NULL) { _dbus_transport_unref (client_transport); @@ -322,6 +322,58 @@ _dbus_transport_debug_pipe_new (const char *server_name, return client_transport; } +/** + * Tries to interpret the address entry as a debug pipe entry. + * + * Sets error if the result is not OK. + * + * @param entry an address entry + * @param a new DBusServer, or #NULL on failure. + * @param error location to store rationale for failure on bad address + * @returns the outcome + * + */ +DBusServerListenResult +_dbus_server_listen_debug_pipe (DBusAddressEntry *entry, + DBusServer **server_p, + DBusError *error) +{ + const char *method; + + *server_p = NULL; + + method = dbus_address_entry_get_method (entry); + + if (strcmp (method, "debug-pipe") == 0) + { + const char *name = dbus_address_entry_get_value (entry, "name"); + + if (name == NULL) + { + _dbus_server_set_bad_address(error, "debug-pipe", "name", + NULL); + return DBUS_SERVER_LISTEN_BAD_ADDRESS; + } + + *server_p = _dbus_server_debug_pipe_new (name, error); + + if (*server_p) + { + _DBUS_ASSERT_ERROR_IS_CLEAR(error); + return DBUS_SERVER_LISTEN_OK; + } + else + { + _DBUS_ASSERT_ERROR_IS_SET(error); + return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; + } + } + else + { + _DBUS_ASSERT_ERROR_IS_CLEAR(error); + return DBUS_SERVER_LISTEN_NOT_HANDLED; + } +} /** @} */ diff --git a/dbus/dbus-server-debug-pipe.h b/dbus/dbus-server-debug-pipe.h index 6590fbd..d6582a7 100644 --- a/dbus/dbus-server-debug-pipe.h +++ b/dbus/dbus-server-debug-pipe.h @@ -30,10 +30,14 @@ DBUS_BEGIN_DECLS -DBusServer* _dbus_server_debug_pipe_new (const char *server_name, - DBusError *error); -DBusTransport* _dbus_transport_debug_pipe_new (const char *server_name, - DBusError *error); +DBusServer* _dbus_server_debug_pipe_new (const char *server_name, + DBusError *error); +DBusTransport* _dbus_transport_debug_pipe_new (const char *server_name, + DBusError *error); +DBusServerListenResult _dbus_server_listen_debug_pipe (DBusAddressEntry *entry, + DBusServer **server_p, + DBusError *error); + DBUS_END_DECLS diff --git a/dbus/dbus-server-protected.h b/dbus/dbus-server-protected.h index 09eeb3b..2d30792 100644 --- a/dbus/dbus-server-protected.h +++ b/dbus/dbus-server-protected.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -121,6 +122,22 @@ void _dbus_server_toggle_timeout (DBusServer *server, void _dbus_server_ref_unlocked (DBusServer *server); void _dbus_server_unref_unlocked (DBusServer *server); +typedef enum +{ + DBUS_SERVER_LISTEN_NOT_HANDLED, /**< we aren't in charge of this address type */ + DBUS_SERVER_LISTEN_OK, /**< we set up the listen */ + DBUS_SERVER_LISTEN_BAD_ADDRESS, /**< malformed address */ + DBUS_SERVER_LISTEN_DID_NOT_CONNECT /**< well-formed address but failed to set it up */ +} DBusServerListenResult; + +DBusServerListenResult _dbus_server_listen_platform_specific (DBusAddressEntry *entry, + DBusServer **server_p, + DBusError *error); +void _dbus_server_set_bad_address (DBusError *error, + const char *address_problem_type, + const char *address_problem_field, + const char *address_problem_other); + #ifdef DBUS_DISABLE_CHECKS #define TOOK_LOCK_CHECK(server) #define RELEASING_LOCK_CHECK(server) diff --git a/dbus/dbus-server-socket.c b/dbus/dbus-server-socket.c new file mode 100644 index 0000000..f5f2263 --- /dev/null +++ b/dbus/dbus-server-socket.c @@ -0,0 +1,458 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-server-socket.c Server implementation for sockets + * + * Copyright (C) 2002, 2003, 2004, 2006 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-server-socket.h" +#include "dbus-transport-socket.h" +#include "dbus-connection-internal.h" +#include "dbus-string.h" + +/** + * @defgroup DBusServerSocket DBusServer implementations for SOCKET + * @ingroup DBusInternals + * @brief Implementation details of DBusServer on SOCKET + * + * @{ + */ +/** + * + * Opaque object representing a Socket server implementation. + */ +typedef struct DBusServerSocket DBusServerSocket; + +/** + * Implementation details of DBusServerSocket. All members + * are private. + */ +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 */ +}; + +static void +socket_finalize (DBusServer *server) +{ + DBusServerSocket *socket_server = (DBusServerSocket*) server; + + _dbus_server_finalize_base (server); + + if (socket_server->watch) + { + _dbus_watch_unref (socket_server->watch); + socket_server->watch = NULL; + } + + dbus_free (socket_server->socket_name); + dbus_free (server); +} + +/** + * @todo unreffing the connection at the end may cause + * us to drop the last ref to the connection before + * disconnecting it. That is invalid. + * + * @todo doesn't this leak a server refcount if + * new_connection_function is NULL? + */ +/* Return value is just for memory, not other failures. */ +static dbus_bool_t +handle_new_client_fd_and_unlock (DBusServer *server, + int client_fd) +{ + DBusConnection *connection; + DBusTransport *transport; + DBusNewConnectionFunction new_connection_function; + void *new_connection_data; + + _dbus_verbose ("Creating new client connection with fd %d\n", client_fd); + + HAVE_LOCK_CHECK (server); + + if (!_dbus_set_fd_nonblocking (client_fd, NULL)) + { + SERVER_UNLOCK (server); + return TRUE; + } + + transport = _dbus_transport_new_for_socket (client_fd, &server->guid_hex, NULL); + if (transport == NULL) + { + _dbus_close_socket (client_fd, NULL); + SERVER_UNLOCK (server); + return FALSE; + } + + if (!_dbus_transport_set_auth_mechanisms (transport, + (const char **) server->auth_mechanisms)) + { + _dbus_transport_unref (transport); + SERVER_UNLOCK (server); + return FALSE; + } + + /* note that client_fd is now owned by the transport, and will be + * closed on transport disconnection/finalization + */ + + connection = _dbus_connection_new_for_transport (transport); + _dbus_transport_unref (transport); + transport = NULL; /* now under the connection lock */ + + if (connection == NULL) + { + SERVER_UNLOCK (server); + return FALSE; + } + + /* See if someone wants to handle this new connection, self-referencing + * for paranoia. + */ + new_connection_function = server->new_connection_function; + new_connection_data = server->new_connection_data; + + _dbus_server_ref_unlocked (server); + SERVER_UNLOCK (server); + + if (new_connection_function) + { + (* new_connection_function) (server, connection, + new_connection_data); + dbus_server_unref (server); + } + + /* If no one grabbed a reference, the connection will die. */ + dbus_connection_unref (connection); + + return TRUE; +} + +static dbus_bool_t +socket_handle_watch (DBusWatch *watch, + unsigned int flags, + void *data) +{ + DBusServer *server = data; + DBusServerSocket *socket_server = data; + + SERVER_LOCK (server); + + _dbus_assert (watch == socket_server->watch); + + _dbus_verbose ("Handling client connection, flags 0x%x\n", flags); + + if (flags & DBUS_WATCH_READABLE) + { + int client_fd; + int listen_fd; + + listen_fd = dbus_watch_get_fd (watch); + + client_fd = _dbus_accept (listen_fd); + + if (client_fd < 0) + { + /* EINTR handled for us */ + + if (errno == EAGAIN || errno == EWOULDBLOCK) + _dbus_verbose ("No client available to accept after all\n"); + else + _dbus_verbose ("Failed to accept a client connection: %s\n", + _dbus_strerror (errno)); + + SERVER_UNLOCK (server); + } + else + { + _dbus_fd_set_close_on_exec (client_fd); + + if (!handle_new_client_fd_and_unlock (server, client_fd)) + _dbus_verbose ("Rejected client connection due to lack of memory\n"); + } + } + + if (flags & DBUS_WATCH_ERROR) + _dbus_verbose ("Error on server listening socket\n"); + + if (flags & DBUS_WATCH_HANGUP) + _dbus_verbose ("Hangup on server listening socket\n"); + + return TRUE; +} + +static void +socket_disconnect (DBusServer *server) +{ + DBusServerSocket *socket_server = (DBusServerSocket*) server; + + HAVE_LOCK_CHECK (server); + + if (socket_server->watch) + { + _dbus_server_remove_watch (server, + socket_server->watch); + _dbus_watch_unref (socket_server->watch); + socket_server->watch = NULL; + } + + _dbus_close_socket (socket_server->fd, NULL); + socket_server->fd = -1; + + if (socket_server->socket_name != NULL) + { + DBusString tmp; + _dbus_string_init_const (&tmp, socket_server->socket_name); + _dbus_delete_file (&tmp, NULL); + } + + HAVE_LOCK_CHECK (server); +} + +static const DBusServerVTable socket_vtable = { + socket_finalize, + socket_disconnect +}; + +/** + * Creates a new server listening on the given file descriptor. The + * file descriptor should be nonblocking (use + * _dbus_set_fd_nonblocking() to make it so). The file descriptor + * should be listening for connections, that is, listen() should have + * been successfully invoked on it. The server will use accept() to + * accept new client connections. + * + * @param fd the file descriptor. + * @param address the server's address + * @returns the new server, or #NULL if no memory. + * + */ +DBusServer* +_dbus_server_new_for_socket (int fd, + const DBusString *address) +{ + DBusServerSocket *socket_server; + DBusServer *server; + DBusWatch *watch; + + socket_server = dbus_new0 (DBusServerSocket, 1); + if (socket_server == NULL) + return NULL; + + watch = _dbus_watch_new (fd, + DBUS_WATCH_READABLE, + TRUE, + socket_handle_watch, socket_server, + NULL); + if (watch == NULL) + { + dbus_free (socket_server); + return NULL; + } + + if (!_dbus_server_init_base (&socket_server->base, + &socket_vtable, address)) + { + _dbus_watch_unref (watch); + dbus_free (socket_server); + return NULL; + } + + server = (DBusServer*) socket_server; + + SERVER_LOCK (server); + + if (!_dbus_server_add_watch (&socket_server->base, + watch)) + { + SERVER_UNLOCK (server); + _dbus_server_finalize_base (&socket_server->base); + _dbus_watch_unref (watch); + dbus_free (socket_server); + return NULL; + } + + socket_server->fd = fd; + socket_server->watch = watch; + + SERVER_UNLOCK (server); + + return (DBusServer*) socket_server; +} + +/** + * Creates a new server listening on the given hostname and port. + * If the hostname is NULL, listens on localhost. + * + * @param host the hostname to listen on. + * @param port the port to listen on. + * @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, + DBusError *error) +{ + DBusServer *server; + int listen_fd; + DBusString address; + DBusString host_str; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (!_dbus_string_init (&address)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + if (host == NULL) + host = "localhost"; + + _dbus_string_init_const (&host_str, host); + if (!_dbus_string_append (&address, "tcp:host=") || + !_dbus_address_append_escaped (&address, &host_str) || + !_dbus_string_append (&address, ",port=") || + !_dbus_string_append_int (&address, port)) + { + _dbus_string_free (&address); + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + listen_fd = _dbus_listen_tcp_socket (host, port, error); + _dbus_fd_set_close_on_exec (listen_fd); + + if (listen_fd < 0) + { + _dbus_string_free (&address); + return NULL; + } + + server = _dbus_server_new_for_socket (listen_fd, &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; + } + + _dbus_string_free (&address); + + return server; + + +} + +/** + * Tries to interpret the address entry for various socket-related + * addresses (well, currently only tcp). + * + * Sets error if the result is not OK. + * + * @param entry an address entry + * @param server_p a new DBusServer, or #NULL on failure. + * @param error location to store rationale for failure on bad address + * @returns the outcome + * + */ +DBusServerListenResult +_dbus_server_listen_socket (DBusAddressEntry *entry, + DBusServer **server_p, + DBusError *error) +{ + const char *method; + + *server_p = NULL; + + method = dbus_address_entry_get_method (entry); + + if (strcmp (method, "tcp") == 0) + { + const char *host = dbus_address_entry_get_value (entry, "host"); + const char *port = dbus_address_entry_get_value (entry, "port"); + DBusString str; + long lport; + dbus_bool_t sresult; + + if (port == NULL) + { + _dbus_server_set_bad_address(error, "tcp", "port", NULL); + return DBUS_SERVER_LISTEN_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_server_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, error); + + if (*server_p) + { + _DBUS_ASSERT_ERROR_IS_CLEAR(error); + return DBUS_SERVER_LISTEN_OK; + } + else + { + _DBUS_ASSERT_ERROR_IS_SET(error); + return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; + } + } + else + { + _DBUS_ASSERT_ERROR_IS_CLEAR(error); + return DBUS_SERVER_LISTEN_NOT_HANDLED; + } +} + +/** + * This is a bad hack since it's really unix domain socket + * specific. Also, the function weirdly adopts ownership + * of the passed-in string. + * + * @param server a socket server + * @param filename socket filename to report/delete + * + */ +void +_dbus_server_socket_own_filename (DBusServer *server, + char *filename) +{ + DBusServerSocket *socket_server = (DBusServerSocket*) server; + + socket_server->socket_name = filename; +} + + +/** @} */ + diff --git a/dbus/dbus-server-socket.h b/dbus/dbus-server-socket.h new file mode 100644 index 0000000..384098e --- /dev/null +++ b/dbus/dbus-server-socket.h @@ -0,0 +1,46 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-server-socket.h Server implementation for sockets + * + * Copyright (C) 2002, 2006 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef DBUS_SERVER_SOCKET_H +#define DBUS_SERVER_SOCKET_H + +#include +#include + +DBUS_BEGIN_DECLS + +DBusServer* _dbus_server_new_for_socket (int fd, + const DBusString *address); +DBusServer* _dbus_server_new_for_tcp_socket (const char *host, + dbus_uint32_t port, + DBusError *error); +DBusServerListenResult _dbus_server_listen_socket (DBusAddressEntry *entry, + DBusServer **server_p, + DBusError *error); + + +void _dbus_server_socket_own_filename (DBusServer *server, + char *filename); + +DBUS_END_DECLS + +#endif /* DBUS_SERVER_SOCKET_H */ diff --git a/dbus/dbus-server-unix.c b/dbus/dbus-server-unix.c index 377dfb0..873307e 100644 --- a/dbus/dbus-server-unix.c +++ b/dbus/dbus-server-unix.c @@ -23,11 +23,11 @@ #include "dbus-internals.h" #include "dbus-server-unix.h" +#include "dbus-server-socket.h" #include "dbus-transport-unix.h" #include "dbus-connection-internal.h" +#include "dbus-sysdeps-unix.h" #include "dbus-string.h" -#include -#include /** * @defgroup DBusServerUnix DBusServer implementations for UNIX @@ -36,271 +36,123 @@ * * @{ */ -/** - * - * Opaque object representing a Unix server implementation. - */ -typedef struct DBusServerUnix DBusServerUnix; - -/** - * Implementation details of DBusServerUnix. All members - * are private. - */ -struct DBusServerUnix -{ - 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 */ -}; - -static void -unix_finalize (DBusServer *server) -{ - DBusServerUnix *unix_server = (DBusServerUnix*) server; - - _dbus_server_finalize_base (server); - - if (unix_server->watch) - { - _dbus_watch_unref (unix_server->watch); - unix_server->watch = NULL; - } - - dbus_free (unix_server->socket_name); - dbus_free (server); -} /** - * @todo unreffing the connection at the end may cause - * us to drop the last ref to the connection before - * disconnecting it. That is invalid. - * - * @todo doesn't this leak a server refcount if - * new_connection_function is NULL? + * Tries to interpret the address entry in a platform-specific + * way, creating a platform-specific server type if appropriate. + * Sets error if the result is not OK. + * + * @param entry an address entry + * @param a new DBusServer, or #NULL on failure. + * @param error location to store rationale for failure on bad address + * @returns the outcome + * */ -/* Return value is just for memory, not other failures. */ -static dbus_bool_t -handle_new_client_fd_and_unlock (DBusServer *server, - int client_fd) +DBusServerListenResult +_dbus_server_listen_platform_specific (DBusAddressEntry *entry, + DBusServer **server_p, + DBusError *error) { - DBusConnection *connection; - DBusTransport *transport; - DBusNewConnectionFunction new_connection_function; - void *new_connection_data; - - _dbus_verbose ("Creating new client connection with fd %d\n", client_fd); + const char *method; - HAVE_LOCK_CHECK (server); - - if (!_dbus_set_fd_nonblocking (client_fd, NULL)) - { - SERVER_UNLOCK (server); - return TRUE; - } - - transport = _dbus_transport_new_for_fd (client_fd, &server->guid_hex, NULL); - if (transport == NULL) - { - _dbus_close_socket (client_fd, NULL); - SERVER_UNLOCK (server); - return FALSE; - } - - if (!_dbus_transport_set_auth_mechanisms (transport, - (const char **) server->auth_mechanisms)) - { - _dbus_transport_unref (transport); - SERVER_UNLOCK (server); - return FALSE; - } - - /* note that client_fd is now owned by the transport, and will be - * closed on transport disconnection/finalization - */ - - connection = _dbus_connection_new_for_transport (transport); - _dbus_transport_unref (transport); - transport = NULL; /* now under the connection lock */ + *server_p = NULL; - if (connection == NULL) - { - SERVER_UNLOCK (server); - return FALSE; - } - - /* See if someone wants to handle this new connection, self-referencing - * for paranoia. - */ - new_connection_function = server->new_connection_function; - new_connection_data = server->new_connection_data; + method = dbus_address_entry_get_method (entry); - _dbus_server_ref_unlocked (server); - SERVER_UNLOCK (server); - - if (new_connection_function) + if (strcmp (method, "unix") == 0) { - (* new_connection_function) (server, connection, - new_connection_data); - dbus_server_unref (server); - } - - /* If no one grabbed a reference, the connection will die. */ - dbus_connection_unref (connection); - - return TRUE; -} - -static dbus_bool_t -unix_handle_watch (DBusWatch *watch, - unsigned int flags, - void *data) -{ - DBusServer *server = data; - DBusServerUnix *unix_server = data; - - SERVER_LOCK (server); - - _dbus_assert (watch == unix_server->watch); + const char *path = dbus_address_entry_get_value (entry, "path"); + const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir"); + const char *abstract = dbus_address_entry_get_value (entry, "abstract"); + + if (path == NULL && tmpdir == NULL && abstract == NULL) + { + _dbus_server_set_bad_address(error, "unix", + "path or tmpdir or abstract", + NULL); + return DBUS_SERVER_LISTEN_BAD_ADDRESS; + } - _dbus_verbose ("Handling client connection, flags 0x%x\n", flags); - - if (flags & DBUS_WATCH_READABLE) - { - int client_fd; - int listen_fd; - - listen_fd = dbus_watch_get_fd (watch); + if ((path && tmpdir) || + (path && abstract) || + (tmpdir && abstract)) + { + _dbus_server_set_bad_address(error, NULL, NULL, + "cannot specify two of \"path\" and \"tmpdir\" and \"abstract\" at the same time"); + return DBUS_SERVER_LISTEN_BAD_ADDRESS; + } - client_fd = _dbus_accept (listen_fd); - - if (client_fd < 0) + if (tmpdir != NULL) { - /* EINTR handled for us */ - - if (errno == EAGAIN || errno == EWOULDBLOCK) - _dbus_verbose ("No client available to accept after all\n"); + DBusString full_path; + DBusString filename; + + if (!_dbus_string_init (&full_path)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; + } + + if (!_dbus_string_init (&filename)) + { + _dbus_string_free (&full_path); + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; + } + + if (!_dbus_string_append (&filename, + "dbus-") || + !_dbus_generate_random_ascii (&filename, 10) || + !_dbus_string_append (&full_path, tmpdir) || + !_dbus_concat_dir_and_file (&full_path, &filename)) + { + _dbus_string_free (&full_path); + _dbus_string_free (&filename); + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; + } + + /* Always use abstract namespace if possible with tmpdir */ + + *server_p = + _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path), +#ifdef HAVE_ABSTRACT_SOCKETS + TRUE, +#else + FALSE, +#endif + error); + + _dbus_string_free (&full_path); + _dbus_string_free (&filename); + } + else + { + if (path) + *server_p = _dbus_server_new_for_domain_socket (path, FALSE, error); else - _dbus_verbose ("Failed to accept a client connection: %s\n", - _dbus_strerror (errno)); + *server_p = _dbus_server_new_for_domain_socket (abstract, TRUE, error); + } - SERVER_UNLOCK (server); + if (*server_p != NULL) + { + _DBUS_ASSERT_ERROR_IS_CLEAR(error); + return DBUS_SERVER_LISTEN_OK; } else { - _dbus_fd_set_close_on_exec (client_fd); - - if (!handle_new_client_fd_and_unlock (server, client_fd)) - _dbus_verbose ("Rejected client connection due to lack of memory\n"); + _DBUS_ASSERT_ERROR_IS_SET(error); + return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } } - - if (flags & DBUS_WATCH_ERROR) - _dbus_verbose ("Error on server listening socket\n"); - - if (flags & DBUS_WATCH_HANGUP) - _dbus_verbose ("Hangup on server listening socket\n"); - - return TRUE; -} - -static void -unix_disconnect (DBusServer *server) -{ - DBusServerUnix *unix_server = (DBusServerUnix*) server; - - HAVE_LOCK_CHECK (server); - - if (unix_server->watch) - { - _dbus_server_remove_watch (server, - unix_server->watch); - _dbus_watch_unref (unix_server->watch); - unix_server->watch = NULL; - } - - _dbus_close_socket (unix_server->fd, NULL); - unix_server->fd = -1; - - if (unix_server->socket_name != NULL) - { - DBusString tmp; - _dbus_string_init_const (&tmp, unix_server->socket_name); - _dbus_delete_file (&tmp, NULL); - } - - HAVE_LOCK_CHECK (server); -} - -static const DBusServerVTable unix_vtable = { - unix_finalize, - unix_disconnect -}; - -/** - * Creates a new server listening on the given file descriptor. The - * file descriptor should be nonblocking (use - * _dbus_set_fd_nonblocking() to make it so). The file descriptor - * should be listening for connections, that is, listen() should have - * been successfully invoked on it. The server will use accept() to - * accept new client connections. - * - * @param fd the file descriptor. - * @param address the server's address - * @returns the new server, or #NULL if no memory. - * - */ -DBusServer* -_dbus_server_new_for_fd (int fd, - const DBusString *address) -{ - DBusServerUnix *unix_server; - DBusServer *server; - DBusWatch *watch; - - unix_server = dbus_new0 (DBusServerUnix, 1); - if (unix_server == NULL) - return NULL; - - watch = _dbus_watch_new (fd, - DBUS_WATCH_READABLE, - TRUE, - unix_handle_watch, unix_server, - NULL); - if (watch == NULL) - { - dbus_free (unix_server); - return NULL; - } - - if (!_dbus_server_init_base (&unix_server->base, - &unix_vtable, address)) - { - _dbus_watch_unref (watch); - dbus_free (unix_server); - return NULL; - } - - server = (DBusServer*) unix_server; - - SERVER_LOCK (server); - - if (!_dbus_server_add_watch (&unix_server->base, - watch)) + else { - SERVER_UNLOCK (server); - _dbus_server_finalize_base (&unix_server->base); - _dbus_watch_unref (watch); - dbus_free (unix_server); - return NULL; + /* If we don't handle the method, we return NULL with the + * error unset + */ + _DBUS_ASSERT_ERROR_IS_CLEAR(error); + return DBUS_SERVER_LISTEN_NOT_HANDLED; } - - unix_server->fd = fd; - unix_server->watch = watch; - - SERVER_UNLOCK (server); - - return (DBusServer*) unix_server; } /** @@ -317,7 +169,6 @@ _dbus_server_new_for_domain_socket (const char *path, DBusError *error) { DBusServer *server; - DBusServerUnix *unix_server; int listen_fd; DBusString address; char *path_copy; @@ -358,15 +209,14 @@ _dbus_server_new_for_domain_socket (const char *path, goto failed_1; } - server = _dbus_server_new_for_fd (listen_fd, &address); + server = _dbus_server_new_for_socket (listen_fd, &address); if (server == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_2; } - unix_server = (DBusServerUnix*) server; - unix_server->socket_name = path_copy; + _dbus_server_socket_own_filename(server, path_copy); _dbus_string_free (&address); @@ -382,71 +232,5 @@ _dbus_server_new_for_domain_socket (const char *path, return NULL; } -/** - * Creates a new server listening on the given hostname and port. - * If the hostname is NULL, listens on localhost. - * - * @param host the hostname to listen on. - * @param port the port to listen on. - * @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, - DBusError *error) -{ - DBusServer *server; - int listen_fd; - DBusString address; - DBusString host_str; - - _DBUS_ASSERT_ERROR_IS_CLEAR (error); - - if (!_dbus_string_init (&address)) - { - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - return NULL; - } - - if (host == NULL) - host = "localhost"; - - _dbus_string_init_const (&host_str, host); - if (!_dbus_string_append (&address, "tcp:host=") || - !_dbus_address_append_escaped (&address, &host_str) || - !_dbus_string_append (&address, ",port=") || - !_dbus_string_append_int (&address, port)) - { - _dbus_string_free (&address); - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - return NULL; - } - - listen_fd = _dbus_listen_tcp_socket (host, port, error); - _dbus_fd_set_close_on_exec (listen_fd); - - if (listen_fd < 0) - { - _dbus_string_free (&address); - return NULL; - } - - server = _dbus_server_new_for_fd (listen_fd, &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; - } - - _dbus_string_free (&address); - - return server; - - -} - /** @} */ diff --git a/dbus/dbus-server-unix.h b/dbus/dbus-server-unix.h index 275b5f4..dcc9285 100644 --- a/dbus/dbus-server-unix.h +++ b/dbus/dbus-server-unix.h @@ -28,15 +28,9 @@ DBUS_BEGIN_DECLS -DBusServer* _dbus_server_new_for_fd (int fd, - const DBusString *address); DBusServer* _dbus_server_new_for_domain_socket (const char *path, dbus_bool_t abstract, DBusError *error); -DBusServer* _dbus_server_new_for_tcp_socket (const char *host, - dbus_uint32_t port, - DBusError *error); - DBUS_END_DECLS diff --git a/dbus/dbus-server.c b/dbus/dbus-server.c index 5e980cb..7a140fd 100644 --- a/dbus/dbus-server.c +++ b/dbus/dbus-server.c @@ -23,6 +23,7 @@ #include "dbus-server.h" #include "dbus-server-unix.h" +#include "dbus-server-socket.h" #include "dbus-string.h" #ifdef DBUS_BUILD_TESTS #include "dbus-server-debug-pipe.h" @@ -441,6 +442,21 @@ _dbus_server_toggle_timeout (DBusServer *server, enabled); } +void +_dbus_server_set_bad_address (DBusError *error, + const char *address_problem_type, + const char *address_problem_field, + const char *address_problem_other) +{ + if (address_problem_type != NULL) + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, + "Server address of type %s was missing argument %s", + address_problem_type, address_problem_field); + else + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, + "Could not parse server address: %s", + address_problem_other); +} /** @} */ @@ -463,6 +479,18 @@ _dbus_server_toggle_timeout (DBusServer *server, * */ +static const struct { + DBusServerListenResult (* func) (DBusAddressEntry *entry, + DBusServer **server_p, + DBusError *error); +} listen_funcs[] = { + { _dbus_server_listen_socket }, + { _dbus_server_listen_platform_specific } +#ifdef DBUS_BUILD_TESTS + , { _dbus_server_listen_debug_pipe } +#endif +}; + /** * Listens for new connections on the given address. * Returns #NULL if listening fails for any reason. @@ -470,10 +498,7 @@ _dbus_server_toggle_timeout (DBusServer *server, * dbus_server_set_new_connection_function() and * dbus_server_set_watch_functions() should be called * immediately to render the server fully functional. - * - * @todo error messages on bad address could really be better. - * DBusResultCode is a bit limiting here. - * + * * @param address the address of this server. * @param error location to store rationale for failure. * @returns a new DBusServer, or #NULL on failure. @@ -486,10 +511,9 @@ dbus_server_listen (const char *address, DBusServer *server; DBusAddressEntry **entries; int len, i; - const char *address_problem_type; - const char *address_problem_field; - const char *address_problem_other; - + DBusError first_connect_error; + dbus_bool_t handled_once; + _dbus_return_val_if_fail (address != NULL, NULL); _dbus_return_val_if_error_is_set (error, NULL); @@ -497,161 +521,111 @@ dbus_server_listen (const char *address, return NULL; server = NULL; - address_problem_type = NULL; - address_problem_field = NULL; - address_problem_other = NULL; + dbus_error_init (&first_connect_error); + handled_once = FALSE; for (i = 0; i < len; i++) { - const char *method; + int j; - method = dbus_address_entry_get_method (entries[i]); + for (j = 0; j < (int) _DBUS_N_ELEMENTS (listen_funcs); ++j) + { + DBusServerListenResult result; + DBusError tmp_error; + + dbus_error_init (&tmp_error); + result = (* listen_funcs[j].func) (entries[i], + &server, + &tmp_error); - if (strcmp (method, "unix") == 0) - { - const char *path = dbus_address_entry_get_value (entries[i], "path"); - const char *tmpdir = dbus_address_entry_get_value (entries[i], "tmpdir"); - const char *abstract = dbus_address_entry_get_value (entries[i], "abstract"); - - if (path == NULL && tmpdir == NULL && abstract == NULL) + if (result == DBUS_SERVER_LISTEN_OK) { - address_problem_type = "unix"; - address_problem_field = "path or tmpdir or abstract"; - goto bad_address; + _dbus_assert (server != NULL); + _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); + handled_once = TRUE; + goto out; } - - if ((path && tmpdir) || - (path && abstract) || - (tmpdir && abstract)) + else if (result == DBUS_SERVER_LISTEN_BAD_ADDRESS) { - address_problem_other = "cannot specify two of \"path\" and \"tmpdir\" and \"abstract\" at the same time"; - goto bad_address; + _dbus_assert (server == NULL); + _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); + dbus_move_error (&tmp_error, error); + handled_once = TRUE; + goto out; } - - if (tmpdir != NULL) + else if (result == DBUS_SERVER_LISTEN_NOT_HANDLED) { - DBusString full_path; - DBusString filename; - - if (!_dbus_string_init (&full_path)) - { - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - goto out; - } - - if (!_dbus_string_init (&filename)) - { - _dbus_string_free (&full_path); - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - goto out; - } - - if (!_dbus_string_append (&filename, - "dbus-") || - !_dbus_generate_random_ascii (&filename, 10) || - !_dbus_string_append (&full_path, tmpdir) || - !_dbus_concat_dir_and_file (&full_path, &filename)) - { - _dbus_string_free (&full_path); - _dbus_string_free (&filename); - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - goto out; - } - - /* Always use abstract namespace if possible with tmpdir */ - - server = - _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path), -#ifdef HAVE_ABSTRACT_SOCKETS - TRUE, -#else - FALSE, -#endif - error); + _dbus_assert (server == NULL); + _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); - _dbus_string_free (&full_path); - _dbus_string_free (&filename); + /* keep trying addresses */ } - else + else if (result == DBUS_SERVER_LISTEN_DID_NOT_CONNECT) { - if (path) - server = _dbus_server_new_for_domain_socket (path, FALSE, error); + _dbus_assert (server == NULL); + _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); + if (!dbus_error_is_set (&first_connect_error)) + dbus_move_error (&tmp_error, &first_connect_error); else - server = _dbus_server_new_for_domain_socket (abstract, TRUE, error); - } - } - else if (strcmp (method, "tcp") == 0) - { - const char *host = dbus_address_entry_get_value (entries[i], "host"); - const char *port = dbus_address_entry_get_value (entries[i], "port"); - DBusString str; - long lport; - dbus_bool_t sresult; - - if (port == NULL) - { - address_problem_type = "tcp"; - address_problem_field = "port"; - goto bad_address; - } + dbus_error_free (&tmp_error); - _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) - { - address_problem_other = "Port is not an integer between 0 and 65535"; - goto bad_address; + handled_once = TRUE; + + /* keep trying addresses */ } - - server = _dbus_server_new_for_tcp_socket (host, lport, error); + } - if (server) - break; - } -#ifdef DBUS_BUILD_TESTS - else if (strcmp (method, "debug-pipe") == 0) - { - const char *name = dbus_address_entry_get_value (entries[i], "name"); + _dbus_assert (server == NULL); + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + } - if (name == NULL) - { - address_problem_type = "debug-pipe"; - address_problem_field = "name"; - goto bad_address; - } + out: - server = _dbus_server_debug_pipe_new (name, error); - } -#endif + if (!handled_once) + { + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + if (len > 0) + dbus_set_error (error, + DBUS_ERROR_BAD_ADDRESS, + "Unknown address type '%s'", + dbus_address_entry_get_method (entries[0])); else - { - address_problem_other = "Unknown address type (examples of valid types are \"unix\" and \"tcp\")"; - goto bad_address; - } - - if (server) - break; + dbus_set_error (error, + DBUS_ERROR_BAD_ADDRESS, + "Empty address '%s'", + address); } - - out: dbus_address_entries_free (entries); - return server; - bad_address: - dbus_address_entries_free (entries); - if (address_problem_type != NULL) - dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, - "Server address of type %s was missing argument %s", - address_problem_type, address_problem_field); - else - dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, - "Could not parse server address: %s", - address_problem_other); + if (server == NULL) + { + _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error) || + dbus_error_is_set (error)); + + if (error && dbus_error_is_set (error)) + { + /* already set the error */ + } + else + { + /* didn't set the error but either error should be + * NULL or first_connect_error should be set. + */ + _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error)); + dbus_move_error (&first_connect_error, error); + } + + _DBUS_ASSERT_ERROR_IS_CLEAR (&first_connect_error); /* be sure we freed it */ + _DBUS_ASSERT_ERROR_IS_SET (error); - return NULL; + return NULL; + } + else + { + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + return server; + } } /** @@ -1166,17 +1140,30 @@ _dbus_server_test (void) for (i = 0; i < _DBUS_N_ELEMENTS (valid_addresses); i++) { - server = dbus_server_listen (valid_addresses[i], NULL); + DBusError error; + + /* FIXME um, how are the two tests here different? */ + + dbus_error_init (&error); + server = dbus_server_listen (valid_addresses[i], &error); if (server == NULL) - _dbus_assert_not_reached ("Failed to listen for valid address."); + { + _dbus_warn ("server listen error: %s: %s\n", error.name, error.message); + dbus_error_free (&error); + _dbus_assert_not_reached ("Failed to listen for valid address."); + } dbus_server_disconnect (server); dbus_server_unref (server); /* Try disconnecting before unreffing */ - server = dbus_server_listen (valid_addresses[i], NULL); + server = dbus_server_listen (valid_addresses[i], &error); if (server == NULL) - _dbus_assert_not_reached ("Failed to listen for valid address."); + { + _dbus_warn ("server listen error: %s: %s\n", error.name, error.message); + dbus_error_free (&error); + _dbus_assert_not_reached ("Failed to listen for valid address."); + } dbus_server_disconnect (server); dbus_server_unref (server); diff --git a/dbus/dbus-sysdeps-unix.h b/dbus/dbus-sysdeps-unix.h index ab1fb38..f1fe3b0 100644 --- a/dbus/dbus-sysdeps-unix.h +++ b/dbus/dbus-sysdeps-unix.h @@ -28,6 +28,10 @@ #include #include +#ifdef DBUS_WIN +#error "Don't include this on Windows" +#endif + DBUS_BEGIN_DECLS dbus_bool_t @@ -51,6 +55,15 @@ _dbus_write_two (int fd, int start2, int len2); +dbus_bool_t _dbus_open_unix_socket (int *fd, + DBusError *error); +int _dbus_connect_unix_socket (const char *path, + dbus_bool_t abstract, + DBusError *error); +int _dbus_listen_unix_socket (const char *path, + dbus_bool_t abstract, + DBusError *error); + DBUS_END_DECLS #endif /* DBUS_SYSDEPS_UNIX_H */ diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index 6e30197..c1ed533 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -100,8 +100,6 @@ typedef unsigned long dbus_gid_t; dbus_bool_t _dbus_open_tcp_socket (int *fd, DBusError *error); -dbus_bool_t _dbus_open_unix_socket (int *fd, - DBusError *error); dbus_bool_t _dbus_close_socket (int fd, DBusError *error); int _dbus_read_socket (int fd, @@ -118,15 +116,6 @@ int _dbus_write_socket_two (int fd, const DBusString *buffer2, int start2, int len2); - - - -int _dbus_connect_unix_socket (const char *path, - dbus_bool_t abstract, - DBusError *error); -int _dbus_listen_unix_socket (const char *path, - dbus_bool_t abstract, - DBusError *error); int _dbus_connect_tcp_socket (const char *host, dbus_uint32_t port, DBusError *error); @@ -145,6 +134,9 @@ typedef struct dbus_gid_t gid; /**< group ID or DBUS_GID_UNSET */ } DBusCredentials; +/* FIXME these read/send credentials should get moved to sysdeps-unix.h, + * or renamed to reflect what they mean cross-platform + */ dbus_bool_t _dbus_read_credentials_unix_socket (int client_fd, DBusCredentials *credentials, DBusError *error); diff --git a/dbus/dbus-transport-protected.h b/dbus/dbus-transport-protected.h index b60151e..5a09d70 100644 --- a/dbus/dbus-transport-protected.h +++ b/dbus/dbus-transport-protected.h @@ -66,9 +66,9 @@ struct DBusTransportVTable void (* live_messages_changed) (DBusTransport *transport); /**< Outstanding messages counter changed */ - dbus_bool_t (* get_unix_fd) (DBusTransport *transport, - int *fd_p); - /**< Get UNIX file descriptor */ + dbus_bool_t (* get_socket_fd) (DBusTransport *transport, + int *fd_p); + /**< Get socket file descriptor */ }; /** diff --git a/dbus/dbus-transport-socket.c b/dbus/dbus-transport-socket.c new file mode 100644 index 0000000..6499118 --- /dev/null +++ b/dbus/dbus-transport-socket.c @@ -0,0 +1,1255 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-transport-socket.c Socket subclasses of DBusTransport + * + * Copyright (C) 2002, 2003, 2004, 2006 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-connection-internal.h" +#include "dbus-transport-socket.h" +#include "dbus-transport-protected.h" +#include "dbus-watch.h" + + +/** + * @defgroup DBusTransportSocket DBusTransport implementations for sockets + * @ingroup DBusInternals + * @brief Implementation details of DBusTransport on sockets + * + * @{ + */ + +/** + * Opaque object representing a socket file descriptor transport. + */ +typedef struct DBusTransportSocket DBusTransportSocket; + +/** + * Implementation details of DBusTransportSocket. All members are private. + */ +struct DBusTransportSocket +{ + DBusTransport base; /**< Parent instance */ + int fd; /**< File descriptor. */ + DBusWatch *read_watch; /**< Watch for readability. */ + DBusWatch *write_watch; /**< Watch for writability. */ + + int max_bytes_read_per_iteration; /**< To avoid blocking too long. */ + int max_bytes_written_per_iteration; /**< To avoid blocking too long. */ + + int message_bytes_written; /**< Number of bytes of current + * outgoing message that have + * been written. + */ + DBusString encoded_outgoing; /**< Encoded version of current + * outgoing message. + */ + DBusString encoded_incoming; /**< Encoded version of current + * incoming data. + */ +}; + +static void +free_watches (DBusTransport *transport) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + + _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); + + if (socket_transport->read_watch) + { + if (transport->connection) + _dbus_connection_remove_watch_unlocked (transport->connection, + socket_transport->read_watch); + _dbus_watch_invalidate (socket_transport->read_watch); + _dbus_watch_unref (socket_transport->read_watch); + socket_transport->read_watch = NULL; + } + + if (socket_transport->write_watch) + { + if (transport->connection) + _dbus_connection_remove_watch_unlocked (transport->connection, + socket_transport->write_watch); + _dbus_watch_invalidate (socket_transport->write_watch); + _dbus_watch_unref (socket_transport->write_watch); + socket_transport->write_watch = NULL; + } + + _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME); +} + +static void +socket_finalize (DBusTransport *transport) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + + _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); + + free_watches (transport); + + _dbus_string_free (&socket_transport->encoded_outgoing); + _dbus_string_free (&socket_transport->encoded_incoming); + + _dbus_transport_finalize_base (transport); + + _dbus_assert (socket_transport->read_watch == NULL); + _dbus_assert (socket_transport->write_watch == NULL); + + dbus_free (transport); +} + +static void +check_write_watch (DBusTransport *transport) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + dbus_bool_t needed; + + if (transport->connection == NULL) + return; + + if (transport->disconnected) + { + _dbus_assert (socket_transport->write_watch == NULL); + return; + } + + _dbus_transport_ref (transport); + + if (_dbus_transport_get_is_authenticated (transport)) + needed = _dbus_connection_has_messages_to_send_unlocked (transport->connection); + else + { + if (transport->send_credentials_pending) + needed = TRUE; + else + { + DBusAuthState auth_state; + + auth_state = _dbus_auth_do_work (transport->auth); + + /* If we need memory we install the write watch just in case, + * if there's no need for it, it will get de-installed + * next time we try reading. + */ + if (auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND || + auth_state == DBUS_AUTH_STATE_WAITING_FOR_MEMORY) + needed = TRUE; + else + needed = FALSE; + } + } + + _dbus_verbose ("check_write_watch(): needed = %d on connection %p watch %p fd = %d outgoing messages exist %d\n", + needed, transport->connection, socket_transport->write_watch, + socket_transport->fd, + _dbus_connection_has_messages_to_send_unlocked (transport->connection)); + + _dbus_connection_toggle_watch_unlocked (transport->connection, + socket_transport->write_watch, + needed); + + _dbus_transport_unref (transport); +} + +static void +check_read_watch (DBusTransport *transport) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + dbus_bool_t need_read_watch; + + _dbus_verbose ("%s: fd = %d\n", + _DBUS_FUNCTION_NAME, socket_transport->fd); + + if (transport->connection == NULL) + return; + + if (transport->disconnected) + { + _dbus_assert (socket_transport->read_watch == NULL); + return; + } + + _dbus_transport_ref (transport); + + if (_dbus_transport_get_is_authenticated (transport)) + need_read_watch = + _dbus_counter_get_value (transport->live_messages_size) < transport->max_live_messages_size; + else + { + if (transport->receive_credentials_pending) + need_read_watch = TRUE; + else + { + /* The reason to disable need_read_watch when not WAITING_FOR_INPUT + * is to avoid spinning on the file descriptor when we're waiting + * to write or for some other part of the auth process + */ + DBusAuthState auth_state; + + auth_state = _dbus_auth_do_work (transport->auth); + + /* If we need memory we install the read watch just in case, + * if there's no need for it, it will get de-installed + * next time we try reading. If we're authenticated we + * install it since we normally have it installed while + * authenticated. + */ + if (auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT || + auth_state == DBUS_AUTH_STATE_WAITING_FOR_MEMORY || + auth_state == DBUS_AUTH_STATE_AUTHENTICATED) + need_read_watch = TRUE; + else + need_read_watch = FALSE; + } + } + + _dbus_verbose (" setting read watch enabled = %d\n", need_read_watch); + _dbus_connection_toggle_watch_unlocked (transport->connection, + socket_transport->read_watch, + need_read_watch); + + _dbus_transport_unref (transport); +} + +static void +do_io_error (DBusTransport *transport) +{ + _dbus_transport_ref (transport); + _dbus_transport_disconnect (transport); + _dbus_transport_unref (transport); +} + +/* return value is whether we successfully read any new data. */ +static dbus_bool_t +read_data_into_auth (DBusTransport *transport, + dbus_bool_t *oom) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + DBusString *buffer; + int bytes_read; + + *oom = FALSE; + + _dbus_auth_get_buffer (transport->auth, &buffer); + + bytes_read = _dbus_read_socket (socket_transport->fd, + buffer, socket_transport->max_bytes_read_per_iteration); + + _dbus_auth_return_buffer (transport->auth, buffer, + bytes_read > 0 ? bytes_read : 0); + + if (bytes_read > 0) + { + _dbus_verbose (" read %d bytes in auth phase\n", bytes_read); + + return TRUE; + } + else if (bytes_read < 0) + { + /* EINTR already handled for us */ + + if (errno == ENOMEM) + { + *oom = TRUE; + } + else if (errno == EAGAIN || + errno == EWOULDBLOCK) + ; /* do nothing, just return FALSE below */ + else + { + _dbus_verbose ("Error reading from remote app: %s\n", + _dbus_strerror (errno)); + do_io_error (transport); + } + + return FALSE; + } + else + { + _dbus_assert (bytes_read == 0); + + _dbus_verbose ("Disconnected from remote app\n"); + do_io_error (transport); + + return FALSE; + } +} + +/* Return value is whether we successfully wrote any bytes */ +static dbus_bool_t +write_data_from_auth (DBusTransport *transport) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + int bytes_written; + const DBusString *buffer; + + if (!_dbus_auth_get_bytes_to_send (transport->auth, + &buffer)) + return FALSE; + + bytes_written = _dbus_write_socket (socket_transport->fd, + buffer, + 0, _dbus_string_get_length (buffer)); + + if (bytes_written > 0) + { + _dbus_auth_bytes_sent (transport->auth, bytes_written); + return TRUE; + } + else if (bytes_written < 0) + { + /* EINTR already handled for us */ + + if (errno == EAGAIN || + errno == EWOULDBLOCK) + ; + else + { + _dbus_verbose ("Error writing to remote app: %s\n", + _dbus_strerror (errno)); + do_io_error (transport); + } + } + + return FALSE; +} + +static void +exchange_credentials (DBusTransport *transport, + dbus_bool_t do_reading, + dbus_bool_t do_writing) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + + if (do_writing && transport->send_credentials_pending) + { + if (_dbus_send_credentials_unix_socket (socket_transport->fd, + NULL)) + { + transport->send_credentials_pending = FALSE; + } + else + { + _dbus_verbose ("Failed to write credentials\n"); + do_io_error (transport); + } + } + + if (do_reading && transport->receive_credentials_pending) + { + if (_dbus_read_credentials_unix_socket (socket_transport->fd, + &transport->credentials, + NULL)) + { + transport->receive_credentials_pending = FALSE; + } + else + { + _dbus_verbose ("Failed to read credentials\n"); + do_io_error (transport); + } + } + + if (!(transport->send_credentials_pending || + transport->receive_credentials_pending)) + { + _dbus_auth_set_credentials (transport->auth, + &transport->credentials); + } +} + +static dbus_bool_t +do_authentication (DBusTransport *transport, + dbus_bool_t do_reading, + dbus_bool_t do_writing, + dbus_bool_t *auth_completed) +{ + dbus_bool_t oom; + dbus_bool_t orig_auth_state; + + oom = FALSE; + + orig_auth_state = _dbus_transport_get_is_authenticated (transport); + + /* This is essential to avoid the check_write_watch() at the end, + * we don't want to add a write watch in do_iteration before + * we try writing and get EAGAIN + */ + if (orig_auth_state) + { + if (auth_completed) + *auth_completed = FALSE; + return TRUE; + } + + _dbus_transport_ref (transport); + + while (!_dbus_transport_get_is_authenticated (transport) && + _dbus_transport_get_is_connected (transport)) + { + exchange_credentials (transport, do_reading, do_writing); + + if (transport->send_credentials_pending || + transport->receive_credentials_pending) + { + _dbus_verbose ("send_credentials_pending = %d receive_credentials_pending = %d\n", + transport->send_credentials_pending, + transport->receive_credentials_pending); + goto out; + } + +#define TRANSPORT_SIDE(t) ((t)->is_server ? "server" : "client") + switch (_dbus_auth_do_work (transport->auth)) + { + case DBUS_AUTH_STATE_WAITING_FOR_INPUT: + _dbus_verbose (" %s auth state: waiting for input\n", + TRANSPORT_SIDE (transport)); + if (!do_reading || !read_data_into_auth (transport, &oom)) + goto out; + break; + + case DBUS_AUTH_STATE_WAITING_FOR_MEMORY: + _dbus_verbose (" %s auth state: waiting for memory\n", + TRANSPORT_SIDE (transport)); + oom = TRUE; + goto out; + break; + + case DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND: + _dbus_verbose (" %s auth state: bytes to send\n", + TRANSPORT_SIDE (transport)); + if (!do_writing || !write_data_from_auth (transport)) + goto out; + break; + + case DBUS_AUTH_STATE_NEED_DISCONNECT: + _dbus_verbose (" %s auth state: need to disconnect\n", + TRANSPORT_SIDE (transport)); + do_io_error (transport); + break; + + case DBUS_AUTH_STATE_AUTHENTICATED: + _dbus_verbose (" %s auth state: authenticated\n", + TRANSPORT_SIDE (transport)); + break; + } + } + + out: + if (auth_completed) + *auth_completed = (orig_auth_state != _dbus_transport_get_is_authenticated (transport)); + + check_read_watch (transport); + check_write_watch (transport); + _dbus_transport_unref (transport); + + if (oom) + return FALSE; + else + return TRUE; +} + +/* returns false on oom */ +static dbus_bool_t +do_writing (DBusTransport *transport) +{ + int total; + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + dbus_bool_t oom; + + /* No messages without authentication! */ + if (!_dbus_transport_get_is_authenticated (transport)) + { + _dbus_verbose ("Not authenticated, not writing anything\n"); + return TRUE; + } + + if (transport->disconnected) + { + _dbus_verbose ("Not connected, not writing anything\n"); + return TRUE; + } + +#if 1 + _dbus_verbose ("do_writing(), have_messages = %d, fd = %d\n", + _dbus_connection_has_messages_to_send_unlocked (transport->connection), + socket_transport->fd); +#endif + + oom = FALSE; + total = 0; + + while (!transport->disconnected && + _dbus_connection_has_messages_to_send_unlocked (transport->connection)) + { + int bytes_written; + DBusMessage *message; + const DBusString *header; + const DBusString *body; + int header_len, body_len; + int total_bytes_to_write; + + if (total > socket_transport->max_bytes_written_per_iteration) + { + _dbus_verbose ("%d bytes exceeds %d bytes written per iteration, returning\n", + total, socket_transport->max_bytes_written_per_iteration); + goto out; + } + + message = _dbus_connection_get_message_to_send (transport->connection); + _dbus_assert (message != NULL); + _dbus_message_lock (message); + +#if 0 + _dbus_verbose ("writing message %p\n", message); +#endif + + _dbus_message_get_network_data (message, + &header, &body); + + header_len = _dbus_string_get_length (header); + body_len = _dbus_string_get_length (body); + + if (_dbus_auth_needs_encoding (transport->auth)) + { + if (_dbus_string_get_length (&socket_transport->encoded_outgoing) == 0) + { + if (!_dbus_auth_encode_data (transport->auth, + header, &socket_transport->encoded_outgoing)) + { + oom = TRUE; + goto out; + } + + if (!_dbus_auth_encode_data (transport->auth, + body, &socket_transport->encoded_outgoing)) + { + _dbus_string_set_length (&socket_transport->encoded_outgoing, 0); + oom = TRUE; + goto out; + } + } + + total_bytes_to_write = _dbus_string_get_length (&socket_transport->encoded_outgoing); + +#if 0 + _dbus_verbose ("encoded message is %d bytes\n", + total_bytes_to_write); +#endif + + bytes_written = + _dbus_write_socket (socket_transport->fd, + &socket_transport->encoded_outgoing, + socket_transport->message_bytes_written, + total_bytes_to_write - socket_transport->message_bytes_written); + } + else + { + total_bytes_to_write = header_len + body_len; + +#if 0 + _dbus_verbose ("message is %d bytes\n", + total_bytes_to_write); +#endif + + if (socket_transport->message_bytes_written < header_len) + { + bytes_written = + _dbus_write_socket_two (socket_transport->fd, + header, + socket_transport->message_bytes_written, + header_len - socket_transport->message_bytes_written, + body, + 0, body_len); + } + else + { + bytes_written = + _dbus_write_socket (socket_transport->fd, + body, + (socket_transport->message_bytes_written - header_len), + body_len - + (socket_transport->message_bytes_written - header_len)); + } + } + + if (bytes_written < 0) + { + /* EINTR already handled for us */ + + if (errno == EAGAIN || + errno == EWOULDBLOCK) + goto out; + else + { + _dbus_verbose ("Error writing to remote app: %s\n", + _dbus_strerror (errno)); + do_io_error (transport); + goto out; + } + } + else + { + _dbus_verbose (" wrote %d bytes of %d\n", bytes_written, + total_bytes_to_write); + + total += bytes_written; + socket_transport->message_bytes_written += bytes_written; + + _dbus_assert (socket_transport->message_bytes_written <= + total_bytes_to_write); + + if (socket_transport->message_bytes_written == total_bytes_to_write) + { + socket_transport->message_bytes_written = 0; + _dbus_string_set_length (&socket_transport->encoded_outgoing, 0); + + _dbus_connection_message_sent (transport->connection, + message); + } + } + } + + out: + if (oom) + return FALSE; + else + return TRUE; +} + +/* returns false on out-of-memory */ +static dbus_bool_t +do_reading (DBusTransport *transport) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + DBusString *buffer; + int bytes_read; + int total; + dbus_bool_t oom; + + _dbus_verbose ("%s: fd = %d\n", _DBUS_FUNCTION_NAME, + socket_transport->fd); + + /* No messages without authentication! */ + if (!_dbus_transport_get_is_authenticated (transport)) + return TRUE; + + oom = FALSE; + + total = 0; + + again: + + /* See if we've exceeded max messages and need to disable reading */ + check_read_watch (transport); + + if (total > socket_transport->max_bytes_read_per_iteration) + { + _dbus_verbose ("%d bytes exceeds %d bytes read per iteration, returning\n", + total, socket_transport->max_bytes_read_per_iteration); + goto out; + } + + _dbus_assert (socket_transport->read_watch != NULL || + transport->disconnected); + + if (transport->disconnected) + goto out; + + if (!dbus_watch_get_enabled (socket_transport->read_watch)) + return TRUE; + + if (_dbus_auth_needs_decoding (transport->auth)) + { + if (_dbus_string_get_length (&socket_transport->encoded_incoming) > 0) + bytes_read = _dbus_string_get_length (&socket_transport->encoded_incoming); + else + bytes_read = _dbus_read_socket (socket_transport->fd, + &socket_transport->encoded_incoming, + socket_transport->max_bytes_read_per_iteration); + + _dbus_assert (_dbus_string_get_length (&socket_transport->encoded_incoming) == + bytes_read); + + if (bytes_read > 0) + { + int orig_len; + + _dbus_message_loader_get_buffer (transport->loader, + &buffer); + + orig_len = _dbus_string_get_length (buffer); + + if (!_dbus_auth_decode_data (transport->auth, + &socket_transport->encoded_incoming, + buffer)) + { + _dbus_verbose ("Out of memory decoding incoming data\n"); + oom = TRUE; + goto out; + } + + _dbus_message_loader_return_buffer (transport->loader, + buffer, + _dbus_string_get_length (buffer) - orig_len); + + _dbus_string_set_length (&socket_transport->encoded_incoming, 0); + } + } + else + { + _dbus_message_loader_get_buffer (transport->loader, + &buffer); + + bytes_read = _dbus_read_socket (socket_transport->fd, + buffer, socket_transport->max_bytes_read_per_iteration); + + _dbus_message_loader_return_buffer (transport->loader, + buffer, + bytes_read < 0 ? 0 : bytes_read); + } + + if (bytes_read < 0) + { + /* EINTR already handled for us */ + + if (errno == ENOMEM) + { + _dbus_verbose ("Out of memory in read()/do_reading()\n"); + oom = TRUE; + goto out; + } + else if (errno == EAGAIN || + errno == EWOULDBLOCK) + goto out; + else + { + _dbus_verbose ("Error reading from remote app: %s\n", + _dbus_strerror (errno)); + do_io_error (transport); + goto out; + } + } + else if (bytes_read == 0) + { + _dbus_verbose ("Disconnected from remote app\n"); + do_io_error (transport); + goto out; + } + else + { + _dbus_verbose (" read %d bytes\n", bytes_read); + + total += bytes_read; + + if (!_dbus_transport_queue_messages (transport)) + { + oom = TRUE; + _dbus_verbose (" out of memory when queueing messages we just read in the transport\n"); + goto out; + } + + /* Try reading more data until we get EAGAIN and return, or + * exceed max bytes per iteration. If in blocking mode of + * course we'll block instead of returning. + */ + goto again; + } + + out: + if (oom) + return FALSE; + else + return TRUE; +} + +static dbus_bool_t +socket_handle_watch (DBusTransport *transport, + DBusWatch *watch, + unsigned int flags) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + + _dbus_assert (watch == socket_transport->read_watch || + watch == socket_transport->write_watch); + _dbus_assert (watch != NULL); + + /* Disconnect in case of an error. In case of hangup do not + * disconnect the transport because data can still be in the buffer + * and do_reading may need several iteration to read it all (because + * of its max_bytes_read_per_iteration limit). The condition where + * flags == HANGUP (without READABLE) probably never happen in fact. + */ + if ((flags & DBUS_WATCH_ERROR) || + ((flags & DBUS_WATCH_HANGUP) && !(flags & DBUS_WATCH_READABLE))) + { + _dbus_verbose ("Hang up or error on watch\n"); + _dbus_transport_disconnect (transport); + return TRUE; + } + + if (watch == socket_transport->read_watch && + (flags & DBUS_WATCH_READABLE)) + { + dbus_bool_t auth_finished; +#if 1 + _dbus_verbose ("handling read watch %p flags = %x\n", + watch, flags); +#endif + if (!do_authentication (transport, TRUE, FALSE, &auth_finished)) + return FALSE; + + /* We don't want to do a read immediately following + * a successful authentication. This is so we + * have a chance to propagate the authentication + * state further up. Specifically, we need to + * process any pending data from the auth object. + */ + if (!auth_finished) + { + if (!do_reading (transport)) + { + _dbus_verbose ("no memory to read\n"); + return FALSE; + } + } + else + { + _dbus_verbose ("Not reading anything since we just completed the authentication\n"); + } + } + else if (watch == socket_transport->write_watch && + (flags & DBUS_WATCH_WRITABLE)) + { +#if 1 + _dbus_verbose ("handling write watch, have_outgoing_messages = %d\n", + _dbus_connection_has_messages_to_send_unlocked (transport->connection)); +#endif + if (!do_authentication (transport, FALSE, TRUE, NULL)) + return FALSE; + + if (!do_writing (transport)) + { + _dbus_verbose ("no memory to write\n"); + return FALSE; + } + + /* See if we still need the write watch */ + check_write_watch (transport); + } +#ifdef DBUS_ENABLE_VERBOSE_MODE + else + { + if (watch == socket_transport->read_watch) + _dbus_verbose ("asked to handle read watch with non-read condition 0x%x\n", + flags); + else if (watch == socket_transport->write_watch) + _dbus_verbose ("asked to handle write watch with non-write condition 0x%x\n", + flags); + else + _dbus_verbose ("asked to handle watch %p on fd %d that we don't recognize\n", + watch, dbus_watch_get_fd (watch)); + } +#endif /* DBUS_ENABLE_VERBOSE_MODE */ + + return TRUE; +} + +static void +socket_disconnect (DBusTransport *transport) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + + _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); + + free_watches (transport); + + _dbus_close_socket (socket_transport->fd, NULL); + socket_transport->fd = -1; +} + +static dbus_bool_t +socket_connection_set (DBusTransport *transport) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + + _dbus_watch_set_handler (socket_transport->write_watch, + _dbus_connection_handle_watch, + transport->connection, NULL); + + _dbus_watch_set_handler (socket_transport->read_watch, + _dbus_connection_handle_watch, + transport->connection, NULL); + + if (!_dbus_connection_add_watch_unlocked (transport->connection, + socket_transport->write_watch)) + return FALSE; + + if (!_dbus_connection_add_watch_unlocked (transport->connection, + socket_transport->read_watch)) + { + _dbus_connection_remove_watch_unlocked (transport->connection, + socket_transport->write_watch); + return FALSE; + } + + check_read_watch (transport); + check_write_watch (transport); + + return TRUE; +} + +/** + * @todo We need to have a way to wake up the select sleep if + * a new iteration request comes in with a flag (read/write) that + * we're not currently serving. Otherwise a call that just reads + * could block a write call forever (if there are no incoming + * messages). + */ +static void +socket_do_iteration (DBusTransport *transport, + unsigned int flags, + int timeout_milliseconds) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + DBusPollFD poll_fd; + int poll_res; + int poll_timeout; + + _dbus_verbose (" iteration flags = %s%s timeout = %d read_watch = %p write_watch = %p fd = %d\n", + flags & DBUS_ITERATION_DO_READING ? "read" : "", + flags & DBUS_ITERATION_DO_WRITING ? "write" : "", + timeout_milliseconds, + socket_transport->read_watch, + socket_transport->write_watch, + socket_transport->fd); + + /* the passed in DO_READING/DO_WRITING flags indicate whether to + * read/write messages, but regardless of those we may need to block + * for reading/writing to do auth. But if we do reading for auth, + * we don't want to read any messages yet if not given DO_READING. + */ + + poll_fd.fd = socket_transport->fd; + poll_fd.events = 0; + + if (_dbus_transport_get_is_authenticated (transport)) + { + /* This is kind of a hack; if we have stuff to write, then try + * to avoid the poll. This is probably about a 5% speedup on an + * echo client/server. + * + * If both reading and writing were requested, we want to avoid this + * since it could have funky effects: + * - both ends spinning waiting for the other one to read + * data so they can finish writing + * - prioritizing all writing ahead of reading + */ + if ((flags & DBUS_ITERATION_DO_WRITING) && + !(flags & (DBUS_ITERATION_DO_READING | DBUS_ITERATION_BLOCK)) && + !transport->disconnected && + _dbus_connection_has_messages_to_send_unlocked (transport->connection)) + { + do_writing (transport); + + if (transport->disconnected || + !_dbus_connection_has_messages_to_send_unlocked (transport->connection)) + goto out; + } + + /* If we get here, we decided to do the poll() after all */ + _dbus_assert (socket_transport->read_watch); + if (flags & DBUS_ITERATION_DO_READING) + poll_fd.events |= _DBUS_POLLIN; + + _dbus_assert (socket_transport->write_watch); + if (flags & DBUS_ITERATION_DO_WRITING) + poll_fd.events |= _DBUS_POLLOUT; + } + else + { + DBusAuthState auth_state; + + auth_state = _dbus_auth_do_work (transport->auth); + + if (transport->receive_credentials_pending || + auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT) + poll_fd.events |= _DBUS_POLLIN; + + if (transport->send_credentials_pending || + auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND) + poll_fd.events |= _DBUS_POLLOUT; + } + + if (poll_fd.events) + { + if (flags & DBUS_ITERATION_BLOCK) + poll_timeout = timeout_milliseconds; + else + poll_timeout = 0; + + /* For blocking selects we drop the connection lock here + * to avoid blocking out connection access during a potentially + * indefinite blocking call. The io path is still protected + * by the io_path_cond condvar, so we won't reenter this. + */ + if (flags & DBUS_ITERATION_BLOCK) + { + _dbus_verbose ("unlock %s pre poll\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (transport->connection); + } + + again: + poll_res = _dbus_poll (&poll_fd, 1, poll_timeout); + + if (poll_res < 0 && errno == EINTR) + goto again; + + if (flags & DBUS_ITERATION_BLOCK) + { + _dbus_verbose ("lock %s post poll\n", _DBUS_FUNCTION_NAME); + _dbus_connection_lock (transport->connection); + } + + if (poll_res >= 0) + { + if (poll_res == 0) + poll_fd.revents = 0; /* some concern that posix does not guarantee this; + * valgrind flags it as an error. though it probably + * is guaranteed on linux at least. + */ + + if (poll_fd.revents & _DBUS_POLLERR) + do_io_error (transport); + else + { + dbus_bool_t need_read = (poll_fd.revents & _DBUS_POLLIN) > 0; + dbus_bool_t need_write = (poll_fd.revents & _DBUS_POLLOUT) > 0; + dbus_bool_t authentication_completed; + + _dbus_verbose ("in iteration, need_read=%d need_write=%d\n", + need_read, need_write); + do_authentication (transport, need_read, need_write, + &authentication_completed); + + /* See comment in socket_handle_watch. */ + if (authentication_completed) + goto out; + + if (need_read && (flags & DBUS_ITERATION_DO_READING)) + do_reading (transport); + if (need_write && (flags & DBUS_ITERATION_DO_WRITING)) + do_writing (transport); + } + } + else + { + _dbus_verbose ("Error from _dbus_poll(): %s\n", + _dbus_strerror (errno)); + } + } + + + out: + /* We need to install the write watch only if we did not + * successfully write everything. Note we need to be careful that we + * don't call check_write_watch *before* do_writing, since it's + * inefficient to add the write watch, and we can avoid it most of + * the time since we can write immediately. + * + * However, we MUST always call check_write_watch(); DBusConnection code + * relies on the fact that running an iteration will notice that + * messages are pending. + */ + check_write_watch (transport); + + _dbus_verbose (" ... leaving do_iteration()\n"); +} + +static void +socket_live_messages_changed (DBusTransport *transport) +{ + /* See if we should look for incoming messages again */ + check_read_watch (transport); +} + + +static dbus_bool_t +socket_get_socket_fd (DBusTransport *transport, + int *fd_p) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + + *fd_p = socket_transport->fd; + + return TRUE; +} + +static const DBusTransportVTable socket_vtable = { + socket_finalize, + socket_handle_watch, + socket_disconnect, + socket_connection_set, + socket_do_iteration, + socket_live_messages_changed, + socket_get_socket_fd +}; + +/** + * Creates a new transport for the given socket file descriptor. The file + * descriptor must be nonblocking (use _dbus_set_fd_nonblocking() to + * make it so). This function is shared by various transports that + * boil down to a full duplex file descriptor. + * + * @param fd the file descriptor. + * @param server_guid non-#NULL if this transport is on the server side of a connection + * @param address the transport's address + * @returns the new transport, or #NULL if no memory. + */ +DBusTransport* +_dbus_transport_new_for_socket (int fd, + const DBusString *server_guid, + const DBusString *address) +{ + DBusTransportSocket *socket_transport; + + socket_transport = dbus_new0 (DBusTransportSocket, 1); + if (socket_transport == NULL) + return NULL; + + if (!_dbus_string_init (&socket_transport->encoded_outgoing)) + goto failed_0; + + if (!_dbus_string_init (&socket_transport->encoded_incoming)) + goto failed_1; + + socket_transport->write_watch = _dbus_watch_new (fd, + DBUS_WATCH_WRITABLE, + FALSE, + NULL, NULL, NULL); + if (socket_transport->write_watch == NULL) + goto failed_2; + + socket_transport->read_watch = _dbus_watch_new (fd, + DBUS_WATCH_READABLE, + FALSE, + NULL, NULL, NULL); + if (socket_transport->read_watch == NULL) + goto failed_3; + + if (!_dbus_transport_init_base (&socket_transport->base, + &socket_vtable, + server_guid, address)) + goto failed_4; + + socket_transport->fd = fd; + socket_transport->message_bytes_written = 0; + + /* These values should probably be tunable or something. */ + socket_transport->max_bytes_read_per_iteration = 2048; + socket_transport->max_bytes_written_per_iteration = 2048; + + return (DBusTransport*) socket_transport; + + failed_4: + _dbus_watch_unref (socket_transport->read_watch); + failed_3: + _dbus_watch_unref (socket_transport->write_watch); + failed_2: + _dbus_string_free (&socket_transport->encoded_incoming); + failed_1: + _dbus_string_free (&socket_transport->encoded_outgoing); + failed_0: + dbus_free (socket_transport); + return NULL; +} + +/** + * Creates a new transport for the given hostname and port. + * + * @param host the host to connect to + * @param port the port 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, + DBusError *error) +{ + int fd; + DBusTransport *transport; + DBusString address; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (!_dbus_string_init (&address)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + if (!_dbus_string_append (&address, "tcp:")) + goto error; + + if (host != NULL && + (!_dbus_string_append (&address, "host=") || + !_dbus_string_append (&address, host))) + goto error; + + if (!_dbus_string_append (&address, ",port=") || + !_dbus_string_append_int (&address, port)) + goto error; + + fd = _dbus_connect_tcp_socket (host, port, error); + if (fd < 0) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + _dbus_string_free (&address); + return NULL; + } + + _dbus_fd_set_close_on_exec (fd); + + _dbus_verbose ("Successfully connected to tcp socket %s:%d\n", + host, port); + + transport = _dbus_transport_new_for_socket (fd, NULL, &address); + if (transport == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + _dbus_close_socket (fd, NULL); + _dbus_string_free (&address); + fd = -1; + } + + _dbus_string_free (&address); + + return transport; + +error: + _dbus_string_free (&address); + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; +} + +/** @} */ + diff --git a/dbus/dbus-transport-socket.h b/dbus/dbus-transport-socket.h new file mode 100644 index 0000000..aab5991 --- /dev/null +++ b/dbus/dbus-transport-socket.h @@ -0,0 +1,40 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-transport-socket.h Socket subclasses of DBusTransport + * + * Copyright (C) 2002, 2006 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef DBUS_TRANSPORT_SOCKET_H +#define DBUS_TRANSPORT_SOCKET_H + +#include + +DBUS_BEGIN_DECLS + +DBusTransport* _dbus_transport_new_for_socket (int fd, + const DBusString *server_guid, + const DBusString *address); +DBusTransport* _dbus_transport_new_for_tcp_socket (const char *host, + dbus_int32_t port, + DBusError *error); + + +DBUS_END_DECLS + +#endif /* DBUS_TRANSPORT_SOCKET_H */ diff --git a/dbus/dbus-transport-unix.c b/dbus/dbus-transport-unix.c index 55a89a5..7874fd1 100644 --- a/dbus/dbus-transport-unix.c +++ b/dbus/dbus-transport-unix.c @@ -26,7 +26,7 @@ #include "dbus-transport-unix.h" #include "dbus-transport-protected.h" #include "dbus-watch.h" - +#include "dbus-sysdeps-unix.h" /** * @defgroup DBusTransportUnix DBusTransport implementations for UNIX @@ -37,1152 +37,6 @@ */ /** - * Opaque object representing a Unix file descriptor transport. - */ -typedef struct DBusTransportUnix DBusTransportUnix; - -/** - * Implementation details of DBusTransportUnix. All members are private. - */ -struct DBusTransportUnix -{ - DBusTransport base; /**< Parent instance */ - int fd; /**< File descriptor. */ - DBusWatch *read_watch; /**< Watch for readability. */ - DBusWatch *write_watch; /**< Watch for writability. */ - - int max_bytes_read_per_iteration; /**< To avoid blocking too long. */ - int max_bytes_written_per_iteration; /**< To avoid blocking too long. */ - - int message_bytes_written; /**< Number of bytes of current - * outgoing message that have - * been written. - */ - DBusString encoded_outgoing; /**< Encoded version of current - * outgoing message. - */ - DBusString encoded_incoming; /**< Encoded version of current - * incoming data. - */ -}; - -static void -free_watches (DBusTransport *transport) -{ - DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; - - _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); - - if (unix_transport->read_watch) - { - if (transport->connection) - _dbus_connection_remove_watch_unlocked (transport->connection, - unix_transport->read_watch); - _dbus_watch_invalidate (unix_transport->read_watch); - _dbus_watch_unref (unix_transport->read_watch); - unix_transport->read_watch = NULL; - } - - if (unix_transport->write_watch) - { - if (transport->connection) - _dbus_connection_remove_watch_unlocked (transport->connection, - unix_transport->write_watch); - _dbus_watch_invalidate (unix_transport->write_watch); - _dbus_watch_unref (unix_transport->write_watch); - unix_transport->write_watch = NULL; - } - - _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME); -} - -static void -unix_finalize (DBusTransport *transport) -{ - DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; - - _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); - - free_watches (transport); - - _dbus_string_free (&unix_transport->encoded_outgoing); - _dbus_string_free (&unix_transport->encoded_incoming); - - _dbus_transport_finalize_base (transport); - - _dbus_assert (unix_transport->read_watch == NULL); - _dbus_assert (unix_transport->write_watch == NULL); - - dbus_free (transport); -} - -static void -check_write_watch (DBusTransport *transport) -{ - DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; - dbus_bool_t needed; - - if (transport->connection == NULL) - return; - - if (transport->disconnected) - { - _dbus_assert (unix_transport->write_watch == NULL); - return; - } - - _dbus_transport_ref (transport); - - if (_dbus_transport_get_is_authenticated (transport)) - needed = _dbus_connection_has_messages_to_send_unlocked (transport->connection); - else - { - if (transport->send_credentials_pending) - needed = TRUE; - else - { - DBusAuthState auth_state; - - auth_state = _dbus_auth_do_work (transport->auth); - - /* If we need memory we install the write watch just in case, - * if there's no need for it, it will get de-installed - * next time we try reading. - */ - if (auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND || - auth_state == DBUS_AUTH_STATE_WAITING_FOR_MEMORY) - needed = TRUE; - else - needed = FALSE; - } - } - - _dbus_verbose ("check_write_watch(): needed = %d on connection %p watch %p fd = %d outgoing messages exist %d\n", - needed, transport->connection, unix_transport->write_watch, - unix_transport->fd, - _dbus_connection_has_messages_to_send_unlocked (transport->connection)); - - _dbus_connection_toggle_watch_unlocked (transport->connection, - unix_transport->write_watch, - needed); - - _dbus_transport_unref (transport); -} - -static void -check_read_watch (DBusTransport *transport) -{ - DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; - dbus_bool_t need_read_watch; - - _dbus_verbose ("%s: fd = %d\n", - _DBUS_FUNCTION_NAME, unix_transport->fd); - - if (transport->connection == NULL) - return; - - if (transport->disconnected) - { - _dbus_assert (unix_transport->read_watch == NULL); - return; - } - - _dbus_transport_ref (transport); - - if (_dbus_transport_get_is_authenticated (transport)) - need_read_watch = - _dbus_counter_get_value (transport->live_messages_size) < transport->max_live_messages_size; - else - { - if (transport->receive_credentials_pending) - need_read_watch = TRUE; - else - { - /* The reason to disable need_read_watch when not WAITING_FOR_INPUT - * is to avoid spinning on the file descriptor when we're waiting - * to write or for some other part of the auth process - */ - DBusAuthState auth_state; - - auth_state = _dbus_auth_do_work (transport->auth); - - /* If we need memory we install the read watch just in case, - * if there's no need for it, it will get de-installed - * next time we try reading. If we're authenticated we - * install it since we normally have it installed while - * authenticated. - */ - if (auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT || - auth_state == DBUS_AUTH_STATE_WAITING_FOR_MEMORY || - auth_state == DBUS_AUTH_STATE_AUTHENTICATED) - need_read_watch = TRUE; - else - need_read_watch = FALSE; - } - } - - _dbus_verbose (" setting read watch enabled = %d\n", need_read_watch); - _dbus_connection_toggle_watch_unlocked (transport->connection, - unix_transport->read_watch, - need_read_watch); - - _dbus_transport_unref (transport); -} - -static void -do_io_error (DBusTransport *transport) -{ - _dbus_transport_ref (transport); - _dbus_transport_disconnect (transport); - _dbus_transport_unref (transport); -} - -/* return value is whether we successfully read any new data. */ -static dbus_bool_t -read_data_into_auth (DBusTransport *transport, - dbus_bool_t *oom) -{ - DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; - DBusString *buffer; - int bytes_read; - - *oom = FALSE; - - _dbus_auth_get_buffer (transport->auth, &buffer); - - bytes_read = _dbus_read_socket (unix_transport->fd, - buffer, unix_transport->max_bytes_read_per_iteration); - - _dbus_auth_return_buffer (transport->auth, buffer, - bytes_read > 0 ? bytes_read : 0); - - if (bytes_read > 0) - { - _dbus_verbose (" read %d bytes in auth phase\n", bytes_read); - - return TRUE; - } - else if (bytes_read < 0) - { - /* EINTR already handled for us */ - - if (errno == ENOMEM) - { - *oom = TRUE; - } - else if (errno == EAGAIN || - errno == EWOULDBLOCK) - ; /* do nothing, just return FALSE below */ - else - { - _dbus_verbose ("Error reading from remote app: %s\n", - _dbus_strerror (errno)); - do_io_error (transport); - } - - return FALSE; - } - else - { - _dbus_assert (bytes_read == 0); - - _dbus_verbose ("Disconnected from remote app\n"); - do_io_error (transport); - - return FALSE; - } -} - -/* Return value is whether we successfully wrote any bytes */ -static dbus_bool_t -write_data_from_auth (DBusTransport *transport) -{ - DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; - int bytes_written; - const DBusString *buffer; - - if (!_dbus_auth_get_bytes_to_send (transport->auth, - &buffer)) - return FALSE; - - bytes_written = _dbus_write_socket (unix_transport->fd, - buffer, - 0, _dbus_string_get_length (buffer)); - - if (bytes_written > 0) - { - _dbus_auth_bytes_sent (transport->auth, bytes_written); - return TRUE; - } - else if (bytes_written < 0) - { - /* EINTR already handled for us */ - - if (errno == EAGAIN || - errno == EWOULDBLOCK) - ; - else - { - _dbus_verbose ("Error writing to remote app: %s\n", - _dbus_strerror (errno)); - do_io_error (transport); - } - } - - return FALSE; -} - -static void -exchange_credentials (DBusTransport *transport, - dbus_bool_t do_reading, - dbus_bool_t do_writing) -{ - DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; - - if (do_writing && transport->send_credentials_pending) - { - if (_dbus_send_credentials_unix_socket (unix_transport->fd, - NULL)) - { - transport->send_credentials_pending = FALSE; - } - else - { - _dbus_verbose ("Failed to write credentials\n"); - do_io_error (transport); - } - } - - if (do_reading && transport->receive_credentials_pending) - { - if (_dbus_read_credentials_unix_socket (unix_transport->fd, - &transport->credentials, - NULL)) - { - transport->receive_credentials_pending = FALSE; - } - else - { - _dbus_verbose ("Failed to read credentials\n"); - do_io_error (transport); - } - } - - if (!(transport->send_credentials_pending || - transport->receive_credentials_pending)) - { - _dbus_auth_set_credentials (transport->auth, - &transport->credentials); - } -} - -static dbus_bool_t -do_authentication (DBusTransport *transport, - dbus_bool_t do_reading, - dbus_bool_t do_writing, - dbus_bool_t *auth_completed) -{ - dbus_bool_t oom; - dbus_bool_t orig_auth_state; - - oom = FALSE; - - orig_auth_state = _dbus_transport_get_is_authenticated (transport); - - /* This is essential to avoid the check_write_watch() at the end, - * we don't want to add a write watch in do_iteration before - * we try writing and get EAGAIN - */ - if (orig_auth_state) - { - if (auth_completed) - *auth_completed = FALSE; - return TRUE; - } - - _dbus_transport_ref (transport); - - while (!_dbus_transport_get_is_authenticated (transport) && - _dbus_transport_get_is_connected (transport)) - { - exchange_credentials (transport, do_reading, do_writing); - - if (transport->send_credentials_pending || - transport->receive_credentials_pending) - { - _dbus_verbose ("send_credentials_pending = %d receive_credentials_pending = %d\n", - transport->send_credentials_pending, - transport->receive_credentials_pending); - goto out; - } - -#define TRANSPORT_SIDE(t) ((t)->is_server ? "server" : "client") - switch (_dbus_auth_do_work (transport->auth)) - { - case DBUS_AUTH_STATE_WAITING_FOR_INPUT: - _dbus_verbose (" %s auth state: waiting for input\n", - TRANSPORT_SIDE (transport)); - if (!do_reading || !read_data_into_auth (transport, &oom)) - goto out; - break; - - case DBUS_AUTH_STATE_WAITING_FOR_MEMORY: - _dbus_verbose (" %s auth state: waiting for memory\n", - TRANSPORT_SIDE (transport)); - oom = TRUE; - goto out; - break; - - case DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND: - _dbus_verbose (" %s auth state: bytes to send\n", - TRANSPORT_SIDE (transport)); - if (!do_writing || !write_data_from_auth (transport)) - goto out; - break; - - case DBUS_AUTH_STATE_NEED_DISCONNECT: - _dbus_verbose (" %s auth state: need to disconnect\n", - TRANSPORT_SIDE (transport)); - do_io_error (transport); - break; - - case DBUS_AUTH_STATE_AUTHENTICATED: - _dbus_verbose (" %s auth state: authenticated\n", - TRANSPORT_SIDE (transport)); - break; - } - } - - out: - if (auth_completed) - *auth_completed = (orig_auth_state != _dbus_transport_get_is_authenticated (transport)); - - check_read_watch (transport); - check_write_watch (transport); - _dbus_transport_unref (transport); - - if (oom) - return FALSE; - else - return TRUE; -} - -/* returns false on oom */ -static dbus_bool_t -do_writing (DBusTransport *transport) -{ - int total; - DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; - dbus_bool_t oom; - - /* No messages without authentication! */ - if (!_dbus_transport_get_is_authenticated (transport)) - { - _dbus_verbose ("Not authenticated, not writing anything\n"); - return TRUE; - } - - if (transport->disconnected) - { - _dbus_verbose ("Not connected, not writing anything\n"); - return TRUE; - } - -#if 1 - _dbus_verbose ("do_writing(), have_messages = %d, fd = %d\n", - _dbus_connection_has_messages_to_send_unlocked (transport->connection), - unix_transport->fd); -#endif - - oom = FALSE; - total = 0; - - while (!transport->disconnected && - _dbus_connection_has_messages_to_send_unlocked (transport->connection)) - { - int bytes_written; - DBusMessage *message; - const DBusString *header; - const DBusString *body; - int header_len, body_len; - int total_bytes_to_write; - - if (total > unix_transport->max_bytes_written_per_iteration) - { - _dbus_verbose ("%d bytes exceeds %d bytes written per iteration, returning\n", - total, unix_transport->max_bytes_written_per_iteration); - goto out; - } - - message = _dbus_connection_get_message_to_send (transport->connection); - _dbus_assert (message != NULL); - _dbus_message_lock (message); - -#if 0 - _dbus_verbose ("writing message %p\n", message); -#endif - - _dbus_message_get_network_data (message, - &header, &body); - - header_len = _dbus_string_get_length (header); - body_len = _dbus_string_get_length (body); - - if (_dbus_auth_needs_encoding (transport->auth)) - { - if (_dbus_string_get_length (&unix_transport->encoded_outgoing) == 0) - { - if (!_dbus_auth_encode_data (transport->auth, - header, &unix_transport->encoded_outgoing)) - { - oom = TRUE; - goto out; - } - - if (!_dbus_auth_encode_data (transport->auth, - body, &unix_transport->encoded_outgoing)) - { - _dbus_string_set_length (&unix_transport->encoded_outgoing, 0); - oom = TRUE; - goto out; - } - } - - total_bytes_to_write = _dbus_string_get_length (&unix_transport->encoded_outgoing); - -#if 0 - _dbus_verbose ("encoded message is %d bytes\n", - total_bytes_to_write); -#endif - - bytes_written = - _dbus_write_socket (unix_transport->fd, - &unix_transport->encoded_outgoing, - unix_transport->message_bytes_written, - total_bytes_to_write - unix_transport->message_bytes_written); - } - else - { - total_bytes_to_write = header_len + body_len; - -#if 0 - _dbus_verbose ("message is %d bytes\n", - total_bytes_to_write); -#endif - - if (unix_transport->message_bytes_written < header_len) - { - bytes_written = - _dbus_write_socket_two (unix_transport->fd, - header, - unix_transport->message_bytes_written, - header_len - unix_transport->message_bytes_written, - body, - 0, body_len); - } - else - { - bytes_written = - _dbus_write_socket (unix_transport->fd, - body, - (unix_transport->message_bytes_written - header_len), - body_len - - (unix_transport->message_bytes_written - header_len)); - } - } - - if (bytes_written < 0) - { - /* EINTR already handled for us */ - - if (errno == EAGAIN || - errno == EWOULDBLOCK) - goto out; - else - { - _dbus_verbose ("Error writing to remote app: %s\n", - _dbus_strerror (errno)); - do_io_error (transport); - goto out; - } - } - else - { - _dbus_verbose (" wrote %d bytes of %d\n", bytes_written, - total_bytes_to_write); - - total += bytes_written; - unix_transport->message_bytes_written += bytes_written; - - _dbus_assert (unix_transport->message_bytes_written <= - total_bytes_to_write); - - if (unix_transport->message_bytes_written == total_bytes_to_write) - { - unix_transport->message_bytes_written = 0; - _dbus_string_set_length (&unix_transport->encoded_outgoing, 0); - - _dbus_connection_message_sent (transport->connection, - message); - } - } - } - - out: - if (oom) - return FALSE; - else - return TRUE; -} - -/* returns false on out-of-memory */ -static dbus_bool_t -do_reading (DBusTransport *transport) -{ - DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; - DBusString *buffer; - int bytes_read; - int total; - dbus_bool_t oom; - - _dbus_verbose ("%s: fd = %d\n", _DBUS_FUNCTION_NAME, - unix_transport->fd); - - /* No messages without authentication! */ - if (!_dbus_transport_get_is_authenticated (transport)) - return TRUE; - - oom = FALSE; - - total = 0; - - again: - - /* See if we've exceeded max messages and need to disable reading */ - check_read_watch (transport); - - if (total > unix_transport->max_bytes_read_per_iteration) - { - _dbus_verbose ("%d bytes exceeds %d bytes read per iteration, returning\n", - total, unix_transport->max_bytes_read_per_iteration); - goto out; - } - - _dbus_assert (unix_transport->read_watch != NULL || - transport->disconnected); - - if (transport->disconnected) - goto out; - - if (!dbus_watch_get_enabled (unix_transport->read_watch)) - return TRUE; - - if (_dbus_auth_needs_decoding (transport->auth)) - { - if (_dbus_string_get_length (&unix_transport->encoded_incoming) > 0) - bytes_read = _dbus_string_get_length (&unix_transport->encoded_incoming); - else - bytes_read = _dbus_read_socket (unix_transport->fd, - &unix_transport->encoded_incoming, - unix_transport->max_bytes_read_per_iteration); - - _dbus_assert (_dbus_string_get_length (&unix_transport->encoded_incoming) == - bytes_read); - - if (bytes_read > 0) - { - int orig_len; - - _dbus_message_loader_get_buffer (transport->loader, - &buffer); - - orig_len = _dbus_string_get_length (buffer); - - if (!_dbus_auth_decode_data (transport->auth, - &unix_transport->encoded_incoming, - buffer)) - { - _dbus_verbose ("Out of memory decoding incoming data\n"); - oom = TRUE; - goto out; - } - - _dbus_message_loader_return_buffer (transport->loader, - buffer, - _dbus_string_get_length (buffer) - orig_len); - - _dbus_string_set_length (&unix_transport->encoded_incoming, 0); - } - } - else - { - _dbus_message_loader_get_buffer (transport->loader, - &buffer); - - bytes_read = _dbus_read_socket (unix_transport->fd, - buffer, unix_transport->max_bytes_read_per_iteration); - - _dbus_message_loader_return_buffer (transport->loader, - buffer, - bytes_read < 0 ? 0 : bytes_read); - } - - if (bytes_read < 0) - { - /* EINTR already handled for us */ - - if (errno == ENOMEM) - { - _dbus_verbose ("Out of memory in read()/do_reading()\n"); - oom = TRUE; - goto out; - } - else if (errno == EAGAIN || - errno == EWOULDBLOCK) - goto out; - else - { - _dbus_verbose ("Error reading from remote app: %s\n", - _dbus_strerror (errno)); - do_io_error (transport); - goto out; - } - } - else if (bytes_read == 0) - { - _dbus_verbose ("Disconnected from remote app\n"); - do_io_error (transport); - goto out; - } - else - { - _dbus_verbose (" read %d bytes\n", bytes_read); - - total += bytes_read; - - if (!_dbus_transport_queue_messages (transport)) - { - oom = TRUE; - _dbus_verbose (" out of memory when queueing messages we just read in the transport\n"); - goto out; - } - - /* Try reading more data until we get EAGAIN and return, or - * exceed max bytes per iteration. If in blocking mode of - * course we'll block instead of returning. - */ - goto again; - } - - out: - if (oom) - return FALSE; - else - return TRUE; -} - -static dbus_bool_t -unix_handle_watch (DBusTransport *transport, - DBusWatch *watch, - unsigned int flags) -{ - DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; - - _dbus_assert (watch == unix_transport->read_watch || - watch == unix_transport->write_watch); - _dbus_assert (watch != NULL); - - /* Disconnect in case of an error. In case of hangup do not - * disconnect the transport because data can still be in the buffer - * and do_reading may need several iteration to read it all (because - * of its max_bytes_read_per_iteration limit). The condition where - * flags == HANGUP (without READABLE) probably never happen in fact. - */ - if ((flags & DBUS_WATCH_ERROR) || - ((flags & DBUS_WATCH_HANGUP) && !(flags & DBUS_WATCH_READABLE))) - { - _dbus_verbose ("Hang up or error on watch\n"); - _dbus_transport_disconnect (transport); - return TRUE; - } - - if (watch == unix_transport->read_watch && - (flags & DBUS_WATCH_READABLE)) - { - dbus_bool_t auth_finished; -#if 1 - _dbus_verbose ("handling read watch %p flags = %x\n", - watch, flags); -#endif - if (!do_authentication (transport, TRUE, FALSE, &auth_finished)) - return FALSE; - - /* We don't want to do a read immediately following - * a successful authentication. This is so we - * have a chance to propagate the authentication - * state further up. Specifically, we need to - * process any pending data from the auth object. - */ - if (!auth_finished) - { - if (!do_reading (transport)) - { - _dbus_verbose ("no memory to read\n"); - return FALSE; - } - } - else - { - _dbus_verbose ("Not reading anything since we just completed the authentication\n"); - } - } - else if (watch == unix_transport->write_watch && - (flags & DBUS_WATCH_WRITABLE)) - { -#if 1 - _dbus_verbose ("handling write watch, have_outgoing_messages = %d\n", - _dbus_connection_has_messages_to_send_unlocked (transport->connection)); -#endif - if (!do_authentication (transport, FALSE, TRUE, NULL)) - return FALSE; - - if (!do_writing (transport)) - { - _dbus_verbose ("no memory to write\n"); - return FALSE; - } - - /* See if we still need the write watch */ - check_write_watch (transport); - } -#ifdef DBUS_ENABLE_VERBOSE_MODE - else - { - if (watch == unix_transport->read_watch) - _dbus_verbose ("asked to handle read watch with non-read condition 0x%x\n", - flags); - else if (watch == unix_transport->write_watch) - _dbus_verbose ("asked to handle write watch with non-write condition 0x%x\n", - flags); - else - _dbus_verbose ("asked to handle watch %p on fd %d that we don't recognize\n", - watch, dbus_watch_get_fd (watch)); - } -#endif /* DBUS_ENABLE_VERBOSE_MODE */ - - return TRUE; -} - -static void -unix_disconnect (DBusTransport *transport) -{ - DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; - - _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); - - free_watches (transport); - - _dbus_close_socket (unix_transport->fd, NULL); - unix_transport->fd = -1; -} - -static dbus_bool_t -unix_connection_set (DBusTransport *transport) -{ - DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; - - _dbus_watch_set_handler (unix_transport->write_watch, - _dbus_connection_handle_watch, - transport->connection, NULL); - - _dbus_watch_set_handler (unix_transport->read_watch, - _dbus_connection_handle_watch, - transport->connection, NULL); - - if (!_dbus_connection_add_watch_unlocked (transport->connection, - unix_transport->write_watch)) - return FALSE; - - if (!_dbus_connection_add_watch_unlocked (transport->connection, - unix_transport->read_watch)) - { - _dbus_connection_remove_watch_unlocked (transport->connection, - unix_transport->write_watch); - return FALSE; - } - - check_read_watch (transport); - check_write_watch (transport); - - return TRUE; -} - -/** - * @todo We need to have a way to wake up the select sleep if - * a new iteration request comes in with a flag (read/write) that - * we're not currently serving. Otherwise a call that just reads - * could block a write call forever (if there are no incoming - * messages). - */ -static void -unix_do_iteration (DBusTransport *transport, - unsigned int flags, - int timeout_milliseconds) -{ - DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; - DBusPollFD poll_fd; - int poll_res; - int poll_timeout; - - _dbus_verbose (" iteration flags = %s%s timeout = %d read_watch = %p write_watch = %p fd = %d\n", - flags & DBUS_ITERATION_DO_READING ? "read" : "", - flags & DBUS_ITERATION_DO_WRITING ? "write" : "", - timeout_milliseconds, - unix_transport->read_watch, - unix_transport->write_watch, - unix_transport->fd); - - /* the passed in DO_READING/DO_WRITING flags indicate whether to - * read/write messages, but regardless of those we may need to block - * for reading/writing to do auth. But if we do reading for auth, - * we don't want to read any messages yet if not given DO_READING. - */ - - poll_fd.fd = unix_transport->fd; - poll_fd.events = 0; - - if (_dbus_transport_get_is_authenticated (transport)) - { - /* This is kind of a hack; if we have stuff to write, then try - * to avoid the poll. This is probably about a 5% speedup on an - * echo client/server. - * - * If both reading and writing were requested, we want to avoid this - * since it could have funky effects: - * - both ends spinning waiting for the other one to read - * data so they can finish writing - * - prioritizing all writing ahead of reading - */ - if ((flags & DBUS_ITERATION_DO_WRITING) && - !(flags & (DBUS_ITERATION_DO_READING | DBUS_ITERATION_BLOCK)) && - !transport->disconnected && - _dbus_connection_has_messages_to_send_unlocked (transport->connection)) - { - do_writing (transport); - - if (transport->disconnected || - !_dbus_connection_has_messages_to_send_unlocked (transport->connection)) - goto out; - } - - /* If we get here, we decided to do the poll() after all */ - _dbus_assert (unix_transport->read_watch); - if (flags & DBUS_ITERATION_DO_READING) - poll_fd.events |= _DBUS_POLLIN; - - _dbus_assert (unix_transport->write_watch); - if (flags & DBUS_ITERATION_DO_WRITING) - poll_fd.events |= _DBUS_POLLOUT; - } - else - { - DBusAuthState auth_state; - - auth_state = _dbus_auth_do_work (transport->auth); - - if (transport->receive_credentials_pending || - auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT) - poll_fd.events |= _DBUS_POLLIN; - - if (transport->send_credentials_pending || - auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND) - poll_fd.events |= _DBUS_POLLOUT; - } - - if (poll_fd.events) - { - if (flags & DBUS_ITERATION_BLOCK) - poll_timeout = timeout_milliseconds; - else - poll_timeout = 0; - - /* For blocking selects we drop the connection lock here - * to avoid blocking out connection access during a potentially - * indefinite blocking call. The io path is still protected - * by the io_path_cond condvar, so we won't reenter this. - */ - if (flags & DBUS_ITERATION_BLOCK) - { - _dbus_verbose ("unlock %s pre poll\n", _DBUS_FUNCTION_NAME); - _dbus_connection_unlock (transport->connection); - } - - again: - poll_res = _dbus_poll (&poll_fd, 1, poll_timeout); - - if (poll_res < 0 && errno == EINTR) - goto again; - - if (flags & DBUS_ITERATION_BLOCK) - { - _dbus_verbose ("lock %s post poll\n", _DBUS_FUNCTION_NAME); - _dbus_connection_lock (transport->connection); - } - - if (poll_res >= 0) - { - if (poll_res == 0) - poll_fd.revents = 0; /* some concern that posix does not guarantee this; - * valgrind flags it as an error. though it probably - * is guaranteed on linux at least. - */ - - if (poll_fd.revents & _DBUS_POLLERR) - do_io_error (transport); - else - { - dbus_bool_t need_read = (poll_fd.revents & _DBUS_POLLIN) > 0; - dbus_bool_t need_write = (poll_fd.revents & _DBUS_POLLOUT) > 0; - dbus_bool_t authentication_completed; - - _dbus_verbose ("in iteration, need_read=%d need_write=%d\n", - need_read, need_write); - do_authentication (transport, need_read, need_write, - &authentication_completed); - - /* See comment in unix_handle_watch. */ - if (authentication_completed) - goto out; - - if (need_read && (flags & DBUS_ITERATION_DO_READING)) - do_reading (transport); - if (need_write && (flags & DBUS_ITERATION_DO_WRITING)) - do_writing (transport); - } - } - else - { - _dbus_verbose ("Error from _dbus_poll(): %s\n", - _dbus_strerror (errno)); - } - } - - - out: - /* We need to install the write watch only if we did not - * successfully write everything. Note we need to be careful that we - * don't call check_write_watch *before* do_writing, since it's - * inefficient to add the write watch, and we can avoid it most of - * the time since we can write immediately. - * - * However, we MUST always call check_write_watch(); DBusConnection code - * relies on the fact that running an iteration will notice that - * messages are pending. - */ - check_write_watch (transport); - - _dbus_verbose (" ... leaving do_iteration()\n"); -} - -static void -unix_live_messages_changed (DBusTransport *transport) -{ - /* See if we should look for incoming messages again */ - check_read_watch (transport); -} - - -static dbus_bool_t -unix_get_unix_fd (DBusTransport *transport, - int *fd_p) -{ - DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; - - *fd_p = unix_transport->fd; - - return TRUE; -} - -static const DBusTransportVTable unix_vtable = { - unix_finalize, - unix_handle_watch, - unix_disconnect, - unix_connection_set, - unix_do_iteration, - unix_live_messages_changed, - unix_get_unix_fd -}; - -/** - * Creates a new transport for the given file descriptor. The file - * descriptor must be nonblocking (use _dbus_set_fd_nonblocking() to - * make it so). This function is shared by various transports that - * boil down to a full duplex file descriptor. - * - * @param fd the file descriptor. - * @param server_guid non-#NULL if this transport is on the server side of a connection - * @param address the transport's address - * @returns the new transport, or #NULL if no memory. - */ -DBusTransport* -_dbus_transport_new_for_fd (int fd, - const DBusString *server_guid, - const DBusString *address) -{ - DBusTransportUnix *unix_transport; - - unix_transport = dbus_new0 (DBusTransportUnix, 1); - if (unix_transport == NULL) - return NULL; - - if (!_dbus_string_init (&unix_transport->encoded_outgoing)) - goto failed_0; - - if (!_dbus_string_init (&unix_transport->encoded_incoming)) - goto failed_1; - - unix_transport->write_watch = _dbus_watch_new (fd, - DBUS_WATCH_WRITABLE, - FALSE, - NULL, NULL, NULL); - if (unix_transport->write_watch == NULL) - goto failed_2; - - unix_transport->read_watch = _dbus_watch_new (fd, - DBUS_WATCH_READABLE, - FALSE, - NULL, NULL, NULL); - if (unix_transport->read_watch == NULL) - goto failed_3; - - if (!_dbus_transport_init_base (&unix_transport->base, - &unix_vtable, - server_guid, address)) - goto failed_4; - - unix_transport->fd = fd; - unix_transport->message_bytes_written = 0; - - /* These values should probably be tunable or something. */ - unix_transport->max_bytes_read_per_iteration = 2048; - unix_transport->max_bytes_written_per_iteration = 2048; - - return (DBusTransport*) unix_transport; - - failed_4: - _dbus_watch_unref (unix_transport->read_watch); - failed_3: - _dbus_watch_unref (unix_transport->write_watch); - failed_2: - _dbus_string_free (&unix_transport->encoded_incoming); - failed_1: - _dbus_string_free (&unix_transport->encoded_outgoing); - failed_0: - dbus_free (unix_transport); - return NULL; -} - -/** * Creates a new transport for the given Unix domain socket * path. This creates a client-side of a transport. * @@ -1235,7 +89,7 @@ _dbus_transport_new_for_domain_socket (const char *path, _dbus_verbose ("Successfully connected to unix socket %s\n", path); - transport = _dbus_transport_new_for_fd (fd, NULL, &address); + transport = _dbus_transport_new_for_socket (fd, NULL, &address); if (transport == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); @@ -1253,74 +107,4 @@ _dbus_transport_new_for_domain_socket (const char *path, return NULL; } -/** - * Creates a new transport for the given hostname and port. - * - * @param host the host to connect to - * @param port the port 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, - DBusError *error) -{ - int fd; - DBusTransport *transport; - DBusString address; - - _DBUS_ASSERT_ERROR_IS_CLEAR (error); - - if (!_dbus_string_init (&address)) - { - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - return NULL; - } - - if (!_dbus_string_append (&address, "tcp:")) - goto error; - - if (host != NULL && - (!_dbus_string_append (&address, "host=") || - !_dbus_string_append (&address, host))) - goto error; - - if (!_dbus_string_append (&address, ",port=") || - !_dbus_string_append_int (&address, port)) - goto error; - - fd = _dbus_connect_tcp_socket (host, port, error); - if (fd < 0) - { - _DBUS_ASSERT_ERROR_IS_SET (error); - _dbus_string_free (&address); - return NULL; - } - - _dbus_fd_set_close_on_exec (fd); - - _dbus_verbose ("Successfully connected to tcp socket %s:%d\n", - host, port); - - transport = _dbus_transport_new_for_fd (fd, NULL, &address); - if (transport == NULL) - { - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - _dbus_close_socket (fd, NULL); - _dbus_string_free (&address); - fd = -1; - } - - _dbus_string_free (&address); - - return transport; - -error: - _dbus_string_free (&address); - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - return NULL; -} - /** @} */ - diff --git a/dbus/dbus-transport-unix.h b/dbus/dbus-transport-unix.h index 73986ba..ebd04ec 100644 --- a/dbus/dbus-transport-unix.h +++ b/dbus/dbus-transport-unix.h @@ -27,15 +27,9 @@ DBUS_BEGIN_DECLS -DBusTransport* _dbus_transport_new_for_fd (int fd, - const DBusString *server_guid, - const DBusString *address); DBusTransport* _dbus_transport_new_for_domain_socket (const char *path, dbus_bool_t abstract, DBusError *error); -DBusTransport* _dbus_transport_new_for_tcp_socket (const char *host, - dbus_int32_t port, - DBusError *error); DBUS_END_DECLS diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c index e155cc4..fd44595 100644 --- a/dbus/dbus-transport.c +++ b/dbus/dbus-transport.c @@ -23,6 +23,7 @@ #include "dbus-transport-protected.h" #include "dbus-transport-unix.h" +#include "dbus-transport-socket.h" #include "dbus-connection-internal.h" #include "dbus-watch.h" #include "dbus-auth.h" @@ -655,19 +656,19 @@ _dbus_transport_set_connection (DBusTransport *transport, } /** - * Get the UNIX file descriptor, if any. + * Get the socket file descriptor, if any. * * @param transport the transport * @param fd_p pointer to fill in with the descriptor * @returns #TRUE if a descriptor was available */ dbus_bool_t -_dbus_transport_get_unix_fd (DBusTransport *transport, - int *fd_p) +_dbus_transport_get_socket_fd (DBusTransport *transport, + int *fd_p) { dbus_bool_t retval; - if (transport->vtable->get_unix_fd == NULL) + if (transport->vtable->get_socket_fd == NULL) return FALSE; if (transport->disconnected) @@ -675,8 +676,8 @@ _dbus_transport_get_unix_fd (DBusTransport *transport, _dbus_transport_ref (transport); - retval = (* transport->vtable->get_unix_fd) (transport, - fd_p); + retval = (* transport->vtable->get_socket_fd) (transport, + fd_p); _dbus_transport_unref (transport); diff --git a/dbus/dbus-transport.h b/dbus/dbus-transport.h index 502cfb0..4784e46 100644 --- a/dbus/dbus-transport.h +++ b/dbus/dbus-transport.h @@ -56,11 +56,10 @@ long _dbus_transport_get_max_message_size (DBusTransport void _dbus_transport_set_max_received_size (DBusTransport *transport, long size); long _dbus_transport_get_max_received_size (DBusTransport *transport); +dbus_bool_t _dbus_transport_get_socket_fd (DBusTransport *transport, + int *fd_p); dbus_bool_t _dbus_transport_get_unix_user (DBusTransport *transport, unsigned long *uid); -dbus_bool_t _dbus_transport_get_unix_fd (DBusTransport *transport, - int *fd_p); - dbus_bool_t _dbus_transport_get_unix_process_id (DBusTransport *transport, unsigned long *pid); void _dbus_transport_set_unix_user_function (DBusTransport *transport, -- 2.7.4