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