D-Bus  1.8.20
dbus-server.c
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 /* dbus-server.c DBusServer object
00003  *
00004  * Copyright (C) 2002, 2003, 2004, 2005 Red Hat Inc.
00005  *
00006  * Licensed under the Academic Free License version 2.1
00007  * 
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  * 
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00021  *
00022  */ 
00023 
00024 #include <config.h>
00025 #include "dbus-server.h"
00026 #include "dbus-server-unix.h"
00027 #include "dbus-server-socket.h"
00028 #include "dbus-string.h"
00029 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00030 #include "dbus-server-debug-pipe.h"
00031 #endif
00032 #include "dbus-address.h"
00033 #include "dbus-protocol.h"
00034 
00056 #ifndef _dbus_server_trace_ref
00057 void
00058 _dbus_server_trace_ref (DBusServer *server,
00059     int old_refcount,
00060     int new_refcount,
00061     const char *why)
00062 {
00063   static int enabled = -1;
00064 
00065   _dbus_trace_ref ("DBusServer", server, old_refcount, new_refcount, why,
00066       "DBUS_SERVER_TRACE", &enabled);
00067 }
00068 #endif
00069 
00070 /* this is a little fragile since it assumes the address doesn't
00071  * already have a guid, but it shouldn't
00072  */
00073 static char*
00074 copy_address_with_guid_appended (const DBusString *address,
00075                                  const DBusString *guid_hex)
00076 {
00077   DBusString with_guid;
00078   char *retval;
00079   
00080   if (!_dbus_string_init (&with_guid))
00081     return NULL;
00082 
00083   if (!_dbus_string_copy (address, 0, &with_guid,
00084                           _dbus_string_get_length (&with_guid)) ||
00085       !_dbus_string_append (&with_guid, ",guid=") ||
00086       !_dbus_string_copy (guid_hex, 0,
00087                           &with_guid, _dbus_string_get_length (&with_guid)))
00088     {
00089       _dbus_string_free (&with_guid);
00090       return NULL;
00091     }
00092 
00093   retval = NULL;
00094   _dbus_string_steal_data (&with_guid, &retval);
00095 
00096   _dbus_string_free (&with_guid);
00097       
00098   return retval; /* may be NULL if steal_data failed */
00099 }
00100 
00110 dbus_bool_t
00111 _dbus_server_init_base (DBusServer             *server,
00112                         const DBusServerVTable *vtable,
00113                         const DBusString       *address)
00114 {
00115   server->vtable = vtable;
00116 
00117 #ifdef DBUS_DISABLE_ASSERT
00118   _dbus_atomic_inc (&server->refcount);
00119 #else
00120     {
00121       dbus_int32_t old_refcount = _dbus_atomic_inc (&server->refcount);
00122 
00123       _dbus_assert (old_refcount == 0);
00124     }
00125 #endif
00126 
00127   server->address = NULL;
00128   server->watches = NULL;
00129   server->timeouts = NULL;
00130   server->published_address = FALSE;
00131 
00132   if (!_dbus_string_init (&server->guid_hex))
00133     return FALSE;
00134 
00135   _dbus_generate_uuid (&server->guid);
00136 
00137   if (!_dbus_uuid_encode (&server->guid, &server->guid_hex))
00138     goto failed;
00139   
00140   server->address = copy_address_with_guid_appended (address,
00141                                                      &server->guid_hex);
00142   if (server->address == NULL)
00143     goto failed;
00144   
00145   _dbus_rmutex_new_at_location (&server->mutex);
00146   if (server->mutex == NULL)
00147     goto failed;
00148   
00149   server->watches = _dbus_watch_list_new ();
00150   if (server->watches == NULL)
00151     goto failed;
00152 
00153   server->timeouts = _dbus_timeout_list_new ();
00154   if (server->timeouts == NULL)
00155     goto failed;
00156 
00157   _dbus_data_slot_list_init (&server->slot_list);
00158 
00159   _dbus_verbose ("Initialized server on address %s\n", server->address);
00160   
00161   return TRUE;
00162 
00163  failed:
00164   _dbus_rmutex_free_at_location (&server->mutex);
00165   server->mutex = NULL;
00166   if (server->watches)
00167     {
00168       _dbus_watch_list_free (server->watches);
00169       server->watches = NULL;
00170     }
00171   if (server->timeouts)
00172     {
00173       _dbus_timeout_list_free (server->timeouts);
00174       server->timeouts = NULL;
00175     }
00176   if (server->address)
00177     {
00178       dbus_free (server->address);
00179       server->address = NULL;
00180     }
00181   _dbus_string_free (&server->guid_hex);
00182   
00183   return FALSE;
00184 }
00185 
00192 void
00193 _dbus_server_finalize_base (DBusServer *server)
00194 {
00195   /* We don't have the lock, but nobody should be accessing
00196    * concurrently since they don't have a ref
00197    */
00198 #ifndef DBUS_DISABLE_CHECKS
00199   _dbus_assert (!server->have_server_lock);
00200 #endif
00201   _dbus_assert (server->disconnected);
00202   
00203   /* calls out to application code... */
00204   _dbus_data_slot_list_free (&server->slot_list);
00205 
00206   dbus_server_set_new_connection_function (server, NULL, NULL, NULL);
00207 
00208   _dbus_watch_list_free (server->watches);
00209   _dbus_timeout_list_free (server->timeouts);
00210 
00211   _dbus_rmutex_free_at_location (&server->mutex);
00212   
00213   dbus_free (server->address);
00214 
00215   dbus_free_string_array (server->auth_mechanisms);
00216 
00217   _dbus_string_free (&server->guid_hex);
00218 }
00219 
00220 
00222 typedef dbus_bool_t (* DBusWatchAddFunction)     (DBusWatchList *list,
00223                                                   DBusWatch     *watch);
00225 typedef void        (* DBusWatchRemoveFunction)  (DBusWatchList *list,
00226                                                   DBusWatch     *watch);
00228 typedef void        (* DBusWatchToggleFunction)  (DBusWatchList *list,
00229                                                   DBusWatch     *watch,
00230                                                   dbus_bool_t    enabled);
00231 
00232 static dbus_bool_t
00233 protected_change_watch (DBusServer             *server,
00234                         DBusWatch              *watch,
00235                         DBusWatchAddFunction    add_function,
00236                         DBusWatchRemoveFunction remove_function,
00237                         DBusWatchToggleFunction toggle_function,
00238                         dbus_bool_t             enabled)
00239 {
00240   DBusWatchList *watches;
00241   dbus_bool_t retval;
00242   
00243   HAVE_LOCK_CHECK (server);
00244 
00245   /* This isn't really safe or reasonable; a better pattern is the "do
00246    * everything, then drop lock and call out" one; but it has to be
00247    * propagated up through all callers
00248    */
00249   
00250   watches = server->watches;
00251   if (watches)
00252     {
00253       server->watches = NULL;
00254       _dbus_server_ref_unlocked (server);
00255       SERVER_UNLOCK (server);
00256 
00257       if (add_function)
00258         retval = (* add_function) (watches, watch);
00259       else if (remove_function)
00260         {
00261           retval = TRUE;
00262           (* remove_function) (watches, watch);
00263         }
00264       else
00265         {
00266           retval = TRUE;
00267           (* toggle_function) (watches, watch, enabled);
00268         }
00269       
00270       SERVER_LOCK (server);
00271       server->watches = watches;
00272       _dbus_server_unref_unlocked (server);
00273 
00274       return retval;
00275     }
00276   else
00277     return FALSE;
00278 }
00279 
00287 dbus_bool_t
00288 _dbus_server_add_watch (DBusServer *server,
00289                         DBusWatch  *watch)
00290 {
00291   HAVE_LOCK_CHECK (server);
00292   return protected_change_watch (server, watch,
00293                                  _dbus_watch_list_add_watch,
00294                                  NULL, NULL, FALSE);
00295 }
00296 
00303 void
00304 _dbus_server_remove_watch  (DBusServer *server,
00305                             DBusWatch  *watch)
00306 {
00307   HAVE_LOCK_CHECK (server);
00308   protected_change_watch (server, watch,
00309                           NULL,
00310                           _dbus_watch_list_remove_watch,
00311                           NULL, FALSE);
00312 }
00313 
00321 void
00322 _dbus_server_toggle_all_watches (DBusServer  *server,
00323                                 dbus_bool_t  enabled)
00324 {
00325   _dbus_watch_list_toggle_all_watches (server->watches, enabled);
00326 }
00327 
00329 typedef dbus_bool_t (* DBusTimeoutAddFunction)    (DBusTimeoutList *list,
00330                                                    DBusTimeout     *timeout);
00332 typedef void        (* DBusTimeoutRemoveFunction) (DBusTimeoutList *list,
00333                                                    DBusTimeout     *timeout);
00335 typedef void        (* DBusTimeoutToggleFunction) (DBusTimeoutList *list,
00336                                                    DBusTimeout     *timeout,
00337                                                    dbus_bool_t      enabled);
00338 
00339 
00340 static dbus_bool_t
00341 protected_change_timeout (DBusServer               *server,
00342                           DBusTimeout              *timeout,
00343                           DBusTimeoutAddFunction    add_function,
00344                           DBusTimeoutRemoveFunction remove_function,
00345                           DBusTimeoutToggleFunction toggle_function,
00346                           dbus_bool_t               enabled)
00347 {
00348   DBusTimeoutList *timeouts;
00349   dbus_bool_t retval;
00350   
00351   HAVE_LOCK_CHECK (server);
00352 
00353   /* This isn't really safe or reasonable; a better pattern is the "do everything, then
00354    * drop lock and call out" one; but it has to be propagated up through all callers
00355    */
00356   
00357   timeouts = server->timeouts;
00358   if (timeouts)
00359     {
00360       server->timeouts = NULL;
00361       _dbus_server_ref_unlocked (server);
00362       SERVER_UNLOCK (server);
00363 
00364       if (add_function)
00365         retval = (* add_function) (timeouts, timeout);
00366       else if (remove_function)
00367         {
00368           retval = TRUE;
00369           (* remove_function) (timeouts, timeout);
00370         }
00371       else
00372         {
00373           retval = TRUE;
00374           (* toggle_function) (timeouts, timeout, enabled);
00375         }
00376       
00377       SERVER_LOCK (server);
00378       server->timeouts = timeouts;
00379       _dbus_server_unref_unlocked (server);
00380 
00381       return retval;
00382     }
00383   else
00384     return FALSE;
00385 }
00386 
00396 dbus_bool_t
00397 _dbus_server_add_timeout (DBusServer  *server,
00398                           DBusTimeout *timeout)
00399 {
00400   return protected_change_timeout (server, timeout,
00401                                    _dbus_timeout_list_add_timeout,
00402                                    NULL, NULL, FALSE);
00403 }
00404 
00411 void
00412 _dbus_server_remove_timeout (DBusServer  *server,
00413                              DBusTimeout *timeout)
00414 {
00415   protected_change_timeout (server, timeout,
00416                             NULL,
00417                             _dbus_timeout_list_remove_timeout,
00418                             NULL, FALSE);
00419 }
00420 
00430 void
00431 _dbus_server_toggle_timeout (DBusServer  *server,
00432                              DBusTimeout *timeout,
00433                              dbus_bool_t  enabled)
00434 {
00435   protected_change_timeout (server, timeout,
00436                             NULL, NULL,
00437                             _dbus_timeout_list_toggle_timeout,
00438                             enabled);
00439 }
00440 
00441 
00447 void
00448 _dbus_server_ref_unlocked (DBusServer *server)
00449 {
00450   dbus_int32_t old_refcount;
00451 
00452   _dbus_assert (server != NULL);
00453   HAVE_LOCK_CHECK (server);
00454 
00455   old_refcount = _dbus_atomic_inc (&server->refcount);
00456   _dbus_assert (old_refcount > 0);
00457   _dbus_server_trace_ref (server, old_refcount, old_refcount + 1,
00458       "ref_unlocked");
00459 }
00460 
00466 void
00467 _dbus_server_unref_unlocked (DBusServer *server)
00468 {
00469   dbus_int32_t old_refcount;
00470 
00471   /* Keep this in sync with dbus_server_unref */
00472 
00473   _dbus_assert (server != NULL);
00474 
00475   HAVE_LOCK_CHECK (server);
00476 
00477   old_refcount = _dbus_atomic_dec (&server->refcount);
00478   _dbus_assert (old_refcount > 0);
00479 
00480   _dbus_server_trace_ref (server, old_refcount, old_refcount - 1,
00481       "unref_unlocked");
00482 
00483   if (old_refcount == 1)
00484     {
00485       _dbus_assert (server->disconnected);
00486       
00487       SERVER_UNLOCK (server);
00488       
00489       _dbus_assert (server->vtable->finalize != NULL);
00490       
00491       (* server->vtable->finalize) (server);
00492     }
00493 }
00494 
00516 static const struct {
00517   DBusServerListenResult (* func) (DBusAddressEntry *entry,
00518                                    DBusServer      **server_p,
00519                                    DBusError        *error);
00520 } listen_funcs[] = {
00521   { _dbus_server_listen_socket }
00522   , { _dbus_server_listen_platform_specific }
00523 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
00524   , { _dbus_server_listen_debug_pipe }
00525 #endif
00526 };
00527 
00548 DBusServer*
00549 dbus_server_listen (const char     *address,
00550                     DBusError      *error)
00551 {
00552   DBusServer *server;
00553   DBusAddressEntry **entries;
00554   int len, i;
00555   DBusError first_connect_error = DBUS_ERROR_INIT;
00556   dbus_bool_t handled_once;
00557   
00558   _dbus_return_val_if_fail (address != NULL, NULL);
00559   _dbus_return_val_if_error_is_set (error, NULL);
00560   
00561   if (!dbus_parse_address (address, &entries, &len, error))
00562     return NULL;
00563 
00564   server = NULL;
00565   handled_once = FALSE;
00566 
00567   for (i = 0; i < len; i++)
00568     {
00569       int j;
00570 
00571       for (j = 0; j < (int) _DBUS_N_ELEMENTS (listen_funcs); ++j)
00572         {
00573           DBusServerListenResult result;
00574           DBusError tmp_error = DBUS_ERROR_INIT;
00575 
00576           result = (* listen_funcs[j].func) (entries[i],
00577                                              &server,
00578                                              &tmp_error);
00579 
00580           if (result == DBUS_SERVER_LISTEN_OK)
00581             {
00582               _dbus_assert (server != NULL);
00583               _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
00584               handled_once = TRUE;
00585               goto out;
00586             }
00587           else if (result == DBUS_SERVER_LISTEN_ADDRESS_ALREADY_USED)
00588             {
00589               _dbus_assert (server == NULL);
00590               dbus_set_error (error,
00591                        DBUS_ERROR_ADDRESS_IN_USE,
00592                        "Address '%s' already used",
00593                        dbus_address_entry_get_method (entries[0]));
00594               handled_once = TRUE;
00595               goto out;
00596             }
00597           else if (result == DBUS_SERVER_LISTEN_BAD_ADDRESS)
00598             {
00599               _dbus_assert (server == NULL);
00600               _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
00601               dbus_move_error (&tmp_error, error);
00602               handled_once = TRUE;
00603               goto out;
00604             }
00605           else if (result == DBUS_SERVER_LISTEN_NOT_HANDLED)
00606             {
00607               _dbus_assert (server == NULL);
00608               _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
00609 
00610               /* keep trying addresses */
00611             }
00612           else if (result == DBUS_SERVER_LISTEN_DID_NOT_CONNECT)
00613             {
00614               _dbus_assert (server == NULL);
00615               _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
00616               if (!dbus_error_is_set (&first_connect_error))
00617                 dbus_move_error (&tmp_error, &first_connect_error);
00618               else
00619                 dbus_error_free (&tmp_error);
00620 
00621               handled_once = TRUE;
00622               
00623               /* keep trying addresses */
00624             }
00625         }
00626 
00627       _dbus_assert (server == NULL);
00628       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00629     }
00630 
00631  out:
00632 
00633   if (!handled_once)
00634     {
00635       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00636       if (len > 0)
00637         dbus_set_error (error,
00638                        DBUS_ERROR_BAD_ADDRESS,
00639                        "Unknown address type '%s'",
00640                        dbus_address_entry_get_method (entries[0]));
00641       else
00642         dbus_set_error (error,
00643                         DBUS_ERROR_BAD_ADDRESS,
00644                         "Empty address '%s'",
00645                         address);
00646     }
00647   
00648   dbus_address_entries_free (entries);
00649 
00650   if (server == NULL)
00651     {
00652       _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error) ||
00653                    dbus_error_is_set (error));
00654       
00655       if (error && dbus_error_is_set (error))
00656         {
00657           /* already set the error */
00658         }
00659       else
00660         {
00661           /* didn't set the error but either error should be
00662            * NULL or first_connect_error should be set.
00663            */
00664           _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error));
00665           dbus_move_error (&first_connect_error, error);
00666         }
00667 
00668       _DBUS_ASSERT_ERROR_IS_CLEAR (&first_connect_error); /* be sure we freed it */
00669       _DBUS_ASSERT_ERROR_IS_SET (error);
00670 
00671       return NULL;
00672     }
00673   else
00674     {
00675       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00676       return server;
00677     }
00678 }
00679 
00686 DBusServer *
00687 dbus_server_ref (DBusServer *server)
00688 {
00689   dbus_int32_t old_refcount;
00690 
00691   _dbus_return_val_if_fail (server != NULL, NULL);
00692 
00693   old_refcount = _dbus_atomic_inc (&server->refcount);
00694 
00695 #ifndef DBUS_DISABLE_CHECKS
00696   if (_DBUS_UNLIKELY (old_refcount <= 0))
00697     {
00698       _dbus_atomic_dec (&server->refcount);
00699       _dbus_warn_check_failed (_dbus_return_if_fail_warning_format,
00700                                _DBUS_FUNCTION_NAME, "old_refcount > 0",
00701                                __FILE__, __LINE__);
00702       return NULL;
00703     }
00704 #endif
00705 
00706   _dbus_server_trace_ref (server, old_refcount, old_refcount + 1, "ref");
00707 
00708   return server;
00709 }
00710 
00719 void
00720 dbus_server_unref (DBusServer *server)
00721 {
00722   dbus_int32_t old_refcount;
00723 
00724   /* keep this in sync with unref_unlocked */
00725 
00726   _dbus_return_if_fail (server != NULL);
00727 
00728   old_refcount = _dbus_atomic_dec (&server->refcount);
00729 
00730 #ifndef DBUS_DISABLE_CHECKS
00731   if (_DBUS_UNLIKELY (old_refcount <= 0))
00732     {
00733       /* undo side-effect first
00734        * please do not try to simplify the code here by using
00735        * _dbus_atomic_get(), why we don't use it is
00736        * because it issues another atomic operation even though
00737        * DBUS_DISABLE_CHECKS defined.
00738        * Bug: https://bugs.freedesktop.org/show_bug.cgi?id=68303
00739        */
00740       _dbus_atomic_inc (&server->refcount);
00741       _dbus_warn_check_failed (_dbus_return_if_fail_warning_format,
00742                                _DBUS_FUNCTION_NAME, "old_refcount > 0",
00743                                __FILE__, __LINE__);
00744       return;
00745     }
00746 #endif
00747 
00748   _dbus_server_trace_ref (server, old_refcount, old_refcount - 1, "unref");
00749 
00750   if (old_refcount == 1)
00751     {
00752       /* lock not held! */
00753       _dbus_assert (server->disconnected);
00754       
00755       _dbus_assert (server->vtable->finalize != NULL);
00756       
00757       (* server->vtable->finalize) (server);
00758     }
00759 }
00760 
00769 void
00770 dbus_server_disconnect (DBusServer *server)
00771 {
00772   _dbus_return_if_fail (server != NULL);
00773 
00774   dbus_server_ref (server);
00775   SERVER_LOCK (server);
00776 
00777   _dbus_assert (server->vtable->disconnect != NULL);
00778 
00779   if (!server->disconnected)
00780     {
00781       /* this has to be first so recursive calls to disconnect don't happen */
00782       server->disconnected = TRUE;
00783       
00784       (* server->vtable->disconnect) (server);
00785     }
00786 
00787   SERVER_UNLOCK (server);
00788   dbus_server_unref (server);
00789 }
00790 
00796 dbus_bool_t
00797 dbus_server_get_is_connected (DBusServer *server)
00798 {
00799   dbus_bool_t retval;
00800   
00801   _dbus_return_val_if_fail (server != NULL, FALSE);
00802 
00803   SERVER_LOCK (server);
00804   retval = !server->disconnected;
00805   SERVER_UNLOCK (server);
00806 
00807   return retval;
00808 }
00809 
00817 char*
00818 dbus_server_get_address (DBusServer *server)
00819 {
00820   char *retval;
00821   
00822   _dbus_return_val_if_fail (server != NULL, NULL);
00823 
00824   SERVER_LOCK (server);
00825   retval = _dbus_strdup (server->address);
00826   SERVER_UNLOCK (server);
00827 
00828   return retval;
00829 }
00830 
00853 char*
00854 dbus_server_get_id (DBusServer *server)
00855 {
00856   char *retval;
00857   
00858   _dbus_return_val_if_fail (server != NULL, NULL);
00859 
00860   SERVER_LOCK (server);
00861   retval = NULL;
00862   _dbus_string_copy_data (&server->guid_hex, &retval);
00863   SERVER_UNLOCK (server);
00864 
00865   return retval;
00866 }
00867 
00888 void
00889 dbus_server_set_new_connection_function (DBusServer                *server,
00890                                          DBusNewConnectionFunction  function,
00891                                          void                      *data,
00892                                          DBusFreeFunction           free_data_function)
00893 {
00894   DBusFreeFunction old_free_function;
00895   void *old_data;
00896   
00897   _dbus_return_if_fail (server != NULL);
00898 
00899   SERVER_LOCK (server);
00900   old_free_function = server->new_connection_free_data_function;
00901   old_data = server->new_connection_data;
00902   
00903   server->new_connection_function = function;
00904   server->new_connection_data = data;
00905   server->new_connection_free_data_function = free_data_function;
00906   SERVER_UNLOCK (server);
00907     
00908   if (old_free_function != NULL)
00909     (* old_free_function) (old_data);
00910 }
00911 
00928 dbus_bool_t
00929 dbus_server_set_watch_functions (DBusServer              *server,
00930                                  DBusAddWatchFunction     add_function,
00931                                  DBusRemoveWatchFunction  remove_function,
00932                                  DBusWatchToggledFunction toggled_function,
00933                                  void                    *data,
00934                                  DBusFreeFunction         free_data_function)
00935 {
00936   dbus_bool_t result;
00937   DBusWatchList *watches;
00938   
00939   _dbus_return_val_if_fail (server != NULL, FALSE);
00940 
00941   SERVER_LOCK (server);
00942   watches = server->watches;
00943   server->watches = NULL;
00944   if (watches)
00945     {
00946       SERVER_UNLOCK (server);
00947       result = _dbus_watch_list_set_functions (watches,
00948                                                add_function,
00949                                                remove_function,
00950                                                toggled_function,
00951                                                data,
00952                                                free_data_function);
00953       SERVER_LOCK (server);
00954     }
00955   else
00956     {
00957       _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
00958       result = FALSE;
00959     }
00960   server->watches = watches;
00961   SERVER_UNLOCK (server);
00962   
00963   return result;
00964 }
00965 
00981 dbus_bool_t
00982 dbus_server_set_timeout_functions (DBusServer                *server,
00983                                    DBusAddTimeoutFunction     add_function,
00984                                    DBusRemoveTimeoutFunction  remove_function,
00985                                    DBusTimeoutToggledFunction toggled_function,
00986                                    void                      *data,
00987                                    DBusFreeFunction           free_data_function)
00988 {
00989   dbus_bool_t result;
00990   DBusTimeoutList *timeouts;
00991   
00992   _dbus_return_val_if_fail (server != NULL, FALSE);
00993 
00994   SERVER_LOCK (server);
00995   timeouts = server->timeouts;
00996   server->timeouts = NULL;
00997   if (timeouts)
00998     {
00999       SERVER_UNLOCK (server);
01000       result = _dbus_timeout_list_set_functions (timeouts,
01001                                                  add_function,
01002                                                  remove_function,
01003                                                  toggled_function,
01004                                                  data,
01005                                                  free_data_function);
01006       SERVER_LOCK (server);
01007     }
01008   else
01009     {
01010       _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
01011       result = FALSE;
01012     }
01013   server->timeouts = timeouts;
01014   SERVER_UNLOCK (server);
01015   
01016   return result;
01017 }
01018 
01032 dbus_bool_t
01033 dbus_server_set_auth_mechanisms (DBusServer  *server,
01034                                  const char **mechanisms)
01035 {
01036   char **copy;
01037 
01038   _dbus_return_val_if_fail (server != NULL, FALSE);
01039 
01040   SERVER_LOCK (server);
01041   
01042   if (mechanisms != NULL)
01043     {
01044       copy = _dbus_dup_string_array (mechanisms);
01045       if (copy == NULL)
01046         {
01047           SERVER_UNLOCK (server);
01048           return FALSE;
01049         }
01050     }
01051   else
01052     copy = NULL;
01053 
01054   dbus_free_string_array (server->auth_mechanisms);
01055   server->auth_mechanisms = copy;
01056 
01057   SERVER_UNLOCK (server);
01058   
01059   return TRUE;
01060 }
01061 
01062 static DBusDataSlotAllocator slot_allocator =
01063   _DBUS_DATA_SLOT_ALLOCATOR_INIT (_DBUS_LOCK_NAME (server_slots));
01064 
01079 dbus_bool_t
01080 dbus_server_allocate_data_slot (dbus_int32_t *slot_p)
01081 {
01082   return _dbus_data_slot_allocator_alloc (&slot_allocator,
01083                                           slot_p);
01084 }
01085 
01097 void
01098 dbus_server_free_data_slot (dbus_int32_t *slot_p)
01099 {
01100   _dbus_return_if_fail (*slot_p >= 0);
01101   
01102   _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
01103 }
01104 
01118 dbus_bool_t
01119 dbus_server_set_data (DBusServer       *server,
01120                       int               slot,
01121                       void             *data,
01122                       DBusFreeFunction  free_data_func)
01123 {
01124   DBusFreeFunction old_free_func;
01125   void *old_data;
01126   dbus_bool_t retval;
01127 
01128   _dbus_return_val_if_fail (server != NULL, FALSE);
01129 
01130   SERVER_LOCK (server);
01131   
01132   retval = _dbus_data_slot_list_set (&slot_allocator,
01133                                      &server->slot_list,
01134                                      slot, data, free_data_func,
01135                                      &old_free_func, &old_data);
01136 
01137 
01138   SERVER_UNLOCK (server);
01139   
01140   if (retval)
01141     {
01142       /* Do the actual free outside the server lock */
01143       if (old_free_func)
01144         (* old_free_func) (old_data);
01145     }
01146 
01147   return retval;
01148 }
01149 
01158 void*
01159 dbus_server_get_data (DBusServer   *server,
01160                       int           slot)
01161 {
01162   void *res;
01163 
01164   _dbus_return_val_if_fail (server != NULL, NULL);
01165   
01166   SERVER_LOCK (server);
01167   
01168   res = _dbus_data_slot_list_get (&slot_allocator,
01169                                   &server->slot_list,
01170                                   slot);
01171 
01172   SERVER_UNLOCK (server);
01173   
01174   return res;
01175 }
01176 
01179 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
01180 #include "dbus-test.h"
01181 #include <string.h>
01182 
01183 dbus_bool_t
01184 _dbus_server_test (void)
01185 {
01186   const char *valid_addresses[] = {
01187     "tcp:port=1234",
01188     "tcp:host=localhost,port=1234",
01189     "tcp:host=localhost,port=1234;tcp:port=5678",
01190 #ifdef DBUS_UNIX
01191     "unix:path=./boogie",
01192     "tcp:port=1234;unix:path=./boogie",
01193 #endif
01194   };
01195 
01196   DBusServer *server;
01197   int i;
01198   
01199   for (i = 0; i < _DBUS_N_ELEMENTS (valid_addresses); i++)
01200     {
01201       DBusError error = DBUS_ERROR_INIT;
01202       char *address;
01203       char *id;
01204 
01205       server = dbus_server_listen (valid_addresses[i], &error);
01206       if (server == NULL)
01207         {
01208           _dbus_warn ("server listen error: %s: %s\n", error.name, error.message);
01209           dbus_error_free (&error);
01210           _dbus_assert_not_reached ("Failed to listen for valid address.");
01211         }
01212 
01213       id = dbus_server_get_id (server);
01214       _dbus_assert (id != NULL);
01215       address = dbus_server_get_address (server);
01216       _dbus_assert (address != NULL);
01217 
01218       if (strstr (address, id) == NULL)
01219         {
01220           _dbus_warn ("server id '%s' is not in the server address '%s'\n",
01221                       id, address);
01222           _dbus_assert_not_reached ("bad server id or address");
01223         }
01224 
01225       dbus_free (id);
01226       dbus_free (address);
01227       
01228       dbus_server_disconnect (server);
01229       dbus_server_unref (server);
01230     }
01231 
01232   return TRUE;
01233 }
01234 
01235 #endif /* DBUS_ENABLE_EMBEDDED_TESTS */