diff options
Diffstat (limited to 'dbus/dbus-transport-socket.c')
-rw-r--r-- | dbus/dbus-transport-socket.c | 264 |
1 files changed, 184 insertions, 80 deletions
diff --git a/dbus/dbus-transport-socket.c b/dbus/dbus-transport-socket.c index 544d00a9..a3951ef4 100644 --- a/dbus/dbus-transport-socket.c +++ b/dbus/dbus-transport-socket.c @@ -22,6 +22,7 @@ */ #include <config.h> +#include <sys/ioctl.h> #include "dbus-internals.h" #include "dbus-connection-internal.h" #include "dbus-nonce.h" @@ -38,43 +39,13 @@ * @{ */ -/** - * 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 ("start\n"); - + if (socket_transport->read_watch) { if (transport->connection) @@ -104,7 +75,7 @@ socket_finalize (DBusTransport *transport) DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; _dbus_verbose ("\n"); - + free_watches (transport); _dbus_string_free (&socket_transport->encoded_outgoing); @@ -136,7 +107,16 @@ check_write_watch (DBusTransport *transport) _dbus_transport_ref (transport); if (_dbus_transport_get_is_authenticated (transport)) - needed = _dbus_connection_has_messages_to_send_unlocked (transport->connection); + { + if (!socket_transport->auth_notified && + socket_transport->vtable->authenticated != NULL) + { + socket_transport->auth_notified = TRUE; + socket_transport->vtable->authenticated (socket_transport); + } + + needed = _dbus_connection_has_messages_to_send_unlocked (transport->connection); + } else { if (transport->send_credentials_pending) @@ -146,7 +126,7 @@ check_write_watch (DBusTransport *transport) 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. @@ -191,9 +171,18 @@ check_read_watch (DBusTransport *transport) _dbus_transport_ref (transport); if (_dbus_transport_get_is_authenticated (transport)) - need_read_watch = - (_dbus_counter_get_size_value (transport->live_messages) < transport->max_live_messages_size) && - (_dbus_counter_get_unix_fd_value (transport->live_messages) < transport->max_live_messages_unix_fds); + { + if (!socket_transport->auth_notified && + socket_transport->vtable->authenticated != NULL) + { + socket_transport->auth_notified = TRUE; + socket_transport->vtable->authenticated (socket_transport); + } + + need_read_watch = + (_dbus_counter_get_size_value (transport->live_messages) < transport->max_live_messages_size) && + (_dbus_counter_get_unix_fd_value (transport->live_messages) < transport->max_live_messages_unix_fds); + } else { if (transport->receive_credentials_pending) @@ -489,6 +478,59 @@ do_authentication (DBusTransport *transport, return TRUE; } +static int +_write_socket (DBusTransportSocket *socket_transport, + DBusMessage *message, + const DBusString *buffer, + int start, + int len) +{ + int bytes_written; + + if (socket_transport->vtable->write_socket != NULL) + { + bytes_written = socket_transport->vtable->write_socket (socket_transport, + message, + buffer, start, len); + } + else + { + bytes_written = _dbus_write_socket (socket_transport->fd, + buffer, + start, len); + } + + return bytes_written; +} + +static int +_write_socket_two (DBusTransportSocket *socket_transport, + DBusMessage *message, + const DBusString *header, + int header_start, + int header_len, + const DBusString *body, + int body_start, + int body_len) +{ + int bytes_written; + + if (socket_transport->vtable->write_socket_two != NULL) + { + bytes_written = socket_transport->vtable->write_socket_two (socket_transport, message, + header, header_start, header_len, + body, body_start, body_len); + } + else + { + bytes_written = _dbus_write_socket_two (socket_transport->fd, + header, header_start, header_len, + body, body_start, body_len); + } + + return bytes_written; +} + /* returns false on oom */ static dbus_bool_t do_writing (DBusTransport *transport) @@ -579,12 +621,13 @@ do_writing (DBusTransport *transport) _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); + _write_socket (socket_transport, + message, + &socket_transport->encoded_outgoing, + socket_transport->message_bytes_written, + total_bytes_to_write - socket_transport->message_bytes_written); } else { @@ -623,21 +666,23 @@ do_writing (DBusTransport *transport) 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); + _write_socket_two (socket_transport, + message, + 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)); + _write_socket (socket_transport, + message, + body, + (socket_transport->message_bytes_written - header_len), + body_len - + (socket_transport->message_bytes_written - header_len)); } } } @@ -696,7 +741,7 @@ do_reading (DBusTransport *transport) { DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; DBusString *buffer; - int bytes_read; + int bytes_read, bytes_available; int total; dbus_bool_t oom; @@ -730,7 +775,12 @@ do_reading (DBusTransport *transport) if (!dbus_watch_get_enabled (socket_transport->read_watch)) return TRUE; - + + if (ioctl (socket_transport->fd, FIONREAD, &bytes_available) < 0) + bytes_available = socket_transport->max_bytes_read_per_iteration; + else if (bytes_available < socket_transport->max_bytes_read_per_iteration) + bytes_available = socket_transport->max_bytes_read_per_iteration; + if (_dbus_auth_needs_decoding (transport->auth)) { /* Does fd passing even make sense with encoded data? */ @@ -741,7 +791,7 @@ do_reading (DBusTransport *transport) else bytes_read = _dbus_read_socket (socket_transport->fd, &socket_transport->encoded_incoming, - socket_transport->max_bytes_read_per_iteration); + bytes_available); _dbus_assert (_dbus_string_get_length (&socket_transport->encoded_incoming) == bytes_read); @@ -796,7 +846,7 @@ do_reading (DBusTransport *transport) bytes_read = _dbus_read_socket_with_unix_fds(socket_transport->fd, buffer, - socket_transport->max_bytes_read_per_iteration, + bytes_available, fds, &n_fds); if (bytes_read >= 0 && n_fds > 0) @@ -808,7 +858,7 @@ do_reading (DBusTransport *transport) #endif { bytes_read = _dbus_read_socket (socket_transport->fd, - buffer, socket_transport->max_bytes_read_per_iteration); + buffer, bytes_available); } _dbus_message_loader_return_buffer (transport->loader, @@ -1207,6 +1257,19 @@ socket_get_socket_fd (DBusTransport *transport, return TRUE; } +static void +socket_process_incoming_message (DBusTransport *transport, + DBusMessage *message) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + + if (socket_transport->vtable->message_received != NULL) + { + (* socket_transport->vtable->message_received) (socket_transport, + message); + } +} + static const DBusTransportVTable socket_vtable = { socket_finalize, socket_handle_watch, @@ -1214,37 +1277,40 @@ static const DBusTransportVTable socket_vtable = { socket_connection_set, socket_do_iteration, socket_live_messages_changed, - socket_get_socket_fd + socket_get_socket_fd, + socket_process_incoming_message }; /** - * 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. + * Initializes the base class members of DBusTransportSocket. Chained up to + * by subclasses in their constructor. The server GUID is the + * globally unique ID for the server creating this connection + * and will be #NULL for the client side of a connection. The GUID + * is in hex format. * - * @param fd the file descriptor. + * @param socket_transport the transport being created. + * @param fd The socket for this transport + * @param vtable the subclass vtable. * @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. + * @param address the address of the transport + * @returns #TRUE on success. */ -DBusTransport* -_dbus_transport_new_for_socket (int fd, - const DBusString *server_guid, - const DBusString *address) +dbus_bool_t +_dbus_transport_socket_init_base (DBusTransportSocket *socket_transport, + int fd, + const DBusTransportSocketVTable *vtable, + 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->auth_notified = FALSE; + socket_transport->vtable = vtable; + socket_transport->write_watch = _dbus_watch_new (fd, DBUS_WATCH_WRITABLE, FALSE, @@ -1275,7 +1341,7 @@ _dbus_transport_new_for_socket (int fd, socket_transport->max_bytes_read_per_iteration = 2048; socket_transport->max_bytes_written_per_iteration = 2048; - return (DBusTransport*) socket_transport; + return TRUE; failed_4: _dbus_watch_invalidate (socket_transport->read_watch); @@ -1288,8 +1354,46 @@ _dbus_transport_new_for_socket (int fd, failed_1: _dbus_string_free (&socket_transport->encoded_outgoing); failed_0: - dbus_free (socket_transport); - return NULL; + + return FALSE; +} + +/** + * 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; + static const DBusTransportSocketVTable vtable = { + NULL + }; + + socket_transport = dbus_new0 (DBusTransportSocket, 1); + if (socket_transport == NULL) + return NULL; + + if (!_dbus_transport_socket_init_base (socket_transport, + fd, + &vtable, + server_guid, + address)) + { + dbus_free (socket_transport); + return NULL; + } + + return (DBusTransport *) socket_transport; } /** |