D-Bus
1.10.12
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-server.c DBusServer object 00003 * 00004 * Copyright (C) 2002, 2003, 2004, 2005 Red Hat Inc. 00005 * 00006 * Licensed under the Academic Free License version 2.1 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 * 00022 */ 00023 00024 #include <config.h> 00025 #include "dbus-server.h" 00026 #include "dbus-server-unix.h" 00027 #include "dbus-server-socket.h" 00028 #include "dbus-string.h" 00029 #ifdef DBUS_ENABLE_EMBEDDED_TESTS 00030 #include "dbus-server-debug-pipe.h" 00031 #endif 00032 #include "dbus-address.h" 00033 #include "dbus-protocol.h" 00034 00056 #ifndef _dbus_server_trace_ref 00057 void 00058 _dbus_server_trace_ref (DBusServer *server, 00059 int old_refcount, 00060 int new_refcount, 00061 const char *why) 00062 { 00063 static int enabled = -1; 00064 00065 _dbus_trace_ref ("DBusServer", server, old_refcount, new_refcount, why, 00066 "DBUS_SERVER_TRACE", &enabled); 00067 } 00068 #endif 00069 00070 /* this is a little fragile since it assumes the address doesn't 00071 * already have a guid, but it shouldn't 00072 */ 00073 static char* 00074 copy_address_with_guid_appended (const DBusString *address, 00075 const DBusString *guid_hex) 00076 { 00077 DBusString with_guid; 00078 char *retval; 00079 00080 if (!_dbus_string_init (&with_guid)) 00081 return NULL; 00082 00083 if (!_dbus_string_copy (address, 0, &with_guid, 00084 _dbus_string_get_length (&with_guid)) || 00085 !_dbus_string_append (&with_guid, ",guid=") || 00086 !_dbus_string_copy (guid_hex, 0, 00087 &with_guid, _dbus_string_get_length (&with_guid))) 00088 { 00089 _dbus_string_free (&with_guid); 00090 return NULL; 00091 } 00092 00093 retval = NULL; 00094 _dbus_string_steal_data (&with_guid, &retval); 00095 00096 _dbus_string_free (&with_guid); 00097 00098 return retval; /* may be NULL if steal_data failed */ 00099 } 00100 00111 dbus_bool_t 00112 _dbus_server_init_base (DBusServer *server, 00113 const DBusServerVTable *vtable, 00114 const DBusString *address, 00115 DBusError *error) 00116 { 00117 server->vtable = vtable; 00118 00119 #ifdef DBUS_DISABLE_ASSERT 00120 _dbus_atomic_inc (&server->refcount); 00121 #else 00122 { 00123 dbus_int32_t old_refcount = _dbus_atomic_inc (&server->refcount); 00124 00125 _dbus_assert (old_refcount == 0); 00126 } 00127 #endif 00128 00129 server->address = NULL; 00130 server->watches = NULL; 00131 server->timeouts = NULL; 00132 server->published_address = FALSE; 00133 00134 if (!_dbus_string_init (&server->guid_hex)) 00135 { 00136 _DBUS_SET_OOM (error); 00137 return FALSE; 00138 } 00139 00140 if (!_dbus_generate_uuid (&server->guid, error)) 00141 goto failed; 00142 00143 if (!_dbus_uuid_encode (&server->guid, &server->guid_hex)) 00144 goto oom; 00145 00146 server->address = copy_address_with_guid_appended (address, 00147 &server->guid_hex); 00148 if (server->address == NULL) 00149 goto oom; 00150 00151 _dbus_rmutex_new_at_location (&server->mutex); 00152 if (server->mutex == NULL) 00153 goto oom; 00154 00155 server->watches = _dbus_watch_list_new (); 00156 if (server->watches == NULL) 00157 goto oom; 00158 00159 server->timeouts = _dbus_timeout_list_new (); 00160 if (server->timeouts == NULL) 00161 goto oom; 00162 00163 _dbus_data_slot_list_init (&server->slot_list); 00164 00165 _dbus_verbose ("Initialized server on address %s\n", server->address); 00166 00167 return TRUE; 00168 00169 oom: 00170 _DBUS_SET_OOM (error); 00171 failed: 00172 _dbus_rmutex_free_at_location (&server->mutex); 00173 server->mutex = NULL; 00174 if (server->watches) 00175 { 00176 _dbus_watch_list_free (server->watches); 00177 server->watches = NULL; 00178 } 00179 if (server->timeouts) 00180 { 00181 _dbus_timeout_list_free (server->timeouts); 00182 server->timeouts = NULL; 00183 } 00184 if (server->address) 00185 { 00186 dbus_free (server->address); 00187 server->address = NULL; 00188 } 00189 _dbus_string_free (&server->guid_hex); 00190 00191 return FALSE; 00192 } 00193 00200 void 00201 _dbus_server_finalize_base (DBusServer *server) 00202 { 00203 /* We don't have the lock, but nobody should be accessing 00204 * concurrently since they don't have a ref 00205 */ 00206 #ifndef DBUS_DISABLE_CHECKS 00207 _dbus_assert (!server->have_server_lock); 00208 #endif 00209 _dbus_assert (server->disconnected); 00210 00211 /* calls out to application code... */ 00212 _dbus_data_slot_list_free (&server->slot_list); 00213 00214 dbus_server_set_new_connection_function (server, NULL, NULL, NULL); 00215 00216 _dbus_watch_list_free (server->watches); 00217 _dbus_timeout_list_free (server->timeouts); 00218 00219 _dbus_rmutex_free_at_location (&server->mutex); 00220 00221 dbus_free (server->address); 00222 00223 dbus_free_string_array (server->auth_mechanisms); 00224 00225 _dbus_string_free (&server->guid_hex); 00226 } 00227 00228 00230 typedef dbus_bool_t (* DBusWatchAddFunction) (DBusWatchList *list, 00231 DBusWatch *watch); 00233 typedef void (* DBusWatchRemoveFunction) (DBusWatchList *list, 00234 DBusWatch *watch); 00236 typedef void (* DBusWatchToggleFunction) (DBusWatchList *list, 00237 DBusWatch *watch, 00238 dbus_bool_t enabled); 00239 00240 static dbus_bool_t 00241 protected_change_watch (DBusServer *server, 00242 DBusWatch *watch, 00243 DBusWatchAddFunction add_function, 00244 DBusWatchRemoveFunction remove_function, 00245 DBusWatchToggleFunction toggle_function, 00246 dbus_bool_t enabled) 00247 { 00248 DBusWatchList *watches; 00249 dbus_bool_t retval; 00250 00251 HAVE_LOCK_CHECK (server); 00252 00253 /* This isn't really safe or reasonable; a better pattern is the "do 00254 * everything, then drop lock and call out" one; but it has to be 00255 * propagated up through all callers 00256 */ 00257 00258 watches = server->watches; 00259 if (watches) 00260 { 00261 server->watches = NULL; 00262 _dbus_server_ref_unlocked (server); 00263 SERVER_UNLOCK (server); 00264 00265 if (add_function) 00266 retval = (* add_function) (watches, watch); 00267 else if (remove_function) 00268 { 00269 retval = TRUE; 00270 (* remove_function) (watches, watch); 00271 } 00272 else 00273 { 00274 retval = TRUE; 00275 (* toggle_function) (watches, watch, enabled); 00276 } 00277 00278 SERVER_LOCK (server); 00279 server->watches = watches; 00280 _dbus_server_unref_unlocked (server); 00281 00282 return retval; 00283 } 00284 else 00285 return FALSE; 00286 } 00287 00295 dbus_bool_t 00296 _dbus_server_add_watch (DBusServer *server, 00297 DBusWatch *watch) 00298 { 00299 HAVE_LOCK_CHECK (server); 00300 return protected_change_watch (server, watch, 00301 _dbus_watch_list_add_watch, 00302 NULL, NULL, FALSE); 00303 } 00304 00311 void 00312 _dbus_server_remove_watch (DBusServer *server, 00313 DBusWatch *watch) 00314 { 00315 HAVE_LOCK_CHECK (server); 00316 protected_change_watch (server, watch, 00317 NULL, 00318 _dbus_watch_list_remove_watch, 00319 NULL, FALSE); 00320 } 00321 00329 void 00330 _dbus_server_toggle_all_watches (DBusServer *server, 00331 dbus_bool_t enabled) 00332 { 00333 _dbus_watch_list_toggle_all_watches (server->watches, enabled); 00334 } 00335 00337 typedef dbus_bool_t (* DBusTimeoutAddFunction) (DBusTimeoutList *list, 00338 DBusTimeout *timeout); 00340 typedef void (* DBusTimeoutRemoveFunction) (DBusTimeoutList *list, 00341 DBusTimeout *timeout); 00343 typedef void (* DBusTimeoutToggleFunction) (DBusTimeoutList *list, 00344 DBusTimeout *timeout, 00345 dbus_bool_t enabled); 00346 00347 00348 static dbus_bool_t 00349 protected_change_timeout (DBusServer *server, 00350 DBusTimeout *timeout, 00351 DBusTimeoutAddFunction add_function, 00352 DBusTimeoutRemoveFunction remove_function, 00353 DBusTimeoutToggleFunction toggle_function, 00354 dbus_bool_t enabled) 00355 { 00356 DBusTimeoutList *timeouts; 00357 dbus_bool_t retval; 00358 00359 HAVE_LOCK_CHECK (server); 00360 00361 /* This isn't really safe or reasonable; a better pattern is the "do everything, then 00362 * drop lock and call out" one; but it has to be propagated up through all callers 00363 */ 00364 00365 timeouts = server->timeouts; 00366 if (timeouts) 00367 { 00368 server->timeouts = NULL; 00369 _dbus_server_ref_unlocked (server); 00370 SERVER_UNLOCK (server); 00371 00372 if (add_function) 00373 retval = (* add_function) (timeouts, timeout); 00374 else if (remove_function) 00375 { 00376 retval = TRUE; 00377 (* remove_function) (timeouts, timeout); 00378 } 00379 else 00380 { 00381 retval = TRUE; 00382 (* toggle_function) (timeouts, timeout, enabled); 00383 } 00384 00385 SERVER_LOCK (server); 00386 server->timeouts = timeouts; 00387 _dbus_server_unref_unlocked (server); 00388 00389 return retval; 00390 } 00391 else 00392 return FALSE; 00393 } 00394 00404 dbus_bool_t 00405 _dbus_server_add_timeout (DBusServer *server, 00406 DBusTimeout *timeout) 00407 { 00408 return protected_change_timeout (server, timeout, 00409 _dbus_timeout_list_add_timeout, 00410 NULL, NULL, FALSE); 00411 } 00412 00419 void 00420 _dbus_server_remove_timeout (DBusServer *server, 00421 DBusTimeout *timeout) 00422 { 00423 protected_change_timeout (server, timeout, 00424 NULL, 00425 _dbus_timeout_list_remove_timeout, 00426 NULL, FALSE); 00427 } 00428 00438 void 00439 _dbus_server_toggle_timeout (DBusServer *server, 00440 DBusTimeout *timeout, 00441 dbus_bool_t enabled) 00442 { 00443 protected_change_timeout (server, timeout, 00444 NULL, NULL, 00445 _dbus_timeout_list_toggle_timeout, 00446 enabled); 00447 } 00448 00449 00455 void 00456 _dbus_server_ref_unlocked (DBusServer *server) 00457 { 00458 dbus_int32_t old_refcount; 00459 00460 _dbus_assert (server != NULL); 00461 HAVE_LOCK_CHECK (server); 00462 00463 old_refcount = _dbus_atomic_inc (&server->refcount); 00464 _dbus_assert (old_refcount > 0); 00465 _dbus_server_trace_ref (server, old_refcount, old_refcount + 1, 00466 "ref_unlocked"); 00467 } 00468 00474 void 00475 _dbus_server_unref_unlocked (DBusServer *server) 00476 { 00477 dbus_int32_t old_refcount; 00478 00479 /* Keep this in sync with dbus_server_unref */ 00480 00481 _dbus_assert (server != NULL); 00482 00483 HAVE_LOCK_CHECK (server); 00484 00485 old_refcount = _dbus_atomic_dec (&server->refcount); 00486 _dbus_assert (old_refcount > 0); 00487 00488 _dbus_server_trace_ref (server, old_refcount, old_refcount - 1, 00489 "unref_unlocked"); 00490 00491 if (old_refcount == 1) 00492 { 00493 _dbus_assert (server->disconnected); 00494 00495 SERVER_UNLOCK (server); 00496 00497 _dbus_assert (server->vtable->finalize != NULL); 00498 00499 (* server->vtable->finalize) (server); 00500 } 00501 } 00502 00524 static const struct { 00525 DBusServerListenResult (* func) (DBusAddressEntry *entry, 00526 DBusServer **server_p, 00527 DBusError *error); 00528 } listen_funcs[] = { 00529 { _dbus_server_listen_socket } 00530 , { _dbus_server_listen_platform_specific } 00531 #ifdef DBUS_ENABLE_EMBEDDED_TESTS 00532 , { _dbus_server_listen_debug_pipe } 00533 #endif 00534 }; 00535 00556 DBusServer* 00557 dbus_server_listen (const char *address, 00558 DBusError *error) 00559 { 00560 DBusServer *server; 00561 DBusAddressEntry **entries; 00562 int len, i; 00563 DBusError first_connect_error = DBUS_ERROR_INIT; 00564 dbus_bool_t handled_once; 00565 00566 _dbus_return_val_if_fail (address != NULL, NULL); 00567 _dbus_return_val_if_error_is_set (error, NULL); 00568 00569 if (!dbus_parse_address (address, &entries, &len, error)) 00570 return NULL; 00571 00572 server = NULL; 00573 handled_once = FALSE; 00574 00575 for (i = 0; i < len; i++) 00576 { 00577 int j; 00578 00579 for (j = 0; j < (int) _DBUS_N_ELEMENTS (listen_funcs); ++j) 00580 { 00581 DBusServerListenResult result; 00582 DBusError tmp_error = DBUS_ERROR_INIT; 00583 00584 result = (* listen_funcs[j].func) (entries[i], 00585 &server, 00586 &tmp_error); 00587 00588 if (result == DBUS_SERVER_LISTEN_OK) 00589 { 00590 _dbus_assert (server != NULL); 00591 _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); 00592 handled_once = TRUE; 00593 goto out; 00594 } 00595 else if (result == DBUS_SERVER_LISTEN_ADDRESS_ALREADY_USED) 00596 { 00597 _dbus_assert (server == NULL); 00598 dbus_set_error (error, 00599 DBUS_ERROR_ADDRESS_IN_USE, 00600 "Address '%s' already used", 00601 dbus_address_entry_get_method (entries[0])); 00602 handled_once = TRUE; 00603 goto out; 00604 } 00605 else if (result == DBUS_SERVER_LISTEN_BAD_ADDRESS) 00606 { 00607 _dbus_assert (server == NULL); 00608 _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); 00609 dbus_move_error (&tmp_error, error); 00610 handled_once = TRUE; 00611 goto out; 00612 } 00613 else if (result == DBUS_SERVER_LISTEN_NOT_HANDLED) 00614 { 00615 _dbus_assert (server == NULL); 00616 _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); 00617 00618 /* keep trying addresses */ 00619 } 00620 else if (result == DBUS_SERVER_LISTEN_DID_NOT_CONNECT) 00621 { 00622 _dbus_assert (server == NULL); 00623 _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); 00624 if (!dbus_error_is_set (&first_connect_error)) 00625 dbus_move_error (&tmp_error, &first_connect_error); 00626 else 00627 dbus_error_free (&tmp_error); 00628 00629 handled_once = TRUE; 00630 00631 /* keep trying addresses */ 00632 } 00633 } 00634 00635 _dbus_assert (server == NULL); 00636 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00637 } 00638 00639 out: 00640 00641 if (!handled_once) 00642 { 00643 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00644 if (len > 0) 00645 dbus_set_error (error, 00646 DBUS_ERROR_BAD_ADDRESS, 00647 "Unknown address type '%s'", 00648 dbus_address_entry_get_method (entries[0])); 00649 else 00650 dbus_set_error (error, 00651 DBUS_ERROR_BAD_ADDRESS, 00652 "Empty address '%s'", 00653 address); 00654 } 00655 00656 dbus_address_entries_free (entries); 00657 00658 if (server == NULL) 00659 { 00660 _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error) || 00661 dbus_error_is_set (error)); 00662 00663 if (error && dbus_error_is_set (error)) 00664 { 00665 /* already set the error */ 00666 } 00667 else 00668 { 00669 /* didn't set the error but either error should be 00670 * NULL or first_connect_error should be set. 00671 */ 00672 _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error)); 00673 dbus_move_error (&first_connect_error, error); 00674 } 00675 00676 _DBUS_ASSERT_ERROR_IS_CLEAR (&first_connect_error); /* be sure we freed it */ 00677 _DBUS_ASSERT_ERROR_IS_SET (error); 00678 00679 return NULL; 00680 } 00681 else 00682 { 00683 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00684 return server; 00685 } 00686 } 00687 00694 DBusServer * 00695 dbus_server_ref (DBusServer *server) 00696 { 00697 dbus_int32_t old_refcount; 00698 00699 _dbus_return_val_if_fail (server != NULL, NULL); 00700 00701 old_refcount = _dbus_atomic_inc (&server->refcount); 00702 00703 #ifndef DBUS_DISABLE_CHECKS 00704 if (_DBUS_UNLIKELY (old_refcount <= 0)) 00705 { 00706 _dbus_atomic_dec (&server->refcount); 00707 _dbus_warn_check_failed (_dbus_return_if_fail_warning_format, 00708 _DBUS_FUNCTION_NAME, "old_refcount > 0", 00709 __FILE__, __LINE__); 00710 return NULL; 00711 } 00712 #endif 00713 00714 _dbus_server_trace_ref (server, old_refcount, old_refcount + 1, "ref"); 00715 00716 return server; 00717 } 00718 00727 void 00728 dbus_server_unref (DBusServer *server) 00729 { 00730 dbus_int32_t old_refcount; 00731 00732 /* keep this in sync with unref_unlocked */ 00733 00734 _dbus_return_if_fail (server != NULL); 00735 00736 old_refcount = _dbus_atomic_dec (&server->refcount); 00737 00738 #ifndef DBUS_DISABLE_CHECKS 00739 if (_DBUS_UNLIKELY (old_refcount <= 0)) 00740 { 00741 /* undo side-effect first 00742 * please do not try to simplify the code here by using 00743 * _dbus_atomic_get(), why we don't use it is 00744 * because it issues another atomic operation even though 00745 * DBUS_DISABLE_CHECKS defined. 00746 * Bug: https://bugs.freedesktop.org/show_bug.cgi?id=68303 00747 */ 00748 _dbus_atomic_inc (&server->refcount); 00749 _dbus_warn_check_failed (_dbus_return_if_fail_warning_format, 00750 _DBUS_FUNCTION_NAME, "old_refcount > 0", 00751 __FILE__, __LINE__); 00752 return; 00753 } 00754 #endif 00755 00756 _dbus_server_trace_ref (server, old_refcount, old_refcount - 1, "unref"); 00757 00758 if (old_refcount == 1) 00759 { 00760 /* lock not held! */ 00761 _dbus_assert (server->disconnected); 00762 00763 _dbus_assert (server->vtable->finalize != NULL); 00764 00765 (* server->vtable->finalize) (server); 00766 } 00767 } 00768 00777 void 00778 dbus_server_disconnect (DBusServer *server) 00779 { 00780 _dbus_return_if_fail (server != NULL); 00781 00782 dbus_server_ref (server); 00783 SERVER_LOCK (server); 00784 00785 _dbus_assert (server->vtable->disconnect != NULL); 00786 00787 if (!server->disconnected) 00788 { 00789 /* this has to be first so recursive calls to disconnect don't happen */ 00790 server->disconnected = TRUE; 00791 00792 (* server->vtable->disconnect) (server); 00793 } 00794 00795 SERVER_UNLOCK (server); 00796 dbus_server_unref (server); 00797 } 00798 00804 dbus_bool_t 00805 dbus_server_get_is_connected (DBusServer *server) 00806 { 00807 dbus_bool_t retval; 00808 00809 _dbus_return_val_if_fail (server != NULL, FALSE); 00810 00811 SERVER_LOCK (server); 00812 retval = !server->disconnected; 00813 SERVER_UNLOCK (server); 00814 00815 return retval; 00816 } 00817 00825 char* 00826 dbus_server_get_address (DBusServer *server) 00827 { 00828 char *retval; 00829 00830 _dbus_return_val_if_fail (server != NULL, NULL); 00831 00832 SERVER_LOCK (server); 00833 retval = _dbus_strdup (server->address); 00834 SERVER_UNLOCK (server); 00835 00836 return retval; 00837 } 00838 00861 char* 00862 dbus_server_get_id (DBusServer *server) 00863 { 00864 char *retval; 00865 00866 _dbus_return_val_if_fail (server != NULL, NULL); 00867 00868 SERVER_LOCK (server); 00869 retval = NULL; 00870 _dbus_string_copy_data (&server->guid_hex, &retval); 00871 SERVER_UNLOCK (server); 00872 00873 return retval; 00874 } 00875 00896 void 00897 dbus_server_set_new_connection_function (DBusServer *server, 00898 DBusNewConnectionFunction function, 00899 void *data, 00900 DBusFreeFunction free_data_function) 00901 { 00902 DBusFreeFunction old_free_function; 00903 void *old_data; 00904 00905 _dbus_return_if_fail (server != NULL); 00906 00907 SERVER_LOCK (server); 00908 old_free_function = server->new_connection_free_data_function; 00909 old_data = server->new_connection_data; 00910 00911 server->new_connection_function = function; 00912 server->new_connection_data = data; 00913 server->new_connection_free_data_function = free_data_function; 00914 SERVER_UNLOCK (server); 00915 00916 if (old_free_function != NULL) 00917 (* old_free_function) (old_data); 00918 } 00919 00936 dbus_bool_t 00937 dbus_server_set_watch_functions (DBusServer *server, 00938 DBusAddWatchFunction add_function, 00939 DBusRemoveWatchFunction remove_function, 00940 DBusWatchToggledFunction toggled_function, 00941 void *data, 00942 DBusFreeFunction free_data_function) 00943 { 00944 dbus_bool_t result; 00945 DBusWatchList *watches; 00946 00947 _dbus_return_val_if_fail (server != NULL, FALSE); 00948 00949 SERVER_LOCK (server); 00950 watches = server->watches; 00951 server->watches = NULL; 00952 if (watches) 00953 { 00954 SERVER_UNLOCK (server); 00955 result = _dbus_watch_list_set_functions (watches, 00956 add_function, 00957 remove_function, 00958 toggled_function, 00959 data, 00960 free_data_function); 00961 SERVER_LOCK (server); 00962 } 00963 else 00964 { 00965 _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME); 00966 result = FALSE; 00967 } 00968 server->watches = watches; 00969 SERVER_UNLOCK (server); 00970 00971 return result; 00972 } 00973 00989 dbus_bool_t 00990 dbus_server_set_timeout_functions (DBusServer *server, 00991 DBusAddTimeoutFunction add_function, 00992 DBusRemoveTimeoutFunction remove_function, 00993 DBusTimeoutToggledFunction toggled_function, 00994 void *data, 00995 DBusFreeFunction free_data_function) 00996 { 00997 dbus_bool_t result; 00998 DBusTimeoutList *timeouts; 00999 01000 _dbus_return_val_if_fail (server != NULL, FALSE); 01001 01002 SERVER_LOCK (server); 01003 timeouts = server->timeouts; 01004 server->timeouts = NULL; 01005 if (timeouts) 01006 { 01007 SERVER_UNLOCK (server); 01008 result = _dbus_timeout_list_set_functions (timeouts, 01009 add_function, 01010 remove_function, 01011 toggled_function, 01012 data, 01013 free_data_function); 01014 SERVER_LOCK (server); 01015 } 01016 else 01017 { 01018 _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME); 01019 result = FALSE; 01020 } 01021 server->timeouts = timeouts; 01022 SERVER_UNLOCK (server); 01023 01024 return result; 01025 } 01026 01040 dbus_bool_t 01041 dbus_server_set_auth_mechanisms (DBusServer *server, 01042 const char **mechanisms) 01043 { 01044 char **copy; 01045 01046 _dbus_return_val_if_fail (server != NULL, FALSE); 01047 01048 SERVER_LOCK (server); 01049 01050 if (mechanisms != NULL) 01051 { 01052 copy = _dbus_dup_string_array (mechanisms); 01053 if (copy == NULL) 01054 { 01055 SERVER_UNLOCK (server); 01056 return FALSE; 01057 } 01058 } 01059 else 01060 copy = NULL; 01061 01062 dbus_free_string_array (server->auth_mechanisms); 01063 server->auth_mechanisms = copy; 01064 01065 SERVER_UNLOCK (server); 01066 01067 return TRUE; 01068 } 01069 01070 static DBusDataSlotAllocator slot_allocator = 01071 _DBUS_DATA_SLOT_ALLOCATOR_INIT (_DBUS_LOCK_NAME (server_slots)); 01072 01087 dbus_bool_t 01088 dbus_server_allocate_data_slot (dbus_int32_t *slot_p) 01089 { 01090 return _dbus_data_slot_allocator_alloc (&slot_allocator, 01091 slot_p); 01092 } 01093 01105 void 01106 dbus_server_free_data_slot (dbus_int32_t *slot_p) 01107 { 01108 _dbus_return_if_fail (*slot_p >= 0); 01109 01110 _dbus_data_slot_allocator_free (&slot_allocator, slot_p); 01111 } 01112 01126 dbus_bool_t 01127 dbus_server_set_data (DBusServer *server, 01128 int slot, 01129 void *data, 01130 DBusFreeFunction free_data_func) 01131 { 01132 DBusFreeFunction old_free_func; 01133 void *old_data; 01134 dbus_bool_t retval; 01135 01136 _dbus_return_val_if_fail (server != NULL, FALSE); 01137 01138 SERVER_LOCK (server); 01139 01140 retval = _dbus_data_slot_list_set (&slot_allocator, 01141 &server->slot_list, 01142 slot, data, free_data_func, 01143 &old_free_func, &old_data); 01144 01145 01146 SERVER_UNLOCK (server); 01147 01148 if (retval) 01149 { 01150 /* Do the actual free outside the server lock */ 01151 if (old_free_func) 01152 (* old_free_func) (old_data); 01153 } 01154 01155 return retval; 01156 } 01157 01166 void* 01167 dbus_server_get_data (DBusServer *server, 01168 int slot) 01169 { 01170 void *res; 01171 01172 _dbus_return_val_if_fail (server != NULL, NULL); 01173 01174 SERVER_LOCK (server); 01175 01176 res = _dbus_data_slot_list_get (&slot_allocator, 01177 &server->slot_list, 01178 slot); 01179 01180 SERVER_UNLOCK (server); 01181 01182 return res; 01183 } 01184 01187 #ifdef DBUS_ENABLE_EMBEDDED_TESTS 01188 #include "dbus-test.h" 01189 #include <string.h> 01190 01191 dbus_bool_t 01192 _dbus_server_test (void) 01193 { 01194 const char *valid_addresses[] = { 01195 "tcp:port=1234", 01196 "tcp:host=localhost,port=1234", 01197 "tcp:host=localhost,port=1234;tcp:port=5678", 01198 #ifdef DBUS_UNIX 01199 "unix:path=./boogie", 01200 "tcp:port=1234;unix:path=./boogie", 01201 #endif 01202 }; 01203 01204 DBusServer *server; 01205 int i; 01206 01207 for (i = 0; i < _DBUS_N_ELEMENTS (valid_addresses); i++) 01208 { 01209 DBusError error = DBUS_ERROR_INIT; 01210 char *address; 01211 char *id; 01212 01213 server = dbus_server_listen (valid_addresses[i], &error); 01214 if (server == NULL) 01215 { 01216 _dbus_warn ("server listen error: %s: %s\n", error.name, error.message); 01217 dbus_error_free (&error); 01218 _dbus_assert_not_reached ("Failed to listen for valid address."); 01219 } 01220 01221 id = dbus_server_get_id (server); 01222 _dbus_assert (id != NULL); 01223 address = dbus_server_get_address (server); 01224 _dbus_assert (address != NULL); 01225 01226 if (strstr (address, id) == NULL) 01227 { 01228 _dbus_warn ("server id '%s' is not in the server address '%s'\n", 01229 id, address); 01230 _dbus_assert_not_reached ("bad server id or address"); 01231 } 01232 01233 dbus_free (id); 01234 dbus_free (address); 01235 01236 dbus_server_disconnect (server); 01237 dbus_server_unref (server); 01238 } 01239 01240 return TRUE; 01241 } 01242 01243 #endif /* DBUS_ENABLE_EMBEDDED_TESTS */