1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
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: #include <dbus/dbus-list.h>
32: #include <dbus/dbus-hash.h>
33: #include <dbus/dbus-timeout.h>
34:
35: static void bus_connection_remove_transactions (DBusConnection *connection);
36:
37: typedef struct
38: {
39: BusExpireItem expire_item;
40:
41: DBusConnection *will_get_reply;
42: DBusConnection *will_send_reply;
43:
44: dbus_uint32_t reply_serial;
45:
46: } BusPendingReply;
47:
48: struct BusConnections
49: {
50: int refcount;
51: DBusList *completed;
52: int n_completed;
53: DBusList *incomplete;
54: int n_incomplete;
55: BusContext *context;
56: DBusHashTable *completed_by_user;
57: DBusTimeout *expire_timeout;
58: int stamp;
59: BusExpireList *pending_replies;
60: };
61:
62: static dbus_int32_t connection_data_slot = -1;
63:
64: typedef struct
65: {
66: BusConnections *connections;
67: DBusList *link_in_connection_list;
68: DBusConnection *connection;
69: DBusList *services_owned;
70: int n_services_owned;
71: DBusList *match_rules;
72: int n_match_rules;
73: char *name;
74: DBusList *transaction_messages;
75: DBusMessage *oom_message;
76: DBusPreallocatedSend *oom_preallocated;
77: BusClientPolicy *policy;
78:
79: BusSELinuxID *selinux_id;
80:
81: long connection_tv_sec;
82: long connection_tv_usec;
83: int stamp;
84: } BusConnectionData;
85:
86: static dbus_bool_t bus_pending_reply_expired (BusExpireList *list,
87: DBusList *link,
88: void *data);
89:
90: static void bus_connection_drop_pending_replies (BusConnections *connections,
91: DBusConnection *connection);
92:
93: static dbus_bool_t expire_incomplete_timeout (void *data);
94:
95: #define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot))
96:
97: static DBusLoop*
98: connection_get_loop (DBusConnection *connection)
99: {
100: BusConnectionData *d;
101:
102: d = BUS_CONNECTION_DATA (connection);
103:
104: return bus_context_get_loop (d->connections->context);
105: }
106:
107:
108: static int
109: get_connections_for_uid (BusConnections *connections,
110: dbus_uid_t uid)
111: {
112: void *val;
113: int current_count;
114:
115:
116:
117: val = _dbus_hash_table_lookup_ulong (connections->completed_by_user,
118: uid);
119:
120: current_count = _DBUS_POINTER_TO_INT (val);
121:
122: return current_count;
123: }
124:
125: static dbus_bool_t
126: adjust_connections_for_uid (BusConnections *connections,
127: dbus_uid_t uid,
128: int adjustment)
129: {
130: int current_count;
131:
132: current_count = get_connections_for_uid (connections, uid);
133:
134: _dbus_verbose ("Adjusting connection count for UID " DBUS_UID_FORMAT
135: ": was %d adjustment %d making %d\n",
136: uid, current_count, adjustment, current_count + adjustment);
137:
138: _dbus_assert (current_count >= 0);
139:
140: current_count += adjustment;
141:
142: _dbus_assert (current_count >= 0);
143:
144: if (current_count == 0)
145: {
146: _dbus_hash_table_remove_ulong (connections->completed_by_user, uid);
147: return TRUE;
148: }
149: else
150: {
151: dbus_bool_t retval;
152:
153: retval = _dbus_hash_table_insert_ulong (connections->completed_by_user,
154: uid, _DBUS_INT_TO_POINTER (current_count));
155:
156:
157:
158:
159: _dbus_assert (adjustment > 0 ||
160: (adjustment <= 0 && retval));
161:
162: return retval;
163: }
164: }
165:
166: void
167: bus_connection_disconnected (DBusConnection *connection)
168: {
169: BusConnectionData *d;
170: BusService *service;
171: BusMatchmaker *matchmaker;
172:
173: d = BUS_CONNECTION_DATA (connection);
174: _dbus_assert (d != NULL);
175:
176: _dbus_verbose ("%s disconnected, dropping all service ownership and releasing\n",
177: d->name ? d->name : "(inactive)");
178:
179:
180: if (d->n_match_rules > 0)
181: {
182: matchmaker = bus_context_get_matchmaker (d->connections->context);
183: bus_matchmaker_disconnected (matchmaker, connection);
184: }
185:
186:
187:
188:
189:
190:
191:
192:
193: while ((service = _dbus_list_get_last (&d->services_owned)))
194: {
195: BusTransaction *transaction;
196: DBusError error;
197:
198: retry:
199:
200: dbus_error_init (&error);
201:
202: while ((transaction = bus_transaction_new (d->connections->context)) == NULL)
203: _dbus_wait_for_memory ();
204:
205: if (!bus_service_remove_owner (service, connection,
206: transaction, &error))
207: {
208: _DBUS_ASSERT_ERROR_IS_SET (&error);
209:
210: if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
211: {
212: dbus_error_free (&error);
213: bus_transaction_cancel_and_free (transaction);
214: _dbus_wait_for_memory ();
215: goto retry;
216: }
217: else
218: {
219: _dbus_verbose ("Failed to remove service owner: %s %s\n",
220: error.name, error.message);
221: _dbus_assert_not_reached ("Removing service owner failed for non-memory-related reason");
222: }
223: }
224:
225: bus_transaction_execute_and_free (transaction);
226: }
227:
228: bus_dispatch_remove_connection (connection);
229:
230:
231: if (!dbus_connection_set_watch_functions (connection,
232: NULL, NULL, NULL,
233: connection,
234: NULL))
235: _dbus_assert_not_reached ("setting watch functions to NULL failed");
236:
237: if (!dbus_connection_set_timeout_functions (connection,
238: NULL, NULL, NULL,
239: connection,
240: NULL))
241: _dbus_assert_not_reached ("setting timeout functions to NULL failed");
242:
243: dbus_connection_set_unix_user_function (connection,
244: NULL, NULL, NULL);
245:
246: dbus_connection_set_dispatch_status_function (connection,
247: NULL, NULL, NULL);
248:
249: bus_connection_remove_transactions (connection);
250:
251: if (d->link_in_connection_list != NULL)
252: {
253: if (d->name != NULL)
254: {
255: unsigned long uid;
256:
257: _dbus_list_remove_link (&d->connections->completed, d->link_in_connection_list);
258: d->link_in_connection_list = NULL;
259: d->connections->n_completed -= 1;
260:
261: if (dbus_connection_get_unix_user (connection, &uid))
262: {
263: if (!adjust_connections_for_uid (d->connections,
264: uid, -1))
265: _dbus_assert_not_reached ("adjusting downward should never fail");
266: }
267: }
268: else
269: {
270: _dbus_list_remove_link (&d->connections->incomplete, d->link_in_connection_list);
271: d->link_in_connection_list = NULL;
272: d->connections->n_incomplete -= 1;
273: }
274:
275: _dbus_assert (d->connections->n_incomplete >= 0);
276: _dbus_assert (d->connections->n_completed >= 0);
277: }
278:
279: bus_connection_drop_pending_replies (d->connections, connection);
280:
281:
282: dbus_connection_set_data (connection,
283: connection_data_slot,
284: NULL, NULL);
285:
286: dbus_connection_unref (connection);
287: }
288:
289: static dbus_bool_t
290: connection_watch_callback (DBusWatch *watch,
291: unsigned int condition,
292: void *data)
293: {
294:
295:
296:
297:
298:
299: #if 0
300: _dbus_verbose ("Calling handle_watch\n");
301: #endif
302: return dbus_watch_handle (watch, condition);
303: }
304:
305: static dbus_bool_t
306: add_connection_watch (DBusWatch *watch,
307: void *data)
308: {
309: DBusConnection *connection = data;
310:
311: return _dbus_loop_add_watch (connection_get_loop (connection),
312: watch, connection_watch_callback, connection,
313: NULL);
314: }
315:
316: static void
317: remove_connection_watch (DBusWatch *watch,
318: void *data)
319: {
320: DBusConnection *connection = data;
321:
322: _dbus_loop_remove_watch (connection_get_loop (connection),
323: watch, connection_watch_callback, connection);
324: }
325:
326: static void
327: connection_timeout_callback (DBusTimeout *timeout,
328: void *data)
329: {
330:
331:
332:
333: dbus_timeout_handle (timeout);
334: }
335:
336: static dbus_bool_t
337: add_connection_timeout (DBusTimeout *timeout,
338: void *data)
339: {
340: DBusConnection *connection = data;
341:
342: return _dbus_loop_add_timeout (connection_get_loop (connection),
343: timeout, connection_timeout_callback, connection, NULL);
344: }
345:
346: static void
347: remove_connection_timeout (DBusTimeout *timeout,
348: void *data)
349: {
350: DBusConnection *connection = data;
351:
352: _dbus_loop_remove_timeout (connection_get_loop (connection),
353: timeout, connection_timeout_callback, connection);
354: }
355:
356: static void
357: dispatch_status_function (DBusConnection *connection,
358: DBusDispatchStatus new_status,
359: void *data)
360: {
361: DBusLoop *loop = data;
362:
363: if (new_status != DBUS_DISPATCH_COMPLETE)
364: {
365: while (!_dbus_loop_queue_dispatch (loop, connection))
366: _dbus_wait_for_memory ();
367: }
368: }
369:
370: static dbus_bool_t
371: allow_user_function (DBusConnection *connection,
372: unsigned long uid,
373: void *data)
374: {
375: BusConnectionData *d;
376:
377: d = BUS_CONNECTION_DATA (connection);
378:
379: _dbus_assert (d != NULL);
380:
381: return bus_context_allow_user (d->connections->context, uid);
382: }
383:
384: static void
385: free_connection_data (void *data)
386: {
387: BusConnectionData *d = data;
388:
389:
390: _dbus_assert (d->services_owned == NULL);
391: _dbus_assert (d->n_services_owned == 0);
392:
393: _dbus_assert (d->transaction_messages == NULL);
394:
395: if (d->oom_preallocated)
396: dbus_connection_free_preallocated_send (d->connection, d->oom_preallocated);
397:
398: if (d->oom_message)
399: dbus_message_unref (d->oom_message);
400:
401: if (d->policy)
402: bus_client_policy_unref (d->policy);
403:
404: if (d->selinux_id)
405: bus_selinux_id_unref (d->selinux_id);
406:
407: dbus_free (d->name);
408:
409: dbus_free (d);
410: }
411:
412: static void
413: call_timeout_callback (DBusTimeout *timeout,
414: void *data)
415: {
416:
417: dbus_timeout_handle (timeout);
418: }
419:
420: BusConnections*
421: bus_connections_new (BusContext *context)
422: {
423: BusConnections *connections;
424:
425: if (!dbus_connection_allocate_data_slot (&connection_data_slot))
426: goto failed_0;
427:
428: connections = dbus_new0 (BusConnections, 1);
429: if (connections == NULL)
430: goto failed_1;
431:
432: connections->completed_by_user = _dbus_hash_table_new (DBUS_HASH_ULONG,
433: NULL, NULL);
434: if (connections->completed_by_user == NULL)
435: goto failed_2;
436:
437: connections->expire_timeout = _dbus_timeout_new (100,
438: expire_incomplete_timeout,
439: connections, NULL);
440: if (connections->expire_timeout == NULL)
441: goto failed_3;
442:
443: _dbus_timeout_set_enabled (connections->expire_timeout, FALSE);
444:
445: connections->pending_replies = bus_expire_list_new (bus_context_get_loop (context),
446: bus_context_get_reply_timeout (context),
447: bus_pending_reply_expired,
448: connections);
449: if (connections->pending_replies == NULL)
450: goto failed_4;
451:
452: if (!_dbus_loop_add_timeout (bus_context_get_loop (context),
453: connections->expire_timeout,
454: call_timeout_callback, NULL, NULL))
455: goto failed_5;
456:
457: connections->refcount = 1;
458: connections->context = context;
459:
460: return connections;
461:
462: failed_5:
463: bus_expire_list_free (connections->pending_replies);
464: failed_4:
465: _dbus_timeout_unref (connections->expire_timeout);
466: failed_3:
467: _dbus_hash_table_unref (connections->completed_by_user);
468: failed_2:
469: dbus_free (connections);
470: failed_1:
471: dbus_connection_free_data_slot (&connection_data_slot);
472: failed_0:
473: return NULL;
474: }
475:
476: BusConnections *
477: bus_connections_ref (BusConnections *connections)
478: {
479: _dbus_assert (connections->refcount > 0);
480: connections->refcount += 1;
481:
482: return connections;
483: }
484:
485: void
486: bus_connections_unref (BusConnections *connections)
487: {
488: _dbus_assert (connections->refcount > 0);
489: connections->refcount -= 1;
490: if (connections->refcount == 0)
491: {
492:
493: while (connections->incomplete != NULL)
494: {
495: DBusConnection *connection;
496:
497: connection = connections->incomplete->data;
498:
499: dbus_connection_ref (connection);
500: dbus_connection_close (connection);
501: bus_connection_disconnected (connection);
502: dbus_connection_unref (connection);
503: }
504:
505: _dbus_assert (connections->n_incomplete == 0);
506:
507:
508: while (connections->completed != NULL)
509: {
510: DBusConnection *connection;
511:
512: connection = connections->completed->data;
513:
514: dbus_connection_ref (connection);
515: dbus_connection_close (connection);
516: bus_connection_disconnected (connection);
517: dbus_connection_unref (connection);
518: }
519:
520: _dbus_assert (connections->n_completed == 0);
521:
522: bus_expire_list_free (connections->pending_replies);
523:
524: _dbus_loop_remove_timeout (bus_context_get_loop (connections->context),
525: connections->expire_timeout,
526: call_timeout_callback, NULL);
527:
528: _dbus_timeout_unref (connections->expire_timeout);
529:
530: _dbus_hash_table_unref (connections->completed_by_user);
531:
532: dbus_free (connections);
533:
534: dbus_connection_free_data_slot (&connection_data_slot);
535: }
536: }
537:
538: dbus_bool_t
539: bus_connections_setup_connection (BusConnections *connections,
540: DBusConnection *connection)
541: {
542: BusConnectionData *d;
543: dbus_bool_t retval;
544: DBusError error;
545:
546: d = dbus_new0 (BusConnectionData, 1);
547:
548: if (d == NULL)
549: return FALSE;
550:
551: d->connections = connections;
552: d->connection = connection;
553:
554: _dbus_get_current_time (&d->connection_tv_sec,
555: &d->connection_tv_usec);
556:
557: _dbus_assert (connection_data_slot >= 0);
558:
559: if (!dbus_connection_set_data (connection,
560: connection_data_slot,
561: d, free_connection_data))
562: {
563: dbus_free (d);
564: return FALSE;
565: }
566:
567: dbus_connection_set_route_peer_messages (connection, TRUE);
568:
569: retval = FALSE;
570:
571: dbus_error_init (&error);
572: d->selinux_id = bus_selinux_init_connection_id (connection,
573: &error);
574: if (dbus_error_is_set (&error))
575: {
576:
577:
578:
579:
580:
581: dbus_error_free (&error);
582: goto out;
583: }
584:
585: if (!dbus_connection_set_watch_functions (connection,
586: add_connection_watch,
587: remove_connection_watch,
588: NULL,
589: connection,
590: NULL))
591: goto out;
592:
593: if (!dbus_connection_set_timeout_functions (connection,
594: add_connection_timeout,
595: remove_connection_timeout,
596: NULL,
597: connection, NULL))
598: goto out;
599:
600: dbus_connection_set_unix_user_function (connection,
601: allow_user_function,
602: NULL, NULL);
603:
604: dbus_connection_set_dispatch_status_function (connection,
605: dispatch_status_function,
606: bus_context_get_loop (connections->context),
607: NULL);
608:
609: d->link_in_connection_list = _dbus_list_alloc_link (connection);
610: if (d->link_in_connection_list == NULL)
611: goto out;
612:
613:
614: if (!bus_dispatch_add_connection (connection))
615: goto out;
616:
617: if (dbus_connection_get_dispatch_status (connection) != DBUS_DISPATCH_COMPLETE