commit.msg
[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 2.1
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 "policy.h"
26 #include "services.h"
27 #include "utils.h"
28 #include "signals.h"
29 #include "expirelist.h"
30 #include "selinux.h"
31 #include <dbus/dbus-list.h>
32 #include <dbus/dbus-hash.h>
33 #include <dbus/dbus-timeout.h>
34 #include <dbus/dbus-userdb.h>
35
36 static void bus_connection_remove_transactions (DBusConnection *connection);
37
38 typedef struct
39 {
40   BusExpireItem expire_item;
41
42   DBusConnection *will_get_reply;
43   DBusConnection *will_send_reply;
44
45   dbus_uint32_t reply_serial;
46   
47 } BusPendingReply;
48
49 struct BusConnections
50 {
51   int refcount;
52   DBusList *completed;  /**< List of all completed connections */
53   int n_completed;      /**< Length of completed list */
54   DBusList *incomplete; /**< List of all not-yet-active connections */
55   int n_incomplete;     /**< Length of incomplete list */
56   BusContext *context;
57   DBusHashTable *completed_by_user; /**< Number of completed connections for each UID */
58   DBusTimeout *expire_timeout; /**< Timeout for expiring incomplete connections. */
59   int stamp;                   /**< Incrementing number */
60   BusExpireList *pending_replies; /**< List of pending replies */
61 };
62
63 static dbus_int32_t connection_data_slot = -1;
64
65 typedef struct
66 {
67   BusConnections *connections;
68   DBusList *link_in_connection_list;
69   DBusConnection *connection;
70   DBusList *services_owned;
71   int n_services_owned;
72   DBusList *match_rules;
73   int n_match_rules;
74   char *name;
75   DBusList *transaction_messages; /**< Stuff we need to send as part of a transaction */
76   DBusMessage *oom_message;
77   DBusPreallocatedSend *oom_preallocated;
78   BusClientPolicy *policy;
79
80   BusSELinuxID *selinux_id;
81
82   long connection_tv_sec;  /**< Time when we connected (seconds component) */
83   long connection_tv_usec; /**< Time when we connected (microsec component) */
84   int stamp;               /**< connections->stamp last time we were traversed */
85 } BusConnectionData;
86
87 static dbus_bool_t bus_pending_reply_expired (BusExpireList *list,
88                                               DBusList      *link,
89                                               void          *data);
90
91 static void bus_connection_drop_pending_replies (BusConnections  *connections,
92                                                  DBusConnection  *connection);
93
94 static dbus_bool_t expire_incomplete_timeout (void *data);
95
96 #define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot))
97
98 static DBusLoop*
99 connection_get_loop (DBusConnection *connection)
100 {
101   BusConnectionData *d;
102
103   d = BUS_CONNECTION_DATA (connection);
104
105   return bus_context_get_loop (d->connections->context);
106 }
107
108
109 static int
110 get_connections_for_uid (BusConnections *connections,
111                          dbus_uid_t      uid)
112 {
113   void *val;
114   int current_count;
115
116   /* val is NULL is 0 when it isn't in the hash yet */
117   
118   val = _dbus_hash_table_lookup_ulong (connections->completed_by_user,
119                                        uid);
120
121   current_count = _DBUS_POINTER_TO_INT (val);
122
123   return current_count;
124 }
125
126 static dbus_bool_t
127 adjust_connections_for_uid (BusConnections *connections,
128                             dbus_uid_t      uid,
129                             int             adjustment)
130 {
131   int current_count;
132
133   current_count = get_connections_for_uid (connections, uid);
134
135   _dbus_verbose ("Adjusting connection count for UID " DBUS_UID_FORMAT
136                  ": was %d adjustment %d making %d\n",
137                  uid, current_count, adjustment, current_count + adjustment);
138   
139   _dbus_assert (current_count >= 0);
140   
141   current_count += adjustment;
142
143   _dbus_assert (current_count >= 0);
144
145   if (current_count == 0)
146     {
147       _dbus_hash_table_remove_ulong (connections->completed_by_user, uid);
148       return TRUE;
149     }
150   else
151     {
152       dbus_bool_t retval;
153       
154       retval = _dbus_hash_table_insert_ulong (connections->completed_by_user,
155                                               uid, _DBUS_INT_TO_POINTER (current_count));
156
157       /* only positive adjustment can fail as otherwise
158        * a hash entry should already exist
159        */
160       _dbus_assert (adjustment > 0 ||
161                     (adjustment <= 0 && retval));
162
163       return retval;
164     }
165 }
166
167 void
168 bus_connection_disconnected (DBusConnection *connection)
169 {
170   BusConnectionData *d;
171   BusService *service;
172   BusMatchmaker *matchmaker;
173   
174   d = BUS_CONNECTION_DATA (connection);
175   _dbus_assert (d != NULL);
176
177   _dbus_verbose ("%s disconnected, dropping all service ownership and releasing\n",
178                  d->name ? d->name : "(inactive)");
179
180   /* Delete our match rules */
181   if (d->n_match_rules > 0)
182     {
183       matchmaker = bus_context_get_matchmaker (d->connections->context);
184       bus_matchmaker_disconnected (matchmaker, connection);
185     }
186   
187   /* Drop any service ownership. Unfortunately, this requires
188    * memory allocation and there doesn't seem to be a good way to
189    * handle it other than sleeping; we can't "fail" the operation of
190    * disconnecting a client, and preallocating a broadcast "service is
191    * now gone" message for every client-service pair seems kind of
192    * involved.
193    */
194   while ((service = _dbus_list_get_last (&d->services_owned)))
195     {
196       BusTransaction *transaction;
197       DBusError error;
198
199     retry:
200       
201       dbus_error_init (&error);
202         
203       while ((transaction = bus_transaction_new (d->connections->context)) == NULL)
204         _dbus_wait_for_memory ();
205         
206       if (!bus_service_remove_owner (service, connection,
207                                      transaction, &error))
208         {
209           _DBUS_ASSERT_ERROR_IS_SET (&error);
210           
211           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
212             {
213               dbus_error_free (&error);
214               bus_transaction_cancel_and_free (transaction);
215               _dbus_wait_for_memory ();
216               goto retry;
217             }
218           else
219             {
220               _dbus_verbose ("Failed to remove service owner: %s %s\n",
221                              error.name, error.message);
222               _dbus_assert_not_reached ("Removing service owner failed for non-memory-related reason");
223             }
224         }
225         
226       bus_transaction_execute_and_free (transaction);
227     }
228
229   bus_dispatch_remove_connection (connection);
230   
231   /* no more watching */
232   if (!dbus_connection_set_watch_functions (connection,
233                                             NULL, NULL, NULL,
234                                             connection,
235                                             NULL))
236     _dbus_assert_not_reached ("setting watch functions to NULL failed");
237
238   if (!dbus_connection_set_timeout_functions (connection,
239                                               NULL, NULL, NULL,
240                                               connection,
241                                               NULL))
242     _dbus_assert_not_reached ("setting timeout functions to NULL failed");
243   
244   dbus_connection_set_unix_user_function (connection,
245                                           NULL, NULL, NULL);
246
247   dbus_connection_set_dispatch_status_function (connection,
248                                                 NULL, NULL, NULL);
249   
250   bus_connection_remove_transactions (connection);
251
252   if (d->link_in_connection_list != NULL)
253     {
254       if (d->name != NULL)
255         {
256           unsigned long uid;
257           
258           _dbus_list_remove_link (&d->connections->completed, d->link_in_connection_list);
259           d->link_in_connection_list = NULL;
260           d->connections->n_completed -= 1;
261
262           if (dbus_connection_get_unix_user (connection, &uid))
263             {
264               if (!adjust_connections_for_uid (d->connections,
265                                                uid, -1))
266                 _dbus_assert_not_reached ("adjusting downward should never fail");
267             }
268         }
269       else
270         {
271           _dbus_list_remove_link (&d->connections->incomplete, d->link_in_connection_list);
272           d->link_in_connection_list = NULL;
273           d->connections->n_incomplete -= 1;
274         }
275       
276       _dbus_assert (d->connections->n_incomplete >= 0);
277       _dbus_assert (d->connections->n_completed >= 0);
278     }
279
280   bus_connection_drop_pending_replies (d->connections, connection);
281   
282   /* frees "d" as side effect */
283   dbus_connection_set_data (connection,
284                             connection_data_slot,
285                             NULL, NULL);
286   
287   dbus_connection_unref (connection);
288 }
289
290 static dbus_bool_t
291 connection_watch_callback (DBusWatch     *watch,
292                            unsigned int   condition,
293                            void          *data)
294 {
295  /* FIXME this can be done in dbus-mainloop.c
296   * if the code in activation.c for the babysitter
297   * watch handler is fixed.
298   */
299   
300 #if 0
301   _dbus_verbose ("Calling handle_watch\n");
302 #endif
303   return dbus_watch_handle (watch, condition);
304 }
305
306 static dbus_bool_t
307 add_connection_watch (DBusWatch      *watch,
308                       void           *data)
309 {
310   DBusConnection *connection = data;
311
312   return _dbus_loop_add_watch (connection_get_loop (connection),
313                                watch, connection_watch_callback, connection,
314                                NULL);
315 }
316
317 static void
318 remove_connection_watch (DBusWatch      *watch,
319                          void           *data)
320 {
321   DBusConnection *connection = data;
322   
323   _dbus_loop_remove_watch (connection_get_loop (connection),
324                            watch, connection_watch_callback, connection);
325 }
326
327 static void
328 connection_timeout_callback (DBusTimeout   *timeout,
329                              void          *data)
330 {
331   /* DBusConnection *connection = data; */
332
333   /* can return FALSE on OOM but we just let it fire again later */
334   dbus_timeout_handle (timeout);
335 }
336
337 static dbus_bool_t
338 add_connection_timeout (DBusTimeout    *timeout,
339                         void           *data)
340 {
341   DBusConnection *connection = data;
342   
343   return _dbus_loop_add_timeout (connection_get_loop (connection),
344                                  timeout, connection_timeout_callback, connection, NULL);
345 }
346
347 static void
348 remove_connection_timeout (DBusTimeout    *timeout,
349                            void           *data)
350 {
351   DBusConnection *connection = data;
352   
353   _dbus_loop_remove_timeout (connection_get_loop (connection),
354                              timeout, connection_timeout_callback, connection);
355 }
356
357 static void
358 dispatch_status_function (DBusConnection    *connection,
359                           DBusDispatchStatus new_status,
360                           void              *data)
361 {
362   DBusLoop *loop = data;
363   
364   if (new_status != DBUS_DISPATCH_COMPLETE)
365     {
366       while (!_dbus_loop_queue_dispatch (loop, connection))
367         _dbus_wait_for_memory ();
368     }
369 }
370
371 static dbus_bool_t
372 allow_user_function (DBusConnection *connection,
373                      unsigned long   uid,
374                      void           *data)
375 {
376   BusConnectionData *d;
377     
378   d = BUS_CONNECTION_DATA (connection);
379
380   _dbus_assert (d != NULL);
381   
382   return bus_context_allow_user (d->connections->context, uid);
383 }
384
385 static void
386 free_connection_data (void *data)
387 {
388   BusConnectionData *d = data;
389
390   /* services_owned should be NULL since we should be disconnected */
391   _dbus_assert (d->services_owned == NULL);
392   _dbus_assert (d->n_services_owned == 0);
393   /* similarly */
394   _dbus_assert (d->transaction_messages == NULL);
395
396   if (d->oom_preallocated)
397     dbus_connection_free_preallocated_send (d->connection, d->oom_preallocated);
398
399   if (d->oom_message)
400     dbus_message_unref (d->oom_message);
401
402   if (d->policy)
403     bus_client_policy_unref (d->policy);
404
405   if (d->selinux_id)
406     bus_selinux_id_unref (d->selinux_id);
407   
408   dbus_free (d->name);
409   
410   dbus_free (d);
411 }
412
413 static void
414 call_timeout_callback (DBusTimeout   *timeout,
415                        void          *data)
416 {
417   /* can return FALSE on OOM but we just let it fire again later */
418   dbus_timeout_handle (timeout);
419 }
420
421 BusConnections*
422 bus_connections_new (BusContext *context)
423 {
424   BusConnections *connections;
425
426   if (!dbus_connection_allocate_data_slot (&connection_data_slot))
427     goto failed_0;
428
429   connections = dbus_new0 (BusConnections, 1);
430   if (connections == NULL)
431     goto failed_1;
432
433   connections->completed_by_user = _dbus_hash_table_new (DBUS_HASH_ULONG,
434                                                          NULL, NULL);
435   if (connections->completed_by_user == NULL)
436     goto failed_2;
437
438   connections->expire_timeout = _dbus_timeout_new (100, /* irrelevant */
439                                                    expire_incomplete_timeout,
440                                                    connections, NULL);
441   if (connections->expire_timeout == NULL)
442     goto failed_3;
443
444   _dbus_timeout_set_enabled (connections->expire_timeout, FALSE);
445
446   connections->pending_replies = bus_expire_list_new (bus_context_get_loop (context),
447                                                       bus_context_get_reply_timeout (context),
448                                                       bus_pending_reply_expired,
449                                                       connections);
450   if (connections->pending_replies == NULL)
451     goto failed_4;
452   
453   if (!_dbus_loop_add_timeout (bus_context_get_loop (context),
454                                connections->expire_timeout,
455                                call_timeout_callback, NULL, NULL))
456     goto failed_5;
457   
458   connections->refcount = 1;
459   connections->context = context;
460   
461   return connections;
462
463  failed_5:
464   bus_expire_list_free (connections->pending_replies);
465  failed_4:
466   _dbus_timeout_unref (connections->expire_timeout);
467  failed_3:
468   _dbus_hash_table_unref (connections->completed_by_user);
469  failed_2:
470   dbus_free (connections);
471  failed_1:
472   dbus_connection_free_data_slot (&connection_data_slot);
473  failed_0:
474   return NULL;
475 }
476
477 BusConnections *
478 bus_connections_ref (BusConnections *connections)
479 {
480   _dbus_assert (connections->refcount > 0);
481   connections->refcount += 1;
482
483   return connections;
484 }
485
486 void
487 bus_connections_unref (BusConnections *connections)
488 {
489   _dbus_assert (connections->refcount > 0);
490   connections->refcount -= 1;
491   if (connections->refcount == 0)
492     {
493       /* drop all incomplete */
494       while (connections->incomplete != NULL)
495         {
496           DBusConnection *connection;
497
498           connection = connections->incomplete->data;
499
500           dbus_connection_ref (connection);
501           dbus_connection_close (connection);
502           bus_connection_disconnected (connection);
503           dbus_connection_unref (connection);
504         }
505
506       _dbus_assert (connections->n_incomplete == 0);
507       
508       /* drop all real connections */
509       while (connections->completed != NULL)
510         {
511           DBusConnection *connection;
512
513           connection = connections->completed->data;
514
515           dbus_connection_ref (connection);
516           dbus_connection_close (connection);
517           bus_connection_disconnected (connection);
518           dbus_connection_unref (connection);
519         }
520
521       _dbus_assert (connections->n_completed == 0);
522
523       bus_expire_list_free (connections->pending_replies);
524       
525       _dbus_loop_remove_timeout (bus_context_get_loop (connections->context),
526                                  connections->expire_timeout,
527                                  call_timeout_callback, NULL);
528       
529       _dbus_timeout_unref (connections->expire_timeout);
530       
531       _dbus_hash_table_unref (connections->completed_by_user);
532       
533       dbus_free (connections);
534
535       dbus_connection_free_data_slot (&connection_data_slot);
536     }
537 }
538
539 dbus_bool_t
540 bus_connections_setup_connection (BusConnections *connections,
541                                   DBusConnection *connection)
542 {
543   BusConnectionData *d;
544   dbus_bool_t retval;
545   DBusError error;
546   
547   d = dbus_new0 (BusConnectionData, 1);
548   
549   if (d == NULL)
550     return FALSE;
551
552   d->connections = connections;
553   d->connection = connection;
554   
555   _dbus_get_current_time (&d->connection_tv_sec,
556                           &d->connection_tv_usec);
557   
558   _dbus_assert (connection_data_slot >= 0);
559   
560   if (!dbus_connection_set_data (connection,
561                                  connection_data_slot,
562                                  d, free_connection_data))
563     {
564       dbus_free (d);
565       return FALSE;
566     }
567
568   dbus_connection_set_route_peer_messages (connection, TRUE);
569   
570   retval = FALSE;
571
572   dbus_error_init (&error);
573   d->selinux_id = bus_selinux_init_connection_id (connection,
574                                                   &error);
575   if (dbus_error_is_set (&error))
576     {
577       /* This is a bit bogus because we pretend all errors
578        * are OOM; this is done because we know that in bus.c
579        * an OOM error disconnects the connection, which is
580        * the same thing we want on any other error.
581        */
582       dbus_error_free (&error);
583       goto out;
584     }
585   
586   if (!dbus_connection_set_watch_functions (connection,
587                                             add_connection_watch,
588                                             remove_connection_watch,
589                                             NULL,
590                                             connection,
591                                             NULL))
592     goto out;
593   
594   if (!dbus_connection_set_timeout_functions (connection,
595                                               add_connection_timeout,
596                                               remove_connection_timeout,
597                                               NULL,
598                                               connection, NULL))
599     goto out;
600   
601   dbus_connection_set_unix_user_function (connection,
602                                           allow_user_function,
603                                           NULL, NULL);
604
605   dbus_connection_set_dispatch_status_function (connection,
606                                                 dispatch_status_function,
607                                                 bus_context_get_loop (connections->context),
608                                                 NULL);
609
610   d->link_in_connection_list = _dbus_list_alloc_link (connection);
611   if (d->link_in_connection_list == NULL)
612     goto out;
613   
614   /* Setup the connection with the dispatcher */
615   if (!bus_dispatch_add_connection (connection))
616     goto out;
617
618   if (dbus_connection_get_dispatch_status (connection) != DBUS_DISPATCH_COMPLETE)
619     {
620       if (!_dbus_loop_queue_dispatch (bus_context_get_loop (connections->context), connection))
621         {
622           bus_dispatch_remove_connection (connection);
623           goto out;
624         }
625     }
626
627   _dbus_list_append_link (&connections->incomplete, d->link_in_connection_list);
628   connections->n_incomplete += 1;
629   
630   dbus_connection_ref (connection);
631
632   /* Note that we might disconnect ourselves here, but it only takes
633    * effect on return to the main loop. We call this to free up
634    * expired connections if possible, and to queue the timeout for our
635    * own expiration.
636    */
637   bus_connections_expire_incomplete (connections);
638   
639   /* And we might also disconnect ourselves here, but again it
640    * only takes effect on return to main loop.
641    */
642   if (connections->n_incomplete >
643       bus_context_get_max_incomplete_connections (connections->context))
644     {
645       _dbus_verbose ("Number of incomplete connections exceeds max, dropping oldest one\n");
646       
647       _dbus_assert (connections->incomplete != NULL);
648       /* Disconnect the oldest unauthenticated connection.  FIXME
649        * would it be more secure to drop a *random* connection?  This
650        * algorithm seems to mean that if someone can create new
651        * connections quickly enough, they can keep anyone else from
652        * completing authentication. But random may or may not really
653        * help with that, a more elaborate solution might be required.
654        */
655       dbus_connection_close (connections->incomplete->data);
656     }
657   
658   retval = TRUE;
659
660  out:
661   if (!retval)
662     {
663       if (d->selinux_id)
664         bus_selinux_id_unref (d->selinux_id);
665       d->selinux_id = NULL;
666       
667       if (!dbus_connection_set_watch_functions (connection,
668                                                 NULL, NULL, NULL,
669                                                 connection,
670                                                 NULL))
671         _dbus_assert_not_reached ("setting watch functions to NULL failed");
672       
673       if (!dbus_connection_set_timeout_functions (connection,
674                                                   NULL, NULL, NULL,
675                                                   connection,
676                                                   NULL))
677         _dbus_assert_not_reached ("setting timeout functions to NULL failed");
678
679       dbus_connection_set_unix_user_function (connection,
680                                               NULL, NULL, NULL);
681
682       dbus_connection_set_dispatch_status_function (connection,
683                                                     NULL, NULL, NULL);
684
685       if (d->link_in_connection_list != NULL)
686         {
687           _dbus_assert (d->link_in_connection_list->next == NULL);
688           _dbus_assert (d->link_in_connection_list->prev == NULL);
689           _dbus_list_free_link (d->link_in_connection_list);
690           d->link_in_connection_list = NULL;
691         }
692       
693       if (!dbus_connection_set_data (connection,
694                                      connection_data_slot,
695                                      NULL, NULL))
696         _dbus_assert_not_reached ("failed to set connection data to null");
697
698       /* "d" has now been freed */
699     }
700   
701   return retval;
702 }
703
704 void
705 bus_connections_expire_incomplete (BusConnections *connections)
706 {    
707   int next_interval;
708
709   next_interval = -1;
710   
711   if (connections->incomplete != NULL)
712     {
713       long tv_sec, tv_usec;
714       DBusList *link;
715       int auth_timeout;
716       
717       _dbus_get_current_time (&tv_sec, &tv_usec);
718       auth_timeout = bus_context_get_auth_timeout (connections->context);
719   
720       link = _dbus_list_get_first_link (&connections->incomplete);
721       while (link != NULL)
722         {
723           DBusList *next = _dbus_list_get_next_link (&connections->incomplete, link);
724           DBusConnection *connection;
725           BusConnectionData *d;
726           double elapsed;
727       
728           connection = link->data;
729       
730           d = BUS_CONNECTION_DATA (connection);
731       
732           _dbus_assert (d != NULL);
733       
734           elapsed = ELAPSED_MILLISECONDS_SINCE (d->connection_tv_sec,
735                                                 d->connection_tv_usec,
736                                                 tv_sec, tv_usec);
737
738           if (elapsed >= (double) auth_timeout)
739             {
740               _dbus_verbose ("Timing out authentication for connection %p\n", connection);
741               dbus_connection_close (connection);
742             }
743           else
744             {
745               /* We can end the loop, since the connections are in oldest-first order */
746               next_interval = ((double)auth_timeout) - elapsed;
747               _dbus_verbose ("Connection %p authentication expires in %d milliseconds\n",
748                              connection, next_interval);
749           
750               break;
751             }
752       
753           link = next;
754         }
755     }
756
757   bus_expire_timeout_set_interval (connections->expire_timeout,
758                                    next_interval);
759 }
760
761 static dbus_bool_t
762 expire_incomplete_timeout (void *data)
763 {
764   BusConnections *connections = data;
765
766   _dbus_verbose ("Running %s\n", _DBUS_FUNCTION_NAME);
767   
768   /* note that this may remove the timeout */
769   bus_connections_expire_incomplete (connections);
770
771   return TRUE;
772 }
773
774 dbus_bool_t
775 bus_connection_get_groups  (DBusConnection   *connection,
776                             unsigned long   **groups,
777                             int              *n_groups,
778                             DBusError        *error)
779 {
780   BusConnectionData *d;
781   unsigned long uid;
782   
783   d = BUS_CONNECTION_DATA (connection);
784
785   _dbus_assert (d != NULL);
786
787   *groups = NULL;
788   *n_groups = 0;
789
790   if (dbus_connection_get_unix_user (connection, &uid))
791     {
792       if (!_dbus_groups_from_uid (uid, groups, n_groups))
793         {
794           _dbus_verbose ("Did not get any groups for UID %lu\n",
795                          uid);
796           return FALSE;
797         }
798       else
799         {
800           _dbus_verbose ("Got %d groups for UID %lu\n",
801                          *n_groups, uid);
802           return TRUE;
803         }
804     }
805   else
806     return TRUE; /* successfully got 0 groups */
807 }
808
809 dbus_bool_t
810 bus_connection_is_in_group (DBusConnection *connection,
811                             unsigned long   gid)
812 {
813   int i;
814   unsigned long *group_ids;
815   int n_group_ids;
816
817   if (!bus_connection_get_groups (connection, &group_ids, &n_group_ids,
818                                   NULL))
819     return FALSE;
820
821   i = 0;
822   while (i < n_group_ids)
823     {
824       if (group_ids[i] == gid)
825         {
826           dbus_free (group_ids);
827           return TRUE;
828         }
829       ++i;
830     }
831
832   dbus_free (group_ids);
833   return FALSE;
834 }
835
836 BusClientPolicy*
837 bus_connection_get_policy (DBusConnection *connection)
838 {
839   BusConnectionData *d;
840     
841   d = BUS_CONNECTION_DATA (connection);
842
843   _dbus_assert (d != NULL);
844   _dbus_assert (d->policy != NULL);
845   
846   return d->policy;
847 }
848
849 static dbus_bool_t
850 foreach_active (BusConnections               *connections,
851                 BusConnectionForeachFunction  function,
852                 void                         *data)
853 {
854   DBusList *link;
855   
856   link = _dbus_list_get_first_link (&connections->completed);
857   while (link != NULL)
858     {
859       DBusConnection *connection = link->data;
860       DBusList *next = _dbus_list_get_next_link (&connections->completed, link);
861
862       if (!(* function) (connection, data))
863         return FALSE;
864       
865       link = next;
866     }
867
868   return TRUE;
869 }
870
871 static dbus_bool_t
872 foreach_inactive (BusConnections               *connections,
873                   BusConnectionForeachFunction  function,
874                   void                         *data)
875 {
876   DBusList *link;
877   
878   link = _dbus_list_get_first_link (&connections->incomplete);
879   while (link != NULL)
880     {
881       DBusConnection *connection = link->data;
882       DBusList *next = _dbus_list_get_next_link (&connections->incomplete, link);
883
884       if (!(* function) (connection, data))
885         return FALSE;
886       
887       link = next;
888     }
889
890   return TRUE;
891 }
892
893 /**
894  * Calls function on each active connection; if the function returns
895  * #FALSE, stops iterating. Active connections are authenticated
896  * and have sent a Hello message.
897  *
898  * @param connections the connections object
899  * @param function the function
900  * @param data data to pass to it as a second arg
901  */
902 void
903 bus_connections_foreach_active (BusConnections               *connections,
904                                 BusConnectionForeachFunction  function,
905                                 void                         *data)
906 {
907   foreach_active (connections, function, data);
908 }
909
910 /**
911  * Calls function on each connection; if the function returns
912  * #FALSE, stops iterating.
913  *
914  * @param connections the connections object
915  * @param function the function
916  * @param data data to pass to it as a second arg
917  */
918 void
919 bus_connections_foreach (BusConnections               *connections,
920                          BusConnectionForeachFunction  function,
921                          void                         *data)
922 {
923   if (!foreach_active (connections, function, data))
924     return;
925
926   foreach_inactive (connections, function, data);
927 }
928
929 BusContext*
930 bus_connections_get_context (BusConnections *connections)
931 {
932   return connections->context;
933 }
934
935 /*
936  * This is used to avoid covering the same connection twice when
937  * traversing connections. Note that it assumes we will
938  * bus_connection_mark_stamp() each connection at least once per
939  * INT_MAX increments of the global stamp, or wraparound would break
940  * things.
941  */
942 void
943 bus_connections_increment_stamp (BusConnections *connections)
944 {
945   connections->stamp += 1;
946 }
947
948 /* Mark connection with current stamp, return TRUE if it
949  * didn't already have that stamp
950  */
951 dbus_bool_t
952 bus_connection_mark_stamp (DBusConnection *connection)
953 {
954   BusConnectionData *d;
955   
956   d = BUS_CONNECTION_DATA (connection);
957   
958   _dbus_assert (d != NULL);
959
960   if (d->stamp == d->connections->stamp)
961     return FALSE;
962   else
963     {
964       d->stamp = d->connections->stamp;
965       return TRUE;
966     }
967 }
968
969 BusContext*
970 bus_connection_get_context (DBusConnection *connection)
971 {
972   BusConnectionData *d;
973
974   d = BUS_CONNECTION_DATA (connection);
975
976   _dbus_assert (d != NULL);
977
978   return d->connections->context;
979 }
980
981 BusConnections*
982 bus_connection_get_connections (DBusConnection *connection)
983 {
984   BusConnectionData *d;
985     
986   d = BUS_CONNECTION_DATA (connection);
987
988   _dbus_assert (d != NULL);
989
990   return d->connections;
991 }
992
993 BusRegistry*
994 bus_connection_get_registry (DBusConnection *connection)
995 {
996   BusConnectionData *d;
997
998   d = BUS_CONNECTION_DATA (connection);
999
1000   _dbus_assert (d != NULL);
1001
1002   return bus_context_get_registry (d->connections->context);
1003 }
1004
1005 BusActivation*
1006 bus_connection_get_activation (DBusConnection *connection)
1007 {
1008   BusConnectionData *d;
1009
1010   d = BUS_CONNECTION_DATA (connection);
1011
1012   _dbus_assert (d != NULL);
1013
1014   return bus_context_get_activation (d->connections->context);
1015 }
1016
1017 BusMatchmaker*
1018 bus_connection_get_matchmaker (DBusConnection *connection)
1019 {
1020   BusConnectionData *d;
1021
1022   d = BUS_CONNECTION_DATA (connection);
1023
1024   _dbus_assert (d != NULL);
1025
1026   return bus_context_get_matchmaker (d->connections->context);
1027 }
1028
1029 BusSELinuxID*
1030 bus_connection_get_selinux_id (DBusConnection *connection)
1031 {
1032   BusConnectionData *d;
1033
1034   d = BUS_CONNECTION_DATA (connection);
1035
1036   _dbus_assert (d != NULL);
1037
1038   return d->selinux_id;
1039 }
1040
1041 /**
1042  * Checks whether the connection is registered with the message bus.
1043  *
1044  * @param connection the connection
1045  * @returns #TRUE if we're an active message bus participant
1046  */
1047 dbus_bool_t
1048 bus_connection_is_active (DBusConnection *connection)
1049 {
1050   BusConnectionData *d;
1051
1052   d = BUS_CONNECTION_DATA (connection);
1053   
1054   return d != NULL && d->name != NULL;
1055 }
1056
1057 dbus_bool_t
1058 bus_connection_preallocate_oom_error (DBusConnection *connection)
1059 {
1060   DBusMessage *message;
1061   DBusPreallocatedSend *preallocated;
1062   BusConnectionData *d;
1063
1064   d = BUS_CONNECTION_DATA (connection);  
1065
1066   _dbus_assert (d != NULL);
1067
1068   if (d->oom_preallocated != NULL)
1069     return TRUE;
1070   
1071   preallocated = dbus_connection_preallocate_send (connection);
1072   if (preallocated == NULL)
1073     return FALSE;
1074
1075   message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR);
1076
1077   if (message == NULL)
1078     {
1079       dbus_connection_free_preallocated_send (connection, preallocated);
1080       return FALSE;
1081     }
1082
1083   /* d->name may be NULL, but that is OK */
1084   if (!dbus_message_set_error_name (message, DBUS_ERROR_NO_MEMORY) ||
1085       !dbus_message_set_destination (message, d->name) ||
1086       !dbus_message_set_sender (message,
1087                                 DBUS_SERVICE_DBUS))
1088     {
1089       dbus_connection_free_preallocated_send (connection, preallocated);
1090       dbus_message_unref (message);
1091       return FALSE;
1092     }
1093   
1094   /* set reply serial to placeholder value just so space is already allocated
1095    * for it.
1096    */
1097   if (!dbus_message_set_reply_serial (message, 14))
1098     {
1099       dbus_connection_free_preallocated_send (connection, preallocated);
1100       dbus_message_unref (message);
1101       return FALSE;
1102     }
1103
1104   d->oom_message = message;
1105   d->oom_preallocated = preallocated;
1106   
1107   return TRUE;
1108 }
1109
1110 void
1111 bus_connection_send_oom_error (DBusConnection *connection,
1112                                DBusMessage    *in_reply_to)
1113 {
1114   BusConnectionData *d;
1115
1116   d = BUS_CONNECTION_DATA (connection);  
1117
1118   _dbus_assert (d != NULL);  
1119   _dbus_assert (d->oom_message != NULL);
1120
1121   /* should always succeed since we set it to a placeholder earlier */
1122   if (!dbus_message_set_reply_serial (d->oom_message,
1123                                       dbus_message_get_serial (in_reply_to)))
1124     _dbus_assert_not_reached ("Failed to set reply serial for preallocated oom message");
1125
1126   _dbus_assert (dbus_message_get_sender (d->oom_message) != NULL);
1127   
1128   dbus_connection_send_preallocated (connection, d->oom_preallocated,
1129                                      d->oom_message, NULL);
1130
1131   dbus_message_unref (d->oom_message);
1132   d->oom_message = NULL;
1133   d->oom_preallocated = NULL;
1134 }
1135
1136 void
1137 bus_connection_add_match_rule_link (DBusConnection *connection,
1138                                     DBusList       *link)
1139 {
1140   BusConnectionData *d;
1141
1142   d = BUS_CONNECTION_DATA (connection);
1143   _dbus_assert (d != NULL);
1144
1145   _dbus_list_append_link (&d->match_rules, link);
1146
1147   d->n_match_rules += 1;
1148 }
1149
1150 dbus_bool_t
1151 bus_connection_add_match_rule (DBusConnection *connection,
1152                                BusMatchRule   *rule)
1153 {
1154     DBusList *link;
1155
1156   link = _dbus_list_alloc_link (rule);
1157
1158   if (link == NULL)
1159     return FALSE;
1160
1161   bus_connection_add_match_rule_link (connection, link);
1162
1163   return TRUE;
1164 }
1165
1166 void
1167 bus_connection_remove_match_rule (DBusConnection *connection,
1168                                   BusMatchRule   *rule)
1169 {
1170   BusConnectionData *d;
1171
1172   d = BUS_CONNECTION_DATA (connection);
1173   _dbus_assert (d != NULL);
1174
1175   _dbus_list_remove_last (&d->match_rules, rule);
1176
1177   d->n_match_rules -= 1;
1178   _dbus_assert (d->n_match_rules >= 0);
1179 }
1180
1181 int
1182 bus_connection_get_n_match_rules (DBusConnection *connection)
1183 {
1184   BusConnectionData *d;
1185
1186   d = BUS_CONNECTION_DATA (connection);
1187   _dbus_assert (d != NULL);
1188   
1189   return d->n_match_rules;
1190 }
1191
1192 void
1193 bus_connection_add_owned_service_link (DBusConnection *connection,
1194                                        DBusList       *link)
1195 {
1196   BusConnectionData *d;
1197
1198   d = BUS_CONNECTION_DATA (connection);
1199   _dbus_assert (d != NULL);
1200
1201   _dbus_list_append_link (&d->services_owned, link);
1202
1203   d->n_services_owned += 1;
1204 }
1205
1206 dbus_bool_t
1207 bus_connection_add_owned_service (DBusConnection *connection,
1208                                   BusService     *service)
1209 {
1210   DBusList *link;
1211
1212   link = _dbus_list_alloc_link (service);
1213
1214   if (link == NULL)
1215     return FALSE;
1216
1217   bus_connection_add_owned_service_link (connection, link);
1218
1219   return TRUE;
1220 }
1221
1222 void
1223 bus_connection_remove_owned_service (DBusConnection *connection,
1224                                      BusService     *service)
1225 {
1226   BusConnectionData *d;
1227
1228   d = BUS_CONNECTION_DATA (connection);
1229   _dbus_assert (d != NULL);
1230
1231   _dbus_list_remove_last (&d->services_owned, service);
1232
1233   d->n_services_owned -= 1;
1234   _dbus_assert (d->n_services_owned >= 0);
1235 }
1236
1237 int
1238 bus_connection_get_n_services_owned (DBusConnection *connection)
1239 {
1240   BusConnectionData *d;
1241
1242   d = BUS_CONNECTION_DATA (connection);
1243   _dbus_assert (d != NULL);
1244   
1245   return d->n_services_owned;
1246 }
1247
1248 dbus_bool_t
1249 bus_connection_complete (DBusConnection   *connection,
1250                          const DBusString *name,
1251                          DBusError        *error)
1252 {
1253   BusConnectionData *d;
1254   unsigned long uid;
1255   
1256   d = BUS_CONNECTION_DATA (connection);
1257   _dbus_assert (d != NULL);
1258   _dbus_assert (d->name == NULL);
1259   _dbus_assert (d->policy == NULL);
1260
1261   _dbus_assert (!bus_connection_is_active (connection));
1262   
1263   if (!_dbus_string_copy_data (name, &d->name))
1264     {
1265       BUS_SET_OOM (error);
1266       return FALSE;
1267     }
1268
1269   _dbus_assert (d->name != NULL);
1270   
1271   _dbus_verbose ("Name %s assigned to %p\n", d->name, connection);
1272
1273   d->policy = bus_context_create_client_policy (d->connections->context,
1274                                                 connection,
1275                                                 error);
1276
1277   /* we may have a NULL policy on OOM or error getting list of
1278    * groups for a user. In the latter case we don't handle it so
1279    * well currently, as it will just keep failing over and over.
1280    */
1281
1282   if (d->policy == NULL)
1283     {
1284       _dbus_verbose ("Failed to create security policy for connection %p\n",
1285                      connection);
1286       _DBUS_ASSERT_ERROR_IS_SET (error);
1287       dbus_free (d->name);
1288       d->name = NULL;
1289       return FALSE;
1290     }
1291   
1292   if (dbus_connection_get_unix_user (connection, &uid))
1293     {
1294       if (!adjust_connections_for_uid (d->connections,
1295                                        uid, 1))
1296         {
1297           BUS_SET_OOM (error);
1298           dbus_free (d->name);
1299           d->name = NULL;
1300           return FALSE;
1301         }
1302     }
1303   
1304   /* Now the connection is active, move it between lists */
1305   _dbus_list_unlink (&d->connections->incomplete,
1306                      d->link_in_connection_list);
1307   d->connections->n_incomplete -= 1;
1308   _dbus_list_append_link (&d->connections->completed,
1309                           d->link_in_connection_list);
1310   d->connections->n_completed += 1;
1311
1312   _dbus_assert (d->connections->n_incomplete >= 0);
1313   _dbus_assert (d->connections->n_completed > 0);
1314
1315   /* See if we can remove the timeout */
1316   bus_connections_expire_incomplete (d->connections);
1317
1318   _dbus_assert (bus_connection_is_active (connection));
1319   
1320   return TRUE;
1321 }
1322
1323 const char *
1324 bus_connection_get_name (DBusConnection *connection)
1325 {
1326   BusConnectionData *d;
1327   
1328   d = BUS_CONNECTION_DATA (connection);
1329   _dbus_assert (d != NULL);
1330   
1331   return d->name;
1332 }
1333
1334 /**
1335  * Check whether completing the passed-in connection would
1336  * exceed limits, and if so set error and return #FALSE
1337  */
1338 dbus_bool_t
1339 bus_connections_check_limits (BusConnections  *connections,
1340                               DBusConnection  *requesting_completion,
1341                               DBusError       *error)
1342 {
1343   BusConnectionData *d;
1344   unsigned long uid;
1345   
1346   d = BUS_CONNECTION_DATA (requesting_completion);
1347   _dbus_assert (d != NULL);
1348
1349   _dbus_assert (d->name == NULL);
1350
1351   if (connections->n_completed >=
1352       bus_context_get_max_completed_connections (connections->context))
1353     {
1354       dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
1355                       "The maximum number of active connections has been reached");
1356       return FALSE;
1357     }
1358   
1359   if (dbus_connection_get_unix_user (requesting_completion, &uid))
1360     {
1361       if (get_connections_for_uid (connections, uid) >=
1362           bus_context_get_max_connections_per_user (connections->context))
1363         {
1364           dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
1365                           "The maximum number of active connections for UID %lu has been reached",
1366                           uid);
1367           return FALSE;
1368         }
1369     }
1370   
1371   return TRUE;
1372 }
1373
1374 static void
1375 bus_pending_reply_free (BusPendingReply *pending)
1376 {
1377   _dbus_verbose ("Freeing pending reply %p, replier %p receiver %p serial %u\n",
1378                  pending,
1379                  pending->will_send_reply,
1380                  pending->will_get_reply,
1381                  pending->reply_serial);
1382
1383   dbus_free (pending);
1384 }
1385
1386 static dbus_bool_t
1387 bus_pending_reply_send_no_reply (BusConnections  *connections,
1388                                  BusTransaction  *transaction,
1389                                  BusPendingReply *pending)
1390 {
1391   DBusMessage *message;
1392   DBusMessageIter iter;
1393   dbus_bool_t retval;
1394   const char *errmsg;
1395
1396   retval = FALSE;
1397   
1398   message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR);
1399   if (message == NULL)
1400     return FALSE;
1401   
1402   dbus_message_set_no_reply (message, TRUE);
1403   
1404   if (!dbus_message_set_reply_serial (message,
1405                                       pending->reply_serial))
1406     goto out;
1407
1408   if (!dbus_message_set_error_name (message,
1409                                     DBUS_ERROR_NO_REPLY))
1410     goto out;
1411
1412   errmsg = "Message did not receive a reply (timeout by message bus)";
1413   dbus_message_iter_init_append (message, &iter);
1414   if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &errmsg))
1415     goto out;
1416     
1417   if (!bus_transaction_send_from_driver (transaction, pending->will_get_reply,
1418                                          message))
1419     goto out;
1420
1421   retval = TRUE;
1422
1423  out:
1424   dbus_message_unref (message);
1425   return retval;
1426 }
1427
1428 static dbus_bool_t
1429 bus_pending_reply_expired (BusExpireList *list,
1430                            DBusList      *link,
1431                            void          *data)
1432 {
1433   BusPendingReply *pending = link->data;
1434   BusConnections *connections = data;
1435   BusTransaction *transaction;
1436   
1437   /* No reply is forthcoming. So nuke it if we can. If not,
1438    * leave it in the list to try expiring again later when we
1439    * get more memory.
1440    */
1441
1442   _dbus_verbose ("Expiring pending reply %p, replier %p receiver %p serial %u\n",
1443                  pending,
1444                  pending->will_send_reply,
1445                  pending->will_get_reply,
1446                  pending->reply_serial);
1447   
1448   transaction = bus_transaction_new (connections->context);
1449   if (transaction == NULL)
1450     return FALSE;
1451   
1452   if (!bus_pending_reply_send_no_reply (connections,
1453                                         transaction,
1454                                         pending))
1455     {
1456       bus_transaction_cancel_and_free (transaction);
1457       return FALSE;
1458     }
1459   
1460   _dbus_list_remove_link (&connections->pending_replies->items,
1461                           link);
1462   bus_pending_reply_free (pending);
1463   bus_transaction_execute_and_free (transaction);
1464
1465   return TRUE;
1466 }
1467
1468 static void
1469 bus_connection_drop_pending_replies (BusConnections  *connections,
1470                                      DBusConnection  *connection)
1471 {
1472   /* The DBusConnection is almost 100% finalized here, so you can't
1473    * do anything with it except check for pointer equality
1474    */
1475   DBusList *link;
1476
1477   _dbus_verbose ("Dropping pending replies that involve connection %p\n",
1478                  connection);
1479   
1480   link = _dbus_list_get_first_link (&connections->pending_replies->items);
1481   while (link != NULL)
1482     {
1483       DBusList *next;
1484       BusPendingReply *pending;
1485
1486       next = _dbus_list_get_next_link (&connections->pending_replies->items,
1487                                        link);
1488       pending = link->data;
1489
1490       if (pending->will_get_reply == connection)
1491         {
1492           /* We don't need to track this pending reply anymore */
1493
1494           _dbus_verbose ("Dropping pending reply %p, replier %p receiver %p serial %u\n",
1495                          pending,
1496                          pending->will_send_reply,
1497                          pending->will_get_reply,
1498                          pending->reply_serial);
1499           
1500           _dbus_list_remove_link (&connections->pending_replies->items,
1501                                   link);
1502           bus_pending_reply_free (pending);
1503         }
1504       else if (pending->will_send_reply == connection)
1505         {
1506           /* The reply isn't going to be sent, so set things
1507            * up so it will be expired right away
1508            */
1509           _dbus_verbose ("Will expire pending reply %p, replier %p receiver %p serial %u\n",
1510                          pending,
1511                          pending->will_send_reply,
1512                          pending->will_get_reply,
1513                          pending->reply_serial);
1514           
1515           pending->will_send_reply = NULL;
1516           pending->expire_item.added_tv_sec = 0;
1517           pending->expire_item.added_tv_usec = 0;
1518
1519           bus_expire_timeout_set_interval (connections->pending_replies->timeout,
1520                                            0);
1521         }
1522       
1523       link = next;
1524     }
1525 }
1526
1527
1528 typedef struct
1529 {
1530   BusPendingReply *pending;
1531   BusConnections  *connections;
1532 } CancelPendingReplyData;
1533
1534 static void
1535 cancel_pending_reply (void *data)
1536 {
1537   CancelPendingReplyData *d = data;
1538
1539   _dbus_verbose ("%s: d = %p\n", _DBUS_FUNCTION_NAME, d);
1540   
1541   if (!_dbus_list_remove (&d->connections->pending_replies->items,
1542                           d->pending))
1543     _dbus_assert_not_reached ("pending reply did not exist to be cancelled");
1544
1545   bus_pending_reply_free (d->pending); /* since it's been cancelled */
1546 }
1547
1548 static void
1549 cancel_pending_reply_data_free (void *data)
1550 {
1551   CancelPendingReplyData *d = data;
1552
1553   _dbus_verbose ("%s: d = %p\n", _DBUS_FUNCTION_NAME, d);
1554   
1555   /* d->pending should be either freed or still
1556    * in the list of pending replies (owned by someone
1557    * else)
1558    */
1559   
1560   dbus_free (d);
1561 }
1562
1563 /*
1564  * Record that a reply is allowed; return TRUE on success.
1565  */
1566 dbus_bool_t
1567 bus_connections_expect_reply (BusConnections  *connections,
1568                               BusTransaction  *transaction,
1569                               DBusConnection  *will_get_reply,
1570                               DBusConnection  *will_send_reply,
1571                               DBusMessage     *reply_to_this,
1572                               DBusError       *error)
1573 {
1574   BusPendingReply *pending;
1575   dbus_uint32_t reply_serial;
1576   DBusList *link;
1577   CancelPendingReplyData *cprd;
1578   int count;
1579
1580   _dbus_assert (will_get_reply != NULL);
1581   _dbus_assert (will_send_reply != NULL);
1582   _dbus_assert (reply_to_this != NULL);
1583   
1584   if (dbus_message_get_no_reply (reply_to_this))
1585     return TRUE; /* we won't allow a reply, since client doesn't care for one. */
1586   
1587   reply_serial = dbus_message_get_serial (reply_to_this);
1588
1589   link = _dbus_list_get_first_link (&connections->pending_replies->items);
1590   count = 0;
1591   while (link != NULL)
1592     {
1593       pending = link->data;
1594
1595       if (pending->reply_serial == reply_serial &&
1596           pending->will_get_reply == will_get_reply &&
1597           pending->will_send_reply == will_send_reply)
1598         {
1599           dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
1600                           "Message has the same reply serial as a currently-outstanding existing method call");
1601           return FALSE;
1602         }
1603       
1604       link = _dbus_list_get_next_link (&connections->pending_replies->items,
1605                                        link);
1606       if (pending->will_get_reply == will_get_reply)
1607         ++count;
1608     }
1609   
1610   if (count >=
1611       bus_context_get_max_replies_per_connection (connections->context))
1612     {
1613       dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
1614                       "The maximum number of pending replies per connection has been reached");
1615       return FALSE;
1616     }
1617
1618   pending = dbus_new0 (BusPendingReply, 1);
1619   if (pending == NULL)
1620     {
1621       BUS_SET_OOM (error);
1622       return FALSE;
1623     }
1624
1625 #ifdef DBUS_ENABLE_VERBOSE_MODE
1626   /* so we can see a not-yet-added pending reply */
1627   pending->expire_item.added_tv_sec = 1;
1628   pending->expire_item.added_tv_usec = 1;
1629 #endif
1630
1631   pending->will_get_reply = will_get_reply;
1632   pending->will_send_reply = will_send_reply;
1633   pending->reply_serial = reply_serial;
1634   
1635   cprd = dbus_new0 (CancelPendingReplyData, 1);
1636   if (cprd == NULL)
1637     {
1638       BUS_SET_OOM (error);
1639       bus_pending_reply_free (pending);
1640       return FALSE;
1641     }
1642   
1643   if (!_dbus_list_prepend (&connections->pending_replies->items,
1644                            pending))
1645     {
1646       BUS_SET_OOM (error);
1647       dbus_free (cprd);
1648       bus_pending_reply_free (pending);
1649       return FALSE;
1650     }
1651
1652   if (!bus_transaction_add_cancel_hook (transaction,
1653                                         cancel_pending_reply,
1654                                         cprd,
1655                                         cancel_pending_reply_data_free))
1656     {
1657       BUS_SET_OOM (error);
1658       _dbus_list_remove (&connections->pending_replies->items, pending);
1659       dbus_free (cprd);
1660       bus_pending_reply_free (pending);
1661       return FALSE;
1662     }
1663                                         
1664   cprd->pending = pending;
1665   cprd->connections = connections;
1666   
1667   _dbus_get_current_time (&pending->expire_item.added_tv_sec,
1668                           &pending->expire_item.added_tv_usec);
1669
1670   _dbus_verbose ("Added pending reply %p, replier %p receiver %p serial %u\n",
1671                  pending,
1672                  pending->will_send_reply,
1673                  pending->will_get_reply,
1674                  pending->reply_serial);
1675   
1676   return TRUE;
1677 }
1678
1679 typedef struct
1680 {
1681   DBusList        *link;
1682   BusConnections  *connections;
1683 } CheckPendingReplyData;
1684
1685 static void
1686 cancel_check_pending_reply (void *data)
1687 {
1688   CheckPendingReplyData *d = data;
1689
1690   _dbus_verbose ("%s: d = %p\n", _DBUS_FUNCTION_NAME, d);
1691   
1692   _dbus_list_prepend_link (&d->connections->pending_replies->items,
1693                            d->link);
1694   d->link = NULL;
1695 }
1696
1697 static void
1698 check_pending_reply_data_free (void *data)
1699 {
1700   CheckPendingReplyData *d = data;
1701
1702   _dbus_verbose ("%s: d = %p\n", _DBUS_FUNCTION_NAME, d);
1703   
1704   if (d->link != NULL)
1705     {
1706       BusPendingReply *pending = d->link->data;
1707       
1708       _dbus_assert (_dbus_list_find_last (&d->connections->pending_replies->items,
1709                                           pending) == NULL);
1710       
1711       bus_pending_reply_free (pending);
1712       _dbus_list_free_link (d->link);
1713     }
1714   
1715   dbus_free (d);
1716 }
1717
1718 /*
1719  * Check whether a reply is allowed, remove BusPendingReply
1720  * if so, return TRUE if so.
1721  */
1722 dbus_bool_t
1723 bus_connections_check_reply (BusConnections *connections,
1724                              BusTransaction *transaction,
1725                              DBusConnection *sending_reply,
1726                              DBusConnection *receiving_reply,
1727                              DBusMessage    *reply,
1728                              DBusError      *error)
1729 {
1730   CheckPendingReplyData *cprd;
1731   DBusList *link;
1732   dbus_uint32_t reply_serial;
1733   
1734   _dbus_assert (sending_reply != NULL);
1735   _dbus_assert (receiving_reply != NULL);
1736
1737   reply_serial = dbus_message_get_reply_serial (reply);
1738
1739   link = _dbus_list_get_first_link (&connections->pending_replies->items);
1740   while (link != NULL)
1741     {
1742       BusPendingReply *pending = link->data;
1743
1744       if (pending->reply_serial == reply_serial &&
1745           pending->will_get_reply == receiving_reply &&
1746           pending->will_send_reply == sending_reply)
1747         {
1748           _dbus_verbose ("Found pending reply with serial %u\n", reply_serial);
1749           break;
1750         }
1751       
1752       link = _dbus_list_get_next_link (&connections->pending_replies->items,
1753                                        link);
1754     }
1755
1756   if (link == NULL)
1757     {
1758       _dbus_verbose ("No pending reply expected\n");
1759
1760       return FALSE;
1761     }
1762
1763   cprd = dbus_new0 (CheckPendingReplyData, 1);
1764   if (cprd == NULL)
1765     {
1766       BUS_SET_OOM (error);
1767       return FALSE;
1768     }
1769   
1770   if (!bus_transaction_add_cancel_hook (transaction,
1771                                         cancel_check_pending_reply,
1772                                         cprd,
1773                                         check_pending_reply_data_free))
1774     {
1775       BUS_SET_OOM (error);
1776       dbus_free (cprd);
1777       return FALSE;
1778     }
1779
1780   cprd->link = link;
1781   cprd->connections = connections;
1782   
1783   _dbus_list_unlink (&connections->pending_replies->items,
1784                      link);
1785   
1786   _dbus_assert (_dbus_list_find_last (&connections->pending_replies->items,
1787                                       link->data) == NULL);
1788
1789   return TRUE;
1790 }
1791
1792 /*
1793  * Transactions
1794  *
1795  * Note that this is fairly fragile; in particular, don't try to use
1796  * one transaction across any main loop iterations.
1797  */
1798
1799 typedef struct
1800 {
1801   BusTransaction *transaction;
1802   DBusMessage    *message;
1803   DBusPreallocatedSend *preallocated;
1804 } MessageToSend;
1805
1806 typedef struct
1807 {
1808   BusTransactionCancelFunction cancel_function;
1809   DBusFreeFunction free_data_function;
1810   void *data;
1811 } CancelHook;
1812
1813 struct BusTransaction
1814 {
1815   DBusList *connections;
1816   BusContext *context;
1817   DBusList *cancel_hooks;
1818 };
1819
1820 static void
1821 message_to_send_free (DBusConnection *connection,
1822                       MessageToSend  *to_send)
1823 {
1824   if (to_send->message)
1825     dbus_message_unref (to_send->message);
1826
1827   if (to_send->preallocated)
1828     dbus_connection_free_preallocated_send (connection, to_send->preallocated);
1829
1830   dbus_free (to_send);
1831 }
1832
1833 static void
1834 cancel_hook_cancel (void *element,
1835                     void *data)
1836 {
1837   CancelHook *ch = element;
1838
1839   _dbus_verbose ("Running transaction cancel hook\n");
1840   
1841   if (ch->cancel_function)
1842     (* ch->cancel_function) (ch->data);  
1843 }
1844
1845 static void
1846 cancel_hook_free (void *element,
1847                   void *data)
1848 {
1849   CancelHook *ch = element;
1850
1851   if (ch->free_data_function)
1852     (* ch->free_data_function) (ch->data);
1853
1854   dbus_free (ch);
1855 }
1856
1857 static void
1858 free_cancel_hooks (BusTransaction *transaction)
1859 {
1860   _dbus_list_foreach (&transaction->cancel_hooks,
1861                       cancel_hook_free, NULL);
1862   
1863   _dbus_list_clear (&transaction->cancel_hooks);
1864 }
1865
1866 BusTransaction*
1867 bus_transaction_new (BusContext *context)
1868 {
1869   BusTransaction *transaction;
1870
1871   transaction = dbus_new0 (BusTransaction, 1);
1872   if (transaction == NULL)
1873     return NULL;
1874
1875   transaction->context = context;
1876   
1877   return transaction;
1878 }
1879
1880 BusContext*
1881 bus_transaction_get_context (BusTransaction  *transaction)
1882 {
1883   return transaction->context;
1884 }
1885
1886 BusConnections*
1887 bus_transaction_get_connections (BusTransaction  *transaction)
1888 {
1889   return bus_context_get_connections (transaction->context);
1890 }
1891
1892 dbus_bool_t
1893 bus_transaction_send_from_driver (BusTransaction *transaction,
1894                                   DBusConnection *connection,
1895                                   DBusMessage    *message)
1896 {
1897   /* We have to set the sender to the driver, and have
1898    * to check security policy since it was not done in
1899    * dispatch.c
1900    */
1901   _dbus_verbose ("Sending %s %s %s from driver\n",
1902                  dbus_message_get_interface (message) ?
1903                  dbus_message_get_interface (message) : "(no interface)",
1904                  dbus_message_get_member (message) ?
1905                  dbus_message_get_member (message) : "(no member)",
1906                  dbus_message_get_error_name (message) ?
1907                  dbus_message_get_error_name (message) : "(no error name)");
1908                  
1909   if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
1910     return FALSE;
1911
1912   if (bus_connection_is_active (connection))
1913     {
1914       if (!dbus_message_set_destination (message,
1915                                          bus_connection_get_name (connection)))
1916         return FALSE;
1917     }
1918   
1919   /* bus driver never wants a reply */
1920   dbus_message_set_no_reply (message, TRUE);
1921   
1922   /* If security policy doesn't allow the message, we silently
1923    * eat it; the driver doesn't care about getting a reply.
1924    */
1925   if (!bus_context_check_security_policy (bus_transaction_get_context (transaction),
1926                                           transaction,
1927                                           NULL, connection, connection, message, NULL))
1928     return TRUE;
1929
1930   return bus_transaction_send (transaction, connection, message);
1931 }
1932
1933 dbus_bool_t
1934 bus_transaction_send (BusTransaction *transaction,
1935                       DBusConnection *connection,
1936                       DBusMessage    *message)
1937 {
1938   MessageToSend *to_send;
1939   BusConnectionData *d;
1940   DBusList *link;
1941
1942   _dbus_verbose ("  trying to add %s interface=%s member=%s error=%s to transaction%s\n",
1943                  dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ? "error" :
1944                  dbus_message_get_reply_serial (message) != 0 ? "reply" :
1945                  "message",
1946                  dbus_message_get_interface (message) ?
1947                  dbus_message_get_interface (message) : "(unset)",
1948                  dbus_message_get_member (message) ?
1949                  dbus_message_get_member (message) : "(unset)",
1950                  dbus_message_get_error_name (message) ?
1951                  dbus_message_get_error_name (message) : "(unset)",
1952                  dbus_connection_get_is_connected (connection) ?
1953                  "" : " (disconnected)");
1954
1955   _dbus_assert (dbus_message_get_sender (message) != NULL);
1956   
1957   if (!dbus_connection_get_is_connected (connection))
1958     return TRUE; /* silently ignore disconnected connections */
1959   
1960   d = BUS_CONNECTION_DATA (connection);
1961   _dbus_assert (d != NULL);
1962   
1963   to_send = dbus_new (MessageToSend, 1);
1964   if (to_send == NULL)
1965     {
1966       return FALSE;
1967     }
1968
1969   to_send->preallocated = dbus_connection_preallocate_send (connection);
1970   if (to_send->preallocated == NULL)
1971     {
1972       dbus_free (to_send);
1973       return FALSE;
1974     }  
1975   
1976   dbus_message_ref (message);
1977   to_send->message = message;
1978   to_send->transaction = transaction;
1979
1980   _dbus_verbose ("about to prepend message\n");
1981   
1982   if (!_dbus_list_prepend (&d->transaction_messages, to_send))
1983     {
1984       message_to_send_free (connection, to_send);
1985       return FALSE;
1986     }
1987
1988   _dbus_verbose ("prepended message\n");
1989   
1990   /* See if we already had this connection in the list
1991    * for this transaction. If we have a pending message,
1992    * then we should already be in transaction->connections
1993    */
1994   link = _dbus_list_get_first_link (&d->transaction_messages);
1995   _dbus_assert (link->data == to_send);
1996   link = _dbus_list_get_next_link (&d->transaction_messages, link);
1997   while (link != NULL)
1998     {
1999       MessageToSend *m = link->data;
2000       DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link);
2001       
2002       if (m->transaction == transaction)
2003         break;
2004         
2005       link = next;
2006     }
2007
2008   if (link == NULL)
2009     {
2010       if (!_dbus_list_prepend (&transaction->connections, connection))
2011         {
2012           _dbus_list_remove (&d->transaction_messages, to_send);
2013           message_to_send_free (connection, to_send);
2014           return FALSE;
2015         }
2016     }
2017
2018   return TRUE;
2019 }
2020
2021 static void
2022 connection_cancel_transaction (DBusConnection *connection,
2023                                BusTransaction *transaction)
2024 {
2025   DBusList *link;
2026   BusConnectionData *d;
2027   
2028   d = BUS_CONNECTION_DATA (connection);
2029   _dbus_assert (d != NULL);
2030   
2031   link = _dbus_list_get_first_link (&d->transaction_messages);
2032   while (link != NULL)
2033     {
2034       MessageToSend *m = link->data;
2035       DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link);
2036       
2037       if (m->transaction == transaction)
2038         {
2039           _dbus_list_remove_link (&d->transaction_messages,
2040                                   link);
2041           
2042           message_to_send_free (connection, m);
2043         }
2044         
2045       link = next;
2046     }
2047 }
2048
2049 void
2050 bus_transaction_cancel_and_free (BusTransaction *transaction)
2051 {
2052   DBusConnection *connection;
2053
2054   _dbus_verbose ("TRANSACTION: cancelled\n");
2055   
2056   while ((connection = _dbus_list_pop_first (&transaction->connections)))
2057     connection_cancel_transaction (connection, transaction);
2058
2059   _dbus_assert (transaction->connections == NULL);
2060
2061   _dbus_list_foreach (&transaction->cancel_hooks,
2062                       cancel_hook_cancel, NULL);
2063
2064   free_cancel_hooks (transaction);
2065   
2066   dbus_free (transaction);
2067 }
2068
2069 static void
2070 connection_execute_transaction (DBusConnection *connection,
2071                                 BusTransaction *transaction)
2072 {
2073   DBusList *link;
2074   BusConnectionData *d;
2075   
2076   d = BUS_CONNECTION_DATA (connection);
2077   _dbus_assert (d != NULL);
2078
2079   /* Send the queue in order (FIFO) */
2080   link = _dbus_list_get_last_link (&d->transaction_messages);
2081   while (link != NULL)
2082     {
2083       MessageToSend *m = link->data;
2084       DBusList *prev = _dbus_list_get_prev_link (&d->transaction_messages, link);
2085       
2086       if (m->transaction == transaction)
2087         {
2088           _dbus_list_remove_link (&d->transaction_messages,
2089                                   link);
2090
2091           _dbus_assert (dbus_message_get_sender (m->message) != NULL);
2092           
2093           dbus_connection_send_preallocated (connection,
2094                                              m->preallocated,
2095                                              m->message,
2096                                              NULL);
2097
2098           m->preallocated = NULL; /* so we don't double-free it */
2099           
2100           message_to_send_free (connection, m);
2101         }
2102         
2103       link = prev;
2104     }
2105 }
2106
2107 void
2108 bus_transaction_execute_and_free (BusTransaction *transaction)
2109 {
2110   /* For each connection in transaction->connections
2111    * send the messages
2112    */
2113   DBusConnection *connection;
2114
2115   _dbus_verbose ("TRANSACTION: executing\n");
2116   
2117   while ((connection = _dbus_list_pop_first (&transaction->connections)))
2118     connection_execute_transaction (connection, transaction);
2119
2120   _dbus_assert (transaction->connections == NULL);
2121
2122   free_cancel_hooks (transaction);
2123   
2124   dbus_free (transaction);
2125 }
2126
2127 static void
2128 bus_connection_remove_transactions (DBusConnection *connection)
2129 {
2130   MessageToSend *to_send;
2131   BusConnectionData *d;
2132   
2133   d = BUS_CONNECTION_DATA (connection);
2134   _dbus_assert (d != NULL);
2135   
2136   while ((to_send = _dbus_list_get_first (&d->transaction_messages)))
2137     {
2138       /* only has an effect for the first MessageToSend listing this transaction */
2139       _dbus_list_remove (&to_send->transaction->connections,
2140                          connection);
2141
2142       _dbus_list_remove (&d->transaction_messages, to_send);
2143       message_to_send_free (connection, to_send);
2144     }
2145 }
2146
2147 /**
2148  * Converts the DBusError to a message reply
2149  */
2150 dbus_bool_t
2151 bus_transaction_send_error_reply (BusTransaction  *transaction,
2152                                   DBusConnection  *connection,
2153                                   const DBusError *error,
2154                                   DBusMessage     *in_reply_to)
2155 {
2156   DBusMessage *reply;
2157   
2158   _dbus_assert (error != NULL);
2159   _DBUS_ASSERT_ERROR_IS_SET (error);
2160   
2161   _dbus_verbose ("Sending error reply %s \"%s\"\n",
2162                  error->name, error->message);
2163
2164   reply = dbus_message_new_error (in_reply_to,
2165                                   error->name,
2166                                   error->message);
2167   if (reply == NULL)
2168     return FALSE;
2169
2170   if (!bus_transaction_send_from_driver (transaction, connection, reply))
2171     {
2172       dbus_message_unref (reply);
2173       return FALSE;
2174     }
2175
2176   dbus_message_unref (reply);
2177   
2178   return TRUE;
2179 }
2180
2181 dbus_bool_t
2182 bus_transaction_add_cancel_hook (BusTransaction               *transaction,
2183                                  BusTransactionCancelFunction  cancel_function,
2184                                  void                         *data,
2185                                  DBusFreeFunction              free_data_function)
2186 {
2187   CancelHook *ch;
2188
2189   ch = dbus_new (CancelHook, 1);
2190   if (ch == NULL)
2191     return FALSE;
2192
2193   _dbus_verbose ("     adding cancel hook function = %p data = %p\n",
2194                  cancel_function, data);
2195   
2196   ch->cancel_function = cancel_function;
2197   ch->data = data;
2198   ch->free_data_function = free_data_function;
2199
2200   /* It's important that the hooks get run in reverse order that they
2201    * were added
2202    */
2203   if (!_dbus_list_prepend (&transaction->cancel_hooks, ch))
2204     {
2205       dbus_free (ch);
2206       return FALSE;
2207     }
2208
2209   return TRUE;
2210 }