Main Page   Modules   Data Structures   File List   Data Fields   Related Pages  

connection.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* connection.c  Client connections
00003  *
00004  * Copyright (C) 2003  Red Hat, Inc.
00005  *
00006  * Licensed under the Academic Free License version 1.2
00007  * 
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  * 
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 #include "connection.h"
00024 #include "dispatch.h"
00025 #include "policy.h"
00026 #include "services.h"
00027 #include "utils.h"
00028 #include "signals.h"
00029 #include <dbus/dbus-list.h>
00030 #include <dbus/dbus-hash.h>
00031 #include <dbus/dbus-timeout.h>
00032 
00033 static void bus_connection_remove_transactions (DBusConnection *connection);
00034 
00035 struct BusConnections
00036 {
00037   int refcount;
00038   DBusList *completed;  
00039   int n_completed;      
00040   DBusList *incomplete; 
00041   int n_incomplete;     
00042   BusContext *context;
00043   DBusHashTable *completed_by_user; 
00044   DBusTimeout *expire_timeout; 
00045   int stamp;            
00046 };
00047 
00048 static dbus_int32_t connection_data_slot = -1;
00049 
00050 typedef struct
00051 {
00052   BusConnections *connections;
00053   DBusList *link_in_connection_list;
00054   DBusConnection *connection;
00055   DBusList *services_owned;
00056   int n_services_owned;
00057   DBusList *match_rules;
00058   int n_match_rules;
00059   char *name;
00060   DBusList *transaction_messages; 
00061   DBusMessage *oom_message;
00062   DBusPreallocatedSend *oom_preallocated;
00063   BusClientPolicy *policy;
00064 
00065   long connection_tv_sec;  
00066   long connection_tv_usec; 
00067   int stamp;               
00068 } BusConnectionData;
00069 
00070 static dbus_bool_t expire_incomplete_timeout (void *data);
00071 
00072 #define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot))
00073 
00074 static DBusLoop*
00075 connection_get_loop (DBusConnection *connection)
00076 {
00077   BusConnectionData *d;
00078 
00079   d = BUS_CONNECTION_DATA (connection);
00080 
00081   return bus_context_get_loop (d->connections->context);
00082 }
00083 
00084 
00085 static int
00086 get_connections_for_uid (BusConnections *connections,
00087                          dbus_uid_t      uid)
00088 {
00089   void *val;
00090   int current_count;
00091 
00092   /* val is NULL is 0 when it isn't in the hash yet */
00093   
00094   val = _dbus_hash_table_lookup_ulong (connections->completed_by_user,
00095                                        uid);
00096 
00097   current_count = _DBUS_POINTER_TO_INT (val);
00098 
00099   return current_count;
00100 }
00101 
00102 static dbus_bool_t
00103 adjust_connections_for_uid (BusConnections *connections,
00104                             dbus_uid_t      uid,
00105                             int             adjustment)
00106 {
00107   int current_count;
00108 
00109   current_count = get_connections_for_uid (connections, uid);
00110 
00111   _dbus_verbose ("Adjusting connection count for UID " DBUS_UID_FORMAT
00112                  ": was %d adjustment %d making %d\n",
00113                  uid, current_count, adjustment, current_count + adjustment);
00114   
00115   _dbus_assert (current_count >= 0);
00116   
00117   current_count += adjustment;
00118 
00119   _dbus_assert (current_count >= 0);
00120 
00121   if (current_count == 0)
00122     {
00123       _dbus_hash_table_remove_ulong (connections->completed_by_user, uid);
00124       return TRUE;
00125     }
00126   else
00127     {
00128       dbus_bool_t retval;
00129       
00130       retval = _dbus_hash_table_insert_ulong (connections->completed_by_user,
00131                                               uid, _DBUS_INT_TO_POINTER (current_count));
00132 
00133       /* only positive adjustment can fail as otherwise
00134        * a hash entry should already exist
00135        */
00136       _dbus_assert (adjustment > 0 ||
00137                     (adjustment <= 0 && retval));
00138 
00139       return retval;
00140     }
00141 }
00142 
00143 void
00144 bus_connection_disconnected (DBusConnection *connection)
00145 {
00146   BusConnectionData *d;
00147   BusService *service;
00148   BusMatchmaker *matchmaker;
00149   
00150   d = BUS_CONNECTION_DATA (connection);
00151   _dbus_assert (d != NULL);
00152 
00153   _dbus_verbose ("%s disconnected, dropping all service ownership and releasing\n",
00154                  d->name ? d->name : "(inactive)");
00155 
00156   /* Delete our match rules */
00157   if (d->n_match_rules > 0)
00158     {
00159       matchmaker = bus_context_get_matchmaker (d->connections->context);
00160       bus_matchmaker_disconnected (matchmaker, connection);
00161     }
00162   
00163   /* Drop any service ownership. FIXME Unfortunately, this requires
00164    * memory allocation and there doesn't seem to be a good way to
00165    * handle it other than sleeping; we can't "fail" the operation of
00166    * disconnecting a client, and preallocating a broadcast "service is
00167    * now gone" message for every client-service pair seems kind of
00168    * involved. Probably we need to do that though.
00169    */
00170   while ((service = _dbus_list_get_last (&d->services_owned)))
00171     {
00172       BusTransaction *transaction;
00173       DBusError error;
00174 
00175     retry:
00176       
00177       dbus_error_init (&error);
00178         
00179       transaction = NULL;
00180       while (transaction == NULL)
00181         {
00182           transaction = bus_transaction_new (d->connections->context);
00183           _dbus_wait_for_memory ();
00184         }
00185         
00186       if (!bus_service_remove_owner (service, connection,
00187                                      transaction, &error))
00188         {
00189           _DBUS_ASSERT_ERROR_IS_SET (&error);
00190           
00191           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
00192             {
00193               dbus_error_free (&error);
00194               bus_transaction_cancel_and_free (transaction);
00195               _dbus_wait_for_memory ();
00196               goto retry;
00197             }
00198           else
00199             {
00200               _dbus_verbose ("Failed to remove service owner: %s %s\n",
00201                              error.name, error.message);
00202               _dbus_assert_not_reached ("Removing service owner failed for non-memory-related reason");
00203             }
00204         }
00205         
00206       bus_transaction_execute_and_free (transaction);
00207     }
00208 
00209   bus_dispatch_remove_connection (connection);
00210   
00211   /* no more watching */
00212   if (!dbus_connection_set_watch_functions (connection,
00213                                             NULL, NULL, NULL,
00214                                             connection,
00215                                             NULL))
00216     _dbus_assert_not_reached ("setting watch functions to NULL failed");
00217 
00218   if (!dbus_connection_set_timeout_functions (connection,
00219                                               NULL, NULL, NULL,
00220                                               connection,
00221                                               NULL))
00222     _dbus_assert_not_reached ("setting timeout functions to NULL failed");
00223   
00224   dbus_connection_set_unix_user_function (connection,
00225                                           NULL, NULL, NULL);
00226 
00227   dbus_connection_set_dispatch_status_function (connection,
00228                                                 NULL, NULL, NULL);
00229   
00230   bus_connection_remove_transactions (connection);
00231 
00232   if (d->link_in_connection_list != NULL)
00233     {
00234       if (d->name != NULL)
00235         {
00236           unsigned long uid;
00237           
00238           _dbus_list_remove_link (&d->connections->completed, d->link_in_connection_list);
00239           d->link_in_connection_list = NULL;
00240           d->connections->n_completed -= 1;
00241 
00242           if (dbus_connection_get_unix_user (connection, &uid))
00243             {
00244               if (!adjust_connections_for_uid (d->connections,
00245                                                uid, -1))
00246                 _dbus_assert_not_reached ("adjusting downward should never fail");
00247             }
00248         }
00249       else
00250         {
00251           _dbus_list_remove_link (&d->connections->incomplete, d->link_in_connection_list);
00252           d->link_in_connection_list = NULL;
00253           d->connections->n_incomplete -= 1;
00254         }
00255       
00256       _dbus_assert (d->connections->n_incomplete >= 0);
00257       _dbus_assert (d->connections->n_completed >= 0);
00258     }
00259   
00260   /* frees "d" as side effect */
00261   dbus_connection_set_data (connection,
00262                             connection_data_slot,
00263                             NULL, NULL);
00264 
00265   dbus_connection_unref (connection);
00266 }
00267 
00268 static dbus_bool_t
00269 connection_watch_callback (DBusWatch     *watch,
00270                            unsigned int   condition,
00271                            void          *data)
00272 {
00273  /* FIXME this can be done in dbus-mainloop.c
00274   * if the code in activation.c for the babysitter
00275   * watch handler is fixed.
00276   */
00277   
00278 #if 0
00279   _dbus_verbose ("Calling handle_watch\n");
00280 #endif
00281   return dbus_watch_handle (watch, condition);
00282 }
00283 
00284 static dbus_bool_t
00285 add_connection_watch (DBusWatch      *watch,
00286                       void           *data)
00287 {
00288   DBusConnection *connection = data;
00289 
00290   return _dbus_loop_add_watch (connection_get_loop (connection),
00291                                watch, connection_watch_callback, connection,
00292                                NULL);
00293 }
00294 
00295 static void
00296 remove_connection_watch (DBusWatch      *watch,
00297                          void           *data)
00298 {
00299   DBusConnection *connection = data;
00300   
00301   _dbus_loop_remove_watch (connection_get_loop (connection),
00302                            watch, connection_watch_callback, connection);
00303 }
00304 
00305 static void
00306 connection_timeout_callback (DBusTimeout   *timeout,
00307                              void          *data)
00308 {
00309   /* DBusConnection *connection = data; */
00310 
00311   /* can return FALSE on OOM but we just let it fire again later */
00312   dbus_timeout_handle (timeout);
00313 }
00314 
00315 static dbus_bool_t
00316 add_connection_timeout (DBusTimeout    *timeout,
00317                         void           *data)
00318 {
00319   DBusConnection *connection = data;
00320   
00321   return _dbus_loop_add_timeout (connection_get_loop (connection),
00322                                  timeout, connection_timeout_callback, connection, NULL);
00323 }
00324 
00325 static void
00326 remove_connection_timeout (DBusTimeout    *timeout,
00327                            void           *data)
00328 {
00329   DBusConnection *connection = data;
00330   
00331   _dbus_loop_remove_timeout (connection_get_loop (connection),
00332                              timeout, connection_timeout_callback, connection);
00333 }
00334 
00335 static void
00336 dispatch_status_function (DBusConnection    *connection,
00337                           DBusDispatchStatus new_status,
00338                           void              *data)
00339 {
00340   DBusLoop *loop = data;
00341   
00342   if (new_status != DBUS_DISPATCH_COMPLETE)
00343     {
00344       while (!_dbus_loop_queue_dispatch (loop, connection))
00345         _dbus_wait_for_memory ();
00346     }
00347 }
00348 
00349 static dbus_bool_t
00350 allow_user_function (DBusConnection *connection,
00351                      unsigned long   uid,
00352                      void           *data)
00353 {
00354   BusConnectionData *d;
00355     
00356   d = BUS_CONNECTION_DATA (connection);
00357 
00358   _dbus_assert (d != NULL);
00359   
00360   return bus_context_allow_user (d->connections->context, uid);
00361 }
00362 
00363 static void
00364 free_connection_data (void *data)
00365 {
00366   BusConnectionData *d = data;
00367 
00368   /* services_owned should be NULL since we should be disconnected */
00369   _dbus_assert (d->services_owned == NULL);
00370   _dbus_assert (d->n_services_owned == 0);
00371   /* similarly */
00372   _dbus_assert (d->transaction_messages == NULL);
00373 
00374   if (d->oom_preallocated)
00375     dbus_connection_free_preallocated_send (d->connection, d->oom_preallocated);
00376 
00377   if (d->oom_message)
00378     dbus_message_unref (d->oom_message);
00379 
00380   if (d->policy)
00381     bus_client_policy_unref (d->policy);
00382   
00383   dbus_free (d->name);
00384   
00385   dbus_free (d);
00386 }
00387 
00388 static void
00389 call_timeout_callback (DBusTimeout   *timeout,
00390                        void          *data)
00391 {
00392   /* can return FALSE on OOM but we just let it fire again later */
00393   dbus_timeout_handle (timeout);
00394 }
00395 
00396 BusConnections*
00397 bus_connections_new (BusContext *context)
00398 {
00399   BusConnections *connections;
00400 
00401   if (!dbus_connection_allocate_data_slot (&connection_data_slot))
00402     goto failed_0;
00403 
00404   connections = dbus_new0 (BusConnections, 1);
00405   if (connections == NULL)
00406     goto failed_1;
00407 
00408   connections->completed_by_user = _dbus_hash_table_new (DBUS_HASH_ULONG,
00409                                                          NULL, NULL);
00410   if (connections->completed_by_user == NULL)
00411     goto failed_2;
00412 
00413   connections->expire_timeout = _dbus_timeout_new (100, /* irrelevant */
00414                                                    expire_incomplete_timeout,
00415                                                    connections, NULL);
00416   if (connections->expire_timeout == NULL)
00417     goto failed_3;
00418 
00419   _dbus_timeout_set_enabled (connections->expire_timeout, FALSE);
00420 
00421   if (!_dbus_loop_add_timeout (bus_context_get_loop (context),
00422                                connections->expire_timeout,
00423                                call_timeout_callback, NULL, NULL))
00424     goto failed_4;
00425   
00426   connections->refcount = 1;
00427   connections->context = context;
00428   
00429   return connections;
00430 
00431  failed_4:
00432   _dbus_timeout_unref (connections->expire_timeout);
00433  failed_3:
00434   _dbus_hash_table_unref (connections->completed_by_user);
00435  failed_2:
00436   dbus_free (connections);
00437  failed_1:
00438   dbus_connection_free_data_slot (&connection_data_slot);
00439  failed_0:
00440   return NULL;
00441 }
00442 
00443 void
00444 bus_connections_ref (BusConnections *connections)
00445 {
00446   _dbus_assert (connections->refcount > 0);
00447   connections->refcount += 1;
00448 }
00449 
00450 void
00451 bus_connections_unref (BusConnections *connections)
00452 {
00453   _dbus_assert (connections->refcount > 0);
00454   connections->refcount -= 1;
00455   if (connections->refcount == 0)
00456     {
00457       /* drop all incomplete */
00458       while (connections->incomplete != NULL)
00459         {
00460           DBusConnection *connection;
00461 
00462           connection = connections->incomplete->data;
00463 
00464           dbus_connection_ref (connection);
00465           dbus_connection_disconnect (connection);
00466           bus_connection_disconnected (connection);
00467           dbus_connection_unref (connection);
00468         }
00469 
00470       _dbus_assert (connections->n_incomplete == 0);
00471       
00472       /* drop all real connections */
00473       while (connections->completed != NULL)
00474         {
00475           DBusConnection *connection;
00476 
00477           connection = connections->completed->data;
00478 
00479           dbus_connection_ref (connection);
00480           dbus_connection_disconnect (connection);
00481           bus_connection_disconnected (connection);
00482           dbus_connection_unref (connection);          
00483         }
00484 
00485       _dbus_assert (connections->n_completed == 0);
00486 
00487       _dbus_loop_remove_timeout (bus_context_get_loop (connections->context),
00488                                  connections->expire_timeout,
00489                                  call_timeout_callback, NULL);
00490       
00491       _dbus_timeout_unref (connections->expire_timeout);
00492       
00493       _dbus_hash_table_unref (connections->completed_by_user);
00494       
00495       dbus_free (connections);
00496 
00497       dbus_connection_free_data_slot (&connection_data_slot);
00498     }
00499 }
00500 
00501 dbus_bool_t
00502 bus_connections_setup_connection (BusConnections *connections,
00503                                   DBusConnection *connection)
00504 {
00505   BusConnectionData *d;
00506   dbus_bool_t retval;
00507   
00508   d = dbus_new0 (BusConnectionData, 1);
00509   
00510   if (d == NULL)
00511     return FALSE;
00512 
00513   d->connections = connections;
00514   d->connection = connection;
00515   
00516   _dbus_get_current_time (&d->connection_tv_sec,
00517                           &d->connection_tv_usec);
00518   
00519   _dbus_assert (connection_data_slot >= 0);
00520   
00521   if (!dbus_connection_set_data (connection,
00522                                  connection_data_slot,
00523                                  d, free_connection_data))
00524     {
00525       dbus_free (d);
00526       return FALSE;
00527     }
00528 
00529   retval = FALSE;
00530   
00531   if (!dbus_connection_set_watch_functions (connection,
00532                                             add_connection_watch,
00533                                             remove_connection_watch,
00534                                             NULL,
00535                                             connection,
00536                                             NULL))
00537     goto out;
00538   
00539   if (!dbus_connection_set_timeout_functions (connection,
00540                                               add_connection_timeout,
00541                                               remove_connection_timeout,
00542                                               NULL,
00543                                               connection, NULL))
00544     goto out;
00545   
00546   dbus_connection_set_unix_user_function (connection,
00547                                           allow_user_function,
00548                                           NULL, NULL);
00549 
00550   dbus_connection_set_dispatch_status_function (connection,
00551                                                 dispatch_status_function,
00552                                                 bus_context_get_loop (connections->context),
00553                                                 NULL);
00554 
00555   d->link_in_connection_list = _dbus_list_alloc_link (connection);
00556   if (d->link_in_connection_list == NULL)
00557     goto out;
00558   
00559   /* Setup the connection with the dispatcher */
00560   if (!bus_dispatch_add_connection (connection))
00561     goto out;
00562 
00563   if (dbus_connection_get_dispatch_status (connection) != DBUS_DISPATCH_COMPLETE)
00564     {
00565       if (!_dbus_loop_queue_dispatch (bus_context_get_loop (connections->context), connection))
00566         {
00567           bus_dispatch_remove_connection (connection);
00568           goto out;
00569         }
00570     }
00571 
00572   _dbus_list_append_link (&connections->incomplete, d->link_in_connection_list);
00573   connections->n_incomplete += 1;
00574   
00575   dbus_connection_ref (connection);
00576 
00577   /* Note that we might disconnect ourselves here, but it only takes
00578    * effect on return to the main loop. We call this to free up
00579    * expired connections if possible, and to queue the timeout for our
00580    * own expiration.
00581    */
00582   bus_connections_expire_incomplete (connections);
00583   
00584   /* And we might also disconnect ourselves here, but again it
00585    * only takes effect on return to main loop.
00586    */
00587   if (connections->n_incomplete >
00588       bus_context_get_max_incomplete_connections (connections->context))
00589     {
00590       _dbus_verbose ("Number of incomplete connections exceeds max, dropping oldest one\n");
00591       
00592       _dbus_assert (connections->incomplete != NULL);
00593       /* Disconnect the oldest unauthenticated connection.  FIXME
00594        * would it be more secure to drop a *random* connection?  This
00595        * algorithm seems to mean that if someone can create new
00596        * connections quickly enough, they can keep anyone else from
00597        * completing authentication. But random may or may not really
00598        * help with that, a more elaborate solution might be required.
00599        */
00600       dbus_connection_disconnect (connections->incomplete->data);
00601     }
00602   
00603   retval = TRUE;
00604 
00605  out:
00606   if (!retval)
00607     {      
00608       if (!dbus_connection_set_watch_functions (connection,
00609                                                 NULL, NULL, NULL,
00610                                                 connection,
00611                                                 NULL))
00612         _dbus_assert_not_reached ("setting watch functions to NULL failed");
00613       
00614       if (!dbus_connection_set_timeout_functions (connection,
00615                                                   NULL, NULL, NULL,
00616                                                   connection,
00617                                                   NULL))
00618         _dbus_assert_not_reached ("setting timeout functions to NULL failed");
00619 
00620       dbus_connection_set_unix_user_function (connection,
00621                                               NULL, NULL, NULL);
00622 
00623       dbus_connection_set_dispatch_status_function (connection,
00624                                                     NULL, NULL, NULL);
00625 
00626       if (d->link_in_connection_list != NULL)
00627         {
00628           _dbus_assert (d->link_in_connection_list->next == NULL);
00629           _dbus_assert (d->link_in_connection_list->prev == NULL);
00630           _dbus_list_free_link (d->link_in_connection_list);
00631           d->link_in_connection_list = NULL;
00632         }
00633       
00634       if (!dbus_connection_set_data (connection,
00635                                      connection_data_slot,
00636                                      NULL, NULL))
00637         _dbus_assert_not_reached ("failed to set connection data to null");
00638 
00639       /* "d" has now been freed */
00640     }
00641   
00642   return retval;
00643 }
00644 
00645 void
00646 bus_connections_expire_incomplete (BusConnections *connections)
00647 {    
00648   int next_interval;
00649 
00650   next_interval = -1;
00651   
00652   if (connections->incomplete != NULL)
00653     {
00654       long tv_sec, tv_usec;
00655       DBusList *link;
00656       int auth_timeout;
00657       
00658       _dbus_get_current_time (&tv_sec, &tv_usec);
00659       auth_timeout = bus_context_get_auth_timeout (connections->context);
00660   
00661       link = _dbus_list_get_first_link (&connections->incomplete);
00662       while (link != NULL)
00663         {
00664           DBusList *next = _dbus_list_get_next_link (&connections->incomplete, link);
00665           DBusConnection *connection;
00666           BusConnectionData *d;
00667           double elapsed;
00668       
00669           connection = link->data;
00670       
00671           d = BUS_CONNECTION_DATA (connection);
00672       
00673           _dbus_assert (d != NULL);
00674       
00675           elapsed = ((double) tv_sec - (double) d->connection_tv_sec) * 1000.0 +
00676             ((double) tv_usec - (double) d->connection_tv_usec) / 1000.0;
00677 
00678           if (elapsed >= (double) auth_timeout)
00679             {
00680               _dbus_verbose ("Timing out authentication for connection %p\n", connection);
00681               dbus_connection_disconnect (connection);
00682             }
00683           else
00684             {
00685               /* We can end the loop, since the connections are in oldest-first order */
00686               next_interval = ((double)auth_timeout) - elapsed;
00687               _dbus_verbose ("Connection %p authentication expires in %d milliseconds\n",
00688                              connection, next_interval);
00689           
00690               break;
00691             }
00692       
00693           link = next;
00694         }
00695     }
00696   
00697   if (next_interval >= 0)
00698     {
00699       _dbus_timeout_set_interval (connections->expire_timeout,
00700                                   next_interval);
00701       _dbus_timeout_set_enabled (connections->expire_timeout, TRUE);
00702 
00703       _dbus_verbose ("Enabled incomplete connections timeout with interval %d, %d incomplete connections\n",
00704                      next_interval, connections->n_incomplete);
00705     }
00706   else if (dbus_timeout_get_enabled (connections->expire_timeout))
00707     {
00708       _dbus_timeout_set_enabled (connections->expire_timeout, FALSE);
00709 
00710       _dbus_verbose ("Disabled incomplete connections timeout, %d incomplete connections\n",
00711                      connections->n_incomplete);
00712     }
00713   else
00714     _dbus_verbose ("No need to disable incomplete connections timeout\n");
00715 }
00716 
00717 static dbus_bool_t
00718 expire_incomplete_timeout (void *data)
00719 {
00720   BusConnections *connections = data;
00721 
00722   _dbus_verbose ("Running %s\n", _DBUS_FUNCTION_NAME);
00723   
00724   /* note that this may remove the timeout */
00725   bus_connections_expire_incomplete (connections);
00726 
00727   return TRUE;
00728 }
00729 
00730 dbus_bool_t
00731 bus_connection_get_groups  (DBusConnection   *connection,
00732                             unsigned long   **groups,
00733                             int              *n_groups,
00734                             DBusError        *error)
00735 {
00736   BusConnectionData *d;
00737   unsigned long uid;
00738   DBusUserDatabase *user_database;
00739   
00740   d = BUS_CONNECTION_DATA (connection);
00741 
00742   _dbus_assert (d != NULL);
00743 
00744   user_database = bus_context_get_user_database (d->connections->context);
00745   
00746   *groups = NULL;
00747   *n_groups = 0;
00748 
00749   if (dbus_connection_get_unix_user (connection, &uid))
00750     {
00751       if (!_dbus_user_database_get_groups (user_database,
00752                                            uid, groups, n_groups,
00753                                            error))
00754         {
00755           _DBUS_ASSERT_ERROR_IS_SET (error);
00756           _dbus_verbose ("Did not get any groups for UID %lu\n",
00757                          uid);
00758           return FALSE;
00759         }
00760       else
00761         {
00762           _dbus_verbose ("Got %d groups for UID %lu\n",
00763                          *n_groups, uid);
00764           return TRUE;
00765         }
00766     }
00767   else
00768     return TRUE; /* successfully got 0 groups */
00769 }
00770 
00771 dbus_bool_t
00772 bus_connection_is_in_group (DBusConnection *connection,
00773                             unsigned long   gid)
00774 {
00775   int i;
00776   unsigned long *group_ids;
00777   int n_group_ids;
00778 
00779   if (!bus_connection_get_groups (connection, &group_ids, &n_group_ids,
00780                                   NULL))
00781     return FALSE;
00782 
00783   i = 0;
00784   while (i < n_group_ids)
00785     {
00786       if (group_ids[i] == gid)
00787         {
00788           dbus_free (group_ids);
00789           return TRUE;
00790         }
00791       ++i;
00792     }
00793 
00794   dbus_free (group_ids);
00795   return FALSE;
00796 }
00797 
00798 BusClientPolicy*
00799 bus_connection_get_policy (DBusConnection *connection)
00800 {
00801   BusConnectionData *d;
00802     
00803   d = BUS_CONNECTION_DATA (connection);
00804 
00805   _dbus_assert (d != NULL);
00806   _dbus_assert (d->policy != NULL);
00807   
00808   return d->policy;
00809 }
00810 
00811 static dbus_bool_t
00812 foreach_active (BusConnections               *connections,
00813                 BusConnectionForeachFunction  function,
00814                 void                         *data)
00815 {
00816   DBusList *link;
00817   
00818   link = _dbus_list_get_first_link (&connections->completed);
00819   while (link != NULL)
00820     {
00821       DBusConnection *connection = link->data;
00822       DBusList *next = _dbus_list_get_next_link (&connections->completed, link);
00823 
00824       if (!(* function) (connection, data))
00825         return FALSE;
00826       
00827       link = next;
00828     }
00829 
00830   return TRUE;
00831 }
00832 
00833 static dbus_bool_t
00834 foreach_inactive (BusConnections               *connections,
00835                   BusConnectionForeachFunction  function,
00836                   void                         *data)
00837 {
00838   DBusList *link;
00839   
00840   link = _dbus_list_get_first_link (&connections->incomplete);
00841   while (link != NULL)
00842     {
00843       DBusConnection *connection = link->data;
00844       DBusList *next = _dbus_list_get_next_link (&connections->incomplete, link);
00845 
00846       if (!(* function) (connection, data))
00847         return FALSE;
00848       
00849       link = next;
00850     }
00851 
00852   return TRUE;
00853 }
00854 
00864 void
00865 bus_connections_foreach_active (BusConnections               *connections,
00866                                 BusConnectionForeachFunction  function,
00867                                 void                         *data)
00868 {
00869   foreach_active (connections, function, data);
00870 }
00871 
00880 void
00881 bus_connections_foreach (BusConnections               *connections,
00882                          BusConnectionForeachFunction  function,
00883                          void                         *data)
00884 {
00885   if (!foreach_active (connections, function, data))
00886     return;
00887 
00888   foreach_inactive (connections, function, data);
00889 }
00890 
00891 BusContext*
00892 bus_connections_get_context (BusConnections *connections)
00893 {
00894   return connections->context;
00895 }
00896 
00897 /*
00898  * This is used to avoid covering the same connection twice when
00899  * traversing connections. Note that it assumes we will
00900  * bus_connection_mark_stamp() each connection at least once per
00901  * INT_MAX increments of the global stamp, or wraparound would break
00902  * things.
00903  */
00904 void
00905 bus_connections_increment_stamp (BusConnections *connections)
00906 {
00907   connections->stamp += 1;
00908 }
00909 
00910 /* Mark connection with current stamp, return TRUE if it
00911  * didn't already have that stamp
00912  */
00913 dbus_bool_t
00914 bus_connection_mark_stamp (DBusConnection *connection)
00915 {
00916   BusConnectionData *d;
00917   
00918   d = BUS_CONNECTION_DATA (connection);
00919   
00920   _dbus_assert (d != NULL);
00921 
00922   if (d->stamp == d->connections->stamp)
00923     return FALSE;
00924   else
00925     {
00926       d->stamp = d->connections->stamp;
00927       return TRUE;
00928     }
00929 }
00930 
00931 BusContext*
00932 bus_connection_get_context (DBusConnection *connection)
00933 {
00934   BusConnectionData *d;
00935 
00936   d = BUS_CONNECTION_DATA (connection);
00937 
00938   _dbus_assert (d != NULL);
00939 
00940   return d->connections->context;
00941 }
00942 
00943 BusConnections*
00944 bus_connection_get_connections (DBusConnection *connection)
00945 {
00946   BusConnectionData *d;
00947     
00948   d = BUS_CONNECTION_DATA (connection);
00949 
00950   _dbus_assert (d != NULL);
00951 
00952   return d->connections;
00953 }
00954 
00955 BusRegistry*
00956 bus_connection_get_registry (DBusConnection *connection)
00957 {
00958   BusConnectionData *d;
00959 
00960   d = BUS_CONNECTION_DATA (connection);
00961 
00962   _dbus_assert (d != NULL);
00963 
00964   return bus_context_get_registry (d->connections->context);
00965 }
00966 
00967 BusActivation*
00968 bus_connection_get_activation (DBusConnection *connection)
00969 {
00970   BusConnectionData *d;
00971 
00972   d = BUS_CONNECTION_DATA (connection);
00973 
00974   _dbus_assert (d != NULL);
00975 
00976   return bus_context_get_activation (d->connections->context);
00977 }
00978 
00979 BusMatchmaker*
00980 bus_connection_get_matchmaker (DBusConnection *connection)
00981 {
00982   BusConnectionData *d;
00983 
00984   d = BUS_CONNECTION_DATA (connection);
00985 
00986   _dbus_assert (d != NULL);
00987 
00988   return bus_context_get_matchmaker (d->connections->context);
00989 }
00990 
00997 dbus_bool_t
00998 bus_connection_is_active (DBusConnection *connection)
00999 {
01000   BusConnectionData *d;
01001 
01002   d = BUS_CONNECTION_DATA (connection);
01003   
01004   return d != NULL && d->name != NULL;
01005 }
01006 
01007 dbus_bool_t
01008 bus_connection_preallocate_oom_error (DBusConnection *connection)
01009 {
01010   DBusMessage *message;
01011   DBusPreallocatedSend *preallocated;
01012   BusConnectionData *d;
01013 
01014   d = BUS_CONNECTION_DATA (connection);  
01015 
01016   _dbus_assert (d != NULL);
01017 
01018   if (d->oom_preallocated != NULL)
01019     return TRUE;
01020   
01021   preallocated = dbus_connection_preallocate_send (connection);
01022   if (preallocated == NULL)
01023     return FALSE;
01024 
01025   message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR);
01026 
01027   if (message == NULL)
01028     {
01029       dbus_connection_free_preallocated_send (connection, preallocated);
01030       return FALSE;
01031     }
01032 
01033   /* d->name may be NULL, but that is OK */
01034   if (!dbus_message_set_error_name (message, DBUS_ERROR_NO_MEMORY) ||
01035       !dbus_message_set_destination (message, d->name) ||
01036       !dbus_message_set_sender (message,
01037                                 DBUS_SERVICE_ORG_FREEDESKTOP_DBUS))
01038     {
01039       dbus_connection_free_preallocated_send (connection, preallocated);
01040       dbus_message_unref (message);
01041       return FALSE;
01042     }
01043   
01044   /* set reply serial to placeholder value just so space is already allocated
01045    * for it.
01046    */
01047   if (!dbus_message_set_reply_serial (message, 14))
01048     {
01049       dbus_connection_free_preallocated_send (connection, preallocated);
01050       dbus_message_unref (message);
01051       return FALSE;
01052     }
01053 
01054   d->oom_message = message;
01055   d->oom_preallocated = preallocated;
01056   
01057   return TRUE;
01058 }
01059 
01060 void
01061 bus_connection_send_oom_error (DBusConnection *connection,
01062                                DBusMessage    *in_reply_to)
01063 {
01064   BusConnectionData *d;
01065 
01066   d = BUS_CONNECTION_DATA (connection);  
01067 
01068   _dbus_assert (d != NULL);  
01069   _dbus_assert (d->oom_message != NULL);
01070 
01071   /* should always succeed since we set it to a placeholder earlier */
01072   if (!dbus_message_set_reply_serial (d->oom_message,
01073                                       dbus_message_get_serial (in_reply_to)))
01074     _dbus_assert_not_reached ("Failed to set reply serial for preallocated oom message");
01075 
01076   _dbus_assert (dbus_message_get_sender (d->oom_message) != NULL);
01077   
01078   dbus_connection_send_preallocated (connection, d->oom_preallocated,
01079                                      d->oom_message, NULL);
01080 
01081   dbus_message_unref (d->oom_message);
01082   d->oom_message = NULL;
01083   d->oom_preallocated = NULL;
01084 }
01085 
01086 void
01087 bus_connection_add_match_rule_link (DBusConnection *connection,
01088                                     DBusList       *link)
01089 {
01090   BusConnectionData *d;
01091 
01092   d = BUS_CONNECTION_DATA (connection);
01093   _dbus_assert (d != NULL);
01094 
01095   _dbus_list_append_link (&d->match_rules, link);
01096 
01097   d->n_match_rules += 1;
01098 }
01099 
01100 dbus_bool_t
01101 bus_connection_add_match_rule (DBusConnection *connection,
01102                                BusMatchRule   *rule)
01103 {
01104     DBusList *link;
01105 
01106   link = _dbus_list_alloc_link (rule);
01107 
01108   if (link == NULL)
01109     return FALSE;
01110 
01111   bus_connection_add_match_rule_link (connection, link);
01112 
01113   return TRUE;
01114 }
01115 
01116 void
01117 bus_connection_remove_match_rule (DBusConnection *connection,
01118                                   BusMatchRule   *rule)
01119 {
01120   BusConnectionData *d;
01121 
01122   d = BUS_CONNECTION_DATA (connection);
01123   _dbus_assert (d != NULL);
01124 
01125   _dbus_list_remove_last (&d->match_rules, rule);
01126 
01127   d->n_match_rules -= 1;
01128   _dbus_assert (d->n_match_rules >= 0);
01129 }
01130 
01131 int
01132 bus_connection_get_n_match_rules (DBusConnection *connection)
01133 {
01134   BusConnectionData *d;
01135 
01136   d = BUS_CONNECTION_DATA (connection);
01137   _dbus_assert (d != NULL);
01138   
01139   return d->n_match_rules;
01140 }
01141 
01142 void
01143 bus_connection_add_owned_service_link (DBusConnection *connection,
01144                                        DBusList       *link)
01145 {
01146   BusConnectionData *d;
01147 
01148   d = BUS_CONNECTION_DATA (connection);
01149   _dbus_assert (d != NULL);
01150 
01151   _dbus_list_append_link (&d->services_owned, link);
01152 
01153   d->n_services_owned += 1;
01154 }
01155 
01156 dbus_bool_t
01157 bus_connection_add_owned_service (DBusConnection *connection,
01158                                   BusService     *service)
01159 {
01160   DBusList *link;
01161 
01162   link = _dbus_list_alloc_link (service);
01163 
01164   if (link == NULL)
01165     return FALSE;
01166 
01167   bus_connection_add_owned_service_link (connection, link);
01168 
01169   return TRUE;
01170 }
01171 
01172 void
01173 bus_connection_remove_owned_service (DBusConnection *connection,
01174                                      BusService     *service)
01175 {
01176   BusConnectionData *d;
01177 
01178   d = BUS_CONNECTION_DATA (connection);
01179   _dbus_assert (d != NULL);
01180 
01181   _dbus_list_remove_last (&d->services_owned, service);
01182 
01183   d->n_services_owned -= 1;
01184   _dbus_assert (d->n_services_owned >= 0);
01185 }
01186 
01187 int
01188 bus_connection_get_n_services_owned (DBusConnection *connection)
01189 {
01190   BusConnectionData *d;
01191 
01192   d = BUS_CONNECTION_DATA (connection);
01193   _dbus_assert (d != NULL);
01194   
01195   return d->n_services_owned;
01196 }
01197 
01198 dbus_bool_t
01199 bus_connection_complete (DBusConnection   *connection,
01200                          const DBusString *name,
01201                          DBusError        *error)
01202 {
01203   BusConnectionData *d;
01204   unsigned long uid;
01205   
01206   d = BUS_CONNECTION_DATA (connection);
01207   _dbus_assert (d != NULL);
01208   _dbus_assert (d->name == NULL);
01209   _dbus_assert (d->policy == NULL);
01210 
01211   _dbus_assert (!bus_connection_is_active (connection));
01212   
01213   if (!_dbus_string_copy_data (name, &d->name))
01214     {
01215       BUS_SET_OOM (error);
01216       return FALSE;
01217     }
01218 
01219   _dbus_assert (d->name != NULL);
01220   
01221   _dbus_verbose ("Name %s assigned to %p\n", d->name, connection);
01222 
01223   d->policy = bus_context_create_client_policy (d->connections->context,
01224                                                 connection,
01225                                                 error);
01226 
01227   /* we may have a NULL policy on OOM or error getting list of
01228    * groups for a user. In the latter case we don't handle it so
01229    * well currently, as it will just keep failing over and over.
01230    */
01231 
01232   if (d->policy == NULL)
01233     {
01234       _dbus_verbose ("Failed to create security policy for connection %p\n",
01235                      connection);
01236       _DBUS_ASSERT_ERROR_IS_SET (error);
01237       dbus_free (d->name);
01238       d->name = NULL;
01239       return FALSE;
01240     }
01241   
01242   if (dbus_connection_get_unix_user (connection, &uid))
01243     {
01244       if (!adjust_connections_for_uid (d->connections,
01245                                        uid, 1))
01246         {
01247           BUS_SET_OOM (error);
01248           dbus_free (d->name);
01249           d->name = NULL;
01250           return FALSE;
01251         }
01252     }
01253   
01254   /* Now the connection is active, move it between lists */
01255   _dbus_list_unlink (&d->connections->incomplete,
01256                      d->link_in_connection_list);
01257   d->connections->n_incomplete -= 1;
01258   _dbus_list_append_link (&d->connections->completed,
01259                           d->link_in_connection_list);
01260   d->connections->n_completed += 1;
01261 
01262   _dbus_assert (d->connections->n_incomplete >= 0);
01263   _dbus_assert (d->connections->n_completed > 0);
01264 
01265   /* See if we can remove the timeout */
01266   bus_connections_expire_incomplete (d->connections);
01267 
01268   _dbus_assert (bus_connection_is_active (connection));
01269   
01270   return TRUE;
01271 }
01272 
01273 const char *
01274 bus_connection_get_name (DBusConnection *connection)
01275 {
01276   BusConnectionData *d;
01277   
01278   d = BUS_CONNECTION_DATA (connection);
01279   _dbus_assert (d != NULL);
01280   
01281   return d->name;
01282 }
01283 
01288 dbus_bool_t
01289 bus_connections_check_limits (BusConnections  *connections,
01290                               DBusConnection  *requesting_completion,
01291                               DBusError       *error)
01292 {
01293   BusConnectionData *d;
01294   unsigned long uid;
01295   
01296   d = BUS_CONNECTION_DATA (requesting_completion);
01297   _dbus_assert (d != NULL);
01298 
01299   _dbus_assert (d->name == NULL);
01300 
01301   if (connections->n_completed >=
01302       bus_context_get_max_completed_connections (connections->context))
01303     {
01304       dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
01305                       "The maximum number of active connections has been reached");
01306       return FALSE;
01307     }
01308   
01309   if (dbus_connection_get_unix_user (requesting_completion, &uid))
01310     {
01311       if (get_connections_for_uid (connections, uid) >=
01312           bus_context_get_max_connections_per_user (connections->context))
01313         {
01314           dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
01315                           "The maximum number of active connections for UID %lu has been reached",
01316                           uid);
01317           return FALSE;
01318         }
01319     }
01320   
01321   return TRUE;
01322 }
01323 
01324 
01325 /*
01326  * Transactions
01327  *
01328  * Note that this is fairly fragile; in particular, don't try to use
01329  * one transaction across any main loop iterations.
01330  */
01331 
01332 typedef struct
01333 {
01334   BusTransaction *transaction;
01335   DBusMessage    *message;
01336   DBusPreallocatedSend *preallocated;
01337 } MessageToSend;
01338 
01339 typedef struct
01340 {
01341   BusTransactionCancelFunction cancel_function;
01342   DBusFreeFunction free_data_function;
01343   void *data;
01344 } CancelHook;
01345 
01346 struct BusTransaction
01347 {
01348   DBusList *connections;
01349   BusContext *context;
01350   DBusList *cancel_hooks;
01351 };
01352 
01353 static void
01354 message_to_send_free (DBusConnection *connection,
01355                       MessageToSend  *to_send)
01356 {
01357   if (to_send->message)
01358     dbus_message_unref (to_send->message);
01359 
01360   if (to_send->preallocated)
01361     dbus_connection_free_preallocated_send (connection, to_send->preallocated);
01362 
01363   dbus_free (to_send);
01364 }
01365 
01366 static void
01367 cancel_hook_cancel (void *element,
01368                     void *data)
01369 {
01370   CancelHook *ch = element;
01371 
01372   _dbus_verbose ("Running transaction cancel hook\n");
01373   
01374   if (ch->cancel_function)
01375     (* ch->cancel_function) (ch->data);  
01376 }
01377 
01378 static void
01379 cancel_hook_free (void *element,
01380                   void *data)
01381 {
01382   CancelHook *ch = element;
01383 
01384   if (ch->free_data_function)
01385     (* ch->free_data_function) (ch->data);
01386 
01387   dbus_free (ch);
01388 }
01389 
01390 static void
01391 free_cancel_hooks (BusTransaction *transaction)
01392 {
01393   _dbus_list_foreach (&transaction->cancel_hooks,
01394                       cancel_hook_free, NULL);
01395   
01396   _dbus_list_clear (&transaction->cancel_hooks);
01397 }
01398 
01399 BusTransaction*
01400 bus_transaction_new (BusContext *context)
01401 {
01402   BusTransaction *transaction;
01403 
01404   transaction = dbus_new0 (BusTransaction, 1);
01405   if (transaction == NULL)
01406     return NULL;
01407 
01408   transaction->context = context;
01409   
01410   return transaction;
01411 }
01412 
01413 BusContext*
01414 bus_transaction_get_context (BusTransaction  *transaction)
01415 {
01416   return transaction->context;
01417 }
01418 
01419 BusConnections*
01420 bus_transaction_get_connections (BusTransaction  *transaction)
01421 {
01422   return bus_context_get_connections (transaction->context);
01423 }
01424 
01425 dbus_bool_t
01426 bus_transaction_send_from_driver (BusTransaction *transaction,
01427                                   DBusConnection *connection,
01428                                   DBusMessage    *message)
01429 {
01430   /* We have to set the sender to the driver, and have
01431    * to check security policy since it was not done in
01432    * dispatch.c
01433    */
01434   _dbus_verbose ("Sending %s %s %s from driver\n",
01435                  dbus_message_get_interface (message) ?
01436                  dbus_message_get_interface (message) : "(no interface)",
01437                  dbus_message_get_member (message) ?
01438                  dbus_message_get_member (message) : "(no member)",
01439                  dbus_message_get_error_name (message) ?
01440                  dbus_message_get_error_name (message) : "(no error name)");
01441                  
01442   if (!dbus_message_set_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS))
01443     return FALSE;
01444 
01445   /* If security policy doesn't allow the message, we silently
01446    * eat it; the driver doesn't care about getting a reply.
01447    */
01448   if (!bus_context_check_security_policy (bus_transaction_get_context (transaction),
01449                                           NULL, connection, connection, message, NULL))
01450     return TRUE;
01451 
01452   return bus_transaction_send (transaction, connection, message);
01453 }
01454 
01455 dbus_bool_t
01456 bus_transaction_send (BusTransaction *transaction,
01457                       DBusConnection *connection,
01458                       DBusMessage    *message)
01459 {
01460   MessageToSend *to_send;
01461   BusConnectionData *d;
01462   DBusList *link;
01463 
01464   _dbus_verbose ("  trying to add %s interface=%s member=%s error=%s to transaction%s\n",
01465                  dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ? "error" :
01466                  dbus_message_get_reply_serial (message) != 0 ? "reply" :
01467                  "message",
01468                  dbus_message_get_interface (message) ?
01469                  dbus_message_get_interface (message) : "(unset)",
01470                  dbus_message_get_member (message) ?
01471                  dbus_message_get_member (message) : "(unset)",
01472                  dbus_message_get_error_name (message) ?
01473                  dbus_message_get_error_name (message) : "(unset)",
01474                  dbus_connection_get_is_connected (connection) ?
01475                  "" : " (disconnected)");
01476 
01477   _dbus_assert (dbus_message_get_sender (message) != NULL);
01478   
01479   if (!dbus_connection_get_is_connected (connection))
01480     return TRUE; /* silently ignore disconnected connections */
01481   
01482   d = BUS_CONNECTION_DATA (connection);
01483   _dbus_assert (d != NULL);
01484   
01485   to_send = dbus_new (MessageToSend, 1);
01486   if (to_send == NULL)
01487     {
01488       return FALSE;
01489     }
01490 
01491   to_send->preallocated = dbus_connection_preallocate_send (connection);
01492   if (to_send->preallocated == NULL)
01493     {
01494       dbus_free (to_send);
01495       return FALSE;
01496     }  
01497   
01498   dbus_message_ref (message);
01499   to_send->message = message;
01500   to_send->transaction = transaction;
01501 
01502   _dbus_verbose ("about to prepend message\n");
01503   
01504   if (!_dbus_list_prepend (&d->transaction_messages, to_send))
01505     {
01506       message_to_send_free (connection, to_send);
01507       return FALSE;
01508     }
01509 
01510   _dbus_verbose ("prepended message\n");
01511   
01512   /* See if we already had this connection in the list
01513    * for this transaction. If we have a pending message,
01514    * then we should already be in transaction->connections
01515    */
01516   link = _dbus_list_get_first_link (&d->transaction_messages);
01517   _dbus_assert (link->data == to_send);
01518   link = _dbus_list_get_next_link (&d->transaction_messages, link);
01519   while (link != NULL)
01520     {
01521       MessageToSend *m = link->data;
01522       DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link);
01523       
01524       if (m->transaction == transaction)
01525         break;
01526         
01527       link = next;
01528     }
01529 
01530   if (link == NULL)
01531     {
01532       if (!_dbus_list_prepend (&transaction->connections, connection))
01533         {
01534           _dbus_list_remove (&d->transaction_messages, to_send);
01535           message_to_send_free (connection, to_send);
01536           return FALSE;
01537         }
01538     }
01539 
01540   return TRUE;
01541 }
01542 
01543 static void
01544 connection_cancel_transaction (DBusConnection *connection,
01545                                BusTransaction *transaction)
01546 {
01547   DBusList *link;
01548   BusConnectionData *d;
01549   
01550   d = BUS_CONNECTION_DATA (connection);
01551   _dbus_assert (d != NULL);
01552   
01553   link = _dbus_list_get_first_link (&d->transaction_messages);
01554   while (link != NULL)
01555     {
01556       MessageToSend *m = link->data;
01557       DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link);
01558       
01559       if (m->transaction == transaction)
01560         {
01561           _dbus_list_remove_link (&d->transaction_messages,
01562                                   link);
01563           
01564           message_to_send_free (connection, m);
01565         }
01566         
01567       link = next;
01568     }
01569 }
01570 
01571 void
01572 bus_transaction_cancel_and_free (BusTransaction *transaction)
01573 {
01574   DBusConnection *connection;
01575 
01576   _dbus_verbose ("TRANSACTION: cancelled\n");
01577   
01578   while ((connection = _dbus_list_pop_first (&transaction->connections)))
01579     connection_cancel_transaction (connection, transaction);
01580 
01581   _dbus_assert (transaction->connections == NULL);
01582 
01583   _dbus_list_foreach (&transaction->cancel_hooks,
01584                       cancel_hook_cancel, NULL);
01585 
01586   free_cancel_hooks (transaction);
01587   
01588   dbus_free (transaction);
01589 }
01590 
01591 static void
01592 connection_execute_transaction (DBusConnection *connection,
01593                                 BusTransaction *transaction)
01594 {
01595   DBusList *link;
01596   BusConnectionData *d;
01597   
01598   d = BUS_CONNECTION_DATA (connection);
01599   _dbus_assert (d != NULL);
01600 
01601   /* Send the queue in order (FIFO) */
01602   link = _dbus_list_get_last_link (&d->transaction_messages);
01603   while (link != NULL)
01604     {
01605       MessageToSend *m = link->data;
01606       DBusList *prev = _dbus_list_get_prev_link (&d->transaction_messages, link);
01607       
01608       if (m->transaction == transaction)
01609         {
01610           _dbus_list_remove_link (&d->transaction_messages,
01611                                   link);
01612 
01613           _dbus_assert (dbus_message_get_sender (m->message) != NULL);
01614           
01615           dbus_connection_send_preallocated (connection,
01616                                              m->preallocated,
01617                                              m->message,
01618                                              NULL);
01619 
01620           m->preallocated = NULL; /* so we don't double-free it */
01621           
01622           message_to_send_free (connection, m);
01623         }
01624         
01625       link = prev;
01626     }
01627 }
01628 
01629 void
01630 bus_transaction_execute_and_free (BusTransaction *transaction)
01631 {
01632   /* For each connection in transaction->connections
01633    * send the messages
01634    */
01635   DBusConnection *connection;
01636 
01637   _dbus_verbose ("TRANSACTION: executing\n");
01638   
01639   while ((connection = _dbus_list_pop_first (&transaction->connections)))
01640     connection_execute_transaction (connection, transaction);
01641 
01642   _dbus_assert (transaction->connections == NULL);
01643 
01644   free_cancel_hooks (transaction);
01645   
01646   dbus_free (transaction);
01647 }
01648 
01649 static void
01650 bus_connection_remove_transactions (DBusConnection *connection)
01651 {
01652   MessageToSend *to_send;
01653   BusConnectionData *d;
01654   
01655   d = BUS_CONNECTION_DATA (connection);
01656   _dbus_assert (d != NULL);
01657   
01658   while ((to_send = _dbus_list_get_first (&d->transaction_messages)))
01659     {
01660       /* only has an effect for the first MessageToSend listing this transaction */
01661       _dbus_list_remove (&to_send->transaction->connections,
01662                          connection);
01663 
01664       _dbus_list_remove (&d->transaction_messages, to_send);
01665       message_to_send_free (connection, to_send);
01666     }
01667 }
01668 
01672 dbus_bool_t
01673 bus_transaction_send_error_reply (BusTransaction  *transaction,
01674                                   DBusConnection  *connection,
01675                                   const DBusError *error,
01676                                   DBusMessage     *in_reply_to)
01677 {
01678   DBusMessage *reply;
01679   
01680   _dbus_assert (error != NULL);
01681   _DBUS_ASSERT_ERROR_IS_SET (error);
01682   
01683   _dbus_verbose ("Sending error reply %s \"%s\"\n",
01684                  error->name, error->message);
01685 
01686   reply = dbus_message_new_error (in_reply_to,
01687                                   error->name,
01688                                   error->message);
01689   if (reply == NULL)
01690     return FALSE;
01691 
01692   if (!bus_transaction_send_from_driver (transaction, connection, reply))
01693     {
01694       dbus_message_unref (reply);
01695       return FALSE;
01696     }
01697 
01698   dbus_message_unref (reply);
01699   
01700   return TRUE;
01701 }
01702 
01703 dbus_bool_t
01704 bus_transaction_add_cancel_hook (BusTransaction               *transaction,
01705                                  BusTransactionCancelFunction  cancel_function,
01706                                  void                         *data,
01707                                  DBusFreeFunction              free_data_function)
01708 {
01709   CancelHook *ch;
01710 
01711   ch = dbus_new (CancelHook, 1);
01712   if (ch == NULL)
01713     return FALSE;
01714   
01715   ch->cancel_function = cancel_function;
01716   ch->data = data;
01717   ch->free_data_function = free_data_function;
01718 
01719   /* It's important that the hooks get run in reverse order that they
01720    * were added
01721    */
01722   if (!_dbus_list_prepend (&transaction->cancel_hooks, ch))
01723     {
01724       dbus_free (ch);
01725       return FALSE;
01726     }
01727 
01728   return TRUE;
01729 }

Generated on Mon Sep 29 21:30:59 2003 for D-BUS by doxygen1.2.15