2003-03-17 Havoc Pennington <hp@pobox.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
219   if (strcmp (service_name, DBUS_SERVICE_DBUS) == 0) /* to bus driver */
220     {
221       if (!bus_driver_handle_message (connection, transaction, message, &error))
222         goto out;
223     }
224   else if (!bus_connection_is_active (connection)) /* clients must talk to bus driver first */
225     {
226       _dbus_verbose ("Received message from non-registered client. Disconnecting.\n");
227       dbus_connection_disconnect (connection);
228     }
229   /* FIXME what if we un-special-case this service and just have a flag
230    * on services that all service owners will get messages to it, not just
231    * the primary owner.
232    */
233   else if (strcmp (service_name, DBUS_SERVICE_BROADCAST) == 0) /* spam! */
234     {
235       if (!bus_dispatch_broadcast_message (transaction, message, &error))
236         goto out;
237     }
238   else  /* route to named service */
239     {
240       DBusString service_string;
241       BusService *service;
242       BusRegistry *registry;
243
244       registry = bus_connection_get_registry (connection);
245       
246       _dbus_string_init_const (&service_string, service_name);
247       service = bus_registry_lookup (registry, &service_string);
248
249       if (service == NULL)
250         {
251           if (!send_service_nonexistent_error (transaction, connection,
252                                                service_name,
253                                                message, &error))
254             goto out;
255         }
256       else
257         {
258           _dbus_assert (bus_service_get_primary_owner (service) != NULL);
259       
260           /* Dispatch the message */
261           if (!bus_transaction_send_message (transaction,
262                                              bus_service_get_primary_owner (service),
263                                              message))
264             {
265               BUS_SET_OOM (&error);
266               goto out;
267             }
268         }
269     }
270   
271  out:
272   if (dbus_error_is_set (&error))
273     {
274       if (!dbus_connection_get_is_connected (connection))
275         {
276           /* If we disconnected it, we won't bother to send it any error
277            * messages.
278            */
279         }
280       else if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
281         {
282           bus_connection_send_oom_error (connection, message);
283
284           /* cancel transaction due to OOM */
285           if (transaction != NULL)
286             {
287               bus_transaction_cancel_and_free (transaction);
288               transaction = NULL;
289             }
290         }
291       else
292         {
293           /* Try to send the real error, if no mem to do that, send
294            * the OOM error
295            */
296           _dbus_assert (transaction != NULL);
297           
298           if (!bus_transaction_send_error_reply (transaction, connection,
299                                                  &error, message))
300             {
301               bus_connection_send_oom_error (connection, message);
302
303               /* cancel transaction due to OOM */
304               if (transaction != NULL)
305                 {
306                   bus_transaction_cancel_and_free (transaction);
307                   transaction = NULL;
308                 }
309             }
310         }
311       
312       dbus_error_free (&error);
313     }
314
315   if (transaction != NULL)
316     {
317       bus_transaction_execute_and_free (transaction);
318     }
319
320   dbus_connection_unref (connection);
321 }
322
323 static DBusHandlerResult
324 bus_dispatch_message_handler (DBusMessageHandler *handler,
325                               DBusConnection     *connection,
326                               DBusMessage        *message,
327                               void               *user_data)
328 {
329   bus_dispatch (connection, message);
330   
331   return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
332 }
333
334 static dbus_bool_t
335 message_handler_slot_ref (void)
336 {
337   if (message_handler_slot < 0)
338     {
339       message_handler_slot = dbus_connection_allocate_data_slot ();
340       
341       if (message_handler_slot < 0)
342         return FALSE;
343
344       _dbus_assert (message_handler_slot_refcount == 0);
345     }  
346
347   message_handler_slot_refcount += 1;
348
349   return TRUE;
350 }
351
352 static void
353 message_handler_slot_unref (void)
354 {
355   _dbus_assert (message_handler_slot_refcount > 0);
356
357   message_handler_slot_refcount -= 1;
358   
359   if (message_handler_slot_refcount == 0)
360     {
361       dbus_connection_free_data_slot (message_handler_slot);
362       message_handler_slot = -1;
363     }
364 }
365
366 static void
367 free_message_handler (void *data)
368 {
369   DBusMessageHandler *handler = data;
370   
371   _dbus_assert (message_handler_slot >= 0);
372   _dbus_assert (message_handler_slot_refcount > 0);
373   
374   dbus_message_handler_unref (handler);
375   message_handler_slot_unref ();
376 }
377
378 dbus_bool_t
379 bus_dispatch_add_connection (DBusConnection *connection)
380 {
381   DBusMessageHandler *handler;
382
383   if (!message_handler_slot_ref ())
384     return FALSE;
385   
386   handler = dbus_message_handler_new (bus_dispatch_message_handler, NULL, NULL);  
387   if (handler == NULL)
388     {
389       message_handler_slot_unref ();
390       return FALSE;
391     }    
392   
393   if (!dbus_connection_add_filter (connection, handler))
394     {
395       dbus_message_handler_unref (handler);
396       message_handler_slot_unref ();
397       
398       return FALSE;
399     }
400
401   _dbus_assert (message_handler_slot >= 0);
402   _dbus_assert (message_handler_slot_refcount > 0);
403   
404   if (!dbus_connection_set_data (connection,
405                                  message_handler_slot,
406                                  handler,
407                                  free_message_handler))
408     {
409       dbus_message_handler_unref (handler);
410       message_handler_slot_unref ();
411
412       return FALSE;
413     }
414
415   return TRUE;
416 }
417
418 void
419 bus_dispatch_remove_connection (DBusConnection *connection)
420 {
421   /* Here we tell the bus driver that we want to get off. */
422   bus_driver_remove_connection (connection);
423
424   dbus_connection_set_data (connection,
425                             message_handler_slot,
426                             NULL, NULL);
427 }
428
429 #ifdef DBUS_BUILD_TESTS
430
431 typedef dbus_bool_t (* Check1Func) (BusContext     *context);
432 typedef dbus_bool_t (* Check2Func) (BusContext     *context,
433                                     DBusConnection *connection);
434
435 static dbus_bool_t check_no_leftovers (BusContext *context);
436
437 static void
438 flush_bus (BusContext *context)
439 {
440   /* This is race condition city, obviously. since we're all in one
441    * process we can't block, we just have to wait for data we put in
442    * one end of the debug pipe to come out the other end...
443    * a more robust setup would be good.
444    */
445   
446   while (bus_loop_iterate (FALSE))
447     ;
448   _dbus_sleep_milliseconds (15);
449   while (bus_loop_iterate (FALSE))
450     ;
451 }
452
453 typedef struct
454 {
455   const char *expected_service_name;
456   dbus_bool_t failed;
457 } CheckServiceDeletedData;
458
459 static dbus_bool_t
460 check_service_deleted_foreach (DBusConnection *connection,
461                                void           *data)
462 {
463   CheckServiceDeletedData *d = data;
464   DBusMessage *message;
465   DBusError error;
466   char *service_name;
467
468   dbus_error_init (&error);
469   d->failed = TRUE;
470   service_name = NULL;
471   
472   message = dbus_connection_pop_message (connection);
473   if (message == NULL)
474     {
475       _dbus_warn ("Did not receive a message on %p, expecting %s\n",
476                   connection, DBUS_MESSAGE_SERVICE_DELETED);
477       goto out;
478     }
479   else if (!dbus_message_name_is (message, DBUS_MESSAGE_SERVICE_DELETED))
480     {
481       _dbus_warn ("Received message %s on %p, expecting %s\n",
482                   dbus_message_get_name (message),
483                   connection, DBUS_MESSAGE_SERVICE_DELETED);
484       goto out;
485     }
486   else
487     {
488       if (!dbus_message_get_args (message, &error,
489                                   DBUS_TYPE_STRING, &service_name,
490                                   DBUS_TYPE_INVALID))
491         {
492           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
493             {
494               _dbus_verbose ("no memory to get service name arg\n");
495             }
496           else
497             {
498               _dbus_assert (dbus_error_is_set (&error));
499               _dbus_warn ("Did not get the expected single string argument\n");
500               goto out;
501             }
502         }
503       else if (strcmp (service_name, d->expected_service_name) != 0)
504         {
505           _dbus_warn ("expected deletion of service %s, got deletion of %s\n",
506                       d->expected_service_name,
507                       service_name);
508           goto out;
509         }
510     }
511
512   d->failed = FALSE;
513   
514  out:
515   dbus_free (service_name);
516   dbus_error_free (&error);
517   
518   if (message)
519     dbus_message_unref (message);
520
521   return !d->failed;
522 }
523
524 static void
525 kill_client_connection (BusContext     *context,
526                         DBusConnection *connection)
527 {
528   char *base_service;
529   const char *s;
530   CheckServiceDeletedData csdd;
531
532   _dbus_verbose ("killing connection %p\n", connection);
533   
534   s = dbus_bus_get_base_service (connection);
535   _dbus_assert (s != NULL);
536
537   while ((base_service = _dbus_strdup (s)) == NULL)
538     bus_wait_for_memory ();
539
540   dbus_connection_ref (connection);
541   
542   /* kick in the disconnect handler that unrefs the connection */
543   dbus_connection_disconnect (connection);
544
545   flush_bus (context);
546
547   _dbus_assert (bus_test_client_listed (connection));
548   
549   /* Run disconnect handler in test.c */
550   if (bus_connection_dispatch_one_message (connection))
551     _dbus_assert_not_reached ("something received on connection being killed other than the disconnect");
552   
553   _dbus_assert (!dbus_connection_get_is_connected (connection));
554   dbus_connection_unref (connection);
555   connection = NULL;
556   _dbus_assert (!bus_test_client_listed (connection));
557   
558   csdd.expected_service_name = base_service;
559   csdd.failed = FALSE;
560
561   bus_test_clients_foreach (check_service_deleted_foreach,
562                             &csdd);
563
564   dbus_free (base_service);
565   
566   if (csdd.failed)
567     _dbus_assert_not_reached ("didn't get the expected ServiceDeleted messages");
568   
569   if (!check_no_leftovers (context))
570     _dbus_assert_not_reached ("stuff left in message queues after disconnecting a client");
571 }
572
573 static void
574 kill_client_connection_unchecked (DBusConnection *connection)
575 {
576   /* This kills the connection without expecting it to affect
577    * the rest of the bus.
578    */  
579   _dbus_verbose ("Unchecked kill of connection %p\n", connection);
580
581   dbus_connection_ref (connection);
582   dbus_connection_disconnect (connection);
583   /* dispatching disconnect handler will unref once */
584   if (bus_connection_dispatch_one_message (connection))
585     _dbus_assert_not_reached ("message other than disconnect dispatched after failure to register");
586   dbus_connection_unref (connection);
587   _dbus_assert (!bus_test_client_listed (connection));
588 }
589
590 typedef struct
591 {
592   dbus_bool_t failed;
593 } CheckNoMessagesData;
594
595 static dbus_bool_t
596 check_no_messages_foreach (DBusConnection *connection,
597                            void           *data)
598 {
599   CheckNoMessagesData *d = data;
600   DBusMessage *message;
601
602   message = dbus_connection_pop_message (connection);
603   if (message != NULL)
604     {
605       _dbus_warn ("Received message %s on %p, expecting no messages\n",
606                   dbus_message_get_name (message), connection);
607       d->failed = TRUE;
608     }
609
610   if (message)
611     dbus_message_unref (message);
612   return !d->failed;
613 }
614
615 typedef struct
616 {
617   DBusConnection *skip_connection;
618   const char *expected_service_name;
619   dbus_bool_t failed;
620 } CheckServiceCreatedData;
621
622 static dbus_bool_t
623 check_service_created_foreach (DBusConnection *connection,
624                                void           *data)
625 {
626   CheckServiceCreatedData *d = data;
627   DBusMessage *message;
628   DBusError error;
629   char *service_name;
630
631   if (connection == d->skip_connection)
632     return TRUE;
633
634   dbus_error_init (&error);
635   d->failed = TRUE;
636   service_name = NULL;
637   
638   message = dbus_connection_pop_message (connection);
639   if (message == NULL)
640     {
641       _dbus_warn ("Did not receive a message on %p, expecting %s\n",
642                   connection, DBUS_MESSAGE_SERVICE_CREATED);
643       goto out;
644     }
645   else if (!dbus_message_name_is (message, DBUS_MESSAGE_SERVICE_CREATED))
646     {
647       _dbus_warn ("Received message %s on %p, expecting %s\n",
648                   dbus_message_get_name (message),
649                   connection, DBUS_MESSAGE_SERVICE_CREATED);
650       goto out;
651     }
652   else
653     {
654       if (!dbus_message_get_args (message, &error,
655                                   DBUS_TYPE_STRING, &service_name,
656                                   DBUS_TYPE_INVALID))
657         {
658           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
659             {
660               _dbus_verbose ("no memory to get service name arg\n");
661             }
662           else
663             {
664               _dbus_assert (dbus_error_is_set (&error));
665               _dbus_warn ("Did not get the expected single string argument\n");
666               goto out;
667             }
668         }
669       else if (strcmp (service_name, d->expected_service_name) != 0)
670         {
671           _dbus_warn ("expected creation of service %s, got creation of %s\n",
672                       d->expected_service_name,
673                       service_name);
674           goto out;
675         }
676     }
677
678   d->failed = FALSE;
679   
680  out:
681   dbus_free (service_name);
682   dbus_error_free (&error);
683   
684   if (message)
685     dbus_message_unref (message);
686
687   return !d->failed;
688 }
689
690 static dbus_bool_t
691 check_no_leftovers (BusContext *context)
692 {
693   CheckNoMessagesData nmd;
694
695   nmd.failed = FALSE;
696   bus_test_clients_foreach (check_no_messages_foreach,
697                             &nmd);
698   
699   if (nmd.failed)
700     return FALSE;
701   else
702     return TRUE;
703 }
704
705 /* returns TRUE if the correct thing happens,
706  * but the correct thing may include OOM errors.
707  */
708 static dbus_bool_t
709 check_hello_message (BusContext     *context,
710                      DBusConnection *connection)
711 {
712   DBusMessage *message;
713   dbus_int32_t serial;
714   dbus_bool_t retval;
715   DBusError error;
716   char *name;
717   char *acquired;
718   
719   dbus_error_init (&error);
720   name = NULL;
721   acquired = NULL;
722   
723   message = dbus_message_new (DBUS_SERVICE_DBUS,
724                               DBUS_MESSAGE_HELLO);
725
726   if (message == NULL)
727     return TRUE;
728
729   if (!dbus_connection_send (connection, message, &serial))
730     {
731       dbus_message_unref (message);
732       return TRUE;
733     }
734
735   dbus_message_unref (message);
736   message = NULL;
737   
738   flush_bus (context);
739
740   if (!dbus_connection_get_is_connected (connection))
741     {
742       _dbus_verbose ("connection was disconnected\n");
743       return TRUE;
744     }
745   
746   retval = FALSE;
747   
748   message = dbus_connection_pop_message (connection);
749   if (message == NULL)
750     {
751       _dbus_warn ("Did not receive a reply to %s %d on %p\n",
752                   DBUS_MESSAGE_HELLO, serial, connection);
753       goto out;
754     }
755
756   _dbus_verbose ("Received %s on %p\n",
757                  dbus_message_get_name (message), connection);
758
759   if (dbus_message_get_is_error (message))
760     {
761       if (dbus_message_name_is (message,
762                                 DBUS_ERROR_NO_MEMORY))
763         {
764           ; /* good, this is a valid response */
765         }
766       else
767         {
768           _dbus_warn ("Did not expect error %s\n",
769                       dbus_message_get_name (message));
770           goto out;
771         }
772     }
773   else
774     {
775       CheckServiceCreatedData scd;
776       
777       if (dbus_message_name_is (message,
778                                 DBUS_MESSAGE_HELLO))
779         {
780           ; /* good, expected */
781         }
782       else
783         {
784           _dbus_warn ("Did not expect reply %s\n",
785                       dbus_message_get_name (message));
786           goto out;
787         }
788
789     retry_get_hello_name:
790       if (!dbus_message_get_args (message, &error,
791                                   DBUS_TYPE_STRING, &name,
792                                   DBUS_TYPE_INVALID))
793         {
794           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
795             {
796               _dbus_verbose ("no memory to get service name arg from hello\n");
797               dbus_error_free (&error);
798               bus_wait_for_memory ();
799               goto retry_get_hello_name;
800             }
801           else
802             {
803               _dbus_assert (dbus_error_is_set (&error));
804               _dbus_warn ("Did not get the expected single string argument to hello\n");
805               goto out;
806             }
807         }
808
809       _dbus_verbose ("Got hello name: %s\n", name);
810
811       while (!dbus_bus_set_base_service (connection, name))
812         bus_wait_for_memory ();
813       
814       scd.skip_connection = NULL;
815       scd.failed = FALSE;
816       scd.expected_service_name = name;
817       bus_test_clients_foreach (check_service_created_foreach,
818                                 &scd);
819       
820       if (scd.failed)
821         goto out;
822       
823       /* Client should also have gotten ServiceAcquired */
824       dbus_message_unref (message);
825       message = dbus_connection_pop_message (connection);
826       if (message == NULL)
827         {
828           _dbus_warn ("Expecting %s, got nothing\n",
829                       DBUS_MESSAGE_SERVICE_ACQUIRED);
830           goto out;
831         }
832       
833     retry_get_acquired_name:
834       if (!dbus_message_get_args (message, &error,
835                                   DBUS_TYPE_STRING, &acquired,
836                                   DBUS_TYPE_INVALID))
837         {
838           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
839             {
840               _dbus_verbose ("no memory to get service name arg from acquired\n");
841               dbus_error_free (&error);
842               bus_wait_for_memory ();
843               goto retry_get_acquired_name;
844             }
845           else
846             {
847               _dbus_assert (dbus_error_is_set (&error));
848               _dbus_warn ("Did not get the expected single string argument to ServiceAcquired\n");
849               goto out;
850             }
851         }
852
853       _dbus_verbose ("Got acquired name: %s\n", acquired);
854
855       if (strcmp (acquired, name) != 0)
856         {
857           _dbus_warn ("Acquired name is %s but expected %s\n",
858                       acquired, name);
859           goto out;
860         }
861     }
862
863   if (!check_no_leftovers (context))
864     goto out;
865   
866   retval = TRUE;
867   
868  out:
869   dbus_error_free (&error);
870   
871   dbus_free (name);
872   dbus_free (acquired);
873   
874   if (message)
875     dbus_message_unref (message);
876   
877   return retval;
878 }
879
880 /* returns TRUE if the correct thing happens,
881  * but the correct thing may include OOM errors.
882  */
883 static dbus_bool_t
884 check_hello_connection (BusContext *context)
885 {
886   DBusConnection *connection;
887   DBusResultCode result;
888
889   result = DBUS_RESULT_SUCCESS;
890   connection = dbus_connection_open ("debug-pipe:name=test-server", &result);
891   if (connection == NULL)
892     {
893       _dbus_assert (result != DBUS_RESULT_SUCCESS);
894       return TRUE;
895     }
896
897   if (!bus_setup_debug_client (connection))
898     {
899       dbus_connection_disconnect (connection);
900       dbus_connection_unref (connection);
901       return TRUE;
902     }
903
904   if (!check_hello_message (context, connection))
905     return FALSE;
906
907   if (dbus_bus_get_base_service (connection) == NULL)
908     {
909       /* We didn't successfully register, so we can't
910        * do the usual kill_client_connection() checks
911        */
912       kill_client_connection_unchecked (connection);
913     }
914   else
915     {
916       kill_client_connection (context, connection);
917     }
918
919   return TRUE;
920 }
921
922 static void
923 check1_try_iterations (BusContext *context,
924                        const char *description,
925                        Check1Func  func)
926 {
927   int approx_mallocs;
928
929   /* Run once to see about how many mallocs are involved */
930   
931   _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
932   
933   if (! (*func) (context))
934     _dbus_assert_not_reached ("test failed");
935
936   approx_mallocs = _DBUS_INT_MAX - _dbus_get_fail_alloc_counter ();
937
938   _dbus_verbose ("=================\n%s: about %d mallocs total\n=================\n",
939                  description, approx_mallocs);
940   
941   approx_mallocs += 10; /* fudge factor */
942   
943   /* Now run failing each malloc */
944   
945   while (approx_mallocs >= 0)
946     {
947       _dbus_set_fail_alloc_counter (approx_mallocs);
948
949       _dbus_verbose ("\n===\n %s: (will fail malloc %d)\n===\n",
950                      description, approx_mallocs);
951
952       if (! (*func) (context))
953         _dbus_assert_not_reached ("test failed");
954
955       if (!check_no_leftovers (context))
956         _dbus_assert_not_reached ("Messages were left over, should be covered by test suite");
957       
958       approx_mallocs -= 1;
959     }
960
961   _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
962
963   _dbus_verbose ("=================\n%s: all iterations passed\n=================\n",
964                  description);
965 }
966
967 dbus_bool_t
968 bus_dispatch_test (const DBusString *test_data_dir)
969 {
970   BusContext *context;
971   DBusError error;
972   const char *activation_dirs[] = { NULL, NULL };
973   DBusConnection *foo;
974   DBusConnection *bar;
975   DBusConnection *baz;
976   DBusResultCode result;
977
978   dbus_error_init (&error);
979   context = bus_context_new ("debug-pipe:name=test-server",
980                              activation_dirs,
981                              &error);
982   if (context == NULL)
983     _dbus_assert_not_reached ("could not alloc context");
984   
985   foo = dbus_connection_open ("debug-pipe:name=test-server", &result);
986   if (foo == NULL)
987     _dbus_assert_not_reached ("could not alloc connection");
988
989   if (!bus_setup_debug_client (foo))
990     _dbus_assert_not_reached ("could not set up connection");
991
992   if (!check_hello_message (context, foo))
993     _dbus_assert_not_reached ("hello message failed");
994   
995   bar = dbus_connection_open ("debug-pipe:name=test-server", &result);
996   if (bar == NULL)
997     _dbus_assert_not_reached ("could not alloc connection");
998
999   if (!bus_setup_debug_client (bar))
1000     _dbus_assert_not_reached ("could not set up connection");
1001
1002   if (!check_hello_message (context, bar))
1003     _dbus_assert_not_reached ("hello message failed");
1004   
1005   baz = dbus_connection_open ("debug-pipe:name=test-server", &result);
1006   if (baz == NULL)
1007     _dbus_assert_not_reached ("could not alloc connection");
1008
1009   if (!bus_setup_debug_client (baz))
1010     _dbus_assert_not_reached ("could not set up connection");
1011
1012   if (!check_hello_message (context, baz))
1013     _dbus_assert_not_reached ("hello message failed");
1014
1015   check1_try_iterations (context, "create_and_hello",
1016                          check_hello_connection);
1017   
1018   _dbus_verbose ("Disconnecting foo, bar, and baz\n");
1019
1020   kill_client_connection_unchecked (foo);
1021   kill_client_connection_unchecked (bar);
1022   kill_client_connection_unchecked (baz);
1023
1024   bus_context_unref (context);
1025   
1026   return TRUE;
1027 }
1028 #endif /* DBUS_BUILD_TESTS */