diff options
Diffstat (limited to 'dbus')
-rw-r--r-- | dbus/Makefile.am | 2 | ||||
-rw-r--r-- | dbus/dbus-connection.c | 72 | ||||
-rw-r--r-- | dbus/dbus-connection.h | 8 | ||||
-rw-r--r-- | dbus/dbus-marshal.c | 13 | ||||
-rw-r--r-- | dbus/dbus-message-internal.h | 8 | ||||
-rw-r--r-- | dbus/dbus-message.c | 148 | ||||
-rw-r--r-- | dbus/dbus-resources.c | 191 | ||||
-rw-r--r-- | dbus/dbus-resources.h | 52 | ||||
-rw-r--r-- | dbus/dbus-transport-protected.h | 10 | ||||
-rw-r--r-- | dbus/dbus-transport-unix.c | 147 | ||||
-rw-r--r-- | dbus/dbus-transport.c | 105 | ||||
-rw-r--r-- | dbus/dbus-transport.h | 41 |
12 files changed, 714 insertions, 83 deletions
diff --git a/dbus/Makefile.am b/dbus/Makefile.am index 955b793f..b9d97da4 100644 --- a/dbus/Makefile.am +++ b/dbus/Makefile.am @@ -28,6 +28,8 @@ libdbus_1_la_SOURCES= \ dbus-message.c \ dbus-message-handler.c \ dbus-message-internal.h \ + dbus-resources.c \ + dbus-resources.h \ dbus-server.c \ dbus-server-protected.h \ dbus-server-unix.c \ diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 073da8f3..5ffbc57a 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -1,7 +1,7 @@ /* -*- mode: C; c-file-style: "gnu" -*- */ /* dbus-connection.c DBusConnection object * - * Copyright (C) 2002 Red Hat Inc. + * Copyright (C) 2002, 2003 Red Hat Inc. * * Licensed under the Academic Free License version 1.2 * @@ -1274,4 +1274,74 @@ _dbus_connection_free_data_slots (DBusConnection *connection) connection->n_slots = 0; } +/** + * Specifies the maximum size message this connection is allowed to + * receive. Larger messages will result in disconnecting the + * connection. + * + * @param connection a #DBusConnection + * @param size maximum message size the connection can receive, in bytes + */ +void +dbus_connection_set_max_message_size (DBusConnection *connection, + long size) +{ + _dbus_transport_set_max_message_size (connection->transport, + size); +} + +/** + * Gets the value set by dbus_connection_set_max_message_size(). + * + * @param connection the connection + * @returns the max size of a single message + */ +long +dbus_connection_get_max_message_size (DBusConnection *connection) +{ + return _dbus_transport_get_max_message_size (connection->transport); +} + +/** + * Sets the maximum total number of bytes that can be used for all messages + * received on this connection. Messages count toward the maximum until + * they are finalized. When the maximum is reached, the connection will + * not read more data until some messages are finalized. + * + * The semantics of the maximum are: if outstanding messages are + * already above the maximum, additional messages will not be read. + * The semantics are not: if the next message would cause us to exceed + * the maximum, we don't read it. The reason is that we don't know the + * size of a message until after we read it. + * + * Thus, the max live messages size can actually be exceeded + * by up to the maximum size of a single message. + * + * Also, if we read say 1024 bytes off the wire in a single read(), + * and that contains a half-dozen small messages, we may exceed the + * size max by that amount. But this should be inconsequential. + * + * @param connection the connection + * @param size the maximum size in bytes of all outstanding messages + */ +void +dbus_connection_set_max_live_messages_size (DBusConnection *connection, + long size) +{ + _dbus_transport_set_max_live_messages_size (connection->transport, + size); +} + +/** + * Gets the value set by dbus_connection_set_max_live_messages_size(). + * + * @param connection the connection + * @returns the max size of all live messages + */ +long +dbus_connection_get_max_live_messages_size (DBusConnection *connection) +{ + return _dbus_transport_get_max_live_messages_size (connection->transport); +} + /** @} */ diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index d0211b42..31653a50 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -132,6 +132,14 @@ dbus_bool_t dbus_connection_set_data (DBusConnection *connection, void* dbus_connection_get_data (DBusConnection *connection, int slot); +void dbus_connection_set_max_message_size (DBusConnection *connection, + long size); +long dbus_connection_get_max_message_size (DBusConnection *connection); +void dbus_connection_set_max_live_messages_size (DBusConnection *connection, + long size); +long dbus_connection_get_max_live_messages_size (DBusConnection *connection); + + DBUS_END_DECLS; #endif /* DBUS_CONNECTION_H */ diff --git a/dbus/dbus-marshal.c b/dbus/dbus-marshal.c index a6055806..395c2cce 100644 --- a/dbus/dbus-marshal.c +++ b/dbus/dbus-marshal.c @@ -401,6 +401,19 @@ _dbus_demarshal_string (DBusString *str, return retval; } +/** + * Demarshals a byte array. + * + * @todo Should probably demarshal to a DBusString, + * having memcpy() in here is Evil(tm). + * + * @param str the string containing the data + * @param byte_order the byte order + * @param pos the position in the string + * @param new_pos the new position of the string + * @param array_len length of the demarshaled data + * @returns the demarshaled data. + */ unsigned char * _dbus_demarshal_byte_array (DBusString *str, int byte_order, diff --git a/dbus/dbus-message-internal.h b/dbus/dbus-message-internal.h index c57af04f..5ec7ad9d 100644 --- a/dbus/dbus-message-internal.h +++ b/dbus/dbus-message-internal.h @@ -24,6 +24,7 @@ #define DBUS_MESSAGE_INTERNAL_H #include <dbus/dbus-message.h> +#include <dbus/dbus-resources.h> DBUS_BEGIN_DECLS; @@ -38,6 +39,9 @@ void _dbus_message_lock (DBusMessage *message); void _dbus_message_set_client_serial (DBusMessage *message, dbus_int32_t client_serial); +void _dbus_message_add_size_counter (DBusMessage *message, + DBusCounter *counter); + DBusMessageLoader* _dbus_message_loader_new (void); void _dbus_message_loader_ref (DBusMessageLoader *loader); void _dbus_message_loader_unref (DBusMessageLoader *loader); @@ -52,6 +56,10 @@ DBusMessage* _dbus_message_loader_pop_message (DBusMessageLoader dbus_bool_t _dbus_message_loader_get_is_corrupted (DBusMessageLoader *loader); +void _dbus_message_loader_set_max_message_size (DBusMessageLoader *loader, + long size); +long _dbus_message_loader_get_max_message_size (DBusMessageLoader *loader); + DBUS_END_DECLS; #endif /* DBUS_MESSAGE_H */ diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 3bd92803..6206815f 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -1,7 +1,7 @@ /* -*- mode: C; c-file-style: "gnu" -*- */ /* dbus-message.c DBusMessage object * - * Copyright (C) 2002 Red Hat Inc. + * Copyright (C) 2002, 2003 Red Hat Inc. * Copyright (C) 2002, 2003 CodeFactory AB * * Licensed under the Academic Free License version 1.2 @@ -41,13 +41,6 @@ */ /** - * The largest-length message we allow - * - * @todo match this up with whatever the protocol spec says. - */ -#define _DBUS_MAX_MESSAGE_LENGTH (_DBUS_INT_MAX/16) - -/** * @brief Internals of DBusMessage * * Object representing a message received from or to be sent to @@ -72,6 +65,9 @@ struct DBusMessage dbus_int32_t client_serial; /**< Client serial or -1 if not set */ dbus_int32_t reply_serial; /**< Reply serial or -1 if not set */ + + DBusCounter *size_counter; /**< Counter for the size of the message, or #NULL */ + long size_counter_delta; /**< Size we incremented the size counter by. */ unsigned int locked : 1; /**< Message being sent, no modifications allowed. */ }; @@ -127,6 +123,39 @@ _dbus_message_set_client_serial (DBusMessage *message, message->client_serial = client_serial; } +/** + * Adds a counter to be incremented immediately with the + * size of this message, and decremented by the size + * of this message when this message if finalized. + * + * @param message the message + * @param counter the counter + */ +void +_dbus_message_add_size_counter (DBusMessage *message, + DBusCounter *counter) +{ + _dbus_assert (message->size_counter == NULL); /* If this fails we may need to keep a list of + * counters instead of just one + */ + + message->size_counter = counter; + _dbus_counter_ref (message->size_counter); + + /* When we can change message size, we may want to + * update this each time we do so, or we may want to + * just KISS like this. + */ + message->size_counter_delta = + _dbus_string_get_length (&message->header) + + _dbus_string_get_length (&message->body); + + _dbus_verbose ("message has size %ld\n", + message->size_counter_delta); + + _dbus_counter_adjust (message->size_counter, message->size_counter_delta); +} + static void dbus_message_write_header (DBusMessage *message) { @@ -253,7 +282,7 @@ dbus_message_new (const char *service, message->client_serial = -1; message->reply_serial = -1; - if (!_dbus_string_init (&message->header, _DBUS_MAX_MESSAGE_LENGTH)) + if (!_dbus_string_init (&message->header, _DBUS_INT_MAX)) { dbus_free (message->service); dbus_free (message->name); @@ -261,7 +290,7 @@ dbus_message_new (const char *service, return NULL; } - if (!_dbus_string_init (&message->body, _DBUS_MAX_MESSAGE_LENGTH)) + if (!_dbus_string_init (&message->body, _DBUS_INT_MAX)) { dbus_free (message->service); dbus_free (message->name); @@ -302,6 +331,13 @@ dbus_message_unref (DBusMessage *message) message->refcount -= 1; if (message->refcount == 0) { + if (message->size_counter != NULL) + { + _dbus_counter_adjust (message->size_counter, + - message->size_counter_delta); + _dbus_counter_unref (message->size_counter); + } + _dbus_string_free (&message->header); _dbus_string_free (&message->body); @@ -330,7 +366,7 @@ dbus_message_get_name (DBusMessage *message) * The list is terminated with 0. * * @param message the message - * @param type of the first field + * @param first_field_type type of the first field * @param ... value of first field, list of additional type-value pairs * @returns #TRUE on success */ @@ -886,8 +922,21 @@ dbus_message_iter_get_double (DBusMessageIter *iter) iter->pos + 1, NULL); } +/** + * Returns the byte array that the iterator may point to. + * Note that you need to check that the iterator points + * to a byte array prior to using this function. + * + * @todo this function should probably take "unsigned char **" as + * an out param argument, and return boolean or result code. + * + * @param iter the iterator + * @param len return location for length of byte array + * @returns the byte array + */ unsigned char * -dbus_message_iter_get_byte_array (DBusMessageIter *iter, int *len) +dbus_message_iter_get_byte_array (DBusMessageIter *iter, + int *len) { _dbus_assert (dbus_message_iter_get_field_type (iter) == DBUS_TYPE_BYTE_ARRAY); @@ -926,6 +975,8 @@ struct DBusMessageLoader DBusString data; /**< Buffered data */ DBusList *messages; /**< Complete messages. */ + + long max_message_size; /**< Maximum size of a message */ unsigned int buffer_outstanding : 1; /**< Someone is using the buffer to read */ @@ -959,8 +1010,13 @@ _dbus_message_loader_new (void) if (loader == NULL) return NULL; - loader->refcount = 1; + loader->refcount = 1; + /* Try to cap message size at something that won't *totally* hose + * the system if we have a couple of them. + */ + loader->max_message_size = _DBUS_ONE_MEGABYTE * 32; + if (!_dbus_string_init (&loader->data, _DBUS_INT_MAX)) { dbus_free (loader); @@ -1190,10 +1246,10 @@ _dbus_message_loader_return_buffer (DBusMessageLoader *loader, header_len = _dbus_unpack_int32 (byte_order, header_data + 4); body_len = _dbus_unpack_int32 (byte_order, header_data + 8); - if (header_len + body_len > _DBUS_MAX_MESSAGE_LENGTH) + if (header_len + body_len > loader->max_message_size) { _dbus_verbose ("Message claimed length header = %d body = %d exceeds max message length %d\n", - header_len, body_len, _DBUS_MAX_MESSAGE_LENGTH); + header_len, body_len, loader->max_message_size); loader->corrupted = TRUE; return; } @@ -1220,13 +1276,40 @@ _dbus_message_loader_return_buffer (DBusMessageLoader *loader, if (message == NULL) break; /* ugh, postpone this I guess. */ + + if (!_dbus_list_append (&loader->messages, message)) + { + dbus_message_unref (message); + break; + } - _dbus_string_copy (&loader->data, header_len, &message->body, 0); - _dbus_message_set_client_serial (message, client_serial); - - _dbus_list_append (&loader->messages, message); - _dbus_string_delete (&loader->data, 0, header_len + body_len); + _dbus_assert (_dbus_string_get_length (&message->header) == 0); + _dbus_assert (_dbus_string_get_length (&message->body) == 0); + + if (!_dbus_string_move_len (&loader->data, 0, header_len, &message->header, 0)) + { + _dbus_list_remove_last (&loader->messages, message); + dbus_message_unref (message); + break; + } + + if (!_dbus_string_move_len (&loader->data, 0, body_len, &message->body, 0)) + { + dbus_bool_t result; + + /* put the header back, we'll try again later */ + result = _dbus_string_copy_len (&message->header, 0, header_len, + &loader->data, 0); + _dbus_assert (result); /* because DBusString never reallocs smaller */ + _dbus_list_remove_last (&loader->messages, message); + dbus_message_unref (message); + break; + } + + _dbus_assert (_dbus_string_get_length (&message->header) == header_len); + _dbus_assert (_dbus_string_get_length (&message->body) == body_len); + _dbus_verbose ("Loaded message %p\n", message); } else @@ -1264,6 +1347,31 @@ _dbus_message_loader_get_is_corrupted (DBusMessageLoader *loader) return loader->corrupted; } +/** + * Sets the maximum size message we allow. + * + * @param loader the loader + * @param size the max message size in bytes + */ +void +_dbus_message_loader_set_max_message_size (DBusMessageLoader *loader, + long size) +{ + loader->max_message_size = size; +} + +/** + * Gets the maximum allowed message size in bytes. + * + * @param loader the loader + * @returns max size in bytes + */ +long +_dbus_message_loader_get_max_message_size (DBusMessageLoader *loader) +{ + return loader->max_message_size; +} + /** @} */ #ifdef DBUS_BUILD_TESTS #include "dbus-test.h" diff --git a/dbus/dbus-resources.c b/dbus/dbus-resources.c new file mode 100644 index 00000000..edc2e788 --- /dev/null +++ b/dbus/dbus-resources.c @@ -0,0 +1,191 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-resources.c Resource tracking/limits + * + * Copyright (C) 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * 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/dbus-resources.h> +#include <dbus/dbus-internals.h> + +/** + * @defgroup DBusResources Resource limits related code + * @ingroup DBusInternals + * @brief DBusCounter and other stuff related to resource limits + * + * Types and functions related to tracking resource limits, + * such as the maximum amount of memory a connection can use + * for messages, etc. + */ + +/** + * @defgroup DBusResourcesInternals Resource limits implementation details + * @ingroup DBusInternals + * @brief Resource limits implementation details + * + * Implementation details of resource limits code. + * + * @{ + */ + +/** + * @brief Internals of DBusCounter. + * + * DBusCounter internals. DBusCounter is an opaque object, it must be + * used via accessor functions. + */ +struct DBusCounter +{ + int refcount; /**< reference count */ + + long value; /**< current counter value */ + + long notify_guard_value; /**< call notify function when crossing this value */ + DBusCounterNotifyFunction notify_function; /**< notify function */ + void *notify_data; /**< data for notify function */ +}; + +/** @} */ /* end of resource limits internals docs */ + +/** + * @addtogroup DBusResources + * @{ + */ + +/** + * Creates a new DBusCounter. DBusCounter is used + * to count usage of some resource such as memory. + * + * @returns new counter or #NULL on failure + */ +DBusCounter* +_dbus_counter_new (void) +{ + DBusCounter *counter; + + counter = dbus_new (DBusCounter, 1); + if (counter == NULL) + return NULL; + + counter->refcount = 1; + counter->value = 0; + + counter->notify_guard_value = 0; + counter->notify_function = NULL; + counter->notify_data = NULL; + + return counter; +} + +/** + * Increments refcount of the counter + * + * @param counter the counter + */ +void +_dbus_counter_ref (DBusCounter *counter) +{ + _dbus_assert (counter->refcount > 0); + + counter->refcount += 1; +} + +/** + * Decrements refcount of the counter and possibly + * finalizes the counter. + * + * @param counter the counter + */ +void +_dbus_counter_unref (DBusCounter *counter) +{ + _dbus_assert (counter->refcount > 0); + + counter->refcount -= 1; + + if (counter->refcount == 0) + { + + dbus_free (counter); + } +} + +/** + * Adjusts the value of the counter by the given + * delta which may be positive or negative. + * Calls the notify function from _dbus_counter_set_notify() + * if that function has been specified. + * + * @param counter the counter + * @param delta value to add to the counter's current value + */ +void +_dbus_counter_adjust (DBusCounter *counter, + long delta) +{ + long old = counter->value; + + counter->value += delta; + +#if 0 + _dbus_verbose ("Adjusting counter %ld by %ld = %ld\n", + old, delta, counter->value); +#endif + + if (counter->notify_function != NULL && + ((old < counter->notify_guard_value && + counter->value >= counter->notify_guard_value) || + (old >= counter->notify_guard_value && + counter->value < counter->notify_guard_value))) + (* counter->notify_function) (counter, counter->notify_data); +} + +/** + * Gets the current value of the counter. + * + * @param counter the counter + * @returns its current value + */ +long +_dbus_counter_get_value (DBusCounter *counter) +{ + return counter->value; +} + +/** + * Sets the notify function for this counter; the notify function is + * called whenever the counter's value crosses the guard value in + * either direction (moving up, or moving down). + * + * @param counter the counter + * @param guard_value the value we're notified if the counter crosses + * @param function function to call in order to notify + * @param user_data data to pass to the function + */ +void +_dbus_counter_set_notify (DBusCounter *counter, + long guard_value, + DBusCounterNotifyFunction function, + void *user_data) +{ + counter->notify_guard_value = guard_value; + counter->notify_function = function; + counter->notify_data = user_data; +} + +/** @} */ /* end of resource limits exported API */ diff --git a/dbus/dbus-resources.h b/dbus/dbus-resources.h new file mode 100644 index 00000000..26a5b98c --- /dev/null +++ b/dbus/dbus-resources.h @@ -0,0 +1,52 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-resources.h Resource tracking/limits + * + * Copyright (C) 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * 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_RESOURCES_H +#define DBUS_RESOURCES_H + +#include <dbus/dbus-macros.h> +#include <dbus/dbus-errors.h> +#include <dbus/dbus-connection.h> + +DBUS_BEGIN_DECLS; + +typedef struct DBusCounter DBusCounter; + +typedef void (* DBusCounterNotifyFunction) (DBusCounter *counter, + void *user_data); + +DBusCounter* _dbus_counter_new (void); +void _dbus_counter_ref (DBusCounter *counter); +void _dbus_counter_unref (DBusCounter *counter); +void _dbus_counter_adjust (DBusCounter *counter, + long delta); +long _dbus_counter_get_value (DBusCounter *counter); + +void _dbus_counter_set_notify (DBusCounter *counter, + long guard_value, + DBusCounterNotifyFunction function, + void *user_data); + + +DBUS_END_DECLS; + +#endif /* DBUS_RESOURCES_H */ diff --git a/dbus/dbus-transport-protected.h b/dbus/dbus-transport-protected.h index b9bbb40d..46dfe141 100644 --- a/dbus/dbus-transport-protected.h +++ b/dbus/dbus-transport-protected.h @@ -28,6 +28,7 @@ #include <dbus/dbus-transport.h> #include <dbus/dbus-message-internal.h> #include <dbus/dbus-auth.h> +#include <dbus/dbus-resources.h> DBUS_BEGIN_DECLS; @@ -63,6 +64,9 @@ struct DBusTransportVTable /**< Called to do a single "iteration" (block on select/poll * followed by reading or writing data). */ + + void (* live_messages_changed) (DBusTransport *transport); + /**< Outstanding messages counter changed */ }; struct DBusTransport @@ -77,7 +81,11 @@ struct DBusTransport DBusAuth *auth; /**< Authentication conversation */ - DBusCredentials credentials; /**< Credentials of other end */ + DBusCredentials credentials; /**< Credentials of other end */ + + long max_live_messages_size; /**< Max total size of received messages. */ + + DBusCounter *live_messages_size; /**< Counter for size of all live messages. */ unsigned int disconnected : 1; /**< #TRUE if we are disconnected. */ unsigned int authenticated : 1; /**< Cache of auth state; use _dbus_transport_get_is_authenticated() to query value */ diff --git a/dbus/dbus-transport-unix.c b/dbus/dbus-transport-unix.c index be1ab441..ef50863d 100644 --- a/dbus/dbus-transport-unix.c +++ b/dbus/dbus-transport-unix.c @@ -1,7 +1,7 @@ /* -*- mode: C; c-file-style: "gnu" -*- */ /* dbus-transport-unix.c UNIX socket subclasses of DBusTransport * - * Copyright (C) 2002 Red Hat Inc. + * Copyright (C) 2002, 2003 Red Hat Inc. * * Licensed under the Academic Free License version 1.2 * @@ -51,7 +51,7 @@ struct DBusTransportUnix { DBusTransport base; /**< Parent instance */ int fd; /**< File descriptor. */ - DBusWatch *watch; /**< Watch for readability. */ + DBusWatch *read_watch; /**< Watch for readability. */ DBusWatch *write_watch; /**< Watch for writability. */ int max_bytes_read_per_iteration; /**< To avoid blocking too long. */ @@ -71,14 +71,14 @@ free_watches (DBusTransport *transport) { DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; - if (unix_transport->watch) + if (unix_transport->read_watch) { if (transport->connection) _dbus_connection_remove_watch (transport->connection, - unix_transport->watch); - _dbus_watch_invalidate (unix_transport->watch); - _dbus_watch_unref (unix_transport->watch); - unix_transport->watch = NULL; + 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) @@ -103,7 +103,7 @@ unix_finalize (DBusTransport *transport) _dbus_transport_finalize_base (transport); - _dbus_assert (unix_transport->watch == NULL); + _dbus_assert (unix_transport->read_watch == NULL); _dbus_assert (unix_transport->write_watch == NULL); dbus_free (transport); @@ -138,7 +138,7 @@ check_write_watch (DBusTransport *transport) /* we can maybe add it some other time, just silently bomb */ if (unix_transport->write_watch == NULL) - return; + goto out; if (!_dbus_connection_add_watch (transport->connection, unix_transport->write_watch)) @@ -158,6 +158,63 @@ check_write_watch (DBusTransport *transport) unix_transport->write_watch = NULL; } + out: + _dbus_transport_unref (transport); +} + +static void +check_read_watch (DBusTransport *transport) +{ + DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; + dbus_bool_t need_read_watch; + + if (transport->connection == NULL) + return; + + _dbus_transport_ref (transport); + + need_read_watch = + _dbus_counter_get_value (transport->live_messages_size) < transport->max_live_messages_size; + + if (transport->disconnected) + need_read_watch = FALSE; + + if (need_read_watch && + unix_transport->read_watch == NULL) + { + _dbus_verbose ("Adding read watch to unix fd %d\n", + unix_transport->fd); + + unix_transport->read_watch = + _dbus_watch_new (unix_transport->fd, + DBUS_WATCH_READABLE); + + /* we can maybe add it some other time, just silently bomb */ + if (unix_transport->read_watch == NULL) + goto out; + + if (!_dbus_connection_add_watch (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; + } + } + else if (!need_read_watch && + unix_transport->read_watch != NULL) + { + _dbus_verbose ("Removing read watch from unix fd %d\n", + unix_transport->fd); + + _dbus_connection_remove_watch (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; + } + + out: _dbus_transport_unref (transport); } @@ -178,7 +235,8 @@ queue_messages (DBusTransport *transport) while ((message = _dbus_message_loader_pop_message (transport->loader))) { _dbus_verbose ("queueing received message %p\n", message); - + + _dbus_message_add_size_counter (message, transport->live_messages_size); _dbus_connection_queue_received_message (transport->connection, message); dbus_message_unref (message); @@ -189,6 +247,9 @@ queue_messages (DBusTransport *transport) _dbus_verbose ("Corrupted message stream, disconnecting\n"); do_io_error (transport); } + + /* check read watch in case we've now exceeded max outstanding messages */ + check_read_watch (transport); } /* return value is whether we successfully read any new data. */ @@ -526,6 +587,12 @@ do_writing (DBusTransport *transport) total, unix_transport->max_bytes_written_per_iteration); goto out; } + + if (unix_transport->write_watch == NULL) + { + _dbus_verbose ("write watch removed, not writing more stuff\n"); + goto out; + } message = _dbus_connection_get_message_to_send (transport->connection); _dbus_assert (message != NULL); @@ -650,6 +717,11 @@ do_reading (DBusTransport *transport) total = 0; again: + + /* See if we've exceeded max messages and need to disable reading */ + check_read_watch (transport); + if (unix_transport->read_watch == NULL) + return; if (total > unix_transport->max_bytes_read_per_iteration) { @@ -761,7 +833,7 @@ unix_handle_watch (DBusTransport *transport, { DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; - _dbus_assert (watch == unix_transport->watch || + _dbus_assert (watch == unix_transport->read_watch || watch == unix_transport->write_watch); if (flags & (DBUS_WATCH_HANGUP | DBUS_WATCH_ERROR)) @@ -770,7 +842,7 @@ unix_handle_watch (DBusTransport *transport, return; } - if (watch == unix_transport->watch && + if (watch == unix_transport->read_watch && (flags & DBUS_WATCH_READABLE)) { _dbus_verbose ("handling read watch\n"); @@ -800,30 +872,7 @@ unix_disconnect (DBusTransport *transport) static void unix_connection_set (DBusTransport *transport) { - DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; - DBusWatch *watch; - - _dbus_assert (unix_transport->watch == NULL); - - watch = _dbus_watch_new (unix_transport->fd, - DBUS_WATCH_READABLE); - - if (watch == NULL) - { - _dbus_transport_disconnect (transport); - return; - } - - if (!_dbus_connection_add_watch (transport->connection, - watch)) - { - _dbus_transport_disconnect (transport); - _dbus_watch_unref (watch); - return; - } - - unix_transport->watch = watch; - + check_read_watch (transport); check_write_watch (transport); } @@ -844,6 +893,11 @@ unix_do_iteration (DBusTransport *transport, fd_set read_set; fd_set write_set; dbus_bool_t do_select; + + _dbus_verbose (" iteration flags = %s%s timeout = %d\n", + flags & DBUS_ITERATION_DO_READING ? "read" : "", + flags & DBUS_ITERATION_DO_WRITING ? "write" : "", + timeout_milliseconds); /* "again" has to be up here because on EINTR the fd sets become * undefined @@ -856,6 +910,9 @@ unix_do_iteration (DBusTransport *transport, * 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. + * + * Also, if read_watch == NULL or write_watch == NULL, we don't + * want to read/write so don't. */ FD_ZERO (&read_set); @@ -863,14 +920,15 @@ unix_do_iteration (DBusTransport *transport, if (_dbus_transport_get_is_authenticated (transport)) { - if (flags & DBUS_ITERATION_DO_READING) + if (unix_transport->read_watch && + (flags & DBUS_ITERATION_DO_READING)) { FD_SET (unix_transport->fd, &read_set); do_select = TRUE; } - - if (flags & DBUS_ITERATION_DO_WRITING) + if (unix_transport->write_watch && + (flags & DBUS_ITERATION_DO_WRITING)) { FD_SET (unix_transport->fd, &write_set); do_select = TRUE; @@ -957,13 +1015,21 @@ unix_do_iteration (DBusTransport *transport, } } +static void +unix_live_messages_changed (DBusTransport *transport) +{ + /* See if we should look for incoming messages again */ + check_read_watch (transport); +} + static DBusTransportVTable unix_vtable = { unix_finalize, unix_handle_watch, unix_disconnect, unix_connection_set, unix_messages_pending, - unix_do_iteration + unix_do_iteration, + unix_live_messages_changed }; /** @@ -1009,6 +1075,7 @@ _dbus_transport_new_for_fd (int fd, unix_transport->max_bytes_read_per_iteration = 2048; unix_transport->max_bytes_written_per_iteration = 2048; + check_read_watch ((DBusTransport*) unix_transport); check_write_watch ((DBusTransport*) unix_transport); return (DBusTransport*) unix_transport; diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c index 28326ba7..9b367dcd 100644 --- a/dbus/dbus-transport.c +++ b/dbus/dbus-transport.c @@ -1,7 +1,7 @@ /* -*- mode: C; c-file-style: "gnu" -*- */ /* dbus-transport.c DBusTransport object (internal to D-BUS implementation) * - * Copyright (C) 2002 Red Hat Inc. + * Copyright (C) 2002, 2003 Red Hat Inc. * * Licensed under the Academic Free License version 1.2 * @@ -66,6 +66,27 @@ #define DBUS_TRANSPORT_RELEASE_REF(t) \ if ((t)->connection) dbus_connection_unref ((t)->connection); _dbus_transport_unref (t) +static void +live_messages_size_notify (DBusCounter *counter, + void *user_data) +{ + DBusTransport *transport = user_data; + + DBUS_TRANSPORT_HOLD_REF (transport); + +#if 0 + _dbus_verbose ("Counter value is now %d\n", + (int) _dbus_counter_get_value (counter)); +#endif + + /* disable or re-enable the read watch for the transport if + * required. + */ + if (* transport->vtable->live_messages_changed) + (* transport->vtable->live_messages_changed) (transport); + + DBUS_TRANSPORT_RELEASE_REF (transport); +} /** * Initializes the base class members of DBusTransport. @@ -83,11 +104,12 @@ _dbus_transport_init_base (DBusTransport *transport, { DBusMessageLoader *loader; DBusAuth *auth; + DBusCounter *counter; loader = _dbus_message_loader_new (); if (loader == NULL) return FALSE; - + if (server) auth = _dbus_auth_server_new (); else @@ -97,21 +119,40 @@ _dbus_transport_init_base (DBusTransport *transport, _dbus_message_loader_unref (loader); return FALSE; } + + counter = _dbus_counter_new (); + if (counter == NULL) + { + _dbus_auth_unref (auth); + _dbus_message_loader_unref (loader); + return FALSE; + } transport->refcount = 1; transport->vtable = vtable; transport->loader = loader; transport->auth = auth; + transport->live_messages_size = counter; transport->authenticated = FALSE; transport->messages_need_sending = FALSE; transport->disconnected = FALSE; transport->send_credentials_pending = !server; transport->receive_credentials_pending = server; transport->is_server = server; + + /* Try to default to something that won't totally hose the system, + * but doesn't impose too much of a limitation. + */ + transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63; transport->credentials.pid = -1; transport->credentials.uid = -1; transport->credentials.gid = -1; + + _dbus_counter_set_notify (transport->live_messages_size, + transport->max_live_messages_size, + live_messages_size_notify, + transport); return TRUE; } @@ -127,9 +168,12 @@ _dbus_transport_finalize_base (DBusTransport *transport) { if (!transport->disconnected) _dbus_transport_disconnect (transport); - + _dbus_message_loader_unref (transport->loader); _dbus_auth_unref (transport->auth); + _dbus_counter_set_notify (transport->live_messages_size, + 0, NULL, NULL); + _dbus_counter_unref (transport->live_messages_size); } /** @@ -403,4 +447,59 @@ _dbus_transport_do_iteration (DBusTransport *transport, DBUS_TRANSPORT_RELEASE_REF (transport); } +/** + * See dbus_connection_set_max_message_size(). + * + * @param transport the transport + * @param size the max size of a single message + */ +void +_dbus_transport_set_max_message_size (DBusTransport *transport, + long size) +{ + _dbus_message_loader_set_max_message_size (transport->loader, size); +} + +/** + * See dbus_connection_get_max_message_size(). + * + * @param transport the transport + * @returns max message size + */ +long +_dbus_transport_get_max_message_size (DBusTransport *transport) +{ + return _dbus_message_loader_get_max_message_size (transport->loader); +} + +/** + * See dbus_connection_set_max_live_messages_size(). + * + * @param transport the transport + * @param size the max size of all incoming messages + */ +void +_dbus_transport_set_max_live_messages_size (DBusTransport *transport, + long size) +{ + transport->max_live_messages_size = size; + _dbus_counter_set_notify (transport->live_messages_size, + transport->max_live_messages_size, + live_messages_size_notify, + transport); +} + + +/** + * See dbus_connection_get_max_live_messages_size(). + * + * @param transport the transport + * @returns max bytes for all live messages + */ +long +_dbus_transport_get_max_live_messages_size (DBusTransport *transport) +{ + return transport->max_live_messages_size; +} + /** @} */ diff --git a/dbus/dbus-transport.h b/dbus/dbus-transport.h index 47062b74..5e7de3e5 100644 --- a/dbus/dbus-transport.h +++ b/dbus/dbus-transport.h @@ -30,24 +30,29 @@ DBUS_BEGIN_DECLS; typedef struct DBusTransport DBusTransport; -DBusTransport* _dbus_transport_open (const char *address, - DBusResultCode *result); -void _dbus_transport_ref (DBusTransport *transport); -void _dbus_transport_unref (DBusTransport *transport); -void _dbus_transport_disconnect (DBusTransport *transport); -dbus_bool_t _dbus_transport_get_is_connected (DBusTransport *transport); -dbus_bool_t _dbus_transport_get_is_authenticated (DBusTransport *transport); -void _dbus_transport_handle_watch (DBusTransport *transport, - DBusWatch *watch, - unsigned int condition); -void _dbus_transport_set_connection (DBusTransport *transport, - DBusConnection *connection); -void _dbus_transport_messages_pending (DBusTransport *transport, - int queue_length); -void _dbus_transport_do_iteration (DBusTransport *transport, - unsigned int flags, - int timeout_milliseconds); - +DBusTransport* _dbus_transport_open (const char *address, + DBusResultCode *result); +void _dbus_transport_ref (DBusTransport *transport); +void _dbus_transport_unref (DBusTransport *transport); +void _dbus_transport_disconnect (DBusTransport *transport); +dbus_bool_t _dbus_transport_get_is_connected (DBusTransport *transport); +dbus_bool_t _dbus_transport_get_is_authenticated (DBusTransport *transport); +void _dbus_transport_handle_watch (DBusTransport *transport, + DBusWatch *watch, + unsigned int condition); +void _dbus_transport_set_connection (DBusTransport *transport, + DBusConnection *connection); +void _dbus_transport_messages_pending (DBusTransport *transport, + int queue_length); +void _dbus_transport_do_iteration (DBusTransport *transport, + unsigned int flags, + int timeout_milliseconds); +void _dbus_transport_set_max_message_size (DBusTransport *transport, + long size); +long _dbus_transport_get_max_message_size (DBusTransport *transport); +void _dbus_transport_set_max_live_messages_size (DBusTransport *transport, + long size); +long _dbus_transport_get_max_live_messages_size (DBusTransport *transport); DBUS_END_DECLS; |