2003-02-26 Havoc Pennington <hp@pobox.com>
authorHavoc Pennington <hp@redhat.com>
Wed, 26 Feb 2003 06:42:57 +0000 (06:42 +0000)
committerHavoc Pennington <hp@redhat.com>
Wed, 26 Feb 2003 06:42:57 +0000 (06:42 +0000)
* 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

21 files changed:
ChangeLog
Doxyfile.in
dbus/Makefile.am
dbus/dbus-connection.c
dbus/dbus-dataslot.c [new file with mode: 0644]
dbus/dbus-dataslot.h [new file with mode: 0644]
dbus/dbus-internals.h
dbus/dbus-keyring.c
dbus/dbus-message.c
dbus/dbus-server-protected.h
dbus/dbus-server.c
dbus/dbus-server.h
dbus/dbus-test.c
dbus/dbus-test.h
dbus/dbus-threads.c
dbus/dbus-transport-unix.c
dbus/dbus-transport.c
glib/dbus-glib.h
glib/dbus-gmain.c
glib/dbus-gthread.c
glib/test-dbus-glib.c

index 9b6005e..87adb2a 100644 (file)
--- 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):
index f01db5d..c476deb 100644 (file)
@@ -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
index eb7f5c9..7a064ce 100644 (file)
@@ -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                        \
index 64e83d1..6fb4e84 100644 (file)
@@ -33,6 +33,7 @@
 #include "dbus-message-handler.h"
 #include "dbus-threads.h"
 #include "dbus-protocol.h"
+#include "dbus-dataslot.h"
 
 /**
  * @defgroup DBusConnection DBusConnection
 
 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 (file)
index 0000000..a5909ff
--- /dev/null
@@ -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 (file)
index 0000000..4bb6091
--- /dev/null
@@ -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 */
index 551a377..d928a5c 100644 (file)
@@ -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;
 
index ea20c9c..2162e29 100644 (file)
@@ -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
 
index 584acc7..355d631 100644 (file)
@@ -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.
  */
index f155bbb..24b805c 100644 (file)
@@ -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. */
index 01435e1..0065e51 100644 (file)
@@ -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;
+}
+
 /** @} */
 
index 68d9500..fc3a57e 100644 (file)
@@ -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 */
index b1f8ac1..29ad855 100644 (file)
@@ -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");
index b5e3848..2fc2901 100644 (file)
@@ -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,
index 2a903a2..08cebf5 100644 (file)
@@ -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}
index b30dc1d..81c18b4 100644 (file)
@@ -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;
index 1f34b3b..fc7fd33 100644 (file)
@@ -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 */
index b280e1b..6d90df9 100644 (file)
@@ -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 */
index f8355a3..2638d54 100644 (file)
 #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 */
index 8ed0a13..71a3c1f 100644 (file)
 #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 */
index b1ca2d3..fe9cd6b 100644 (file)
@@ -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");