2003-05-11 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 "policy.h"
26 #include "services.h"
27 #include "utils.h"
28 #include <dbus/dbus-list.h>
29 #include <dbus/dbus-hash.h>
30 #include <dbus/dbus-timeout.h>
31
32 static void bus_connection_remove_transactions (DBusConnection *connection);
33
34 struct BusConnections
35 {
36   int refcount;
37   DBusList *completed;  /**< List of all completed connections */
38   int n_completed;      /**< Length of completed list */
39   DBusList *incomplete; /**< List of all not-yet-active connections */
40   int n_incomplete;     /**< Length of incomplete list */
41   BusContext *context;
42   DBusHashTable *completed_by_user; /**< Number of completed connections for each UID */
43   DBusTimeout *expire_timeout; /**< Timeout for expiring incomplete connections. */
44 };
45
46 static int connection_data_slot = -1;
47 static int connection_data_slot_refcount = 0;
48
49 typedef struct
50 {
51   BusConnections *connections;
52   DBusList *link_in_connection_list;
53   DBusConnection *connection;
54   DBusList *services_owned;
55   int n_services_owned;
56   char *name;
57   DBusList *transaction_messages; /**< Stuff we need to send as part of a transaction */
58   DBusMessage *oom_message;
59   DBusPreallocatedSend *oom_preallocated;
60   BusClientPolicy *policy;
61
62   long connection_tv_sec;  /**< Time when we connected (seconds component) */
63   long connection_tv_usec; /**< Time when we connected (microsec component) */
64 } BusConnectionData;
65
66 static dbus_bool_t expire_incomplete_timeout (void *data);
67
68 #define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot))
69
70 static dbus_bool_t
71 connection_data_slot_ref (void)
72 {
73   if (connection_data_slot < 0)
74     {
75       connection_data_slot = dbus_connection_allocate_data_slot ();
76       
77       if (connection_data_slot < 0)
78         return FALSE;
79
80       _dbus_assert (connection_data_slot_refcount == 0);
81     }  
82
83   connection_data_slot_refcount += 1;
84
85   return TRUE;
86
87 }
88
89 static void
90 connection_data_slot_unref (void)
91 {
92   _dbus_assert (connection_data_slot_refcount > 0);
93
94   connection_data_slot_refcount -= 1;
95   
96   if (connection_data_slot_refcount == 0)
97     {
98       dbus_connection_free_data_slot (connection_data_slot);
99       connection_data_slot = -1;
100     }
101 }
102
103 static DBusLoop*
104 connection_get_loop (DBusConnection *connection)
105 {
106   BusConnectionData *d;
107
108   d = BUS_CONNECTION_DATA (connection);
109
110   return bus_context_get_loop (d->connections->context);
111 }
112
113
114 static int
115 get_connections_for_uid (BusConnections *connections,
116                          dbus_uid_t      uid)
117 {
118   void *val;
119   int current_count;
120
121   /* val is NULL is 0 when it isn't in the hash yet */
122   
123   val = _dbus_hash_table_lookup_ulong (connections->completed_by_user,
124                                        uid);
125
126   current_count = _DBUS_POINTER_TO_INT (val);
127
128   return current_count;
129 }
130
131 static dbus_bool_t
132 adjust_connections_for_uid (BusConnections *connections,
133                             dbus_uid_t      uid,
134                             int             adjustment)
135 {
136   int current_count;
137
138   current_count = get_connections_for_uid (connections, uid);
139
140   _dbus_verbose ("Adjusting connection count for UID " DBUS_UID_FORMAT
141                  ": was %d adjustment %d making %d\n",
142                  uid, current_count, adjustment, current_count + adjustment);
143   
144   _dbus_assert (current_count >= 0);
145   
146   current_count += adjustment;
147
148   _dbus_assert (current_count >= 0);
149
150   if (current_count == 0)
151     {
152       _dbus_hash_table_remove_ulong (connections->completed_by_user, uid);
153       return TRUE;
154     }
155   else
156     {
157       dbus_bool_t retval;
158       
159       retval = _dbus_hash_table_insert_ulong (connections->completed_by_user,
160                                               uid, _DBUS_INT_TO_POINTER (current_count));
161
162       /* only positive adjustment can fail as otherwise
163        * a hash entry should already exist
164        */
165       _dbus_assert (adjustment > 0 ||
166                     (adjustment <= 0 && retval));
167
168       return retval;
169     }
170 }
171
172 void
173 bus_connection_disconnected (DBusConnection *connection)
174 {
175   BusConnectionData *d;
176   BusService *service;
177
178   d = BUS_CONNECTION_DATA (connection);
179   _dbus_assert (d != NULL);
180
181   _dbus_verbose ("%s disconnected, dropping all service ownership and releasing\n",
182                  d->name ? d->name : "(inactive)");
183   
184   /* Drop any service ownership. FIXME Unfortunately, this requires
185    * memory allocation and there doesn't seem to be a good way to
186    * handle it other than sleeping; we can't "fail" the operation of
187    * disconnecting a client, and preallocating a broadcast "service is
188    * now gone" message for every client-service pair seems kind of
189    * involved. Probably we need to do that though.
190    */
191   while ((service = _dbus_list_get_last (&d->services_owned)))
192     {
193       BusTransaction *transaction;
194       DBusError error;
195
196     retry:
197       
198       dbus_error_init (&error);
199         
200       transaction = NULL;
201       while (transaction == NULL)
202         {
203           transaction = bus_transaction_new (d->connections->context);
204           _dbus_wait_for_memory ();
205         }
206         
207       if (!bus_service_remove_owner (service, connection,
208                                      transaction, &error))
209         {
210           _DBUS_ASSERT_ERROR_IS_SET (&error);
211           
212           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
213             {
214               dbus_error_free (&error);
215               bus_transaction_cancel_and_free (transaction);
216               _dbus_wait_for_memory ();
217               goto retry;
218             }
219           else
220             {
221               _dbus_verbose ("Failed to remove service owner: %s %s\n",
222                              error.name, error.message);
223               _dbus_assert_not_reached ("Removing service owner failed for non-memory-related reason");
224             }
225         }
226         
227       bus_transaction_execute_and_free (transaction);
228     }
229
230   bus_dispatch_remove_connection (connection);
231   
232   /* no more watching */
233   if (!dbus_connection_set_watch_functions (connection,
234                                             NULL, NULL, NULL,
235                                             connection,
236                                             NULL))
237     _dbus_assert_not_reached ("setting watch functions to NULL failed");
238
239   if (!dbus_connection_set_timeout_functions (connection,
240                                               NULL, NULL, NULL,
241                                               connection,
242                                               NULL))
243     _dbus_assert_not_reached ("setting timeout functions to NULL failed");
244   
245   dbus_connection_set_unix_user_function (connection,
246                                           NULL, NULL, NULL);
247
248   dbus_connection_set_dispatch_status_function (connection,
249                                                 NULL, NULL, NULL);
250   
251   bus_connection_remove_transactions (connection);
252
253   if (d->link_in_connection_list != NULL)
254     {
255       if (d->name != NULL)
256         {
257           unsigned long uid;
258           
259           _dbus_list_remove_link (&d->connections->completed, d->link_in_connection_list);
260           d->link_in_connection_list = NULL;
261           d->connections->n_completed -= 1;
262
263           if (dbus_connection_get_unix_user (connection, &uid))
264             {
265               if (!adjust_connections_for_uid (d->connections,
266                                                uid, -1))
267                 _dbus_assert_not_reached ("adjusting downward should never fail");
268             }
269         }
270       else
271         {
272           _dbus_list_remove_link (&d->connections->incomplete, d->link_in_connection_list);
273           d->link_in_connection_list = NULL;
274           d->connections->n_incomplete -= 1;
275         }
276       
277       _dbus_assert (d->connections->n_incomplete >= 0);
278       _dbus_assert (d->connections->n_completed >= 0);
279     }
280   
281   /* frees "d" as side effect */
282   dbus_connection_set_data (connection,
283                             connection_data_slot,
284                             NULL, NULL);
285
286   dbus_connection_unref (connection);
287 }
288
289 static dbus_bool_t
290 connection_watch_callback (DBusWatch     *watch,
291                            unsigned int   condition,
292                            void          *data)
293 {
294  /* FIXME this can be done in dbus-mainloop.c
295   * if the code in activation.c for the babysitter
296   * watch handler is fixed.
297   */
298   
299 #if 0
300   _dbus_verbose ("Calling handle_watch\n");
301 #endif
302   return dbus_watch_handle (watch, condition);
303 }
304
305 static dbus_bool_t
306 add_connection_watch (DBusWatch      *watch,
307                       void           *data)
308 {
309   DBusConnection *connection = data;
310
311   return _dbus_loop_add_watch (connection_get_loop (connection),
312                                watch, connection_watch_callback, connection,
313                                NULL);
314 }
315
316 static void
317 remove_connection_watch (DBusWatch      *watch,
318                          void           *data)
319 {
320   DBusConnection *connection = data;
321   
322   _dbus_loop_remove_watch (connection_get_loop (connection),
323                            watch, connection_watch_callback, connection);
324 }
325
326 static void
327 connection_timeout_callback (DBusTimeout   *timeout,
328                              void          *data)
329 {
330   /* DBusConnection *connection = data; */
331
332   /* can return FALSE on OOM but we just let it fire again later */
333   dbus_timeout_handle (timeout);
334 }
335
336 static dbus_bool_t
337 add_connection_timeout (DBusTimeout    *timeout,
338                         void           *data)
339 {
340   DBusConnection *connection = data;
341   
342   return _dbus_loop_add_timeout (connection_get_loop (connection),
343                                  timeout, connection_timeout_callback, connection, NULL);
344 }
345
346 static void
347 remove_connection_timeout (DBusTimeout    *timeout,
348                            void           *data)
349 {
350   DBusConnection *connection = data;
351   
352   _dbus_loop_remove_timeout (connection_get_loop (connection),
353                              timeout, connection_timeout_callback, connection);
354 }
355
356 static void
357 dispatch_status_function (DBusConnection    *connection,
358                           DBusDispatchStatus new_status,
359                           void              *data)
360 {
361   DBusLoop *loop = data;
362   
363   if (new_status != DBUS_DISPATCH_COMPLETE)
364     {
365       while (!_dbus_loop_queue_dispatch (loop, connection))
366         _dbus_wait_for_memory ();
367     }
368 }
369
370 static dbus_bool_t
371 allow_user_function (DBusConnection *connection,
372                      unsigned long   uid,
373                      void           *data)
374 {
375   BusConnectionData *d;
376     
377   d = BUS_CONNECTION_DATA (connection);
378
379   _dbus_assert (d != NULL);
380   
381   return bus_context_allow_user (d->connections->context, uid);
382 }
383
384 static void
385 free_connection_data (void *data)
386 {
387   BusConnectionData *d = data;
388
389   /* services_owned should be NULL since we should be disconnected */
390   _dbus_assert (d->services_owned == NULL);
391   _dbus_assert (d->n_services_owned == 0);
392   /* similarly */
393   _dbus_assert (d->transaction_messages == NULL);
394
395   if (d->oom_preallocated)
396     dbus_connection_free_preallocated_send (d->connection, d->oom_preallocated);
397
398   if (d->oom_message)
399     dbus_message_unref (d->oom_message);
400
401   if (d->policy)
402     bus_client_policy_unref (d->policy);
403   
404   dbus_free (d->name);
405   
406   dbus_free (d);
407 }
408
409 static void
410 call_timeout_callback (DBusTimeout   *timeout,
411                        void          *data)
412 {
413   /* can return FALSE on OOM but we just let it fire again later */
414   dbus_timeout_handle (timeout);
415 }
416
417 BusConnections*
418 bus_connections_new (BusContext *context)
419 {
420   BusConnections *connections;
421
422   if (!connection_data_slot_ref ())
423     goto failed_0;
424
425   connections = dbus_new0 (BusConnections, 1);
426   if (connections == NULL)
427     goto failed_1;
428
429   connections->completed_by_user = _dbus_hash_table_new (DBUS_HASH_ULONG,
430                                                          NULL, NULL);
431   if (connections->completed_by_user == NULL)
432     goto failed_2;
433
434   connections->expire_timeout = _dbus_timeout_new (100, /* irrelevant */
435                                                    expire_incomplete_timeout,
436                                                    connections, NULL);
437   if (connections->expire_timeout == NULL)
438     goto failed_3;
439
440   _dbus_timeout_set_enabled (connections->expire_timeout, FALSE);
441
442   if (!_dbus_loop_add_timeout (bus_context_get_loop (context),
443                                connections->expire_timeout,
444                                call_timeout_callback, NULL, NULL))
445     goto failed_4;
446   
447   connections->refcount = 1;
448   connections->context = context;
449   
450   return connections;
451
452  failed_4:
453   _dbus_timeout_unref (connections->expire_timeout);
454  failed_3:
455   _dbus_hash_table_unref (connections->completed_by_user);
456  failed_2:
457   dbus_free (connections);
458  failed_1:
459   connection_data_slot_unref ();
460  failed_0:
461   return NULL;
462 }
463
464 void
465 bus_connections_ref (BusConnections *connections)
466 {
467   _dbus_assert (connections->refcount > 0);
468   connections->refcount += 1;
469 }
470
471 void
472 bus_connections_unref (BusConnections *connections)
473 {
474   _dbus_assert (connections->refcount > 0);
475   connections->refcount -= 1;
476   if (connections->refcount == 0)
477     {
478       /* drop all incomplete */
479       while (connections->incomplete != NULL)
480         {
481           DBusConnection *connection;
482
483           connection = connections->incomplete->data;
484
485           dbus_connection_ref (connection);
486           dbus_connection_disconnect (connection);
487           bus_connection_disconnected (connection);
488           dbus_connection_unref (connection);
489         }
490
491       _dbus_assert (connections->n_incomplete == 0);
492       
493       /* drop all real connections */
494       while (connections->completed != NULL)
495         {
496           DBusConnection *connection;
497
498           connection = connections->completed->data;
499
500           dbus_connection_ref (connection);
501           dbus_connection_disconnect (connection);
502           bus_connection_disconnected (connection);
503           dbus_connection_unref (connection);          
504         }
505
506       _dbus_assert (connections->n_completed == 0);
507
508       _dbus_loop_remove_timeout (bus_context_get_loop (connections->context),
509                                  connections->expire_timeout,
510                                  call_timeout_callback, NULL);
511       
512       _dbus_timeout_unref (connections->expire_timeout);
513       
514       _dbus_hash_table_unref (connections->completed_by_user);
515       
516       dbus_free (connections);
517
518       connection_data_slot_unref ();
519     }
520 }
521
522 dbus_bool_t
523 bus_connections_setup_connection (BusConnections *connections,
524                                   DBusConnection *connection)
525 {
526   BusConnectionData *d;
527   dbus_bool_t retval;
528   
529   d = dbus_new0 (BusConnectionData, 1);
530   
531   if (d == NULL)
532     return FALSE;
533
534   d->connections = connections;
535   d->connection = connection;
536
537   _dbus_get_current_time (&d->connection_tv_sec,
538                           &d->connection_tv_usec);
539   
540   _dbus_assert (connection_data_slot >= 0);
541   
542   if (!dbus_connection_set_data (connection,
543                                  connection_data_slot,
544                                  d, free_connection_data))
545     {
546       dbus_free (d);
547       return FALSE;
548     }
549
550   retval = FALSE;
551   
552   if (!dbus_connection_set_watch_functions (connection,
553                                             add_connection_watch,
554                                             remove_connection_watch,
555                                             NULL,
556                                             connection,
557                                             NULL))
558     goto out;
559   
560   if (!dbus_connection_set_timeout_functions (connection,
561                                               add_connection_timeout,
562                                               remove_connection_timeout,
563                                               NULL,
564                                               connection, NULL))
565     goto out;
566   
567   dbus_connection_set_unix_user_function (connection,
568                                           allow_user_function,
569                                           NULL, NULL);
570
571   dbus_connection_set_dispatch_status_function (connection,
572                                                 dispatch_status_function,
573                                                 bus_context_get_loop (connections->context),
574                                                 NULL);
575
576   d->link_in_connection_list = _dbus_list_alloc_link (connection);
577   if (d->link_in_connection_list == NULL)
578     goto out;
579   
580   /* Setup the connection with the dispatcher */
581   if (!bus_dispatch_add_connection (connection))
582     goto out;
583
584   if (dbus_connection_get_dispatch_status (connection) != DBUS_DISPATCH_COMPLETE)
585     {
586       if (!_dbus_loop_queue_dispatch (bus_context_get_loop (connections->context), connection))
587         {
588           bus_dispatch_remove_connection (connection);
589           goto out;
590         }
591     }
592
593   _dbus_list_append_link (&connections->incomplete, d->link_in_connection_list);
594   connections->n_incomplete += 1;
595   
596   dbus_connection_ref (connection);
597
598   /* Note that we might disconnect ourselves here, but it only takes
599    * effect on return to the main loop. We call this to free up
600    * expired connections if possible, and to queue the timeout for our
601    * own expiration.
602    */
603   bus_connections_expire_incomplete (connections);
604   
605   /* And we might also disconnect ourselves here, but again it
606    * only takes effect on return to main loop.
607    */
608   if (connections->n_incomplete >
609       bus_context_get_max_incomplete_connections (connections->context))
610     {
611       _dbus_verbose ("Number of incomplete connections exceeds max, dropping oldest one\n");
612       
613       _dbus_assert (connections->incomplete != NULL);
614       /* Disconnect the oldest unauthenticated connection.  FIXME
615        * would it be more secure to drop a *random* connection?  This
616        * algorithm seems to mean that if someone can create new
617        * connections quickly enough, they can keep anyone else from
618        * completing authentication. But random may or may not really
619        * help with that, a more elaborate solution might be required.
620        */
621       dbus_connection_disconnect (connections->incomplete->data);
622     }
623   
624   retval = TRUE;
625
626  out:
627   if (!retval)
628     {      
629       if (!dbus_connection_set_watch_functions (connection,
630                                                 NULL, NULL, NULL,
631                                                 connection,
632                                                 NULL))
633         _dbus_assert_not_reached ("setting watch functions to NULL failed");
634       
635       if (!dbus_connection_set_timeout_functions (connection,
636                                                   NULL, NULL, NULL,
637                                                   connection,
638                                                   NULL))
639         _dbus_assert_not_reached ("setting timeout functions to NULL failed");
640
641       dbus_connection_set_unix_user_function (connection,
642                                               NULL, NULL, NULL);
643
644       dbus_connection_set_dispatch_status_function (connection,
645                                                     NULL, NULL, NULL);
646       
647       if (!dbus_connection_set_data (connection,
648                                      connection_data_slot,
649                                      NULL, NULL))
650         _dbus_assert_not_reached ("failed to set connection data to null");
651
652       if (d->link_in_connection_list != NULL)
653         {
654           _dbus_assert (d->link_in_connection_list->next == NULL);
655           _dbus_assert (d->link_in_connection_list->prev == NULL);
656           _dbus_list_free_link (d->link_in_connection_list);
657         }
658     }
659   
660   return retval;
661 }
662
663 void
664 bus_connections_expire_incomplete (BusConnections *connections)
665 {    
666   int next_interval;
667
668   next_interval = -1;
669   
670   if (connections->incomplete != NULL)
671     {
672       long tv_sec, tv_usec;
673       DBusList *link;
674       int auth_timeout;
675       
676       _dbus_get_current_time (&tv_sec, &tv_usec);
677       auth_timeout = bus_context_get_auth_timeout (connections->context);
678   
679       link = _dbus_list_get_first_link (&connections->incomplete);
680       while (link != NULL)
681         {
682           DBusList *next = _dbus_list_get_next_link (&connections->incomplete, link);
683           DBusConnection *connection;
684           BusConnectionData *d;
685           double elapsed;
686       
687           connection = link->data;
688       
689           d = BUS_CONNECTION_DATA (connection);
690       
691           _dbus_assert (d != NULL);
692       
693           elapsed = ((double) tv_sec - (double) d->connection_tv_sec) * 1000.0 +
694             ((double) tv_usec - (double) d->connection_tv_usec) / 1000.0;
695
696           if (elapsed >= (double) auth_timeout)
697             {
698               _dbus_verbose ("Timing out authentication for connection %p\n", connection);
699               dbus_connection_disconnect (connection);
700             }
701           else
702             {
703               /* We can end the loop, since the connections are in oldest-first order */
704               next_interval = ((double)auth_timeout) - elapsed;
705               _dbus_verbose ("Connection %p authentication expires in %d milliseconds\n",
706                              connection, next_interval);
707           
708               break;
709             }
710       
711           link = next;
712         }
713     }
714   
715   if (next_interval >= 0)
716     {
717       _dbus_timeout_set_interval (connections->expire_timeout,
718                                   next_interval);
719       _dbus_timeout_set_enabled (connections->expire_timeout, TRUE);
720
721       _dbus_verbose ("Enabled incomplete connections timeout with interval %d, %d incomplete connections\n",
722                      next_interval, connections->n_incomplete);
723     }
724   else if (dbus_timeout_get_enabled (connections->expire_timeout))
725     {
726       _dbus_timeout_set_enabled (connections->expire_timeout, FALSE);
727
728       _dbus_verbose ("Disabled incomplete connections timeout, %d incomplete connections\n",
729                      connections->n_incomplete);
730     }
731   else
732     _dbus_verbose ("No need to disable incomplete connections timeout\n");
733 }
734
735 static dbus_bool_t
736 expire_incomplete_timeout (void *data)
737 {
738   BusConnections *connections = data;
739
740   _dbus_verbose ("Running %s\n", _DBUS_FUNCTION_NAME);
741   
742   /* note that this may remove the timeout */
743   bus_connections_expire_incomplete (connections);
744
745   return TRUE;
746 }
747
748 dbus_bool_t
749 bus_connection_get_groups  (DBusConnection   *connection,
750                             unsigned long   **groups,
751                             int              *n_groups,
752                             DBusError        *error)
753 {
754   BusConnectionData *d;
755   unsigned long uid;
756   DBusUserDatabase *user_database;
757   
758   d = BUS_CONNECTION_DATA (connection);
759
760   _dbus_assert (d != NULL);
761
762   user_database = bus_context_get_user_database (d->connections->context);
763   
764   *groups = NULL;
765   *n_groups = 0;
766
767   if (dbus_connection_get_unix_user (connection, &uid))
768     {
769       if (!_dbus_user_database_get_groups (user_database,
770                                            uid, groups, n_groups,
771                                            error))
772         {
773           _DBUS_ASSERT_ERROR_IS_SET (error);
774           _dbus_verbose ("Did not get any groups for UID %lu\n",
775                          uid);
776           return FALSE;
777         }
778       else
779         {
780           _dbus_verbose ("Got %d groups for UID %lu\n",
781                          *n_groups, uid);
782           return TRUE;
783         }
784     }
785   else
786     return TRUE; /* successfully got 0 groups */
787 }
788
789 dbus_bool_t
790 bus_connection_is_in_group (DBusConnection *connection,
791                             unsigned long   gid)
792 {
793   int i;
794   unsigned long *group_ids;
795   int n_group_ids;
796
797   if (!bus_connection_get_groups (connection, &group_ids, &n_group_ids,
798                                   NULL))
799     return FALSE;
800
801   i = 0;
802   while (i < n_group_ids)
803     {
804       if (group_ids[i] == gid)
805         {
806           dbus_free (group_ids);
807           return TRUE;
808         }
809       ++i;
810     }
811
812   dbus_free (group_ids);
813   return FALSE;
814 }
815
816 BusClientPolicy*
817 bus_connection_get_policy (DBusConnection *connection)
818 {
819   BusConnectionData *d;
820     
821   d = BUS_CONNECTION_DATA (connection);
822
823   _dbus_assert (d != NULL);
824   _dbus_assert (d->policy != NULL);
825   
826   return d->policy;
827 }
828
829 static dbus_bool_t
830 foreach_active (BusConnections               *connections,
831                 BusConnectionForeachFunction  function,
832                 void                         *data)
833 {
834   DBusList *link;
835   
836   link = _dbus_list_get_first_link (&connections->completed);
837   while (link != NULL)
838     {
839       DBusConnection *connection = link->data;
840       DBusList *next = _dbus_list_get_next_link (&connections->completed, link);
841
842       if (!(* function) (connection, data))
843         return FALSE;
844       
845       link = next;
846     }
847
848   return TRUE;
849 }
850
851 static dbus_bool_t
852 foreach_inactive (BusConnections               *connections,
853                   BusConnectionForeachFunction  function,
854                   void                         *data)
855 {
856   DBusList *link;
857   
858   link = _dbus_list_get_first_link (&connections->incomplete);
859   while (link != NULL)
860     {
861       DBusConnection *connection = link->data;
862       DBusList *next = _dbus_list_get_next_link (&connections->incomplete, link);
863
864       if (!(* function) (connection, data))
865         return FALSE;
866       
867       link = next;
868     }
869
870   return TRUE;
871 }
872
873 /**
874  * Calls function on each active connection; if the function returns
875  * #FALSE, stops iterating. Active connections are authenticated
876  * and have sent a Hello message.
877  *
878  * @param connections the connections object
879  * @param function the function
880  * @param data data to pass to it as a second arg
881  */
882 void
883 bus_connections_foreach_active (BusConnections               *connections,
884                                 BusConnectionForeachFunction  function,
885                                 void                         *data)
886 {
887   foreach_active (connections, function, data);
888 }
889
890 /**
891  * Calls function on each connection; if the function returns
892  * #FALSE, stops iterating.
893  *
894  * @param connections the connections object
895  * @param function the function
896  * @param data data to pass to it as a second arg
897  */
898 void
899 bus_connections_foreach (BusConnections               *connections,
900                          BusConnectionForeachFunction  function,
901                          void                         *data)
902 {
903   if (!foreach_active (connections, function, data))
904     return;
905
906   foreach_inactive (connections, function, data);
907 }
908
909 BusContext*
910 bus_connections_get_context (BusConnections *connections)
911 {
912   return connections->context;
913 }
914
915 BusContext*
916 bus_connection_get_context (DBusConnection *connection)
917 {
918   BusConnectionData *d;
919
920   d = BUS_CONNECTION_DATA (connection);
921
922   _dbus_assert (d != NULL);
923
924   return d->connections->context;
925 }
926
927 BusConnections*
928 bus_connection_get_connections (DBusConnection *connection)
929 {
930   BusConnectionData *d;
931     
932   d = BUS_CONNECTION_DATA (connection);
933
934   _dbus_assert (d != NULL);
935
936   return d->connections;
937 }
938
939 BusRegistry*
940 bus_connection_get_registry (DBusConnection *connection)
941 {
942   BusConnectionData *d;
943
944   d = BUS_CONNECTION_DATA (connection);
945
946   _dbus_assert (d != NULL);
947
948   return bus_context_get_registry (d->connections->context);
949 }
950
951 BusActivation*
952 bus_connection_get_activation (DBusConnection *connection)
953 {
954   BusConnectionData *d;
955
956   d = BUS_CONNECTION_DATA (connection);
957
958   _dbus_assert (d != NULL);
959
960   return bus_context_get_activation (d->connections->context);
961 }
962
963 /**
964  * Checks whether the connection is registered with the message bus.
965  *
966  * @param connection the connection
967  * @returns #TRUE if we're an active message bus participant
968  */
969 dbus_bool_t
970 bus_connection_is_active (DBusConnection *connection)
971 {
972   BusConnectionData *d;
973
974   d = BUS_CONNECTION_DATA (connection);
975   
976   return d != NULL && d->name != NULL;
977 }
978
979 dbus_bool_t
980 bus_connection_preallocate_oom_error (DBusConnection *connection)
981 {
982   DBusMessage *message;
983   DBusPreallocatedSend *preallocated;
984   BusConnectionData *d;
985
986   d = BUS_CONNECTION_DATA (connection);  
987
988   _dbus_assert (d != NULL);
989
990   if (d->oom_preallocated != NULL)
991     return TRUE;
992   
993   preallocated = dbus_connection_preallocate_send (connection);
994   if (preallocated == NULL)
995     return FALSE;
996
997   /* d->name may be NULL, but that is OK */
998   message = dbus_message_new (DBUS_ERROR_NO_MEMORY,
999                               d->name);
1000   if (message == NULL)
1001     {
1002       dbus_connection_free_preallocated_send (connection, preallocated);
1003       return FALSE;
1004     }
1005
1006   dbus_message_set_is_error (message, TRUE);
1007
1008   if (!dbus_message_set_sender (message,
1009                                 DBUS_SERVICE_DBUS))
1010     {
1011       dbus_connection_free_preallocated_send (connection, preallocated);
1012       dbus_message_unref (message);
1013       return FALSE;
1014     }
1015   
1016   /* set reply serial to placeholder value just so space is already allocated
1017    * for it.
1018    */
1019   if (!dbus_message_set_reply_serial (message, 14))
1020     {
1021       dbus_connection_free_preallocated_send (connection, preallocated);
1022       dbus_message_unref (message);
1023       return FALSE;
1024     }
1025
1026   d->oom_message = message;
1027   d->oom_preallocated = preallocated;
1028   
1029   return TRUE;
1030 }
1031
1032 void
1033 bus_connection_send_oom_error (DBusConnection *connection,
1034                                DBusMessage    *in_reply_to)
1035 {
1036   BusConnectionData *d;
1037
1038   d = BUS_CONNECTION_DATA (connection);  
1039
1040   _dbus_assert (d != NULL);  
1041   _dbus_assert (d->oom_message != NULL);
1042
1043   /* should always succeed since we set it to a placeholder earlier */
1044   if (!dbus_message_set_reply_serial (d->oom_message,
1045                                       dbus_message_get_serial (in_reply_to)))
1046     _dbus_assert_not_reached ("Failed to set reply serial for preallocated oom message");
1047
1048   _dbus_assert (dbus_message_get_sender (d->oom_message) != NULL);
1049   
1050   dbus_connection_send_preallocated (connection, d->oom_preallocated,
1051                                      d->oom_message, NULL);
1052
1053   dbus_message_unref (d->oom_message);
1054   d->oom_message = NULL;
1055   d->oom_preallocated = NULL;
1056 }
1057
1058 void
1059 bus_connection_add_owned_service_link (DBusConnection *connection,
1060                                        DBusList       *link)
1061 {
1062   BusConnectionData *d;
1063
1064   d = BUS_CONNECTION_DATA (connection);
1065   _dbus_assert (d != NULL);
1066
1067   _dbus_list_append_link (&d->services_owned, link);
1068
1069   d->n_services_owned += 1;
1070 }
1071
1072 dbus_bool_t
1073 bus_connection_add_owned_service (DBusConnection *connection,
1074                                   BusService     *service)
1075 {
1076   DBusList *link;
1077
1078   link = _dbus_list_alloc_link (service);
1079
1080   if (link == NULL)
1081     return FALSE;
1082
1083   bus_connection_add_owned_service_link (connection, link);
1084
1085   return TRUE;
1086 }
1087
1088 void
1089 bus_connection_remove_owned_service (DBusConnection *connection,
1090                                      BusService     *service)
1091 {
1092   BusConnectionData *d;
1093
1094   d = BUS_CONNECTION_DATA (connection);
1095   _dbus_assert (d != NULL);
1096
1097   _dbus_list_remove_last (&d->services_owned, service);
1098
1099   d->n_services_owned -= 1;
1100   _dbus_assert (d->n_services_owned >= 0);
1101 }
1102
1103 int
1104 bus_connection_get_n_services_owned (DBusConnection *connection)
1105 {
1106   BusConnectionData *d;
1107
1108   d = BUS_CONNECTION_DATA (connection);
1109   _dbus_assert (d != NULL);
1110   
1111   return d->n_services_owned;
1112 }
1113
1114 dbus_bool_t
1115 bus_connection_complete (DBusConnection   *connection,
1116                          const DBusString *name,
1117                          DBusError        *error)
1118 {
1119   BusConnectionData *d;
1120   unsigned long uid;
1121   
1122   d = BUS_CONNECTION_DATA (connection);
1123   _dbus_assert (d != NULL);
1124   _dbus_assert (d->name == NULL);
1125   _dbus_assert (d->policy == NULL);
1126   
1127   if (!_dbus_string_copy_data (name, &d->name))
1128     {
1129       BUS_SET_OOM (error);
1130       return FALSE;
1131     }
1132
1133   _dbus_assert (d->name != NULL);
1134   
1135   _dbus_verbose ("Name %s assigned to %p\n", d->name, connection);
1136
1137   d->policy = bus_context_create_client_policy (d->connections->context,
1138                                                 connection,
1139                                                 error);
1140
1141   /* we may have a NULL policy on OOM or error getting list of
1142    * groups for a user. In the latter case we don't handle it so
1143    * well currently, as it will just keep failing over and over.
1144    */
1145
1146   if (d->policy == NULL)
1147     {
1148       _dbus_verbose ("Failed to create security policy for connection %p\n",
1149                      connection);
1150       _DBUS_ASSERT_ERROR_IS_SET (error);
1151       dbus_free (d->name);
1152       d->name = NULL;
1153       return FALSE;
1154     }
1155   
1156   if (dbus_connection_get_unix_user (connection, &uid))
1157     {
1158       if (!adjust_connections_for_uid (d->connections,
1159                                        uid, 1))
1160         {
1161           BUS_SET_OOM (error);
1162           dbus_free (d->name);
1163           d->name = NULL;
1164           return FALSE;
1165         }
1166     }
1167   
1168   /* Now the connection is active, move it between lists */
1169   _dbus_list_unlink (&d->connections->incomplete,
1170                      d->link_in_connection_list);
1171   d->connections->n_incomplete -= 1;
1172   _dbus_list_append_link (&d->connections->completed,
1173                           d->link_in_connection_list);
1174   d->connections->n_completed += 1;
1175
1176   _dbus_assert (d->connections->n_incomplete >= 0);
1177   _dbus_assert (d->connections->n_completed > 0);
1178
1179   /* See if we can remove the timeout */
1180   bus_connections_expire_incomplete (d->connections);
1181   
1182   return TRUE;
1183 }
1184
1185 const char *
1186 bus_connection_get_name (DBusConnection *connection)
1187 {
1188   BusConnectionData *d;
1189   
1190   d = BUS_CONNECTION_DATA (connection);
1191   _dbus_assert (d != NULL);
1192   
1193   return d->name;
1194 }
1195
1196 /**
1197  * Check whether completing the passed-in connection would
1198  * exceed limits, and if so set error and return #FALSE
1199  */
1200 dbus_bool_t
1201 bus_connections_check_limits (BusConnections  *connections,
1202                               DBusConnection  *requesting_completion,
1203                               DBusError       *error)
1204 {
1205   BusConnectionData *d;
1206   unsigned long uid;
1207   
1208   d = BUS_CONNECTION_DATA (requesting_completion);
1209   _dbus_assert (d != NULL);
1210
1211   _dbus_assert (d->name == NULL);
1212
1213   if (connections->n_completed >=
1214       bus_context_get_max_completed_connections (connections->context))
1215     {
1216       dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
1217                       "The maximum number of active connections has been reached");
1218       return FALSE;
1219     }
1220   
1221   if (dbus_connection_get_unix_user (requesting_completion, &uid))
1222     {
1223       if (get_connections_for_uid (connections, uid) >=
1224           bus_context_get_max_connections_per_user (connections->context))
1225         {
1226           dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
1227                           "The maximum number of active connections for UID %lu has been reached",
1228                           uid);
1229           return FALSE;
1230         }
1231     }
1232   
1233   return TRUE;
1234 }
1235
1236
1237 /*
1238  * Transactions
1239  *
1240  * Note that this is fairly fragile; in particular, don't try to use
1241  * one transaction across any main loop iterations.
1242  */
1243
1244 typedef struct
1245 {
1246   BusTransaction *transaction;
1247   DBusMessage    *message;
1248   DBusPreallocatedSend *preallocated;
1249 } MessageToSend;
1250
1251 typedef struct
1252 {
1253   BusTransactionCancelFunction cancel_function;
1254   DBusFreeFunction free_data_function;
1255   void *data;
1256 } CancelHook;
1257
1258 struct BusTransaction
1259 {
1260   DBusList *connections;
1261   BusContext *context;
1262   DBusList *cancel_hooks;
1263 };
1264
1265 static void
1266 message_to_send_free (DBusConnection *connection,
1267                       MessageToSend  *to_send)
1268 {
1269   if (to_send->message)
1270     dbus_message_unref (to_send->message);
1271
1272   if (to_send->preallocated)
1273     dbus_connection_free_preallocated_send (connection, to_send->preallocated);
1274
1275   dbus_free (to_send);
1276 }
1277
1278 static void
1279 cancel_hook_cancel (void *element,
1280                     void *data)
1281 {
1282   CancelHook *ch = element;
1283
1284   _dbus_verbose ("Running transaction cancel hook\n");
1285   
1286   if (ch->cancel_function)
1287     (* ch->cancel_function) (ch->data);  
1288 }
1289
1290 static void
1291 cancel_hook_free (void *element,
1292                   void *data)
1293 {
1294   CancelHook *ch = element;
1295
1296   if (ch->free_data_function)
1297     (* ch->free_data_function) (ch->data);
1298
1299   dbus_free (ch);
1300 }
1301
1302 static void
1303 free_cancel_hooks (BusTransaction *transaction)
1304 {
1305   _dbus_list_foreach (&transaction->cancel_hooks,
1306                       cancel_hook_free, NULL);
1307   
1308   _dbus_list_clear (&transaction->cancel_hooks);
1309 }
1310
1311 BusTransaction*
1312 bus_transaction_new (BusContext *context)
1313 {
1314   BusTransaction *transaction;
1315
1316   transaction = dbus_new0 (BusTransaction, 1);
1317   if (transaction == NULL)
1318     return NULL;
1319
1320   transaction->context = context;
1321   
1322   return transaction;
1323 }
1324
1325 BusContext*
1326 bus_transaction_get_context (BusTransaction  *transaction)
1327 {
1328   return transaction->context;
1329 }
1330
1331 BusConnections*
1332 bus_transaction_get_connections (BusTransaction  *transaction)
1333 {
1334   return bus_context_get_connections (transaction->context);
1335 }
1336
1337 dbus_bool_t
1338 bus_transaction_send_from_driver (BusTransaction *transaction,
1339                                   DBusConnection *connection,
1340                                   DBusMessage    *message)
1341 {
1342   /* We have to set the sender to the driver, and have
1343    * to check security policy since it was not done in
1344    * dispatch.c
1345    */
1346   _dbus_verbose ("Sending %s from driver\n",
1347                  dbus_message_get_name (message));
1348   
1349   if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
1350     return FALSE;
1351
1352   /* If security policy doesn't allow the message, we silently
1353    * eat it; the driver doesn't care about getting a reply.
1354    */
1355   if (!bus_context_check_security_policy (bus_transaction_get_context (transaction),
1356                                           NULL, connection, message, NULL))
1357     return TRUE;
1358
1359   return bus_transaction_send (transaction, connection, message);
1360 }
1361
1362 dbus_bool_t
1363 bus_transaction_send (BusTransaction *transaction,
1364                       DBusConnection *connection,
1365                       DBusMessage    *message)
1366 {
1367   MessageToSend *to_send;
1368   BusConnectionData *d;
1369   DBusList *link;
1370
1371   _dbus_verbose ("  trying to add %s %s to transaction%s\n",
1372                  dbus_message_get_is_error (message) ? "error" :
1373                  dbus_message_get_reply_serial (message) != 0 ? "reply" :
1374                  "message",
1375                  dbus_message_get_name (message),
1376                  dbus_connection_get_is_connected (connection) ?
1377                  "" : " (disconnected)");
1378
1379   _dbus_assert (dbus_message_get_sender (message) != NULL);
1380   
1381   if (!dbus_connection_get_is_connected (connection))
1382     return TRUE; /* silently ignore disconnected connections */
1383   
1384   d = BUS_CONNECTION_DATA (connection);
1385   _dbus_assert (d != NULL);
1386   
1387   to_send = dbus_new (MessageToSend, 1);
1388   if (to_send == NULL)
1389     {
1390       return FALSE;
1391     }
1392
1393   to_send->preallocated = dbus_connection_preallocate_send (connection);
1394   if (to_send->preallocated == NULL)
1395     {
1396       dbus_free (to_send);
1397       return FALSE;
1398     }  
1399   
1400   dbus_message_ref (message);
1401   to_send->message = message;
1402   to_send->transaction = transaction;
1403
1404   _dbus_verbose ("about to prepend message\n");
1405   
1406   if (!_dbus_list_prepend (&d->transaction_messages, to_send))
1407     {
1408       message_to_send_free (connection, to_send);
1409       return FALSE;
1410     }
1411
1412   _dbus_verbose ("prepended message\n");
1413   
1414   /* See if we already had this connection in the list
1415    * for this transaction. If we have a pending message,
1416    * then we should already be in transaction->connections
1417    */
1418   link = _dbus_list_get_first_link (&d->transaction_messages);
1419   _dbus_assert (link->data == to_send);
1420   link = _dbus_list_get_next_link (&d->transaction_messages, link);
1421   while (link != NULL)
1422     {
1423       MessageToSend *m = link->data;
1424       DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link);
1425       
1426       if (m->transaction == transaction)
1427         break;
1428         
1429       link = next;
1430     }
1431
1432   if (link == NULL)
1433     {
1434       if (!_dbus_list_prepend (&transaction->connections, connection))
1435         {
1436           _dbus_list_remove (&d->transaction_messages, to_send);
1437           message_to_send_free (connection, to_send);
1438           return FALSE;
1439         }
1440     }
1441
1442   return TRUE;
1443 }
1444
1445 static void
1446 connection_cancel_transaction (DBusConnection *connection,
1447                                BusTransaction *transaction)
1448 {
1449   DBusList *link;
1450   BusConnectionData *d;
1451   
1452   d = BUS_CONNECTION_DATA (connection);
1453   _dbus_assert (d != NULL);
1454   
1455   link = _dbus_list_get_first_link (&d->transaction_messages);
1456   while (link != NULL)
1457     {
1458       MessageToSend *m = link->data;
1459       DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link);
1460       
1461       if (m->transaction == transaction)
1462         {
1463           _dbus_list_remove_link (&d->transaction_messages,
1464                                   link);
1465           
1466           message_to_send_free (connection, m);
1467         }
1468         
1469       link = next;
1470     }
1471 }
1472
1473 void
1474 bus_transaction_cancel_and_free (BusTransaction *transaction)
1475 {
1476   DBusConnection *connection;
1477
1478   _dbus_verbose ("TRANSACTION: cancelled\n");
1479   
1480   while ((connection = _dbus_list_pop_first (&transaction->connections)))
1481     connection_cancel_transaction (connection, transaction);
1482
1483   _dbus_assert (transaction->connections == NULL);
1484
1485   _dbus_list_foreach (&transaction->cancel_hooks,
1486                       cancel_hook_cancel, NULL);
1487
1488   free_cancel_hooks (transaction);
1489   
1490   dbus_free (transaction);
1491 }
1492
1493 static void
1494 connection_execute_transaction (DBusConnection *connection,
1495                                 BusTransaction *transaction)
1496 {
1497   DBusList *link;
1498   BusConnectionData *d;
1499   
1500   d = BUS_CONNECTION_DATA (connection);
1501   _dbus_assert (d != NULL);
1502
1503   /* Send the queue in order (FIFO) */
1504   link = _dbus_list_get_last_link (&d->transaction_messages);
1505   while (link != NULL)
1506     {
1507       MessageToSend *m = link->data;
1508       DBusList *prev = _dbus_list_get_prev_link (&d->transaction_messages, link);
1509       
1510       if (m->transaction == transaction)
1511         {
1512           _dbus_list_remove_link (&d->transaction_messages,
1513                                   link);
1514
1515           _dbus_assert (dbus_message_get_sender (m->message) != NULL);
1516           
1517           dbus_connection_send_preallocated (connection,
1518                                              m->preallocated,
1519                                              m->message,
1520                                              NULL);
1521
1522           m->preallocated = NULL; /* so we don't double-free it */
1523           
1524           message_to_send_free (connection, m);
1525         }
1526         
1527       link = prev;
1528     }
1529 }
1530
1531 void
1532 bus_transaction_execute_and_free (BusTransaction *transaction)
1533 {
1534   /* For each connection in transaction->connections
1535    * send the messages
1536    */
1537   DBusConnection *connection;
1538
1539   _dbus_verbose ("TRANSACTION: executing\n");
1540   
1541   while ((connection = _dbus_list_pop_first (&transaction->connections)))
1542     connection_execute_transaction (connection, transaction);
1543
1544   _dbus_assert (transaction->connections == NULL);
1545
1546   free_cancel_hooks (transaction);
1547   
1548   dbus_free (transaction);
1549 }
1550
1551 static void
1552 bus_connection_remove_transactions (DBusConnection *connection)
1553 {
1554   MessageToSend *to_send;
1555   BusConnectionData *d;
1556   
1557   d = BUS_CONNECTION_DATA (connection);
1558   _dbus_assert (d != NULL);
1559   
1560   while ((to_send = _dbus_list_get_first (&d->transaction_messages)))
1561     {
1562       /* only has an effect for the first MessageToSend listing this transaction */
1563       _dbus_list_remove (&to_send->transaction->connections,
1564                          connection);
1565
1566       _dbus_list_remove (&d->transaction_messages, to_send);
1567       message_to_send_free (connection, to_send);
1568     }
1569 }
1570
1571 /**
1572  * Converts the DBusError to a message reply
1573  */
1574 dbus_bool_t
1575 bus_transaction_send_error_reply (BusTransaction  *transaction,
1576                                   DBusConnection  *connection,
1577                                   const DBusError *error,
1578                                   DBusMessage     *in_reply_to)
1579 {
1580   DBusMessage *reply;
1581   
1582   _dbus_assert (error != NULL);
1583   _DBUS_ASSERT_ERROR_IS_SET (error);
1584
1585   _dbus_verbose ("Sending error reply %s \"%s\"\n",
1586                  error->name, error->message);
1587
1588   reply = dbus_message_new_error_reply (in_reply_to,
1589                                         error->name,
1590                                         error->message);
1591   if (reply == NULL)
1592     return FALSE;
1593
1594   if (!bus_transaction_send_from_driver (transaction, connection, reply))
1595     {
1596       dbus_message_unref (reply);
1597       return FALSE;
1598     }
1599
1600   dbus_message_unref (reply);
1601   
1602   return TRUE;
1603 }
1604
1605 dbus_bool_t
1606 bus_transaction_add_cancel_hook (BusTransaction               *transaction,
1607                                  BusTransactionCancelFunction  cancel_function,
1608                                  void                         *data,
1609                                  DBusFreeFunction              free_data_function)
1610 {
1611   CancelHook *ch;
1612
1613   ch = dbus_new (CancelHook, 1);
1614   if (ch == NULL)
1615     return FALSE;
1616   
1617   ch->cancel_function = cancel_function;
1618   ch->data = data;
1619   ch->free_data_function = free_data_function;
1620
1621   /* It's important that the hooks get run in reverse order that they
1622    * were added
1623    */
1624   if (!_dbus_list_prepend (&transaction->cancel_hooks, ch))
1625     {
1626       dbus_free (ch);
1627       return FALSE;
1628     }
1629
1630   return TRUE;
1631 }