2003-04-05 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_ERROR_IS_CLEAR (error);
75   
76   _dbus_assert (dbus_message_get_sender (message) != NULL);
77
78   connections = bus_transaction_get_connections (transaction);
79   
80   dbus_error_init (&tmp_error);
81   d.message = message;
82   d.transaction = transaction;
83   d.error = &tmp_error;
84   
85   bus_connections_foreach (connections, send_one_message, &d);
86
87   if (dbus_error_is_set (&tmp_error))
88     {
89       dbus_move_error (&tmp_error, error);
90       return FALSE;
91     }
92   else
93     return TRUE;
94 }
95
96 static dbus_bool_t
97 send_service_nonexistent_error (BusTransaction *transaction,
98                                 DBusConnection *connection,
99                                 const char     *service_name,
100                                 DBusMessage    *in_reply_to,
101                                 DBusError      *error)
102 {
103   DBusMessage *error_reply;
104   DBusString error_message;
105   const char *error_str;
106
107   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
108   
109   /* Trying to send a message to a non-existant service,
110    * bounce back an error message.
111    */
112           
113   if (!_dbus_string_init (&error_message))
114     {
115       BUS_SET_OOM (error);
116       return FALSE;
117     }
118
119   if (!_dbus_string_append (&error_message, "Service \"") ||
120       !_dbus_string_append (&error_message, service_name) ||
121       !_dbus_string_append (&error_message, "\" does not exist"))
122     {
123       _dbus_string_free (&error_message);
124       BUS_SET_OOM (error);
125       return FALSE;
126     }
127               
128   error_str = _dbus_string_get_const_data (&error_message);
129   error_reply = dbus_message_new_error_reply (in_reply_to,
130                                               DBUS_ERROR_SERVICE_DOES_NOT_EXIST,
131                                               error_str);
132
133   _dbus_string_free (&error_message);
134               
135   if (error_reply == NULL)
136     {
137       BUS_SET_OOM (error);
138       return FALSE;
139     }
140               
141   if (!bus_transaction_send_message (transaction, connection, error_reply))
142     {
143       dbus_message_unref (error_reply);
144       BUS_SET_OOM (error);
145       return FALSE;
146     }
147               
148   dbus_message_unref (error_reply);
149
150   return TRUE;
151 }
152
153 static void
154 bus_dispatch (DBusConnection *connection,
155               DBusMessage    *message)
156 {
157   const char *sender, *service_name, *message_name;
158   DBusError error;
159   BusTransaction *transaction;
160   BusContext *context;
161   
162   transaction = NULL;
163   dbus_error_init (&error);
164   
165   context = bus_connection_get_context (connection);
166   _dbus_assert (context != NULL);
167   
168   /* If we can't even allocate an OOM error, we just go to sleep
169    * until we can.
170    */
171   while (!bus_connection_preallocate_oom_error (connection))
172     bus_wait_for_memory ();
173   
174   /* Ref connection in case we disconnect it at some point in here */
175   dbus_connection_ref (connection);
176
177   service_name = dbus_message_get_service (message);
178   message_name = dbus_message_get_name (message);
179
180   _dbus_assert (message_name != NULL); /* DBusMessageLoader is supposed to check this */
181
182   _dbus_verbose ("DISPATCH: %s to %s\n",
183                  message_name, service_name ? service_name : "peer");
184   
185   /* If service_name is NULL, this is a message to the bus daemon, not intended
186    * to actually go "on the bus"; e.g. a peer-to-peer ping. Handle these
187    * immediately, especially disconnection messages.
188    */
189   if (service_name == NULL)
190     {      
191       if (strcmp (message_name, DBUS_MESSAGE_LOCAL_DISCONNECT) == 0)
192         bus_connection_disconnected (connection);
193
194       /* DBusConnection also handles some of these automatically, we leave
195        * it to do so.
196        */
197       goto out;
198     }
199
200   _dbus_assert (service_name != NULL); /* this message is intended for bus routing */
201   
202   /* Create our transaction */
203   transaction = bus_transaction_new (context);
204   if (transaction == NULL)
205     {
206       BUS_SET_OOM (&error);
207       goto out;
208     }
209   
210   /* Assign a sender to the message */
211   if (bus_connection_is_active (connection))
212     {
213       sender = bus_connection_get_name (connection);
214       _dbus_assert (sender != NULL);
215
216       if (!dbus_message_set_sender (message, sender))
217         {
218           BUS_SET_OOM (&error);
219           goto out;
220         }
221
222       /* We need to refetch the service name here, because
223        * dbus_message_set_sender can cause the header to be
224        * reallocated, and thus the service_name pointer will become
225        * invalid.
226        */
227       service_name = dbus_message_get_service (message);
228     }
229
230   if (strcmp (service_name, DBUS_SERVICE_DBUS) == 0) /* to bus driver */
231     {
232       if (!bus_driver_handle_message (connection, transaction, message, &error))
233         goto out;
234     }
235   else if (!bus_connection_is_active (connection)) /* clients must talk to bus driver first */
236     {
237       _dbus_verbose ("Received message from non-registered client. Disconnecting.\n");
238       dbus_connection_disconnect (connection);
239     }
240   /* FIXME what if we un-special-case this service and just have a flag
241    * on services that all service owners will get messages to it, not just
242    * the primary owner.
243    */
244   else if (strcmp (service_name, DBUS_SERVICE_BROADCAST) == 0) /* spam! */
245     {
246       if (!bus_dispatch_broadcast_message (transaction, message, &error))
247         goto out;
248     }
249   else  /* route to named service */
250     {
251       DBusString service_string;
252       BusService *service;
253       BusRegistry *registry;
254
255       registry = bus_connection_get_registry (connection);
256       
257       _dbus_string_init_const (&service_string, service_name);
258       service = bus_registry_lookup (registry, &service_string);
259
260       if (service == NULL)
261         {
262           if (!send_service_nonexistent_error (transaction, connection,
263                                                service_name,
264                                                message, &error))
265             goto out;
266         }
267       else
268         {
269           _dbus_assert (bus_service_get_primary_owner (service) != NULL);
270       
271           /* Dispatch the message */
272           if (!bus_transaction_send_message (transaction,
273                                              bus_service_get_primary_owner (service),
274                                              message))
275             {
276               BUS_SET_OOM (&error);
277               goto out;
278             }
279         }
280     }
281   
282  out:
283   if (dbus_error_is_set (&error))
284     {
285       if (!dbus_connection_get_is_connected (connection))
286         {
287           /* If we disconnected it, we won't bother to send it any error
288            * messages.
289            */
290         }
291       else if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
292         {
293           bus_connection_send_oom_error (connection, message);
294
295           /* cancel transaction due to OOM */
296           if (transaction != NULL)
297             {
298               bus_transaction_cancel_and_free (transaction);
299               transaction = NULL;
300             }
301         }
302       else
303         {
304           /* Try to send the real error, if no mem to do that, send
305            * the OOM error
306            */
307           _dbus_assert (transaction != NULL);
308           
309           if (!bus_transaction_send_error_reply (transaction, connection,
310                                                  &error, message))
311             {
312               bus_connection_send_oom_error (connection, message);
313
314               /* cancel transaction due to OOM */
315               if (transaction != NULL)
316                 {
317                   bus_transaction_cancel_and_free (transaction);
318                   transaction = NULL;
319                 }
320             }
321         }
322       
323       dbus_error_free (&error);
324     }
325
326   if (transaction != NULL)
327     {
328       bus_transaction_execute_and_free (transaction);
329     }
330
331   dbus_connection_unref (connection);
332 }
333
334 static DBusHandlerResult
335 bus_dispatch_message_handler (DBusMessageHandler *handler,
336                               DBusConnection     *connection,
337                               DBusMessage        *message,
338                               void               *user_data)
339 {
340   bus_dispatch (connection, message);
341   
342   return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
343 }
344
345 static dbus_bool_t
346 message_handler_slot_ref (void)
347 {
348   if (message_handler_slot < 0)
349     {
350       message_handler_slot = dbus_connection_allocate_data_slot ();
351       
352       if (message_handler_slot < 0)
353         return FALSE;
354
355       _dbus_assert (message_handler_slot_refcount == 0);
356     }  
357
358   message_handler_slot_refcount += 1;
359
360   return TRUE;
361 }
362
363 static void
364 message_handler_slot_unref (void)
365 {
366   _dbus_assert (message_handler_slot_refcount > 0);
367
368   message_handler_slot_refcount -= 1;
369   
370   if (message_handler_slot_refcount == 0)
371     {
372       dbus_connection_free_data_slot (message_handler_slot);
373       message_handler_slot = -1;
374     }
375 }
376
377 static void
378 free_message_handler (void *data)
379 {
380   DBusMessageHandler *handler = data;
381   
382   _dbus_assert (message_handler_slot >= 0);
383   _dbus_assert (message_handler_slot_refcount > 0);
384   
385   dbus_message_handler_unref (handler);
386   message_handler_slot_unref ();
387 }
388
389 dbus_bool_t
390 bus_dispatch_add_connection (DBusConnection *connection)
391 {
392   DBusMessageHandler *handler;
393
394   if (!message_handler_slot_ref ())
395     return FALSE;
396   
397   handler = dbus_message_handler_new (bus_dispatch_message_handler, NULL, NULL);  
398   if (handler == NULL)
399     {
400       message_handler_slot_unref ();
401       return FALSE;
402     }    
403   
404   if (!dbus_connection_add_filter (connection, handler))
405     {
406       dbus_message_handler_unref (handler);
407       message_handler_slot_unref ();
408       
409       return FALSE;
410     }
411
412   _dbus_assert (message_handler_slot >= 0);
413   _dbus_assert (message_handler_slot_refcount > 0);
414   
415   if (!dbus_connection_set_data (connection,
416                                  message_handler_slot,
417                                  handler,
418                                  free_message_handler))
419     {
420       dbus_message_handler_unref (handler);
421       message_handler_slot_unref ();
422
423       return FALSE;
424     }
425
426   return TRUE;
427 }
428
429 void
430 bus_dispatch_remove_connection (DBusConnection *connection)
431 {
432   /* Here we tell the bus driver that we want to get off. */
433   bus_driver_remove_connection (connection);
434
435   dbus_connection_set_data (connection,
436                             message_handler_slot,
437                             NULL, NULL);
438 }
439
440 #ifdef DBUS_BUILD_TESTS
441
442 typedef dbus_bool_t (* Check1Func) (BusContext     *context);
443 typedef dbus_bool_t (* Check2Func) (BusContext     *context,
444                                     DBusConnection *connection);
445
446 static dbus_bool_t check_no_leftovers (BusContext *context);
447
448 typedef struct
449 {
450   const char *expected_service_name;
451   dbus_bool_t failed;
452 } CheckServiceDeletedData;
453
454 static dbus_bool_t
455 check_service_deleted_foreach (DBusConnection *connection,
456                                void           *data)
457 {
458   CheckServiceDeletedData *d = data;
459   DBusMessage *message;
460   DBusError error;
461   char *service_name;
462
463   dbus_error_init (&error);
464   d->failed = TRUE;
465   service_name = NULL;
466   
467   message = dbus_connection_pop_message (connection);
468   if (message == NULL)
469     {
470       _dbus_warn ("Did not receive a message on %p, expecting %s\n",
471                   connection, DBUS_MESSAGE_SERVICE_DELETED);
472       goto out;
473     }
474   else if (!dbus_message_name_is (message, DBUS_MESSAGE_SERVICE_DELETED))
475     {
476       _dbus_warn ("Received message %s on %p, expecting %s\n",
477                   dbus_message_get_name (message),
478                   connection, DBUS_MESSAGE_SERVICE_DELETED);
479       goto out;
480     }
481   else
482     {
483       if (!dbus_message_get_args (message, &error,
484                                   DBUS_TYPE_STRING, &service_name,
485                                   DBUS_TYPE_INVALID))
486         {
487           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
488             {
489               _dbus_verbose ("no memory to get service name arg\n");
490             }
491           else
492             {
493               _dbus_assert (dbus_error_is_set (&error));
494               _dbus_warn ("Did not get the expected single string argument\n");
495               goto out;
496             }
497         }
498       else if (strcmp (service_name, d->expected_service_name) != 0)
499         {
500           _dbus_warn ("expected deletion of service %s, got deletion of %s\n",
501                       d->expected_service_name,
502                       service_name);
503           goto out;
504         }
505     }
506
507   d->failed = FALSE;
508   
509  out:
510   dbus_free (service_name);
511   dbus_error_free (&error);
512   
513   if (message)
514     dbus_message_unref (message);
515
516   return !d->failed;
517 }
518
519 static void
520 kill_client_connection (BusContext     *context,
521                         DBusConnection *connection)
522 {
523   char *base_service;
524   const char *s;
525   CheckServiceDeletedData csdd;
526
527   _dbus_verbose ("killing connection %p\n", connection);
528   
529   s = dbus_bus_get_base_service (connection);
530   _dbus_assert (s != NULL);
531
532   while ((base_service = _dbus_strdup (s)) == NULL)
533     bus_wait_for_memory ();
534
535   dbus_connection_ref (connection);
536   
537   /* kick in the disconnect handler that unrefs the connection */
538   dbus_connection_disconnect (connection);
539
540   bus_test_run_everything (context);
541   
542   _dbus_assert (bus_test_client_listed (connection));
543   
544   /* Run disconnect handler in test.c */
545   if (bus_connection_dispatch_one_message (connection))
546     _dbus_assert_not_reached ("something received on connection being killed other than the disconnect");
547   
548   _dbus_assert (!dbus_connection_get_is_connected (connection));
549   dbus_connection_unref (connection);
550   connection = NULL;
551   _dbus_assert (!bus_test_client_listed (connection));
552   
553   csdd.expected_service_name = base_service;
554   csdd.failed = FALSE;
555
556   bus_test_clients_foreach (check_service_deleted_foreach,
557                             &csdd);
558
559   dbus_free (base_service);
560   
561   if (csdd.failed)
562     _dbus_assert_not_reached ("didn't get the expected ServiceDeleted messages");
563   
564   if (!check_no_leftovers (context))
565     _dbus_assert_not_reached ("stuff left in message queues after disconnecting a client");
566 }
567
568 static void
569 kill_client_connection_unchecked (DBusConnection *connection)
570 {
571   /* This kills the connection without expecting it to affect
572    * the rest of the bus.
573    */  
574   _dbus_verbose ("Unchecked kill of connection %p\n", connection);
575
576   dbus_connection_ref (connection);
577   dbus_connection_disconnect (connection);
578   /* dispatching disconnect handler will unref once */
579   if (bus_connection_dispatch_one_message (connection))
580     _dbus_assert_not_reached ("message other than disconnect dispatched after failure to register");
581   dbus_connection_unref (connection);
582   _dbus_assert (!bus_test_client_listed (connection));
583 }
584
585 typedef struct
586 {
587   dbus_bool_t failed;
588 } CheckNoMessagesData;
589
590 static dbus_bool_t
591 check_no_messages_foreach (DBusConnection *connection,
592                            void           *data)
593 {
594   CheckNoMessagesData *d = data;
595   DBusMessage *message;
596
597   message = dbus_connection_pop_message (connection);
598   if (message != NULL)
599     {
600       _dbus_warn ("Received message %s on %p, expecting no messages\n",
601                   dbus_message_get_name (message), connection);
602       d->failed = TRUE;
603     }
604
605   if (message)
606     dbus_message_unref (message);
607   return !d->failed;
608 }
609
610 typedef struct
611 {
612   DBusConnection *skip_connection;
613   const char *expected_service_name;
614   dbus_bool_t failed;
615 } CheckServiceCreatedData;
616
617 static dbus_bool_t
618 check_service_created_foreach (DBusConnection *connection,
619                                void           *data)
620 {
621   CheckServiceCreatedData *d = data;
622   DBusMessage *message;
623   DBusError error;
624   char *service_name;
625
626   if (connection == d->skip_connection)
627     return TRUE;
628
629   dbus_error_init (&error);
630   d->failed = TRUE;
631   service_name = NULL;
632   
633   message = dbus_connection_pop_message (connection);
634   if (message == NULL)
635     {
636       _dbus_warn ("Did not receive a message on %p, expecting %s\n",
637                   connection, DBUS_MESSAGE_SERVICE_CREATED);
638       goto out;
639     }
640   else if (!dbus_message_name_is (message, DBUS_MESSAGE_SERVICE_CREATED))
641     {
642       _dbus_warn ("Received message %s on %p, expecting %s\n",
643                   dbus_message_get_name (message),
644                   connection, DBUS_MESSAGE_SERVICE_CREATED);
645       goto out;
646     }
647   else
648     {
649       if (!dbus_message_get_args (message, &error,
650                                   DBUS_TYPE_STRING, &service_name,
651                                   DBUS_TYPE_INVALID))
652         {
653           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
654             {
655               _dbus_verbose ("no memory to get service name arg\n");
656             }
657           else
658             {
659               _dbus_assert (dbus_error_is_set (&error));
660               _dbus_warn ("Did not get the expected single string argument\n");
661               goto out;
662             }
663         }
664       else if (strcmp (service_name, d->expected_service_name) != 0)
665         {
666           _dbus_warn ("expected creation of service %s, got creation of %s\n",
667                       d->expected_service_name,
668                       service_name);
669           goto out;
670         }
671     }
672
673   d->failed = FALSE;
674   
675  out:
676   dbus_free (service_name);
677   dbus_error_free (&error);
678   
679   if (message)
680     dbus_message_unref (message);
681
682   return !d->failed;
683 }
684
685 static dbus_bool_t
686 check_no_leftovers (BusContext *context)
687 {
688   CheckNoMessagesData nmd;
689
690   nmd.failed = FALSE;
691   bus_test_clients_foreach (check_no_messages_foreach,
692                             &nmd);
693   
694   if (nmd.failed)
695     return FALSE;
696   else
697     return TRUE;
698 }
699
700 /* returns TRUE if the correct thing happens,
701  * but the correct thing may include OOM errors.
702  */
703 static dbus_bool_t
704 check_hello_message (BusContext     *context,
705                      DBusConnection *connection)
706 {
707   DBusMessage *message;
708   dbus_int32_t serial;
709   dbus_bool_t retval;
710   DBusError error;
711   char *name;
712   char *acquired;
713   
714   dbus_error_init (&error);
715   name = NULL;
716   acquired = NULL;
717   
718   message = dbus_message_new (DBUS_SERVICE_DBUS,
719                               DBUS_MESSAGE_HELLO);
720
721   if (message == NULL)
722     return TRUE;
723
724   if (!dbus_connection_send (connection, message, &serial))
725     {
726       dbus_message_unref (message);
727       return TRUE;
728     }
729
730   dbus_message_unref (message);
731   message = NULL;
732
733   bus_test_run_everything (context);
734
735   if (!dbus_connection_get_is_connected (connection))
736     {
737       _dbus_verbose ("connection was disconnected\n");
738       return TRUE;
739     }
740   
741   retval = FALSE;
742   
743   message = dbus_connection_pop_message (connection);
744   if (message == NULL)
745     {
746       _dbus_warn ("Did not receive a reply to %s %d on %p\n",
747                   DBUS_MESSAGE_HELLO, serial, connection);
748       goto out;
749     }
750
751   _dbus_verbose ("Received %s on %p\n",
752                  dbus_message_get_name (message), connection);
753
754   if (!dbus_message_sender_is (message, DBUS_SERVICE_DBUS))
755     {
756       _dbus_warn ("Message has wrong sender %s\n",
757                   dbus_message_get_sender (message) ?
758                   dbus_message_get_sender (message) : "(none)");
759       goto out;
760     }
761   
762   if (dbus_message_get_is_error (message))
763     {
764       if (dbus_message_name_is (message,
765                                 DBUS_ERROR_NO_MEMORY))
766         {
767           ; /* good, this is a valid response */
768         }
769       else
770         {
771           _dbus_warn ("Did not expect error %s\n",
772                       dbus_message_get_name (message));
773           goto out;
774         }
775     }
776   else
777     {
778       CheckServiceCreatedData scd;
779       
780       if (dbus_message_name_is (message,
781                                 DBUS_MESSAGE_HELLO))
782         {
783           ; /* good, expected */
784         }
785       else
786         {
787           _dbus_warn ("Did not expect reply %s\n",
788                       dbus_message_get_name (message));
789           goto out;
790         }
791
792     retry_get_hello_name:
793       if (!dbus_message_get_args (message, &error,
794                                   DBUS_TYPE_STRING, &name,
795                                   DBUS_TYPE_INVALID))
796         {
797           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
798             {
799               _dbus_verbose ("no memory to get service name arg from hello\n");
800               dbus_error_free (&error);
801               bus_wait_for_memory ();
802               goto retry_get_hello_name;
803             }
804           else
805             {
806               _dbus_assert (dbus_error_is_set (&error));
807               _dbus_warn ("Did not get the expected single string argument to hello\n");
808               goto out;
809             }
810         }
811
812       _dbus_verbose ("Got hello name: %s\n", name);
813
814       while (!dbus_bus_set_base_service (connection, name))
815         bus_wait_for_memory ();
816       
817       scd.skip_connection = NULL;
818       scd.failed = FALSE;
819       scd.expected_service_name = name;
820       bus_test_clients_foreach (check_service_created_foreach,
821                                 &scd);
822       
823       if (scd.failed)
824         goto out;
825       
826       /* Client should also have gotten ServiceAcquired */
827       dbus_message_unref (message);
828       message = dbus_connection_pop_message (connection);
829       if (message == NULL)
830         {
831           _dbus_warn ("Expecting %s, got nothing\n",
832                       DBUS_MESSAGE_SERVICE_ACQUIRED);
833           goto out;
834         }
835       
836     retry_get_acquired_name:
837       if (!dbus_message_get_args (message, &error,
838                                   DBUS_TYPE_STRING, &acquired,
839                                   DBUS_TYPE_INVALID))
840         {
841           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
842             {
843               _dbus_verbose ("no memory to get service name arg from acquired\n");
844               dbus_error_free (&error);
845               bus_wait_for_memory ();
846               goto retry_get_acquired_name;
847             }
848           else
849             {
850               _dbus_assert (dbus_error_is_set (&error));
851               _dbus_warn ("Did not get the expected single string argument to ServiceAcquired\n");
852               goto out;
853             }
854         }
855
856       _dbus_verbose ("Got acquired name: %s\n", acquired);
857
858       if (strcmp (acquired, name) != 0)
859         {
860           _dbus_warn ("Acquired name is %s but expected %s\n",
861                       acquired, name);
862           goto out;
863         }
864     }
865
866   if (!check_no_leftovers (context))
867     goto out;
868   
869   retval = TRUE;
870   
871  out:
872   dbus_error_free (&error);
873   
874   dbus_free (name);
875   dbus_free (acquired);
876   
877   if (message)
878     dbus_message_unref (message);
879   
880   return retval;
881 }
882
883 /* returns TRUE if the correct thing happens,
884  * but the correct thing may include OOM errors.
885  */
886 static dbus_bool_t
887 check_hello_connection (BusContext *context)
888 {
889   DBusConnection *connection;
890   DBusError error;
891
892   dbus_error_init (&error);
893
894   connection = dbus_connection_open ("debug-pipe:name=test-server", &error);
895   if (connection == NULL)
896     {
897       _DBUS_ASSERT_ERROR_IS_SET (&error);
898       dbus_error_free (&error);
899       return TRUE;
900     }
901
902   if (!bus_setup_debug_client (connection))
903     {
904       dbus_connection_disconnect (connection);
905       dbus_connection_unref (connection);
906       return TRUE;
907     }
908
909   if (!check_hello_message (context, connection))
910     return FALSE;
911
912   if (dbus_bus_get_base_service (connection) == NULL)
913     {
914       /* We didn't successfully register, so we can't
915        * do the usual kill_client_connection() checks
916        */
917       kill_client_connection_unchecked (connection);
918     }
919   else
920     {
921       kill_client_connection (context, connection);
922     }
923
924   return TRUE;
925 }
926
927 #define NONEXISTENT_SERVICE_NAME "test.this.service.does.not.exist.ewuoiurjdfxcvn"
928
929 /* returns TRUE if the correct thing happens,
930  * but the correct thing may include OOM errors.
931  */
932 static dbus_bool_t
933 check_nonexistent_service_activation (BusContext     *context,
934                                       DBusConnection *connection)
935 {
936   DBusMessage *message;
937   dbus_int32_t serial;
938   dbus_bool_t retval;
939   DBusError error;
940   
941   dbus_error_init (&error);
942   
943   message = dbus_message_new (DBUS_SERVICE_DBUS,
944                               DBUS_MESSAGE_ACTIVATE_SERVICE);
945
946   if (message == NULL)
947     return TRUE;
948
949   if (!dbus_message_append_args (message,
950                                  DBUS_TYPE_STRING, NONEXISTENT_SERVICE_NAME,
951                                  DBUS_TYPE_UINT32, 0,
952                                  DBUS_TYPE_INVALID))
953     {
954       dbus_message_unref (message);
955       return TRUE;
956     }
957   
958   if (!dbus_connection_send (connection, message, &serial))
959     {
960       dbus_message_unref (message);
961       return TRUE;
962     }
963
964   dbus_message_unref (message);
965   message = NULL;
966
967   bus_test_run_everything (context);
968
969   if (!dbus_connection_get_is_connected (connection))
970     {
971       _dbus_verbose ("connection was disconnected\n");
972       return TRUE;
973     }
974   
975   retval = FALSE;
976   
977   message = dbus_connection_pop_message (connection);
978   if (message == NULL)
979     {
980       _dbus_warn ("Did not receive a reply to %s %d on %p\n",
981                   DBUS_MESSAGE_ACTIVATE_SERVICE, serial, connection);
982       goto out;
983     }
984
985   _dbus_verbose ("Received %s on %p\n",
986                  dbus_message_get_name (message), connection);
987
988   if (dbus_message_get_is_error (message))
989     {
990       if (!dbus_message_sender_is (message, DBUS_SERVICE_DBUS))
991         {
992           _dbus_warn ("Message has wrong sender %s\n",
993                       dbus_message_get_sender (message) ?
994                       dbus_message_get_sender (message) : "(none)");
995           goto out;
996         }
997       
998       if (dbus_message_name_is (message,
999                                 DBUS_ERROR_NO_MEMORY))
1000         {
1001           ; /* good, this is a valid response */
1002         }
1003       else if (dbus_message_name_is (message,
1004                                      DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND))
1005         {
1006           ; /* good, this is expected also */
1007         }
1008       else
1009         {
1010           _dbus_warn ("Did not expect error %s\n",
1011                       dbus_message_get_name (message));
1012           goto out;
1013         }
1014     }
1015   else
1016     {
1017       _dbus_warn ("Did not expect to successfully activate %s\n",
1018                   NONEXISTENT_SERVICE_NAME);
1019       goto out;
1020     }
1021
1022   retval = TRUE;
1023   
1024  out:
1025   if (message)
1026     dbus_message_unref (message);
1027   
1028   return retval;
1029 }
1030
1031 #define EXISTENT_SERVICE_NAME "org.freedesktop.DBus.TestSuiteEchoService"
1032
1033 /* returns TRUE if the correct thing happens,
1034  * but the correct thing may include OOM errors.
1035  */
1036 static dbus_bool_t
1037 check_existent_service_activation (BusContext     *context,
1038                                    DBusConnection *connection)
1039 {
1040   DBusMessage *message;
1041   dbus_int32_t serial;
1042   dbus_bool_t retval;
1043   DBusError error;
1044   
1045   dbus_error_init (&error);
1046   
1047   message = dbus_message_new (DBUS_SERVICE_DBUS,
1048                               DBUS_MESSAGE_ACTIVATE_SERVICE);
1049
1050   if (message == NULL)
1051     return TRUE;
1052
1053   if (!dbus_message_append_args (message,
1054                                  DBUS_TYPE_STRING, EXISTENT_SERVICE_NAME,
1055                                  DBUS_TYPE_UINT32, 0,
1056                                  DBUS_TYPE_INVALID))
1057     {
1058       dbus_message_unref (message);
1059       return TRUE;
1060     }
1061   
1062   if (!dbus_connection_send (connection, message, &serial))
1063     {
1064       dbus_message_unref (message);
1065       return TRUE;
1066     }
1067
1068   dbus_message_unref (message);
1069   message = NULL;
1070
1071   bus_test_run_everything (context);
1072
1073   if (dbus_connection_get_dispatch_status (connection) ==
1074       DBUS_DISPATCH_COMPLETE)
1075     /* now wait for the message bus to hear back from the activated service */
1076     bus_test_run_bus_loop (context);
1077   
1078   /* and process everything again */
1079   bus_test_run_everything (context);
1080
1081   if (!dbus_connection_get_is_connected (connection))
1082     {
1083       _dbus_verbose ("connection was disconnected\n");
1084       return TRUE;
1085     }
1086   
1087   retval = FALSE;
1088   
1089   message = dbus_connection_pop_message (connection);
1090   if (message == NULL)
1091     {
1092       _dbus_warn ("Did not receive a reply to %s %d on %p\n",
1093                   DBUS_MESSAGE_ACTIVATE_SERVICE, serial, connection);
1094       goto out;
1095     }
1096
1097   _dbus_verbose ("Received %s on %p\n",
1098                  dbus_message_get_name (message), connection);
1099
1100   if (dbus_message_get_is_error (message))
1101     {
1102       if (!dbus_message_sender_is (message, DBUS_SERVICE_DBUS))
1103         {
1104           _dbus_warn ("Message has wrong sender %s\n",
1105                       dbus_message_get_sender (message) ?
1106                       dbus_message_get_sender (message) : "(none)");
1107           goto out;
1108         }
1109       
1110       if (dbus_message_name_is (message,
1111                                 DBUS_ERROR_NO_MEMORY))
1112         {
1113           ; /* good, this is a valid response */
1114         }
1115       else if (dbus_message_name_is (message,
1116                                      DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND))
1117         {
1118           ; /* good, this is expected also */
1119         }
1120       else
1121         {
1122           _dbus_warn ("Did not expect error %s\n",
1123                       dbus_message_get_name (message));
1124           goto out;
1125         }
1126     }
1127   else
1128     {
1129       _dbus_warn ("Did not expect to successfully activate %s\n",
1130                   EXISTENT_SERVICE_NAME);
1131       goto out;
1132     }
1133
1134   retval = TRUE;
1135   
1136  out:
1137   if (message)
1138     dbus_message_unref (message);
1139   
1140   return retval;
1141 }
1142
1143 typedef struct
1144 {
1145   Check1Func func;
1146   BusContext *context;
1147 } Check1Data;
1148
1149 static dbus_bool_t
1150 check_oom_check1_func (void *data)
1151 {
1152   Check1Data *d = data;
1153
1154   if (! (* d->func) (d->context))
1155     return FALSE;
1156   
1157   if (!check_no_leftovers (d->context))
1158     {
1159       _dbus_warn ("Messages were left over, should be covered by test suite");
1160       return FALSE;
1161     }
1162
1163   return TRUE;
1164 }
1165
1166 static void
1167 check1_try_iterations (BusContext *context,
1168                        const char *description,
1169                        Check1Func  func)
1170 {
1171   Check1Data d;
1172
1173   d.func = func;
1174   d.context = context;
1175
1176   if (!_dbus_test_oom_handling (description, check_oom_check1_func,
1177                                 &d))
1178     _dbus_assert_not_reached ("test failed");
1179 }
1180
1181 typedef struct
1182 {
1183   Check2Func func;
1184   BusContext *context;
1185   DBusConnection *connection;
1186 } Check2Data;
1187
1188 static dbus_bool_t
1189 check_oom_check2_func (void *data)
1190 {
1191   Check2Data *d = data;
1192
1193   if (! (* d->func) (d->context, d->connection))
1194     return FALSE;
1195   
1196   if (!check_no_leftovers (d->context))
1197     {
1198       _dbus_warn ("Messages were left over, should be covered by test suite");
1199       return FALSE;
1200     }
1201
1202   return TRUE;
1203 }
1204
1205 static void
1206 check2_try_iterations (BusContext     *context,
1207                        DBusConnection *connection,
1208                        const char     *description,
1209                        Check2Func      func)
1210 {
1211   Check2Data d;
1212
1213   d.func = func;
1214   d.context = context;
1215   d.connection = connection;
1216   
1217   if (!_dbus_test_oom_handling (description, check_oom_check2_func,
1218                                 &d))
1219     _dbus_assert_not_reached ("test failed");
1220 }
1221
1222 dbus_bool_t
1223 bus_dispatch_test (const DBusString *test_data_dir)
1224 {
1225   BusContext *context;
1226   DBusConnection *foo;
1227   DBusConnection *bar;
1228   DBusConnection *baz;
1229   DBusError error;
1230   
1231   context = bus_context_new_test (test_data_dir,
1232                                   "valid-config-files/debug-allow-all.conf");
1233   if (context == NULL)
1234     return FALSE;
1235
1236   dbus_error_init (&error);
1237   
1238   foo = dbus_connection_open ("debug-pipe:name=test-server", &error);
1239   if (foo == NULL)
1240     _dbus_assert_not_reached ("could not alloc connection");
1241
1242   if (!bus_setup_debug_client (foo))
1243     _dbus_assert_not_reached ("could not set up connection");
1244
1245   if (!check_hello_message (context, foo))
1246     _dbus_assert_not_reached ("hello message failed");
1247   
1248   bar = dbus_connection_open ("debug-pipe:name=test-server", &error);
1249   if (bar == NULL)
1250     _dbus_assert_not_reached ("could not alloc connection");
1251
1252   if (!bus_setup_debug_client (bar))
1253     _dbus_assert_not_reached ("could not set up connection");
1254
1255   if (!check_hello_message (context, bar))
1256     _dbus_assert_not_reached ("hello message failed");
1257   
1258   baz = dbus_connection_open ("debug-pipe:name=test-server", &error);
1259   if (baz == NULL)
1260     _dbus_assert_not_reached ("could not alloc connection");
1261
1262   if (!bus_setup_debug_client (baz))
1263     _dbus_assert_not_reached ("could not set up connection");
1264
1265   if (!check_hello_message (context, baz))
1266     _dbus_assert_not_reached ("hello message failed");
1267
1268 #if 0
1269   check2_try_iterations (context, foo, "existent_service_activation",
1270                          check_existent_service_activation);
1271 #endif
1272   
1273   check2_try_iterations (context, foo, "nonexistent_service_activation",
1274                          check_nonexistent_service_activation);
1275
1276   check1_try_iterations (context, "create_and_hello",
1277                          check_hello_connection);
1278   
1279   _dbus_verbose ("Disconnecting foo, bar, and baz\n");
1280
1281   kill_client_connection_unchecked (foo);
1282   kill_client_connection_unchecked (bar);
1283   kill_client_connection_unchecked (baz);
1284
1285   bus_context_unref (context);
1286   
1287   return TRUE;
1288 }
1289 #endif /* DBUS_BUILD_TESTS */