D-Bus  1.4.18
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 
00103 #ifdef DBUS_DISABLE_ASSERT
00104   _dbus_atomic_inc (&server->refcount);
00105 #else
00106     {
00107       dbus_int32_t old_refcount = _dbus_atomic_inc (&server->refcount);
00108 
00109       _dbus_assert (old_refcount == 0);
00110     }
00111 #endif
00112 
00113   server->address = NULL;
00114   server->watches = NULL;
00115   server->timeouts = NULL;
00116   server->published_address = FALSE;
00117 
00118   if (!_dbus_string_init (&server->guid_hex))
00119     return FALSE;
00120 
00121   _dbus_generate_uuid (&server->guid);
00122 
00123   if (!_dbus_uuid_encode (&server->guid, &server->guid_hex))
00124     goto failed;
00125   
00126   server->address = copy_address_with_guid_appended (address,
00127                                                      &server->guid_hex);
00128   if (server->address == NULL)
00129     goto failed;
00130   
00131   _dbus_mutex_new_at_location (&server->mutex);
00132   if (server->mutex == NULL)
00133     goto failed;
00134   
00135   server->watches = _dbus_watch_list_new ();
00136   if (server->watches == NULL)
00137     goto failed;
00138 
00139   server->timeouts = _dbus_timeout_list_new ();
00140   if (server->timeouts == NULL)
00141     goto failed;
00142 
00143   _dbus_data_slot_list_init (&server->slot_list);
00144 
00145   _dbus_verbose ("Initialized server on address %s\n", server->address);
00146   
00147   return TRUE;
00148 
00149  failed:
00150   _dbus_mutex_free_at_location (&server->mutex);
00151   server->mutex = NULL;
00152   if (server->watches)
00153     {
00154       _dbus_watch_list_free (server->watches);
00155       server->watches = NULL;
00156     }
00157   if (server->timeouts)
00158     {
00159       _dbus_timeout_list_free (server->timeouts);
00160       server->timeouts = NULL;
00161     }
00162   if (server->address)
00163     {
00164       dbus_free (server->address);
00165       server->address = NULL;
00166     }
00167   _dbus_string_free (&server->guid_hex);
00168   
00169   return FALSE;
00170 }
00171 
00178 void
00179 _dbus_server_finalize_base (DBusServer *server)
00180 {
00181   /* We don't have the lock, but nobody should be accessing
00182    * concurrently since they don't have a ref
00183    */
00184 #ifndef DBUS_DISABLE_CHECKS
00185   _dbus_assert (!server->have_server_lock);
00186 #endif
00187   _dbus_assert (server->disconnected);
00188   
00189   /* calls out to application code... */
00190   _dbus_data_slot_list_free (&server->slot_list);
00191 
00192   dbus_server_set_new_connection_function (server, NULL, NULL, NULL);
00193 
00194   _dbus_watch_list_free (server->watches);
00195   _dbus_timeout_list_free (server->timeouts);
00196 
00197   _dbus_mutex_free_at_location (&server->mutex);
00198   
00199   dbus_free (server->address);
00200 
00201   dbus_free_string_array (server->auth_mechanisms);
00202 
00203   _dbus_string_free (&server->guid_hex);
00204 }
00205 
00206 
00208 typedef dbus_bool_t (* DBusWatchAddFunction)     (DBusWatchList *list,
00209                                                   DBusWatch     *watch);
00211 typedef void        (* DBusWatchRemoveFunction)  (DBusWatchList *list,
00212                                                   DBusWatch     *watch);
00214 typedef void        (* DBusWatchToggleFunction)  (DBusWatchList *list,
00215                                                   DBusWatch     *watch,
00216                                                   dbus_bool_t    enabled);
00217 
00218 static dbus_bool_t
00219 protected_change_watch (DBusServer             *server,
00220                         DBusWatch              *watch,
00221                         DBusWatchAddFunction    add_function,
00222                         DBusWatchRemoveFunction remove_function,
00223                         DBusWatchToggleFunction toggle_function,
00224                         dbus_bool_t             enabled)
00225 {
00226   DBusWatchList *watches;
00227   dbus_bool_t retval;
00228   
00229   HAVE_LOCK_CHECK (server);
00230 
00231   /* This isn't really safe or reasonable; a better pattern is the "do
00232    * everything, then drop lock and call out" one; but it has to be
00233    * propagated up through all callers
00234    */
00235   
00236   watches = server->watches;
00237   if (watches)
00238     {
00239       server->watches = NULL;
00240       _dbus_server_ref_unlocked (server);
00241       SERVER_UNLOCK (server);
00242 
00243       if (add_function)
00244         retval = (* add_function) (watches, watch);
00245       else if (remove_function)
00246         {
00247           retval = TRUE;
00248           (* remove_function) (watches, watch);
00249         }
00250       else
00251         {
00252           retval = TRUE;
00253           (* toggle_function) (watches, watch, enabled);
00254         }
00255       
00256       SERVER_LOCK (server);
00257       server->watches = watches;
00258       _dbus_server_unref_unlocked (server);
00259 
00260       return retval;
00261     }
00262   else
00263     return FALSE;
00264 }
00265 
00273 dbus_bool_t
00274 _dbus_server_add_watch (DBusServer *server,
00275                         DBusWatch  *watch)
00276 {
00277   HAVE_LOCK_CHECK (server);
00278   return protected_change_watch (server, watch,
00279                                  _dbus_watch_list_add_watch,
00280                                  NULL, NULL, FALSE);
00281 }
00282 
00289 void
00290 _dbus_server_remove_watch  (DBusServer *server,
00291                             DBusWatch  *watch)
00292 {
00293   HAVE_LOCK_CHECK (server);
00294   protected_change_watch (server, watch,
00295                           NULL,
00296                           _dbus_watch_list_remove_watch,
00297                           NULL, FALSE);
00298 }
00299 
00307 void
00308 _dbus_server_toggle_all_watches (DBusServer  *server,
00309                                 dbus_bool_t  enabled)
00310 {
00311   _dbus_watch_list_toggle_all_watches (server->watches, 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   HAVE_LOCK_CHECK (server);
00438 
00439 #ifdef DBUS_DISABLE_ASSERT
00440   _dbus_atomic_inc (&server->refcount);
00441 #else
00442     {
00443       dbus_int32_t old_refcount = _dbus_atomic_inc (&server->refcount);
00444 
00445       _dbus_assert (old_refcount > 0);
00446     }
00447 #endif
00448 }
00449 
00455 void
00456 _dbus_server_unref_unlocked (DBusServer *server)
00457 {
00458   dbus_int32_t old_refcount;
00459 
00460   /* Keep this in sync with dbus_server_unref */
00461 
00462   _dbus_assert (server != NULL);
00463 
00464   HAVE_LOCK_CHECK (server);
00465 
00466   old_refcount = _dbus_atomic_dec (&server->refcount);
00467   _dbus_assert (old_refcount > 0);
00468 
00469   if (old_refcount == 1)
00470     {
00471       _dbus_assert (server->disconnected);
00472       
00473       SERVER_UNLOCK (server);
00474       
00475       _dbus_assert (server->vtable->finalize != NULL);
00476       
00477       (* server->vtable->finalize) (server);
00478     }
00479 }
00480 
00502 static const struct {
00503   DBusServerListenResult (* func) (DBusAddressEntry *entry,
00504                                    DBusServer      **server_p,
00505                                    DBusError        *error);
00506 } listen_funcs[] = {
00507   { _dbus_server_listen_socket }
00508   , { _dbus_server_listen_platform_specific }
00509 #ifdef DBUS_BUILD_TESTS
00510   , { _dbus_server_listen_debug_pipe }
00511 #endif
00512 };
00513 
00534 DBusServer*
00535 dbus_server_listen (const char     *address,
00536                     DBusError      *error)
00537 {
00538   DBusServer *server;
00539   DBusAddressEntry **entries;
00540   int len, i;
00541   DBusError first_connect_error = DBUS_ERROR_INIT;
00542   dbus_bool_t handled_once;
00543   
00544   _dbus_return_val_if_fail (address != NULL, NULL);
00545   _dbus_return_val_if_error_is_set (error, NULL);
00546   
00547   if (!dbus_parse_address (address, &entries, &len, error))
00548     return NULL;
00549 
00550   server = NULL;
00551   handled_once = FALSE;
00552 
00553   for (i = 0; i < len; i++)
00554     {
00555       int j;
00556 
00557       for (j = 0; j < (int) _DBUS_N_ELEMENTS (listen_funcs); ++j)
00558         {
00559           DBusServerListenResult result;
00560           DBusError tmp_error = DBUS_ERROR_INIT;
00561 
00562           result = (* listen_funcs[j].func) (entries[i],
00563                                              &server,
00564                                              &tmp_error);
00565 
00566           if (result == DBUS_SERVER_LISTEN_OK)
00567             {
00568               _dbus_assert (server != NULL);
00569               _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
00570               handled_once = TRUE;
00571               goto out;
00572             }
00573           else if (result == DBUS_SERVER_LISTEN_ADDRESS_ALREADY_USED)
00574             {
00575               _dbus_assert (server == NULL);
00576               dbus_set_error (error,
00577                        DBUS_ERROR_ADDRESS_IN_USE,
00578                        "Address '%s' already used",
00579                        dbus_address_entry_get_method (entries[0]));
00580               handled_once = TRUE;
00581               goto out;
00582             }
00583           else if (result == DBUS_SERVER_LISTEN_BAD_ADDRESS)
00584             {
00585               _dbus_assert (server == NULL);
00586               _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
00587               dbus_move_error (&tmp_error, error);
00588               handled_once = TRUE;
00589               goto out;
00590             }
00591           else if (result == DBUS_SERVER_LISTEN_NOT_HANDLED)
00592             {
00593               _dbus_assert (server == NULL);
00594               _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
00595 
00596               /* keep trying addresses */
00597             }
00598           else if (result == DBUS_SERVER_LISTEN_DID_NOT_CONNECT)
00599             {
00600               _dbus_assert (server == NULL);
00601               _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
00602               if (!dbus_error_is_set (&first_connect_error))
00603                 dbus_move_error (&tmp_error, &first_connect_error);
00604               else
00605                 dbus_error_free (&tmp_error);
00606 
00607               handled_once = TRUE;
00608               
00609               /* keep trying addresses */
00610             }
00611         }
00612 
00613       _dbus_assert (server == NULL);
00614       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00615     }
00616 
00617  out:
00618 
00619   if (!handled_once)
00620     {
00621       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00622       if (len > 0)
00623         dbus_set_error (error,
00624                        DBUS_ERROR_BAD_ADDRESS,
00625                        "Unknown address type '%s'",
00626                        dbus_address_entry_get_method (entries[0]));
00627       else
00628         dbus_set_error (error,
00629                         DBUS_ERROR_BAD_ADDRESS,
00630                         "Empty address '%s'",
00631                         address);
00632     }
00633   
00634   dbus_address_entries_free (entries);
00635 
00636   if (server == NULL)
00637     {
00638       _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error) ||
00639                    dbus_error_is_set (error));
00640       
00641       if (error && dbus_error_is_set (error))
00642         {
00643           /* already set the error */
00644         }
00645       else
00646         {
00647           /* didn't set the error but either error should be
00648            * NULL or first_connect_error should be set.
00649            */
00650           _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error));
00651           dbus_move_error (&first_connect_error, error);
00652         }
00653 
00654       _DBUS_ASSERT_ERROR_IS_CLEAR (&first_connect_error); /* be sure we freed it */
00655       _DBUS_ASSERT_ERROR_IS_SET (error);
00656 
00657       return NULL;
00658     }
00659   else
00660     {
00661       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00662       return server;
00663     }
00664 }
00665 
00672 DBusServer *
00673 dbus_server_ref (DBusServer *server)
00674 {
00675   _dbus_return_val_if_fail (server != NULL, NULL);
00676 
00677 #ifdef DBUS_DISABLE_CHECKS
00678   _dbus_atomic_inc (&server->refcount);
00679 #else
00680     {
00681       dbus_int32_t old_refcount;
00682 
00683       /* can't get the refcount without a side-effect */
00684       old_refcount = _dbus_atomic_inc (&server->refcount);
00685 
00686       if (_DBUS_UNLIKELY (old_refcount <= 0))
00687         {
00688           /* undo side-effect first */
00689           _dbus_atomic_dec (&server->refcount);
00690           _dbus_warn_check_failed (_dbus_return_if_fail_warning_format,
00691                                    _DBUS_FUNCTION_NAME, "old_refcount > 0",
00692                                    __FILE__, __LINE__);
00693           return NULL;
00694         }
00695     }
00696 #endif
00697 
00698   return server;
00699 }
00700 
00709 void
00710 dbus_server_unref (DBusServer *server)
00711 {
00712   dbus_int32_t old_refcount;
00713 
00714   /* keep this in sync with unref_unlocked */
00715 
00716   _dbus_return_if_fail (server != NULL);
00717 
00718   /* can't get the refcount without a side-effect */
00719   old_refcount = _dbus_atomic_dec (&server->refcount);
00720 
00721 #ifndef DBUS_DISABLE_CHECKS
00722   if (_DBUS_UNLIKELY (old_refcount <= 0))
00723     {
00724       /* undo side-effect first */
00725       _dbus_atomic_inc (&server->refcount);
00726       _dbus_warn_check_failed (_dbus_return_if_fail_warning_format,
00727                                _DBUS_FUNCTION_NAME, "old_refcount > 0",
00728                                __FILE__, __LINE__);
00729       return;
00730     }
00731 #endif
00732 
00733   if (old_refcount == 1)
00734     {
00735       /* lock not held! */
00736       _dbus_assert (server->disconnected);
00737       
00738       _dbus_assert (server->vtable->finalize != NULL);
00739       
00740       (* server->vtable->finalize) (server);
00741     }
00742 }
00743 
00752 void
00753 dbus_server_disconnect (DBusServer *server)
00754 {
00755   _dbus_return_if_fail (server != NULL);
00756 
00757 #ifdef DBUS_DISABLE_CHECKS
00758   _dbus_atomic_inc (&server->refcount);
00759 #else
00760     {
00761       dbus_int32_t old_refcount = _dbus_atomic_inc (&server->refcount);
00762 
00763       _dbus_return_if_fail (old_refcount > 0);
00764     }
00765 #endif
00766 
00767   SERVER_LOCK (server);
00768 
00769   _dbus_assert (server->vtable->disconnect != NULL);
00770 
00771   if (!server->disconnected)
00772     {
00773       /* this has to be first so recursive calls to disconnect don't happen */
00774       server->disconnected = TRUE;
00775       
00776       (* server->vtable->disconnect) (server);
00777     }
00778 
00779   SERVER_UNLOCK (server);
00780   dbus_server_unref (server);
00781 }
00782 
00788 dbus_bool_t
00789 dbus_server_get_is_connected (DBusServer *server)
00790 {
00791   dbus_bool_t retval;
00792   
00793   _dbus_return_val_if_fail (server != NULL, FALSE);
00794 
00795   SERVER_LOCK (server);
00796   retval = !server->disconnected;
00797   SERVER_UNLOCK (server);
00798 
00799   return retval;
00800 }
00801 
00809 char*
00810 dbus_server_get_address (DBusServer *server)
00811 {
00812   char *retval;
00813   
00814   _dbus_return_val_if_fail (server != NULL, NULL);
00815 
00816   SERVER_LOCK (server);
00817   retval = _dbus_strdup (server->address);
00818   SERVER_UNLOCK (server);
00819 
00820   return retval;
00821 }
00822 
00845 char*
00846 dbus_server_get_id (DBusServer *server)
00847 {
00848   char *retval;
00849   
00850   _dbus_return_val_if_fail (server != NULL, NULL);
00851 
00852   SERVER_LOCK (server);
00853   retval = NULL;
00854   _dbus_string_copy_data (&server->guid_hex, &retval);
00855   SERVER_UNLOCK (server);
00856 
00857   return retval;
00858 }
00859 
00880 void
00881 dbus_server_set_new_connection_function (DBusServer                *server,
00882                                          DBusNewConnectionFunction  function,
00883                                          void                      *data,
00884                                          DBusFreeFunction           free_data_function)
00885 {
00886   DBusFreeFunction old_free_function;
00887   void *old_data;
00888   
00889   _dbus_return_if_fail (server != NULL);
00890 
00891   SERVER_LOCK (server);
00892   old_free_function = server->new_connection_free_data_function;
00893   old_data = server->new_connection_data;
00894   
00895   server->new_connection_function = function;
00896   server->new_connection_data = data;
00897   server->new_connection_free_data_function = free_data_function;
00898   SERVER_UNLOCK (server);
00899     
00900   if (old_free_function != NULL)
00901     (* old_free_function) (old_data);
00902 }
00903 
00920 dbus_bool_t
00921 dbus_server_set_watch_functions (DBusServer              *server,
00922                                  DBusAddWatchFunction     add_function,
00923                                  DBusRemoveWatchFunction  remove_function,
00924                                  DBusWatchToggledFunction toggled_function,
00925                                  void                    *data,
00926                                  DBusFreeFunction         free_data_function)
00927 {
00928   dbus_bool_t result;
00929   DBusWatchList *watches;
00930   
00931   _dbus_return_val_if_fail (server != NULL, FALSE);
00932 
00933   SERVER_LOCK (server);
00934   watches = server->watches;
00935   server->watches = NULL;
00936   if (watches)
00937     {
00938       SERVER_UNLOCK (server);
00939       result = _dbus_watch_list_set_functions (watches,
00940                                                add_function,
00941                                                remove_function,
00942                                                toggled_function,
00943                                                data,
00944                                                free_data_function);
00945       SERVER_LOCK (server);
00946     }
00947   else
00948     {
00949       _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
00950       result = FALSE;
00951     }
00952   server->watches = watches;
00953   SERVER_UNLOCK (server);
00954   
00955   return result;
00956 }
00957 
00973 dbus_bool_t
00974 dbus_server_set_timeout_functions (DBusServer                *server,
00975                                    DBusAddTimeoutFunction     add_function,
00976                                    DBusRemoveTimeoutFunction  remove_function,
00977                                    DBusTimeoutToggledFunction toggled_function,
00978                                    void                      *data,
00979                                    DBusFreeFunction           free_data_function)
00980 {
00981   dbus_bool_t result;
00982   DBusTimeoutList *timeouts;
00983   
00984   _dbus_return_val_if_fail (server != NULL, FALSE);
00985 
00986   SERVER_LOCK (server);
00987   timeouts = server->timeouts;
00988   server->timeouts = NULL;
00989   if (timeouts)
00990     {
00991       SERVER_UNLOCK (server);
00992       result = _dbus_timeout_list_set_functions (timeouts,
00993                                                  add_function,
00994                                                  remove_function,
00995                                                  toggled_function,
00996                                                  data,
00997                                                  free_data_function);
00998       SERVER_LOCK (server);
00999     }
01000   else
01001     {
01002       _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
01003       result = FALSE;
01004     }
01005   server->timeouts = timeouts;
01006   SERVER_UNLOCK (server);
01007   
01008   return result;
01009 }
01010 
01024 dbus_bool_t
01025 dbus_server_set_auth_mechanisms (DBusServer  *server,
01026                                  const char **mechanisms)
01027 {
01028   char **copy;
01029 
01030   _dbus_return_val_if_fail (server != NULL, FALSE);
01031 
01032   SERVER_LOCK (server);
01033   
01034   if (mechanisms != NULL)
01035     {
01036       copy = _dbus_dup_string_array (mechanisms);
01037       if (copy == NULL)
01038         return FALSE;
01039     }
01040   else
01041     copy = NULL;
01042 
01043   dbus_free_string_array (server->auth_mechanisms);
01044   server->auth_mechanisms = copy;
01045 
01046   SERVER_UNLOCK (server);
01047   
01048   return TRUE;
01049 }
01050 
01051 
01052 static DBusDataSlotAllocator slot_allocator;
01053 _DBUS_DEFINE_GLOBAL_LOCK (server_slots);
01054 
01069 dbus_bool_t
01070 dbus_server_allocate_data_slot (dbus_int32_t *slot_p)
01071 {
01072   return _dbus_data_slot_allocator_alloc (&slot_allocator,
01073                                           (DBusMutex **)&_DBUS_LOCK_NAME (server_slots),
01074                                           slot_p);
01075 }
01076 
01088 void
01089 dbus_server_free_data_slot (dbus_int32_t *slot_p)
01090 {
01091   _dbus_return_if_fail (*slot_p >= 0);
01092   
01093   _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
01094 }
01095 
01109 dbus_bool_t
01110 dbus_server_set_data (DBusServer       *server,
01111                       int               slot,
01112                       void             *data,
01113                       DBusFreeFunction  free_data_func)
01114 {
01115   DBusFreeFunction old_free_func;
01116   void *old_data;
01117   dbus_bool_t retval;
01118 
01119   _dbus_return_val_if_fail (server != NULL, FALSE);
01120 
01121   SERVER_LOCK (server);
01122   
01123   retval = _dbus_data_slot_list_set (&slot_allocator,
01124                                      &server->slot_list,
01125                                      slot, data, free_data_func,
01126                                      &old_free_func, &old_data);
01127 
01128 
01129   SERVER_UNLOCK (server);
01130   
01131   if (retval)
01132     {
01133       /* Do the actual free outside the server lock */
01134       if (old_free_func)
01135         (* old_free_func) (old_data);
01136     }
01137 
01138   return retval;
01139 }
01140 
01149 void*
01150 dbus_server_get_data (DBusServer   *server,
01151                       int           slot)
01152 {
01153   void *res;
01154 
01155   _dbus_return_val_if_fail (server != NULL, NULL);
01156   
01157   SERVER_LOCK (server);
01158   
01159   res = _dbus_data_slot_list_get (&slot_allocator,
01160                                   &server->slot_list,
01161                                   slot);
01162 
01163   SERVER_UNLOCK (server);
01164   
01165   return res;
01166 }
01167 
01170 #ifdef DBUS_BUILD_TESTS
01171 #include "dbus-test.h"
01172 #include <string.h>
01173 
01174 dbus_bool_t
01175 _dbus_server_test (void)
01176 {
01177   const char *valid_addresses[] = {
01178     "tcp:port=1234",
01179     "tcp:host=localhost,port=1234",
01180     "tcp:host=localhost,port=1234;tcp:port=5678",
01181 #ifdef DBUS_UNIX
01182     "unix:path=./boogie",
01183     "tcp:port=1234;unix:path=./boogie",
01184 #endif
01185   };
01186 
01187   DBusServer *server;
01188   int i;
01189   
01190   for (i = 0; i < _DBUS_N_ELEMENTS (valid_addresses); i++)
01191     {
01192       DBusError error = DBUS_ERROR_INIT;
01193       char *address;
01194       char *id;
01195 
01196       server = dbus_server_listen (valid_addresses[i], &error);
01197       if (server == NULL)
01198         {
01199           _dbus_warn ("server listen error: %s: %s\n", error.name, error.message);
01200           dbus_error_free (&error);
01201           _dbus_assert_not_reached ("Failed to listen for valid address.");
01202         }
01203 
01204       id = dbus_server_get_id (server);
01205       _dbus_assert (id != NULL);
01206       address = dbus_server_get_address (server);
01207       _dbus_assert (address != NULL);
01208 
01209       if (strstr (address, id) == NULL)
01210         {
01211           _dbus_warn ("server id '%s' is not in the server address '%s'\n",
01212                       id, address);
01213           _dbus_assert_not_reached ("bad server id or address");
01214         }
01215 
01216       dbus_free (id);
01217       dbus_free (address);
01218       
01219       dbus_server_disconnect (server);
01220       dbus_server_unref (server);
01221     }
01222 
01223   return TRUE;
01224 }
01225 
01226 #endif /* DBUS_BUILD_TESTS */