D-Bus  1.8.22
dbus-connection.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-connection.c DBusConnection object
3  *
4  * Copyright (C) 2002-2006 Red Hat Inc.
5  *
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  *
22  */
23 
24 #include <config.h>
25 #include "dbus-shared.h"
26 #include "dbus-connection.h"
27 #include "dbus-list.h"
28 #include "dbus-timeout.h"
29 #include "dbus-transport.h"
30 #include "dbus-watch.h"
31 #include "dbus-connection-internal.h"
32 #include "dbus-pending-call-internal.h"
33 #include "dbus-list.h"
34 #include "dbus-hash.h"
35 #include "dbus-message-internal.h"
36 #include "dbus-message-private.h"
37 #include "dbus-threads.h"
38 #include "dbus-protocol.h"
39 #include "dbus-dataslot.h"
40 #include "dbus-string.h"
41 #include "dbus-signature.h"
42 #include "dbus-pending-call.h"
43 #include "dbus-object-tree.h"
44 #include "dbus-threads-internal.h"
45 #include "dbus-bus.h"
46 #include "dbus-marshal-basic.h"
47 
48 #ifdef DBUS_DISABLE_CHECKS
49 #define TOOK_LOCK_CHECK(connection)
50 #define RELEASING_LOCK_CHECK(connection)
51 #define HAVE_LOCK_CHECK(connection)
52 #else
53 #define TOOK_LOCK_CHECK(connection) do { \
54  _dbus_assert (!(connection)->have_connection_lock); \
55  (connection)->have_connection_lock = TRUE; \
56  } while (0)
57 #define RELEASING_LOCK_CHECK(connection) do { \
58  _dbus_assert ((connection)->have_connection_lock); \
59  (connection)->have_connection_lock = FALSE; \
60  } while (0)
61 #define HAVE_LOCK_CHECK(connection) _dbus_assert ((connection)->have_connection_lock)
62 /* A "DO_NOT_HAVE_LOCK_CHECK" is impossible since we need the lock to check the flag */
63 #endif
64 
65 #define TRACE_LOCKS 1
66 
67 #define CONNECTION_LOCK(connection) do { \
68  if (TRACE_LOCKS) { _dbus_verbose ("LOCK\n"); } \
69  _dbus_rmutex_lock ((connection)->mutex); \
70  TOOK_LOCK_CHECK (connection); \
71  } while (0)
72 
73 #define CONNECTION_UNLOCK(connection) _dbus_connection_unlock (connection)
74 
75 #define SLOTS_LOCK(connection) do { \
76  _dbus_rmutex_lock ((connection)->slot_mutex); \
77  } while (0)
78 
79 #define SLOTS_UNLOCK(connection) do { \
80  _dbus_rmutex_unlock ((connection)->slot_mutex); \
81  } while (0)
82 
83 #define DISPATCH_STATUS_NAME(s) \
84  ((s) == DBUS_DISPATCH_COMPLETE ? "complete" : \
85  (s) == DBUS_DISPATCH_DATA_REMAINS ? "data remains" : \
86  (s) == DBUS_DISPATCH_NEED_MEMORY ? "need memory" : \
87  "???")
88 
206 static void
207 _dbus_connection_trace_ref (DBusConnection *connection,
208  int old_refcount,
209  int new_refcount,
210  const char *why)
211 {
212 #ifdef DBUS_ENABLE_VERBOSE_MODE
213  static int enabled = -1;
214 
215  _dbus_trace_ref ("DBusConnection", connection, old_refcount, new_refcount,
216  why, "DBUS_CONNECTION_TRACE", &enabled);
217 #endif
218 }
219 
224 
229 {
232  void *user_data;
234 };
235 
236 
241 {
245 };
246 
247 #if HAVE_DECL_MSG_NOSIGNAL
248 static dbus_bool_t _dbus_modify_sigpipe = FALSE;
249 #else
250 static dbus_bool_t _dbus_modify_sigpipe = TRUE;
251 #endif
252 
257 {
291  dbus_uint32_t client_serial;
306  char *server_guid;
308  /* These two MUST be bools and not bitfields, because they are protected by a separate lock
309  * from connection->mutex and all bitfields in a word have to be read/written together.
310  * So you can't have a different lock for different bitfields in the same word.
311  */
315  unsigned int shareable : 1;
317  unsigned int exit_on_disconnect : 1;
319  unsigned int route_peer_messages : 1;
321  unsigned int disconnected_message_arrived : 1;
329 #ifndef DBUS_DISABLE_CHECKS
330  unsigned int have_connection_lock : 1;
331 #endif
332 
333 #if defined(DBUS_ENABLE_CHECKS) || defined(DBUS_ENABLE_ASSERT)
334  int generation;
335 #endif
336 };
337 
338 static DBusDispatchStatus _dbus_connection_get_dispatch_status_unlocked (DBusConnection *connection);
339 static void _dbus_connection_update_dispatch_status_and_unlock (DBusConnection *connection,
340  DBusDispatchStatus new_status);
341 static void _dbus_connection_last_unref (DBusConnection *connection);
342 static void _dbus_connection_acquire_dispatch (DBusConnection *connection);
343 static void _dbus_connection_release_dispatch (DBusConnection *connection);
344 static DBusDispatchStatus _dbus_connection_flush_unlocked (DBusConnection *connection);
345 static void _dbus_connection_close_possibly_shared_and_unlock (DBusConnection *connection);
346 static dbus_bool_t _dbus_connection_get_is_connected_unlocked (DBusConnection *connection);
347 static dbus_bool_t _dbus_connection_peek_for_reply_unlocked (DBusConnection *connection,
348  dbus_uint32_t client_serial);
349 
350 static DBusMessageFilter *
351 _dbus_message_filter_ref (DBusMessageFilter *filter)
352 {
353 #ifdef DBUS_DISABLE_ASSERT
354  _dbus_atomic_inc (&filter->refcount);
355 #else
356  dbus_int32_t old_value;
357 
358  old_value = _dbus_atomic_inc (&filter->refcount);
359  _dbus_assert (old_value > 0);
360 #endif
361 
362  return filter;
363 }
364 
365 static void
366 _dbus_message_filter_unref (DBusMessageFilter *filter)
367 {
368  dbus_int32_t old_value;
369 
370  old_value = _dbus_atomic_dec (&filter->refcount);
371  _dbus_assert (old_value > 0);
372 
373  if (old_value == 1)
374  {
375  if (filter->free_user_data_function)
376  (* filter->free_user_data_function) (filter->user_data);
377 
378  dbus_free (filter);
379  }
380 }
381 
387 void
389 {
390  CONNECTION_LOCK (connection);
391 }
392 
398 void
400 {
401  DBusList *expired_messages;
402  DBusList *iter;
403 
404  if (TRACE_LOCKS)
405  {
406  _dbus_verbose ("UNLOCK\n");
407  }
408 
409  /* If we had messages that expired (fell off the incoming or outgoing
410  * queues) while we were locked, actually release them now */
411  expired_messages = connection->expired_messages;
412  connection->expired_messages = NULL;
413 
414  RELEASING_LOCK_CHECK (connection);
415  _dbus_rmutex_unlock (connection->mutex);
416 
417  for (iter = _dbus_list_pop_first_link (&expired_messages);
418  iter != NULL;
419  iter = _dbus_list_pop_first_link (&expired_messages))
420  {
421  DBusMessage *message = iter->data;
422 
423  dbus_message_unref (message);
424  _dbus_list_free_link (iter);
425  }
426 }
427 
435 static void
436 _dbus_connection_wakeup_mainloop (DBusConnection *connection)
437 {
438  if (connection->wakeup_main_function)
439  (*connection->wakeup_main_function) (connection->wakeup_main_data);
440 }
441 
442 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
443 
455 void
456 _dbus_connection_test_get_locks (DBusConnection *connection,
457  DBusMutex **mutex_loc,
458  DBusMutex **dispatch_mutex_loc,
459  DBusMutex **io_path_mutex_loc,
460  DBusCondVar **dispatch_cond_loc,
461  DBusCondVar **io_path_cond_loc)
462 {
463  *mutex_loc = (DBusMutex *) connection->mutex;
464  *dispatch_mutex_loc = (DBusMutex *) connection->dispatch_mutex;
465  *io_path_mutex_loc = (DBusMutex *) connection->io_path_mutex;
466  *dispatch_cond_loc = connection->dispatch_cond;
467  *io_path_cond_loc = connection->io_path_cond;
468 }
469 #endif
470 
479 void
481  DBusList *link)
482 {
483  DBusPendingCall *pending;
484  dbus_uint32_t reply_serial;
485  DBusMessage *message;
486 
488 
490  link);
491  message = link->data;
492 
493  /* If this is a reply we're waiting on, remove timeout for it */
494  reply_serial = dbus_message_get_reply_serial (message);
495  if (reply_serial != 0)
496  {
497  pending = _dbus_hash_table_lookup_int (connection->pending_replies,
498