D-Bus 1.4.1

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 /* this is a little fragile since it assumes the address doesn't
00057  * already have a guid, but it shouldn't
00058  */
00059 static char*
00060 copy_address_with_guid_appended (const DBusString *address,
00061                                  const DBusString *guid_hex)
00062 {
00063   DBusString with_guid;
00064   char *retval;
00065   
00066   if (!_dbus_string_init (&with_guid))
00067     return NULL;
00068 
00069   if (!_dbus_string_copy (address, 0, &with_guid,
00070                           _dbus_string_get_length (&with_guid)) ||
00071       !_dbus_string_append (&with_guid, ",guid=") ||
00072       !_dbus_string_copy (guid_hex, 0,
00073                           &with_guid, _dbus_string_get_length (&with_guid)))
00074     {
00075       _dbus_string_free (&with_guid);
00076       return NULL;
00077     }
00078 
00079   retval = NULL;
00080   _dbus_string_steal_data (&with_guid, &retval);
00081 
00082   _dbus_string_free (&with_guid);
00083       
00084   return retval; /* may be NULL if steal_data failed */
00085 }
00086 
00096 dbus_bool_t
00097 _dbus_server_init_base (DBusServer             *server,
00098                         const DBusServerVTable *vtable,
00099                         const DBusString       *address)
00100 {
00101   server->vtable = vtable;
00102   server->refcount.value = 1;
00103 
00104   server->address = NULL;
00105   server->watches = NULL;
00106   server->timeouts = NULL;
00107   server->published_address = FALSE;
00108 
00109   if (!_dbus_string_init (&server->guid_hex))
00110     return FALSE;
00111 
00112   _dbus_generate_uuid (&server->guid);
00113 
00114   if (!_dbus_uuid_encode (&server->guid, &server->guid_hex))
00115     goto failed;
00116   
00117   server->address = copy_address_with_guid_appended (address,
00118                                                      &server->guid_hex);
00119   if (server->address == NULL)
00120     goto failed;
00121   
00122   _dbus_mutex_new_at_location (&server->mutex);
00123   if (server->mutex == NULL)
00124     goto failed;
00125   
00126   server->watches = _dbus_watch_list_new ();
00127   if (server->watches == NULL)
00128     goto failed;
00129 
00130   server->timeouts = _dbus_timeout_list_new ();
00131   if (server->timeouts == NULL)
00132     goto failed;
00133 
00134   _dbus_data_slot_list_init (&server->slot_list);
00135 
00136   _dbus_verbose ("Initialized server on address %s\n", server->address);
00137   
00138   return TRUE;
00139 
00140  failed:
00141   _dbus_mutex_free_at_location (&server->mutex);
00142   server->mutex = NULL;
00143   if (server->watches)
00144     {
00145       _dbus_watch_list_free (server->watches);
00146       server->watches = NULL;
00147     }
00148   if (server->timeouts)
00149     {
00150       _dbus_timeout_list_free (server->timeouts);
00151       server->timeouts = NULL;
00152     }
00153   if (server->address)
00154     {
00155       dbus_free (server->address);
00156       server->address = NULL;
00157     }
00158   _dbus_string_free (&server->guid_hex);
00159   
00160   return FALSE;
00161 }
00162 
00169 void
00170 _dbus_server_finalize_base (DBusServer *server)
00171 {
00172   /* We don't have the lock, but nobody should be accessing
00173    * concurrently since they don't have a ref
00174    */
00175 #ifndef DBUS_DISABLE_CHECKS
00176   _dbus_assert (!server->have_server_lock);
00177 #endif
00178   _dbus_assert (server->disconnected);
00179   
00180   /* calls out to application code... */
00181   _dbus_data_slot_list_free (&server->slot_list);
00182 
00183   dbus_server_set_new_connection_function (server, NULL, NULL, NULL);
00184 
00185   _dbus_watch_list_free (server->watches);
00186   _dbus_timeout_list_free (server->timeouts);
00187 
00188   _dbus_mutex_free_at_location (&server->mutex);
00189   
00190   dbus_free (server->address);
00191 
00192   dbus_free_string_array (server->auth_mechanisms);
00193 
00194   _dbus_string_free (&server->guid_hex);
00195 }
00196 
00197 
00199 typedef dbus_bool_t (* DBusWatchAddFunction)     (DBusWatchList *list,
00200                                                   DBusWatch     *watch);
00202 typedef void        (* DBusWatchRemoveFunction)  (DBusWatchList *list,
00203                                                   DBusWatch     *watch);
00205 typedef void        (* DBusWatchToggleFunction)  (DBusWatchList *list,
00206                                                   DBusWatch     *watch,
00207                                                   dbus_bool_t    enabled);
00208 
00209 static dbus_bool_t
00210 protected_change_watch (DBusServer             *server,
00211                         DBusWatch              *watch,
00212                         DBusWatchAddFunction    add_function,
00213                         DBusWatchRemoveFunction remove_function,
00214                         DBusWatchToggleFunction toggle_function,
00215                         dbus_bool_t             enabled)
00216 {
00217   DBusWatchList *watches;
00218   dbus_bool_t retval;
00219   
00220   HAVE_LOCK_CHECK (server);
00221 
00222   /* This isn't really safe or reasonable; a better pattern is the "do
00223    * everything, then drop lock and call out" one; but it has to be
00224    * propagated up through all callers
00225    */
00226   
00227   watches = server->watches;
00228   if (watches)
00229     {
00230       server->watches = NULL;
00231       _dbus_server_ref_unlocked (server);
00232       SERVER_UNLOCK (server);
00233 
00234       if (add_function)
00235         retval = (* add_function) (watches, watch);
00236       else if (remove_function)
00237         {
00238           retval = TRUE;
00239           (* remove_function) (watches, watch);
00240         }
00241       else
00242         {
00243           retval = TRUE;
00244           (* toggle_function) (watches, watch, enabled);
00245         }
00246       
00247       SERVER_LOCK (server);
00248       server->watches = watches;
00249       _dbus_server_unref_unlocked (server);
00250 
00251       return retval;
00252     }
00253   else
00254     return FALSE;
00255 }
00256 
00264 dbus_bool_t
00265 _dbus_server_add_watch (DBusServer *server,
00266                         DBusWatch  *watch)
00267 {
00268   HAVE_LOCK_CHECK (server);
00269   return protected_change_watch (server, watch,
00270                                  _dbus_watch_list_add_watch,
00271                                  NULL, NULL, FALSE);
00272 }
00273 
00280 void
00281 _dbus_server_remove_watch  (DBusServer *server,
00282                             DBusWatch  *watch)
00283 {
00284   HAVE_LOCK_CHECK (server);
00285   protected_change_watch (server, watch,
00286                           NULL,
00287                           _dbus_watch_list_remove_watch,
00288                           NULL, FALSE);
00289 }
00290 
00300 void
00301 _dbus_server_toggle_watch (DBusServer  *server,
00302                            DBusWatch   *watch,
00303                            dbus_bool_t  enabled)
00304 {
00305   _dbus_assert (watch != NULL);
00306 
00307   HAVE_LOCK_CHECK (server);
00308   protected_change_watch (server, watch,
00309                           NULL, NULL,
00310                           _dbus_watch_list_toggle_watch,
00311                           enabled);
00312 }
00313 
00315 typedef dbus_bool_t (* DBusTimeoutAddFunction)    (DBusTimeoutList *list,
00316                                                    DBusTimeout     *timeout);
00318 typedef void        (* DBusTimeoutRemoveFunction) (DBusTimeoutList *list,
00319                                                    DBusTimeout     *timeout);
00321 typedef void        (* DBusTimeoutToggleFunction) (DBusTimeoutList *list,
00322                                                    DBusTimeout     *timeout,
00323                                                    dbus_bool_t      enabled);
00324 
00325 
00326 static dbus_bool_t
00327 protected_change_timeout (DBusServer               *server,
00328                           DBusTimeout              *timeout,
00329                           DBusTimeoutAddFunction    add_function,
00330                           DBusTimeoutRemoveFunction remove_function,
00331                           DBusTimeoutToggleFunction toggle_function,
00332                           dbus_bool_t               enabled)
00333 {
00334   DBusTimeoutList *timeouts;
00335   dbus_bool_t retval;
00336   
00337   HAVE_LOCK_CHECK (server);
00338 
00339   /* This isn't really safe or reasonable; a better pattern is the "do everything, then
00340    * drop lock and call out" one; but it has to be propagated up through all callers
00341    */
00342   
00343   timeouts = server->timeouts;
00344   if (timeouts)
00345     {
00346       server->timeouts = NULL;
00347       _dbus_server_ref_unlocked (server);
00348       SERVER_UNLOCK (server);
00349 
00350       if (add_function)
00351         retval = (* add_function) (timeouts, timeout);
00352       else if (remove_function)
00353         {
00354           retval = TRUE;
00355           (* remove_function) (timeouts, timeout);
00356         }
00357       else
00358         {
00359           retval = TRUE;
00360           (* toggle_function) (timeouts, timeout, enabled);
00361         }
00362       
00363       SERVER_LOCK (server);
00364       server->timeouts = timeouts;
00365       _dbus_server_unref_unlocked (server);
00366 
00367       return retval;
00368     }
00369   else
00370     return FALSE;
00371 }
00372 
00382 dbus_bool_t
00383 _dbus_server_add_timeout (DBusServer  *server,
00384                           DBusTimeout *timeout)
00385 {
00386   return protected_change_timeout (server, timeout,
00387                                    _dbus_timeout_list_add_timeout,
00388                                    NULL, NULL, FALSE);
00389 }
00390 
00397 void
00398 _dbus_server_remove_timeout (DBusServer  *server,
00399                              DBusTimeout *timeout)
00400 {
00401   protected_change_timeout (server, timeout,
00402                             NULL,
00403                             _dbus_timeout_list_remove_timeout,
00404                             NULL, FALSE);
00405 }
00406 
00416 void
00417 _dbus_server_toggle_timeout (DBusServer  *server,
00418                              DBusTimeout *timeout,
00419                              dbus_bool_t  enabled)
00420 {
00421   protected_change_timeout (server, timeout,
00422                             NULL, NULL,
00423                             _dbus_timeout_list_toggle_timeout,
00424                             enabled);
00425 }
00426 
00427 
00433 void
00434 _dbus_server_ref_unlocked (DBusServer *server)
00435 {
00436   _dbus_assert (server != NULL);
00437   _dbus_assert (server->refcount.value > 0);
00438   
00439   HAVE_LOCK_CHECK (server);
00440 
00441 #ifdef DBUS_HAVE_ATOMIC_INT
00442   _dbus_atomic_inc (&server->refcount);
00443 #else
00444   _dbus_assert (server->refcount.value > 0);
00445 
00446   server->refcount.value += 1;
00447 #endif
00448 }
00449 
00455 void
00456 _dbus_server_unref_unlocked (DBusServer *server)
00457 {
00458   dbus_bool_t last_unref;
00459 
00460   /* Keep this in sync with dbus_server_unref */
00461   
00462   _dbus_assert (server != NULL);
00463   _dbus_assert (server->refcount.value > 0);
00464 
00465   HAVE_LOCK_CHECK (server);
00466   
00467 #ifdef DBUS_HAVE_ATOMIC_INT
00468   last_unref = (_dbus_atomic_dec (&server->refcount) == 1);
00469 #else
00470   _dbus_assert (server->refcount.value > 0);
00471 
00472   server->refcount.value -= 1;
00473   last_unref = (server->refcount.value == 0);
00474 #endif
00475   
00476   if (last_unref)
00477     {
00478       _dbus_assert (server->disconnected);
00479       
00480       SERVER_UNLOCK (server);
00481       
00482       _dbus_assert (server->vtable->finalize != NULL);
00483       
00484       (* server->vtable->finalize) (server);
00485     }
00486 }
00487 
00509 static const struct {
00510   DBusServerListenResult (* func) (DBusAddressEntry *entry,
00511                                    DBusServer      **server_p,
00512                                    DBusError        *error);
00513 } listen_funcs[] = {
00514   { _dbus_server_listen_socket }
00515   , { _dbus_server_listen_platform_specific }
00516 #ifdef DBUS_BUILD_TESTS
00517   , { _dbus_server_listen_debug_pipe }
00518 #endif
00519 };
00520 
00541 DBusServer*
00542 dbus_server_listen (const char     *address,
00543                     DBusError      *error)
00544 {
00545   DBusServer *server;
00546   DBusAddressEntry **entries;
00547   int len, i;
00548   DBusError first_connect_error = DBUS_ERROR_INIT;
00549   dbus_bool_t handled_once;
00550   
00551   _dbus_return_val_if_fail (address != NULL, NULL);
00552   _dbus_return_val_if_error_is_set (error, NULL);
00553   
00554   if (!dbus_parse_address (address, &entries, &len, error))
00555     return NULL;
00556 
00557   server = NULL;
00558   handled_once = FALSE;
00559 
00560   for (i = 0; i < len; i++)
00561     {
00562       int j;
00563 
00564       for (j = 0; j < (int) _DBUS_N_ELEMENTS (listen_funcs); ++j)
00565         {
00566           DBusServerListenResult result;
00567           DBusError tmp_error = DBUS_ERROR_INIT;
00568 
00569           result = (* listen_funcs[j].func) (entries[i],
00570                                              &server,
00571                                              &tmp_error);
00572 
00573           if (result == DBUS_SERVER_LISTEN_OK)
00574             {
00575               _dbus_assert (server != NULL);
00576               _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
00577               handled_once = TRUE;
00578               goto out;
00579             }
00580           else if (result == DBUS_SERVER_LISTEN_ADDRESS_ALREADY_USED)
00581             {
00582               _dbus_assert (server == NULL);
00583               dbus_set_error (error,
00584                        DBUS_ERROR_ADDRESS_IN_USE,
00585                        "Address '%s' already used",
00586                        dbus_address_entry_get_method (entries[0]));
00587               handled_once = TRUE;
00588               goto out;
00589             }
00590           else if (result == DBUS_SERVER_LISTEN_BAD_ADDRESS)
00591             {
00592               _dbus_assert (server == NULL);
00593               _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
00594               dbus_move_error (&tmp_error, error);
00595               handled_once = TRUE;
00596               goto out;
00597             }
00598           else if (result == DBUS_SERVER_LISTEN_NOT_HANDLED)
00599             {
00600               _dbus_assert (server == NULL);
00601               _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
00602 
00603               /* keep trying addresses */
00604             }
00605           else if (result == DBUS_SERVER_LISTEN_DID_NOT_CONNECT)
00606             {
00607               _dbus_assert (server == NULL);
00608               _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
00609               if (!dbus_error_is_set (&first_connect_error))
00610                 dbus_move_error (&tmp_error, &first_connect_error);
00611               else
00612                 dbus_error_free (&tmp_error);
00613 
00614               handled_once = TRUE;
00615               
00616               /* keep trying addresses */
00617             }
00618         }
00619 
00620       _dbus_assert (server == NULL);
00621       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00622     }
00623 
00624  out:
00625 
00626   if (!handled_once)
00627     {
00628       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00629       if (len > 0)
00630         dbus_set_error (error,
00631                        DBUS_ERROR_BAD_ADDRESS,
00632                        "Unknown address type '%s'",
00633                        dbus_address_entry_get_method (entries[0]));
00634       else
00635         dbus_set_error (error,
00636                         DBUS_ERROR_BAD_ADDRESS,
00637                         "Empty address '%s'",
00638                         address);
00639     }
00640   
00641   dbus_address_entries_free (entries);
00642 
00643   if (server == NULL)
00644     {
00645       _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error) ||
00646                    dbus_error_is_set (error));
00647       
00648       if (error && dbus_error_is_set (error))
00649         {
00650           /* already set the error */
00651         }
00652       else
00653         {
00654           /* didn't set the error but either error should be
00655            * NULL or first_connect_error should be set.
00656            */
00657           _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error));
00658           dbus_move_error (&first_connect_error, error);
00659         }
00660 
00661       _DBUS_ASSERT_ERROR_IS_CLEAR (&first_connect_error); /* be sure we freed it */
00662       _DBUS_ASSERT_ERROR_IS_SET (error);
00663 
00664       return NULL;
00665     }
00666   else
00667     {
00668       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00669       return server;
00670     }
00671 }
00672 
00679 DBusServer *
00680 dbus_server_ref (DBusServer *server)
00681 {
00682   _dbus_return_val_if_fail (server != NULL, NULL);
00683   _dbus_return_val_if_fail (server->refcount.value > 0, NULL);
00684 
00685 #ifdef DBUS_HAVE_ATOMIC_INT
00686   _dbus_atomic_inc (&server->refcount);
00687 #else
00688   SERVER_LOCK (server);
00689   _dbus_assert (server->refcount.value > 0);
00690 
00691   server->refcount.value += 1;
00692   SERVER_UNLOCK (server);
00693 #endif
00694 
00695   return server;
00696 }
00697 
00706 void
00707 dbus_server_unref (DBusServer *server)
00708 {
00709   dbus_bool_t last_unref;
00710 
00711   /* keep this in sync with unref_unlocked */
00712   
00713   _dbus_return_if_fail (server != NULL);
00714   _dbus_return_if_fail (server->refcount.value > 0);
00715 
00716 #ifdef DBUS_HAVE_ATOMIC_INT
00717   last_unref = (_dbus_atomic_dec (&server->refcount) == 1);
00718 #else
00719   SERVER_LOCK (server);
00720   
00721   _dbus_assert (server->refcount.value > 0);
00722 
00723   server->refcount.value -= 1;
00724   last_unref = (server->refcount.value == 0);
00725   
00726   SERVER_UNLOCK (server);
00727 #endif
00728   
00729   if (last_unref)
00730     {
00731       /* lock not held! */
00732       _dbus_assert (server->disconnected);
00733       
00734       _dbus_assert (server->vtable->finalize != NULL);
00735       
00736       (* server->vtable->finalize) (server);
00737     }
00738 }
00739 
00748 void
00749 dbus_server_disconnect (DBusServer *server)
00750 {
00751   _dbus_return_if_fail (server != NULL);
00752   _dbus_return_if_fail (server->refcount.value > 0);
00753 
00754   SERVER_LOCK (server);
00755   _dbus_server_ref_unlocked (server);
00756   
00757   _dbus_assert (server->vtable->disconnect != NULL);
00758 
00759   if (!server->disconnected)
00760     {
00761       /* this has to be first so recursive calls to disconnect don't happen */
00762       server->disconnected = TRUE;
00763       
00764       (* server->vtable->disconnect) (server);
00765     }
00766 
00767   SERVER_UNLOCK (server);
00768   dbus_server_unref (server);
00769 }
00770 
00776 dbus_bool_t
00777 dbus_server_get_is_connected (DBusServer *server)
00778 {
00779   dbus_bool_t retval;
00780   
00781   _dbus_return_val_if_fail (server != NULL, FALSE);
00782 
00783   SERVER_LOCK (server);
00784   retval = !server->disconnected;
00785   SERVER_UNLOCK (server);
00786 
00787   return retval;
00788 }
00789 
00797 char*
00798 dbus_server_get_address (DBusServer *server)
00799 {
00800   char *retval;
00801   
00802   _dbus_return_val_if_fail (server != NULL, NULL);
00803 
00804   SERVER_LOCK (server);
00805   retval = _dbus_strdup (server->address);
00806   SERVER_UNLOCK (server);
00807 
00808   return retval;
00809 }
00810 
00833 char*
00834 dbus_server_get_id (DBusServer *server)
00835 {
00836   char *retval;
00837   
00838   _dbus_return_val_if_fail (server != NULL, NULL);
00839 
00840   SERVER_LOCK (server);
00841   retval = NULL;
00842   _dbus_string_copy_data (&server->guid_hex, &retval);
00843   SERVER_UNLOCK (server);
00844 
00845   return retval;
00846 }
00847 
00868 void
00869 dbus_server_set_new_connection_function (DBusServer                *server,
00870                                          DBusNewConnectionFunction  function,
00871                                          void                      *data,
00872                                          DBusFreeFunction           free_data_function)
00873 {
00874   DBusFreeFunction old_free_function;
00875   void *old_data;
00876   
00877   _dbus_return_if_fail (server != NULL);
00878 
00879   SERVER_LOCK (server);
00880   old_free_function = server->new_connection_free_data_function;
00881   old_data = server->new_connection_data;
00882   
00883   server->new_connection_function = function;
00884   server->new_connection_data = data;
00885   server->new_connection_free_data_function = free_data_function;
00886   SERVER_UNLOCK (server);
00887     
00888   if (old_free_function != NULL)
00889     (* old_free_function) (old_data);
00890 }
00891 
00908 dbus_bool_t
00909 dbus_server_set_watch_functions (DBusServer              *server,
00910                                  DBusAddWatchFunction     add_function,
00911                                  DBusRemoveWatchFunction  remove_function,
00912                                  DBusWatchToggledFunction toggled_function,
00913                                  void                    *data,
00914                                  DBusFreeFunction         free_data_function)
00915 {
00916   dbus_bool_t result;
00917   DBusWatchList *watches;
00918   
00919   _dbus_return_val_if_fail (server != NULL, FALSE);
00920 
00921   SERVER_LOCK (server);
00922   watches = server->watches;
00923   server->watches = NULL;
00924   if (watches)
00925     {
00926       SERVER_UNLOCK (server);
00927       result = _dbus_watch_list_set_functions (watches,
00928                                                add_function,
00929                                                remove_function,
00930                                                toggled_function,
00931                                                data,
00932                                                free_data_function);
00933       SERVER_LOCK (server);
00934     }
00935   else
00936     {
00937       _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
00938       result = FALSE;
00939     }
00940   server->watches = watches;
00941   SERVER_UNLOCK (server);
00942   
00943   return result;
00944 }
00945 
00961 dbus_bool_t
00962 dbus_server_set_timeout_functions (DBusServer                *server,
00963                                    DBusAddTimeoutFunction     add_function,
00964                                    DBusRemoveTimeoutFunction  remove_function,
00965                                    DBusTimeoutToggledFunction toggled_function,
00966                                    void                      *data,
00967                                    DBusFreeFunction           free_data_function)
00968 {
00969   dbus_bool_t result;
00970   DBusTimeoutList *timeouts;
00971   
00972   _dbus_return_val_if_fail (server != NULL, FALSE);
00973 
00974   SERVER_LOCK (server);
00975   timeouts = server->timeouts;
00976   server->timeouts = NULL;
00977   if (timeouts)
00978     {
00979       SERVER_UNLOCK (server);
00980       result = _dbus_timeout_list_set_functions (timeouts,
00981                                                  add_function,
00982                                                  remove_function,
00983                                                  toggled_function,
00984                                                  data,
00985                                                  free_data_function);
00986       SERVER_LOCK (server);
00987     }
00988   else
00989     {
00990       _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
00991       result = FALSE;
00992     }
00993   server->timeouts = timeouts;
00994   SERVER_UNLOCK (server);
00995   
00996   return result;
00997 }
00998 
01012 dbus_bool_t
01013 dbus_server_set_auth_mechanisms (DBusServer  *server,
01014                                  const char **mechanisms)
01015 {
01016   char **copy;
01017 
01018   _dbus_return_val_if_fail (server != NULL, FALSE);
01019 
01020   SERVER_LOCK (server);
01021   
01022   if (mechanisms != NULL)
01023     {
01024       copy = _dbus_dup_string_array (mechanisms);
01025       if (copy == NULL)
01026         return FALSE;
01027     }
01028   else
01029     copy = NULL;
01030 
01031   dbus_free_string_array (server->auth_mechanisms);
01032   server->auth_mechanisms = copy;
01033 
01034   SERVER_UNLOCK (server);
01035   
01036   return TRUE;
01037 }
01038 
01039 
01040 static DBusDataSlotAllocator slot_allocator;
01041 _DBUS_DEFINE_GLOBAL_LOCK (server_slots);
01042 
01057 dbus_bool_t
01058 dbus_server_allocate_data_slot (dbus_int32_t *slot_p)
01059 {
01060   return _dbus_data_slot_allocator_alloc (&slot_allocator,
01061                                           (DBusMutex **)&_DBUS_LOCK_NAME (server_slots),
01062                                           slot_p);
01063 }
01064 
01076 void
01077 dbus_server_free_data_slot (dbus_int32_t *slot_p)
01078 {
01079   _dbus_return_if_fail (*slot_p >= 0);
01080   
01081   _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
01082 }
01083 
01097 dbus_bool_t
01098 dbus_server_set_data (DBusServer       *server,
01099                       int               slot,
01100                       void             *data,
01101                       DBusFreeFunction  free_data_func)
01102 {
01103   DBusFreeFunction old_free_func;
01104   void *old_data;
01105   dbus_bool_t retval;
01106 
01107   _dbus_return_val_if_fail (server != NULL, FALSE);
01108 
01109   SERVER_LOCK (server);
01110   
01111   retval = _dbus_data_slot_list_set (&slot_allocator,
01112                                      &server->slot_list,
01113                                      slot, data, free_data_func,
01114                                      &old_free_func, &old_data);
01115 
01116 
01117   SERVER_UNLOCK (server);
01118   
01119   if (retval)
01120     {
01121       /* Do the actual free outside the server lock */
01122       if (old_free_func)
01123         (* old_free_func) (old_data);
01124     }
01125 
01126   return retval;
01127 }
01128 
01137 void*
01138 dbus_server_get_data (DBusServer   *server,
01139                       int           slot)
01140 {
01141   void *res;
01142 
01143   _dbus_return_val_if_fail (server != NULL, NULL);
01144   
01145   SERVER_LOCK (server);
01146   
01147   res = _dbus_data_slot_list_get (&slot_allocator,
01148                                   &server->slot_list,
01149                                   slot);
01150 
01151   SERVER_UNLOCK (server);
01152   
01153   return res;
01154 }
01155 
01158 #ifdef DBUS_BUILD_TESTS
01159 #include "dbus-test.h"
01160 #include <string.h>
01161 
01162 dbus_bool_t
01163 _dbus_server_test (void)
01164 {
01165   const char *valid_addresses[] = {
01166     "tcp:port=1234",
01167     "tcp:host=localhost,port=1234",
01168     "tcp:host=localhost,port=1234;tcp:port=5678",
01169 #ifdef DBUS_UNIX
01170     "unix:path=./boogie",
01171     "tcp:port=1234;unix:path=./boogie",
01172 #endif
01173   };
01174 
01175   DBusServer *server;
01176   int i;
01177   
01178   for (i = 0; i < _DBUS_N_ELEMENTS (valid_addresses); i++)
01179     {
01180       DBusError error = DBUS_ERROR_INIT;
01181       char *address;
01182       char *id;
01183 
01184       server = dbus_server_listen (valid_addresses[i], &error);
01185       if (server == NULL)
01186         {
01187           _dbus_warn ("server listen error: %s: %s\n", error.name, error.message);
01188           dbus_error_free (&error);
01189           _dbus_assert_not_reached ("Failed to listen for valid address.");
01190         }
01191 
01192       id = dbus_server_get_id (server);
01193       _dbus_assert (id != NULL);
01194       address = dbus_server_get_address (server);
01195       _dbus_assert (address != NULL);
01196 
01197       if (strstr (address, id) == NULL)
01198         {
01199           _dbus_warn ("server id '%s' is not in the server address '%s'\n",
01200                       id, address);
01201           _dbus_assert_not_reached ("bad server id or address");
01202         }
01203 
01204       dbus_free (id);
01205       dbus_free (address);
01206       
01207       dbus_server_disconnect (server);
01208       dbus_server_unref (server);
01209     }
01210 
01211   return TRUE;
01212 }
01213 
01214 #endif /* DBUS_BUILD_TESTS */