D-Bus  1.6.30
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_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 
00321 void
00322 _dbus_server_toggle_all_watches (DBusServer  *server,
00323                                 dbus_bool_t  enabled)
00324 {
00325   _dbus_watch_list_toggle_all_watches (server->watches, enabled);
00326 }
00327 
00329 typedef dbus_bool_t (* DBusTimeoutAddFunction)    (DBusTimeoutList *list,
00330                                                    DBusTimeout     *timeout);
00332 typedef void        (* DBusTimeoutRemoveFunction) (DBusTimeoutList *list,
00333                                                    DBusTimeout     *timeout);
00335 typedef void        (* DBusTimeoutToggleFunction) (DBusTimeoutList *list,
00336                                                    DBusTimeout     *timeout,
00337                                                    dbus_bool_t      enabled);
00338 
00339 
00340 static dbus_bool_t
00341 protected_change_timeout (DBusServer               *server,
00342                           DBusTimeout              *timeout,
00343                           DBusTimeoutAddFunction    add_function,
00344                           DBusTimeoutRemoveFunction remove_function,
00345                           DBusTimeoutToggleFunction toggle_function,
00346                           dbus_bool_t               enabled)
00347 {
00348   DBusTimeoutList *timeouts;
00349   dbus_bool_t retval;
00350   
00351   HAVE_LOCK_CHECK (server);
00352 
00353   /* This isn't really safe or reasonable; a better pattern is the "do everything, then
00354    * drop lock and call out" one; but it has to be propagated up through all callers
00355    */
00356   
00357   timeouts = server->timeouts;
00358   if (timeouts)
00359     {
00360       server->timeouts = NULL;
00361       _dbus_server_ref_unlocked (server);
00362       SERVER_UNLOCK (server);
00363 
00364       if (add_function)
00365         retval = (* add_function) (timeouts, timeout);
00366       else if (remove_function)
00367         {
00368           retval = TRUE;
00369           (* remove_function) (timeouts, timeout);
00370         }
00371       else
00372         {
00373           retval = TRUE;
00374           (* toggle_function) (timeouts, timeout, enabled);
00375         }
00376       
00377       SERVER_LOCK (server);
00378       server->timeouts = timeouts;
00379       _dbus_server_unref_unlocked (server);
00380 
00381       return retval;
00382     }
00383   else
00384     return FALSE;
00385 }
00386 
00396 dbus_bool_t
00397 _dbus_server_add_timeout (DBusServer  *server,
00398                           DBusTimeout *timeout)
00399 {
00400   return protected_change_timeout (server, timeout,
00401                                    _dbus_timeout_list_add_timeout,
00402                                    NULL, NULL, FALSE);
00403 }
00404 
00411 void
00412 _dbus_server_remove_timeout (DBusServer  *server,
00413                              DBusTimeout *timeout)
00414 {
00415   protected_change_timeout (server, timeout,
00416                             NULL,
00417                             _dbus_timeout_list_remove_timeout,
00418                             NULL, FALSE);
00419 }
00420 
00430 void
00431 _dbus_server_toggle_timeout (DBusServer  *server,
00432                              DBusTimeout *timeout,
00433                              dbus_bool_t  enabled)
00434 {
00435   protected_change_timeout (server, timeout,
00436                             NULL, NULL,
00437                             _dbus_timeout_list_toggle_timeout,
00438                             enabled);
00439 }
00440 
00441 
00447 void
00448 _dbus_server_ref_unlocked (DBusServer *server)
00449 {
00450   dbus_int32_t old_refcount;
00451 
00452   _dbus_assert (server != NULL);
00453   HAVE_LOCK_CHECK (server);
00454 
00455   old_refcount = _dbus_atomic_inc (&server->refcount);
00456   _dbus_assert (old_refcount > 0);
00457   _dbus_server_trace_ref (server, old_refcount, old_refcount + 1,
00458       "ref_unlocked");
00459 }
00460 
00466 void
00467 _dbus_server_unref_unlocked (DBusServer *server)
00468 {
00469   dbus_int32_t old_refcount;
00470 
00471   /* Keep this in sync with dbus_server_unref */
00472 
00473   _dbus_assert (server != NULL);
00474 
00475   HAVE_LOCK_CHECK (server);
00476 
00477   old_refcount = _dbus_atomic_dec (&server->refcount);
00478   _dbus_assert (old_refcount > 0);
00479 
00480   _dbus_server_trace_ref (server, old_refcount, old_refcount - 1,
00481       "unref_unlocked");
00482 
00483   if (old_refcount == 1)
00484     {
00485       _dbus_assert (server->disconnected);
00486       
00487       SERVER_UNLOCK (server);
00488       
00489       _dbus_assert (server->vtable->finalize != NULL);
00490       
00491       (* server->vtable->finalize) (server);
00492     }
00493 }
00494 
00516 static const struct {
00517   DBusServerListenResult (* func) (DBusAddressEntry *entry,
00518                                    DBusServer      **server_p,
00519                                    DBusError        *error);
00520 } listen_funcs[] = {
00521   { _dbus_server_listen_socket }
00522   , { _dbus_server_listen_platform_specific }
00523 #ifdef DBUS_BUILD_TESTS
00524   , { _dbus_server_listen_debug_pipe }
00525 #endif
00526 };
00527 
00548 DBusServer*
00549 dbus_server_listen (const char     *address,
00550                     DBusError      *error)
00551 {
00552   DBusServer *server;
00553   DBusAddressEntry **entries;
00554   int len, i;
00555   DBusError first_connect_error = DBUS_ERROR_INIT;
00556   dbus_bool_t handled_once;
00557   
00558   _dbus_return_val_if_fail (address != NULL, NULL);
00559   _dbus_return_val_if_error_is_set (error, NULL);
00560   
00561   if (!dbus_parse_address (address, &entries, &len, error))
00562     return NULL;
00563 
00564   server = NULL;
00565   handled_once = FALSE;
00566 
00567   for (i = 0; i < len; i++)
00568     {
00569       int j;
00570 
00571       for (j = 0; j < (int) _DBUS_N_ELEMENTS (listen_funcs); ++j)
00572         {
00573           DBusServerListenResult result;
00574           DBusError tmp_error = DBUS_ERROR_INIT;
00575 
00576           result = (* listen_funcs[j].func) (entries[i],
00577                                              &server,
00578                                              &tmp_error);
00579 
00580           if (result == DBUS_SERVER_LISTEN_OK)
00581             {
00582               _dbus_assert (server != NULL);
00583               _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
00584               handled_once = TRUE;
00585               goto out;
00586             }
00587           else if (result == DBUS_SERVER_LISTEN_ADDRESS_ALREADY_USED)
00588             {
00589               _dbus_assert (server == NULL);
00590               dbus_set_error (error,
00591                        DBUS_ERROR_ADDRESS_IN_USE,
00592                        "Address '%s' already used",
00593                        dbus_address_entry_get_method (entries[0]));
00594               handled_once = TRUE;
00595               goto out;
00596             }
00597           else if (result == DBUS_SERVER_LISTEN_BAD_ADDRESS)
00598             {
00599               _dbus_assert (server == NULL);
00600               _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
00601               dbus_move_error (&tmp_error, error);
00602               handled_once = TRUE;
00603               goto out;
00604             }
00605           else if (result == DBUS_SERVER_LISTEN_NOT_HANDLED)
00606             {
00607               _dbus_assert (server == NULL);
00608               _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
00609 
00610               /* keep trying addresses */
00611             }
00612           else if (result == DBUS_SERVER_LISTEN_DID_NOT_CONNECT)
00613             {
00614               _dbus_assert (server == NULL);
00615               _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
00616               if (!dbus_error_is_set (&first_connect_error))
00617                 dbus_move_error (&tmp_error, &first_connect_error);
00618               else
00619                 dbus_error_free (&tmp_error);
00620 
00621               handled_once = TRUE;
00622               
00623               /* keep trying addresses */
00624             }
00625         }
00626 
00627       _dbus_assert (server == NULL);
00628       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00629     }
00630 
00631  out:
00632 
00633   if (!handled_once)
00634     {
00635       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00636       if (len > 0)
00637         dbus_set_error (error,
00638                        DBUS_ERROR_BAD_ADDRESS,
00639                        "Unknown address type '%s'",
00640                        dbus_address_entry_get_method (entries[0]));
00641       else
00642         dbus_set_error (error,
00643                         DBUS_ERROR_BAD_ADDRESS,
00644                         "Empty address '%s'",
00645                         address);
00646     }
00647   
00648   dbus_address_entries_free (entries);
00649 
00650   if (server == NULL)
00651     {
00652       _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error) ||
00653                    dbus_error_is_set (error));
00654       
00655       if (error && dbus_error_is_set (error))
00656         {
00657           /* already set the error */
00658         }
00659       else
00660         {
00661           /* didn't set the error but either error should be
00662            * NULL or first_connect_error should be set.
00663            */
00664           _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error));
00665           dbus_move_error (&first_connect_error, error);
00666         }
00667 
00668       _DBUS_ASSERT_ERROR_IS_CLEAR (&first_connect_error); /* be sure we freed it */
00669       _DBUS_ASSERT_ERROR_IS_SET (error);
00670 
00671       return NULL;
00672     }
00673   else
00674     {
00675       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00676       return server;
00677     }
00678 }
00679 
00686 DBusServer *
00687 dbus_server_ref (DBusServer *server)
00688 {
00689   dbus_int32_t old_refcount;
00690 
00691   _dbus_return_val_if_fail (server != NULL, NULL);
00692 
00693   /* can't get the refcount without a side-effect */
00694   old_refcount = _dbus_atomic_inc (&server->refcount);
00695 
00696 #ifndef DBUS_DISABLE_CHECKS
00697   if (_DBUS_UNLIKELY (old_refcount <= 0))
00698     {
00699       /* undo side-effect first */
00700       _dbus_atomic_dec (&server->refcount);
00701       _dbus_warn_check_failed (_dbus_return_if_fail_warning_format,
00702                                _DBUS_FUNCTION_NAME, "old_refcount > 0",
00703                                __FILE__, __LINE__);
00704       return NULL;
00705     }
00706 #endif
00707 
00708   _dbus_server_trace_ref (server, old_refcount, old_refcount + 1, "ref");
00709 
00710   return server;
00711 }
00712 
00721 void
00722 dbus_server_unref (DBusServer *server)
00723 {
00724   dbus_int32_t old_refcount;
00725 
00726   /* keep this in sync with unref_unlocked */
00727 
00728   _dbus_return_if_fail (server != NULL);
00729 
00730   /* can't get the refcount without a side-effect */
00731   old_refcount = _dbus_atomic_dec (&server->refcount);
00732 
00733 #ifndef DBUS_DISABLE_CHECKS
00734   if (_DBUS_UNLIKELY (old_refcount <= 0))
00735     {
00736       /* undo side-effect first */
00737       _dbus_atomic_inc (&server->refcount);
00738       _dbus_warn_check_failed (_dbus_return_if_fail_warning_format,
00739                                _DBUS_FUNCTION_NAME, "old_refcount > 0",
00740                                __FILE__, __LINE__);
00741       return;
00742     }
00743 #endif
00744 
00745   _dbus_server_trace_ref (server, old_refcount, old_refcount - 1, "unref");
00746 
00747   if (old_refcount == 1)
00748     {
00749       /* lock not held! */
00750       _dbus_assert (server->disconnected);
00751       
00752       _dbus_assert (server->vtable->finalize != NULL);
00753       
00754       (* server->vtable->finalize) (server);
00755     }
00756 }
00757 
00766 void
00767 dbus_server_disconnect (DBusServer *server)
00768 {
00769   _dbus_return_if_fail (server != NULL);
00770 
00771 #ifdef DBUS_DISABLE_CHECKS
00772   _dbus_atomic_inc (&server->refcount);
00773 #else
00774     {
00775       dbus_int32_t old_refcount = _dbus_atomic_inc (&server->refcount);
00776 
00777       _dbus_return_if_fail (old_refcount > 0);
00778     }
00779 #endif
00780 
00781   SERVER_LOCK (server);
00782 
00783   _dbus_assert (server->vtable->disconnect != NULL);
00784 
00785   if (!server->disconnected)
00786     {
00787       /* this has to be first so recursive calls to disconnect don't happen */
00788       server->disconnected = TRUE;
00789       
00790       (* server->vtable->disconnect) (server);
00791     }
00792 
00793   SERVER_UNLOCK (server);
00794   dbus_server_unref (server);
00795 }
00796 
00802 dbus_bool_t
00803 dbus_server_get_is_connected (DBusServer *server)
00804 {
00805   dbus_bool_t retval;
00806   
00807   _dbus_return_val_if_fail (server != NULL, FALSE);
00808 
00809   SERVER_LOCK (server);
00810   retval = !server->disconnected;
00811   SERVER_UNLOCK (server);
00812 
00813   return retval;
00814 }
00815 
00823 char*
00824 dbus_server_get_address (DBusServer *server)
00825 {
00826   char *retval;
00827   
00828   _dbus_return_val_if_fail (server != NULL, NULL);
00829 
00830   SERVER_LOCK (server);
00831   retval = _dbus_strdup (server->address);
00832   SERVER_UNLOCK (server);
00833 
00834   return retval;
00835 }
00836 
00859 char*
00860 dbus_server_get_id (DBusServer *server)
00861 {
00862   char *retval;
00863   
00864   _dbus_return_val_if_fail (server != NULL, NULL);
00865 
00866   SERVER_LOCK (server);
00867   retval = NULL;
00868   _dbus_string_copy_data (&server->guid_hex, &retval);
00869   SERVER_UNLOCK (server);
00870 
00871   return retval;
00872 }
00873 
00894 void
00895 dbus_server_set_new_connection_function (DBusServer                *server,
00896                                          DBusNewConnectionFunction  function,
00897                                          void                      *data,
00898                                          DBusFreeFunction           free_data_function)
00899 {
00900   DBusFreeFunction old_free_function;
00901   void *old_data;
00902   
00903   _dbus_return_if_fail (server != NULL);
00904 
00905   SERVER_LOCK (server);
00906   old_free_function = server->new_connection_free_data_function;
00907   old_data = server->new_connection_data;
00908   
00909   server->new_connection_function = function;
00910   server->new_connection_data = data;
00911   server->new_connection_free_data_function = free_data_function;
00912   SERVER_UNLOCK (server);
00913     
00914   if (old_free_function != NULL)
00915     (* old_free_function) (old_data);
00916 }
00917 
00934 dbus_bool_t
00935 dbus_server_set_watch_functions (DBusServer              *server,
00936                                  DBusAddWatchFunction     add_function,
00937                                  DBusRemoveWatchFunction  remove_function,
00938                                  DBusWatchToggledFunction toggled_function,
00939                                  void                    *data,
00940                                  DBusFreeFunction         free_data_function)
00941 {
00942   dbus_bool_t result;
00943   DBusWatchList *watches;
00944   
00945   _dbus_return_val_if_fail (server != NULL, FALSE);
00946 
00947   SERVER_LOCK (server);
00948   watches = server->watches;
00949   server->watches = NULL;
00950   if (watches)
00951     {
00952       SERVER_UNLOCK (server);
00953       result = _dbus_watch_list_set_functions (watches,
00954                                                add_function,
00955                                                remove_function,
00956                                                toggled_function,
00957                                                data,
00958                                                free_data_function);
00959       SERVER_LOCK (server);
00960     }
00961   else
00962     {
00963       _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
00964       result = FALSE;
00965     }
00966   server->watches = watches;
00967   SERVER_UNLOCK (server);
00968   
00969   return result;
00970 }
00971 
00987 dbus_bool_t
00988 dbus_server_set_timeout_functions (DBusServer                *server,
00989                                    DBusAddTimeoutFunction     add_function,
00990                                    DBusRemoveTimeoutFunction  remove_function,
00991                                    DBusTimeoutToggledFunction toggled_function,
00992                                    void                      *data,
00993                                    DBusFreeFunction           free_data_function)
00994 {
00995   dbus_bool_t result;
00996   DBusTimeoutList *timeouts;
00997   
00998   _dbus_return_val_if_fail (server != NULL, FALSE);
00999 
01000   SERVER_LOCK (server);
01001   timeouts = server->timeouts;
01002   server->timeouts = NULL;
01003   if (timeouts)
01004     {
01005       SERVER_UNLOCK (server);
01006       result = _dbus_timeout_list_set_functions (timeouts,
01007                                                  add_function,
01008                                                  remove_function,
01009                                                  toggled_function,
01010                                                  data,
01011                                                  free_data_function);
01012       SERVER_LOCK (server);
01013     }
01014   else
01015     {
01016       _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
01017       result = FALSE;
01018     }
01019   server->timeouts = timeouts;
01020   SERVER_UNLOCK (server);
01021   
01022   return result;
01023 }
01024 
01038 dbus_bool_t
01039 dbus_server_set_auth_mechanisms (DBusServer  *server,
01040                                  const char **mechanisms)
01041 {
01042   char **copy;
01043 
01044   _dbus_return_val_if_fail (server != NULL, FALSE);
01045 
01046   SERVER_LOCK (server);
01047   
01048   if (mechanisms != NULL)
01049     {
01050       copy = _dbus_dup_string_array (mechanisms);
01051       if (copy == NULL)
01052         return FALSE;
01053     }
01054   else
01055     copy = NULL;
01056 
01057   dbus_free_string_array (server->auth_mechanisms);
01058   server->auth_mechanisms = copy;
01059 
01060   SERVER_UNLOCK (server);
01061   
01062   return TRUE;
01063 }
01064 
01065 
01066 static DBusDataSlotAllocator slot_allocator;
01067 _DBUS_DEFINE_GLOBAL_LOCK (server_slots);
01068 
01083 dbus_bool_t
01084 dbus_server_allocate_data_slot (dbus_int32_t *slot_p)
01085 {
01086   return _dbus_data_slot_allocator_alloc (&slot_allocator,
01087                                           (DBusRMutex **)&_DBUS_LOCK_NAME (server_slots),
01088                                           slot_p);
01089 }
01090 
01102 void
01103 dbus_server_free_data_slot (dbus_int32_t *slot_p)
01104 {
01105   _dbus_return_if_fail (*slot_p >= 0);
01106   
01107   _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
01108 }
01109 
01123 dbus_bool_t
01124 dbus_server_set_data (DBusServer       *server,
01125                       int               slot,
01126                       void             *data,
01127                       DBusFreeFunction  free_data_func)
01128 {
01129   DBusFreeFunction old_free_func;
01130   void *old_data;
01131   dbus_bool_t retval;
01132 
01133   _dbus_return_val_if_fail (server != NULL, FALSE);
01134 
01135   SERVER_LOCK (server);
01136   
01137   retval = _dbus_data_slot_list_set (&slot_allocator,
01138                                      &server->slot_list,
01139                                      slot, data, free_data_func,
01140                                      &old_free_func, &old_data);
01141 
01142 
01143   SERVER_UNLOCK (server);
01144   
01145   if (retval)
01146     {
01147       /* Do the actual free outside the server lock */
01148       if (old_free_func)
01149         (* old_free_func) (old_data);
01150     }
01151 
01152   return retval;
01153 }
01154 
01163 void*
01164 dbus_server_get_data (DBusServer   *server,
01165                       int           slot)
01166 {
01167   void *res;
01168 
01169   _dbus_return_val_if_fail (server != NULL, NULL);
01170   
01171   SERVER_LOCK (server);
01172   
01173   res = _dbus_data_slot_list_get (&slot_allocator,
01174                                   &server->slot_list,
01175                                   slot);
01176 
01177   SERVER_UNLOCK (server);
01178   
01179   return res;
01180 }
01181 
01184 #ifdef DBUS_BUILD_TESTS
01185 #include "dbus-test.h"
01186 #include <string.h>
01187 
01188 dbus_bool_t
01189 _dbus_server_test (void)
01190 {
01191   const char *valid_addresses[] = {
01192     "tcp:port=1234",
01193     "tcp:host=localhost,port=1234",
01194     "tcp:host=localhost,port=1234;tcp:port=5678",
01195 #ifdef DBUS_UNIX
01196     "unix:path=./boogie",
01197     "tcp:port=1234;unix:path=./boogie",
01198 #endif
01199   };
01200 
01201   DBusServer *server;
01202   int i;
01203   
01204   for (i = 0; i < _DBUS_N_ELEMENTS (valid_addresses); i++)
01205     {
01206       DBusError error = DBUS_ERROR_INIT;
01207       char *address;
01208       char *id;
01209 
01210       server = dbus_server_listen (valid_addresses[i], &error);
01211       if (server == NULL)
01212         {
01213           _dbus_warn ("server listen error: %s: %s\n", error.name, error.message);
01214           dbus_error_free (&error);
01215           _dbus_assert_not_reached ("Failed to listen for valid address.");
01216         }
01217 
01218       id = dbus_server_get_id (server);
01219       _dbus_assert (id != NULL);
01220       address = dbus_server_get_address (server);
01221       _dbus_assert (address != NULL);
01222 
01223       if (strstr (address, id) == NULL)
01224         {
01225           _dbus_warn ("server id '%s' is not in the server address '%s'\n",
01226                       id, address);
01227           _dbus_assert_not_reached ("bad server id or address");
01228         }
01229 
01230       dbus_free (id);
01231       dbus_free (address);
01232       
01233       dbus_server_disconnect (server);
01234       dbus_server_unref (server);
01235     }
01236 
01237   return TRUE;
01238 }
01239 
01240 #endif /* DBUS_BUILD_TESTS */