2003-03-24 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / bus / dispatch.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dispatch.c  Message dispatcher
3  *
4  * Copyright (C) 2003  CodeFactory AB
5  * Copyright (C) 2003  Red Hat, Inc.
6  *
7  * Licensed under the Academic Free License version 1.2
8  * 
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24
25 #include "dispatch.h"
26 #include "connection.h"
27 #include "driver.h"
28 #include "services.h"
29 #include "utils.h"
30 #include "bus.h"
31 #include "test.h"
32 #include "loop.h"
33 #include <dbus/dbus-internals.h>
34 #include <string.h>
35
36 static int message_handler_slot = -1;
37 static int message_handler_slot_refcount;
38
39 typedef struct
40 {
41   DBusMessage    *message;
42   BusTransaction *transaction;
43   DBusError      *error;
44 } SendMessageData;
45
46 static dbus_bool_t
47 send_one_message (DBusConnection *connection, void *data)
48 {
49   SendMessageData *d = data;
50   
51   if (!bus_connection_is_active (connection))
52     return TRUE;
53
54   if (!bus_transaction_send_message (d->transaction,
55                                      connection,
56                                      d->message))
57     {
58       BUS_SET_OOM (d->error);
59       return FALSE;
60     }
61
62   return TRUE;
63 }
64
65 dbus_bool_t
66 bus_dispatch_broadcast_message (BusTransaction *transaction,
67                                 DBusMessage    *message,
68                                 DBusError      *error)
69 {
70   DBusError tmp_error;
71   SendMessageData d;
72   BusConnections *connections;
73   
74   _dbus_assert (dbus_message_get_sender (message) != NULL);
75
76   connections = bus_transaction_get_connections (transaction);
77   
78   dbus_error_init (&tmp_error);
79   d.message = message;
80   d.transaction = transaction;
81   d.error = &tmp_error;
82   
83   bus_connections_foreach (connections, send_one_message, &d);
84
85   if (dbus_error_is_set (&tmp_error))
86     {
87       dbus_move_error (&tmp_error, error);
88       return FALSE;
89     }
90   else
91     return TRUE;
92 }
93
94 static dbus_bool_t
95 send_service_nonexistent_error (BusTransaction *transaction,
96                                 DBusConnection *connection,
97                                 const char     *service_name,
98                                 DBusMessage    *in_reply_to,
99                                 DBusError      *error)
100 {
101   DBusMessage *error_reply;
102   DBusString error_message;
103   const char *error_str;
104           
105   /* Trying to send a message to a non-existant service,
106    * bounce back an error message.
107    */
108           
109   if (!_dbus_string_init (&error_message, _DBUS_INT_MAX))
110     {
111       BUS_SET_OOM (error);
112       return FALSE;
113     }
114
115   if (!_dbus_string_append (&error_message, "Service \"") ||
116       !_dbus_string_append (&error_message, service_name) ||
117       !_dbus_string_append (&error_message, "\" does not exist"))
118     {
119       _dbus_string_free (&error_message);
120       BUS_SET_OOM (error);
121       return FALSE;
122     }
123               
124   _dbus_string_get_const_data (&error_message, &error_str);
125   error_reply = dbus_message_new_error_reply (in_reply_to,
126                                               DBUS_ERROR_SERVICE_DOES_NOT_EXIST,
127                                               error_str);
128
129   _dbus_string_free (&error_message);
130               
131   if (error_reply == NULL)
132     {
133       BUS_SET_OOM (error);
134       return FALSE;
135     }
136               
137   if (!bus_transaction_send_message (transaction, connection, error_reply))
138     {
139       dbus_message_unref (error_reply);
140       BUS_SET_OOM (error);
141       return FALSE;
142     }
143               
144   dbus_message_unref (error_reply);
145
146   return TRUE;
147 }
148
149 static void
150 bus_dispatch (DBusConnection *connection,
151               DBusMessage    *message)
152 {
153   const char *sender, *service_name, *message_name;
154   DBusError error;
155   BusTransaction *transaction;
156   BusContext *context;
157   
158   transaction = NULL;
159   dbus_error_init (&error);
160   
161   context = bus_connection_get_context (connection);
162   _dbus_assert (context != NULL);
163   
164   /* If we can't even allocate an OOM error, we just go to sleep
165    * until we can.
166    */
167   while (!bus_connection_preallocate_oom_error (connection))
168     bus_wait_for_memory ();
169   
170   /* Ref connection in case we disconnect it at some point in here */
171   dbus_connection_ref (connection);
172
173   service_name = dbus_message_get_service (message);
174   message_name = dbus_message_get_name (message);
175
176   _dbus_assert (message_name != NULL); /* DBusMessageLoader is supposed to check this */
177
178   _dbus_verbose ("DISPATCH: %s to %s\n",
179                  message_name, service_name ? service_name : "peer");
180   
181   /* If service_name is NULL, this is a message to the bus daemon, not intended
182    * to actually go "on the bus"; e.g. a peer-to-peer ping. Handle these
183    * immediately, especially disconnection messages.
184    */
185   if (service_name == NULL)
186     {      
187       if (strcmp (message_name, DBUS_MESSAGE_LOCAL_DISCONNECT) == 0)
188         bus_connection_disconnected (connection);
189
190       /* DBusConnection also handles some of these automatically, we leave
191        * it to do so.
192        */
193       goto out;
194     }
195
196   _dbus_assert (service_name != NULL); /* this message is intended for bus routing */
197   
198   /* Create our transaction */
199   transaction = bus_transaction_new (context);
200   if (transaction == NULL)
201     {
202       BUS_SET_OOM (&error);
203       goto out;
204     }
205   
206   /* Assign a sender to the message */
207   if (bus_connection_is_active (connection))
208     {
209       sender = bus_connection_get_name (connection);
210       _dbus_assert (sender != NULL);
211
212       if (!dbus_message_set_sender (message, sender))
213         {
214           BUS_SET_OOM (&error);
215           goto out;
216         }
217
218       /* We need to refetch the service name here, because
219        * dbus_message_set_sender can cause the header to be
220        * reallocated, and thus the service_name pointer will become
221        * invalid.
222        */
223       service_name = dbus_message_get_service (message);
224     }
225
226   if (strcmp (service_name, DBUS_SERVICE_DBUS) == 0) /* to bus driver */
227     {
228       if (!bus_driver_handle_message (connection, transaction, message, &error))
229         goto out;
230     }
231   else if (!bus_connection_is_active (connection)) /* clients must talk to bus driver first */
232     {
233       _dbus_verbose ("Received message from non-registered client. Disconnecting.\n");
234       dbus_connection_disconnect (connection);
235     }
236   /* FIXME what if we un-special-case this service and just have a flag
237    * on services that all service owners will get messages to it, not just
238    * the primary owner.
239    */
240   else if (strcmp (service_name, DBUS_SERVICE_BROADCAST) == 0) /* spam! */
241     {
242       if (!bus_dispatch_broadcast_message (transaction, message, &error))
243         goto out;
244     }
245   else  /* route to named service */
246     {
247       DBusString service_string;
248       BusService *service;
249       BusRegistry *registry;
250
251       registry = bus_connection_get_registry (connection);
252       
253       _dbus_string_init_const (&service_string, service_name);
254       service = bus_registry_lookup (registry, &service_string);
255
256       if (service == NULL)
257         {
258           if (!send_service_nonexistent_error (transaction, connection,
259                                                service_name,
260                                                message, &error))
261             goto out;
262         }
263       else
264         {
265           _dbus_assert (bus_service_get_primary_owner (service) != NULL);
266       
267           /* Dispatch the message */
268           if (!bus_transaction_send_message (transaction,
269                                              bus_service_get_primary_owner (service),
270                                              message))
271             {
272               BUS_SET_OOM (&error);
273               goto out;
274             }
275         }
276     }
277   
278  out:
279   if (dbus_error_is_set (&error))
280     {
281       if (!dbus_connection_get_is_connected (connection))
282         {
283           /* If we disconnected it, we won't bother to send it any error
284            * messages.
285            */
286         }
287       else if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
288         {
289           bus_connection_send_oom_error (connection, message);
290
291           /* cancel transaction due to OOM */
292           if (transaction != NULL)
293             {
294               bus_transaction_cancel_and_free (transaction);
295               transaction = NULL;
296             }
297         }
298       else
299         {
300           /* Try to send the real error, if no mem to do that, send
301            * the OOM error
302            */
303           _dbus_assert (transaction != NULL);
304           
305           if (!bus_transaction_send_error_reply (transaction, connection,
306                                                  &error, message))
307             {
308               bus_connection_send_oom_error (connection, message);
309
310               /* cancel transaction due to OOM */
311               if (transaction != NULL)
312                 {
313                   bus_transaction_cancel_and_free (transaction);
314                   transaction = NULL;
315                 }
316             }
317         }
318       
319       dbus_error_free (&error);
320     }
321
322   if (transaction != NULL)
323     {
324       bus_transaction_execute_and_free (transaction);
325     }
326
327   dbus_connection_unref (connection);
328 }
329
330 static DBusHandlerResult
331 bus_dispatch_message_handler (DBusMessageHandler *handler,
332                               DBusConnection     *connection,
333                               DBusMessage        *message,
334                               void               *user_data)
335 {
336   bus_dispatch (connection, message);
337   
338   return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
339 }
340
341 static dbus_bool_t
342 message_handler_slot_ref (void)
343 {
344   if (message_handler_slot < 0)
345     {
346       message_handler_slot = dbus_connection_allocate_data_slot ();
347       
348       if (message_handler_slot < 0)
349         return FALSE;
350
351       _dbus_assert (message_handler_slot_refcount == 0);
352     }  
353
354   message_handler_slot_refcount += 1;
355
356   return TRUE;
357 }
358
359 static void
360 message_handler_slot_unref (void)
361 {
362   _dbus_assert (message_handler_slot_refcount > 0);
363
364   message_handler_slot_refcount -= 1;
365   
366   if (message_handler_slot_refcount == 0)
367     {
368       dbus_connection_free_data_slot (message_handler_slot);
369       message_handler_slot = -1;
370     }
371 }
372
373 static void
374 free_message_handler (void *data)
375 {
376   DBusMessageHandler *handler = data;
377   
378   _dbus_assert (message_handler_slot >= 0);
379   _dbus_assert (message_handler_slot_refcount > 0);
380   
381   dbus_message_handler_unref (handler);
382   message_handler_slot_unref ();
383 }
384
385 dbus_bool_t
386 bus_dispatch_add_connection (DBusConnection *connection)
387 {
388   DBusMessageHandler *handler;
389
390   if (!message_handler_slot_ref ())
391     return FALSE;
392   
393   handler = dbus_message_handler_new (bus_dispatch_message_handler, NULL, NULL);  
394   if (handler == NULL)
395     {
396       message_handler_slot_unref ();
397       return FALSE;
398     }    
399   
400   if (!dbus_connection_add_filter (connection, handler))
401     {
402       dbus_message_handler_unref (handler);
403       message_handler_slot_unref ();
404       
405       return FALSE;
406     }
407
408   _dbus_assert (message_handler_slot >= 0);
409   _dbus_assert (message_handler_slot_refcount > 0);
410   
411   if (!dbus_connection_set_data (connection,
412                                  message_handler_slot,
413                                  handler,
414                                  free_message_handler))
415     {
416       dbus_message_handler_unref (handler);
417       message_handler_slot_unref ();
418
419       return FALSE;
420     }
421
422   return TRUE;
423 }
424
425 void
426 bus_dispatch_remove_connection (DBusConnection *connection)
427 {
428   /* Here we tell the bus driver that we want to get off. */
429   bus_driver_remove_connection (connection);
430
431   dbus_connection_set_data (connection,
432                             message_handler_slot,
433                             NULL, NULL);
434 }
435
436 #ifdef DBUS_BUILD_TESTS
437
438 typedef dbus_bool_t (* Check1Func) (BusContext     *context);
439 typedef dbus_bool_t (* Check2Func) (BusContext     *context,
440                                     DBusConnection *connection);
441
442 static dbus_bool_t check_no_leftovers (BusContext *context);
443
444 typedef struct
445 {
446   const char *expected_service_name;
447   dbus_bool_t failed;
448 } CheckServiceDeletedData;
449
450 static dbus_bool_t
451 check_service_deleted_foreach (DBusConnection *connection,
452                                void           *data)
453 {
454   CheckServiceDeletedData *d = data;
455   DBusMessage *message;
456   DBusError error;
457   char *service_name;
458
459   dbus_error_init (&error);
460   d->failed = TRUE;
461   service_name = NULL;
462   
463   message = dbus_connection_pop_message (connection);
464   if (message == NULL)
465     {
466       _dbus_warn ("Did not receive a message on %p, expecting %s\n",
467                   connection, DBUS_MESSAGE_SERVICE_DELETED);
468       goto out;
469     }
470   else if (!dbus_message_name_is (message, DBUS_MESSAGE_SERVICE_DELETED))
471     {
472       _dbus_warn ("Received message %s on %p, expecting %s\n",
473                   dbus_message_get_name (message),
474                   connection, DBUS_MESSAGE_SERVICE_DELETED);
475       goto out;
476     }
477   else
478     {
479       if (!dbus_message_get_args (message, &error,
480                                   DBUS_TYPE_STRING, &service_name,
481                                   DBUS_TYPE_INVALID))
482         {
483           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
484             {
485               _dbus_verbose ("no memory to get service name arg\n");
486             }
487           else
488             {
489               _dbus_assert (dbus_error_is_set (&error));
490               _dbus_warn ("Did not get the expected single string argument\n");
491               goto out;
492             }
493         }
494       else if (strcmp (service_name, d->expected_service_name) != 0)
495         {
496           _dbus_warn ("expected deletion of service %s, got deletion of %s\n",
497                       d->expected_service_name,
498                       service_name);
499           goto out;
500         }
501     }
502
503   d->failed = FALSE;
504   
505  out:
506   dbus_free (service_name);
507   dbus_error_free (&error);
508   
509   if (message)
510     dbus_message_unref (message);
511
512   return !d->failed;
513 }
514
515 static void
516 kill_client_connection (BusContext     *context,
517                         DBusConnection *connection)
518 {
519   char *base_service;
520   const char *s;
521   CheckServiceDeletedData csdd;
522
523   _dbus_verbose ("killing connection %p\n", connection);
524   
525   s = dbus_bus_get_base_service (connection);
526   _dbus_assert (s != NULL);
527
528   while ((base_service = _dbus_strdup (s)) == NULL)
529     bus_wait_for_memory ();
530
531   dbus_connection_ref (connection);
532   
533   /* kick in the disconnect handler that unrefs the connection */
534   dbus_connection_disconnect (connection);
535
536   bus_test_flush_bus (context);
537
538   _dbus_assert (bus_test_client_listed (connection));
539   
540   /* Run disconnect handler in test.c */
541   if (bus_connection_dispatch_one_message (connection))
542     _dbus_assert_not_reached ("something received on connection being killed other than the disconnect");
543   
544   _dbus_assert (!dbus_connection_get_is_connected (connection));
545   dbus_connection_unref (connection);
546   connection = NULL;
547   _dbus_assert (!bus_test_client_listed (connection));
548   
549   csdd.expected_service_name = base_service;
550   csdd.failed = FALSE;
551
552   bus_test_clients_foreach (check_service_deleted_foreach,
553                             &csdd);
554
555   dbus_free (base_service);
556   
557   if (csdd.failed)
558     _dbus_assert_not_reached ("didn't get the expected ServiceDeleted messages");
559   
560   if (!check_no_leftovers (context))
561     _dbus_assert_not_reached ("stuff left in message queues after disconnecting a client");
562 }
563
564 static void
565 kill_client_connection_unchecked (DBusConnection *connection)
566 {
567   /* This kills the connection without expecting it to affect
568    * the rest of the bus.
569    */  
570   _dbus_verbose ("Unchecked kill of connection %p\n", connection);
571
572   dbus_connection_ref (connection);
573   dbus_connection_disconnect (connection);
574   /* dispatching disconnect handler will unref once */
575   if (bus_connection_dispatch_one_message (connection))
576     _dbus_assert_not_reached ("message other than disconnect dispatched after failure to register");
577   dbus_connection_unref (connection);
578   _dbus_assert (!bus_test_client_listed (connection));
579 }
580
581 typedef struct
582 {
583   dbus_bool_t failed;
584 } CheckNoMessagesData;
585
586 static dbus_bool_t
587 check_no_messages_foreach (DBusConnection *connection,
588                            void           *data)
589 {
590   CheckNoMessagesData *d = data;
591   DBusMessage *message;
592
593   message = dbus_connection_pop_message (connection);
594   if (message != NULL)
595     {
596       _dbus_warn ("Received message %s on %p, expecting no messages\n",
597                   dbus_message_get_name (message), connection);
598       d->failed = TRUE;
599     }
600
601   if (message)
602     dbus_message_unref (message);
603   return !d->failed;
604 }
605
606 typedef struct
607 {
608   DBusConnection *skip_connection;
609   const char *expected_service_name;
610   dbus_bool_t failed;
611 } CheckServiceCreatedData;
612
613 static dbus_bool_t
614 check_service_created_foreach (DBusConnection *connection,
615                                void           *data)
616 {
617   CheckServiceCreatedData *d = data;
618   DBusMessage *message;
619   DBusError error;
620   char *service_name;
621
622   if (connection == d->skip_connection)
623     return TRUE;
624
625   dbus_error_init (&error);
626   d->failed = TRUE;
627   service_name = NULL;
628   
629   message = dbus_connection_pop_message (connection);
630   if (message == NULL)
631     {
632       _dbus_warn ("Did not receive a message on %p, expecting %s\n",
633                   connection, DBUS_MESSAGE_SERVICE_CREATED);
634       goto out;
635     }
636   else if (!dbus_message_name_is (message, DBUS_MESSAGE_SERVICE_CREATED))
637     {
638       _dbus_warn ("Received message %s on %p, expecting %s\n",
639                   dbus_message_get_name (message),
640                   connection, DBUS_MESSAGE_SERVICE_CREATED);
641       goto out;
642     }
643   else
644     {
645       if (!dbus_message_get_args (message, &error,
646                                   DBUS_TYPE_STRING, &service_name,
647                                   DBUS_TYPE_INVALID))
648         {
649           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
650             {
651               _dbus_verbose ("no memory to get service name arg\n");
652             }
653           else
654             {
655               _dbus_assert (dbus_error_is_set (&error));
656               _dbus_warn ("Did not get the expected single string argument\n");
657               goto out;
658             }
659         }
660       else if (strcmp (service_name, d->expected_service_name) != 0)
661         {
662           _dbus_warn ("expected creation of service %s, got creation of %s\n",
663                       d->expected_service_name,
664                       service_name);
665           goto out;
666         }
667     }
668
669   d->failed = FALSE;
670   
671  out:
672   dbus_free (service_name);
673   dbus_error_free (&error);
674   
675   if (message)
676     dbus_message_unref (message);
677
678   return !d->failed;
679 }
680
681 static dbus_bool_t
682 check_no_leftovers (BusContext *context)
683 {
684   CheckNoMessagesData nmd;
685
686   nmd.failed = FALSE;
687   bus_test_clients_foreach (check_no_messages_foreach,
688                             &nmd);
689   
690   if (nmd.failed)
691     return FALSE;
692   else
693     return TRUE;
694 }
695
696 /* returns TRUE if the correct thing happens,
697  * but the correct thing may include OOM errors.
698  */
699 static dbus_bool_t
700 check_hello_message (BusContext     *context,
701                      DBusConnection *connection)
702 {
703   DBusMessage *message;
704   dbus_int32_t serial;
705   dbus_bool_t retval;
706   DBusError error;
707   char *name;
708   char *acquired;
709   
710   dbus_error_init (&error);
711   name = NULL;
712   acquired = NULL;
713   
714   message = dbus_message_new (DBUS_SERVICE_DBUS,
715                               DBUS_MESSAGE_HELLO);
716
717   if (message == NULL)
718     return TRUE;
719
720   if (!dbus_connection_send (connection, message, &serial))
721     {
722       dbus_message_unref (message);
723       return TRUE;
724     }
725
726   dbus_message_unref (message);
727   message = NULL;
728   
729   bus_test_flush_bus (context);
730
731   if (!dbus_connection_get_is_connected (connection))
732     {
733       _dbus_verbose ("connection was disconnected\n");
734       return TRUE;
735     }
736   
737   retval = FALSE;
738   
739   message = dbus_connection_pop_message (connection);
740   if (message == NULL)
741     {
742       _dbus_warn ("Did not receive a reply to %s %d on %p\n",
743                   DBUS_MESSAGE_HELLO, serial, connection);
744       goto out;
745     }
746
747   _dbus_verbose ("Received %s on %p\n",
748                  dbus_message_get_name (message), connection);
749
750   if (dbus_message_get_is_error (message))
751     {
752       if (dbus_message_name_is (message,
753                                 DBUS_ERROR_NO_MEMORY))
754         {
755           ; /* good, this is a valid response */
756         }
757       else
758         {
759           _dbus_warn ("Did not expect error %s\n",
760                       dbus_message_get_name (message));
761           goto out;
762         }
763     }
764   else
765     {
766       CheckServiceCreatedData scd;
767       
768       if (dbus_message_name_is (message,
769                                 DBUS_MESSAGE_HELLO))
770         {
771           ; /* good, expected */
772         }
773       else
774         {
775           _dbus_warn ("Did not expect reply %s\n",
776                       dbus_message_get_name (message));
777           goto out;
778         }
779
780     retry_get_hello_name:
781       if (!dbus_message_get_args (message, &error,
782                                   DBUS_TYPE_STRING, &name,
783                                   DBUS_TYPE_INVALID))
784         {
785           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
786             {
787               _dbus_verbose ("no memory to get service name arg from hello\n");
788               dbus_error_free (&error);
789               bus_wait_for_memory ();
790               goto retry_get_hello_name;
791             }
792           else
793             {
794               _dbus_assert (dbus_error_is_set (&error));
795               _dbus_warn ("Did not get the expected single string argument to hello\n");
796               goto out;
797             }
798         }
799
800       _dbus_verbose ("Got hello name: %s\n", name);
801
802       while (!dbus_bus_set_base_service (connection, name))
803         bus_wait_for_memory ();
804       
805       scd.skip_connection = NULL;
806       scd.failed = FALSE;
807       scd.expected_service_name = name;
808       bus_test_clients_foreach (check_service_created_foreach,
809                                 &scd);
810       
811       if (scd.failed)
812         goto out;
813       
814       /* Client should also have gotten ServiceAcquired */
815       dbus_message_unref (message);
816       message = dbus_connection_pop_message (connection);
817       if (message == NULL)
818         {
819           _dbus_warn ("Expecting %s, got nothing\n",
820                       DBUS_MESSAGE_SERVICE_ACQUIRED);
821           goto out;
822         }
823       
824     retry_get_acquired_name:
825       if (!dbus_message_get_args (message, &error,
826                                   DBUS_TYPE_STRING, &acquired,
827                                   DBUS_TYPE_INVALID))
828         {
829           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
830             {
831               _dbus_verbose ("no memory to get service name arg from acquired\n");
832               dbus_error_free (&error);
833               bus_wait_for_memory ();
834               goto retry_get_acquired_name;
835             }
836           else
837             {
838               _dbus_assert (dbus_error_is_set (&error));
839               _dbus_warn ("Did not get the expected single string argument to ServiceAcquired\n");
840               goto out;
841             }
842         }
843
844       _dbus_verbose ("Got acquired name: %s\n", acquired);
845
846       if (strcmp (acquired, name) != 0)
847         {
848           _dbus_warn ("Acquired name is %s but expected %s\n",
849                       acquired, name);
850           goto out;
851         }
852     }
853
854   if (!check_no_leftovers (context))
855     goto out;
856   
857   retval = TRUE;
858   
859  out:
860   dbus_error_free (&error);
861   
862   dbus_free (name);
863   dbus_free (acquired);
864   
865   if (message)
866     dbus_message_unref (message);
867   
868   return retval;
869 }
870
871 /* returns TRUE if the correct thing happens,
872  * but the correct thing may include OOM errors.
873  */
874 static dbus_bool_t
875 check_hello_connection (BusContext *context)
876 {
877   DBusConnection *connection;
878   DBusError error;
879
880   dbus_error_init (&error);
881
882   connection = dbus_connection_open ("debug-pipe:name=test-server", &error);
883   if (connection == NULL)
884     {
885       _DBUS_ASSERT_ERROR_IS_SET (&error);
886       dbus_error_free (&error);
887       return TRUE;
888     }
889
890   if (!bus_setup_debug_client (connection))
891     {
892       dbus_connection_disconnect (connection);
893       dbus_connection_unref (connection);
894       return TRUE;
895     }
896
897   if (!check_hello_message (context, connection))
898     return FALSE;
899
900   if (dbus_bus_get_base_service (connection) == NULL)
901     {
902       /* We didn't successfully register, so we can't
903        * do the usual kill_client_connection() checks
904        */
905       kill_client_connection_unchecked (connection);
906     }
907   else
908     {
909       kill_client_connection (context, connection);
910     }
911
912   return TRUE;
913 }
914
915 static void
916 check1_try_iterations (BusContext *context,
917                        const char *description,
918                        Check1Func  func)
919 {
920   int approx_mallocs;
921
922   /* Run once to see about how many mallocs are involved */
923   
924   _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
925   
926   if (! (*func) (context))
927     _dbus_assert_not_reached ("test failed");
928
929   approx_mallocs = _DBUS_INT_MAX - _dbus_get_fail_alloc_counter ();
930
931   _dbus_verbose ("=================\n%s: about %d mallocs total\n=================\n",
932                  description, approx_mallocs);
933   
934   approx_mallocs += 10; /* fudge factor */
935   
936   /* Now run failing each malloc */
937   
938   while (approx_mallocs >= 0)
939     {
940       _dbus_set_fail_alloc_counter (approx_mallocs);
941
942       _dbus_verbose ("\n===\n %s: (will fail malloc %d)\n===\n",
943                      description, approx_mallocs);
944
945       if (! (*func) (context))
946         _dbus_assert_not_reached ("test failed");
947
948       if (!check_no_leftovers (context))
949         _dbus_assert_not_reached ("Messages were left over, should be covered by test suite");
950       
951       approx_mallocs -= 1;
952     }
953
954   _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
955
956   _dbus_verbose ("=================\n%s: all iterations passed\n=================\n",
957                  description);
958 }
959
960 dbus_bool_t
961 bus_dispatch_test (const DBusString *test_data_dir)
962 {
963   BusContext *context;
964   DBusError error;
965   const char *activation_dirs[] = { NULL, NULL };
966   DBusConnection *foo;
967   DBusConnection *bar;
968   DBusConnection *baz;
969
970   dbus_error_init (&error);
971   context = bus_context_new ("debug-pipe:name=test-server",
972                              activation_dirs,
973                              &error);
974   if (context == NULL)
975     _dbus_assert_not_reached ("could not alloc context");
976   
977   foo = dbus_connection_open ("debug-pipe:name=test-server", &error);
978   if (foo == NULL)
979     _dbus_assert_not_reached ("could not alloc connection");
980
981   if (!bus_setup_debug_client (foo))
982     _dbus_assert_not_reached ("could not set up connection");
983
984   if (!check_hello_message (context, foo))
985     _dbus_assert_not_reached ("hello message failed");
986   
987   bar = dbus_connection_open ("debug-pipe:name=test-server", &error);
988   if (bar == NULL)
989     _dbus_assert_not_reached ("could not alloc connection");
990
991   if (!bus_setup_debug_client (bar))
992     _dbus_assert_not_reached ("could not set up connection");
993
994   if (!check_hello_message (context, bar))
995     _dbus_assert_not_reached ("hello message failed");
996   
997   baz = dbus_connection_open ("debug-pipe:name=test-server", &error);
998   if (baz == NULL)
999     _dbus_assert_not_reached ("could not alloc connection");
1000
1001   if (!bus_setup_debug_client (baz))
1002     _dbus_assert_not_reached ("could not set up connection");
1003
1004   if (!check_hello_message (context, baz))
1005     _dbus_assert_not_reached ("hello message failed");
1006
1007   check1_try_iterations (context, "create_and_hello",
1008                          check_hello_connection);
1009   
1010   _dbus_verbose ("Disconnecting foo, bar, and baz\n");
1011
1012   kill_client_connection_unchecked (foo);
1013   kill_client_connection_unchecked (bar);
1014   kill_client_connection_unchecked (baz);
1015
1016   bus_context_unref (context);
1017   
1018   return TRUE;
1019 }
1020 #endif /* DBUS_BUILD_TESTS */