2003-03-17 Anders Carlsson <andersca@codefactory.se>
[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 static void
445 flush_bus (BusContext *context)
446 {
447   /* This is race condition city, obviously. since we're all in one
448    * process we can't block, we just have to wait for data we put in
449    * one end of the debug pipe to come out the other end...
450    * a more robust setup would be good.
451    */
452   
453   while (bus_loop_iterate (FALSE))
454     ;
455   _dbus_sleep_milliseconds (15);
456   while (bus_loop_iterate (FALSE))
457     ;
458 }
459
460 typedef struct
461 {
462   const char *expected_service_name;
463   dbus_bool_t failed;
464 } CheckServiceDeletedData;
465
466 static dbus_bool_t
467 check_service_deleted_foreach (DBusConnection *connection,
468                                void           *data)
469 {
470   CheckServiceDeletedData *d = data;
471   DBusMessage *message;
472   DBusError error;
473   char *service_name;
474
475   dbus_error_init (&error);
476   d->failed = TRUE;
477   service_name = NULL;
478   
479   message = dbus_connection_pop_message (connection);
480   if (message == NULL)
481     {
482       _dbus_warn ("Did not receive a message on %p, expecting %s\n",
483                   connection, DBUS_MESSAGE_SERVICE_DELETED);
484       goto out;
485     }
486   else if (!dbus_message_name_is (message, DBUS_MESSAGE_SERVICE_DELETED))
487     {
488       _dbus_warn ("Received message %s on %p, expecting %s\n",
489                   dbus_message_get_name (message),
490                   connection, DBUS_MESSAGE_SERVICE_DELETED);
491       goto out;
492     }
493   else
494     {
495       if (!dbus_message_get_args (message, &error,
496                                   DBUS_TYPE_STRING, &service_name,
497                                   DBUS_TYPE_INVALID))
498         {
499           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
500             {
501               _dbus_verbose ("no memory to get service name arg\n");
502             }
503           else
504             {
505               _dbus_assert (dbus_error_is_set (&error));
506               _dbus_warn ("Did not get the expected single string argument\n");
507               goto out;
508             }
509         }
510       else if (strcmp (service_name, d->expected_service_name) != 0)
511         {
512           _dbus_warn ("expected deletion of service %s, got deletion of %s\n",
513                       d->expected_service_name,
514                       service_name);
515           goto out;
516         }
517     }
518
519   d->failed = FALSE;
520   
521  out:
522   dbus_free (service_name);
523   dbus_error_free (&error);
524   
525   if (message)
526     dbus_message_unref (message);
527
528   return !d->failed;
529 }
530
531 static void
532 kill_client_connection (BusContext     *context,
533                         DBusConnection *connection)
534 {
535   char *base_service;
536   const char *s;
537   CheckServiceDeletedData csdd;
538
539   _dbus_verbose ("killing connection %p\n", connection);
540   
541   s = dbus_bus_get_base_service (connection);
542   _dbus_assert (s != NULL);
543
544   while ((base_service = _dbus_strdup (s)) == NULL)
545     bus_wait_for_memory ();
546
547   dbus_connection_ref (connection);
548   
549   /* kick in the disconnect handler that unrefs the connection */
550   dbus_connection_disconnect (connection);
551
552   flush_bus (context);
553
554   _dbus_assert (bus_test_client_listed (connection));
555   
556   /* Run disconnect handler in test.c */
557   if (bus_connection_dispatch_one_message (connection))
558     _dbus_assert_not_reached ("something received on connection being killed other than the disconnect");
559   
560   _dbus_assert (!dbus_connection_get_is_connected (connection));
561   dbus_connection_unref (connection);
562   connection = NULL;
563   _dbus_assert (!bus_test_client_listed (connection));
564   
565   csdd.expected_service_name = base_service;
566   csdd.failed = FALSE;
567
568   bus_test_clients_foreach (check_service_deleted_foreach,
569                             &csdd);
570
571   dbus_free (base_service);
572   
573   if (csdd.failed)
574     _dbus_assert_not_reached ("didn't get the expected ServiceDeleted messages");
575   
576   if (!check_no_leftovers (context))
577     _dbus_assert_not_reached ("stuff left in message queues after disconnecting a client");
578 }
579
580 static void
581 kill_client_connection_unchecked (DBusConnection *connection)
582 {
583   /* This kills the connection without expecting it to affect
584    * the rest of the bus.
585    */  
586   _dbus_verbose ("Unchecked kill of connection %p\n", connection);
587
588   dbus_connection_ref (connection);
589   dbus_connection_disconnect (connection);
590   /* dispatching disconnect handler will unref once */
591   if (bus_connection_dispatch_one_message (connection))
592     _dbus_assert_not_reached ("message other than disconnect dispatched after failure to register");
593   dbus_connection_unref (connection);
594   _dbus_assert (!bus_test_client_listed (connection));
595 }
596
597 typedef struct
598 {
599   dbus_bool_t failed;
600 } CheckNoMessagesData;
601
602 static dbus_bool_t
603 check_no_messages_foreach (DBusConnection *connection,
604                            void           *data)
605 {
606   CheckNoMessagesData *d = data;
607   DBusMessage *message;
608
609   message = dbus_connection_pop_message (connection);
610   if (message != NULL)
611     {
612       _dbus_warn ("Received message %s on %p, expecting no messages\n",
613                   dbus_message_get_name (message), connection);
614       d->failed = TRUE;
615     }
616
617   if (message)
618     dbus_message_unref (message);
619   return !d->failed;
620 }
621
622 typedef struct
623 {
624   DBusConnection *skip_connection;
625   const char *expected_service_name;
626   dbus_bool_t failed;
627 } CheckServiceCreatedData;
628
629 static dbus_bool_t
630 check_service_created_foreach (DBusConnection *connection,
631                                void           *data)
632 {
633   CheckServiceCreatedData *d = data;
634   DBusMessage *message;
635   DBusError error;
636   char *service_name;
637
638   if (connection == d->skip_connection)
639     return TRUE;
640
641   dbus_error_init (&error);
642   d->failed = TRUE;
643   service_name = NULL;
644   
645   message = dbus_connection_pop_message (connection);
646   if (message == NULL)
647     {
648       _dbus_warn ("Did not receive a message on %p, expecting %s\n",
649                   connection, DBUS_MESSAGE_SERVICE_CREATED);
650       goto out;
651     }
652   else if (!dbus_message_name_is (message, DBUS_MESSAGE_SERVICE_CREATED))
653     {
654       _dbus_warn ("Received message %s on %p, expecting %s\n",
655                   dbus_message_get_name (message),
656                   connection, DBUS_MESSAGE_SERVICE_CREATED);
657       goto out;
658     }
659   else
660     {
661       if (!dbus_message_get_args (message, &error,
662                                   DBUS_TYPE_STRING, &service_name,
663                                   DBUS_TYPE_INVALID))
664         {
665           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
666             {
667               _dbus_verbose ("no memory to get service name arg\n");
668             }
669           else
670             {
671               _dbus_assert (dbus_error_is_set (&error));
672               _dbus_warn ("Did not get the expected single string argument\n");
673               goto out;
674             }
675         }
676       else if (strcmp (service_name, d->expected_service_name) != 0)
677         {
678           _dbus_warn ("expected creation of service %s, got creation of %s\n",
679                       d->expected_service_name,
680                       service_name);
681           goto out;
682         }
683     }
684
685   d->failed = FALSE;
686   
687  out:
688   dbus_free (service_name);
689   dbus_error_free (&error);
690   
691   if (message)
692     dbus_message_unref (message);
693
694   return !d->failed;
695 }
696
697 static dbus_bool_t
698 check_no_leftovers (BusContext *context)
699 {
700   CheckNoMessagesData nmd;
701
702   nmd.failed = FALSE;
703   bus_test_clients_foreach (check_no_messages_foreach,
704                             &nmd);
705   
706   if (nmd.failed)
707     return FALSE;
708   else
709     return TRUE;
710 }
711
712 /* returns TRUE if the correct thing happens,
713  * but the correct thing may include OOM errors.
714  */
715 static dbus_bool_t
716 check_hello_message (BusContext     *context,
717                      DBusConnection *connection)
718 {
719   DBusMessage *message;
720   dbus_int32_t serial;
721   dbus_bool_t retval;
722   DBusError error;
723   char *name;
724   char *acquired;
725   
726   dbus_error_init (&error);
727   name = NULL;
728   acquired = NULL;
729   
730   message = dbus_message_new (DBUS_SERVICE_DBUS,
731                               DBUS_MESSAGE_HELLO);
732
733   if (message == NULL)
734     return TRUE;
735
736   if (!dbus_connection_send (connection, message, &serial))
737     {
738       dbus_message_unref (message);
739       return TRUE;
740     }
741
742   dbus_message_unref (message);
743   message = NULL;
744   
745   flush_bus (context);
746
747   if (!dbus_connection_get_is_connected (connection))
748     {
749       _dbus_verbose ("connection was disconnected\n");
750       return TRUE;
751     }
752   
753   retval = FALSE;
754   
755   message = dbus_connection_pop_message (connection);
756   if (message == NULL)
757     {
758       _dbus_warn ("Did not receive a reply to %s %d on %p\n",
759                   DBUS_MESSAGE_HELLO, serial, connection);
760       goto out;
761     }
762
763   _dbus_verbose ("Received %s on %p\n",
764                  dbus_message_get_name (message), connection);
765
766   if (dbus_message_get_is_error (message))
767     {
768       if (dbus_message_name_is (message,
769                                 DBUS_ERROR_NO_MEMORY))
770         {
771           ; /* good, this is a valid response */
772         }
773       else
774         {
775           _dbus_warn ("Did not expect error %s\n",
776                       dbus_message_get_name (message));
777           goto out;
778         }
779     }
780   else
781     {
782       CheckServiceCreatedData scd;
783       
784       if (dbus_message_name_is (message,
785                                 DBUS_MESSAGE_HELLO))
786         {
787           ; /* good, expected */
788         }
789       else
790         {
791           _dbus_warn ("Did not expect reply %s\n",
792                       dbus_message_get_name (message));
793           goto out;
794         }
795
796     retry_get_hello_name:
797       if (!dbus_message_get_args (message, &error,
798                                   DBUS_TYPE_STRING, &name,
799                                   DBUS_TYPE_INVALID))
800         {
801           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
802             {
803               _dbus_verbose ("no memory to get service name arg from hello\n");
804               dbus_error_free (&error);
805               bus_wait_for_memory ();
806               goto retry_get_hello_name;
807             }
808           else
809             {
810               _dbus_assert (dbus_error_is_set (&error));
811               _dbus_warn ("Did not get the expected single string argument to hello\n");
812               goto out;
813             }
814         }
815
816       _dbus_verbose ("Got hello name: %s\n", name);
817
818       while (!dbus_bus_set_base_service (connection, name))
819         bus_wait_for_memory ();
820       
821       scd.skip_connection = NULL;
822       scd.failed = FALSE;
823       scd.expected_service_name = name;
824       bus_test_clients_foreach (check_service_created_foreach,
825                                 &scd);
826       
827       if (scd.failed)
828         goto out;
829       
830       /* Client should also have gotten ServiceAcquired */
831       dbus_message_unref (message);
832       message = dbus_connection_pop_message (connection);
833       if (message == NULL)
834         {
835           _dbus_warn ("Expecting %s, got nothing\n",
836                       DBUS_MESSAGE_SERVICE_ACQUIRED);
837           goto out;
838         }
839       
840     retry_get_acquired_name:
841       if (!dbus_message_get_args (message, &error,
842                                   DBUS_TYPE_STRING, &acquired,
843                                   DBUS_TYPE_INVALID))
844         {
845           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
846             {
847               _dbus_verbose ("no memory to get service name arg from acquired\n");
848               dbus_error_free (&error);
849               bus_wait_for_memory ();
850               goto retry_get_acquired_name;
851             }
852           else
853             {
854               _dbus_assert (dbus_error_is_set (&error));
855               _dbus_warn ("Did not get the expected single string argument to ServiceAcquired\n");
856               goto out;
857             }
858         }
859
860       _dbus_verbose ("Got acquired name: %s\n", acquired);
861
862       if (strcmp (acquired, name) != 0)
863         {
864           _dbus_warn ("Acquired name is %s but expected %s\n",
865                       acquired, name);
866           goto out;
867         }
868     }
869
870   if (!check_no_leftovers (context))
871     goto out;
872   
873   retval = TRUE;
874   
875  out:
876   dbus_error_free (&error);
877   
878   dbus_free (name);
879   dbus_free (acquired);
880   
881   if (message)
882     dbus_message_unref (message);
883   
884   return retval;
885 }
886
887 /* returns TRUE if the correct thing happens,
888  * but the correct thing may include OOM errors.
889  */
890 static dbus_bool_t
891 check_hello_connection (BusContext *context)
892 {
893   DBusConnection *connection;
894   DBusResultCode result;
895
896   result = DBUS_RESULT_SUCCESS;
897   connection = dbus_connection_open ("debug-pipe:name=test-server", &result);
898   if (connection == NULL)
899     {
900       _dbus_assert (result != DBUS_RESULT_SUCCESS);
901       return TRUE;
902     }
903
904   if (!bus_setup_debug_client (connection))
905     {
906       dbus_connection_disconnect (connection);
907       dbus_connection_unref (connection);
908       return TRUE;
909     }
910
911   if (!check_hello_message (context, connection))
912     return FALSE;
913
914   if (dbus_bus_get_base_service (connection) == NULL)
915     {
916       /* We didn't successfully register, so we can't
917        * do the usual kill_client_connection() checks
918        */
919       kill_client_connection_unchecked (connection);
920     }
921   else
922     {
923       kill_client_connection (context, connection);
924     }
925
926   return TRUE;
927 }
928
929 static void
930 check1_try_iterations (BusContext *context,
931                        const char *description,
932                        Check1Func  func)
933 {
934   int approx_mallocs;
935
936   /* Run once to see about how many mallocs are involved */
937   
938   _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
939   
940   if (! (*func) (context))
941     _dbus_assert_not_reached ("test failed");
942
943   approx_mallocs = _DBUS_INT_MAX - _dbus_get_fail_alloc_counter ();
944
945   _dbus_verbose ("=================\n%s: about %d mallocs total\n=================\n",
946                  description, approx_mallocs);
947   
948   approx_mallocs += 10; /* fudge factor */
949   
950   /* Now run failing each malloc */
951   
952   while (approx_mallocs >= 0)
953     {
954       _dbus_set_fail_alloc_counter (approx_mallocs);
955
956       _dbus_verbose ("\n===\n %s: (will fail malloc %d)\n===\n",
957                      description, approx_mallocs);
958
959       if (! (*func) (context))
960         _dbus_assert_not_reached ("test failed");
961
962       if (!check_no_leftovers (context))
963         _dbus_assert_not_reached ("Messages were left over, should be covered by test suite");
964       
965       approx_mallocs -= 1;
966     }
967
968   _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
969
970   _dbus_verbose ("=================\n%s: all iterations passed\n=================\n",
971                  description);
972 }
973
974 dbus_bool_t
975 bus_dispatch_test (const DBusString *test_data_dir)
976 {
977   BusContext *context;
978   DBusError error;
979   const char *activation_dirs[] = { NULL, NULL };
980   DBusConnection *foo;
981   DBusConnection *bar;
982   DBusConnection *baz;
983   DBusResultCode result;
984
985   dbus_error_init (&error);
986   context = bus_context_new ("debug-pipe:name=test-server",
987                              activation_dirs,
988                              &error);
989   if (context == NULL)
990     _dbus_assert_not_reached ("could not alloc context");
991   
992   foo = dbus_connection_open ("debug-pipe:name=test-server", &result);
993   if (foo == NULL)
994     _dbus_assert_not_reached ("could not alloc connection");
995
996   if (!bus_setup_debug_client (foo))
997     _dbus_assert_not_reached ("could not set up connection");
998
999   if (!check_hello_message (context, foo))
1000     _dbus_assert_not_reached ("hello message failed");
1001   
1002   bar = dbus_connection_open ("debug-pipe:name=test-server", &result);
1003   if (bar == NULL)
1004     _dbus_assert_not_reached ("could not alloc connection");
1005
1006   if (!bus_setup_debug_client (bar))
1007     _dbus_assert_not_reached ("could not set up connection");
1008
1009   if (!check_hello_message (context, bar))
1010     _dbus_assert_not_reached ("hello message failed");
1011   
1012   baz = dbus_connection_open ("debug-pipe:name=test-server", &result);
1013   if (baz == NULL)
1014     _dbus_assert_not_reached ("could not alloc connection");
1015
1016   if (!bus_setup_debug_client (baz))
1017     _dbus_assert_not_reached ("could not set up connection");
1018
1019   if (!check_hello_message (context, baz))
1020     _dbus_assert_not_reached ("hello message failed");
1021
1022   check1_try_iterations (context, "create_and_hello",
1023                          check_hello_connection);
1024   
1025   _dbus_verbose ("Disconnecting foo, bar, and baz\n");
1026
1027   kill_client_connection_unchecked (foo);
1028   kill_client_connection_unchecked (bar);
1029   kill_client_connection_unchecked (baz);
1030
1031   bus_context_unref (context);
1032   
1033   return TRUE;
1034 }
1035 #endif /* DBUS_BUILD_TESTS */