D-Bus  1.10.12
dbus-server.c
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 */