1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/ossrv/ofdbus/dbus/bus/connection.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,2225 @@
1.4 +/* -*- mode: C; c-file-style: "gnu" -*- */
1.5 +/* connection.c Client connections
1.6 + *
1.7 + * Copyright (C) 2003 Red Hat, Inc.
1.8 + * Portion Copyright © 2008 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
1.9 + * Licensed under the Academic Free License version 2.1
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify
1.12 + * it under the terms of the GNU General Public License as published by
1.13 + * the Free Software Foundation; either version 2 of the License, or
1.14 + * (at your option) any later version.
1.15 + *
1.16 + * This program is distributed in the hope that it will be useful,
1.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.19 + * GNU General Public License for more details.
1.20 + *
1.21 + * You should have received a copy of the GNU General Public License
1.22 + * along with this program; if not, write to the Free Software
1.23 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1.24 + *
1.25 + */
1.26 +#include "connection.h"
1.27 +#include "dispatch.h"
1.28 +#include "policy.h"
1.29 +#include "services.h"
1.30 +#include "utils.h"
1.31 +#include "signals.h"
1.32 +#include "expirelist.h"
1.33 +#include "selinux.h"
1.34 +#ifndef __SYMBIAN32__
1.35 +#include <dbus/dbus-list.h>
1.36 +#include <dbus/dbus-hash.h>
1.37 +#include <dbus/dbus-timeout.h>
1.38 +#else
1.39 +#include "dbus-list.h"
1.40 +#include "dbus-hash.h"
1.41 +#include "dbus-timeout.h"
1.42 +#endif //__SYMBIAN32__
1.43 +
1.44 +#ifdef __SYMBIAN32__
1.45 +#include "config.h"
1.46 +#endif //__SYMBIAN32__
1.47 +
1.48 +static void bus_connection_remove_transactions (DBusConnection *connection);
1.49 +
1.50 +typedef struct
1.51 +{
1.52 + BusExpireItem expire_item;
1.53 +
1.54 + DBusConnection *will_get_reply;
1.55 + DBusConnection *will_send_reply;
1.56 +
1.57 + dbus_uint32_t reply_serial;
1.58 +
1.59 +} BusPendingReply;
1.60 +
1.61 +struct BusConnections
1.62 +{
1.63 + int refcount;
1.64 + DBusList *completed; /**< List of all completed connections */
1.65 + int n_completed; /**< Length of completed list */
1.66 + DBusList *incomplete; /**< List of all not-yet-active connections */
1.67 + int n_incomplete; /**< Length of incomplete list */
1.68 + BusContext *context;
1.69 + DBusHashTable *completed_by_user; /**< Number of completed connections for each UID */
1.70 + DBusTimeout *expire_timeout; /**< Timeout for expiring incomplete connections. */
1.71 + int stamp; /**< Incrementing number */
1.72 + BusExpireList *pending_replies; /**< List of pending replies */
1.73 +};
1.74 +
1.75 +static dbus_int32_t connection_data_slot = -1;
1.76 +
1.77 +typedef struct
1.78 +{
1.79 + BusConnections *connections;
1.80 + DBusList *link_in_connection_list;
1.81 + DBusConnection *connection;
1.82 + DBusList *services_owned;
1.83 + int n_services_owned;
1.84 + DBusList *match_rules;
1.85 + int n_match_rules;
1.86 + char *name;
1.87 + DBusList *transaction_messages; /**< Stuff we need to send as part of a transaction */
1.88 + DBusMessage *oom_message;
1.89 + DBusPreallocatedSend *oom_preallocated;
1.90 + BusClientPolicy *policy;
1.91 +
1.92 + BusSELinuxID *selinux_id;
1.93 +
1.94 + long connection_tv_sec; /**< Time when we connected (seconds component) */
1.95 + long connection_tv_usec; /**< Time when we connected (microsec component) */
1.96 + int stamp; /**< connections->stamp last time we were traversed */
1.97 +} BusConnectionData;
1.98 +
1.99 +static dbus_bool_t bus_pending_reply_expired (BusExpireList *list,
1.100 + DBusList *link,
1.101 + void *data);
1.102 +
1.103 +static void bus_connection_drop_pending_replies (BusConnections *connections,
1.104 + DBusConnection *connection);
1.105 +
1.106 +static dbus_bool_t expire_incomplete_timeout (void *data);
1.107 +
1.108 +#define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot))
1.109 +
1.110 +static DBusLoop*
1.111 +connection_get_loop (DBusConnection *connection)
1.112 +{
1.113 + BusConnectionData *d;
1.114 +
1.115 + d = BUS_CONNECTION_DATA (connection);
1.116 +
1.117 + return bus_context_get_loop (d->connections->context);
1.118 +}
1.119 +
1.120 +
1.121 +static int
1.122 +get_connections_for_uid (BusConnections *connections,
1.123 + dbus_uid_t uid)
1.124 +{
1.125 + void *val;
1.126 + int current_count;
1.127 +
1.128 + /* val is NULL is 0 when it isn't in the hash yet */
1.129 +
1.130 + val = _dbus_hash_table_lookup_ulong (connections->completed_by_user,
1.131 + uid);
1.132 +
1.133 + current_count = _DBUS_POINTER_TO_INT (val);
1.134 +
1.135 + return current_count;
1.136 +}
1.137 +
1.138 +static dbus_bool_t
1.139 +adjust_connections_for_uid (BusConnections *connections,
1.140 + dbus_uid_t uid,
1.141 + int adjustment)
1.142 +{
1.143 + int current_count;
1.144 +
1.145 + current_count = get_connections_for_uid (connections, uid);
1.146 +
1.147 + _dbus_verbose ("Adjusting connection count for UID " DBUS_UID_FORMAT
1.148 + ": was %d adjustment %d making %d\n",
1.149 + uid, current_count, adjustment, current_count + adjustment);
1.150 +
1.151 + _dbus_assert (current_count >= 0);
1.152 +
1.153 + current_count += adjustment;
1.154 +
1.155 + _dbus_assert (current_count >= 0);
1.156 +
1.157 + if (current_count == 0)
1.158 + {
1.159 + _dbus_hash_table_remove_ulong (connections->completed_by_user, uid);
1.160 + return TRUE;
1.161 + }
1.162 + else
1.163 + {
1.164 + dbus_bool_t retval;
1.165 +
1.166 + retval = _dbus_hash_table_insert_ulong (connections->completed_by_user,
1.167 + uid, _DBUS_INT_TO_POINTER (current_count));
1.168 +
1.169 + /* only positive adjustment can fail as otherwise
1.170 + * a hash entry should already exist
1.171 + */
1.172 + _dbus_assert (adjustment > 0 ||
1.173 + (adjustment <= 0 && retval));
1.174 +
1.175 + return retval;
1.176 + }
1.177 +}
1.178 +
1.179 +void
1.180 +bus_connection_disconnected (DBusConnection *connection)
1.181 +{
1.182 + BusConnectionData *d;
1.183 + BusService *service;
1.184 + BusMatchmaker *matchmaker;
1.185 +
1.186 + d = BUS_CONNECTION_DATA (connection);
1.187 + _dbus_assert (d != NULL);
1.188 +
1.189 + _dbus_verbose ("%s disconnected, dropping all service ownership and releasing\n",
1.190 + d->name ? d->name : "(inactive)");
1.191 +
1.192 + /* Delete our match rules */
1.193 + if (d->n_match_rules > 0)
1.194 + {
1.195 + matchmaker = bus_context_get_matchmaker (d->connections->context);
1.196 + bus_matchmaker_disconnected (matchmaker, connection);
1.197 + }
1.198 +
1.199 + /* Drop any service ownership. Unfortunately, this requires
1.200 + * memory allocation and there doesn't seem to be a good way to
1.201 + * handle it other than sleeping; we can't "fail" the operation of
1.202 + * disconnecting a client, and preallocating a broadcast "service is
1.203 + * now gone" message for every client-service pair seems kind of
1.204 + * involved.
1.205 + */
1.206 + while ((service = _dbus_list_get_last (&d->services_owned)))
1.207 + {
1.208 + BusTransaction *transaction;
1.209 + DBusError error;
1.210 +
1.211 + retry:
1.212 +
1.213 + dbus_error_init (&error);
1.214 +
1.215 + while ((transaction = bus_transaction_new (d->connections->context)) == NULL)
1.216 + _dbus_wait_for_memory ();
1.217 +
1.218 + if (!bus_service_remove_owner (service, connection,
1.219 + transaction, &error))
1.220 + {
1.221 + _DBUS_ASSERT_ERROR_IS_SET (&error);
1.222 +
1.223 + if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
1.224 + {
1.225 + dbus_error_free (&error);
1.226 + bus_transaction_cancel_and_free (transaction);
1.227 + _dbus_wait_for_memory ();
1.228 + goto retry;
1.229 + }
1.230 + else
1.231 + {
1.232 + _dbus_verbose ("Failed to remove service owner: %s %s\n",
1.233 + error.name, error.message);
1.234 + _dbus_assert_not_reached ("Removing service owner failed for non-memory-related reason");
1.235 + }
1.236 + }
1.237 +
1.238 + bus_transaction_execute_and_free (transaction);
1.239 + }
1.240 +
1.241 + bus_dispatch_remove_connection (connection);
1.242 +
1.243 + /* no more watching */
1.244 + if (!dbus_connection_set_watch_functions (connection,
1.245 + NULL, NULL, NULL,
1.246 + connection,
1.247 + NULL))
1.248 + _dbus_assert_not_reached ("setting watch functions to NULL failed");
1.249 +
1.250 + if (!dbus_connection_set_timeout_functions (connection,
1.251 + NULL, NULL, NULL,
1.252 + connection,
1.253 + NULL))
1.254 + _dbus_assert_not_reached ("setting timeout functions to NULL failed");
1.255 +
1.256 + dbus_connection_set_unix_user_function (connection,
1.257 + NULL, NULL, NULL);
1.258 +
1.259 + dbus_connection_set_dispatch_status_function (connection,
1.260 + NULL, NULL, NULL);
1.261 +
1.262 + bus_connection_remove_transactions (connection);
1.263 +
1.264 + if (d->link_in_connection_list != NULL)
1.265 + {
1.266 + if (d->name != NULL)
1.267 + {
1.268 + unsigned long uid;
1.269 +
1.270 + _dbus_list_remove_link (&d->connections->completed, d->link_in_connection_list);
1.271 + d->link_in_connection_list = NULL;
1.272 + d->connections->n_completed -= 1;
1.273 +
1.274 + if (dbus_connection_get_unix_user (connection, &uid))
1.275 + {
1.276 + if (!adjust_connections_for_uid (d->connections,
1.277 + uid, -1))
1.278 + _dbus_assert_not_reached ("adjusting downward should never fail");
1.279 + }
1.280 + }
1.281 + else
1.282 + {
1.283 + _dbus_list_remove_link (&d->connections->incomplete, d->link_in_connection_list);
1.284 + d->link_in_connection_list = NULL;
1.285 + d->connections->n_incomplete -= 1;
1.286 + }
1.287 +
1.288 + _dbus_assert (d->connections->n_incomplete >= 0);
1.289 + _dbus_assert (d->connections->n_completed >= 0);
1.290 + }
1.291 +
1.292 + bus_connection_drop_pending_replies (d->connections, connection);
1.293 +
1.294 + /* frees "d" as side effect */
1.295 + dbus_connection_set_data (connection,
1.296 + connection_data_slot,
1.297 + NULL, NULL);
1.298 +
1.299 + dbus_connection_unref (connection);
1.300 +}
1.301 +
1.302 +static dbus_bool_t
1.303 +connection_watch_callback (DBusWatch *watch,
1.304 + unsigned int condition,
1.305 + void *data)
1.306 +{
1.307 + /* FIXME this can be done in dbus-mainloop.c
1.308 + * if the code in activation.c for the babysitter
1.309 + * watch handler is fixed.
1.310 + */
1.311 +
1.312 +#if 0
1.313 + _dbus_verbose ("Calling handle_watch\n");
1.314 +#endif
1.315 + return dbus_watch_handle (watch, condition);
1.316 +}
1.317 +
1.318 +static dbus_bool_t
1.319 +add_connection_watch (DBusWatch *watch,
1.320 + void *data)
1.321 +{
1.322 + DBusConnection *connection = data;
1.323 +
1.324 + return _dbus_loop_add_watch (connection_get_loop (connection),
1.325 + watch, connection_watch_callback, connection,
1.326 + NULL);
1.327 +}
1.328 +
1.329 +static void
1.330 +remove_connection_watch (DBusWatch *watch,
1.331 + void *data)
1.332 +{
1.333 + DBusConnection *connection = data;
1.334 +
1.335 + _dbus_loop_remove_watch (connection_get_loop (connection),
1.336 + watch, connection_watch_callback, connection);
1.337 +}
1.338 +
1.339 +static void
1.340 +connection_timeout_callback (DBusTimeout *timeout,
1.341 + void *data)
1.342 +{
1.343 + /* DBusConnection *connection = data; */
1.344 +
1.345 + /* can return FALSE on OOM but we just let it fire again later */
1.346 + dbus_timeout_handle (timeout);
1.347 +}
1.348 +
1.349 +static dbus_bool_t
1.350 +add_connection_timeout (DBusTimeout *timeout,
1.351 + void *data)
1.352 +{
1.353 + DBusConnection *connection = data;
1.354 +
1.355 + return _dbus_loop_add_timeout (connection_get_loop (connection),
1.356 + timeout, connection_timeout_callback, connection, NULL);
1.357 +}
1.358 +
1.359 +static void
1.360 +remove_connection_timeout (DBusTimeout *timeout,
1.361 + void *data)
1.362 +{
1.363 + DBusConnection *connection = data;
1.364 +
1.365 + _dbus_loop_remove_timeout (connection_get_loop (connection),
1.366 + timeout, connection_timeout_callback, connection);
1.367 +}
1.368 +
1.369 +static void
1.370 +dispatch_status_function (DBusConnection *connection,
1.371 + DBusDispatchStatus new_status,
1.372 + void *data)
1.373 +{
1.374 + DBusLoop *loop = data;
1.375 +
1.376 + if (new_status != DBUS_DISPATCH_COMPLETE)
1.377 + {
1.378 + while (!_dbus_loop_queue_dispatch (loop, connection))
1.379 + _dbus_wait_for_memory ();
1.380 + }
1.381 +}
1.382 +
1.383 +static dbus_bool_t
1.384 +allow_user_function (DBusConnection *connection,
1.385 + unsigned long uid,
1.386 + void *data)
1.387 +{
1.388 + BusConnectionData *d;
1.389 +
1.390 + d = BUS_CONNECTION_DATA (connection);
1.391 +
1.392 + _dbus_assert (d != NULL);
1.393 +
1.394 + return bus_context_allow_user (d->connections->context, uid);
1.395 +}
1.396 +
1.397 +static void
1.398 +free_connection_data (void *data)
1.399 +{
1.400 + BusConnectionData *d = data;
1.401 +
1.402 + /* services_owned should be NULL since we should be disconnected */
1.403 + _dbus_assert (d->services_owned == NULL);
1.404 + _dbus_assert (d->n_services_owned == 0);
1.405 + /* similarly */
1.406 + _dbus_assert (d->transaction_messages == NULL);
1.407 +
1.408 + if (d->oom_preallocated)
1.409 + dbus_connection_free_preallocated_send (d->connection, d->oom_preallocated);
1.410 +
1.411 + if (d->oom_message)
1.412 + dbus_message_unref (d->oom_message);
1.413 +
1.414 + if (d->policy)
1.415 + bus_client_policy_unref (d->policy);
1.416 +
1.417 + if (d->selinux_id)
1.418 + bus_selinux_id_unref (d->selinux_id);
1.419 +
1.420 + dbus_free (d->name);
1.421 +
1.422 + dbus_free (d);
1.423 +}
1.424 +
1.425 +static void
1.426 +call_timeout_callback (DBusTimeout *timeout,
1.427 + void *data)
1.428 +{
1.429 + /* can return FALSE on OOM but we just let it fire again later */
1.430 + dbus_timeout_handle (timeout);
1.431 +}
1.432 +
1.433 +BusConnections*
1.434 +bus_connections_new (BusContext *context)
1.435 +{
1.436 + BusConnections *connections;
1.437 +
1.438 + if (!dbus_connection_allocate_data_slot (&connection_data_slot))
1.439 + goto failed_0;
1.440 +
1.441 + connections = dbus_new0 (BusConnections, 1);
1.442 + if (connections == NULL)
1.443 + goto failed_1;
1.444 +
1.445 + connections->completed_by_user = _dbus_hash_table_new (DBUS_HASH_ULONG,
1.446 + NULL, NULL);
1.447 + if (connections->completed_by_user == NULL)
1.448 + goto failed_2;
1.449 +
1.450 + connections->expire_timeout = _dbus_timeout_new (100, /* irrelevant */
1.451 + expire_incomplete_timeout,
1.452 + connections, NULL);
1.453 + if (connections->expire_timeout == NULL)
1.454 + goto failed_3;
1.455 +
1.456 + _dbus_timeout_set_enabled (connections->expire_timeout, FALSE);
1.457 +
1.458 + connections->pending_replies = bus_expire_list_new (bus_context_get_loop (context),
1.459 + bus_context_get_reply_timeout (context),
1.460 + bus_pending_reply_expired,
1.461 + connections);
1.462 + if (connections->pending_replies == NULL)
1.463 + goto failed_4;
1.464 +
1.465 + if (!_dbus_loop_add_timeout (bus_context_get_loop (context),
1.466 + connections->expire_timeout,
1.467 + call_timeout_callback, NULL, NULL))
1.468 + goto failed_5;
1.469 +
1.470 + connections->refcount = 1;
1.471 + connections->context = context;
1.472 +
1.473 + return connections;
1.474 +
1.475 + failed_5:
1.476 + bus_expire_list_free (connections->pending_replies);
1.477 + failed_4:
1.478 + _dbus_timeout_unref (connections->expire_timeout);
1.479 + failed_3:
1.480 + _dbus_hash_table_unref (connections->completed_by_user);
1.481 + failed_2:
1.482 + dbus_free (connections);
1.483 + failed_1:
1.484 + dbus_connection_free_data_slot (&connection_data_slot);
1.485 + failed_0:
1.486 + return NULL;
1.487 +}
1.488 +
1.489 +BusConnections *
1.490 +bus_connections_ref (BusConnections *connections)
1.491 +{
1.492 + _dbus_assert (connections->refcount > 0);
1.493 + connections->refcount += 1;
1.494 +
1.495 + return connections;
1.496 +}
1.497 +
1.498 +void
1.499 +bus_connections_unref (BusConnections *connections)
1.500 +{
1.501 + _dbus_assert (connections->refcount > 0);
1.502 + connections->refcount -= 1;
1.503 + if (connections->refcount == 0)
1.504 + {
1.505 + /* drop all incomplete */
1.506 + while (connections->incomplete != NULL)
1.507 + {
1.508 + DBusConnection *connection;
1.509 +
1.510 + connection = connections->incomplete->data;
1.511 +
1.512 + dbus_connection_ref (connection);
1.513 + dbus_connection_close (connection);
1.514 + bus_connection_disconnected (connection);
1.515 + dbus_connection_unref (connection);
1.516 + }
1.517 +
1.518 + _dbus_assert (connections->n_incomplete == 0);
1.519 +
1.520 + /* drop all real connections */
1.521 + while (connections->completed != NULL)
1.522 + {
1.523 + DBusConnection *connection;
1.524 +
1.525 + connection = connections->completed->data;
1.526 +
1.527 + dbus_connection_ref (connection);
1.528 + dbus_connection_close (connection);
1.529 + bus_connection_disconnected (connection);
1.530 + dbus_connection_unref (connection);
1.531 + }
1.532 +
1.533 + _dbus_assert (connections->n_completed == 0);
1.534 +
1.535 + bus_expire_list_free (connections->pending_replies);
1.536 +
1.537 + _dbus_loop_remove_timeout (bus_context_get_loop (connections->context),
1.538 + connections->expire_timeout,
1.539 + call_timeout_callback, NULL);
1.540 +
1.541 + _dbus_timeout_unref (connections->expire_timeout);
1.542 +
1.543 + _dbus_hash_table_unref (connections->completed_by_user);
1.544 +
1.545 + dbus_free (connections);
1.546 +
1.547 + dbus_connection_free_data_slot (&connection_data_slot);
1.548 + }
1.549 +}
1.550 +
1.551 +dbus_bool_t
1.552 +bus_connections_setup_connection (BusConnections *connections,
1.553 + DBusConnection *connection)
1.554 +{
1.555 + BusConnectionData *d;
1.556 + dbus_bool_t retval;
1.557 + DBusError error;
1.558 +
1.559 + d = dbus_new0 (BusConnectionData, 1);
1.560 +
1.561 + if (d == NULL)
1.562 + return FALSE;
1.563 +
1.564 + d->connections = connections;
1.565 + d->connection = connection;
1.566 +
1.567 + _dbus_get_current_time (&d->connection_tv_sec,
1.568 + &d->connection_tv_usec);
1.569 +
1.570 + _dbus_assert (connection_data_slot >= 0);
1.571 +
1.572 + if (!dbus_connection_set_data (connection,
1.573 + connection_data_slot,
1.574 + d, free_connection_data))
1.575 + {
1.576 + dbus_free (d);
1.577 + return FALSE;
1.578 + }
1.579 +
1.580 + dbus_connection_set_route_peer_messages (connection, TRUE);
1.581 +
1.582 + retval = FALSE;
1.583 +
1.584 + dbus_error_init (&error);
1.585 + d->selinux_id = bus_selinux_init_connection_id (connection,
1.586 + &error);
1.587 + if (dbus_error_is_set (&error))
1.588 + {
1.589 + /* This is a bit bogus because we pretend all errors
1.590 + * are OOM; this is done because we know that in bus.c
1.591 + * an OOM error disconnects the connection, which is
1.592 + * the same thing we want on any other error.
1.593 + */
1.594 + dbus_error_free (&error);
1.595 + goto out;
1.596 + }
1.597 +
1.598 + if (!dbus_connection_set_watch_functions (connection,
1.599 + add_connection_watch,
1.600 + remove_connection_watch,
1.601 + NULL,
1.602 + connection,
1.603 + NULL))
1.604 + goto out;
1.605 +
1.606 + if (!dbus_connection_set_timeout_functions (connection,
1.607 + add_connection_timeout,
1.608 + remove_connection_timeout,
1.609 + NULL,
1.610 + connection, NULL))
1.611 + goto out;
1.612 +
1.613 + dbus_connection_set_unix_user_function (connection,
1.614 + allow_user_function,
1.615 + NULL, NULL);
1.616 +
1.617 + dbus_connection_set_dispatch_status_function (connection,
1.618 + dispatch_status_function,
1.619 + bus_context_get_loop (connections->context),
1.620 + NULL);
1.621 +
1.622 + d->link_in_connection_list = _dbus_list_alloc_link (connection);
1.623 + if (d->link_in_connection_list == NULL)
1.624 + goto out;
1.625 +
1.626 + /* Setup the connection with the dispatcher */
1.627 + if (!bus_dispatch_add_connection (connection))
1.628 + goto out;
1.629 +
1.630 + if (dbus_connection_get_dispatch_status (connection) != DBUS_DISPATCH_COMPLETE)
1.631 + {
1.632 + if (!_dbus_loop_queue_dispatch (bus_context_get_loop (connections->context), connection))
1.633 + {
1.634 + bus_dispatch_remove_connection (connection);
1.635 + goto out;
1.636 + }
1.637 + }
1.638 +
1.639 + _dbus_list_append_link (&connections->incomplete, d->link_in_connection_list);
1.640 + connections->n_incomplete += 1;
1.641 +
1.642 + dbus_connection_ref (connection);
1.643 +
1.644 + /* Note that we might disconnect ourselves here, but it only takes
1.645 + * effect on return to the main loop. We call this to free up
1.646 + * expired connections if possible, and to queue the timeout for our
1.647 + * own expiration.
1.648 + */
1.649 + bus_connections_expire_incomplete (connections);
1.650 +
1.651 + /* And we might also disconnect ourselves here, but again it
1.652 + * only takes effect on return to main loop.
1.653 + */
1.654 + if (connections->n_incomplete >
1.655 + bus_context_get_max_incomplete_connections (connections->context))
1.656 + {
1.657 + _dbus_verbose ("Number of incomplete connections exceeds max, dropping oldest one\n");
1.658 +
1.659 + _dbus_assert (connections->incomplete != NULL);
1.660 + /* Disconnect the oldest unauthenticated connection. FIXME
1.661 + * would it be more secure to drop a *random* connection? This
1.662 + * algorithm seems to mean that if someone can create new
1.663 + * connections quickly enough, they can keep anyone else from
1.664 + * completing authentication. But random may or may not really
1.665 + * help with that, a more elaborate solution might be required.
1.666 + */
1.667 + dbus_connection_close (connections->incomplete->data);
1.668 + }
1.669 +
1.670 + retval = TRUE;
1.671 +
1.672 + out:
1.673 + if (!retval)
1.674 + {
1.675 + if (d->selinux_id)
1.676 + bus_selinux_id_unref (d->selinux_id);
1.677 + d->selinux_id = NULL;
1.678 +
1.679 + if (!dbus_connection_set_watch_functions (connection,
1.680 + NULL, NULL, NULL,
1.681 + connection,
1.682 + NULL))
1.683 + _dbus_assert_not_reached ("setting watch functions to NULL failed");
1.684 +
1.685 + if (!dbus_connection_set_timeout_functions (connection,
1.686 + NULL, NULL, NULL,
1.687 + connection,
1.688 + NULL))
1.689 + _dbus_assert_not_reached ("setting timeout functions to NULL failed");
1.690 +
1.691 + dbus_connection_set_unix_user_function (connection,
1.692 + NULL, NULL, NULL);
1.693 +
1.694 + dbus_connection_set_dispatch_status_function (connection,
1.695 + NULL, NULL, NULL);
1.696 +
1.697 + if (d->link_in_connection_list != NULL)
1.698 + {
1.699 + _dbus_assert (d->link_in_connection_list->next == NULL);
1.700 + _dbus_assert (d->link_in_connection_list->prev == NULL);
1.701 + _dbus_list_free_link (d->link_in_connection_list);
1.702 + d->link_in_connection_list = NULL;
1.703 + }
1.704 +
1.705 + if (!dbus_connection_set_data (connection,
1.706 + connection_data_slot,
1.707 + NULL, NULL))
1.708 + _dbus_assert_not_reached ("failed to set connection data to null");
1.709 +
1.710 + /* "d" has now been freed */
1.711 + }
1.712 +
1.713 + return retval;
1.714 +}
1.715 +
1.716 +void
1.717 +bus_connections_expire_incomplete (BusConnections *connections)
1.718 +{
1.719 + int next_interval;
1.720 +
1.721 + next_interval = -1;
1.722 +
1.723 + if (connections->incomplete != NULL)
1.724 + {
1.725 + long tv_sec, tv_usec;
1.726 + DBusList *link;
1.727 + int auth_timeout;
1.728 +
1.729 + _dbus_get_current_time (&tv_sec, &tv_usec);
1.730 + auth_timeout = bus_context_get_auth_timeout (connections->context);
1.731 +
1.732 + link = _dbus_list_get_first_link (&connections->incomplete);
1.733 + while (link != NULL)
1.734 + {
1.735 + DBusList *next = _dbus_list_get_next_link (&connections->incomplete, link);
1.736 + DBusConnection *connection;
1.737 + BusConnectionData *d;
1.738 + double elapsed;
1.739 +
1.740 + connection = link->data;
1.741 +
1.742 + d = BUS_CONNECTION_DATA (connection);
1.743 +
1.744 + _dbus_assert (d != NULL);
1.745 +
1.746 + elapsed = ELAPSED_MILLISECONDS_SINCE (d->connection_tv_sec,
1.747 + d->connection_tv_usec,
1.748 + tv_sec, tv_usec);
1.749 +
1.750 + if (elapsed >= (double) auth_timeout)
1.751 + {
1.752 + _dbus_verbose ("Timing out authentication for connection %p\n", connection);
1.753 + dbus_connection_close (connection);
1.754 + }
1.755 + else
1.756 + {
1.757 + /* We can end the loop, since the connections are in oldest-first order */
1.758 + next_interval = ((double)auth_timeout) - elapsed;
1.759 + _dbus_verbose ("Connection %p authentication expires in %d milliseconds\n",
1.760 + connection, next_interval);
1.761 +
1.762 + break;
1.763 + }
1.764 +
1.765 + link = next;
1.766 + }
1.767 + }
1.768 +
1.769 + bus_expire_timeout_set_interval (connections->expire_timeout,
1.770 + next_interval);
1.771 +}
1.772 +
1.773 +static dbus_bool_t
1.774 +expire_incomplete_timeout (void *data)
1.775 +{
1.776 + BusConnections *connections = data;
1.777 +
1.778 + _dbus_verbose ("Running %s\n", _DBUS_FUNCTION_NAME);
1.779 +
1.780 + /* note that this may remove the timeout */
1.781 + bus_connections_expire_incomplete (connections);
1.782 +
1.783 + return TRUE;
1.784 +}
1.785 +
1.786 +dbus_bool_t
1.787 +bus_connection_get_groups (DBusConnection *connection,
1.788 + unsigned long **groups,
1.789 + int *n_groups,
1.790 + DBusError *error)
1.791 +{
1.792 + BusConnectionData *d;
1.793 + unsigned long uid;
1.794 + DBusUserDatabase *user_database;
1.795 +
1.796 + d = BUS_CONNECTION_DATA (connection);
1.797 +
1.798 + _dbus_assert (d != NULL);
1.799 +
1.800 + user_database = bus_context_get_user_database (d->connections->context);
1.801 +
1.802 + *groups = NULL;
1.803 + *n_groups = 0;
1.804 +
1.805 + if (dbus_connection_get_unix_user (connection, &uid))
1.806 + {
1.807 + if (!_dbus_user_database_get_groups (user_database,
1.808 + uid, groups, n_groups,
1.809 + error))
1.810 + {
1.811 + _DBUS_ASSERT_ERROR_IS_SET (error);
1.812 + _dbus_verbose ("Did not get any groups for UID %lu\n",
1.813 + uid);
1.814 + return FALSE;
1.815 + }
1.816 + else
1.817 + {
1.818 + _dbus_verbose ("Got %d groups for UID %lu\n",
1.819 + *n_groups, uid);
1.820 + return TRUE;
1.821 + }
1.822 + }
1.823 + else
1.824 + return TRUE; /* successfully got 0 groups */
1.825 +}
1.826 +
1.827 +dbus_bool_t
1.828 +bus_connection_is_in_group (DBusConnection *connection,
1.829 + unsigned long gid)
1.830 +{
1.831 + int i;
1.832 + unsigned long *group_ids;
1.833 + int n_group_ids;
1.834 +
1.835 + if (!bus_connection_get_groups (connection, &group_ids, &n_group_ids,
1.836 + NULL))
1.837 + return FALSE;
1.838 +
1.839 + i = 0;
1.840 + while (i < n_group_ids)
1.841 + {
1.842 + if (group_ids[i] == gid)
1.843 + {
1.844 + dbus_free (group_ids);
1.845 + return TRUE;
1.846 + }
1.847 + ++i;
1.848 + }
1.849 +
1.850 + dbus_free (group_ids);
1.851 + return FALSE;
1.852 +}
1.853 +
1.854 +BusClientPolicy*
1.855 +bus_connection_get_policy (DBusConnection *connection)
1.856 +{
1.857 + BusConnectionData *d;
1.858 +
1.859 + d = BUS_CONNECTION_DATA (connection);
1.860 +
1.861 + _dbus_assert (d != NULL);
1.862 + _dbus_assert (d->policy != NULL);
1.863 +
1.864 + return d->policy;
1.865 +}
1.866 +
1.867 +static dbus_bool_t
1.868 +foreach_active (BusConnections *connections,
1.869 + BusConnectionForeachFunction function,
1.870 + void *data)
1.871 +{
1.872 + DBusList *link;
1.873 +
1.874 + link = _dbus_list_get_first_link (&connections->completed);
1.875 + while (link != NULL)
1.876 + {
1.877 + DBusConnection *connection = link->data;
1.878 + DBusList *next = _dbus_list_get_next_link (&connections->completed, link);
1.879 +
1.880 + if (!(* function) (connection, data))
1.881 + return FALSE;
1.882 +
1.883 + link = next;
1.884 + }
1.885 +
1.886 + return TRUE;
1.887 +}
1.888 +
1.889 +static dbus_bool_t
1.890 +foreach_inactive (BusConnections *connections,
1.891 + BusConnectionForeachFunction function,
1.892 + void *data)
1.893 +{
1.894 + DBusList *link;
1.895 +
1.896 + link = _dbus_list_get_first_link (&connections->incomplete);
1.897 + while (link != NULL)
1.898 + {
1.899 + DBusConnection *connection = link->data;
1.900 + DBusList *next = _dbus_list_get_next_link (&connections->incomplete, link);
1.901 +
1.902 + if (!(* function) (connection, data))
1.903 + return FALSE;
1.904 +
1.905 + link = next;
1.906 + }
1.907 +
1.908 + return TRUE;
1.909 +}
1.910 +
1.911 +/**
1.912 + * Calls function on each active connection; if the function returns
1.913 + * #FALSE, stops iterating. Active connections are authenticated
1.914 + * and have sent a Hello message.
1.915 + *
1.916 + * @param connections the connections object
1.917 + * @param function the function
1.918 + * @param data data to pass to it as a second arg
1.919 + */
1.920 +void
1.921 +bus_connections_foreach_active (BusConnections *connections,
1.922 + BusConnectionForeachFunction function,
1.923 + void *data)
1.924 +{
1.925 + foreach_active (connections, function, data);
1.926 +}
1.927 +
1.928 +/**
1.929 + * Calls function on each connection; if the function returns
1.930 + * #FALSE, stops iterating.
1.931 + *
1.932 + * @param connections the connections object
1.933 + * @param function the function
1.934 + * @param data data to pass to it as a second arg
1.935 + */
1.936 +void
1.937 +bus_connections_foreach (BusConnections *connections,
1.938 + BusConnectionForeachFunction function,
1.939 + void *data)
1.940 +{
1.941 + if (!foreach_active (connections, function, data))
1.942 + return;
1.943 +
1.944 + foreach_inactive (connections, function, data);
1.945 +}
1.946 +
1.947 +BusContext*
1.948 +bus_connections_get_context (BusConnections *connections)
1.949 +{
1.950 + return connections->context;
1.951 +}
1.952 +
1.953 +/*
1.954 + * This is used to avoid covering the same connection twice when
1.955 + * traversing connections. Note that it assumes we will
1.956 + * bus_connection_mark_stamp() each connection at least once per
1.957 + * INT_MAX increments of the global stamp, or wraparound would break
1.958 + * things.
1.959 + */
1.960 +void
1.961 +bus_connections_increment_stamp (BusConnections *connections)
1.962 +{
1.963 + connections->stamp += 1;
1.964 +}
1.965 +
1.966 +/* Mark connection with current stamp, return TRUE if it
1.967 + * didn't already have that stamp
1.968 + */
1.969 +dbus_bool_t
1.970 +bus_connection_mark_stamp (DBusConnection *connection)
1.971 +{
1.972 + BusConnectionData *d;
1.973 +
1.974 + d = BUS_CONNECTION_DATA (connection);
1.975 +
1.976 + _dbus_assert (d != NULL);
1.977 +
1.978 + if (d->stamp == d->connections->stamp)
1.979 + return FALSE;
1.980 + else
1.981 + {
1.982 + d->stamp = d->connections->stamp;
1.983 + return TRUE;
1.984 + }
1.985 +}
1.986 +
1.987 +BusContext*
1.988 +bus_connection_get_context (DBusConnection *connection)
1.989 +{
1.990 + BusConnectionData *d;
1.991 +
1.992 + d = BUS_CONNECTION_DATA (connection);
1.993 +
1.994 + _dbus_assert (d != NULL);
1.995 +
1.996 + return d->connections->context;
1.997 +}
1.998 +
1.999 +BusConnections*
1.1000 +bus_connection_get_connections (DBusConnection *connection)
1.1001 +{
1.1002 + BusConnectionData *d;
1.1003 +
1.1004 + d = BUS_CONNECTION_DATA (connection);
1.1005 +
1.1006 + _dbus_assert (d != NULL);
1.1007 +
1.1008 + return d->connections;
1.1009 +}
1.1010 +
1.1011 +BusRegistry*
1.1012 +bus_connection_get_registry (DBusConnection *connection)
1.1013 +{
1.1014 + BusConnectionData *d;
1.1015 +
1.1016 + d = BUS_CONNECTION_DATA (connection);
1.1017 +
1.1018 + _dbus_assert (d != NULL);
1.1019 +
1.1020 + return bus_context_get_registry (d->connections->context);
1.1021 +}
1.1022 +
1.1023 +BusActivation*
1.1024 +bus_connection_get_activation (DBusConnection *connection)
1.1025 +{
1.1026 + BusConnectionData *d;
1.1027 +
1.1028 + d = BUS_CONNECTION_DATA (connection);
1.1029 +
1.1030 + _dbus_assert (d != NULL);
1.1031 +
1.1032 + return bus_context_get_activation (d->connections->context);
1.1033 +}
1.1034 +
1.1035 +BusMatchmaker*
1.1036 +bus_connection_get_matchmaker (DBusConnection *connection)
1.1037 +{
1.1038 + BusConnectionData *d;
1.1039 +
1.1040 + d = BUS_CONNECTION_DATA (connection);
1.1041 +
1.1042 + _dbus_assert (d != NULL);
1.1043 +
1.1044 + return bus_context_get_matchmaker (d->connections->context);
1.1045 +}
1.1046 +
1.1047 +BusSELinuxID*
1.1048 +bus_connection_get_selinux_id (DBusConnection *connection)
1.1049 +{
1.1050 + BusConnectionData *d;
1.1051 +
1.1052 + d = BUS_CONNECTION_DATA (connection);
1.1053 +
1.1054 + _dbus_assert (d != NULL);
1.1055 +
1.1056 + return d->selinux_id;
1.1057 +}
1.1058 +
1.1059 +/**
1.1060 + * Checks whether the connection is registered with the message bus.
1.1061 + *
1.1062 + * @param connection the connection
1.1063 + * @returns #TRUE if we're an active message bus participant
1.1064 + */
1.1065 +dbus_bool_t
1.1066 +bus_connection_is_active (DBusConnection *connection)
1.1067 +{
1.1068 + BusConnectionData *d;
1.1069 +
1.1070 + d = BUS_CONNECTION_DATA (connection);
1.1071 +
1.1072 + return d != NULL && d->name != NULL;
1.1073 +}
1.1074 +
1.1075 +dbus_bool_t
1.1076 +bus_connection_preallocate_oom_error (DBusConnection *connection)
1.1077 +{
1.1078 + DBusMessage *message;
1.1079 + DBusPreallocatedSend *preallocated;
1.1080 + BusConnectionData *d;
1.1081 +
1.1082 + d = BUS_CONNECTION_DATA (connection);
1.1083 +
1.1084 + _dbus_assert (d != NULL);
1.1085 +
1.1086 + if (d->oom_preallocated != NULL)
1.1087 + return TRUE;
1.1088 +
1.1089 + preallocated = dbus_connection_preallocate_send (connection);
1.1090 + if (preallocated == NULL)
1.1091 + return FALSE;
1.1092 +
1.1093 + message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR);
1.1094 +
1.1095 + if (message == NULL)
1.1096 + {
1.1097 + dbus_connection_free_preallocated_send (connection, preallocated);
1.1098 + return FALSE;
1.1099 + }
1.1100 +
1.1101 + /* d->name may be NULL, but that is OK */
1.1102 + if (!dbus_message_set_error_name (message, DBUS_ERROR_NO_MEMORY) ||
1.1103 + !dbus_message_set_destination (message, d->name) ||
1.1104 + !dbus_message_set_sender (message,
1.1105 + DBUS_SERVICE_DBUS))
1.1106 + {
1.1107 + dbus_connection_free_preallocated_send (connection, preallocated);
1.1108 + dbus_message_unref (message);
1.1109 + return FALSE;
1.1110 + }
1.1111 +
1.1112 + /* set reply serial to placeholder value just so space is already allocated
1.1113 + * for it.
1.1114 + */
1.1115 + if (!dbus_message_set_reply_serial (message, 14))
1.1116 + {
1.1117 + dbus_connection_free_preallocated_send (connection, preallocated);
1.1118 + dbus_message_unref (message);
1.1119 + return FALSE;
1.1120 + }
1.1121 +
1.1122 + d->oom_message = message;
1.1123 + d->oom_preallocated = preallocated;
1.1124 +
1.1125 + return TRUE;
1.1126 +}
1.1127 +
1.1128 +void
1.1129 +bus_connection_send_oom_error (DBusConnection *connection,
1.1130 + DBusMessage *in_reply_to)
1.1131 +{
1.1132 + BusConnectionData *d;
1.1133 +
1.1134 + d = BUS_CONNECTION_DATA (connection);
1.1135 +
1.1136 + _dbus_assert (d != NULL);
1.1137 + _dbus_assert (d->oom_message != NULL);
1.1138 +
1.1139 + /* should always succeed since we set it to a placeholder earlier */
1.1140 + if (!dbus_message_set_reply_serial (d->oom_message,
1.1141 + dbus_message_get_serial (in_reply_to)))
1.1142 + _dbus_assert_not_reached ("Failed to set reply serial for preallocated oom message");
1.1143 +
1.1144 + _dbus_assert (dbus_message_get_sender (d->oom_message) != NULL);
1.1145 +
1.1146 + dbus_connection_send_preallocated (connection, d->oom_preallocated,
1.1147 + d->oom_message, NULL);
1.1148 +
1.1149 + dbus_message_unref (d->oom_message);
1.1150 + d->oom_message = NULL;
1.1151 + d->oom_preallocated = NULL;
1.1152 +}
1.1153 +
1.1154 +void
1.1155 +bus_connection_add_match_rule_link (DBusConnection *connection,
1.1156 + DBusList *link)
1.1157 +{
1.1158 + BusConnectionData *d;
1.1159 +
1.1160 + d = BUS_CONNECTION_DATA (connection);
1.1161 + _dbus_assert (d != NULL);
1.1162 +
1.1163 + _dbus_list_append_link (&d->match_rules, link);
1.1164 +
1.1165 + d->n_match_rules += 1;
1.1166 +}
1.1167 +
1.1168 +dbus_bool_t
1.1169 +bus_connection_add_match_rule (DBusConnection *connection,
1.1170 + BusMatchRule *rule)
1.1171 +{
1.1172 + DBusList *link;
1.1173 +
1.1174 + link = _dbus_list_alloc_link (rule);
1.1175 +
1.1176 + if (link == NULL)
1.1177 + return FALSE;
1.1178 +
1.1179 + bus_connection_add_match_rule_link (connection, link);
1.1180 +
1.1181 + return TRUE;
1.1182 +}
1.1183 +
1.1184 +void
1.1185 +bus_connection_remove_match_rule (DBusConnection *connection,
1.1186 + BusMatchRule *rule)
1.1187 +{
1.1188 + BusConnectionData *d;
1.1189 +
1.1190 + d = BUS_CONNECTION_DATA (connection);
1.1191 + _dbus_assert (d != NULL);
1.1192 +
1.1193 + _dbus_list_remove_last (&d->match_rules, rule);
1.1194 +
1.1195 + d->n_match_rules -= 1;
1.1196 + _dbus_assert (d->n_match_rules >= 0);
1.1197 +}
1.1198 +
1.1199 +int
1.1200 +bus_connection_get_n_match_rules (DBusConnection *connection)
1.1201 +{
1.1202 + BusConnectionData *d;
1.1203 +
1.1204 + d = BUS_CONNECTION_DATA (connection);
1.1205 + _dbus_assert (d != NULL);
1.1206 +
1.1207 + return d->n_match_rules;
1.1208 +}
1.1209 +
1.1210 +void
1.1211 +bus_connection_add_owned_service_link (DBusConnection *connection,
1.1212 + DBusList *link)
1.1213 +{
1.1214 + BusConnectionData *d;
1.1215 +
1.1216 + d = BUS_CONNECTION_DATA (connection);
1.1217 + _dbus_assert (d != NULL);
1.1218 +
1.1219 + _dbus_list_append_link (&d->services_owned, link);
1.1220 +
1.1221 + d->n_services_owned += 1;
1.1222 +}
1.1223 +
1.1224 +dbus_bool_t
1.1225 +bus_connection_add_owned_service (DBusConnection *connection,
1.1226 + BusService *service)
1.1227 +{
1.1228 + DBusList *link;
1.1229 +
1.1230 + link = _dbus_list_alloc_link (service);
1.1231 +
1.1232 + if (link == NULL)
1.1233 + return FALSE;
1.1234 +
1.1235 + bus_connection_add_owned_service_link (connection, link);
1.1236 +
1.1237 + return TRUE;
1.1238 +}
1.1239 +
1.1240 +void
1.1241 +bus_connection_remove_owned_service (DBusConnection *connection,
1.1242 + BusService *service)
1.1243 +{
1.1244 + BusConnectionData *d;
1.1245 +
1.1246 + d = BUS_CONNECTION_DATA (connection);
1.1247 + _dbus_assert (d != NULL);
1.1248 +
1.1249 + _dbus_list_remove_last (&d->services_owned, service);
1.1250 +
1.1251 + d->n_services_owned -= 1;
1.1252 + _dbus_assert (d->n_services_owned >= 0);
1.1253 +}
1.1254 +
1.1255 +int
1.1256 +bus_connection_get_n_services_owned (DBusConnection *connection)
1.1257 +{
1.1258 + BusConnectionData *d;
1.1259 +
1.1260 + d = BUS_CONNECTION_DATA (connection);
1.1261 + _dbus_assert (d != NULL);
1.1262 +
1.1263 + return d->n_services_owned;
1.1264 +}
1.1265 +
1.1266 +dbus_bool_t
1.1267 +bus_connection_complete (DBusConnection *connection,
1.1268 + const DBusString *name,
1.1269 + DBusError *error)
1.1270 +{
1.1271 + BusConnectionData *d;
1.1272 + unsigned long uid;
1.1273 +
1.1274 + d = BUS_CONNECTION_DATA (connection);
1.1275 + _dbus_assert (d != NULL);
1.1276 + _dbus_assert (d->name == NULL);
1.1277 + _dbus_assert (d->policy == NULL);
1.1278 +
1.1279 + _dbus_assert (!bus_connection_is_active (connection));
1.1280 +
1.1281 + if (!_dbus_string_copy_data (name, &d->name))
1.1282 + {
1.1283 + BUS_SET_OOM (error);
1.1284 + return FALSE;
1.1285 + }
1.1286 +
1.1287 + _dbus_assert (d->name != NULL);
1.1288 +
1.1289 + _dbus_verbose ("Name %s assigned to %p\n", d->name, connection);
1.1290 +
1.1291 + d->policy = bus_context_create_client_policy (d->connections->context,
1.1292 + connection,
1.1293 + error);
1.1294 +
1.1295 + /* we may have a NULL policy on OOM or error getting list of
1.1296 + * groups for a user. In the latter case we don't handle it so
1.1297 + * well currently, as it will just keep failing over and over.
1.1298 + */
1.1299 +
1.1300 + if (d->policy == NULL)
1.1301 + {
1.1302 + _dbus_verbose ("Failed to create security policy for connection %p\n",
1.1303 + connection);
1.1304 + _DBUS_ASSERT_ERROR_IS_SET (error);
1.1305 + dbus_free (d->name);
1.1306 + d->name = NULL;
1.1307 + return FALSE;
1.1308 + }
1.1309 +
1.1310 + if (dbus_connection_get_unix_user (connection, &uid))
1.1311 + {
1.1312 + if (!adjust_connections_for_uid (d->connections,
1.1313 + uid, 1))
1.1314 + {
1.1315 + BUS_SET_OOM (error);
1.1316 + dbus_free (d->name);
1.1317 + d->name = NULL;
1.1318 + return FALSE;
1.1319 + }
1.1320 + }
1.1321 +
1.1322 + /* Now the connection is active, move it between lists */
1.1323 + _dbus_list_unlink (&d->connections->incomplete,
1.1324 + d->link_in_connection_list);
1.1325 + d->connections->n_incomplete -= 1;
1.1326 + _dbus_list_append_link (&d->connections->completed,
1.1327 + d->link_in_connection_list);
1.1328 + d->connections->n_completed += 1;
1.1329 +
1.1330 + _dbus_assert (d->connections->n_incomplete >= 0);
1.1331 + _dbus_assert (d->connections->n_completed > 0);
1.1332 +
1.1333 + /* See if we can remove the timeout */
1.1334 + bus_connections_expire_incomplete (d->connections);
1.1335 +
1.1336 + _dbus_assert (bus_connection_is_active (connection));
1.1337 +
1.1338 + return TRUE;
1.1339 +}
1.1340 +
1.1341 +const char *
1.1342 +bus_connection_get_name (DBusConnection *connection)
1.1343 +{
1.1344 + BusConnectionData *d;
1.1345 +
1.1346 + d = BUS_CONNECTION_DATA (connection);
1.1347 + _dbus_assert (d != NULL);
1.1348 +
1.1349 + return d->name;
1.1350 +}
1.1351 +
1.1352 +/**
1.1353 + * Check whether completing the passed-in connection would
1.1354 + * exceed limits, and if so set error and return #FALSE
1.1355 + */
1.1356 +dbus_bool_t
1.1357 +bus_connections_check_limits (BusConnections *connections,
1.1358 + DBusConnection *requesting_completion,
1.1359 + DBusError *error)
1.1360 +{
1.1361 + BusConnectionData *d;
1.1362 + unsigned long uid;
1.1363 +
1.1364 + d = BUS_CONNECTION_DATA (requesting_completion);
1.1365 + _dbus_assert (d != NULL);
1.1366 +
1.1367 + _dbus_assert (d->name == NULL);
1.1368 +
1.1369 + if (connections->n_completed >=
1.1370 + bus_context_get_max_completed_connections (connections->context))
1.1371 + {
1.1372 + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
1.1373 + "The maximum number of active connections has been reached");
1.1374 + return FALSE;
1.1375 + }
1.1376 +
1.1377 + if (dbus_connection_get_unix_user (requesting_completion, &uid))
1.1378 + {
1.1379 + if (get_connections_for_uid (connections, uid) >=
1.1380 + bus_context_get_max_connections_per_user (connections->context))
1.1381 + {
1.1382 + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
1.1383 + "The maximum number of active connections for UID %lu has been reached",
1.1384 + uid);
1.1385 + return FALSE;
1.1386 + }
1.1387 + }
1.1388 +
1.1389 + return TRUE;
1.1390 +}
1.1391 +
1.1392 +static void
1.1393 +bus_pending_reply_free (BusPendingReply *pending)
1.1394 +{
1.1395 + _dbus_verbose ("Freeing pending reply %p, replier %p receiver %p serial %u\n",
1.1396 + pending,
1.1397 + pending->will_send_reply,
1.1398 + pending->will_get_reply,
1.1399 + pending->reply_serial);
1.1400 +
1.1401 + dbus_free (pending);
1.1402 +}
1.1403 +
1.1404 +static dbus_bool_t
1.1405 +bus_pending_reply_send_no_reply (BusConnections *connections,
1.1406 + BusTransaction *transaction,
1.1407 + BusPendingReply *pending)
1.1408 +{
1.1409 + DBusMessage *message;
1.1410 + DBusMessageIter iter;
1.1411 + dbus_bool_t retval;
1.1412 + const char *errmsg;
1.1413 +
1.1414 + retval = FALSE;
1.1415 +
1.1416 + message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR);
1.1417 + if (message == NULL)
1.1418 + return FALSE;
1.1419 +
1.1420 + dbus_message_set_no_reply (message, TRUE);
1.1421 +
1.1422 + if (!dbus_message_set_reply_serial (message,
1.1423 + pending->reply_serial))
1.1424 + goto out;
1.1425 +
1.1426 + if (!dbus_message_set_error_name (message,
1.1427 + DBUS_ERROR_NO_REPLY))
1.1428 + goto out;
1.1429 +
1.1430 + errmsg = "Message did not receive a reply (timeout by message bus)";
1.1431 + dbus_message_iter_init_append (message, &iter);
1.1432 + if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &errmsg))
1.1433 + goto out;
1.1434 +
1.1435 + if (!bus_transaction_send_from_driver (transaction, pending->will_get_reply,
1.1436 + message))
1.1437 + goto out;
1.1438 +
1.1439 + retval = TRUE;
1.1440 +
1.1441 + out:
1.1442 + dbus_message_unref (message);
1.1443 + return retval;
1.1444 +}
1.1445 +
1.1446 +static dbus_bool_t
1.1447 +bus_pending_reply_expired (BusExpireList *list,
1.1448 + DBusList *link,
1.1449 + void *data)
1.1450 +{
1.1451 + BusPendingReply *pending = link->data;
1.1452 + BusConnections *connections = data;
1.1453 + BusTransaction *transaction;
1.1454 +
1.1455 + /* No reply is forthcoming. So nuke it if we can. If not,
1.1456 + * leave it in the list to try expiring again later when we
1.1457 + * get more memory.
1.1458 + */
1.1459 +
1.1460 + _dbus_verbose ("Expiring pending reply %p, replier %p receiver %p serial %u\n",
1.1461 + pending,
1.1462 + pending->will_send_reply,
1.1463 + pending->will_get_reply,
1.1464 + pending->reply_serial);
1.1465 +
1.1466 + transaction = bus_transaction_new (connections->context);
1.1467 + if (transaction == NULL)
1.1468 + return FALSE;
1.1469 +
1.1470 + if (!bus_pending_reply_send_no_reply (connections,
1.1471 + transaction,
1.1472 + pending))
1.1473 + {
1.1474 + bus_transaction_cancel_and_free (transaction);
1.1475 + return FALSE;
1.1476 + }
1.1477 +
1.1478 + _dbus_list_remove_link (&connections->pending_replies->items,
1.1479 + link);
1.1480 + bus_pending_reply_free (pending);
1.1481 + bus_transaction_execute_and_free (transaction);
1.1482 +
1.1483 + return TRUE;
1.1484 +}
1.1485 +
1.1486 +static void
1.1487 +bus_connection_drop_pending_replies (BusConnections *connections,
1.1488 + DBusConnection *connection)
1.1489 +{
1.1490 + /* The DBusConnection is almost 100% finalized here, so you can't
1.1491 + * do anything with it except check for pointer equality
1.1492 + */
1.1493 + DBusList *link;
1.1494 +
1.1495 + _dbus_verbose ("Dropping pending replies that involve connection %p\n",
1.1496 + connection);
1.1497 +
1.1498 + link = _dbus_list_get_first_link (&connections->pending_replies->items);
1.1499 + while (link != NULL)
1.1500 + {
1.1501 + DBusList *next;
1.1502 + BusPendingReply *pending;
1.1503 +
1.1504 + next = _dbus_list_get_next_link (&connections->pending_replies->items,
1.1505 + link);
1.1506 + pending = link->data;
1.1507 +
1.1508 + if (pending->will_get_reply == connection)
1.1509 + {
1.1510 + /* We don't need to track this pending reply anymore */
1.1511 +
1.1512 + _dbus_verbose ("Dropping pending reply %p, replier %p receiver %p serial %u\n",
1.1513 + pending,
1.1514 + pending->will_send_reply,
1.1515 + pending->will_get_reply,
1.1516 + pending->reply_serial);
1.1517 +
1.1518 + _dbus_list_remove_link (&connections->pending_replies->items,
1.1519 + link);
1.1520 + bus_pending_reply_free (pending);
1.1521 + }
1.1522 + else if (pending->will_send_reply == connection)
1.1523 + {
1.1524 + /* The reply isn't going to be sent, so set things
1.1525 + * up so it will be expired right away
1.1526 + */
1.1527 + _dbus_verbose ("Will expire pending reply %p, replier %p receiver %p serial %u\n",
1.1528 + pending,
1.1529 + pending->will_send_reply,
1.1530 + pending->will_get_reply,
1.1531 + pending->reply_serial);
1.1532 +
1.1533 + pending->will_send_reply = NULL;
1.1534 + pending->expire_item.added_tv_sec = 0;
1.1535 + pending->expire_item.added_tv_usec = 0;
1.1536 +
1.1537 + bus_expire_timeout_set_interval (connections->pending_replies->timeout,
1.1538 + 0);
1.1539 + }
1.1540 +
1.1541 + link = next;
1.1542 + }
1.1543 +}
1.1544 +
1.1545 +
1.1546 +typedef struct
1.1547 +{
1.1548 + BusPendingReply *pending;
1.1549 + BusConnections *connections;
1.1550 +} CancelPendingReplyData;
1.1551 +
1.1552 +static void
1.1553 +cancel_pending_reply (void *data)
1.1554 +{
1.1555 + CancelPendingReplyData *d = data;
1.1556 +
1.1557 + _dbus_verbose ("%s: d = %p\n", _DBUS_FUNCTION_NAME, d);
1.1558 +
1.1559 + if (!_dbus_list_remove (&d->connections->pending_replies->items,
1.1560 + d->pending))
1.1561 + _dbus_assert_not_reached ("pending reply did not exist to be cancelled");
1.1562 +
1.1563 + bus_pending_reply_free (d->pending); /* since it's been cancelled */
1.1564 +}
1.1565 +
1.1566 +static void
1.1567 +cancel_pending_reply_data_free (void *data)
1.1568 +{
1.1569 + CancelPendingReplyData *d = data;
1.1570 +
1.1571 + _dbus_verbose ("%s: d = %p\n", _DBUS_FUNCTION_NAME, d);
1.1572 +
1.1573 + /* d->pending should be either freed or still
1.1574 + * in the list of pending replies (owned by someone
1.1575 + * else)
1.1576 + */
1.1577 +
1.1578 + dbus_free (d);
1.1579 +}
1.1580 +
1.1581 +/*
1.1582 + * Record that a reply is allowed; return TRUE on success.
1.1583 + */
1.1584 +dbus_bool_t
1.1585 +bus_connections_expect_reply (BusConnections *connections,
1.1586 + BusTransaction *transaction,
1.1587 + DBusConnection *will_get_reply,
1.1588 + DBusConnection *will_send_reply,
1.1589 + DBusMessage *reply_to_this,
1.1590 + DBusError *error)
1.1591 +{
1.1592 + BusPendingReply *pending;
1.1593 + dbus_uint32_t reply_serial;
1.1594 + DBusList *link;
1.1595 + CancelPendingReplyData *cprd;
1.1596 + int count;
1.1597 +
1.1598 + _dbus_assert (will_get_reply != NULL);
1.1599 + _dbus_assert (will_send_reply != NULL);
1.1600 + _dbus_assert (reply_to_this != NULL);
1.1601 +
1.1602 + if (dbus_message_get_no_reply (reply_to_this))
1.1603 + return TRUE; /* we won't allow a reply, since client doesn't care for one. */
1.1604 +
1.1605 + reply_serial = dbus_message_get_serial (reply_to_this);
1.1606 +
1.1607 + link = _dbus_list_get_first_link (&connections->pending_replies->items);
1.1608 + count = 0;
1.1609 + while (link != NULL)
1.1610 + {
1.1611 + pending = link->data;
1.1612 +
1.1613 + if (pending->reply_serial == reply_serial &&
1.1614 + pending->will_get_reply == will_get_reply &&
1.1615 + pending->will_send_reply == will_send_reply)
1.1616 + {
1.1617 + dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
1.1618 + "Message has the same reply serial as a currently-outstanding existing method call");
1.1619 + return FALSE;
1.1620 + }
1.1621 +
1.1622 + link = _dbus_list_get_next_link (&connections->pending_replies->items,
1.1623 + link);
1.1624 + if (pending->will_get_reply == will_get_reply)
1.1625 + ++count;
1.1626 + }
1.1627 +
1.1628 + if (count >=
1.1629 + bus_context_get_max_replies_per_connection (connections->context))
1.1630 + {
1.1631 + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
1.1632 + "The maximum number of pending replies per connection has been reached");
1.1633 + return FALSE;
1.1634 + }
1.1635 +
1.1636 + pending = dbus_new0 (BusPendingReply, 1);
1.1637 + if (pending == NULL)
1.1638 + {
1.1639 + BUS_SET_OOM (error);
1.1640 + return FALSE;
1.1641 + }
1.1642 +
1.1643 +#ifdef DBUS_ENABLE_VERBOSE_MODE
1.1644 + /* so we can see a not-yet-added pending reply */
1.1645 + pending->expire_item.added_tv_sec = 1;
1.1646 + pending->expire_item.added_tv_usec = 1;
1.1647 +#endif
1.1648 +
1.1649 + pending->will_get_reply = will_get_reply;
1.1650 + pending->will_send_reply = will_send_reply;
1.1651 + pending->reply_serial = reply_serial;
1.1652 +
1.1653 + cprd = dbus_new0 (CancelPendingReplyData, 1);
1.1654 + if (cprd == NULL)
1.1655 + {
1.1656 + BUS_SET_OOM (error);
1.1657 + bus_pending_reply_free (pending);
1.1658 + return FALSE;
1.1659 + }
1.1660 +
1.1661 + if (!_dbus_list_prepend (&connections->pending_replies->items,
1.1662 + pending))
1.1663 + {
1.1664 + BUS_SET_OOM (error);
1.1665 + dbus_free (cprd);
1.1666 + bus_pending_reply_free (pending);
1.1667 + return FALSE;
1.1668 + }
1.1669 +
1.1670 + if (!bus_transaction_add_cancel_hook (transaction,
1.1671 + cancel_pending_reply,
1.1672 + cprd,
1.1673 + cancel_pending_reply_data_free))
1.1674 + {
1.1675 + BUS_SET_OOM (error);
1.1676 + _dbus_list_remove (&connections->pending_replies->items, pending);
1.1677 + dbus_free (cprd);
1.1678 + bus_pending_reply_free (pending);
1.1679 + return FALSE;
1.1680 + }
1.1681 +
1.1682 + cprd->pending = pending;
1.1683 + cprd->connections = connections;
1.1684 +
1.1685 + _dbus_get_current_time (&pending->expire_item.added_tv_sec,
1.1686 + &pending->expire_item.added_tv_usec);
1.1687 +
1.1688 + _dbus_verbose ("Added pending reply %p, replier %p receiver %p serial %u\n",
1.1689 + pending,
1.1690 + pending->will_send_reply,
1.1691 + pending->will_get_reply,
1.1692 + pending->reply_serial);
1.1693 +
1.1694 + return TRUE;
1.1695 +}
1.1696 +
1.1697 +typedef struct
1.1698 +{
1.1699 + DBusList *link;
1.1700 + BusConnections *connections;
1.1701 +} CheckPendingReplyData;
1.1702 +
1.1703 +static void
1.1704 +cancel_check_pending_reply (void *data)
1.1705 +{
1.1706 + CheckPendingReplyData *d = data;
1.1707 +
1.1708 + _dbus_verbose ("%s: d = %p\n", _DBUS_FUNCTION_NAME, d);
1.1709 +
1.1710 + _dbus_list_prepend_link (&d->connections->pending_replies->items,
1.1711 + d->link);
1.1712 + d->link = NULL;
1.1713 +}
1.1714 +
1.1715 +static void
1.1716 +check_pending_reply_data_free (void *data)
1.1717 +{
1.1718 + CheckPendingReplyData *d = data;
1.1719 +
1.1720 + _dbus_verbose ("%s: d = %p\n", _DBUS_FUNCTION_NAME, d);
1.1721 +
1.1722 + if (d->link != NULL)
1.1723 + {
1.1724 + BusPendingReply *pending = d->link->data;
1.1725 +
1.1726 + _dbus_assert (_dbus_list_find_last (&d->connections->pending_replies->items,
1.1727 + pending) == NULL);
1.1728 +
1.1729 + bus_pending_reply_free (pending);
1.1730 + _dbus_list_free_link (d->link);
1.1731 + }
1.1732 +
1.1733 + dbus_free (d);
1.1734 +}
1.1735 +
1.1736 +/*
1.1737 + * Check whether a reply is allowed, remove BusPendingReply
1.1738 + * if so, return TRUE if so.
1.1739 + */
1.1740 +dbus_bool_t
1.1741 +bus_connections_check_reply (BusConnections *connections,
1.1742 + BusTransaction *transaction,
1.1743 + DBusConnection *sending_reply,
1.1744 + DBusConnection *receiving_reply,
1.1745 + DBusMessage *reply,
1.1746 + DBusError *error)
1.1747 +{
1.1748 + CheckPendingReplyData *cprd;
1.1749 + DBusList *link;
1.1750 + dbus_uint32_t reply_serial;
1.1751 +
1.1752 + _dbus_assert (sending_reply != NULL);
1.1753 + _dbus_assert (receiving_reply != NULL);
1.1754 +
1.1755 + reply_serial = dbus_message_get_reply_serial (reply);
1.1756 +
1.1757 + link = _dbus_list_get_first_link (&connections->pending_replies->items);
1.1758 + while (link != NULL)
1.1759 + {
1.1760 + BusPendingReply *pending = link->data;
1.1761 +
1.1762 + if (pending->reply_serial == reply_serial &&
1.1763 + pending->will_get_reply == receiving_reply &&
1.1764 + pending->will_send_reply == sending_reply)
1.1765 + {
1.1766 + _dbus_verbose ("Found pending reply with serial %u\n", reply_serial);
1.1767 + break;
1.1768 + }
1.1769 +
1.1770 + link = _dbus_list_get_next_link (&connections->pending_replies->items,
1.1771 + link);
1.1772 + }
1.1773 +
1.1774 + if (link == NULL)
1.1775 + {
1.1776 + _dbus_verbose ("No pending reply expected\n");
1.1777 +
1.1778 + return FALSE;
1.1779 + }
1.1780 +
1.1781 + cprd = dbus_new0 (CheckPendingReplyData, 1);
1.1782 + if (cprd == NULL)
1.1783 + {
1.1784 + BUS_SET_OOM (error);
1.1785 + return FALSE;
1.1786 + }
1.1787 +
1.1788 + if (!bus_transaction_add_cancel_hook (transaction,
1.1789 + cancel_check_pending_reply,
1.1790 + cprd,
1.1791 + check_pending_reply_data_free))
1.1792 + {
1.1793 + BUS_SET_OOM (error);
1.1794 + dbus_free (cprd);
1.1795 + return FALSE;
1.1796 + }
1.1797 +
1.1798 + cprd->link = link;
1.1799 + cprd->connections = connections;
1.1800 +
1.1801 + _dbus_list_unlink (&connections->pending_replies->items,
1.1802 + link);
1.1803 +
1.1804 + _dbus_assert (_dbus_list_find_last (&connections->pending_replies->items,
1.1805 + link->data) == NULL);
1.1806 +
1.1807 + return TRUE;
1.1808 +}
1.1809 +
1.1810 +/*
1.1811 + * Transactions
1.1812 + *
1.1813 + * Note that this is fairly fragile; in particular, don't try to use
1.1814 + * one transaction across any main loop iterations.
1.1815 + */
1.1816 +
1.1817 +typedef struct
1.1818 +{
1.1819 + BusTransaction *transaction;
1.1820 + DBusMessage *message;
1.1821 + DBusPreallocatedSend *preallocated;
1.1822 +} MessageToSend;
1.1823 +
1.1824 +typedef struct
1.1825 +{
1.1826 + BusTransactionCancelFunction cancel_function;
1.1827 + DBusFreeFunction free_data_function;
1.1828 + void *data;
1.1829 +} CancelHook;
1.1830 +
1.1831 +struct BusTransaction
1.1832 +{
1.1833 + DBusList *connections;
1.1834 + BusContext *context;
1.1835 + DBusList *cancel_hooks;
1.1836 +};
1.1837 +
1.1838 +static void
1.1839 +message_to_send_free (DBusConnection *connection,
1.1840 + MessageToSend *to_send)
1.1841 +{
1.1842 + if (to_send->message)
1.1843 + dbus_message_unref (to_send->message);
1.1844 +
1.1845 + if (to_send->preallocated)
1.1846 + dbus_connection_free_preallocated_send (connection, to_send->preallocated);
1.1847 +
1.1848 + dbus_free (to_send);
1.1849 +}
1.1850 +
1.1851 +static void
1.1852 +cancel_hook_cancel (void *element,
1.1853 + void *data)
1.1854 +{
1.1855 + CancelHook *ch = element;
1.1856 +
1.1857 + _dbus_verbose ("Running transaction cancel hook\n");
1.1858 +
1.1859 + if (ch->cancel_function)
1.1860 + (* ch->cancel_function) (ch->data);
1.1861 +}
1.1862 +
1.1863 +static void
1.1864 +cancel_hook_free (void *element,
1.1865 + void *data)
1.1866 +{
1.1867 + CancelHook *ch = element;
1.1868 +
1.1869 + if (ch->free_data_function)
1.1870 + (* ch->free_data_function) (ch->data);
1.1871 +
1.1872 + dbus_free (ch);
1.1873 +}
1.1874 +
1.1875 +static void
1.1876 +free_cancel_hooks (BusTransaction *transaction)
1.1877 +{
1.1878 + _dbus_list_foreach (&transaction->cancel_hooks,
1.1879 + cancel_hook_free, NULL);
1.1880 +
1.1881 + _dbus_list_clear (&transaction->cancel_hooks);
1.1882 +}
1.1883 +
1.1884 +BusTransaction*
1.1885 +bus_transaction_new (BusContext *context)
1.1886 +{
1.1887 + BusTransaction *transaction;
1.1888 +
1.1889 + transaction = dbus_new0 (BusTransaction, 1);
1.1890 + if (transaction == NULL)
1.1891 + return NULL;
1.1892 +
1.1893 + transaction->context = context;
1.1894 +
1.1895 + return transaction;
1.1896 +}
1.1897 +
1.1898 +BusContext*
1.1899 +bus_transaction_get_context (BusTransaction *transaction)
1.1900 +{
1.1901 + return transaction->context;
1.1902 +}
1.1903 +
1.1904 +BusConnections*
1.1905 +bus_transaction_get_connections (BusTransaction *transaction)
1.1906 +{
1.1907 + return bus_context_get_connections (transaction->context);
1.1908 +}
1.1909 +
1.1910 +dbus_bool_t
1.1911 +bus_transaction_send_from_driver (BusTransaction *transaction,
1.1912 + DBusConnection *connection,
1.1913 + DBusMessage *message)
1.1914 +{
1.1915 + /* We have to set the sender to the driver, and have
1.1916 + * to check security policy since it was not done in
1.1917 + * dispatch.c
1.1918 + */
1.1919 + _dbus_verbose ("Sending %s %s %s from driver\n",
1.1920 + dbus_message_get_interface (message) ?
1.1921 + dbus_message_get_interface (message) : "(no interface)",
1.1922 + dbus_message_get_member (message) ?
1.1923 + dbus_message_get_member (message) : "(no member)",
1.1924 + dbus_message_get_error_name (message) ?
1.1925 + dbus_message_get_error_name (message) : "(no error name)");
1.1926 +
1.1927 + if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
1.1928 + return FALSE;
1.1929 +
1.1930 + if (bus_connection_is_active (connection))
1.1931 + {
1.1932 + if (!dbus_message_set_destination (message,
1.1933 + bus_connection_get_name (connection)))
1.1934 + return FALSE;
1.1935 + }
1.1936 +
1.1937 + /* bus driver never wants a reply */
1.1938 + dbus_message_set_no_reply (message, TRUE);
1.1939 +
1.1940 + /* If security policy doesn't allow the message, we silently
1.1941 + * eat it; the driver doesn't care about getting a reply.
1.1942 + */
1.1943 + if (!bus_context_check_security_policy (bus_transaction_get_context (transaction),
1.1944 + transaction,
1.1945 + NULL, connection, connection, message, NULL))
1.1946 + return TRUE;
1.1947 +
1.1948 + return bus_transaction_send (transaction, connection, message);
1.1949 +}
1.1950 +
1.1951 +dbus_bool_t
1.1952 +bus_transaction_send (BusTransaction *transaction,
1.1953 + DBusConnection *connection,
1.1954 + DBusMessage *message)
1.1955 +{
1.1956 + MessageToSend *to_send;
1.1957 + BusConnectionData *d;
1.1958 + DBusList *link;
1.1959 +
1.1960 + _dbus_verbose (" trying to add %s interface=%s member=%s error=%s to transaction%s\n",
1.1961 + dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ? "error" :
1.1962 + dbus_message_get_reply_serial (message) != 0 ? "reply" :
1.1963 + "message",
1.1964 + dbus_message_get_interface (message) ?
1.1965 + dbus_message_get_interface (message) : "(unset)",
1.1966 + dbus_message_get_member (message) ?
1.1967 + dbus_message_get_member (message) : "(unset)",
1.1968 + dbus_message_get_error_name (message) ?
1.1969 + dbus_message_get_error_name (message) : "(unset)",
1.1970 + dbus_connection_get_is_connected (connection) ?
1.1971 + "" : " (disconnected)");
1.1972 +
1.1973 + _dbus_assert (dbus_message_get_sender (message) != NULL);
1.1974 +
1.1975 + if (!dbus_connection_get_is_connected (connection))
1.1976 + return TRUE; /* silently ignore disconnected connections */
1.1977 +
1.1978 + d = BUS_CONNECTION_DATA (connection);
1.1979 + _dbus_assert (d != NULL);
1.1980 +
1.1981 + to_send = dbus_new (MessageToSend, 1);
1.1982 + if (to_send == NULL)
1.1983 + {
1.1984 + return FALSE;
1.1985 + }
1.1986 +
1.1987 + to_send->preallocated = dbus_connection_preallocate_send (connection);
1.1988 + if (to_send->preallocated == NULL)
1.1989 + {
1.1990 + dbus_free (to_send);
1.1991 + return FALSE;
1.1992 + }
1.1993 +
1.1994 + dbus_message_ref (message);
1.1995 + to_send->message = message;
1.1996 + to_send->transaction = transaction;
1.1997 +
1.1998 + _dbus_verbose ("about to prepend message\n");
1.1999 +
1.2000 + if (!_dbus_list_prepend (&d->transaction_messages, to_send))
1.2001 + {
1.2002 + message_to_send_free (connection, to_send);
1.2003 + return FALSE;
1.2004 + }
1.2005 +
1.2006 + _dbus_verbose ("prepended message\n");
1.2007 +
1.2008 + /* See if we already had this connection in the list
1.2009 + * for this transaction. If we have a pending message,
1.2010 + * then we should already be in transaction->connections
1.2011 + */
1.2012 + link = _dbus_list_get_first_link (&d->transaction_messages);
1.2013 + _dbus_assert (link->data == to_send);
1.2014 + link = _dbus_list_get_next_link (&d->transaction_messages, link);
1.2015 + while (link != NULL)
1.2016 + {
1.2017 + MessageToSend *m = link->data;
1.2018 + DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link);
1.2019 +
1.2020 + if (m->transaction == transaction)
1.2021 + break;
1.2022 +
1.2023 + link = next;
1.2024 + }
1.2025 +
1.2026 + if (link == NULL)
1.2027 + {
1.2028 + if (!_dbus_list_prepend (&transaction->connections, connection))
1.2029 + {
1.2030 + _dbus_list_remove (&d->transaction_messages, to_send);
1.2031 + message_to_send_free (connection, to_send);
1.2032 + return FALSE;
1.2033 + }
1.2034 + }
1.2035 +
1.2036 + return TRUE;
1.2037 +}
1.2038 +
1.2039 +static void
1.2040 +connection_cancel_transaction (DBusConnection *connection,
1.2041 + BusTransaction *transaction)
1.2042 +{
1.2043 + DBusList *link;
1.2044 + BusConnectionData *d;
1.2045 +
1.2046 + d = BUS_CONNECTION_DATA (connection);
1.2047 + _dbus_assert (d != NULL);
1.2048 +
1.2049 + link = _dbus_list_get_first_link (&d->transaction_messages);
1.2050 + while (link != NULL)
1.2051 + {
1.2052 + MessageToSend *m = link->data;
1.2053 + DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link);
1.2054 +
1.2055 + if (m->transaction == transaction)
1.2056 + {
1.2057 + _dbus_list_remove_link (&d->transaction_messages,
1.2058 + link);
1.2059 +
1.2060 + message_to_send_free (connection, m);
1.2061 + }
1.2062 +
1.2063 + link = next;
1.2064 + }
1.2065 +}
1.2066 +
1.2067 +void
1.2068 +bus_transaction_cancel_and_free (BusTransaction *transaction)
1.2069 +{
1.2070 + DBusConnection *connection;
1.2071 +
1.2072 + _dbus_verbose ("TRANSACTION: cancelled\n");
1.2073 +
1.2074 + while ((connection = _dbus_list_pop_first (&transaction->connections)))
1.2075 + connection_cancel_transaction (connection, transaction);
1.2076 +
1.2077 + _dbus_assert (transaction->connections == NULL);
1.2078 +
1.2079 + _dbus_list_foreach (&transaction->cancel_hooks,
1.2080 + cancel_hook_cancel, NULL);
1.2081 +
1.2082 + free_cancel_hooks (transaction);
1.2083 +
1.2084 + dbus_free (transaction);
1.2085 +}
1.2086 +
1.2087 +static void
1.2088 +connection_execute_transaction (DBusConnection *connection,
1.2089 + BusTransaction *transaction)
1.2090 +{
1.2091 + DBusList *link;
1.2092 + BusConnectionData *d;
1.2093 +
1.2094 + d = BUS_CONNECTION_DATA (connection);
1.2095 + _dbus_assert (d != NULL);
1.2096 +
1.2097 + /* Send the queue in order (FIFO) */
1.2098 + link = _dbus_list_get_last_link (&d->transaction_messages);
1.2099 + while (link != NULL)
1.2100 + {
1.2101 + MessageToSend *m = link->data;
1.2102 + DBusList *prev = _dbus_list_get_prev_link (&d->transaction_messages, link);
1.2103 +
1.2104 + if (m->transaction == transaction)
1.2105 + {
1.2106 + _dbus_list_remove_link (&d->transaction_messages,
1.2107 + link);
1.2108 +
1.2109 + _dbus_assert (dbus_message_get_sender (m->message) != NULL);
1.2110 +
1.2111 + dbus_connection_send_preallocated (connection,
1.2112 + m->preallocated,
1.2113 + m->message,
1.2114 + NULL);
1.2115 +
1.2116 + m->preallocated = NULL; /* so we don't double-free it */
1.2117 +
1.2118 + message_to_send_free (connection, m);
1.2119 + }
1.2120 +
1.2121 + link = prev;
1.2122 + }
1.2123 +}
1.2124 +
1.2125 +void
1.2126 +bus_transaction_execute_and_free (BusTransaction *transaction)
1.2127 +{
1.2128 + /* For each connection in transaction->connections
1.2129 + * send the messages
1.2130 + */
1.2131 + DBusConnection *connection;
1.2132 +
1.2133 + _dbus_verbose ("TRANSACTION: executing\n");
1.2134 +
1.2135 + while ((connection = _dbus_list_pop_first (&transaction->connections)))
1.2136 + connection_execute_transaction (connection, transaction);
1.2137 +
1.2138 + _dbus_assert (transaction->connections == NULL);
1.2139 +
1.2140 + free_cancel_hooks (transaction);
1.2141 +
1.2142 + dbus_free (transaction);
1.2143 +}
1.2144 +
1.2145 +static void
1.2146 +bus_connection_remove_transactions (DBusConnection *connection)
1.2147 +{
1.2148 + MessageToSend *to_send;
1.2149 + BusConnectionData *d;
1.2150 +
1.2151 + d = BUS_CONNECTION_DATA (connection);
1.2152 + _dbus_assert (d != NULL);
1.2153 +
1.2154 + while ((to_send = _dbus_list_get_first (&d->transaction_messages)))
1.2155 + {
1.2156 + /* only has an effect for the first MessageToSend listing this transaction */
1.2157 + _dbus_list_remove (&to_send->transaction->connections,
1.2158 + connection);
1.2159 +
1.2160 + _dbus_list_remove (&d->transaction_messages, to_send);
1.2161 + message_to_send_free (connection, to_send);
1.2162 + }
1.2163 +}
1.2164 +
1.2165 +/**
1.2166 + * Converts the DBusError to a message reply
1.2167 + */
1.2168 +dbus_bool_t
1.2169 +bus_transaction_send_error_reply (BusTransaction *transaction,
1.2170 + DBusConnection *connection,
1.2171 + const DBusError *error,
1.2172 + DBusMessage *in_reply_to)
1.2173 +{
1.2174 + DBusMessage *reply;
1.2175 +
1.2176 + _dbus_assert (error != NULL);
1.2177 + _DBUS_ASSERT_ERROR_IS_SET (error);
1.2178 +
1.2179 + _dbus_verbose ("Sending error reply %s \"%s\"\n",
1.2180 + error->name, error->message);
1.2181 +
1.2182 + reply = dbus_message_new_error (in_reply_to,
1.2183 + error->name,
1.2184 + error->message);
1.2185 + if (reply == NULL)
1.2186 + return FALSE;
1.2187 +
1.2188 + if (!bus_transaction_send_from_driver (transaction, connection, reply))
1.2189 + {
1.2190 + dbus_message_unref (reply);
1.2191 + return FALSE;
1.2192 + }
1.2193 +
1.2194 + dbus_message_unref (reply);
1.2195 +
1.2196 + return TRUE;
1.2197 +}
1.2198 +
1.2199 +dbus_bool_t
1.2200 +bus_transaction_add_cancel_hook (BusTransaction *transaction,
1.2201 + BusTransactionCancelFunction cancel_function,
1.2202 + void *data,
1.2203 + DBusFreeFunction free_data_function)
1.2204 +{
1.2205 + CancelHook *ch;
1.2206 +
1.2207 + ch = dbus_new (CancelHook, 1);
1.2208 + if (ch == NULL)
1.2209 + return FALSE;
1.2210 +
1.2211 + _dbus_verbose (" adding cancel hook function = %p data = %p\n",
1.2212 + cancel_function, data);
1.2213 +
1.2214 + ch->cancel_function = cancel_function;
1.2215 + ch->data = data;
1.2216 + ch->free_data_function = free_data_function;
1.2217 +
1.2218 + /* It's important that the hooks get run in reverse order that they
1.2219 + * were added
1.2220 + */
1.2221 + if (!_dbus_list_prepend (&transaction->cancel_hooks, ch))
1.2222 + {
1.2223 + dbus_free (ch);
1.2224 + return FALSE;
1.2225 + }
1.2226 +
1.2227 + return TRUE;
1.2228 +}