summaryrefslogtreecommitdiff
path: root/dbus/dbus-transport-socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'dbus/dbus-transport-socket.c')
-rw-r--r--dbus/dbus-transport-socket.c264
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;
}
/**