D-Bus
1.6.8
|
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_BUILD_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 00110 dbus_bool_t 00111 _dbus_server_init_base (DBusServer *server, 00112 const DBusServerVTable *vtable, 00113 const DBusString *address) 00114 { 00115 server->vtable = vtable; 00116 00117 #ifdef DBUS_DISABLE_ASSERT 00118 _dbus_atomic_inc (&server->refcount); 00119 #else 00120 { 00121 dbus_int32_t old_refcount = _dbus_atomic_inc (&server->refcount); 00122 00123 _dbus_assert (old_refcount == 0); 00124 } 00125 #endif 00126 00127 server->address = NULL; 00128 server->watches = NULL; 00129 server->timeouts = NULL; 00130 server->published_address = FALSE; 00131 00132 if (!_dbus_string_init (&server->guid_hex)) 00133 return FALSE; 00134 00135 _dbus_generate_uuid (&server->guid); 00136 00137 if (!_dbus_uuid_encode (&server->guid, &server->guid_hex)) 00138 goto failed; 00139 00140 server->address = copy_address_with_guid_appended (address, 00141 &server->guid_hex); 00142 if (server->address == NULL) 00143 goto failed; 00144 00145 _dbus_rmutex_new_at_location (&server->mutex); 00146 if (server->mutex == NULL) 00147 goto failed; 00148 00149 server->watches = _dbus_watch_list_new (); 00150 if (server->watches == NULL) 00151 goto failed; 00152 00153 server->timeouts = _dbus_timeout_list_new (); 00154 if (server->timeouts == NULL) 00155 goto failed; 00156 00157 _dbus_data_slot_list_init (&server->slot_list); 00158 00159 _dbus_verbose ("Initialized server on address %s\n", server->address); 00160 00161 return TRUE; 00162 00163 failed: 00164 _dbus_rmutex_free_at_location (&server->mutex); 00165 server->mutex = NULL; 00166 if (server->watches) 00167 { 00168 _dbus_watch_list_free (server->watches); 00169 server->watches = NULL; 00170 } 00171 if (server->timeouts) 00172 { 00173 _dbus_timeout_list_free (server->timeouts); 00174 server->timeouts = NULL; 00175 } 00176 if (server->address) 00177 { 00178 dbus_free (server->address); 00179 server->address = NULL; 00180 } 00181 _dbus_string_free (&server->guid_hex); 00182 00183 return FALSE; 00184 } 00185 00192 void 00193 _dbus_server_finalize_base (DBusServer *server) 00194 { 00195 /* We don't have the lock, but nobody should be accessing 00196 * concurrently since they don't have a ref 00197 */ 00198 #ifndef DBUS_DISABLE_CHECKS 00199 _dbus_assert (!server->have_server_lock); 00200 #endif 00201 _dbus_assert (server->disconnected); 00202 00203 /* calls out to application code... */ 00204 _dbus_data_slot_list_free (&server->slot_list); 00205 00206 dbus_server_set_new_connection_function (server, NULL, NULL, NULL); 00207 00208 _dbus_watch_list_free (server->watches); 00209 _dbus_timeout_list_free (server->timeouts); 00210 00211 _dbus_rmutex_free_at_location (&server->mutex); 00212 00213 dbus_free (server->address); 00214 00215 dbus_free_string_array (server->auth_mechanisms); 00216 00217 _dbus_string_free (&server->guid_hex); 00218 } 00219 00220 00222 typedef dbus_bool_t (* DBusWatchAddFunction) (DBusWatchList *list, 00223 DBusWatch *watch); 00225 typedef void (* DBusWatchRemoveFunction) (DBusWatchList *list, 00226 DBusWatch *watch); 00228 typedef void (* DBusWatchToggleFunction) (DBusWatchList *list, 00229 DBusWatch *watch, 00230 dbus_bool_t enabled); 00231 00232 static dbus_bool_t 00233 protected_change_watch (DBusServer *server, 00234 DBusWatch *watch, 00235 DBusWatchAddFunction add_function, 00236 DBusWatchRemoveFunction remove_function, 00237 DBusWatchToggleFunction toggle_function, 00238 dbus_bool_t enabled) 00239 { 00240 DBusWatchList *watches; 00241 dbus_bool_t retval; 00242 00243 HAVE_LOCK_CHECK (server); 00244 00245 /* This isn't really safe or reasonable; a better pattern is the "do 00246 * everything, then drop lock and call out" one; but it has to be 00247 * propagated up through all callers 00248 */ 00249 00250 watches = server->watches; 00251 if (watches) 00252 { 00253 server->watches = NULL; 00254 _dbus_server_ref_unlocked (server); 00255 SERVER_UNLOCK (server); 00256 00257 if (add_function) 00258 retval = (* add_function) (watches, watch); 00259 else if (remove_function) 00260 { 00261 retval = TRUE; 00262 (* remove_function) (watches, watch); 00263 } 00264 else 00265 { 00266 retval = TRUE; 00267 (* toggle_function) (watches, watch, enabled); 00268 } 00269 00270 SERVER_LOCK (server); 00271 server->watches = watches; 00272 _dbus_server_unref_unlocked (server); 00273 00274 return retval; 00275 } 00276 else 00277 return FALSE; 00278 } 00279 00287 dbus_bool_t 00288 _dbus_server_add_watch (DBusServer *server, 00289 DBusWatch *watch) 00290 { 00291 HAVE_LOCK_CHECK (server); 00292 return protected_change_watch (server, watch, 00293 _dbus_watch_list_add_watch, 00294 NULL, NULL, FALSE); 00295 } 00296 00303 void 00304 _dbus_server_remove_watch (DBusServer *server, 00305 DBusWatch *watch) 00306 { 00307 HAVE_LOCK_CHECK (server); 00308 protected_change_watch (server, watch, 00309 NULL, 00310 _dbus_watch_list_remove_watch, 00311 NULL, FALSE); 00312 } 00313 00323 void 00324 _dbus_server_toggle_watch (DBusServer *server, 00325 DBusWatch *watch, 00326 dbus_bool_t enabled) 00327 { 00328 _dbus_assert (watch != NULL); 00329 00330 HAVE_LOCK_CHECK (server); 00331 protected_change_watch (server, watch, 00332 NULL, NULL, 00333 _dbus_watch_list_toggle_watch, 00334 enabled); 00335 } 00336 00338 typedef dbus_bool_t (* DBusTimeoutAddFunction) (DBusTimeoutList *list, 00339 DBusTimeout *timeout); 00341 typedef void (* DBusTimeoutRemoveFunction) (DBusTimeoutList *list, 00342 DBusTimeout *timeout); 00344 typedef void (* DBusTimeoutToggleFunction) (DBusTimeoutList *list, 00345 DBusTimeout *timeout, 00346 dbus_bool_t enabled); 00347 00348 00349 static dbus_bool_t 00350 protected_change_timeout (DBusServer *server, 00351 DBusTimeout *timeout, 00352 DBusTimeoutAddFunction add_function, 00353 DBusTimeoutRemoveFunction remove_function, 00354 DBusTimeoutToggleFunction toggle_function, 00355 dbus_bool_t enabled) 00356 { 00357 DBusTimeoutList *timeouts; 00358 dbus_bool_t retval; 00359 00360 HAVE_LOCK_CHECK (server); 00361 00362 /* This isn't really safe or reasonable; a better pattern is the "do everything, then 00363 * drop lock and call out" one; but it has to be propagated up through all callers 00364 */ 00365 00366 timeouts = server->timeouts; 00367 if (timeouts) 00368 { 00369 server->timeouts = NULL; 00370 _dbus_server_ref_unlocked (server); 00371 SERVER_UNLOCK (server); 00372 00373 if (add_function) 00374 retval = (* add_function) (timeouts, timeout); 00375 else if (remove_function) 00376 { 00377 retval = TRUE; 00378 (* remove_function) (timeouts, timeout); 00379 } 00380 else 00381 { 00382 retval = TRUE; 00383 (* toggle_function) (timeouts, timeout, enabled); 00384 } 00385 00386 SERVER_LOCK (server); 00387 server->timeouts = timeouts; 00388 _dbus_server_unref_unlocked (server); 00389 00390 return retval; 00391 } 00392 else 00393 return FALSE; 00394 } 00395 00405 dbus_bool_t 00406 _dbus_server_add_timeout (DBusServer *server, 00407 DBusTimeout *timeout) 00408 { 00409 return protected_change_timeout (server, timeout, 00410 _dbus_timeout_list_add_timeout, 00411 NULL, NULL, FALSE); 00412 } 00413 00420 void 00421 _dbus_server_remove_timeout (DBusServer *server, 00422 DBusTimeout *timeout) 00423 { 00424 protected_change_timeout (server, timeout, 00425 NULL, 00426 _dbus_timeout_list_remove_timeout, 00427 NULL, FALSE); 00428 } 00429 00439 void 00440 _dbus_server_toggle_timeout (DBusServer *server, 00441 DBusTimeout *timeout, 00442 dbus_bool_t enabled) 00443 { 00444 protected_change_timeout (server, timeout, 00445 NULL, NULL, 00446 _dbus_timeout_list_toggle_timeout, 00447 enabled); 00448 } 00449 00450 00456 void 00457 _dbus_server_ref_unlocked (DBusServer *server) 00458 { 00459 dbus_int32_t old_refcount; 00460 00461 _dbus_assert (server != NULL); 00462 HAVE_LOCK_CHECK (server); 00463 00464 old_refcount = _dbus_atomic_inc (&server->refcount); 00465 _dbus_assert (old_refcount > 0); 00466 _dbus_server_trace_ref (server, old_refcount, old_refcount + 1, 00467 "ref_unlocked"); 00468 } 00469 00475 void 00476 _dbus_server_unref_unlocked (DBusServer *server) 00477 { 00478 dbus_int32_t old_refcount; 00479 00480 /* Keep this in sync with dbus_server_unref */ 00481 00482 _dbus_assert (server != NULL); 00483 00484 HAVE_LOCK_CHECK (server); 00485 00486 old_refcount = _dbus_atomic_dec (&server->refcount); 00487 _dbus_assert (old_refcount > 0); 00488 00489 _dbus_server_trace_ref (server, old_refcount, old_refcount - 1, 00490 "unref_unlocked"); 00491 00492 if (old_refcount == 1) 00493 { 00494 _dbus_assert (server->disconnected); 00495 00496 SERVER_UNLOCK (server); 00497 00498 _dbus_assert (server->vtable->finalize != NULL); 00499 00500 (* server->vtable->finalize) (server); 00501 } 00502 } 00503 00525 static const struct { 00526 DBusServerListenResult (* func) (DBusAddressEntry *entry, 00527 DBusServer **server_p, 00528 DBusError *error); 00529 } listen_funcs[] = { 00530 { _dbus_server_listen_socket } 00531 , { _dbus_server_listen_platform_specific } 00532 #ifdef DBUS_BUILD_TESTS 00533 , { _dbus_server_listen_debug_pipe } 00534 #endif 00535 }; 00536 00557 DBusServer* 00558 dbus_server_listen (const char *address, 00559 DBusError *error) 00560 { 00561 DBusServer *server; 00562 DBusAddressEntry **entries; 00563 int len, i; 00564 DBusError first_connect_error = DBUS_ERROR_INIT; 00565 dbus_bool_t handled_once; 00566 00567 _dbus_return_val_if_fail (address != NULL, NULL); 00568 _dbus_return_val_if_error_is_set (error, NULL); 00569 00570 if (!dbus_parse_address (address, &entries, &len, error)) 00571 return NULL; 00572 00573 server = NULL; 00574 handled_once = FALSE; 00575 00576 for (i = 0; i < len; i++) 00577 { 00578 int j; 00579 00580 for (j = 0; j < (int) _DBUS_N_ELEMENTS (listen_funcs); ++j) 00581 { 00582 DBusServerListenResult result; 00583 DBusError tmp_error = DBUS_ERROR_INIT; 00584 00585 result = (* listen_funcs[j].func) (entries[i], 00586 &server, 00587 &tmp_error); 00588 00589 if (result == DBUS_SERVER_LISTEN_OK) 00590 { 00591 _dbus_assert (server != NULL); 00592 _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); 00593 handled_once = TRUE; 00594 goto out; 00595 } 00596 else if (result == DBUS_SERVER_LISTEN_ADDRESS_ALREADY_USED) 00597 { 00598 _dbus_assert (server == NULL); 00599 dbus_set_error (error, 00600 DBUS_ERROR_ADDRESS_IN_USE, 00601 "Address '%s' already used", 00602 dbus_address_entry_get_method (entries[0])); 00603 handled_once = TRUE; 00604 goto out; 00605 } 00606 else if (result == DBUS_SERVER_LISTEN_BAD_ADDRESS) 00607 { 00608 _dbus_assert (server == NULL); 00609 _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); 00610 dbus_move_error (&tmp_error, error); 00611 handled_once = TRUE; 00612 goto out; 00613 } 00614 else if (result == DBUS_SERVER_LISTEN_NOT_HANDLED) 00615 { 00616 _dbus_assert (server == NULL); 00617 _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); 00618 00619 /* keep trying addresses */ 00620 } 00621 else if (result == DBUS_SERVER_LISTEN_DID_NOT_CONNECT) 00622 { 00623 _dbus_assert (server == NULL); 00624 _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); 00625 if (!dbus_error_is_set (&first_connect_error)) 00626 dbus_move_error (&tmp_error, &first_connect_error); 00627 else 00628 dbus_error_free (&tmp_error); 00629 00630 handled_once = TRUE; 00631 00632 /* keep trying addresses */ 00633 } 00634 } 00635 00636 _dbus_assert (server == NULL); 00637 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00638 } 00639 00640 out: 00641 00642 if (!handled_once) 00643 { 00644 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00645 if (len > 0) 00646 dbus_set_error (error, 00647 DBUS_ERROR_BAD_ADDRESS, 00648 "Unknown address type '%s'", 00649 dbus_address_entry_get_method (entries[0])); 00650 else 00651 dbus_set_error (error, 00652 DBUS_ERROR_BAD_ADDRESS, 00653 "Empty address '%s'", 00654 address); 00655 } 00656 00657 dbus_address_entries_free (entries); 00658 00659 if (server == NULL) 00660 { 00661 _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error) || 00662 dbus_error_is_set (error)); 00663 00664 if (error && dbus_error_is_set (error)) 00665 { 00666 /* already set the error */ 00667 } 00668 else 00669 { 00670 /* didn't set the error but either error should be 00671 * NULL or first_connect_error should be set. 00672 */ 00673 _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error)); 00674 dbus_move_error (&first_connect_error, error); 00675 } 00676 00677 _DBUS_ASSERT_ERROR_IS_CLEAR (&first_connect_error); /* be sure we freed it */ 00678 _DBUS_ASSERT_ERROR_IS_SET (error); 00679 00680 return NULL; 00681 } 00682 else 00683 { 00684 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00685 return server; 00686 } 00687 } 00688 00695 DBusServer * 00696 dbus_server_ref (DBusServer *server) 00697 { 00698 dbus_int32_t old_refcount; 00699 00700 _dbus_return_val_if_fail (server != NULL, NULL); 00701 00702 /* can't get the refcount without a side-effect */ 00703 old_refcount = _dbus_atomic_inc (&server->refcount); 00704 00705 #ifndef DBUS_DISABLE_CHECKS 00706 if (_DBUS_UNLIKELY (old_refcount <= 0)) 00707 { 00708 /* undo side-effect first */ 00709 _dbus_atomic_dec (&server->refcount); 00710 _dbus_warn_check_failed (_dbus_return_if_fail_warning_format, 00711 _DBUS_FUNCTION_NAME, "old_refcount > 0", 00712 __FILE__, __LINE__); 00713 return NULL; 00714 } 00715 #endif 00716 00717 _dbus_server_trace_ref (server, old_refcount, old_refcount + 1, "ref"); 00718 00719 return server; 00720 } 00721 00730 void 00731 dbus_server_unref (DBusServer *server) 00732 { 00733 dbus_int32_t old_refcount; 00734 00735 /* keep this in sync with unref_unlocked */ 00736 00737 _dbus_return_if_fail (server != NULL); 00738 00739 /* can't get the refcount without a side-effect */ 00740 old_refcount = _dbus_atomic_dec (&server->refcount); 00741 00742 #ifndef DBUS_DISABLE_CHECKS 00743 if (_DBUS_UNLIKELY (old_refcount <= 0)) 00744 { 00745 /* undo side-effect first */ 00746 _dbus_atomic_inc (&server->refcount); 00747 _dbus_warn_check_failed (_dbus_return_if_fail_warning_format, 00748 _DBUS_FUNCTION_NAME, "old_refcount > 0", 00749 __FILE__, __LINE__); 00750 return; 00751 } 00752 #endif 00753 00754 _dbus_server_trace_ref (server, old_refcount, old_refcount - 1, "unref"); 00755 00756 if (old_refcount == 1) 00757 { 00758 /* lock not held! */ 00759 _dbus_assert (server->disconnected); 00760 00761 _dbus_assert (server->vtable->finalize != NULL); 00762 00763 (* server->vtable->finalize) (server); 00764 } 00765 } 00766 00775 void 00776 dbus_server_disconnect (DBusServer *server) 00777 { 00778 _dbus_return_if_fail (server != NULL); 00779 00780 #ifdef DBUS_DISABLE_CHECKS 00781 _dbus_atomic_inc (&server->refcount); 00782 #else 00783 { 00784 dbus_int32_t old_refcount = _dbus_atomic_inc (&server->refcount); 00785 00786 _dbus_return_if_fail (old_refcount > 0); 00787 } 00788 #endif 00789 00790 SERVER_LOCK (server); 00791 00792 _dbus_assert (server->vtable->disconnect != NULL); 00793 00794 if (!server->disconnected) 00795 { 00796 /* this has to be first so recursive calls to disconnect don't happen */ 00797 server->disconnected = TRUE; 00798 00799 (* server->vtable->disconnect) (server); 00800 } 00801 00802 SERVER_UNLOCK (server); 00803 dbus_server_unref (server); 00804 } 00805 00811 dbus_bool_t 00812 dbus_server_get_is_connected (DBusServer *server) 00813 { 00814 dbus_bool_t retval; 00815 00816 _dbus_return_val_if_fail (server != NULL, FALSE); 00817 00818 SERVER_LOCK (server); 00819 retval = !server->disconnected; 00820 SERVER_UNLOCK (server); 00821 00822 return retval; 00823 } 00824 00832 char* 00833 dbus_server_get_address (DBusServer *server) 00834 { 00835 char *retval; 00836 00837 _dbus_return_val_if_fail (server != NULL, NULL); 00838 00839 SERVER_LOCK (server); 00840 retval = _dbus_strdup (server->address); 00841 SERVER_UNLOCK (server); 00842 00843 return retval; 00844 } 00845 00868 char* 00869 dbus_server_get_id (DBusServer *server) 00870 { 00871 char *retval; 00872 00873 _dbus_return_val_if_fail (server != NULL, NULL); 00874 00875 SERVER_LOCK (server); 00876 retval = NULL; 00877 _dbus_string_copy_data (&server->guid_hex, &retval); 00878 SERVER_UNLOCK (server); 00879 00880 return retval; 00881 } 00882 00903 void 00904 dbus_server_set_new_connection_function (DBusServer *server, 00905 DBusNewConnectionFunction function, 00906 void *data, 00907 DBusFreeFunction free_data_function) 00908 { 00909 DBusFreeFunction old_free_function; 00910 void *old_data; 00911 00912 _dbus_return_if_fail (server != NULL); 00913 00914 SERVER_LOCK (server); 00915 old_free_function = server->new_connection_free_data_function; 00916 old_data = server->new_connection_data; 00917 00918 server->new_connection_function = function; 00919 server->new_connection_data = data; 00920 server->new_connection_free_data_function = free_data_function; 00921 SERVER_UNLOCK (server); 00922 00923 if (old_free_function != NULL) 00924 (* old_free_function) (old_data); 00925 } 00926 00943 dbus_bool_t 00944 dbus_server_set_watch_functions (DBusServer *server, 00945 DBusAddWatchFunction add_function, 00946 DBusRemoveWatchFunction remove_function, 00947 DBusWatchToggledFunction toggled_function, 00948 void *data, 00949 DBusFreeFunction free_data_function) 00950 { 00951 dbus_bool_t result; 00952 DBusWatchList *watches; 00953 00954 _dbus_return_val_if_fail (server != NULL, FALSE); 00955 00956 SERVER_LOCK (server); 00957 watches = server->watches; 00958 server->watches = NULL; 00959 if (watches) 00960 { 00961 SERVER_UNLOCK (server); 00962 result = _dbus_watch_list_set_functions (watches, 00963 add_function, 00964 remove_function, 00965 toggled_function, 00966 data, 00967 free_data_function); 00968 SERVER_LOCK (server); 00969 } 00970 else 00971 { 00972 _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME); 00973 result = FALSE; 00974 } 00975 server->watches = watches; 00976 SERVER_UNLOCK (server); 00977 00978 return result; 00979 } 00980 00996 dbus_bool_t 00997 dbus_server_set_timeout_functions (DBusServer *server, 00998 DBusAddTimeoutFunction add_function, 00999 DBusRemoveTimeoutFunction remove_function, 01000 DBusTimeoutToggledFunction toggled_function, 01001 void *data, 01002 DBusFreeFunction free_data_function) 01003 { 01004 dbus_bool_t result; 01005 DBusTimeoutList *timeouts; 01006 01007 _dbus_return_val_if_fail (server != NULL, FALSE); 01008 01009 SERVER_LOCK (server); 01010 timeouts = server->timeouts; 01011 server->timeouts = NULL; 01012 if (timeouts) 01013 { 01014 SERVER_UNLOCK (server); 01015 result = _dbus_timeout_list_set_functions (timeouts, 01016 add_function, 01017 remove_function, 01018 toggled_function, 01019 data, 01020 free_data_function); 01021 SERVER_LOCK (server); 01022 } 01023 else 01024 { 01025 _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME); 01026 result = FALSE; 01027 } 01028 server->timeouts = timeouts; 01029 SERVER_UNLOCK (server); 01030 01031 return result; 01032 } 01033 01047 dbus_bool_t 01048 dbus_server_set_auth_mechanisms (DBusServer *server, 01049 const char **mechanisms) 01050 { 01051 char **copy; 01052 01053 _dbus_return_val_if_fail (server != NULL, FALSE); 01054 01055 SERVER_LOCK (server); 01056 01057 if (mechanisms != NULL) 01058 { 01059 copy = _dbus_dup_string_array (mechanisms); 01060 if (copy == NULL) 01061 return FALSE; 01062 } 01063 else 01064 copy = NULL; 01065 01066 dbus_free_string_array (server->auth_mechanisms); 01067 server->auth_mechanisms = copy; 01068 01069 SERVER_UNLOCK (server); 01070 01071 return TRUE; 01072 } 01073 01074 01075 static DBusDataSlotAllocator slot_allocator; 01076 _DBUS_DEFINE_GLOBAL_LOCK (server_slots); 01077 01092 dbus_bool_t 01093 dbus_server_allocate_data_slot (dbus_int32_t *slot_p) 01094 { 01095 return _dbus_data_slot_allocator_alloc (&slot_allocator, 01096 (DBusRMutex **)&_DBUS_LOCK_NAME (server_slots), 01097 slot_p); 01098 } 01099 01111 void 01112 dbus_server_free_data_slot (dbus_int32_t *slot_p) 01113 { 01114 _dbus_return_if_fail (*slot_p >= 0); 01115 01116 _dbus_data_slot_allocator_free (&slot_allocator, slot_p); 01117 } 01118 01132 dbus_bool_t 01133 dbus_server_set_data (DBusServer *server, 01134 int slot, 01135 void *data, 01136 DBusFreeFunction free_data_func) 01137 { 01138 DBusFreeFunction old_free_func; 01139 void *old_data; 01140 dbus_bool_t retval; 01141 01142 _dbus_return_val_if_fail (server != NULL, FALSE); 01143 01144 SERVER_LOCK (server); 01145 01146 retval = _dbus_data_slot_list_set (&slot_allocator, 01147 &server->slot_list, 01148 slot, data, free_data_func, 01149 &old_free_func, &old_data); 01150 01151 01152 SERVER_UNLOCK (server); 01153 01154 if (retval) 01155 { 01156 /* Do the actual free outside the server lock */ 01157 if (old_free_func) 01158 (* old_free_func) (old_data); 01159 } 01160 01161 return retval; 01162 } 01163 01172 void* 01173 dbus_server_get_data (DBusServer *server, 01174 int slot) 01175 { 01176 void *res; 01177 01178 _dbus_return_val_if_fail (server != NULL, NULL); 01179 01180 SERVER_LOCK (server); 01181 01182 res = _dbus_data_slot_list_get (&slot_allocator, 01183 &server->slot_list, 01184 slot); 01185 01186 SERVER_UNLOCK (server); 01187 01188 return res; 01189 } 01190 01193 #ifdef DBUS_BUILD_TESTS 01194 #include "dbus-test.h" 01195 #include <string.h> 01196 01197 dbus_bool_t 01198 _dbus_server_test (void) 01199 { 01200 const char *valid_addresses[] = { 01201 "tcp:port=1234", 01202 "tcp:host=localhost,port=1234", 01203 "tcp:host=localhost,port=1234;tcp:port=5678", 01204 #ifdef DBUS_UNIX 01205 "unix:path=./boogie", 01206 "tcp:port=1234;unix:path=./boogie", 01207 #endif 01208 }; 01209 01210 DBusServer *server; 01211 int i; 01212 01213 for (i = 0; i < _DBUS_N_ELEMENTS (valid_addresses); i++) 01214 { 01215 DBusError error = DBUS_ERROR_INIT; 01216 char *address; 01217 char *id; 01218 01219 server = dbus_server_listen (valid_addresses[i], &error); 01220 if (server == NULL) 01221 { 01222 _dbus_warn ("server listen error: %s: %s\n", error.name, error.message); 01223 dbus_error_free (&error); 01224 _dbus_assert_not_reached ("Failed to listen for valid address."); 01225 } 01226 01227 id = dbus_server_get_id (server); 01228 _dbus_assert (id != NULL); 01229 address = dbus_server_get_address (server); 01230 _dbus_assert (address != NULL); 01231 01232 if (strstr (address, id) == NULL) 01233 { 01234 _dbus_warn ("server id '%s' is not in the server address '%s'\n", 01235 id, address); 01236 _dbus_assert_not_reached ("bad server id or address"); 01237 } 01238 01239 dbus_free (id); 01240 dbus_free (address); 01241 01242 dbus_server_disconnect (server); 01243 dbus_server_unref (server); 01244 } 01245 01246 return TRUE; 01247 } 01248 01249 #endif /* DBUS_BUILD_TESTS */