D-Bus  1.4.10
dbus-server.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-server.c DBusServer object
3  *
4  * Copyright (C) 2002, 2003, 2004, 2005 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-server.h"
26 #include "dbus-server-unix.h"
27 #include "dbus-server-socket.h"
28 #include "dbus-string.h"
29 #ifdef DBUS_BUILD_TESTS
30 #include "dbus-server-debug-pipe.h"
31 #endif
32 #include "dbus-address.h"
33 #include "dbus-protocol.h"
34 
56 /* this is a little fragile since it assumes the address doesn't
57  * already have a guid, but it shouldn't
58  */
59 static char*
60 copy_address_with_guid_appended (const DBusString *address,
61  const DBusString *guid_hex)
62 {
63  DBusString with_guid;
64  char *retval;
65 
66  if (!_dbus_string_init (&with_guid))
67  return NULL;
68 
69  if (!_dbus_string_copy (address, 0, &with_guid,
70  _dbus_string_get_length (&with_guid)) ||
71  !_dbus_string_append (&with_guid, ",guid=") ||
72  !_dbus_string_copy (guid_hex, 0,
73  &with_guid, _dbus_string_get_length (&with_guid)))
74  {
75  _dbus_string_free (&with_guid);
76  return NULL;
77  }
78 
79  retval = NULL;
80  _dbus_string_steal_data (&with_guid, &retval);
81 
82  _dbus_string_free (&with_guid);
83 
84  return retval; /* may be NULL if steal_data failed */
85 }
86 
98  const DBusServerVTable *vtable,
99  const DBusString *address)
100 {
101  server->vtable = vtable;
102  server->refcount.value = 1;
103 
104  server->address = NULL;
105  server->watches = NULL;
106  server->timeouts = NULL;
107  server->published_address = FALSE;
108 
109  if (!_dbus_string_init (&server->guid_hex))
110  return FALSE;
111 
112  _dbus_generate_uuid (&server->guid);
113 
114  if (!_dbus_uuid_encode (&server->guid, &server->guid_hex))
115  goto failed;
116 
117  server->address = copy_address_with_guid_appended (address,
118  &server->guid_hex);
119  if (server->address == NULL)
120  goto failed;
121 
123  if (server->mutex == NULL)
124  goto failed;
125 
126  server->watches = _dbus_watch_list_new ();
127  if (server->watches == NULL)
128  goto failed;
129 
130  server->timeouts = _dbus_timeout_list_new ();
131  if (server->timeouts == NULL)
132  goto failed;
133 
135 
136  _dbus_verbose ("Initialized server on address %s\n", server->address);
137 
138  return TRUE;
139 
140  failed:
142  server->mutex = NULL;
143  if (server->watches)
144  {
145  _dbus_watch_list_free (server->watches);
146  server->watches = NULL;
147  }
148  if (server->timeouts)
149  {
151  server->timeouts = NULL;
152  }
153  if (server->address)
154  {
155  dbus_free (server->address);
156  server->address = NULL;
157  }
158  _dbus_string_free (&server->guid_hex);
159 
160  return FALSE;
161 }
162 
169 void
171 {
172  /* We don't have the lock, but nobody should be accessing
173  * concurrently since they don't have a ref
174  */
175 #ifndef DBUS_DISABLE_CHECKS
176  _dbus_assert (!server->have_server_lock);
177 #endif
178  _dbus_assert (server->disconnected);
179 
180  /* calls out to application code... */
182 
184 
185  _dbus_watch_list_free (server->watches);
187 
189 
190  dbus_free (server->address);
191 
193 
194  _dbus_string_free (&server->guid_hex);
195 }
196 
197 
200  DBusWatch *watch);
202 typedef void (* DBusWatchRemoveFunction) (DBusWatchList *list,
203  DBusWatch *watch);
205 typedef void (* DBusWatchToggleFunction) (DBusWatchList *list,
206  DBusWatch *watch,
207  dbus_bool_t enabled);
208 
209 static dbus_bool_t
210 protected_change_watch (DBusServer *server,
211  DBusWatch *watch,
212  DBusWatchAddFunction add_function,
213  DBusWatchRemoveFunction remove_function,
214  DBusWatchToggleFunction toggle_function,
215  dbus_bool_t enabled)
216 {
217  DBusWatchList *watches;
218  dbus_bool_t retval;
219 
220  HAVE_LOCK_CHECK (server);
221 
222  /* This isn't really safe or reasonable; a better pattern is the "do
223  * everything, then drop lock and call out" one; but it has to be
224  * propagated up through all callers
225  */
226 
227  watches = server->watches;
228  if (watches)
229  {
230  server->watches = NULL;
231  _dbus_server_ref_unlocked (server);
232  SERVER_UNLOCK (server);
233 
234  if (add_function)
235  retval = (* add_function) (watches, watch);
236  else if (remove_function)
237  {
238  retval = TRUE;
239  (* remove_function) (watches, watch);
240  }
241  else
242  {
243  retval = TRUE;
244  (* toggle_function) (watches, watch, enabled);
245  }
246 
247  SERVER_LOCK (server);
248  server->watches = watches;
250 
251  return retval;
252  }
253  else
254  return FALSE;
255 }
256 
266  DBusWatch *watch)
267 {
268  HAVE_LOCK_CHECK (server);
269  return protected_change_watch (server, watch,
271  NULL, NULL, FALSE);
272 }
273 
280 void
282  DBusWatch *watch)
283 {
284  HAVE_LOCK_CHECK (server);
285  protected_change_watch (server, watch,
286  NULL,
288  NULL, FALSE);
289 }
290 
300 void
302  DBusWatch *watch,
303  dbus_bool_t enabled)
304 {
305  _dbus_assert (watch != NULL);
306 
307  HAVE_LOCK_CHECK (server);
308  protected_change_watch (server, watch,
309  NULL, NULL,
311  enabled);
312 }
313 
316  DBusTimeout *timeout);
319  DBusTimeout *timeout);
322  DBusTimeout *timeout,
323  dbus_bool_t enabled);
324 
325 
326 static dbus_bool_t
327 protected_change_timeout (DBusServer *server,
328  DBusTimeout *timeout,
329  DBusTimeoutAddFunction add_function,
330  DBusTimeoutRemoveFunction remove_function,
331  DBusTimeoutToggleFunction toggle_function,
332  dbus_bool_t enabled)
333 {
334  DBusTimeoutList *timeouts;
335  dbus_bool_t retval;
336 
337  HAVE_LOCK_CHECK (server);
338 
339  /* This isn't really safe or reasonable; a better pattern is the "do everything, then
340  * drop lock and call out" one; but it has to be propagated up through all callers
341  */
342 
343  timeouts = server->timeouts;
344  if (timeouts)
345  {
346  server->timeouts = NULL;
347  _dbus_server_ref_unlocked (server);
348  SERVER_UNLOCK (server);
349 
350  if (add_function)
351  retval = (* add_function) (timeouts, timeout);
352  else if (remove_function)
353  {
354  retval = TRUE;
355  (* remove_function) (timeouts, timeout);
356  }
357  else
358  {
359  retval = TRUE;
360  (* toggle_function) (timeouts, timeout, enabled);
361  }
362 
363  SERVER_LOCK (server);
364  server->timeouts = timeouts;
366 
367  return retval;
368  }
369  else
370  return FALSE;
371 }
372 
384  DBusTimeout *timeout)
385 {
386  return protected_change_timeout (server, timeout,
388  NULL, NULL, FALSE);
389 }
390 
397 void
399  DBusTimeout *timeout)
400 {
401  protected_change_timeout (server, timeout,
402  NULL,
404  NULL, FALSE);
405 }
406 
416 void
418  DBusTimeout *timeout,
419  dbus_bool_t enabled)
420 {
421  protected_change_timeout (server, timeout,
422  NULL, NULL,
424  enabled);
425 }
426 
427 
433 void
435 {
436  _dbus_assert (server != NULL);
437  _dbus_assert (server->refcount.value > 0);
438 
439  HAVE_LOCK_CHECK (server);
440 
441 #ifdef DBUS_HAVE_ATOMIC_INT
442  _dbus_atomic_inc (&server->refcount);
443 #else
444  _dbus_assert (server->refcount.value > 0);
445 
446  server->refcount.value += 1;
447 #endif
448 }
449 
455 void
457 {
458  dbus_bool_t last_unref;
459 
460  /* Keep this in sync with dbus_server_unref */
461 
462  _dbus_assert (server != NULL);
463  _dbus_assert (server->refcount.value > 0);
464 
465  HAVE_LOCK_CHECK (server);
466 
467 #ifdef DBUS_HAVE_ATOMIC_INT
468  last_unref = (_dbus_atomic_dec (&server->refcount) == 1);
469 #else
470  _dbus_assert (server->refcount.value > 0);
471 
472  server->refcount.value -= 1;
473  last_unref = (server->refcount.value == 0);
474 #endif
475 
476  if (last_unref)
477  {
478  _dbus_assert (server->disconnected);
479 
480  SERVER_UNLOCK (server);
481 
482  _dbus_assert (server->vtable->finalize != NULL);
483 
484  (* server->vtable->finalize) (server);
485  }
486 }
487 
509 static const struct {
510  DBusServerListenResult (* func) (DBusAddressEntry *entry,
511  DBusServer **server_p,
512  DBusError *error);
513 } listen_funcs[] = {
516 #ifdef DBUS_BUILD_TESTS
517  , { _dbus_server_listen_debug_pipe }
518 #endif
519 };
520 
541 DBusServer*
542 dbus_server_listen (const char *address,
543  DBusError *error)
544 {
545  DBusServer *server;
546  DBusAddressEntry **entries;
547  int len, i;
548  DBusError first_connect_error = DBUS_ERROR_INIT;
549  dbus_bool_t handled_once;
550 
551  _dbus_return_val_if_fail (address != NULL, NULL);
552  _dbus_return_val_if_error_is_set (error, NULL);
553 
554  if (!dbus_parse_address (address, &entries, &len, error))
555  return NULL;
556 
557  server = NULL;
558  handled_once = FALSE;
559 
560  for (i = 0; i < len; i++)
561  {
562  int j;
563 
564  for (j = 0; j < (int) _DBUS_N_ELEMENTS (listen_funcs); ++j)
565  {
566  DBusServerListenResult result;
567  DBusError tmp_error = DBUS_ERROR_INIT;
568 
569  result = (* listen_funcs[j].func) (entries[i],
570  &server,
571  &tmp_error);
572 
573  if (result == DBUS_SERVER_LISTEN_OK)
574  {
575  _dbus_assert (server != NULL);
576  _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
577  handled_once = TRUE;
578  goto out;
579  }
580  else if (result == DBUS_SERVER_LISTEN_ADDRESS_ALREADY_USED)
581  {
582  _dbus_assert (server == NULL);
583  dbus_set_error (error,
585  "Address '%s' already used",
586  dbus_address_entry_get_method (entries[0]));
587  handled_once = TRUE;
588  goto out;
589  }
590  else if (result == DBUS_SERVER_LISTEN_BAD_ADDRESS)
591  {
592  _dbus_assert (server == NULL);
593  _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
594  dbus_move_error (&tmp_error, error);
595  handled_once = TRUE;
596  goto out;
597  }
598  else if (result == DBUS_SERVER_LISTEN_NOT_HANDLED)
599  {
600  _dbus_assert (server == NULL);
601  _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
602 
603  /* keep trying addresses */
604  }
605  else if (result == DBUS_SERVER_LISTEN_DID_NOT_CONNECT)
606  {
607  _dbus_assert (server == NULL);
608  _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
609  if (!dbus_error_is_set (&first_connect_error))
610  dbus_move_error (&tmp_error, &first_connect_error);
611  else
612  dbus_error_free (&tmp_error);
613 
614  handled_once = TRUE;
615 
616  /* keep trying addresses */
617  }
618  }
619 
620  _dbus_assert (server == NULL);
621  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
622  }
623 
624  out:
625 
626  if (!handled_once)
627  {
628  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
629  if (len > 0)
630  dbus_set_error (error,
632  "Unknown address type '%s'",
633  dbus_address_entry_get_method (entries[0]));
634  else
635  dbus_set_error (error,
637  "Empty address '%s'",
638  address);
639  }
640 
641  dbus_address_entries_free (entries);
642 
643  if (server == NULL)
644  {
645  _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error) ||
646  dbus_error_is_set (error));
647 
648  if (error && dbus_error_is_set (error))
649  {
650  /* already set the error */
651  }
652  else
653  {
654  /* didn't set the error but either error should be
655  * NULL or first_connect_error should be set.
656  */
657  _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error));
658  dbus_move_error (&first_connect_error, error);
659  }
660 
661  _DBUS_ASSERT_ERROR_IS_CLEAR (&first_connect_error); /* be sure we freed it */
662  _DBUS_ASSERT_ERROR_IS_SET (error);
663 
664  return NULL;
665  }
666  else
667  {
668  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
669  return server;
670  }
671 }
672 
679 DBusServer *
681 {
682  _dbus_return_val_if_fail (server != NULL, NULL);
683  _dbus_return_val_if_fail (server->refcount.value > 0, NULL);
684 
685 #ifdef DBUS_HAVE_ATOMIC_INT
686  _dbus_atomic_inc (&server->refcount);
687 #else
688  SERVER_LOCK (server);
689  _dbus_assert (server->refcount.value > 0);
690 
691  server->refcount.value += 1;
692  SERVER_UNLOCK (server);
693 #endif
694 
695  return server;
696 }
697 
706 void
708 {
709  dbus_bool_t last_unref;
710 
711  /* keep this in sync with unref_unlocked */
712 
713  _dbus_return_if_fail (server != NULL);
714  _dbus_return_if_fail (server->refcount.value > 0);
715 
716 #ifdef DBUS_HAVE_ATOMIC_INT
717  last_unref = (_dbus_atomic_dec (&server->refcount) == 1);
718 #else
719  SERVER_LOCK (server);
720 
721  _dbus_assert (server->refcount.value > 0);
722 
723  server->refcount.value -= 1;
724  last_unref = (server->refcount.value == 0);
725 
726  SERVER_UNLOCK (server);
727 #endif
728 
729  if (last_unref)
730  {
731  /* lock not held! */
732  _dbus_assert (server->disconnected);
733 
734  _dbus_assert (server->vtable->finalize != NULL);
735 
736  (* server->vtable->finalize) (server);
737  }
738 }
739 
748 void
750 {
751  _dbus_return_if_fail (server != NULL);
752  _dbus_return_if_fail (server->refcount.value > 0);
753 
754  SERVER_LOCK (server);
755  _dbus_server_ref_unlocked (server);
756 
757  _dbus_assert (server->vtable->disconnect != NULL);
758 
759  if (!server->disconnected)
760  {
761  /* this has to be first so recursive calls to disconnect don't happen */
762  server->disconnected = TRUE;
763 
764  (* server->vtable->disconnect) (server);
765  }
766 
767  SERVER_UNLOCK (server);
768  dbus_server_unref (server);
769 }
770 
778 {
779  dbus_bool_t retval;
780 
781  _dbus_return_val_if_fail (server != NULL, FALSE);
782 
783  SERVER_LOCK (server);
784  retval = !server->disconnected;
785  SERVER_UNLOCK (server);
786 
787  return retval;
788 }
789 
797 char*
799 {
800  char *retval;
801 
802  _dbus_return_val_if_fail (server != NULL, NULL);
803 
804  SERVER_LOCK (server);
805  retval = _dbus_strdup (server->address);
806  SERVER_UNLOCK (server);
807 
808  return retval;
809 }
810 
833 char*
835 {
836  char *retval;
837 
838  _dbus_return_val_if_fail (server != NULL, NULL);
839 
840  SERVER_LOCK (server);
841  retval = NULL;
842  _dbus_string_copy_data (&server->guid_hex, &retval);
843  SERVER_UNLOCK (server);
844 
845  return retval;
846 }
847 
868 void
870  DBusNewConnectionFunction function,
871  void *data,
872  DBusFreeFunction free_data_function)
873 {
874  DBusFreeFunction old_free_function;
875  void *old_data;
876 
877  _dbus_return_if_fail (server != NULL);
878 
879  SERVER_LOCK (server);
880  old_free_function = server->new_connection_free_data_function;
881  old_data = server->new_connection_data;
882 
883  server->new_connection_function = function;
884  server->new_connection_data = data;
885  server->new_connection_free_data_function = free_data_function;
886  SERVER_UNLOCK (server);
887 
888  if (old_free_function != NULL)
889  (* old_free_function) (old_data);
890 }
891 
910  DBusAddWatchFunction add_function,
911  DBusRemoveWatchFunction remove_function,
912  DBusWatchToggledFunction toggled_function,
913  void *data,
914  DBusFreeFunction free_data_function)
915 {
916  dbus_bool_t result;
917  DBusWatchList *watches;
918 
919  _dbus_return_val_if_fail (server != NULL, FALSE);
920 
921  SERVER_LOCK (server);
922  watches = server->watches;
923  server->watches = NULL;
924  if (watches)
925  {
926  SERVER_UNLOCK (server);
927  result = _dbus_watch_list_set_functions (watches,
928  add_function,
929  remove_function,
930  toggled_function,
931  data,
932  free_data_function);
933  SERVER_LOCK (server);
934  }
935  else
936  {
937  _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
938  result = FALSE;
939  }
940  server->watches = watches;
941  SERVER_UNLOCK (server);
942 
943  return result;
944 }
945 
963  DBusAddTimeoutFunction add_function,
964  DBusRemoveTimeoutFunction remove_function,
965  DBusTimeoutToggledFunction toggled_function,
966  void *data,
967  DBusFreeFunction free_data_function)
968 {
969  dbus_bool_t result;
970  DBusTimeoutList *timeouts;
971 
972  _dbus_return_val_if_fail (server != NULL, FALSE);
973 
974  SERVER_LOCK (server);
975  timeouts = server->timeouts;
976  server->timeouts = NULL;
977  if (timeouts)
978  {
979  SERVER_UNLOCK (server);
980  result = _dbus_timeout_list_set_functions (timeouts,
981  add_function,
982  remove_function,
983  toggled_function,
984  data,
985  free_data_function);
986  SERVER_LOCK (server);
987  }
988  else
989  {
990  _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
991  result = FALSE;
992  }
993  server->timeouts = timeouts;
994  SERVER_UNLOCK (server);
995 
996  return result;
997 }
998 
1014  const char **mechanisms)
1015 {
1016  char **copy;
1017 
1018  _dbus_return_val_if_fail (server != NULL, FALSE);
1019 
1020  SERVER_LOCK (server);
1021 
1022  if (mechanisms != NULL)
1023  {
1024  copy = _dbus_dup_string_array (mechanisms);
1025  if (copy == NULL)
1026  return FALSE;
1027  }
1028  else
1029  copy = NULL;
1030 
1032  server->auth_mechanisms = copy;
1033 
1034  SERVER_UNLOCK (server);
1035 
1036  return TRUE;
1037 }
1038 
1039 
1040 static DBusDataSlotAllocator slot_allocator;
1041 _DBUS_DEFINE_GLOBAL_LOCK (server_slots);
1042 
1059 {
1060  return _dbus_data_slot_allocator_alloc (&slot_allocator,
1061  (DBusMutex **)&_DBUS_LOCK_NAME (server_slots),
1062  slot_p);
1063 }
1064 
1076 void
1078 {
1079  _dbus_return_if_fail (*slot_p >= 0);
1080 
1081  _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
1082 }
1083 
1099  int slot,
1100  void *data,
1101  DBusFreeFunction free_data_func)
1102 {
1103  DBusFreeFunction old_free_func;
1104  void *old_data;
1105  dbus_bool_t retval;
1106 
1107  _dbus_return_val_if_fail (server != NULL, FALSE);
1108 
1109  SERVER_LOCK (server);
1110 
1111  retval = _dbus_data_slot_list_set (&slot_allocator,
1112  &server->slot_list,
1113  slot, data, free_data_func,
1114  &old_free_func, &old_data);
1115 
1116 
1117  SERVER_UNLOCK (server);
1118 
1119  if (retval)
1120  {
1121  /* Do the actual free outside the server lock */
1122  if (old_free_func)
1123  (* old_free_func) (old_data);
1124  }
1125 
1126  return retval;
1127 }
1128 
1137 void*
1139  int slot)
1140 {
1141  void *res;
1142 
1143  _dbus_return_val_if_fail (server != NULL, NULL);
1144 
1145  SERVER_LOCK (server);
1146 
1147  res = _dbus_data_slot_list_get (&slot_allocator,
1148  &server->slot_list,
1149  slot);
1150 
1151  SERVER_UNLOCK (server);
1152 
1153  return res;
1154 }
1155 
1158 #ifdef DBUS_BUILD_TESTS
1159 #include "dbus-test.h"
1160 #include <string.h>
1161 
1163 _dbus_server_test (void)
1164 {
1165  const char *valid_addresses[] = {
1166  "tcp:port=1234",
1167  "tcp:host=localhost,port=1234",
1168  "tcp:host=localhost,port=1234;tcp:port=5678",
1169 #ifdef DBUS_UNIX
1170  "unix:path=./boogie",
1171  "tcp:port=1234;unix:path=./boogie",
1172 #endif
1173  };
1174 
1175  DBusServer *server;
1176  int i;
1177 
1178  for (i = 0; i < _DBUS_N_ELEMENTS (valid_addresses); i++)
1179  {
1180  DBusError error = DBUS_ERROR_INIT;
1181  char *address;
1182  char *id;
1183 
1184  server = dbus_server_listen (valid_addresses[i], &error);
1185  if (server == NULL)
1186  {
1187  _dbus_warn ("server listen error: %s: %s\n", error.name, error.message);
1188  dbus_error_free (&error);
1189  _dbus_assert_not_reached ("Failed to listen for valid address.");
1190  }
1191 
1192  id = dbus_server_get_id (server);
1193  _dbus_assert (id != NULL);
1194  address = dbus_server_get_address (server);
1195  _dbus_assert (address != NULL);
1196 
1197  if (strstr (address, id) == NULL)
1198  {
1199  _dbus_warn ("server id '%s' is not in the server address '%s'\n",
1200  id, address);
1201  _dbus_assert_not_reached ("bad server id or address");
1202  }
1203 
1204  dbus_free (id);
1205  dbus_free (address);
1206 
1207  dbus_server_disconnect (server);
1208  dbus_server_unref (server);
1209  }
1210 
1211  return TRUE;
1212 }
1213 
1214 #endif /* DBUS_BUILD_TESTS */