e5a8131507b386f547c5728da916fd45c7aed39c
[platform/upstream/dbus.git] / dbus / dbus-object-registry.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-object-registry.c  DBusObjectRegistry (internals of DBusConnection)
3  *
4  * Copyright (C) 2003  Red Hat Inc.
5  *
6  * Licensed under the Academic Free License version 1.2
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23 #include "dbus-object-registry.h"
24 #include "dbus-connection-internal.h"
25 #include "dbus-internals.h"
26 #include "dbus-hash.h"
27 #include "dbus-protocol.h"
28 #include <string.h>
29
30 /**
31  * @defgroup DBusObjectRegistry Map object IDs to implementations
32  * @ingroup  DBusInternals
33  * @brief DBusObjectRegistry is used by DBusConnection to track object IDs
34  *
35  * Types and functions related to DBusObjectRegistry. These
36  * are all internal.
37  *
38  * @todo interface entries and signal connections are handled pretty
39  * much identically, with lots of duplicate code.  Once we're sure
40  * they will always be the same, we could merge this code.
41  *
42  * @{
43  */
44
45 typedef struct DBusObjectEntry DBusObjectEntry;
46 typedef struct DBusInterfaceEntry DBusInterfaceEntry;
47 typedef struct DBusSignalEntry DBusSignalEntry;
48
49 #define DBUS_MAX_OBJECTS_PER_INTERFACE 65535
50 struct DBusInterfaceEntry
51 {
52   unsigned int n_objects : 16;   /**< Number of objects with this interface */
53   unsigned int n_allocated : 16; /**< Allocated size of objects array */
54   dbus_uint16_t *objects;        /**< Index of each object with the interface */
55   char name[4];                  /**< Name of interface (actually allocated larger) */
56 };
57
58 #define DBUS_MAX_CONNECTIONS_PER_SIGNAL 65535
59 struct DBusSignalEntry
60 {
61   unsigned int n_connections : 16; /**< Number of connections to this signal */
62   unsigned int n_allocated : 16;   /**< Allocated size of objects array */
63   dbus_uint16_t *connections;      /**< Index of each object connected (can have dups for multiple
64                                     * connections)
65                                     */
66   char name[4];                    /**< Interface of signal, nul, then name of signal (actually allocated larger) */
67 };
68
69  /* 14 bits for object index, 32K objects */
70 #define DBUS_OBJECT_INDEX_BITS          (14)
71 #define DBUS_OBJECT_INDEX_MASK          (0x3fff)
72 #define DBUS_MAX_OBJECTS_PER_CONNECTION DBUS_OBJECT_INDEX_MASK
73 struct DBusObjectEntry
74 {
75   unsigned int id_index      : 14; /**< Index of this entry in the entries array */
76   unsigned int id_times_used : 18; /**< Count of times entry has been used; avoids recycling IDs too often */
77
78   void *object_impl;               /**< Pointer to application-supplied implementation */
79   const DBusObjectVTable *vtable;  /**< Virtual table for this object */
80   DBusInterfaceEntry **interfaces; /**< NULL-terminated list of interfaces */
81   DBusSignalEntry    **signals;    /**< Signal connections (contains dups, one each time we connect) */
82 };
83
84 struct DBusObjectRegistry
85 {
86   int refcount;
87   DBusConnection *connection;
88
89   DBusObjectEntry *entries;
90   int n_entries_allocated;
91   int n_entries_used;
92
93   DBusHashTable *interface_table;
94
95   DBusHashTable *signal_table;
96 };
97
98 static void
99 free_interface_entry (void *entry)
100 {
101   DBusInterfaceEntry *iface = entry;
102
103   if (iface == NULL) /* DBusHashTable stupidity */
104     return;
105   
106   dbus_free (iface->objects);
107   dbus_free (iface);
108 }
109
110 static void
111 free_signal_entry (void *entry)
112 {
113   DBusSignalEntry *signal = entry;
114
115   if (signal == NULL) /* DBusHashTable stupidity */
116     return;
117   
118   dbus_free (signal->connections);
119   dbus_free (signal);
120 }
121
122 DBusObjectRegistry*
123 _dbus_object_registry_new (DBusConnection *connection)
124 {
125   DBusObjectRegistry *registry;
126   DBusHashTable *interface_table;
127   DBusHashTable *signal_table;
128   
129   /* the connection passed in here isn't fully constructed,
130    * so don't do anything more than store a pointer to
131    * it
132    */
133
134   registry = NULL;
135   interface_table = NULL;
136   signal_table = NULL;
137   
138   registry = dbus_new0 (DBusObjectRegistry, 1);
139   if (registry == NULL)
140     goto oom;
141
142   interface_table = _dbus_hash_table_new (DBUS_HASH_STRING,
143                                           NULL, free_interface_entry);
144   if (interface_table == NULL)
145     goto oom;
146
147   signal_table = _dbus_hash_table_new (DBUS_HASH_TWO_STRINGS,
148                                        NULL, free_signal_entry);
149   if (signal_table == NULL)
150     goto oom;
151   
152   registry->refcount = 1;
153   registry->connection = connection;
154   registry->interface_table = interface_table;
155   registry->signal_table = signal_table;
156   
157   return registry;
158
159  oom:
160   if (registry)
161     dbus_free (registry);
162   if (interface_table)
163     _dbus_hash_table_unref (interface_table);
164   if (signal_table)
165     _dbus_hash_table_unref (signal_table);
166   
167   return NULL;
168 }
169
170 void
171 _dbus_object_registry_ref (DBusObjectRegistry *registry)
172 {
173   _dbus_assert (registry->refcount > 0);
174
175   registry->refcount += 1;
176 }
177
178 void
179 _dbus_object_registry_unref (DBusObjectRegistry *registry)
180 {
181   _dbus_assert (registry->refcount > 0);
182
183   registry->refcount -= 1;
184
185   if (registry->refcount == 0)
186     {
187       int i;
188       
189       _dbus_assert (registry->n_entries_used == 0);
190       _dbus_assert (_dbus_hash_table_get_n_entries (registry->interface_table) == 0);
191       _dbus_assert (_dbus_hash_table_get_n_entries (registry->signal_table) == 0);
192
193       i = 0;
194       while (i < registry->n_entries_allocated)
195         {
196           if (registry->entries[i].interfaces)
197             dbus_free (registry->entries[i].interfaces);
198           if (registry->entries[i].signals)
199             dbus_free (registry->entries[i].signals);
200           ++i;
201         }
202       
203       _dbus_hash_table_unref (registry->interface_table);
204       _dbus_hash_table_unref (registry->signal_table);
205       dbus_free (registry->entries);
206       dbus_free (registry);
207     }
208 }
209
210 #define ENTRY_TO_ID(entry)                                              \
211   (((dbus_uint32_t) (entry)->id_index) |                                \
212    (((dbus_uint32_t)(entry)->id_times_used) << DBUS_OBJECT_INDEX_BITS))
213
214 #define ID_TO_INDEX(id) \
215   (((dbus_uint32_t) (id)) & DBUS_OBJECT_INDEX_MASK)
216
217 #define ID_TO_TIMES_USED(id) \
218   (((dbus_uint32_t) (id)) >> DBUS_OBJECT_INDEX_BITS)
219
220 static DBusObjectEntry*
221 validate_id (DBusObjectRegistry *registry,
222              const DBusObjectID *object_id)
223 {
224   int idx;
225   int times_used;
226   dbus_uint32_t instance_bits;
227   
228   instance_bits = dbus_object_id_get_instance_bits (object_id);
229
230   /* Verify that connection ID bits are the same */
231 #ifdef DBUS_BUILD_TESTS
232   if (registry->connection)
233 #endif
234     {
235       DBusObjectID tmp_id;
236       
237       _dbus_connection_init_id (registry->connection,
238                                 &tmp_id);
239       dbus_object_id_set_instance_bits (&tmp_id, instance_bits);
240       
241       if (!dbus_object_id_equal (&tmp_id, object_id))
242         return NULL;
243     }
244   
245   idx = ID_TO_INDEX (instance_bits);
246   times_used = ID_TO_TIMES_USED (instance_bits);
247   
248   if (idx >= registry->n_entries_allocated)
249     return NULL;
250   if (registry->entries[idx].vtable == NULL)
251     return NULL;
252   if (registry->entries[idx].id_times_used != times_used)
253     return NULL;
254   _dbus_assert (registry->entries[idx].id_index == idx);
255   _dbus_assert (registry->n_entries_used > 0);
256
257   return &registry->entries[idx];
258 }
259
260 static void
261 id_from_entry (DBusObjectRegistry *registry,
262                DBusObjectID       *object_id,
263                DBusObjectEntry    *entry)
264 {
265 #ifdef DBUS_BUILD_TESTS
266   if (registry->connection)
267 #endif
268     _dbus_connection_init_id (registry->connection,
269                               object_id);
270 #ifdef DBUS_BUILD_TESTS
271   else
272     {
273       dbus_object_id_set_server_bits (object_id, 1);
274       dbus_object_id_set_client_bits (object_id, 2);
275     }
276 #endif
277
278   _dbus_assert (dbus_object_id_get_server_bits (object_id) != 0);
279   _dbus_assert (dbus_object_id_get_client_bits (object_id) != 0);
280   
281   dbus_object_id_set_instance_bits (object_id,
282                                     ENTRY_TO_ID (entry));
283
284   _dbus_assert (dbus_object_id_get_instance_bits (object_id) != 0);
285 }
286
287 static void
288 info_from_entry (DBusObjectRegistry *registry,
289                  DBusObjectInfo     *info,
290                  DBusObjectEntry    *entry)
291 {
292   info->connection = registry->connection;
293   info->object_impl = entry->object_impl;
294
295   id_from_entry (registry, &info->object_id, entry);
296 }
297
298 static DBusInterfaceEntry*
299 lookup_interface (DBusObjectRegistry *registry,
300                   const char         *name,
301                   dbus_bool_t         create_if_not_found)
302 {
303   DBusInterfaceEntry *entry;
304   int sz;
305   int len;
306   
307   entry = _dbus_hash_table_lookup_string (registry->interface_table,
308                                           name);
309   if (entry != NULL || !create_if_not_found)
310     return entry;
311   
312   _dbus_assert (create_if_not_found);
313
314   len = strlen (name);
315   sz = _DBUS_STRUCT_OFFSET (DBusInterfaceEntry, name) + len + 1;
316   entry = dbus_malloc (sz);
317   if (entry == NULL)
318     return NULL;
319   entry->n_objects = 0;
320   entry->n_allocated = 0;
321   entry->objects = NULL;
322   memcpy (entry->name, name, len + 1);
323
324   if (!_dbus_hash_table_insert_string (registry->interface_table,
325                                        entry->name, entry))
326     {
327       dbus_free (entry);
328       return NULL;
329     }
330   
331   return entry;
332 }
333
334 static void
335 delete_interface (DBusObjectRegistry *registry,
336                   DBusInterfaceEntry *entry)
337 {
338   _dbus_hash_table_remove_string (registry->interface_table,
339                                   entry->name);
340 }
341
342 static dbus_bool_t
343 interface_entry_add_object (DBusInterfaceEntry *entry,
344                             dbus_uint16_t       object_index)
345 {
346   if (entry->n_objects == entry->n_allocated)
347     {
348       unsigned int new_alloc;
349       dbus_uint16_t *new_objects;
350       
351       if (entry->n_allocated == 0)
352         new_alloc = 2;
353       else
354         new_alloc = entry->n_allocated * 2;
355
356       /* Right now MAX_OBJECTS_PER_INTERFACE can't possibly be reached
357        * since the max number of objects _total_ is smaller, but the
358        * code is here for future robustness.
359        */
360       
361       if (new_alloc > DBUS_MAX_OBJECTS_PER_INTERFACE)
362         new_alloc = DBUS_MAX_OBJECTS_PER_INTERFACE;
363       if (new_alloc == entry->n_allocated)
364         {
365           _dbus_warn ("Attempting to register another instance with interface %s, but max count %d reached\n",
366                       entry->name, DBUS_MAX_OBJECTS_PER_INTERFACE);
367           return FALSE;
368         }
369
370       new_objects = dbus_realloc (entry->objects, new_alloc * sizeof (dbus_uint16_t));
371       if (new_objects == NULL)
372         return FALSE;
373       entry->objects = new_objects;
374       entry->n_allocated = new_alloc;
375     }
376
377   _dbus_assert (entry->n_objects < entry->n_allocated);
378
379   entry->objects[entry->n_objects] = object_index;
380   entry->n_objects += 1;
381
382   return TRUE;
383 }
384
385 static void
386 interface_entry_remove_object (DBusInterfaceEntry *entry,
387                                dbus_uint16_t       object_index)
388 {
389   unsigned int i;
390
391   i = 0;
392   while (i < entry->n_objects)
393     {
394       if (entry->objects[i] == object_index)
395         break;
396       ++i;
397     }
398
399   if (i == entry->n_objects)
400     {
401       _dbus_assert_not_reached ("Tried to remove object from an interface that didn't list that object\n");
402       return;
403     }
404
405   memmove (&entry->objects[i],
406            &entry->objects[i+1],
407            (entry->n_objects - i - 1) * sizeof (entry->objects[0]));
408   entry->n_objects -= 1;  
409 }
410
411 static void
412 object_remove_from_interfaces (DBusObjectRegistry *registry,
413                                DBusObjectEntry    *entry)
414 {
415   if (entry->interfaces != NULL)
416     {
417       int i;
418       
419       i = 0;
420       while (entry->interfaces[i] != NULL)
421         {
422           DBusInterfaceEntry *iface = entry->interfaces[i];
423           
424           interface_entry_remove_object (iface, entry->id_index);
425           if (iface->n_objects == 0)
426             delete_interface (registry, iface);
427           ++i;
428         }
429     }
430 }
431
432 static DBusSignalEntry*
433 lookup_signal (DBusObjectRegistry *registry,
434                const char         *signal_interface,
435                const char         *signal_name,
436                dbus_bool_t         create_if_not_found)
437 {
438   DBusSignalEntry *entry;
439   int sz;
440   size_t len_interface, len_name;
441   char buf[2 * DBUS_MAXIMUM_NAME_LENGTH + 2];
442
443   /* This is all a little scary and maybe we shouldn't jump
444    * through these hoops just to save some bytes.
445    */
446   
447   len_interface = strlen (signal_interface);
448   len_name = strlen (signal_name);
449   
450   _dbus_assert (len_interface + len_name + 2 <= sizeof (buf));
451
452   memcpy (buf, signal_interface, len_interface + 1);
453   memcpy (buf + len_interface + 1, signal_name, len_name + 1);
454   
455   entry = _dbus_hash_table_lookup_two_strings (registry->signal_table,
456                                                buf);
457   if (entry != NULL || !create_if_not_found)
458     return entry;
459   
460   _dbus_assert (create_if_not_found);
461
462   sz = _DBUS_STRUCT_OFFSET (DBusSignalEntry, name) + len_interface + len_name + 2;
463   entry = dbus_malloc (sz);
464   if (entry == NULL)
465     return NULL;
466   entry->n_connections = 0;
467   entry->n_allocated = 0;
468   entry->connections = NULL;
469   memcpy (entry->name, buf, len_interface + len_name + 2);
470
471   if (!_dbus_hash_table_insert_two_strings (registry->signal_table,
472                                             entry->name, entry))
473     {
474       dbus_free (entry);
475       return NULL;
476     }
477   
478   return entry;
479 }
480
481 static void
482 delete_signal (DBusObjectRegistry *registry,
483                DBusSignalEntry *entry)
484 {
485   _dbus_hash_table_remove_two_strings (registry->signal_table,
486                                        entry->name);
487 }
488
489 static dbus_bool_t
490 signal_entry_add_object (DBusSignalEntry *entry,
491                          dbus_uint16_t    object_index)
492 {
493   if (entry->n_connections == entry->n_allocated)
494     {
495       unsigned int new_alloc;
496       dbus_uint16_t *new_objects;
497       
498       if (entry->n_allocated == 0)
499         new_alloc = 2;
500       else
501         new_alloc = entry->n_allocated * 2;
502
503       /* Right now MAX_CONNECTIONS_PER_SIGNAL can't possibly be reached
504        * since the max number of objects _total_ is smaller, but the
505        * code is here for future robustness.
506        */
507       
508       if (new_alloc > DBUS_MAX_CONNECTIONS_PER_SIGNAL)
509         new_alloc = DBUS_MAX_CONNECTIONS_PER_SIGNAL;
510       if (new_alloc == entry->n_allocated)
511         {
512           _dbus_warn ("Attempting to register another instance with signal %s, but max count %d reached\n",
513                       entry->name, DBUS_MAX_CONNECTIONS_PER_SIGNAL);
514           return FALSE;
515         }
516
517       new_objects = dbus_realloc (entry->connections, new_alloc * sizeof (dbus_uint16_t));
518       if (new_objects == NULL)
519         return FALSE;
520       entry->connections = new_objects;
521       entry->n_allocated = new_alloc;
522     }
523
524   _dbus_assert (entry->n_connections < entry->n_allocated);
525
526   entry->connections[entry->n_connections] = object_index;
527   entry->n_connections += 1;
528
529   return TRUE;
530 }
531
532 static void
533 signal_entry_remove_object (DBusSignalEntry *entry,
534                             dbus_uint16_t    object_index)
535 {
536   unsigned int i;
537
538   i = 0;
539   while (i < entry->n_connections)
540     {
541       if (entry->connections[i] == object_index)
542         break;
543       ++i;
544     }
545
546   if (i == entry->n_connections)
547     {
548       _dbus_assert_not_reached ("Tried to remove object from an signal that didn't list that object\n");
549       return;
550     }
551
552   memmove (&entry->connections[i],
553            &entry->connections[i+1],
554            (entry->n_connections - i - 1) * sizeof (entry->connections[0]));
555   entry->n_connections -= 1;  
556 }
557
558 static void
559 object_remove_from_signals (DBusObjectRegistry *registry,
560                             DBusObjectEntry    *entry)
561 {
562   if (entry->signals != NULL)
563     {
564       int i;
565       
566       i = 0;
567       while (entry->signals[i] != NULL)
568         {
569           DBusSignalEntry *signal = entry->signals[i];
570           
571           signal_entry_remove_object (signal, entry->id_index);
572           if (signal->n_connections == 0)
573             delete_signal (registry, signal);
574           ++i;
575         }
576     }
577 }
578
579 /**
580  * Connect this object to the given signal, such that if a
581  * signal emission message is received with the given
582  * signal name, the message will be routed to the
583  * given object.
584  *
585  * Must be called with #DBusConnection lock held.
586  * 
587  * @param registry the object registry
588  * @param object_id object that would like to see the signal
589  * @param signal_interface signal interface name
590  * @param signal_name signal member name
591  *
592  * @returns #FALSE if no memory
593  */
594 dbus_bool_t
595 _dbus_object_registry_connect_locked (DBusObjectRegistry *registry,
596                                       const DBusObjectID *object_id,
597                                       const char         *signal_interface,
598                                       const char         *signal_name)
599 {
600   DBusSignalEntry **new_signals;
601   DBusSignalEntry *signal;
602   DBusObjectEntry *entry;
603   int i;
604
605   _dbus_assert (signal_interface != NULL);
606   _dbus_assert (signal_name != NULL);
607   
608   entry = validate_id (registry, object_id);
609   if (entry == NULL)
610     {
611       _dbus_warn ("Tried to connect a nonexistent D-BUS object ID to signal \"%s\"\n",
612                   signal_name);
613       
614       return FALSE;
615     }
616
617   /* O(n) in number of connections unfortunately, but in practice I
618    * don't think it will matter.  It's marginally a space-time
619    * tradeoff (save an n_signals field) but the NULL termination is
620    * just as large as an n_signals once we have even a single
621    * connection.
622    */
623   i = 0;
624   if (entry->signals != NULL)
625     {
626       while (entry->signals[i] != NULL)
627         ++i;
628     }
629   
630   new_signals = dbus_realloc (entry->signals,
631                               (i + 2) * sizeof (DBusSignalEntry*));
632   
633   if (new_signals == NULL)
634     return FALSE;
635
636   entry->signals = new_signals;
637   
638   signal = lookup_signal (registry, signal_interface, signal_name, TRUE); 
639   if (signal == NULL)
640     goto oom;
641
642   if (!signal_entry_add_object (signal, entry->id_index))
643     goto oom;
644   
645   entry->signals[i] = signal;
646   ++i;
647   entry->signals[i] = NULL;
648
649   return TRUE;
650   
651  oom:
652   if (signal && signal->n_connections == 0)
653     delete_signal (registry, signal);
654   
655   return FALSE;
656 }
657
658 /**
659  * Reverses effects of _dbus_object_registry_disconnect_locked().
660  *
661  * @param registry the object registry
662  * @param object_id object that would like to see the signal
663  * @param signal_interface signal interface
664  * @param signal_name signal name
665  */
666 void
667 _dbus_object_registry_disconnect_locked (DBusObjectRegistry      *registry,
668                                          const DBusObjectID      *object_id,
669                                          const char              *signal_interface,
670                                          const char              *signal_name)
671 {
672   DBusObjectEntry *entry;
673   DBusSignalEntry *signal;
674
675   _dbus_assert (signal_interface != NULL);
676   _dbus_assert (signal_name != NULL);
677   
678   entry = validate_id (registry, object_id);
679   if (entry == NULL)
680     {
681       _dbus_warn ("Tried to disconnect signal \"%s\"::\"%s\" from a nonexistent D-BUS object ID\n",
682                   signal_interface, signal_name);
683       
684       return;
685     }
686
687   signal = lookup_signal (registry, signal_interface, signal_name, FALSE);
688   if (signal == NULL)
689     {
690       _dbus_warn ("Tried to disconnect signal \"%s\"::\"%s\" but no such signal is connected\n",
691                   signal_interface, signal_name);
692       return;
693     }
694   
695   signal_entry_remove_object (signal, entry->id_index);
696
697   if (signal->n_connections == 0)
698     delete_signal (registry, signal);
699 }
700
701 static DBusHandlerResult
702 handle_method_call_and_unlock (DBusObjectRegistry *registry,
703                                DBusMessage        *message)
704 {
705   DBusInterfaceEntry *iface_entry;
706   DBusObjectEntry *object_entry;
707   DBusObjectInfo info;
708   const DBusObjectVTable *vtable;
709   
710   _dbus_assert (registry != NULL);
711   _dbus_assert (message != NULL);  
712
713   /* FIXME handle calls to an object ID instead of just an
714    * interface name
715    */
716   
717   /* If the message isn't to a specific object ID, we send
718    * it to the first object that supports the given interface.
719    */
720   iface_entry = lookup_interface (registry,
721                                   dbus_message_get_interface (message),
722                                   FALSE);
723   
724   if (iface_entry == NULL)
725     {
726 #ifdef DBUS_BUILD_TESTS
727       if (registry->connection)
728 #endif
729         _dbus_connection_unlock (registry->connection);
730
731       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
732     }
733   
734   _dbus_assert (iface_entry->n_objects > 0);
735   _dbus_assert (iface_entry->objects != NULL);
736
737   object_entry = &registry->entries[iface_entry->objects[0]];
738
739
740   /* Once we have an object entry, pass message to the object */
741   
742   _dbus_assert (object_entry->vtable != NULL);
743
744   info_from_entry (registry, &info, object_entry);
745   vtable = object_entry->vtable;
746   
747   /* Drop lock and invoke application code */
748 #ifdef DBUS_BUILD_TESTS
749   if (registry->connection)
750 #endif
751     _dbus_connection_unlock (registry->connection);
752   
753   (* vtable->message) (&info, message);
754
755   return DBUS_HANDLER_RESULT_HANDLED;
756 }
757
758 typedef struct
759 {
760   DBusObjectID id;
761 } ObjectEmitData;
762
763 static DBusHandlerResult
764 handle_signal_and_unlock (DBusObjectRegistry *registry,
765                           DBusMessage        *message)
766 {
767   DBusSignalEntry *signal_entry;
768   int i;
769   ObjectEmitData *objects;
770   int n_objects;
771   
772   _dbus_assert (registry != NULL);
773   _dbus_assert (message != NULL);
774
775   signal_entry = lookup_signal (registry,
776                                 dbus_message_get_interface (message),
777                                 dbus_message_get_member (message),
778                                 FALSE);
779   
780   if (signal_entry == NULL)
781     {
782 #ifdef DBUS_BUILD_TESTS
783       if (registry->connection)
784 #endif
785         _dbus_connection_unlock (registry->connection);
786       
787       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
788     }
789   
790   _dbus_assert (signal_entry->n_connections > 0);
791   _dbus_assert (signal_entry->connections != NULL);
792
793   /* make a copy for safety vs. reentrancy */
794
795   /* FIXME (?) if you disconnect a signal during (vs. before)
796    * emission, you still receive that signal. To fix this uses more
797    * memory because we don't have a per-connection object at the
798    * moment. You would have to introduce a connection object and
799    * refcount it and have a "disconnected" flag. This is more like
800    * GObject semantics but also maybe not important at this level (the
801    * GObject/Qt wrappers can mop it up).
802    */
803   
804   n_objects = signal_entry->n_connections;
805   objects = dbus_new (ObjectEmitData, n_objects);
806
807   if (objects == NULL)
808     {
809 #ifdef DBUS_BUILD_TESTS
810       if (registry->connection)
811 #endif
812         _dbus_connection_unlock (registry->connection);
813       
814       return DBUS_HANDLER_RESULT_NEED_MEMORY;
815     }
816
817   i = 0;
818   while (i < signal_entry->n_connections)
819     {
820       DBusObjectEntry *object_entry;
821       int idx;
822       
823       idx = signal_entry->connections[i];
824
825       object_entry = &registry->entries[idx];
826
827       _dbus_assert (object_entry->vtable != NULL);
828       
829       id_from_entry (registry,
830                      &objects[i].id,
831                      object_entry);
832       
833       ++i;
834     }
835
836 #ifdef DBUS_BUILD_TESTS
837   if (registry->connection)
838 #endif
839     _dbus_connection_ref_unlocked (registry->connection);
840   _dbus_object_registry_ref (registry);
841   dbus_message_ref (message);
842   
843   i = 0;
844   while (i < n_objects)
845     {
846       DBusObjectEntry *object_entry;
847
848       /* If an object ID no longer exists, don't send the
849        * signal
850        */
851       object_entry = validate_id (registry, &objects[i].id);
852       if (object_entry != NULL)
853         {
854           const DBusObjectVTable *vtable;
855           DBusObjectInfo info;
856
857           info_from_entry (registry, &info, object_entry);
858           vtable = object_entry->vtable;
859
860           /* Drop lock and invoke application code */
861 #ifdef DBUS_BUILD_TESTS
862           if (registry->connection)
863 #endif
864             _dbus_connection_unlock (registry->connection);
865           
866           (* vtable->message) (&info, message);
867
868           /* Reacquire lock */
869 #ifdef DBUS_BUILD_TESTS
870           if (registry->connection)
871 #endif
872             _dbus_connection_lock (registry->connection);
873         }
874       ++i;
875     }
876
877   dbus_message_unref (message);
878   _dbus_object_registry_unref (registry);
879 #ifdef DBUS_BUILD_TESTS
880   if (registry->connection)
881 #endif
882     _dbus_connection_unref_unlocked (registry->connection);
883
884   dbus_free (objects);
885   
886   /* Drop lock a final time */
887 #ifdef DBUS_BUILD_TESTS
888   if (registry->connection)
889 #endif
890     _dbus_connection_unlock (registry->connection);
891
892   return DBUS_HANDLER_RESULT_HANDLED;
893 }
894
895 /**
896  * Handle a message, passing it to any objects in the registry that
897  * should receive it.
898  *
899  * @todo handle messages to an object ID, not just those to
900  * an interface name.
901  * 
902  * @param registry the object registry
903  * @param message the message to handle
904  * @returns what to do with the message next
905  */
906 DBusHandlerResult
907 _dbus_object_registry_handle_and_unlock (DBusObjectRegistry *registry,
908                                          DBusMessage        *message)
909 {
910   int type;
911   
912   _dbus_assert (registry != NULL);
913   _dbus_assert (message != NULL);
914   
915   type = dbus_message_get_type (message);
916
917   switch (type)
918     {
919     case DBUS_MESSAGE_TYPE_METHOD_CALL:
920       return handle_method_call_and_unlock (registry, message);
921     case DBUS_MESSAGE_TYPE_SIGNAL:
922       return handle_signal_and_unlock (registry, message);
923     default:
924 #ifdef DBUS_BUILD_TESTS
925       if (registry->connection)
926 #endif
927         _dbus_connection_unlock (registry->connection);
928
929       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
930     }
931 }
932
933 dbus_bool_t
934 _dbus_object_registry_add_and_unlock (DBusObjectRegistry      *registry,
935                                       const char             **interfaces,
936                                       const DBusObjectVTable  *vtable,
937                                       void                    *object_impl,
938                                       DBusObjectID            *object_id)
939 {
940   int idx;
941   int i;
942   DBusObjectInfo info;
943   
944   if (registry->n_entries_used == registry->n_entries_allocated)
945     {
946       DBusObjectEntry *new_entries;
947       int new_alloc;
948
949       if (registry->n_entries_allocated == 0)
950         new_alloc = 16;
951       else
952         {
953           if (registry->n_entries_allocated == DBUS_MAX_OBJECTS_PER_CONNECTION)
954             {
955               _dbus_warn ("Attempting to register a new D-BUS object, but maximum object count of %d reached\n",
956                           DBUS_MAX_OBJECTS_PER_CONNECTION);
957               goto out_0;
958             }
959
960           new_alloc = registry->n_entries_allocated * 2;
961           if (new_alloc > DBUS_MAX_OBJECTS_PER_CONNECTION)
962             new_alloc = DBUS_MAX_OBJECTS_PER_CONNECTION;
963         }
964
965       new_entries = dbus_realloc (registry->entries,
966                                   new_alloc * sizeof (DBusObjectEntry));
967
968       if (new_entries == NULL)
969         goto out_0;
970
971       memset (&new_entries[registry->n_entries_allocated],
972               '\0',
973               sizeof (DBusObjectEntry) * (new_alloc - registry->n_entries_allocated));
974
975       registry->entries = new_entries;
976       registry->n_entries_allocated = new_alloc;
977     }
978   _dbus_assert (registry->n_entries_used < registry->n_entries_allocated);
979
980   /* We linear search for an available entry. However, short-circuit
981    * the hopefully-common situation where we don't have a sparse
982    * array.
983    */
984   if (registry->entries[registry->n_entries_used].vtable == NULL)
985     {
986       idx = registry->n_entries_used;
987     }
988   else
989     {
990       /* If we do have a sparse array, we try to get rid of it rather
991        * than using empty slots on the end, so we won't hit this case
992        * next time.
993        */
994
995       /* If index n_entries_used is occupied, then
996        * there is at least one entry outside of
997        * the range [0, n_entries_used). Thus, there is
998        * at least one blank entry inside that range.
999        */
1000       idx = 0;
1001       while (idx < registry->n_entries_used)
1002         {
1003           if (registry->entries[idx].vtable == NULL)
1004             break;
1005           ++idx;
1006         }
1007
1008       _dbus_assert (idx < registry->n_entries_used);
1009     }
1010   
1011   registry->entries[idx].id_index = idx;
1012   /* Overflow is OK here, but zero isn't as it's a null ID */
1013   registry->entries[idx].id_times_used += 1;
1014   if (registry->entries[idx].id_times_used == 0)
1015     registry->entries[idx].id_times_used += 1;
1016     
1017   registry->entries[idx].vtable = vtable;
1018   registry->entries[idx].object_impl = object_impl;
1019
1020   registry->n_entries_used += 1;
1021
1022   i = 0;
1023   if (interfaces != NULL)
1024     {
1025       while (interfaces[i] != NULL)
1026         ++i;
1027     }
1028
1029   if (i > 0)
1030     {
1031       DBusInterfaceEntry **new_interfaces;
1032       
1033       new_interfaces = 
1034         dbus_realloc (registry->entries[idx].interfaces,
1035                       (i + 1) * sizeof (DBusInterfaceEntry*));
1036       
1037       if (new_interfaces == NULL)
1038         {
1039           /* maintain invariant that .interfaces array points to something
1040            * valid in oom handler (entering this function it pointed to
1041            * stale data but a valid malloc block)
1042            */
1043           dbus_free (registry->entries[idx].interfaces);
1044           registry->entries[idx].interfaces = NULL;
1045           goto out_1;
1046         }
1047
1048       /* NULL-init so it's NULL-terminated and the OOM
1049        * case can see how far we got
1050        */
1051       while (i >= 0)
1052         {
1053           new_interfaces[i] = NULL;
1054           --i;
1055         }
1056       
1057       registry->entries[idx].interfaces = new_interfaces;
1058     }
1059   else
1060     {
1061       dbus_free (registry->entries[idx].interfaces);
1062       registry->entries[idx].interfaces = NULL;
1063     }
1064
1065   /* Fill in interfaces */
1066   if (interfaces != NULL)
1067     {
1068       i = 0;
1069       while (interfaces[i] != NULL)
1070         {
1071           DBusInterfaceEntry *iface;
1072           
1073           iface = lookup_interface (registry, interfaces[i],
1074                                     TRUE);
1075           if (iface == NULL)
1076             goto out_1;
1077           
1078           if (!interface_entry_add_object (iface, idx))
1079             {
1080               if (iface->n_objects == 0)
1081                 delete_interface (registry, iface);
1082               goto out_1;
1083             }
1084           
1085           registry->entries[idx].interfaces[i] = iface;
1086           
1087           ++i;
1088         }
1089     }
1090   
1091   info_from_entry (registry, &info, &registry->entries[idx]);
1092   if (object_id)
1093     *object_id = info.object_id;
1094   
1095   /* Drop lock and invoke application code */
1096 #ifdef DBUS_BUILD_TESTS
1097   if (registry->connection)
1098 #endif
1099     _dbus_connection_unlock (registry->connection);
1100   
1101   (* vtable->registered) (&info);
1102
1103   return TRUE;
1104   
1105  out_1:    
1106   registry->entries[idx].vtable = NULL;
1107   registry->entries[idx].object_impl = NULL;
1108   registry->n_entries_used -= 1;
1109
1110   object_remove_from_interfaces (registry,
1111                                  &registry->entries[idx]);
1112   
1113  out_0:
1114 #ifdef DBUS_BUILD_TESTS
1115   if (registry->connection)
1116 #endif
1117     _dbus_connection_unlock (registry->connection);
1118   return FALSE;
1119 }
1120
1121 void
1122 _dbus_object_registry_remove_and_unlock (DBusObjectRegistry *registry,
1123                                          const DBusObjectID *object_id)
1124 {
1125   DBusObjectInfo info;
1126   DBusObjectEntry *entry;
1127   const DBusObjectVTable *vtable;
1128
1129   entry = validate_id (registry, object_id);
1130   if (entry == NULL)
1131     {
1132       _dbus_warn ("Tried to unregister a nonexistent D-BUS object ID\n");
1133 #ifdef DBUS_BUILD_TESTS
1134       if (registry->connection)
1135 #endif
1136         _dbus_connection_unlock (registry->connection);
1137       
1138       return;
1139     }
1140
1141   object_remove_from_signals (registry, entry);
1142   object_remove_from_interfaces (registry, entry);
1143   
1144   info_from_entry (registry, &info, entry);
1145   vtable = entry->vtable;
1146   entry->vtable = NULL;
1147   entry->object_impl = NULL;
1148   registry->n_entries_used -= 1;
1149   
1150   /* Drop lock and invoke application code */
1151 #ifdef DBUS_BUILD_TESTS
1152   if (registry->connection)
1153 #endif
1154     _dbus_connection_unlock (registry->connection);
1155
1156   (* vtable->unregistered) (&info);
1157 }
1158
1159
1160 void
1161 _dbus_object_registry_free_all_unlocked (DBusObjectRegistry *registry)
1162 {
1163   int i;
1164   
1165   i = 0;
1166   while (registry->n_entries_used > 0)
1167     {
1168       _dbus_assert (i < registry->n_entries_allocated);
1169       if (registry->entries[i].vtable != NULL)
1170         {
1171           DBusObjectInfo info;
1172           const DBusObjectVTable *vtable;
1173
1174           object_remove_from_interfaces (registry,
1175                                          &registry->entries[i]);
1176           
1177           info_from_entry (registry, &info, &registry->entries[i]);
1178           vtable = registry->entries[i].vtable;
1179           registry->entries[i].vtable = NULL;
1180           registry->entries[i].object_impl = NULL;
1181           registry->n_entries_used -= 1;
1182           _dbus_assert (registry->n_entries_used >= 0);
1183
1184           (* vtable->unregistered) (&info);
1185         }
1186
1187       ++i;
1188     }
1189
1190   _dbus_assert (registry->n_entries_used == 0);
1191 }
1192
1193 /** @} */
1194
1195 #ifdef DBUS_BUILD_TESTS
1196 #include "dbus-test.h"
1197 #include <stdio.h>
1198
1199 static void
1200 noop_message_function (DBusObjectInfo *info,
1201                        DBusMessage    *message)
1202 {
1203   /* nothing */
1204 }
1205
1206 static void
1207 add_and_remove_objects (DBusObjectRegistry *registry)
1208 {
1209 #define N_OBJECTS 73
1210   DBusObjectID ids[N_OBJECTS];
1211   const char *zero_interfaces[] = { NULL };
1212   const char *one_interface[] = { "org.freedesktop.Test.Blah", NULL };
1213   const char *three_interfaces[] = { "org.freedesktop.Test.Blah",
1214                                      "org.freedesktop.Test.Baz",
1215                                      "org.freedesktop.Test.Foo",
1216                                      NULL };
1217   int i;
1218   DBusMessage *message;
1219   
1220   i = 0;
1221   while (i < N_OBJECTS)
1222     {
1223       DBusCallbackObject *callback;
1224       const char **interfaces;
1225       
1226       callback = dbus_callback_object_new (noop_message_function, NULL, NULL);
1227       if (callback == NULL)
1228         goto out;
1229
1230       interfaces = NULL;
1231       switch (i % 3)
1232         {
1233         case 0:
1234           interfaces = zero_interfaces;
1235           break;
1236         case 1:
1237           interfaces = one_interface;
1238           break;
1239         case 2:
1240           interfaces = three_interfaces;
1241           break;
1242         }
1243       _dbus_assert (interfaces != NULL);
1244       
1245       if (!_dbus_object_registry_add_and_unlock (registry,
1246                                                  interfaces,
1247                                                  dbus_callback_object_vtable,
1248                                                  callback,
1249                                                  &ids[i]))
1250         {
1251           dbus_callback_object_unref (callback);
1252           goto out;
1253         }
1254
1255       dbus_callback_object_unref (callback);
1256       
1257       ++i;
1258     }
1259                                      
1260   i = 0;
1261   while (i < N_OBJECTS)
1262     {
1263       if (i > (N_OBJECTS - 20) || (i % 3) == 0)
1264         {
1265           _dbus_object_registry_remove_and_unlock (registry,
1266                                                    &ids[i]);
1267           dbus_object_id_set_null (&ids[i]);
1268         }
1269       
1270       ++i;
1271     }
1272                                      
1273   i = 0;
1274   while (i < N_OBJECTS)
1275     {
1276       if (dbus_object_id_is_null (&ids[i]))
1277         {
1278           DBusCallbackObject *callback;
1279           const char **interfaces;
1280       
1281           callback = dbus_callback_object_new (noop_message_function, NULL, NULL);
1282           if (callback == NULL)
1283             goto out;
1284
1285           interfaces = NULL;
1286           switch (i % 4)
1287             {
1288             case 0:
1289               interfaces = NULL;
1290               break;
1291             case 1:
1292               interfaces = zero_interfaces;
1293               break;
1294             case 2:
1295               interfaces = one_interface;
1296               break;
1297             case 3:
1298               interfaces = three_interfaces;
1299               break;
1300             }
1301       
1302           if (!_dbus_object_registry_add_and_unlock (registry,
1303                                                      interfaces,
1304                                                      dbus_callback_object_vtable,
1305                                                      callback,
1306                                                      &ids[i]))
1307             {
1308               dbus_callback_object_unref (callback);
1309               goto out;
1310             }
1311           
1312           dbus_callback_object_unref (callback);
1313         }
1314       
1315       ++i;
1316     }
1317
1318   message = dbus_message_new_method_call ("org.freedesktop.Test.Foo",
1319                                           "Bar", NULL);
1320   if (message != NULL)
1321     {
1322       if (_dbus_object_registry_handle_and_unlock (registry, message) !=
1323           DBUS_HANDLER_RESULT_HANDLED)
1324         _dbus_assert_not_reached ("message not handled\n");
1325       dbus_message_unref (message);
1326     }
1327
1328   message = dbus_message_new_method_call ("org.freedesktop.Test.Blah",
1329                                           "Baz", NULL);
1330   if (message != NULL)
1331     {
1332       if (_dbus_object_registry_handle_and_unlock (registry, message) !=
1333           DBUS_HANDLER_RESULT_HANDLED)
1334         _dbus_assert_not_reached ("message not handled\n");
1335       dbus_message_unref (message);
1336     }
1337
1338   message = dbus_message_new_method_call ("org.freedesktop.Test.NotRegisteredIface",
1339                                           "Boo", NULL);
1340   if (message != NULL)
1341     {
1342       if (_dbus_object_registry_handle_and_unlock (registry, message) !=
1343           DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
1344         _dbus_assert_not_reached ("message handled but no handler was registered\n");
1345       dbus_message_unref (message);
1346     }
1347   
1348   i = 0;
1349   while (i < (N_OBJECTS - 30))
1350     {
1351       _dbus_assert (!dbus_object_id_is_null (&ids[i]));
1352       
1353       _dbus_object_registry_remove_and_unlock (registry,
1354                                                &ids[i]);
1355       ++i;
1356     }
1357
1358  out:
1359   /* unregister the rest this way, to test this function */
1360   _dbus_object_registry_free_all_unlocked (registry);
1361 }
1362
1363 static dbus_bool_t
1364 object_registry_test_iteration (void *data)
1365 {
1366   DBusObjectRegistry *registry;
1367   
1368   registry = _dbus_object_registry_new (NULL);
1369   if (registry == NULL)
1370     return TRUE;
1371
1372   /* we do this twice since realloc behavior will differ each time,
1373    * and the IDs will get recycled leading to slightly different
1374    * codepaths
1375    */
1376   add_and_remove_objects (registry);
1377   add_and_remove_objects (registry);
1378   
1379   _dbus_object_registry_unref (registry);
1380
1381   return TRUE;
1382 }
1383
1384 /**
1385  * @ingroup DBusObjectRegistry
1386  * Unit test for DBusObjectRegistry
1387  * @returns #TRUE on success.
1388  */
1389 dbus_bool_t
1390 _dbus_object_registry_test (void)
1391 {
1392   _dbus_test_oom_handling ("object registry",
1393                            object_registry_test_iteration,
1394                            NULL);
1395   
1396   return TRUE;
1397 }
1398
1399 #endif /* DBUS_BUILD_TESTS */