summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-02-26 06:42:57 +0000
committerHavoc Pennington <hp@redhat.com>2003-02-26 06:42:57 +0000
commit7265423411609c14ddb9e6643463b840afcaa09b (patch)
tree199b4d4bee1531333292518bf83425eb01ad2fd3
parent3781f063a6dfbdeafea6d1c6c8ac10c8b22f8586 (diff)
2003-02-26 Havoc Pennington <hp@pobox.com>
* dbus/dbus-connection.c (dbus_connection_send_message_with_reply_and_block): fix crash where we ref'd the outgoing message instead of the returned reply * dbus/dbus-transport-unix.c (do_authentication): check read watch at the end of this function, so if we didn't need to read for authentication, we reinstall it for receiving messages * dbus/dbus-message.c (dbus_message_new_reply): allow replies to a NULL sender for peer-to-peer case * dbus/dbus-transport-unix.c (check_read_watch): handle !authenticated case correctly * glib/dbus-gmain.c: add support for DBusServer * dbus/dbus-server.c: add data slot support * glib/dbus-gmain.c (dbus_connection_setup_with_g_main): check return values and handle errors * dbus/dbus-dataslot.c: factor out the data slot stuff from DBusConnection * Doxyfile.in (INPUT): add glib subdir * glib/dbus-gmain.c (dbus_connection_setup_with_g_main): rename setup_with_g_main instead of hookup_with_g_main; write docs
-rw-r--r--ChangeLog31
-rw-r--r--Doxyfile.in2
-rw-r--r--dbus/Makefile.am2
-rw-r--r--dbus/dbus-connection.c263
-rw-r--r--dbus/dbus-dataslot.c372
-rw-r--r--dbus/dbus-dataslot.h76
-rw-r--r--dbus/dbus-internals.h14
-rw-r--r--dbus/dbus-keyring.c2
-rw-r--r--dbus/dbus-message.c24
-rw-r--r--dbus/dbus-server-protected.h3
-rw-r--r--dbus/dbus-server.c136
-rw-r--r--dbus/dbus-server.h9
-rw-r--r--dbus/dbus-test.c4
-rw-r--r--dbus/dbus-test.h23
-rw-r--r--dbus/dbus-threads.c3
-rw-r--r--dbus/dbus-transport-unix.c38
-rw-r--r--dbus/dbus-transport.c3
-rw-r--r--glib/dbus-glib.h5
-rw-r--r--glib/dbus-gmain.c257
-rw-r--r--glib/dbus-gthread.c16
-rw-r--r--glib/test-dbus-glib.c2
21 files changed, 1039 insertions, 246 deletions
diff --git a/ChangeLog b/ChangeLog
index 9b6005e4..87adb2a8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,34 @@
+2003-02-26 Havoc Pennington <hp@pobox.com>
+
+ * dbus/dbus-connection.c
+ (dbus_connection_send_message_with_reply_and_block): fix crash
+ where we ref'd the outgoing message instead of the returned reply
+
+ * dbus/dbus-transport-unix.c (do_authentication): check read watch
+ at the end of this function, so if we didn't need to read for
+ authentication, we reinstall it for receiving messages
+
+ * dbus/dbus-message.c (dbus_message_new_reply): allow replies to
+ a NULL sender for peer-to-peer case
+
+ * dbus/dbus-transport-unix.c (check_read_watch): handle
+ !authenticated case correctly
+
+ * glib/dbus-gmain.c: add support for DBusServer
+
+ * dbus/dbus-server.c: add data slot support
+
+ * glib/dbus-gmain.c (dbus_connection_setup_with_g_main): check
+ return values and handle errors
+
+ * dbus/dbus-dataslot.c: factor out the data slot stuff from
+ DBusConnection
+
+ * Doxyfile.in (INPUT): add glib subdir
+
+ * glib/dbus-gmain.c (dbus_connection_setup_with_g_main): rename
+ setup_with_g_main instead of hookup_with_g_main; write docs
+
2003-02-24 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-marshal.c: (_dbus_marshal_validate_arg):
diff --git a/Doxyfile.in b/Doxyfile.in
index f01db5d9..c476deb0 100644
--- a/Doxyfile.in
+++ b/Doxyfile.in
@@ -49,7 +49,7 @@ WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
-INPUT = dbus bus
+INPUT = dbus bus glib
FILE_PATTERNS = *.c *.h
RECURSIVE = YES
#EXCLUDE = test
diff --git a/dbus/Makefile.am b/dbus/Makefile.am
index eb7f5c93..7a064ce8 100644
--- a/dbus/Makefile.am
+++ b/dbus/Makefile.am
@@ -73,6 +73,8 @@ libdbus_1_la_SOURCES= \
noinst_LTLIBRARIES=libdbus-convenience.la
libdbus_convenience_la_SOURCES= \
+ dbus-dataslot.c \
+ dbus-dataslot.h \
dbus-hash.c \
dbus-hash.h \
dbus-internals.c \
diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c
index 64e83d11..6fb4e84c 100644
--- a/dbus/dbus-connection.c
+++ b/dbus/dbus-connection.c
@@ -33,6 +33,7 @@
#include "dbus-message-handler.h"
#include "dbus-threads.h"
#include "dbus-protocol.h"
+#include "dbus-dataslot.h"
/**
* @defgroup DBusConnection DBusConnection
@@ -66,15 +67,6 @@
static dbus_bool_t _dbus_modify_sigpipe = TRUE;
-/** Opaque typedef for DBusDataSlot */
-typedef struct DBusDataSlot DBusDataSlot;
-/** DBusDataSlot is used to store application data on the connection */
-struct DBusDataSlot
-{
- void *data; /**< The application data */
- DBusFreeFunction free_data_func; /**< Free the application data */
-};
-
/**
* Implementation details of DBusConnection. All fields are private.
*/
@@ -105,8 +97,8 @@ struct DBusConnection
DBusHashTable *handler_table; /**< Table of registered DBusMessageHandler */
DBusList *filter_list; /**< List of filters. */
- DBusDataSlot *data_slots; /**< Data slots */
- int n_slots; /**< Slots allocated so far. */
+
+ DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */
DBusHashTable *pending_replies; /**< Hash of message serials and their message handlers. */
DBusCounter *connection_counter; /**< Counter that we decrement when finalized */
@@ -130,7 +122,6 @@ typedef struct
static void reply_handler_data_free (ReplyHandlerData *data);
-static void _dbus_connection_free_data_slots_nolock (DBusConnection *connection);
static void _dbus_connection_remove_timeout_locked (DBusConnection *connection,
DBusTimeout *timeout);
@@ -572,8 +563,8 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
connection->pending_replies = pending_replies;
connection->filter_list = NULL;
- connection->data_slots = NULL;
- connection->n_slots = 0;
+ _dbus_data_slot_list_init (&connection->slot_list);
+
connection->client_serial = 1;
connection->disconnect_message_link = disconnect_link;
@@ -798,8 +789,9 @@ _dbus_connection_last_unref (DBusConnection *connection)
_dbus_timeout_list_free (connection->timeouts);
connection->timeouts = NULL;
-
- _dbus_connection_free_data_slots_nolock (connection);
+
+ /* calls out to application code... */
+ _dbus_data_slot_list_free (&connection->slot_list);
_dbus_hash_iter_init (connection->handler_table, &iter);
while (_dbus_hash_iter_next (&iter))
@@ -1078,6 +1070,10 @@ reply_handler_data_free (ReplyHandlerData *data)
* you want a very short or very long timeout. There is no way to
* avoid a timeout entirely, other than passing INT_MAX for the
* timeout to postpone it indefinitely.
+ *
+ * @todo I think we should rename this function family
+ * dbus_connection_send(), send_with_reply(), etc. (i.e.
+ * drop the "message" part), the names are too long.
*
* @param connection the connection
* @param message the message to send
@@ -1086,13 +1082,6 @@ reply_handler_data_free (ReplyHandlerData *data)
* @param result return location for result code
* @returns #TRUE if the message is successfully queued, #FALSE if no memory.
*
- * @todo this function isn't implemented because we need message serials
- * and other slightly more rich DBusMessage implementation in order to
- * implement it. The basic idea will be to keep a hash of serials we're
- * expecting a reply to, and also to add a way to tell GLib or Qt to
- * install a timeout. Then install a timeout which is the shortest
- * timeout of any pending reply.
- *
*/
dbus_bool_t
dbus_connection_send_message_with_reply (DBusConnection *connection,
@@ -1227,10 +1216,9 @@ dbus_connection_send_message_with_reply (DBusConnection *connection,
* wrong, result is set to whatever is appropriate, such as
* #DBUS_RESULT_NO_MEMORY.
*
- * @todo I believe if we get EINTR or otherwise interrupt the
- * do_iteration call in here, we won't block the required length of
- * time. I think there probably has to be a loop: "while (!timeout_elapsed)
- * { check_for_reply_in_queue(); iterate_with_remaining_timeout(); }"
+ * @todo could use performance improvements (it keeps scanning
+ * the whole message queue for example) and has thread issues,
+ * see comments in source
*
* @param connection the connection
* @param message the message to send
@@ -1247,22 +1235,47 @@ dbus_connection_send_message_with_reply_and_block (DBusConnection *connectio
{
dbus_int32_t client_serial;
DBusList *link;
+ long start_tv_sec, start_tv_usec;
+ long end_tv_sec, end_tv_usec;
+ long tv_sec, tv_usec;
if (timeout_milliseconds == -1)
timeout_milliseconds = DEFAULT_TIMEOUT_VALUE;
+
+ /* it would probably seem logical to pass in _DBUS_INT_MAX
+ * for infinite timeout, but then math below would get
+ * all overflow-prone, so smack that down.
+ */
+ if (timeout_milliseconds > _DBUS_ONE_HOUR_IN_MILLISECONDS * 6)
+ timeout_milliseconds = _DBUS_ONE_HOUR_IN_MILLISECONDS * 6;
if (!dbus_connection_send_message (connection, message, &client_serial, result))
return NULL;
+ message = NULL;
+
/* Flush message queue */
dbus_connection_flush (connection);
dbus_mutex_lock (connection->mutex);
+
+ _dbus_get_current_time (&start_tv_sec, &start_tv_usec);
+ end_tv_sec = start_tv_sec + timeout_milliseconds / 1000;
+ end_tv_usec = start_tv_usec + (timeout_milliseconds % 1000) * 1000;
+ end_tv_sec += end_tv_usec / _DBUS_USEC_PER_SECOND;
+ end_tv_usec = end_tv_usec % _DBUS_USEC_PER_SECOND;
+
+ _dbus_verbose ("will block %d milliseconds from %ld sec %ld usec to %ld sec %ld usec\n",
+ timeout_milliseconds,
+ start_tv_sec, start_tv_usec,
+ end_tv_sec, end_tv_usec);
/* Now we wait... */
/* THREAD TODO: This is busted. What if a dispatch_message or pop_message
* gets the message before we do?
*/
+ block_again:
+
_dbus_connection_do_iteration (connection,
DBUS_ITERATION_DO_READING |
DBUS_ITERATION_BLOCK,
@@ -1278,7 +1291,7 @@ dbus_connection_send_message_with_reply_and_block (DBusConnection *connectio
if (_dbus_message_get_reply_serial (reply) == client_serial)
{
_dbus_list_remove (&connection->incoming_messages, link);
- dbus_message_ref (message);
+ dbus_message_ref (reply);
if (result)
*result = DBUS_RESULT_SUCCESS;
@@ -1289,8 +1302,27 @@ dbus_connection_send_message_with_reply_and_block (DBusConnection *connectio
link = _dbus_list_get_next_link (&connection->incoming_messages, link);
}
- if (result)
- *result = DBUS_RESULT_NO_REPLY;
+ _dbus_get_current_time (&tv_sec, &tv_usec);
+
+ if (tv_sec < start_tv_sec)
+ ; /* clock set backward, bail out */
+ else if (connection->disconnect_message_link == NULL)
+ ; /* we're disconnected, bail out */
+ else if (tv_sec < end_tv_sec ||
+ (tv_sec == end_tv_sec && tv_usec < end_tv_usec))
+ {
+ timeout_milliseconds = (end_tv_sec - tv_sec) * 1000 +
+ (end_tv_usec - tv_usec) / 1000;
+ _dbus_verbose ("%d milliseconds remain\n", timeout_milliseconds);
+ _dbus_assert (timeout_milliseconds > 0);
+
+ goto block_again; /* not expired yet */
+ }
+
+ if (dbus_connection_get_is_connected (connection))
+ dbus_set_result (result, DBUS_RESULT_NO_REPLY);
+ else
+ dbus_set_result (result, DBUS_RESULT_DISCONNECTED);
dbus_mutex_unlock (connection->mutex);
@@ -1850,6 +1882,12 @@ dbus_connection_remove_filter (DBusConnection *connection,
* this function with the name of a message that already has a
* handler. If the function returns #FALSE, the handlers were not
* registered due to lack of memory.
+ *
+ * @todo the messages_to_handle arg may be more convenient if it's a
+ * single string instead of an array. Though right now MessageHandler
+ * is sort of designed to say be associated with an entire object with
+ * multiple methods, that's why for example the connection only
+ * weakrefs it. So maybe the "manual" API should be different.
*
* @param connection the connection
* @param handler the handler
@@ -1969,25 +2007,23 @@ dbus_connection_unregister_handler (DBusConnection *connection,
dbus_mutex_unlock (connection->mutex);
}
-static int *allocated_slots = NULL;
-static int n_allocated_slots = 0;
-static int n_used_slots = 0;
-static DBusMutex *allocated_slots_lock = NULL;
+static DBusDataSlotAllocator slot_allocator;
/**
- * Initialize the mutex used for #DBusConnecton data
+ * Initialize the mutex used for #DBusConnection data
* slot reservations.
*
* @returns the mutex
*/
DBusMutex *
-_dbus_allocated_slots_init_lock (void)
+_dbus_connection_slots_init_lock (void)
{
- allocated_slots_lock = dbus_mutex_new ();
- return allocated_slots_lock;
+ if (!_dbus_data_slot_allocator_init (&slot_allocator))
+ return NULL;
+ else
+ return slot_allocator.lock;
}
-
/**
* Allocates an integer ID to be used for storing application-specific
* data on any DBusConnection. The allocated ID may then be used
@@ -2001,50 +2037,7 @@ _dbus_allocated_slots_init_lock (void)
int
dbus_connection_allocate_data_slot (void)
{
- int slot;
-
- if (!dbus_mutex_lock (allocated_slots_lock))
- return -1;
-
- if (n_used_slots < n_allocated_slots)
- {
- slot = 0;
- while (slot < n_allocated_slots)
- {
- if (allocated_slots[slot] < 0)
- {
- allocated_slots[slot] = slot;
- n_used_slots += 1;
- break;
- }
- ++slot;
- }
-
- _dbus_assert (slot < n_allocated_slots);
- }
- else
- {
- int *tmp;
-
- slot = -1;
- tmp = dbus_realloc (allocated_slots,
- sizeof (int) * (n_allocated_slots + 1));
- if (tmp == NULL)
- goto out;
-
- allocated_slots = tmp;
- slot = n_allocated_slots;
- n_allocated_slots += 1;
- n_used_slots += 1;
- allocated_slots[slot] = slot;
- }
-
- _dbus_assert (slot >= 0);
- _dbus_assert (slot < n_allocated_slots);
-
- out:
- dbus_mutex_unlock (allocated_slots_lock);
- return slot;
+ return _dbus_data_slot_allocator_alloc (&slot_allocator);
}
/**
@@ -2061,22 +2054,7 @@ dbus_connection_allocate_data_slot (void)
void
dbus_connection_free_data_slot (int slot)
{
- dbus_mutex_lock (allocated_slots_lock);
-
- _dbus_assert (slot < n_allocated_slots);
- _dbus_assert (allocated_slots[slot] == slot);
-
- allocated_slots[slot] = -1;
- n_used_slots -= 1;
-
- if (n_used_slots == 0)
- {
- dbus_free (allocated_slots);
- allocated_slots = NULL;
- n_allocated_slots = 0;
- }
-
- dbus_mutex_unlock (allocated_slots_lock);
+ _dbus_data_slot_allocator_free (&slot_allocator, slot);
}
/**
@@ -2100,50 +2078,25 @@ dbus_connection_set_data (DBusConnection *connection,
{
DBusFreeFunction old_free_func;
void *old_data;
+ dbus_bool_t retval;
dbus_mutex_lock (connection->mutex);
- _dbus_assert (slot < n_allocated_slots);
- _dbus_assert (allocated_slots[slot] == slot);
-
- if (slot >= connection->n_slots)
- {
- DBusDataSlot *tmp;
- int i;
-
- tmp = dbus_realloc (connection->data_slots,
- sizeof (DBusDataSlot) * (slot + 1));
- if (tmp == NULL)
- {
- dbus_mutex_unlock (connection->mutex);
- return FALSE;
- }
-
- connection->data_slots = tmp;
- i = connection->n_slots;
- connection->n_slots = slot + 1;
- while (i < connection->n_slots)
- {
- connection->data_slots[i].data = NULL;
- connection->data_slots[i].free_data_func = NULL;
- ++i;
- }
- }
-
- _dbus_assert (slot < connection->n_slots);
-
- old_data = connection->data_slots[slot].data;
- old_free_func = connection->data_slots[slot].free_data_func;
-
- connection->data_slots[slot].data = data;
- connection->data_slots[slot].free_data_func = free_data_func;
+ retval = _dbus_data_slot_list_set (&slot_allocator,
+ &connection->slot_list,
+ slot, data, free_data_func,
+ &old_free_func, &old_data);
+
dbus_mutex_unlock (connection->mutex);
- /* Do the actual free outside the connection lock */
- if (old_free_func)
- (* old_free_func) (old_data);
+ if (retval)
+ {
+ /* Do the actual free outside the connection lock */
+ if (old_free_func)
+ (* old_free_func) (old_data);
+ }
- return TRUE;
+ return retval;
}
/**
@@ -2161,15 +2114,11 @@ dbus_connection_get_data (DBusConnection *connection,
void *res;
dbus_mutex_lock (connection->mutex);
-
- _dbus_assert (slot < n_allocated_slots);
- _dbus_assert (allocated_slots[slot] == slot);
-
- if (slot >= connection->n_slots)
- res = NULL;
- else
- res = connection->data_slots[slot].data;
+ res = _dbus_data_slot_list_get (&slot_allocator,
+ &connection->slot_list,
+ slot);
+
dbus_mutex_unlock (connection->mutex);
return res;
@@ -2187,30 +2136,6 @@ dbus_connection_set_change_sigpipe (dbus_bool_t will_modify_sigpipe)
_dbus_modify_sigpipe = will_modify_sigpipe;
}
-/* This must be called with the connection lock not held to avoid
- * holding it over the free_data callbacks, so it can basically
- * only be called at last unref
- */
-static void
-_dbus_connection_free_data_slots_nolock (DBusConnection *connection)
-{
- int i;
-
- i = 0;
- while (i < connection->n_slots)
- {
- if (connection->data_slots[i].free_data_func)
- (* connection->data_slots[i].free_data_func) (connection->data_slots[i].data);
- connection->data_slots[i].data = NULL;
- connection->data_slots[i].free_data_func = NULL;
- ++i;
- }
-
- dbus_free (connection->data_slots);
- connection->data_slots = NULL;
- connection->n_slots = 0;
-}
-
/**
* Specifies the maximum size message this connection is allowed to
* receive. Larger messages will result in disconnecting the
diff --git a/dbus/dbus-dataslot.c b/dbus/dbus-dataslot.c
new file mode 100644
index 00000000..a5909ffc
--- /dev/null
+++ b/dbus/dbus-dataslot.c
@@ -0,0 +1,372 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-dataslot.c storing data on objects
+ *
+ * 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-dataslot.h"
+#include "dbus-threads.h"
+
+/**
+ * @defgroup DBusDataSlot Data slots
+ * @ingroup DBusInternals
+ * @brief Storing data by ID
+ *
+ * Types and functions related to storing data by an
+ * allocated ID. This is used for dbus_connection_set_data(),
+ * dbus_server_set_data(), etc.
+ * @{
+ */
+
+/**
+ * Initializes a data slot allocator object, used to assign
+ * integer IDs for data slots.
+ *
+ * @param allocator the allocator to initialize
+ */
+dbus_bool_t
+_dbus_data_slot_allocator_init (DBusDataSlotAllocator *allocator)
+{
+ allocator->allocated_slots = NULL;
+ allocator->n_allocated_slots = 0;
+ allocator->n_used_slots = 0;
+ allocator->lock = dbus_mutex_new ();
+ if (allocator->lock == NULL)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+/**
+ * Allocates an integer ID to be used for storing data
+ * in a #DBusDataSlotList.
+ *
+ * @param allocator the allocator
+ * @returns the integer ID, or -1 on failure
+ */
+int
+_dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator)
+{
+ int slot;
+
+ if (!dbus_mutex_lock (allocator->lock))
+ return -1;
+
+ if (allocator->n_used_slots < allocator->n_allocated_slots)
+ {
+ slot = 0;
+ while (slot < allocator->n_allocated_slots)
+ {
+ if (allocator->allocated_slots[slot] < 0)
+ {
+ allocator->allocated_slots[slot] = slot;
+ allocator->n_used_slots += 1;
+ break;
+ }
+ ++slot;
+ }
+
+ _dbus_assert (slot < allocator->n_allocated_slots);
+ }
+ else
+ {
+ int *tmp;
+
+ slot = -1;
+ tmp = dbus_realloc (allocator->allocated_slots,
+ sizeof (int) * (allocator->n_allocated_slots + 1));
+ if (tmp == NULL)
+ goto out;
+
+ allocator->allocated_slots = tmp;
+ slot = allocator->n_allocated_slots;
+ allocator->n_allocated_slots += 1;
+ allocator->n_used_slots += 1;
+ allocator->allocated_slots[slot] = slot;
+ }
+
+ _dbus_assert (slot >= 0);
+ _dbus_assert (slot < allocator->n_allocated_slots);
+
+ out:
+ dbus_mutex_unlock (allocator->lock);
+ return slot;
+}
+
+/**
+ * Deallocates an ID previously allocated with
+ * _dbus_data_slot_allocator_alloc(). Existing data stored on
+ * existing #DBusDataList objects with this ID will be freed when the
+ * data list is finalized, but may not be retrieved (and may only be
+ * replaced if someone else reallocates the slot).
+ *
+ * @param allocator the allocator
+ * @param slot the slot to deallocate
+ */
+void
+_dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator,
+ int slot)
+{
+ dbus_mutex_lock (allocator->lock);
+
+ _dbus_assert (slot < allocator->n_allocated_slots);
+ _dbus_assert (allocator->allocated_slots[slot] == slot);
+
+ allocator->allocated_slots[slot] = -1;
+ allocator->n_used_slots -= 1;
+
+ if (allocator->n_used_slots == 0)
+ {
+ dbus_free (allocator->allocated_slots);
+ allocator->allocated_slots = NULL;
+ allocator->n_allocated_slots = 0;
+ }
+
+ dbus_mutex_unlock (allocator->lock);
+}
+
+/**
+ * Initializes a slot list.
+ * @param list the list to initialize.
+ */
+void
+_dbus_data_slot_list_init (DBusDataSlotList *list)
+{
+ list->slots = NULL;
+ list->n_slots = 0;
+}
+
+/**
+ * Stores a pointer in the data slot list, along with an optional
+ * function to be used for freeing the data when the data is set
+ * again, or when the slot list is finalized. The slot number must
+ * have been allocated with _dbus_data_slot_allocator_alloc() for the
+ * same allocator passed in here. The same allocator has to be used
+ * with the slot list every time.
+ *
+ * @param allocator the allocator to use
+ * @param list the data slot list
+ * @param slot the slot number
+ * @param data the data to store
+ * @param free_data_func finalizer function for the data
+ * @param old_free_func free function for any previously-existing data
+ * @param old_data previously-existing data, should be freed with old_free_func
+ * @returns #TRUE if there was enough memory to store the data
+ */
+dbus_bool_t
+_dbus_data_slot_list_set (DBusDataSlotAllocator *allocator,
+ DBusDataSlotList *list,
+ int slot,
+ void *data,
+ DBusFreeFunction free_data_func,
+ DBusFreeFunction *old_free_func,
+ void **old_data)
+{
+ _dbus_assert (slot < allocator->n_allocated_slots);
+ _dbus_assert (allocator->allocated_slots[slot] == slot);
+
+ if (slot >= list->n_slots)
+ {
+ DBusDataSlot *tmp;
+ int i;
+
+ tmp = dbus_realloc (list->slots,
+ sizeof (DBusDataSlot) * (slot + 1));
+ if (tmp == NULL)
+ return FALSE;
+
+ list->slots = tmp;
+ i = list->n_slots;
+ list->n_slots = slot + 1;
+ while (i < list->n_slots)
+ {
+ list->slots[i].data = NULL;
+ list->slots[i].free_data_func = NULL;
+ ++i;
+ }
+ }
+
+ _dbus_assert (slot < list->n_slots);
+
+ *old_data = list->slots[slot].data;
+ *old_free_func = list->slots[slot].free_data_func;
+
+ list->slots[slot].data = data;
+ list->slots[slot].free_data_func = free_data_func;
+
+ return TRUE;
+}
+
+/**
+ * Retrieves data previously set with _dbus_data_slot_list_set_data().
+ * The slot must still be allocated (must not have been freed).
+ *
+ * @param allocator the allocator slot was allocated from
+ * @param list the data slot list
+ * @param slot the slot to get data from
+ * @returns the data, or #NULL if not found
+ */
+void*
+_dbus_data_slot_list_get (DBusDataSlotAllocator *allocator,
+ DBusDataSlotList *list,
+ int slot)
+{
+ _dbus_assert (slot < allocator->n_allocated_slots);
+ _dbus_assert (allocator->allocated_slots[slot] == slot);
+
+ if (slot >= list->n_slots)
+ return NULL;
+ else
+ return list->slots[slot].data;
+}
+
+/**
+ * Frees the data slot list and all data slots contained
+ * in it, calling application-provided free functions
+ * if they exist.
+ *
+ * @param list the list to free
+ */
+void
+_dbus_data_slot_list_free (DBusDataSlotList *list)
+{
+ int i;
+
+ i = 0;
+ while (i < list->n_slots)
+ {
+ if (list->slots[i].free_data_func)
+ (* list->slots[i].free_data_func) (list->slots[i].data);
+ list->slots[i].data = NULL;
+ list->slots[i].free_data_func = NULL;
+ ++i;
+ }
+
+ dbus_free (list->slots);
+ list->slots = NULL;
+ list->n_slots = 0;
+}
+
+/** @} */
+
+#ifdef DBUS_BUILD_TESTS
+#include "dbus-test.h"
+#include <stdio.h>
+
+static int free_counter;
+
+static void
+test_free_slot_data_func (void *data)
+{
+ int i = _DBUS_POINTER_TO_INT (data);
+
+ _dbus_assert (free_counter == i);
+ ++free_counter;
+}
+
+/**
+ * Test function for data slots
+ */
+dbus_bool_t
+_dbus_data_slot_test (void)
+{
+ DBusDataSlotAllocator allocator;
+ DBusDataSlotList list;
+ int i;
+ DBusFreeFunction old_free_func;
+ void *old_data;
+
+ if (!_dbus_data_slot_allocator_init (&allocator))
+ _dbus_assert_not_reached ("no memory for allocator");
+
+ _dbus_data_slot_list_init (&list);
+
+#define N_SLOTS 100
+
+ i = 0;
+ while (i < N_SLOTS)
+ {
+ /* we don't really want apps to rely on this ordered
+ * allocation, but it simplifies things to rely on it
+ * here.
+ */
+ if (_dbus_data_slot_allocator_alloc (&allocator) != i)
+ _dbus_assert_not_reached ("did not allocate slots in numeric order\n");
+
+ ++i;
+ }
+
+ i = 0;
+ while (i < N_SLOTS)
+ {
+ if (!_dbus_data_slot_list_set (&allocator, &list,
+ i,
+ _DBUS_INT_TO_POINTER (i),
+ test_free_slot_data_func,
+ &old_free_func, &old_data))
+ _dbus_assert_not_reached ("no memory to set data");
+
+ _dbus_assert (old_free_func == NULL);
+ _dbus_assert (old_data == NULL);
+
+ _dbus_assert (_dbus_data_slot_list_get (&allocator, &list, i) ==
+ _DBUS_INT_TO_POINTER (i));
+
+ ++i;
+ }
+
+ free_counter = 0;
+ i = 0;
+ while (i < N_SLOTS)
+ {
+ if (!_dbus_data_slot_list_set (&allocator, &list,
+ i,
+ _DBUS_INT_TO_POINTER (i),
+ test_free_slot_data_func,
+ &old_free_func, &old_data))
+ _dbus_assert_not_reached ("no memory to set data");
+
+ _dbus_assert (old_free_func == test_free_slot_data_func);
+ _dbus_assert (_DBUS_POINTER_TO_INT (old_data) == i);
+
+ (* old_free_func) (old_data);
+ _dbus_assert (i == (free_counter - 1));
+
+ _dbus_assert (_dbus_data_slot_list_get (&allocator, &list, i) ==
+ _DBUS_INT_TO_POINTER (i));
+
+ ++i;
+ }
+
+ free_counter = 0;
+ _dbus_data_slot_list_free (&list);
+
+ _dbus_assert (N_SLOTS == free_counter);
+
+ i = 0;
+ while (i < N_SLOTS)
+ {
+ _dbus_data_slot_allocator_free (&allocator, i);
+ ++i;
+ }
+
+ return TRUE;
+}
+
+#endif /* DBUS_BUILD_TESTS */
diff --git a/dbus/dbus-dataslot.h b/dbus/dbus-dataslot.h
new file mode 100644
index 00000000..4bb6091f
--- /dev/null
+++ b/dbus/dbus-dataslot.h
@@ -0,0 +1,76 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-dataslot.h storing data on objects
+ *
+ * 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_DATASLOT_H
+#define DBUS_DATASLOT_H
+
+#include <dbus/dbus-internals.h>
+
+DBUS_BEGIN_DECLS;
+
+typedef struct DBusDataSlotAllocator DBusDataSlotAllocator;
+typedef struct DBusDataSlotList DBusDataSlotList;
+
+/** Opaque typedef for DBusDataSlot */
+typedef struct DBusDataSlot DBusDataSlot;
+/** DBusDataSlot is used to store application data on the connection */
+struct DBusDataSlot
+{
+ void *data; /**< The application data */
+ DBusFreeFunction free_data_func; /**< Free the application data */
+};
+
+struct DBusDataSlotAllocator
+{
+ int *allocated_slots; /**< Allocated slots */
+ int n_allocated_slots; /**< number of slots malloc'd */
+ int n_used_slots; /**< number of slots used */
+ DBusMutex *lock; /**< thread lock */
+};
+
+struct DBusDataSlotList
+{
+ DBusDataSlot *slots; /**< Data slots */
+ int n_slots; /**< Slots we have storage for in data_slots */
+};
+
+dbus_bool_t _dbus_data_slot_allocator_init (DBusDataSlotAllocator *allocator);
+int _dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator);
+void _dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator,
+ int slot_id);
+
+void _dbus_data_slot_list_init (DBusDataSlotList *list);
+dbus_bool_t _dbus_data_slot_list_set (DBusDataSlotAllocator *allocator,
+ DBusDataSlotList *list,
+ int slot,
+ void *data,
+ DBusFreeFunction free_data_func,
+ DBusFreeFunction *old_free_func,
+ void **old_data);
+void* _dbus_data_slot_list_get (DBusDataSlotAllocator *allocator,
+ DBusDataSlotList *list,
+ int slot);
+void _dbus_data_slot_list_free (DBusDataSlotList *list);
+
+DBUS_END_DECLS;
+
+#endif /* DBUS_DATASLOT_H */
diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h
index 551a377f..d928a5c8 100644
--- a/dbus/dbus-internals.h
+++ b/dbus/dbus-internals.h
@@ -118,6 +118,8 @@ char* _dbus_strdup (const char *str);
#define _DBUS_MAX_SUN_PATH_LENGTH 99
#define _DBUS_ONE_KILOBYTE 1024
#define _DBUS_ONE_MEGABYTE 1024 * _DBUS_ONE_KILOBYTE
+#define _DBUS_ONE_HOUR_IN_MILLISECONDS (1000 * 60 * 60)
+#define _DBUS_USEC_PER_SECOND (1000000)
#undef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
@@ -155,12 +157,12 @@ dbus_bool_t _dbus_decrement_fail_alloc_counter (void);
#endif /* !DBUS_BUILD_TESTS */
/* Thread initializers */
-DBusMutex *_dbus_list_init_lock (void);
-DBusMutex *_dbus_allocated_slots_init_lock (void);
-DBusMutex *_dbus_atomic_init_lock (void);
-DBusMutex *_dbus_message_handler_init_lock (void);
-DBusMutex *_dbus_user_info_init_lock (void);
-
+DBusMutex *_dbus_list_init_lock (void);
+DBusMutex *_dbus_connection_slots_init_lock (void);
+DBusMutex *_dbus_server_slots_init_lock (void);
+DBusMutex *_dbus_atomic_init_lock (void);
+DBusMutex *_dbus_message_handler_init_lock (void);
+DBusMutex *_dbus_user_info_init_lock (void);
DBUS_END_DECLS;
diff --git a/dbus/dbus-keyring.c b/dbus/dbus-keyring.c
index ea20c9c4..2162e296 100644
--- a/dbus/dbus-keyring.c
+++ b/dbus/dbus-keyring.c
@@ -168,7 +168,7 @@ free_keys (DBusKey *keys,
*/
/** Maximum number of timeouts waiting for lock before we decide it's stale */
-#define MAX_LOCK_TIMEOUTS 16
+#define MAX_LOCK_TIMEOUTS 32
/** Length of each timeout while waiting for a lock */
#define LOCK_TIMEOUT_MILLISECONDS 250
diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c
index 584acc7e..355d6310 100644
--- a/dbus/dbus-message.c
+++ b/dbus/dbus-message.c
@@ -184,8 +184,12 @@ get_string_field (DBusMessage *message,
int field,
int *len)
{
- int offset = message->header_fields[field].offset;
+ int offset;
const char *data;
+
+ offset = message->header_fields[field].offset;
+
+ _dbus_assert (field < FIELD_LAST);
if (offset < 0)
return NULL;
@@ -209,13 +213,17 @@ get_string_field (DBusMessage *message,
static dbus_int32_t
get_int_field (DBusMessage *message,
- int field)
+ int field)
{
- int offset = message->header_fields[field].offset;
+ int offset;
+
+ _dbus_assert (field < FIELD_LAST);
+
+ offset = message->header_fields[field].offset;
if (offset < 0)
return -1; /* useless if -1 is a valid value of course */
-
+
return _dbus_demarshal_int32 (&message->header,
message->byte_order,
offset,
@@ -798,8 +806,8 @@ dbus_message_new_reply (DBusMessage *original_message)
FIELD_SENDER, NULL);
name = get_string_field (original_message,
FIELD_NAME, NULL);
-
- _dbus_assert (sender != NULL);
+
+ /* sender is allowed to be null here in peer-to-peer case */
message = dbus_message_new (sender, name);
@@ -1703,6 +1711,10 @@ dbus_message_get_args_valist (DBusMessage *message,
* ref/unref is kind of annoying to deal with, and slower too.
* This implies not ref'ing the message from the iter.
*
+ * @todo I'd also name this dbus_message_iter_new() or
+ * for the static object dbus_message_iter_init() rather
+ * than making it a method on the message
+ *
* @param message the message
* @returns a new iter.
*/
diff --git a/dbus/dbus-server-protected.h b/dbus/dbus-server-protected.h
index f155bbb8..24b805c4 100644
--- a/dbus/dbus-server-protected.h
+++ b/dbus/dbus-server-protected.h
@@ -28,6 +28,7 @@
#include <dbus/dbus-timeout.h>
#include <dbus/dbus-watch.h>
#include <dbus/dbus-resources.h>
+#include <dbus/dbus-dataslot.h>
DBUS_BEGIN_DECLS;
@@ -61,6 +62,8 @@ struct DBusServer
*/
int max_connections; /**< Max number of connections allowed at once. */
+
+ DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */
DBusNewConnectionFunction new_connection_function;
/**< Callback to invoke when a new connection is created. */
diff --git a/dbus/dbus-server.c b/dbus/dbus-server.c
index 01435e1a..0065e510 100644
--- a/dbus/dbus-server.c
+++ b/dbus/dbus-server.c
@@ -1,7 +1,7 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-server.c DBusServer object
*
- * Copyright (C) 2002 Red Hat Inc.
+ * Copyright (C) 2002, 2003 Red Hat Inc.
*
* Licensed under the Academic Free License version 1.2
*
@@ -37,6 +37,9 @@
* A DBusServer represents a server that other applications
* can connect to. Each connection from another application
* is represented by a DBusConnection.
+ *
+ * @todo Thread safety hasn't been looked at for #DBusServer
+ * @todo Need notification to apps of disconnection, may matter for some transports
*/
/**
@@ -86,6 +89,8 @@ _dbus_server_init_base (DBusServer *server,
}
server->max_connections = 256; /* same as an X server, seems like a nice default */
+
+ _dbus_data_slot_list_init (&server->slot_list);
return TRUE;
}
@@ -99,6 +104,9 @@ _dbus_server_init_base (DBusServer *server,
void
_dbus_server_finalize_base (DBusServer *server)
{
+ /* calls out to application code... */
+ _dbus_data_slot_list_free (&server->slot_list);
+
dbus_server_set_new_connection_function (server, NULL, NULL, NULL);
if (!server->disconnected)
@@ -510,5 +518,131 @@ dbus_server_get_n_connections (DBusServer *server)
return _dbus_counter_get_value (server->connection_counter);
}
+
+static DBusDataSlotAllocator slot_allocator;
+
+/**
+ * Initialize the mutex used for #DBusConnection data
+ * slot reservations.
+ *
+ * @returns the mutex
+ */
+DBusMutex *
+_dbus_server_slots_init_lock (void)
+{
+ if (!_dbus_data_slot_allocator_init (&slot_allocator))
+ return NULL;
+ else
+ return slot_allocator.lock;
+}
+
+/**
+ * Allocates an integer ID to be used for storing application-specific
+ * data on any DBusServer. The allocated ID may then be used
+ * with dbus_server_set_data() and dbus_server_get_data().
+ * If allocation fails, -1 is returned. Again, the allocated
+ * slot is global, i.e. all DBusServer objects will
+ * have a slot with the given integer ID reserved.
+ *
+ * @returns -1 on failure, otherwise the data slot ID
+ */
+int
+dbus_server_allocate_data_slot (void)
+{
+ return _dbus_data_slot_allocator_alloc (&slot_allocator);
+}
+
+/**
+ * Deallocates a global ID for server data slots.
+ * dbus_server_get_data() and dbus_server_set_data()
+ * may no longer be used with this slot.
+ * Existing data stored on existing DBusServer objects
+ * will be freed when the server is finalized,
+ * but may not be retrieved (and may only be replaced
+ * if someone else reallocates the slot).
+ *
+ * @param slot the slot to deallocate
+ */
+void
+dbus_server_free_data_slot (int slot)
+{
+ _dbus_data_slot_allocator_free (&slot_allocator, slot);
+}
+
+/**
+ * Stores a pointer on a DBusServer, along
+ * with an optional function to be used for freeing
+ * the data when the data is set again, or when
+ * the server is finalized. The slot number
+ * must have been allocated with dbus_server_allocate_data_slot().
+ *
+ * @param server the server
+ * @param slot the slot number
+ * @param data the data to store
+ * @param free_data_func finalizer function for the data
+ * @returns #TRUE if there was enough memory to store the data
+ */
+dbus_bool_t
+dbus_server_set_data (DBusServer *server,
+ int slot,
+ void *data,
+ DBusFreeFunction free_data_func)
+{
+ DBusFreeFunction old_free_func;
+ void *old_data;
+ dbus_bool_t retval;
+
+#if 0
+ dbus_mutex_lock (server->mutex);
+#endif
+
+ retval = _dbus_data_slot_list_set (&slot_allocator,
+ &server->slot_list,
+ slot, data, free_data_func,
+ &old_free_func, &old_data);
+
+#if 0
+ dbus_mutex_unlock (server->mutex);
+#endif
+
+ if (retval)
+ {
+ /* Do the actual free outside the server lock */
+ if (old_free_func)
+ (* old_free_func) (old_data);
+ }
+
+ return retval;
+}
+
+/**
+ * Retrieves data previously set with dbus_server_set_data().
+ * The slot must still be allocated (must not have been freed).
+ *
+ * @param server the server
+ * @param slot the slot to get data from
+ * @returns the data, or #NULL if not found
+ */
+void*
+dbus_server_get_data (DBusServer *server,
+ int slot)
+{
+ void *res;
+
+#if 0
+ dbus_mutex_lock (server->mutex);
+#endif
+
+ res = _dbus_data_slot_list_get (&slot_allocator,
+ &server->slot_list,
+ slot);
+
+#if 0
+ dbus_mutex_unlock (server->mutex);
+#endif
+
+ return res;
+}
+
/** @} */
diff --git a/dbus/dbus-server.h b/dbus/dbus-server.h
index 68d95006..fc3a57e7 100644
--- a/dbus/dbus-server.h
+++ b/dbus/dbus-server.h
@@ -71,6 +71,15 @@ int dbus_server_get_max_connections (DBusServer *server)
int dbus_server_get_n_connections (DBusServer *server);
+int dbus_server_allocate_data_slot (void);
+void dbus_server_free_data_slot (int slot);
+dbus_bool_t dbus_server_set_data (DBusServer *server,
+ int slot,
+ void *data,
+ DBusFreeFunction free_data_func);
+void* dbus_server_get_data (DBusServer *server,
+ int slot);
+
DBUS_END_DECLS;
#endif /* DBUS_SERVER_H */
diff --git a/dbus/dbus-test.c b/dbus/dbus-test.c
index b1f8ac1d..29ad855d 100644
--- a/dbus/dbus-test.c
+++ b/dbus/dbus-test.c
@@ -59,6 +59,10 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir)
if (!_dbus_string_test ())
die ("strings");
+ printf ("%s: running data slot tests\n", "dbus-test");
+ if (!_dbus_data_slot_test ())
+ die ("dataslot");
+
printf ("%s: running keyring tests\n", "dbus-test");
if (!_dbus_keyring_test ())
die ("keyring");
diff --git a/dbus/dbus-test.h b/dbus/dbus-test.h
index b5e38480..2fc2901b 100644
--- a/dbus/dbus-test.h
+++ b/dbus/dbus-test.h
@@ -35,17 +35,18 @@ typedef enum
_DBUS_MESSAGE_UNKNOWN
} DBusMessageValidity;
-dbus_bool_t _dbus_hash_test (void);
-dbus_bool_t _dbus_list_test (void);
-dbus_bool_t _dbus_marshal_test (void);
-dbus_bool_t _dbus_mem_pool_test (void);
-dbus_bool_t _dbus_string_test (void);
-dbus_bool_t _dbus_address_test (void);
-dbus_bool_t _dbus_message_test (const char *test_data_dir);
-dbus_bool_t _dbus_auth_test (const char *test_data_dir);
-dbus_bool_t _dbus_md5_test (void);
-dbus_bool_t _dbus_sha_test (const char *test_data_dir);
-dbus_bool_t _dbus_keyring_test (void);
+dbus_bool_t _dbus_hash_test (void);
+dbus_bool_t _dbus_list_test (void);
+dbus_bool_t _dbus_marshal_test (void);
+dbus_bool_t _dbus_mem_pool_test (void);
+dbus_bool_t _dbus_string_test (void);
+dbus_bool_t _dbus_address_test (void);
+dbus_bool_t _dbus_message_test (const char *test_data_dir);
+dbus_bool_t _dbus_auth_test (const char *test_data_dir);
+dbus_bool_t _dbus_md5_test (void);
+dbus_bool_t _dbus_sha_test (const char *test_data_dir);
+dbus_bool_t _dbus_keyring_test (void);
+dbus_bool_t _dbus_data_slot_test (void);
void dbus_internal_do_not_use_run_tests (const char *test_data_dir);
dbus_bool_t dbus_internal_do_not_use_try_message_file (const DBusString *filename,
diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c
index 2a903a27..08cebf50 100644
--- a/dbus/dbus-threads.c
+++ b/dbus/dbus-threads.c
@@ -205,7 +205,8 @@ init_static_locks(void)
DBusMutex *mutex;
} static_locks[] = {
{&_dbus_list_init_lock},
- {&_dbus_allocated_slots_init_lock},
+ {&_dbus_server_slots_init_lock},
+ {&_dbus_connection_slots_init_lock},
{&_dbus_atomic_init_lock},
{&_dbus_message_handler_init_lock},
{&_dbus_user_info_init_lock}
diff --git a/dbus/dbus-transport-unix.c b/dbus/dbus-transport-unix.c
index b30dc1d6..81c18b4a 100644
--- a/dbus/dbus-transport-unix.c
+++ b/dbus/dbus-transport-unix.c
@@ -157,7 +157,12 @@ check_write_watch (DBusTransport *transport)
_dbus_watch_unref (unix_transport->write_watch);
unix_transport->write_watch = NULL;
}
-
+ else
+ {
+ _dbus_verbose ("Write watch is unchanged from %p on fd %d\n",
+ unix_transport->write_watch, unix_transport->fd);
+ }
+
out:
_dbus_transport_unref (transport);
}
@@ -173,9 +178,16 @@ check_read_watch (DBusTransport *transport)
_dbus_transport_ref (transport);
- need_read_watch =
- _dbus_counter_get_value (transport->live_messages_size) < transport->max_live_messages_size;
+ if (_dbus_transport_get_is_authenticated (transport))
+ need_read_watch =
+ _dbus_counter_get_value (transport->live_messages_size) < transport->max_live_messages_size;
+ else
+ need_read_watch = transport->receive_credentials_pending ||
+ _dbus_auth_do_work (transport->auth) == DBUS_AUTH_STATE_WAITING_FOR_INPUT;
+ _dbus_verbose ("need_read_watch = %d authenticated = %d\n",
+ need_read_watch, _dbus_transport_get_is_authenticated (transport));
+
if (transport->disconnected)
need_read_watch = FALSE;
@@ -213,7 +225,12 @@ check_read_watch (DBusTransport *transport)
_dbus_watch_unref (unix_transport->read_watch);
unix_transport->read_watch = NULL;
}
-
+ else
+ {
+ _dbus_verbose ("Read watch is unchanged from %p on fd %d\n",
+ unix_transport->read_watch, unix_transport->fd);
+ }
+
out:
_dbus_transport_unref (transport);
}
@@ -552,6 +569,7 @@ do_authentication (DBusTransport *transport,
}
out:
+ check_read_watch (transport);
check_write_watch (transport);
_dbus_transport_unref (transport);
}
@@ -902,10 +920,12 @@ unix_do_iteration (DBusTransport *transport,
dbus_bool_t do_select;
int select_res;
- _dbus_verbose (" iteration flags = %s%s timeout = %d\n",
+ _dbus_verbose (" iteration flags = %s%s timeout = %d read_watch = %p write_watch = %p\n",
flags & DBUS_ITERATION_DO_READING ? "read" : "",
flags & DBUS_ITERATION_DO_WRITING ? "write" : "",
- timeout_milliseconds);
+ timeout_milliseconds,
+ unix_transport->read_watch,
+ unix_transport->write_watch);
/* "again" has to be up here because on EINTR the fd sets become
* undefined
@@ -948,13 +968,15 @@ unix_do_iteration (DBusTransport *transport,
auth_state = _dbus_auth_do_work (transport->auth);
- if (auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT)
+ if (transport->receive_credentials_pending ||
+ auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT)
{
FD_SET (unix_transport->fd, &read_set);
do_select = TRUE;
}
- if (auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND)
+ if (transport->send_credentials_pending ||
+ auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND)
{
FD_SET (unix_transport->fd, &write_set);
do_select = TRUE;
diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c
index 1f34b3bb..fc7fd33f 100644
--- a/dbus/dbus-transport.c
+++ b/dbus/dbus-transport.c
@@ -485,6 +485,9 @@ _dbus_transport_do_iteration (DBusTransport *transport,
{
_dbus_assert (transport->vtable->do_iteration != NULL);
+ _dbus_verbose ("Transport iteration flags 0x%x timeout %d connected = %d\n",
+ flags, timeout_milliseconds, !transport->disconnected);
+
if ((flags & (DBUS_ITERATION_DO_WRITING |
DBUS_ITERATION_DO_READING)) == 0)
return; /* Nothing to do */
diff --git a/glib/dbus-glib.h b/glib/dbus-glib.h
index b280e1b7..6d90df94 100644
--- a/glib/dbus-glib.h
+++ b/glib/dbus-glib.h
@@ -26,7 +26,8 @@
#include <dbus/dbus.h>
#include <glib.h>
-void dbus_gthread_init (void);
-void dbus_connection_hookup_with_g_main (DBusConnection *connection);
+void dbus_gthread_init (void);
+void dbus_connection_setup_with_g_main (DBusConnection *connection);
+void dbus_server_setup_with_g_main (DBusServer *server);
#endif /* DBUS_GLIB_H */
diff --git a/glib/dbus-gmain.c b/glib/dbus-gmain.c
index f8355a3f..2638d54b 100644
--- a/glib/dbus-gmain.c
+++ b/glib/dbus-gmain.c
@@ -24,40 +24,77 @@
#include "dbus-glib.h"
#include <glib.h>
-typedef struct _DBusGSource DBusGSource;
+/**
+ * @defgroup DBusGLib GLib bindings
+ * @ingroup DBus
+ * @brief API for using D-BUS with GLib
+ *
+ * Convenience functions are provided for using D-BUS
+ * with the GLib library (see http://www.gtk.org for GLib
+ * information).
+ *
+ */
-struct _DBusGSource
+/**
+ * @defgroup DBusGLibInternals GLib bindings implementation details
+ * @ingroup DBusInternals
+ * @brief Implementation details of GLib bindings
+ *
+ * @{
+ */
+
+/** @typedef DBusGSource
+ * A GSource representing a #DBusConnection or #DBusServer
+ */
+typedef struct DBusGSource DBusGSource;
+
+struct DBusGSource
{
- GSource source;
+ GSource source; /**< the parent GSource */
- DBusConnection *connection;
+ GList *poll_fds; /**< descriptors we're watching */
+ GHashTable *watches; /**< hash of DBusWatch objects */
- GList *poll_fds;
- GHashTable *watches;
+ void *connection_or_server; /**< DBusConnection or DBusServer */
};
+static GStaticMutex connection_slot_lock = G_STATIC_MUTEX_INIT;
static int connection_slot = -1;
+static GStaticMutex server_slot_lock = G_STATIC_MUTEX_INIT;
+static int server_slot = -1;
static gboolean dbus_connection_prepare (GSource *source,
- gint *timeout);
+ gint *timeout);
static gboolean dbus_connection_check (GSource *source);
static gboolean dbus_connection_dispatch (GSource *source,
- GSourceFunc callback,
- gpointer user_data);
-
-
-static GSourceFuncs dbus_funcs = {
+ GSourceFunc callback,
+ gpointer user_data);
+static gboolean dbus_server_prepare (GSource *source,
+ gint *timeout);
+static gboolean dbus_server_check (GSource *source);
+static gboolean dbus_server_dispatch (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data);
+
+static GSourceFuncs dbus_connection_funcs = {
dbus_connection_prepare,
dbus_connection_check,
dbus_connection_dispatch,
NULL
};
+static GSourceFuncs dbus_server_funcs = {
+ dbus_server_prepare,
+ dbus_server_check,
+ dbus_server_dispatch,
+ NULL
+};
+
static gboolean
dbus_connection_prepare (GSource *source,
gint *timeout)
{
- DBusConnection *connection = ((DBusGSource *)source)->connection;
+ DBusConnection *connection = ((DBusGSource *)source)->connection_or_server;
*timeout = -1;
@@ -65,7 +102,16 @@ dbus_connection_prepare (GSource *source,
}
static gboolean
-dbus_connection_check (GSource *source)
+dbus_server_prepare (GSource *source,
+ gint *timeout)
+{
+ *timeout = -1;
+
+ return FALSE;
+}
+
+static gboolean
+dbus_gsource_check (GSource *source)
{
DBusGSource *dbus_source = (DBusGSource *)source;
GList *list;
@@ -86,9 +132,22 @@ dbus_connection_check (GSource *source)
}
static gboolean
-dbus_connection_dispatch (GSource *source,
- GSourceFunc callback,
- gpointer user_data)
+dbus_connection_check (GSource *source)
+{
+ return dbus_gsource_check (source);
+}
+
+static gboolean
+dbus_server_check (GSource *source)
+{
+ return dbus_gsource_check (source);
+}
+
+static gboolean
+dbus_gsource_dispatch (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data,
+ dbus_bool_t is_server)
{
DBusGSource *dbus_source = (DBusGSource *)source;
GList *copy, *list;
@@ -115,21 +174,63 @@ dbus_connection_dispatch (GSource *source,
condition |= DBUS_WATCH_ERROR;
if (poll_fd->revents & G_IO_HUP)
condition |= DBUS_WATCH_HANGUP;
-
- dbus_connection_handle_watch (dbus_source->connection, watch, condition);
+
+ if (is_server)
+ dbus_server_handle_watch (dbus_source->connection_or_server,
+ watch, condition);
+ else
+ dbus_connection_handle_watch (dbus_source->connection_or_server,
+ watch, condition);
}
list = list->next;
}
- g_list_free (copy);
-
- /* Dispatch messages */
- while (dbus_connection_dispatch_message (dbus_source->connection));
+ g_list_free (copy);
return TRUE;
}
+static gboolean
+dbus_connection_dispatch (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ DBusGSource *dbus_source = (DBusGSource *)source;
+ DBusConnection *connection = dbus_source->connection_or_server;
+
+ dbus_connection_ref (connection);
+
+ dbus_gsource_dispatch (source, callback, user_data,
+ FALSE);
+
+ /* Dispatch messages */
+ while (dbus_connection_dispatch_message (connection))
+ ;
+
+ dbus_connection_unref (connection);
+
+ return TRUE;
+}
+
+static gboolean
+dbus_server_dispatch (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ DBusGSource *dbus_source = (DBusGSource *)source;
+ DBusServer *server = dbus_source->connection_or_server;
+
+ dbus_server_ref (server);
+
+ dbus_gsource_dispatch (source, callback, user_data,
+ TRUE);
+
+ dbus_server_unref (server);
+
+ return TRUE;
+}
+
static void
add_watch (DBusWatch *watch,
gpointer data)
@@ -184,7 +285,6 @@ timeout_handler (gpointer data)
return FALSE;
}
-
static void
add_timeout (DBusTimeout *timeout,
void *data)
@@ -204,7 +304,7 @@ remove_timeout (DBusTimeout *timeout,
guint timeout_tag;
timeout_tag = GPOINTER_TO_UINT (dbus_timeout_get_data (timeout));
-
+
g_source_remove (timeout_tag);
}
@@ -214,33 +314,112 @@ free_source (GSource *source)
g_source_destroy (source);
}
-void
-dbus_connection_hookup_with_g_main (DBusConnection *connection)
+/** @} */ /* End of GLib bindings internals */
+
+/** @addtogroup DBusGLib
+ * @{
+ */
+
+static GSource*
+create_source (void *connection_or_server,
+ GSourceFuncs *funcs)
{
GSource *source;
DBusGSource *dbus_source;
- source = g_source_new (&dbus_funcs, sizeof (DBusGSource));
+ source = g_source_new (funcs, sizeof (DBusGSource));
dbus_source = (DBusGSource *)source;
dbus_source->watches = g_hash_table_new (NULL, NULL);
- dbus_source->connection = connection;
+ dbus_source->connection_or_server = connection_or_server;
+
+ return source;
+}
+
+/**
+ * Sets the watch and timeout functions of a #DBusConnection
+ * to integrate the connection with the GLib main loop.
+ *
+ * @param connection the connection
+ */
+void
+dbus_connection_setup_with_g_main (DBusConnection *connection)
+{
+ GSource *source;
+
+ source = create_source (connection, &dbus_connection_funcs);
dbus_connection_set_watch_functions (connection,
- add_watch,
- remove_watch,
- source, NULL);
- dbus_connection_set_timeout_functions (connection,
- add_timeout,
- remove_timeout,
- NULL, NULL);
+ add_watch,
+ remove_watch,
+ source, NULL);
+ dbus_connection_set_timeout_functions (connection,
+ add_timeout,
+ remove_timeout,
+ NULL, NULL);
+
g_source_attach (source, NULL);
+ g_static_mutex_lock (&connection_slot_lock);
if (connection_slot == -1 )
connection_slot = dbus_connection_allocate_data_slot ();
+ g_static_mutex_unlock (&connection_slot_lock);
- dbus_connection_set_data (connection, connection_slot, source,
- (DBusFreeFunction)free_source);
-
+ if (connection_slot < 0)
+ goto nomem;
+
+ if (!dbus_connection_set_data (connection, connection_slot, source,
+ (DBusFreeFunction)free_source))
+ goto nomem;
+
+ return;
+
+ nomem:
+ g_error ("Not enough memory to set up DBusConnection for use with GLib");
+}
+
+/**
+ * Sets the watch and timeout functions of a #DBusServer
+ * to integrate the server with the GLib main loop.
+ *
+ * @param server the server
+ */
+void
+dbus_server_setup_with_g_main (DBusServer *server)
+{
+ GSource *source;
+
+ source = create_source (server, &dbus_server_funcs);
+
+ dbus_server_set_watch_functions (server,
+ add_watch,
+ remove_watch,
+ source, NULL);
+
+ dbus_server_set_timeout_functions (server,
+ add_timeout,
+ remove_timeout,
+ NULL, NULL);
+
+ g_source_attach (source, NULL);
+
+ g_static_mutex_lock (&server_slot_lock);
+ if (server_slot == -1 )
+ server_slot = dbus_server_allocate_data_slot ();
+ g_static_mutex_unlock (&server_slot_lock);
+
+ if (server_slot < 0)
+ goto nomem;
+
+ if (!dbus_server_set_data (server, server_slot, source,
+ (DBusFreeFunction)free_source))
+ goto nomem;
+
+ return;
+
+ nomem:
+ g_error ("Not enough memory to set up DBusServer for use with GLib");
}
+
+/** @} */ /* end of public API */
diff --git a/glib/dbus-gthread.c b/glib/dbus-gthread.c
index 8ed0a13a..71a3c1f5 100644
--- a/glib/dbus-gthread.c
+++ b/glib/dbus-gthread.c
@@ -25,6 +25,10 @@
#include <dbus/dbus.h>
#include "dbus-glib.h"
+/** @addtogroup DBusGLibInternals
+ * @{
+ */
+
static DBusMutex * dbus_gmutex_new (void);
static void dbus_gmutex_free (DBusMutex *mutex);
static dbus_bool_t dbus_gmutex_lock (DBusMutex *mutex);
@@ -149,7 +153,17 @@ dbus_gcondvar_wake_all (DBusCondVar *cond)
g_cond_broadcast ((GCond *)cond);
}
+/** @} End of internals */
+/** @addtogroup DBusGLib
+ * @{
+ */
+/**
+ * Initializes the D-BUS thread system to use
+ * GLib threads. This function may only be called
+ * once and must be called prior to calling any
+ * other function in the D-BUS API.
+ */
void
dbus_gthread_init (void)
{
@@ -158,3 +172,5 @@ dbus_gthread_init (void)
dbus_threads_init (&functions);
}
+
+/** @} end of public API */
diff --git a/glib/test-dbus-glib.c b/glib/test-dbus-glib.c
index b1ca2d3c..fe9cd6b9 100644
--- a/glib/test-dbus-glib.c
+++ b/glib/test-dbus-glib.c
@@ -27,7 +27,7 @@ main (int argc, char **argv)
return 1;
}
- dbus_connection_hookup_with_g_main (connection);
+ dbus_connection_setup_with_g_main (connection);
message = dbus_message_new ("org.freedesktop.DBus", "org.freedesktop.DBus.Hello");