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