D-Bus 1.6.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_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 */