2003-03-17 Havoc Pennington <hp@pobox.com>
[platform/upstream/dbus.git] / bus / connection.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* connection.c  Client connections
3  *
4  * Copyright (C) 2003  Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 1.2
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23 #include "connection.h"
24 #include "dispatch.h"
25 #include "loop.h"
26 #include "services.h"
27 #include "utils.h"
28 #include <dbus/dbus-list.h>
29
30 static void bus_connection_remove_transactions (DBusConnection *connection);
31
32 struct BusConnections
33 {
34   int refcount;
35   DBusList *list; /**< List of all the connections */
36   BusContext *context;
37 };
38
39 static int connection_data_slot = -1;
40 static int connection_data_slot_refcount = 0;
41
42 typedef struct
43 {
44   BusConnections *connections;
45   DBusConnection *connection;
46   DBusList *services_owned;
47   char *name;
48   DBusList *transaction_messages; /**< Stuff we need to send as part of a transaction */
49   DBusMessage *oom_message;
50   DBusPreallocatedSend *oom_preallocated;
51 } BusConnectionData;
52
53 #define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot))
54
55 static dbus_bool_t
56 connection_data_slot_ref (void)
57 {
58   if (connection_data_slot < 0)
59     {
60       connection_data_slot = dbus_connection_allocate_data_slot ();
61       
62       if (connection_data_slot < 0)
63         return FALSE;
64
65       _dbus_assert (connection_data_slot_refcount == 0);
66     }  
67
68   connection_data_slot_refcount += 1;
69
70   return TRUE;
71
72 }
73
74 static void
75 connection_data_slot_unref (void)
76 {
77   _dbus_assert (connection_data_slot_refcount > 0);
78
79   connection_data_slot_refcount -= 1;
80   
81   if (connection_data_slot_refcount == 0)
82     {
83       dbus_connection_free_data_slot (connection_data_slot);
84       connection_data_slot = -1;
85     }
86 }
87
88 void
89 bus_connection_disconnected (DBusConnection *connection)
90 {
91   BusConnectionData *d;
92   BusService *service;
93
94   d = BUS_CONNECTION_DATA (connection);
95   _dbus_assert (d != NULL);
96
97   _dbus_verbose ("%s disconnected, dropping all service ownership and releasing\n",
98                  d->name ? d->name : "(inactive)");
99   
100   /* Drop any service ownership. FIXME Unfortunately, this requires
101    * memory allocation and there doesn't seem to be a good way to
102    * handle it other than sleeping; we can't "fail" the operation of
103    * disconnecting a client, and preallocating a broadcast "service is
104    * now gone" message for every client-service pair seems kind of
105    * involved. Probably we need to do that though, and also
106    * extend BusTransaction to be able to revert generic
107    * stuff, not just sending a message (so we can e.g. revert
108    * removal of service owners).
109    */
110   while ((service = _dbus_list_get_last (&d->services_owned)))
111     {
112       BusTransaction *transaction;
113       DBusError error;
114
115     retry:
116       
117       dbus_error_init (&error);
118         
119       transaction = NULL;
120       while (transaction == NULL)
121         {
122           transaction = bus_transaction_new (d->connections->context);
123           bus_wait_for_memory ();
124         }
125         
126       if (!bus_service_remove_owner (service, connection,
127                                      transaction, &error))
128         {
129           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
130             {
131               dbus_error_free (&error);
132               bus_transaction_cancel_and_free (transaction);
133               bus_wait_for_memory ();
134               goto retry;
135             }
136           else
137             _dbus_assert_not_reached ("Removing service owner failed for non-memory-related reason");
138         }
139         
140       bus_transaction_execute_and_free (transaction);
141     }
142
143   bus_dispatch_remove_connection (connection);
144   
145   /* no more watching */
146   if (!dbus_connection_set_watch_functions (connection,
147                                             NULL, NULL, NULL,
148                                             connection,
149                                             NULL))
150     _dbus_assert_not_reached ("setting watch functions to NULL failed");
151
152   if (!dbus_connection_set_timeout_functions (connection,
153                                               NULL, NULL, NULL,
154                                               connection,
155                                               NULL))
156     _dbus_assert_not_reached ("setting timeout functions to NULL failed");
157   
158   bus_connection_remove_transactions (connection);
159
160   _dbus_list_remove (&d->connections->list, connection);
161
162   /* frees "d" as side effect */
163   dbus_connection_set_data (connection,
164                             connection_data_slot,
165                             NULL, NULL);
166
167   dbus_connection_unref (connection);
168 }
169
170 static dbus_bool_t
171 connection_watch_callback (DBusWatch     *watch,
172                            unsigned int   condition,
173                            void          *data)
174 {
175   DBusConnection *connection = data;
176   dbus_bool_t retval;
177
178   dbus_connection_ref (connection);
179   
180   retval = dbus_connection_handle_watch (connection, watch, condition);
181
182   bus_connection_dispatch_all_messages (connection);
183   
184   dbus_connection_unref (connection);
185
186   return retval;
187 }
188
189 static dbus_bool_t
190 add_connection_watch (DBusWatch      *watch,
191                       DBusConnection *connection)
192 {
193   return bus_loop_add_watch (watch, connection_watch_callback, connection,
194                              NULL);
195 }
196
197 static void
198 remove_connection_watch (DBusWatch      *watch,
199                          DBusConnection *connection)
200 {
201   bus_loop_remove_watch (watch, connection_watch_callback, connection);
202 }
203
204 static void
205 connection_timeout_callback (DBusTimeout   *timeout,
206                              void          *data)
207 {
208   DBusConnection *connection = data;
209
210   dbus_connection_ref (connection);
211
212   /* can return FALSE on OOM but we just let it fire again later */
213   dbus_timeout_handle (timeout);
214
215   bus_connection_dispatch_all_messages (connection);
216   
217   dbus_connection_unref (connection);
218 }
219
220 static dbus_bool_t
221 add_connection_timeout (DBusTimeout    *timeout,
222                         DBusConnection *connection)
223 {
224   return bus_loop_add_timeout (timeout, connection_timeout_callback, connection, NULL);
225 }
226
227 static void
228 remove_connection_timeout (DBusTimeout    *timeout,
229                            DBusConnection *connection)
230 {
231   bus_loop_remove_timeout (timeout, connection_timeout_callback, connection);
232 }
233
234 static void
235 free_connection_data (void *data)
236 {
237   BusConnectionData *d = data;
238
239   /* services_owned should be NULL since we should be disconnected */
240   _dbus_assert (d->services_owned == NULL);
241   /* similarly */
242   _dbus_assert (d->transaction_messages == NULL);
243
244   if (d->oom_preallocated)
245     dbus_connection_free_preallocated_send (d->connection, d->oom_preallocated);
246
247   if (d->oom_message)
248     dbus_message_unref (d->oom_message);
249   
250   dbus_free (d->name);
251   
252   dbus_free (d);
253 }
254
255 BusConnections*
256 bus_connections_new (BusContext *context)
257 {
258   BusConnections *connections;
259
260   if (!connection_data_slot_ref ())
261     return NULL;
262
263   connections = dbus_new0 (BusConnections, 1);
264   if (connections == NULL)
265     {
266       connection_data_slot_unref ();
267       return NULL;
268     }
269   
270   connections->refcount = 1;
271   connections->context = context;
272   
273   return connections;
274 }
275
276 void
277 bus_connections_ref (BusConnections *connections)
278 {
279   _dbus_assert (connections->refcount > 0);
280   connections->refcount += 1;
281 }
282
283 void
284 bus_connections_unref (BusConnections *connections)
285 {
286   _dbus_assert (connections->refcount > 0);
287   connections->refcount -= 1;
288   if (connections->refcount == 0)
289     {
290       while (connections->list != NULL)
291         {
292           DBusConnection *connection;
293
294           connection = connections->list->data;
295
296           dbus_connection_ref (connection);
297           dbus_connection_disconnect (connection);
298           bus_connection_disconnected (connection);
299           dbus_connection_unref (connection);
300         }
301       
302       _dbus_list_clear (&connections->list);
303       
304       dbus_free (connections);
305
306       connection_data_slot_unref ();
307     }
308 }
309
310 dbus_bool_t
311 bus_connections_setup_connection (BusConnections *connections,
312                                   DBusConnection *connection)
313 {
314   BusConnectionData *d;
315   dbus_bool_t retval;
316   
317   d = dbus_new0 (BusConnectionData, 1);
318   
319   if (d == NULL)
320     return FALSE;
321
322   d->connections = connections;
323   d->connection = connection;
324
325   _dbus_assert (connection_data_slot >= 0);
326   
327   if (!dbus_connection_set_data (connection,
328                                  connection_data_slot,
329                                  d, free_connection_data))
330     {
331       dbus_free (d);
332       return FALSE;
333     }
334
335   retval = FALSE;
336   
337   if (!dbus_connection_set_watch_functions (connection,
338                                             (DBusAddWatchFunction) add_connection_watch,
339                                             (DBusRemoveWatchFunction) remove_connection_watch,
340                                             NULL,
341                                             connection,
342                                             NULL))
343     goto out;
344   
345   if (!dbus_connection_set_timeout_functions (connection,
346                                               (DBusAddTimeoutFunction) add_connection_timeout,
347                                               (DBusRemoveTimeoutFunction) remove_connection_timeout,
348                                               NULL,
349                                               connection, NULL))
350     goto out;
351
352   
353   /* Setup the connection with the dispatcher */
354   if (!bus_dispatch_add_connection (connection))
355     goto out;
356   
357   if (!_dbus_list_append (&connections->list, connection))
358     {
359       bus_dispatch_remove_connection (connection);
360       goto out;
361     }
362   
363   dbus_connection_ref (connection);
364   retval = TRUE;
365
366  out:
367   if (!retval)
368     {
369       if (!dbus_connection_set_data (connection,
370                                      connection_data_slot,
371                                      NULL, NULL))
372         _dbus_assert_not_reached ("failed to set connection data to null");
373         
374       if (!dbus_connection_set_watch_functions (connection,
375                                                 NULL, NULL, NULL,
376                                                 connection,
377                                                 NULL))
378         _dbus_assert_not_reached ("setting watch functions to NULL failed");
379       
380       if (!dbus_connection_set_timeout_functions (connection,
381                                                   NULL, NULL, NULL,
382                                                   connection,
383                                                   NULL))
384         _dbus_assert_not_reached ("setting timeout functions to NULL failed");
385     }
386   
387   return retval;
388 }
389
390
391 /**
392  * Calls function on each connection; if the function returns
393  * #FALSE, stops iterating.
394  *
395  * @param connections the connections object
396  * @param function the function
397  * @param data data to pass to it as a second arg
398  */
399 void
400 bus_connections_foreach (BusConnections               *connections,
401                          BusConnectionForeachFunction  function,
402                         void                          *data)
403 {
404   DBusList *link;
405   
406   link = _dbus_list_get_first_link (&connections->list);
407   while (link != NULL)
408     {
409       DBusConnection *connection = link->data;
410       DBusList *next = _dbus_list_get_next_link (&connections->list, link);
411
412       if (!(* function) (connection, data))
413         break;
414       
415       link = next;
416     }
417 }
418
419 BusContext*
420 bus_connections_get_context (BusConnections *connections)
421 {
422   return connections->context;
423 }
424
425 BusContext*
426 bus_connection_get_context (DBusConnection *connection)
427 {
428   BusConnectionData *d;
429
430   d = BUS_CONNECTION_DATA (connection);
431
432   _dbus_assert (d != NULL);
433
434   return d->connections->context;
435 }
436
437 BusConnections*
438 bus_connection_get_connections (DBusConnection *connection)
439 {
440   BusConnectionData *d;
441     
442   d = BUS_CONNECTION_DATA (connection);
443
444   _dbus_assert (d != NULL);
445
446   return d->connections;
447 }
448
449 BusRegistry*
450 bus_connection_get_registry (DBusConnection *connection)
451 {
452   BusConnectionData *d;
453
454   d = BUS_CONNECTION_DATA (connection);
455
456   _dbus_assert (d != NULL);
457
458   return bus_context_get_registry (d->connections->context);
459 }
460
461 BusActivation*
462 bus_connection_get_activation (DBusConnection *connection)
463 {
464   BusConnectionData *d;
465
466   d = BUS_CONNECTION_DATA (connection);
467
468   _dbus_assert (d != NULL);
469
470   return bus_context_get_activation (d->connections->context);
471 }
472
473 /**
474  * Checks whether the connection is registered with the message bus.
475  *
476  * @param connection the connection
477  * @returns #TRUE if we're an active message bus participant
478  */
479 dbus_bool_t
480 bus_connection_is_active (DBusConnection *connection)
481 {
482   BusConnectionData *d;
483
484   d = BUS_CONNECTION_DATA (connection);
485   
486   return d != NULL && d->name != NULL;
487 }
488
489 dbus_bool_t
490 bus_connection_preallocate_oom_error (DBusConnection *connection)
491 {
492   DBusMessage *message;
493   DBusPreallocatedSend *preallocated;
494   BusConnectionData *d;
495
496   d = BUS_CONNECTION_DATA (connection);  
497
498   _dbus_assert (d != NULL);
499
500   if (d->oom_preallocated != NULL)
501     return TRUE;
502   
503   preallocated = dbus_connection_preallocate_send (connection);
504   if (preallocated == NULL)
505     return FALSE;
506
507   message = dbus_message_new (DBUS_SERVICE_DBUS,
508                               DBUS_ERROR_NO_MEMORY);
509   if (message == NULL)
510     {
511       dbus_connection_free_preallocated_send (connection, preallocated);
512       return FALSE;
513     }
514
515   dbus_message_set_is_error (message, TRUE);
516   
517   /* set reply serial to placeholder value just so space is already allocated
518    * for it.
519    */
520   if (!dbus_message_set_reply_serial (message, 14))
521     {
522       dbus_connection_free_preallocated_send (connection, preallocated);
523       dbus_message_unref (message);
524       return FALSE;
525     }
526
527   d->oom_message = message;
528   d->oom_preallocated = preallocated;
529   
530   return TRUE;
531 }
532
533 void
534 bus_connection_send_oom_error (DBusConnection *connection,
535                                DBusMessage    *in_reply_to)
536 {
537   BusConnectionData *d;
538
539   d = BUS_CONNECTION_DATA (connection);  
540
541   _dbus_assert (d != NULL);  
542   _dbus_assert (d->oom_message != NULL);
543
544   /* should always succeed since we set it to a placeholder earlier */
545   if (!dbus_message_set_reply_serial (d->oom_message,
546                                       dbus_message_get_serial (in_reply_to)))
547     _dbus_assert_not_reached ("Failed to set reply serial for preallocated oom message");
548
549   dbus_connection_send_preallocated (connection, d->oom_preallocated,
550                                      d->oom_message, NULL);
551
552   dbus_message_unref (d->oom_message);
553   d->oom_message = NULL;
554   d->oom_preallocated = NULL;
555 }
556
557 dbus_bool_t
558 bus_connection_add_owned_service (DBusConnection *connection,
559                                   BusService     *service)
560 {
561   BusConnectionData *d;
562
563   d = BUS_CONNECTION_DATA (connection);
564   _dbus_assert (d != NULL);
565
566   if (!_dbus_list_append (&d->services_owned,
567                           service))
568     return FALSE;
569
570   return TRUE;
571 }
572
573 void
574 bus_connection_remove_owned_service (DBusConnection *connection,
575                                      BusService     *service)
576 {
577   BusConnectionData *d;
578
579   d = BUS_CONNECTION_DATA (connection);
580   _dbus_assert (d != NULL);
581
582   _dbus_list_remove_last (&d->services_owned, service);
583 }
584
585 dbus_bool_t
586 bus_connection_set_name (DBusConnection   *connection,
587                          const DBusString *name)
588 {
589   const char *c_name;
590   BusConnectionData *d;
591   
592   d = BUS_CONNECTION_DATA (connection);
593   _dbus_assert (d != NULL);
594   _dbus_assert (d->name == NULL);
595
596   _dbus_string_get_const_data (name, &c_name);
597
598   d->name = _dbus_strdup (c_name);
599
600   if (d->name == NULL)
601     return FALSE;
602
603   _dbus_verbose ("Name %s assigned to %p\n", d->name, connection);
604   
605   return TRUE;
606 }
607
608 const char *
609 bus_connection_get_name (DBusConnection *connection)
610 {
611   BusConnectionData *d;
612   
613   d = BUS_CONNECTION_DATA (connection);
614   _dbus_assert (d != NULL);
615   
616   return d->name;
617 }
618
619 typedef struct
620 {
621   BusTransaction *transaction;
622   DBusMessage    *message;
623   DBusPreallocatedSend *preallocated;
624 } MessageToSend;
625
626 struct BusTransaction
627 {
628   DBusList *connections;
629   BusContext *context;
630 };
631
632 static void
633 message_to_send_free (DBusConnection *connection,
634                       MessageToSend  *to_send)
635 {
636   if (to_send->message)
637     dbus_message_unref (to_send->message);
638
639   if (to_send->preallocated)
640     dbus_connection_free_preallocated_send (connection, to_send->preallocated);
641
642   dbus_free (to_send);
643 }
644
645 BusTransaction*
646 bus_transaction_new (BusContext *context)
647 {
648   BusTransaction *transaction;
649
650   transaction = dbus_new0 (BusTransaction, 1);
651   if (transaction == NULL)
652     return NULL;
653
654   transaction->context = context;
655   
656   return transaction;
657 }
658
659 BusContext*
660 bus_transaction_get_context (BusTransaction  *transaction)
661 {
662   return transaction->context;
663 }
664
665 BusConnections*
666 bus_transaction_get_connections (BusTransaction  *transaction)
667 {
668   return bus_context_get_connections (transaction->context);
669 }
670
671 dbus_bool_t
672 bus_transaction_send_message (BusTransaction *transaction,
673                               DBusConnection *connection,
674                               DBusMessage    *message)
675 {
676   MessageToSend *to_send;
677   BusConnectionData *d;
678   DBusList *link;
679
680   _dbus_verbose ("  trying to add message %s to transaction%s\n",
681                  dbus_message_get_name (message),
682                  dbus_connection_get_is_connected (connection) ?
683                  "" : " (disconnected)");
684   
685   if (!dbus_connection_get_is_connected (connection))
686     return TRUE; /* silently ignore disconnected connections */
687   
688   d = BUS_CONNECTION_DATA (connection);
689   _dbus_assert (d != NULL);
690   
691   to_send = dbus_new (MessageToSend, 1);
692   if (to_send == NULL)
693     {
694       return FALSE;
695     }
696
697   to_send->preallocated = dbus_connection_preallocate_send (connection);
698   if (to_send->preallocated == NULL)
699     {
700       dbus_free (to_send);
701       return FALSE;
702     }  
703   
704   dbus_message_ref (message);
705   to_send->message = message;
706   to_send->transaction = transaction;
707
708   _dbus_verbose ("about to prepend message\n");
709   
710   if (!_dbus_list_prepend (&d->transaction_messages, to_send))
711     {
712       message_to_send_free (connection, to_send);
713       return FALSE;
714     }
715
716   _dbus_verbose ("prepended message\n");
717   
718   /* See if we already had this connection in the list
719    * for this transaction. If we have a pending message,
720    * then we should already be in transaction->connections
721    */
722   link = _dbus_list_get_first_link (&d->transaction_messages);
723   _dbus_assert (link->data == to_send);
724   link = _dbus_list_get_next_link (&d->transaction_messages, link);
725   while (link != NULL)
726     {
727       MessageToSend *m = link->data;
728       DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link);
729       
730       if (m->transaction == transaction)
731         break;
732         
733       link = next;
734     }
735
736   if (link == NULL)
737     {
738       if (!_dbus_list_prepend (&transaction->connections, connection))
739         {
740           _dbus_list_remove (&d->transaction_messages, to_send);
741           message_to_send_free (connection, to_send);
742           return FALSE;
743         }
744     }
745
746   return TRUE;
747 }
748
749 static void
750 connection_cancel_transaction (DBusConnection *connection,
751                                BusTransaction *transaction)
752 {
753   DBusList *link;
754   BusConnectionData *d;
755   
756   d = BUS_CONNECTION_DATA (connection);
757   _dbus_assert (d != NULL);
758   
759   link = _dbus_list_get_first_link (&d->transaction_messages);
760   while (link != NULL)
761     {
762       MessageToSend *m = link->data;
763       DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link);
764       
765       if (m->transaction == transaction)
766         {
767           _dbus_list_remove_link (&d->transaction_messages,
768                                   link);
769           
770           message_to_send_free (connection, m);
771         }
772         
773       link = next;
774     }
775 }
776
777 void
778 bus_transaction_cancel_and_free (BusTransaction *transaction)
779 {
780   DBusConnection *connection;
781
782   _dbus_verbose ("TRANSACTION: cancelled\n");
783   
784   while ((connection = _dbus_list_pop_first (&transaction->connections)))
785     connection_cancel_transaction (connection, transaction);
786
787   _dbus_assert (transaction->connections == NULL);
788
789   dbus_free (transaction);
790 }
791
792 static void
793 connection_execute_transaction (DBusConnection *connection,
794                                 BusTransaction *transaction)
795 {
796   DBusList *link;
797   BusConnectionData *d;
798   
799   d = BUS_CONNECTION_DATA (connection);
800   _dbus_assert (d != NULL);
801
802   /* Send the queue in order (FIFO) */
803   link = _dbus_list_get_last_link (&d->transaction_messages);
804   while (link != NULL)
805     {
806       MessageToSend *m = link->data;
807       DBusList *prev = _dbus_list_get_prev_link (&d->transaction_messages, link);
808       
809       if (m->transaction == transaction)
810         {
811           _dbus_list_remove_link (&d->transaction_messages,
812                                   link);
813
814           dbus_connection_send_preallocated (connection,
815                                              m->preallocated,
816                                              m->message,
817                                              NULL);
818
819           m->preallocated = NULL; /* so we don't double-free it */
820           
821           message_to_send_free (connection, m);
822         }
823         
824       link = prev;
825     }
826 }
827
828 void
829 bus_transaction_execute_and_free (BusTransaction *transaction)
830 {
831   /* For each connection in transaction->connections
832    * send the messages
833    */
834   DBusConnection *connection;
835
836   _dbus_verbose ("TRANSACTION: executing\n");
837   
838   while ((connection = _dbus_list_pop_first (&transaction->connections)))
839     connection_execute_transaction (connection, transaction);
840
841   _dbus_assert (transaction->connections == NULL);
842
843   dbus_free (transaction);
844 }
845
846 static void
847 bus_connection_remove_transactions (DBusConnection *connection)
848 {
849   MessageToSend *to_send;
850   BusConnectionData *d;
851   
852   d = BUS_CONNECTION_DATA (connection);
853   _dbus_assert (d != NULL);
854   
855   while ((to_send = _dbus_list_get_first (&d->transaction_messages)))
856     {
857       /* only has an effect for the first MessageToSend listing this transaction */
858       _dbus_list_remove (&to_send->transaction->connections,
859                          connection);
860
861       _dbus_list_remove (&d->transaction_messages, to_send);
862       message_to_send_free (connection, to_send);
863     }
864 }
865
866 /**
867  * Converts the DBusError to a message reply
868  */
869 dbus_bool_t
870 bus_transaction_send_error_reply (BusTransaction  *transaction,
871                                   DBusConnection  *connection,
872                                   const DBusError *error,
873                                   DBusMessage     *in_reply_to)
874 {
875   DBusMessage *reply;
876
877   _dbus_assert (error != NULL);
878   _DBUS_ASSERT_ERROR_IS_SET (error);
879   
880   reply = dbus_message_new_error_reply (in_reply_to,
881                                         error->name,
882                                         error->message);
883   if (reply == NULL)
884     return FALSE;
885
886   if (!bus_transaction_send_message (transaction, connection, reply))
887     {
888       dbus_message_unref (reply);
889       return FALSE;
890     }
891
892   return TRUE;
893 }