summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog27
-rw-r--r--dbus/Makefile.am2
-rw-r--r--dbus/dbus-connection.c72
-rw-r--r--dbus/dbus-connection.h8
-rw-r--r--dbus/dbus-marshal.c13
-rw-r--r--dbus/dbus-message-internal.h8
-rw-r--r--dbus/dbus-message.c148
-rw-r--r--dbus/dbus-resources.c191
-rw-r--r--dbus/dbus-resources.h52
-rw-r--r--dbus/dbus-transport-protected.h10
-rw-r--r--dbus/dbus-transport-unix.c147
-rw-r--r--dbus/dbus-transport.c105
-rw-r--r--dbus/dbus-transport.h41
-rw-r--r--test/echo-server.c3
-rw-r--r--test/watch.c2
15 files changed, 745 insertions, 84 deletions
diff --git a/ChangeLog b/ChangeLog
index e80783f4..3cccd3a9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,32 @@
2003-01-18 Havoc Pennington <hp@pobox.com>
+ * dbus/dbus-transport-unix.c (unix_do_iteration): only do the
+ reading/writing if read_watch != NULL or write_watch != NULL.
+
+ * dbus/dbus-message.c (_dbus_message_loader_return_buffer): fix
+ the message loader code to actually load message->header and
+ message->body into the newly-created message.
+
+ * dbus/dbus-transport-unix.c (check_write_watch): fix a mem leak
+ in OOM case
+
+ * dbus/dbus-connection.c (dbus_connection_set_max_message_size)
+ (dbus_connection_get_max_message_size)
+ (dbus_connection_set_max_live_messages_size)
+ (dbus_connection_get_max_live_messages_size): implement some
+ resource limitation functions
+
+ * dbus/dbus-resources.c: new file implementing some of the
+ resource limits stuff
+
+ * dbus/dbus-message.c (dbus_message_iter_get_byte_array): add
+ missing docs, add @todo to handle OOM etc.
+
+ * dbus/dbus-marshal.c (_dbus_demarshal_byte_array): add missing
+ docs
+
+2003-01-18 Havoc Pennington <hp@pobox.com>
+
* dbus/dbus-connection.c (dbus_connection_unref): disconnect the
connection if it hasn't been already.
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;
diff --git a/test/echo-server.c b/test/echo-server.c
index 99f97ffd..27e10e72 100644
--- a/test/echo-server.c
+++ b/test/echo-server.c
@@ -9,6 +9,9 @@ new_connection_callback (DBusServer *server,
{
printf ("Got new connection\n");
+ dbus_connection_set_max_live_messages_size (new_connection,
+ 10);
+
setup_connection (new_connection);
}
diff --git a/test/watch.c b/test/watch.c
index 02a1e976..71d9cdc2 100644
--- a/test/watch.c
+++ b/test/watch.c
@@ -146,7 +146,7 @@ check_messages (void)
{
DBusMessage *reply;
- printf ("Received message %d, sending reply\n", count);
+ fprintf (stderr, "Received message %d, sending reply\n", count);
reply = dbus_message_new ("org.freedesktop.DBus.Test", "org.freedesktop.DBus.Test");
dbus_connection_send_message (connection,