1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* connection.c Client connections
4 * Copyright (C) 2003 Red Hat, Inc.
6 * Licensed under the Academic Free License version 1.2
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "connection.h"
28 #include <dbus/dbus-list.h>
30 static void bus_connection_remove_transactions (DBusConnection *connection);
35 DBusList *list; /**< List of all the connections */
39 static int connection_data_slot = -1;
40 static int connection_data_slot_refcount = 0;
44 BusConnections *connections;
45 DBusConnection *connection;
46 DBusList *services_owned;
48 DBusList *transaction_messages; /**< Stuff we need to send as part of a transaction */
49 DBusMessage *oom_message;
50 DBusPreallocatedSend *oom_preallocated;
51 BusClientPolicy *policy;
54 #define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot))
57 connection_data_slot_ref (void)
59 if (connection_data_slot < 0)
61 connection_data_slot = dbus_connection_allocate_data_slot ();
63 if (connection_data_slot < 0)
66 _dbus_assert (connection_data_slot_refcount == 0);
69 connection_data_slot_refcount += 1;
76 connection_data_slot_unref (void)
78 _dbus_assert (connection_data_slot_refcount > 0);
80 connection_data_slot_refcount -= 1;
82 if (connection_data_slot_refcount == 0)
84 dbus_connection_free_data_slot (connection_data_slot);
85 connection_data_slot = -1;
90 connection_get_loop (DBusConnection *connection)
94 d = BUS_CONNECTION_DATA (connection);
96 return bus_context_get_loop (d->connections->context);
100 bus_connection_disconnected (DBusConnection *connection)
102 BusConnectionData *d;
105 d = BUS_CONNECTION_DATA (connection);
106 _dbus_assert (d != NULL);
108 _dbus_verbose ("%s disconnected, dropping all service ownership and releasing\n",
109 d->name ? d->name : "(inactive)");
111 /* Drop any service ownership. FIXME Unfortunately, this requires
112 * memory allocation and there doesn't seem to be a good way to
113 * handle it other than sleeping; we can't "fail" the operation of
114 * disconnecting a client, and preallocating a broadcast "service is
115 * now gone" message for every client-service pair seems kind of
116 * involved. Probably we need to do that though, and also
117 * extend BusTransaction to be able to revert generic
118 * stuff, not just sending a message (so we can e.g. revert
119 * removal of service owners).
121 while ((service = _dbus_list_get_last (&d->services_owned)))
123 BusTransaction *transaction;
128 dbus_error_init (&error);
131 while (transaction == NULL)
133 transaction = bus_transaction_new (d->connections->context);
134 _dbus_wait_for_memory ();
137 if (!bus_service_remove_owner (service, connection,
138 transaction, &error))
140 _DBUS_ASSERT_ERROR_IS_SET (&error);
142 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
144 dbus_error_free (&error);
145 bus_transaction_cancel_and_free (transaction);
146 _dbus_wait_for_memory ();
151 _dbus_verbose ("Failed to remove service owner: %s %s\n",
152 error.name, error.message);
153 _dbus_assert_not_reached ("Removing service owner failed for non-memory-related reason");
157 bus_transaction_execute_and_free (transaction);
160 bus_dispatch_remove_connection (connection);
162 /* no more watching */
163 if (!dbus_connection_set_watch_functions (connection,
167 _dbus_assert_not_reached ("setting watch functions to NULL failed");
169 if (!dbus_connection_set_timeout_functions (connection,
173 _dbus_assert_not_reached ("setting timeout functions to NULL failed");
175 dbus_connection_set_unix_user_function (connection,
178 dbus_connection_set_dispatch_status_function (connection,
181 bus_connection_remove_transactions (connection);
183 _dbus_list_remove (&d->connections->list, connection);
185 /* frees "d" as side effect */
186 dbus_connection_set_data (connection,
187 connection_data_slot,
190 dbus_connection_unref (connection);
194 connection_watch_callback (DBusWatch *watch,
195 unsigned int condition,
198 DBusConnection *connection = data;
202 _dbus_verbose ("Calling handle_watch\n");
204 retval = dbus_connection_handle_watch (connection, watch, condition);
210 add_connection_watch (DBusWatch *watch,
213 DBusConnection *connection = data;
215 return _dbus_loop_add_watch (connection_get_loop (connection),
216 watch, connection_watch_callback, connection,
221 remove_connection_watch (DBusWatch *watch,
224 DBusConnection *connection = data;
226 _dbus_loop_remove_watch (connection_get_loop (connection),
227 watch, connection_watch_callback, connection);
231 connection_timeout_callback (DBusTimeout *timeout,
234 DBusConnection *connection = data;
236 /* can return FALSE on OOM but we just let it fire again later */
237 dbus_timeout_handle (timeout);
241 add_connection_timeout (DBusTimeout *timeout,
244 DBusConnection *connection = data;
246 return _dbus_loop_add_timeout (connection_get_loop (connection),
247 timeout, connection_timeout_callback, connection, NULL);
251 remove_connection_timeout (DBusTimeout *timeout,
254 DBusConnection *connection = data;
256 _dbus_loop_remove_timeout (connection_get_loop (connection),
257 timeout, connection_timeout_callback, connection);
261 dispatch_status_function (DBusConnection *connection,
262 DBusDispatchStatus new_status,
265 DBusLoop *loop = data;
267 if (new_status != DBUS_DISPATCH_COMPLETE)
269 while (!_dbus_loop_queue_dispatch (loop, connection))
270 _dbus_wait_for_memory ();
275 allow_user_function (DBusConnection *connection,
279 BusConnectionData *d;
281 d = BUS_CONNECTION_DATA (connection);
283 _dbus_assert (d != NULL);
285 return bus_context_allow_user (d->connections->context, uid);
289 free_connection_data (void *data)
291 BusConnectionData *d = data;
293 /* services_owned should be NULL since we should be disconnected */
294 _dbus_assert (d->services_owned == NULL);
296 _dbus_assert (d->transaction_messages == NULL);
298 if (d->oom_preallocated)
299 dbus_connection_free_preallocated_send (d->connection, d->oom_preallocated);
302 dbus_message_unref (d->oom_message);
305 bus_client_policy_unref (d->policy);
313 bus_connections_new (BusContext *context)
315 BusConnections *connections;
317 if (!connection_data_slot_ref ())
320 connections = dbus_new0 (BusConnections, 1);
321 if (connections == NULL)
323 connection_data_slot_unref ();
327 connections->refcount = 1;
328 connections->context = context;
334 bus_connections_ref (BusConnections *connections)
336 _dbus_assert (connections->refcount > 0);
337 connections->refcount += 1;
341 bus_connections_unref (BusConnections *connections)
343 _dbus_assert (connections->refcount > 0);
344 connections->refcount -= 1;
345 if (connections->refcount == 0)
347 while (connections->list != NULL)
349 DBusConnection *connection;
351 connection = connections->list->data;
353 dbus_connection_ref (connection);
354 dbus_connection_disconnect (connection);
355 bus_connection_disconnected (connection);
356 dbus_connection_unref (connection);
359 _dbus_list_clear (&connections->list);
361 dbus_free (connections);
363 connection_data_slot_unref ();
368 bus_connections_setup_connection (BusConnections *connections,
369 DBusConnection *connection)
371 BusConnectionData *d;
374 d = dbus_new0 (BusConnectionData, 1);
379 d->connections = connections;
380 d->connection = connection;
382 _dbus_assert (connection_data_slot >= 0);
384 if (!dbus_connection_set_data (connection,
385 connection_data_slot,
386 d, free_connection_data))
394 if (!dbus_connection_set_watch_functions (connection,
395 add_connection_watch,
396 remove_connection_watch,
402 if (!dbus_connection_set_timeout_functions (connection,
403 add_connection_timeout,
404 remove_connection_timeout,
410 dbus_connection_set_unix_user_function (connection,
414 dbus_connection_set_dispatch_status_function (connection,
415 dispatch_status_function,
416 bus_context_get_loop (connections->context),
419 /* Setup the connection with the dispatcher */
420 if (!bus_dispatch_add_connection (connection))
423 if (!_dbus_list_append (&connections->list, connection))
425 bus_dispatch_remove_connection (connection);
429 if (dbus_connection_get_dispatch_status (connection) != DBUS_DISPATCH_COMPLETE)
431 if (!_dbus_loop_queue_dispatch (bus_context_get_loop (connections->context), connection))
433 bus_dispatch_remove_connection (connection);
438 dbus_connection_ref (connection);
444 if (!dbus_connection_set_watch_functions (connection,
448 _dbus_assert_not_reached ("setting watch functions to NULL failed");
450 if (!dbus_connection_set_timeout_functions (connection,
454 _dbus_assert_not_reached ("setting timeout functions to NULL failed");
456 dbus_connection_set_unix_user_function (connection,
459 dbus_connection_set_dispatch_status_function (connection,
462 if (!dbus_connection_set_data (connection,
463 connection_data_slot,
465 _dbus_assert_not_reached ("failed to set connection data to null");
472 bus_connection_get_groups (DBusConnection *connection,
473 unsigned long **groups,
476 BusConnectionData *d;
478 DBusUserDatabase *user_database;
480 d = BUS_CONNECTION_DATA (connection);
482 _dbus_assert (d != NULL);
484 user_database = bus_context_get_user_database (d->connections->context);
489 if (dbus_connection_get_unix_user (connection, &uid))
491 if (!_dbus_user_database_get_groups (user_database,
492 uid, groups, n_groups,
495 _dbus_verbose ("Did not get any groups for UID %lu\n",
501 _dbus_verbose ("Got %d groups for UID %lu\n",
507 return TRUE; /* successfully got 0 groups */
511 bus_connection_is_in_group (DBusConnection *connection,
515 unsigned long *group_ids;
518 if (!bus_connection_get_groups (connection, &group_ids, &n_group_ids))
522 while (i < n_group_ids)
524 if (group_ids[i] == gid)
526 dbus_free (group_ids);
532 dbus_free (group_ids);
537 bus_connection_get_policy (DBusConnection *connection)
539 BusConnectionData *d;
541 d = BUS_CONNECTION_DATA (connection);
543 _dbus_assert (d != NULL);
545 if (!dbus_connection_get_is_authenticated (connection))
547 _dbus_verbose ("Tried to get policy for unauthenticated connection!\n");
551 /* We do lazy creation of the policy because
552 * it can only be done post-authentication.
554 if (d->policy == NULL)
557 bus_context_create_client_policy (d->connections->context,
560 /* we may have a NULL policy on OOM or error getting list of
561 * groups for a user. In the latter case we don't handle it so
562 * well currently, just keep pretending we're out of memory,
563 * which is kind of bizarre.
571 * Calls function on each connection; if the function returns
572 * #FALSE, stops iterating.
574 * @param connections the connections object
575 * @param function the function
576 * @param data data to pass to it as a second arg
579 bus_connections_foreach (BusConnections *connections,
580 BusConnectionForeachFunction function,
585 link = _dbus_list_get_first_link (&connections->list);
588 DBusConnection *connection = link->data;
589 DBusList *next = _dbus_list_get_next_link (&connections->list, link);
591 if (!(* function) (connection, data))
599 bus_connections_get_context (BusConnections *connections)
601 return connections->context;
605 bus_connection_get_context (DBusConnection *connection)
607 BusConnectionData *d;
609 d = BUS_CONNECTION_DATA (connection);
611 _dbus_assert (d != NULL);
613 return d->connections->context;
617 bus_connection_get_connections (DBusConnection *connection)
619 BusConnectionData *d;
621 d = BUS_CONNECTION_DATA (connection);
623 _dbus_assert (d != NULL);
625 return d->connections;
629 bus_connection_get_registry (DBusConnection *connection)
631 BusConnectionData *d;
633 d = BUS_CONNECTION_DATA (connection);
635 _dbus_assert (d != NULL);
637 return bus_context_get_registry (d->connections->context);
641 bus_connection_get_activation (DBusConnection *connection)
643 BusConnectionData *d;
645 d = BUS_CONNECTION_DATA (connection);
647 _dbus_assert (d != NULL);
649 return bus_context_get_activation (d->connections->context);
653 * Checks whether the connection is registered with the message bus.
655 * @param connection the connection
656 * @returns #TRUE if we're an active message bus participant
659 bus_connection_is_active (DBusConnection *connection)
661 BusConnectionData *d;
663 d = BUS_CONNECTION_DATA (connection);
665 return d != NULL && d->name != NULL;
669 bus_connection_preallocate_oom_error (DBusConnection *connection)
671 DBusMessage *message;
672 DBusPreallocatedSend *preallocated;
673 BusConnectionData *d;
675 d = BUS_CONNECTION_DATA (connection);
677 _dbus_assert (d != NULL);
679 if (d->oom_preallocated != NULL)
682 preallocated = dbus_connection_preallocate_send (connection);
683 if (preallocated == NULL)
686 /* d->name may be NULL, but that should be OK */
687 message = dbus_message_new (d->name,
688 DBUS_ERROR_NO_MEMORY);
691 dbus_connection_free_preallocated_send (connection, preallocated);
695 dbus_message_set_is_error (message, TRUE);
697 if (!dbus_message_set_sender (message,
700 dbus_connection_free_preallocated_send (connection, preallocated);
701 dbus_message_unref (message);
705 /* set reply serial to placeholder value just so space is already allocated
708 if (!dbus_message_set_reply_serial (message, 14))
710 dbus_connection_free_preallocated_send (connection, preallocated);
711 dbus_message_unref (message);
715 d->oom_message = message;
716 d->oom_preallocated = preallocated;
722 bus_connection_send_oom_error (DBusConnection *connection,
723 DBusMessage *in_reply_to)
725 BusConnectionData *d;
727 d = BUS_CONNECTION_DATA (connection);
729 _dbus_assert (d != NULL);
730 _dbus_assert (d->oom_message != NULL);
732 /* should always succeed since we set it to a placeholder earlier */
733 if (!dbus_message_set_reply_serial (d->oom_message,
734 dbus_message_get_serial (in_reply_to)))
735 _dbus_assert_not_reached ("Failed to set reply serial for preallocated oom message");
737 _dbus_assert (dbus_message_get_sender (d->oom_message) != NULL);
739 dbus_connection_send_preallocated (connection, d->oom_preallocated,
740 d->oom_message, NULL);
742 dbus_message_unref (d->oom_message);
743 d->oom_message = NULL;
744 d->oom_preallocated = NULL;
748 bus_connection_add_owned_service_link (DBusConnection *connection,
751 BusConnectionData *d;
753 d = BUS_CONNECTION_DATA (connection);
754 _dbus_assert (d != NULL);
756 _dbus_list_append_link (&d->services_owned, link);
760 bus_connection_add_owned_service (DBusConnection *connection,
765 link = _dbus_list_alloc_link (service);
770 bus_connection_add_owned_service_link (connection, link);
776 bus_connection_remove_owned_service (DBusConnection *connection,
779 BusConnectionData *d;
781 d = BUS_CONNECTION_DATA (connection);
782 _dbus_assert (d != NULL);
784 _dbus_list_remove_last (&d->services_owned, service);
788 bus_connection_set_name (DBusConnection *connection,
789 const DBusString *name)
791 BusConnectionData *d;
793 d = BUS_CONNECTION_DATA (connection);
794 _dbus_assert (d != NULL);
795 _dbus_assert (d->name == NULL);
797 if (!_dbus_string_copy_data (name, &d->name))
800 _dbus_assert (d->name != NULL);
802 _dbus_verbose ("Name %s assigned to %p\n", d->name, connection);
808 bus_connection_get_name (DBusConnection *connection)
810 BusConnectionData *d;
812 d = BUS_CONNECTION_DATA (connection);
813 _dbus_assert (d != NULL);
821 * Note that this is fairly fragile; in particular, don't try to use
822 * one transaction across any main loop iterations.
827 BusTransaction *transaction;
828 DBusMessage *message;
829 DBusPreallocatedSend *preallocated;
834 BusTransactionCancelFunction cancel_function;
835 DBusFreeFunction free_data_function;
839 struct BusTransaction
841 DBusList *connections;
843 DBusList *cancel_hooks;
847 message_to_send_free (DBusConnection *connection,
848 MessageToSend *to_send)
850 if (to_send->message)
851 dbus_message_unref (to_send->message);
853 if (to_send->preallocated)
854 dbus_connection_free_preallocated_send (connection, to_send->preallocated);
860 cancel_hook_cancel (void *element,
863 CancelHook *ch = element;
865 _dbus_verbose ("Running transaction cancel hook\n");
867 if (ch->cancel_function)
868 (* ch->cancel_function) (ch->data);
872 cancel_hook_free (void *element,
875 CancelHook *ch = element;
877 if (ch->free_data_function)
878 (* ch->free_data_function) (ch->data);
884 free_cancel_hooks (BusTransaction *transaction)
886 _dbus_list_foreach (&transaction->cancel_hooks,
887 cancel_hook_free, NULL);
889 _dbus_list_clear (&transaction->cancel_hooks);
893 bus_transaction_new (BusContext *context)
895 BusTransaction *transaction;
897 transaction = dbus_new0 (BusTransaction, 1);
898 if (transaction == NULL)
901 transaction->context = context;
907 bus_transaction_get_context (BusTransaction *transaction)
909 return transaction->context;
913 bus_transaction_get_connections (BusTransaction *transaction)
915 return bus_context_get_connections (transaction->context);
919 bus_transaction_send_from_driver (BusTransaction *transaction,
920 DBusConnection *connection,
921 DBusMessage *message)
923 /* We have to set the sender to the driver, and have
924 * to check security policy since it was not done in
927 _dbus_verbose ("Sending %s from driver\n",
928 dbus_message_get_name (message));
930 if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
933 /* If security policy doesn't allow the message, we silently
934 * eat it; the driver doesn't care about getting a reply.
936 if (!bus_context_check_security_policy (bus_transaction_get_context (transaction),
937 NULL, connection, message, NULL))
940 return bus_transaction_send (transaction, connection, message);
944 bus_transaction_send (BusTransaction *transaction,
945 DBusConnection *connection,
946 DBusMessage *message)
948 MessageToSend *to_send;
949 BusConnectionData *d;
952 _dbus_verbose (" trying to add %s %s to transaction%s\n",
953 dbus_message_get_is_error (message) ? "error" :
954 dbus_message_get_reply_serial (message) != -1 ? "reply" :
956 dbus_message_get_name (message),
957 dbus_connection_get_is_connected (connection) ?
958 "" : " (disconnected)");
960 _dbus_assert (dbus_message_get_sender (message) != NULL);
962 if (!dbus_connection_get_is_connected (connection))
963 return TRUE; /* silently ignore disconnected connections */
965 d = BUS_CONNECTION_DATA (connection);
966 _dbus_assert (d != NULL);
968 to_send = dbus_new (MessageToSend, 1);
974 to_send->preallocated = dbus_connection_preallocate_send (connection);
975 if (to_send->preallocated == NULL)
981 dbus_message_ref (message);
982 to_send->message = message;
983 to_send->transaction = transaction;
985 _dbus_verbose ("about to prepend message\n");
987 if (!_dbus_list_prepend (&d->transaction_messages, to_send))
989 message_to_send_free (connection, to_send);
993 _dbus_verbose ("prepended message\n");
995 /* See if we already had this connection in the list
996 * for this transaction. If we have a pending message,
997 * then we should already be in transaction->connections
999 link = _dbus_list_get_first_link (&d->transaction_messages);
1000 _dbus_assert (link->data == to_send);
1001 link = _dbus_list_get_next_link (&d->transaction_messages, link);
1002 while (link != NULL)
1004 MessageToSend *m = link->data;
1005 DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link);
1007 if (m->transaction == transaction)
1015 if (!_dbus_list_prepend (&transaction->connections, connection))
1017 _dbus_list_remove (&d->transaction_messages, to_send);
1018 message_to_send_free (connection, to_send);
1027 connection_cancel_transaction (DBusConnection *connection,
1028 BusTransaction *transaction)
1031 BusConnectionData *d;
1033 d = BUS_CONNECTION_DATA (connection);
1034 _dbus_assert (d != NULL);
1036 link = _dbus_list_get_first_link (&d->transaction_messages);
1037 while (link != NULL)
1039 MessageToSend *m = link->data;
1040 DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link);
1042 if (m->transaction == transaction)
1044 _dbus_list_remove_link (&d->transaction_messages,
1047 message_to_send_free (connection, m);
1055 bus_transaction_cancel_and_free (BusTransaction *transaction)
1057 DBusConnection *connection;
1059 _dbus_verbose ("TRANSACTION: cancelled\n");
1061 while ((connection = _dbus_list_pop_first (&transaction->connections)))
1062 connection_cancel_transaction (connection, transaction);
1064 _dbus_assert (transaction->connections == NULL);
1066 _dbus_list_foreach (&transaction->cancel_hooks,
1067 cancel_hook_cancel, NULL);
1069 free_cancel_hooks (transaction);
1071 dbus_free (transaction);
1075 connection_execute_transaction (DBusConnection *connection,
1076 BusTransaction *transaction)
1079 BusConnectionData *d;
1081 d = BUS_CONNECTION_DATA (connection);
1082 _dbus_assert (d != NULL);
1084 /* Send the queue in order (FIFO) */
1085 link = _dbus_list_get_last_link (&d->transaction_messages);
1086 while (link != NULL)
1088 MessageToSend *m = link->data;
1089 DBusList *prev = _dbus_list_get_prev_link (&d->transaction_messages, link);
1091 if (m->transaction == transaction)
1093 _dbus_list_remove_link (&d->transaction_messages,
1096 _dbus_assert (dbus_message_get_sender (m->message) != NULL);
1098 dbus_connection_send_preallocated (connection,
1103 m->preallocated = NULL; /* so we don't double-free it */
1105 message_to_send_free (connection, m);
1113 bus_transaction_execute_and_free (BusTransaction *transaction)
1115 /* For each connection in transaction->connections
1118 DBusConnection *connection;
1120 _dbus_verbose ("TRANSACTION: executing\n");
1122 while ((connection = _dbus_list_pop_first (&transaction->connections)))
1123 connection_execute_transaction (connection, transaction);
1125 _dbus_assert (transaction->connections == NULL);
1127 free_cancel_hooks (transaction);
1129 dbus_free (transaction);
1133 bus_connection_remove_transactions (DBusConnection *connection)
1135 MessageToSend *to_send;
1136 BusConnectionData *d;
1138 d = BUS_CONNECTION_DATA (connection);
1139 _dbus_assert (d != NULL);
1141 while ((to_send = _dbus_list_get_first (&d->transaction_messages)))
1143 /* only has an effect for the first MessageToSend listing this transaction */
1144 _dbus_list_remove (&to_send->transaction->connections,
1147 _dbus_list_remove (&d->transaction_messages, to_send);
1148 message_to_send_free (connection, to_send);
1153 * Converts the DBusError to a message reply
1156 bus_transaction_send_error_reply (BusTransaction *transaction,
1157 DBusConnection *connection,
1158 const DBusError *error,
1159 DBusMessage *in_reply_to)
1163 _dbus_assert (error != NULL);
1164 _DBUS_ASSERT_ERROR_IS_SET (error);
1166 reply = dbus_message_new_error_reply (in_reply_to,
1172 if (!bus_transaction_send_from_driver (transaction, connection, reply))
1174 dbus_message_unref (reply);
1178 dbus_message_unref (reply);
1184 bus_transaction_add_cancel_hook (BusTransaction *transaction,
1185 BusTransactionCancelFunction cancel_function,
1187 DBusFreeFunction free_data_function)
1191 ch = dbus_new (CancelHook, 1);
1195 ch->cancel_function = cancel_function;
1197 ch->free_data_function = free_data_function;
1199 /* It's important that the hooks get run in reverse order that they
1202 if (!_dbus_list_prepend (&transaction->cancel_hooks, ch))