dbus-server.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */ 
00023 
00024 #include "dbus-server.h"
00025 #include "dbus-server-unix.h"
00026 #include "dbus-server-socket.h"
00027 #include "dbus-string.h"
00028 #ifdef DBUS_BUILD_TESTS
00029 #include "dbus-server-debug-pipe.h"
00030 #endif
00031 #include "dbus-address.h"
00032 #include "dbus-protocol.h"
00033 
00055 /* this is a little fragile since it assumes the address doesn't
00056  * already have a guid, but it shouldn't
00057  */
00058 static char*
00059 copy_address_with_guid_appended (const DBusString *address,
00060                                  const DBusString *guid_hex)
00061 {
00062   DBusString with_guid;
00063   char *retval;
00064   
00065   if (!_dbus_string_init (&with_guid))
00066     return NULL;
00067 
00068   if (!_dbus_string_copy (address, 0, &with_guid,
00069                           _dbus_string_get_length (&with_guid)) ||
00070       !_dbus_string_append (&with_guid, ",guid=") ||
00071       !_dbus_string_copy (guid_hex, 0,
00072                           &with_guid, _dbus_string_get_length (&with_guid)))
00073     {
00074       _dbus_string_free (&with_guid);
00075       return NULL;
00076     }
00077 
00078   retval = NULL;
00079   _dbus_string_steal_data (&with_guid, &retval);
00080 
00081   _dbus_string_free (&with_guid);
00082       
00083   return retval; /* may be NULL if steal_data failed */
00084 }
00085 
00095 dbus_bool_t
00096 _dbus_server_init_base (DBusServer             *server,
00097                         const DBusServerVTable *vtable,
00098                         const DBusString       *address)
00099 {
00100   server->vtable = vtable;
00101   server->refcount.value = 1;
00102 
00103   server->address = NULL;
00104   server->watches = NULL;
00105   server->timeouts = NULL;
00106 
00107   if (!_dbus_string_init (&server->guid_hex))
00108     return FALSE;
00109 
00110   _dbus_generate_uuid (&server->guid);
00111 
00112   if (!_dbus_uuid_encode (&server->guid, &server->guid_hex))
00113     goto failed;
00114   
00115   server->address = copy_address_with_guid_appended (address,
00116                                                      &server->guid_hex);
00117   if (server->address == NULL)
00118     goto failed;
00119   
00120   _dbus_mutex_new_at_location (&server->mutex);
00121   if (server->mutex == NULL)
00122     goto failed;
00123   
00124   server->watches = _dbus_watch_list_new ();
00125   if (server->watches == NULL)
00126     goto failed;
00127 
00128   server->timeouts = _dbus_timeout_list_new ();
00129   if (server->timeouts == NULL)
00130     goto failed;
00131 
00132   _dbus_data_slot_list_init (&server->slot_list);
00133 
00134   _dbus_verbose ("Initialized server on address %s\n", server->address);
00135   
00136   return TRUE;
00137 
00138  failed:
00139   _dbus_mutex_free_at_location (&server->mutex);
00140   server->mutex = NULL;
00141   if (server->watches)
00142     {
00143       _dbus_watch_list_free (server->watches);
00144       server->watches = NULL;
00145     }
00146   if (server->timeouts)
00147     {
00148       _dbus_timeout_list_free (server->timeouts);
00149       server->timeouts = NULL;
00150     }
00151   if (server->address)
00152     {
00153       dbus_free (server->address);
00154       server->address = NULL;
00155     }
00156   _dbus_string_free (&server->guid_hex);
00157   
00158   return FALSE;
00159 }
00160 
00167 void
00168 _dbus_server_finalize_base (DBusServer *server)
00169 {
00170   /* We don't have the lock, but nobody should be accessing
00171    * concurrently since they don't have a ref
00172    */
00173 #ifndef DBUS_DISABLE_CHECKS
00174   _dbus_assert (!server->have_server_lock);
00175 #endif
00176   _dbus_assert (server->disconnected);
00177   
00178   /* calls out to application code... */
00179   _dbus_data_slot_list_free (&server->slot_list);
00180 
00181   dbus_server_set_new_connection_function (server, NULL, NULL, NULL);
00182 
00183   _dbus_watch_list_free (server->watches);
00184   _dbus_timeout_list_free (server->timeouts);
00185 
00186   _dbus_mutex_free_at_location (&server->mutex);
00187   
00188   dbus_free (server->address);
00189 
00190   dbus_free_string_array (server->auth_mechanisms);
00191 
00192   _dbus_string_free (&server->guid_hex);
00193 }
00194 
00195 
00197 typedef dbus_bool_t (* DBusWatchAddFunction)     (DBusWatchList *list,
00198                                                   DBusWatch     *watch);
00200 typedef void        (* DBusWatchRemoveFunction)  (DBusWatchList *list,
00201                                                   DBusWatch     *watch);
00203 typedef void        (* DBusWatchToggleFunction)  (DBusWatchList *list,
00204                                                   DBusWatch     *watch,
00205                                                   dbus_bool_t    enabled);
00206 
00207 static dbus_bool_t
00208 protected_change_watch (DBusServer             *server,
00209                         DBusWatch              *watch,
00210                         DBusWatchAddFunction    add_function,
00211                         DBusWatchRemoveFunction remove_function,
00212                         DBusWatchToggleFunction toggle_function,
00213                         dbus_bool_t             enabled)
00214 {
00215   DBusWatchList *watches;
00216   dbus_bool_t retval;
00217   
00218   HAVE_LOCK_CHECK (server);
00219 
00220   /* This isn't really safe or reasonable; a better pattern is the "do
00221    * everything, then drop lock and call out" one; but it has to be
00222    * propagated up through all callers
00223    */
00224   
00225   watches = server->watches;
00226   if (watches)
00227     {
00228       server->watches = NULL;
00229       _dbus_server_ref_unlocked (server);
00230       SERVER_UNLOCK (server);
00231 
00232       if (add_function)
00233         retval = (* add_function) (watches, watch);
00234       else if (remove_function)
00235         {
00236           retval = TRUE;
00237           (* remove_function) (watches, watch);
00238         }
00239       else
00240         {
00241           retval = TRUE;
00242           (* toggle_function) (watches, watch, enabled);
00243         }
00244       
00245       SERVER_LOCK (server);
00246       server->watches = watches;
00247       _dbus_server_unref_unlocked (server);
00248 
00249       return retval;
00250     }
00251   else
00252     return FALSE;
00253 }
00254 
00262 dbus_bool_t
00263 _dbus_server_add_watch (DBusServer *server,
00264                         DBusWatch  *watch)
00265 {
00266   HAVE_LOCK_CHECK (server);
00267   return protected_change_watch (server, watch,
00268                                  _dbus_watch_list_add_watch,
00269                                  NULL, NULL, FALSE);
00270 }
00271 
00278 void
00279 _dbus_server_remove_watch  (DBusServer *server,
00280                             DBusWatch  *watch)
00281 {
00282   HAVE_LOCK_CHECK (server);
00283   protected_change_watch (server, watch,
00284                           NULL,
00285                           _dbus_watch_list_remove_watch,
00286                           NULL, FALSE);
00287 }
00288 
00298 void
00299 _dbus_server_toggle_watch (DBusServer  *server,
00300                            DBusWatch   *watch,
00301                            dbus_bool_t  enabled)
00302 {
00303   _dbus_assert (watch != NULL);
00304 
00305   HAVE_LOCK_CHECK (server);
00306   protected_change_watch (server, watch,
00307                           NULL, NULL,
00308                           _dbus_watch_list_toggle_watch,
00309                           enabled);
00310 }
00311 
00313 typedef dbus_bool_t (* DBusTimeoutAddFunction)    (DBusTimeoutList *list,
00314                                                    DBusTimeout     *timeout);
00316 typedef void        (* DBusTimeoutRemoveFunction) (DBusTimeoutList *list,
00317                                                    DBusTimeout     *timeout);
00319 typedef void        (* DBusTimeoutToggleFunction) (DBusTimeoutList *list,
00320                                                    DBusTimeout     *timeout,
00321                                                    dbus_bool_t      enabled);
00322 
00323 
00324 static dbus_bool_t
00325 protected_change_timeout (DBusServer               *server,
00326                           DBusTimeout              *timeout,
00327                           DBusTimeoutAddFunction    add_function,
00328                           DBusTimeoutRemoveFunction remove_function,
00329                           DBusTimeoutToggleFunction toggle_function,
00330                           dbus_bool_t               enabled)
00331 {
00332   DBusTimeoutList *timeouts;
00333   dbus_bool_t retval;
00334   
00335   HAVE_LOCK_CHECK (server);
00336 
00337   /* This isn't really safe or reasonable; a better pattern is the "do everything, then
00338    * drop lock and call out" one; but it has to be propagated up through all callers
00339    */
00340   
00341   timeouts = server->timeouts;
00342   if (timeouts)
00343     {
00344       server->timeouts = NULL;
00345       _dbus_server_ref_unlocked (server);
00346       SERVER_UNLOCK (server);
00347 
00348       if (add_function)
00349         retval = (* add_function) (timeouts, timeout);
00350       else if (remove_function)
00351         {
00352           retval = TRUE;
00353           (* remove_function) (timeouts, timeout);
00354         }
00355       else
00356         {
00357           retval = TRUE;
00358           (* toggle_function) (timeouts, timeout, enabled);
00359         }
00360       
00361       SERVER_LOCK (server);
00362       server->timeouts = timeouts;
00363       _dbus_server_unref_unlocked (server);
00364 
00365       return retval;
00366     }
00367   else
00368     return FALSE;
00369 }
00370 
00380 dbus_bool_t
00381 _dbus_server_add_timeout (DBusServer  *server,
00382                           DBusTimeout *timeout)
00383 {
00384   return protected_change_timeout (server, timeout,
00385                                    _dbus_timeout_list_add_timeout,
00386                                    NULL, NULL, FALSE);
00387 }
00388 
00395 void
00396 _dbus_server_remove_timeout (DBusServer  *server,
00397                              DBusTimeout *timeout)
00398 {
00399   protected_change_timeout (server, timeout,
00400                             NULL,
00401                             _dbus_timeout_list_remove_timeout,
00402                             NULL, FALSE);
00403 }
00404 
00414 void
00415 _dbus_server_toggle_timeout (DBusServer  *server,
00416                              DBusTimeout *timeout,
00417                              dbus_bool_t  enabled)
00418 {
00419   protected_change_timeout (server, timeout,
00420                             NULL, NULL,
00421                             _dbus_timeout_list_toggle_timeout,
00422                             enabled);
00423 }
00424 
00425 
00431 void
00432 _dbus_server_ref_unlocked (DBusServer *server)
00433 {
00434   _dbus_assert (server != NULL);
00435   _dbus_assert (server->refcount.value > 0);
00436   
00437   HAVE_LOCK_CHECK (server);
00438 
00439 #ifdef DBUS_HAVE_ATOMIC_INT
00440   _dbus_atomic_inc (&server->refcount);
00441 #else
00442   _dbus_assert (server->refcount.value > 0);
00443 
00444   server->refcount.value += 1;
00445 #endif
00446 }
00447 
00453 void
00454 _dbus_server_unref_unlocked (DBusServer *server)
00455 {
00456   dbus_bool_t last_unref;
00457 
00458   /* Keep this in sync with dbus_server_unref */
00459   
00460   _dbus_assert (server != NULL);
00461   _dbus_assert (server->refcount.value > 0);
00462 
00463   HAVE_LOCK_CHECK (server);
00464   
00465 #ifdef DBUS_HAVE_ATOMIC_INT
00466   last_unref = (_dbus_atomic_dec (&server->refcount) == 1);
00467 #else
00468   _dbus_assert (server->refcount.value > 0);
00469 
00470   server->refcount.value -= 1;
00471   last_unref = (server->refcount.value == 0);
00472 #endif
00473   
00474   if (last_unref)
00475     {
00476       _dbus_assert (server->disconnected);
00477       
00478       SERVER_UNLOCK (server);
00479       
00480       _dbus_assert (server->vtable->finalize != NULL);
00481       
00482       (* server->vtable->finalize) (server);
00483     }
00484 }
00485 
00507 static const struct {
00508   DBusServerListenResult (* func) (DBusAddressEntry *entry,
00509                                    DBusServer      **server_p,
00510                                    DBusError        *error);
00511 } listen_funcs[] = {
00512   { _dbus_server_listen_socket },
00513   { _dbus_server_listen_platform_specific }
00514 #ifdef DBUS_BUILD_TESTS
00515   , { _dbus_server_listen_debug_pipe }
00516 #endif
00517 };
00518 
00539 DBusServer*
00540 dbus_server_listen (const char     *address,
00541                     DBusError      *error)
00542 {
00543   DBusServer *server;
00544   DBusAddressEntry **entries;
00545   int len, i;
00546   DBusError first_connect_error;
00547   dbus_bool_t handled_once;
00548   
00549   _dbus_return_val_if_fail (address != NULL, NULL);
00550   _dbus_return_val_if_error_is_set (error, NULL);
00551   
00552   if (!dbus_parse_address (address, &entries, &len, error))
00553     return NULL;
00554 
00555   server = NULL;
00556   dbus_error_init (&first_connect_error);
00557   handled_once = FALSE;
00558   
00559   for (i = 0; i < len; i++)
00560     {
00561       int j;
00562 
00563       for (j = 0; j < (int) _DBUS_N_ELEMENTS (listen_funcs); ++j)
00564         {
00565           DBusServerListenResult result;
00566           DBusError tmp_error;
00567       
00568           dbus_error_init (&tmp_error);
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_BAD_ADDRESS)
00581             {
00582               _dbus_assert (server == NULL);
00583               _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
00584               dbus_move_error (&tmp_error, error);
00585               handled_once = TRUE;
00586               goto out;
00587             }
00588           else if (result == DBUS_SERVER_LISTEN_NOT_HANDLED)
00589             {
00590               _dbus_assert (server == NULL);
00591               _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
00592 
00593               /* keep trying addresses */
00594             }
00595           else if (result == DBUS_SERVER_LISTEN_DID_NOT_CONNECT)
00596             {
00597               _dbus_assert (server == NULL);
00598               _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
00599               if (!dbus_error_is_set (&first_connect_error))
00600                 dbus_move_error (&tmp_error, &first_connect_error);
00601               else
00602                 dbus_error_free (&tmp_error);
00603 
00604               handled_once = TRUE;
00605               
00606               /* keep trying addresses */
00607             }
00608         }
00609 
00610       _dbus_assert (server == NULL);
00611       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00612     }
00613 
00614  out:
00615 
00616   if (!handled_once)
00617     {
00618       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00619       if (len > 0)
00620         dbus_set_error (error,
00621                        DBUS_ERROR_BAD_ADDRESS,
00622                        "Unknown address type '%s'",
00623                        dbus_address_entry_get_method (entries[0]));
00624       else
00625         dbus_set_error (error,
00626                         DBUS_ERROR_BAD_ADDRESS,
00627                         "Empty address '%s'",
00628                         address);
00629     }
00630   
00631   dbus_address_entries_free (entries);
00632 
00633   if (server == NULL)
00634     {
00635       _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error) ||
00636                    dbus_error_is_set (error));
00637       
00638       if (error && dbus_error_is_set (error))
00639         {
00640           /* already set the error */
00641         }
00642       else
00643         {
00644           /* didn't set the error but either error should be
00645            * NULL or first_connect_error should be set.
00646            */
00647           _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error));
00648           dbus_move_error (&first_connect_error, error);
00649         }
00650 
00651       _DBUS_ASSERT_ERROR_IS_CLEAR (&first_connect_error); /* be sure we freed it */
00652       _DBUS_ASSERT_ERROR_IS_SET (error);
00653 
00654       return NULL;
00655     }
00656   else
00657     {
00658       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00659       return server;
00660     }
00661 }
00662 
00669 DBusServer *
00670 dbus_server_ref (DBusServer *server)
00671 {
00672   _dbus_return_val_if_fail (server != NULL, NULL);
00673   _dbus_return_val_if_fail (server->refcount.value > 0, NULL);
00674 
00675 #ifdef DBUS_HAVE_ATOMIC_INT
00676   _dbus_atomic_inc (&server->refcount);
00677 #else
00678   SERVER_LOCK (server);
00679   _dbus_assert (server->refcount.value > 0);
00680 
00681   server->refcount.value += 1;
00682   SERVER_UNLOCK (server);
00683 #endif
00684 
00685   return server;
00686 }
00687 
00696 void
00697 dbus_server_unref (DBusServer *server)
00698 {
00699   dbus_bool_t last_unref;
00700 
00701   /* keep this in sync with unref_unlocked */
00702   
00703   _dbus_return_if_fail (server != NULL);
00704   _dbus_return_if_fail (server->refcount.value > 0);
00705 
00706 #ifdef DBUS_HAVE_ATOMIC_INT
00707   last_unref = (_dbus_atomic_dec (&server->refcount) == 1);
00708 #else
00709   SERVER_LOCK (server);
00710   
00711   _dbus_assert (server->refcount.value > 0);
00712 
00713   server->refcount.value -= 1;
00714   last_unref = (server->refcount.value == 0);
00715   
00716   SERVER_UNLOCK (server);
00717 #endif
00718   
00719   if (last_unref)
00720     {
00721       /* lock not held! */
00722       _dbus_assert (server->disconnected);
00723       
00724       _dbus_assert (server->vtable->finalize != NULL);
00725       
00726       (* server->vtable->finalize) (server);
00727     }
00728 }
00729 
00738 void
00739 dbus_server_disconnect (DBusServer *server)
00740 {
00741   _dbus_return_if_fail (server != NULL);
00742   _dbus_return_if_fail (server->refcount.value > 0);
00743 
00744   SERVER_LOCK (server);
00745   _dbus_server_ref_unlocked (server);
00746   
00747   _dbus_assert (server->vtable->disconnect != NULL);
00748 
00749   if (!server->disconnected)
00750     {
00751       /* this has to be first so recursive calls to disconnect don't happen */
00752       server->disconnected = TRUE;
00753       
00754       (* server->vtable->disconnect) (server);
00755     }
00756 
00757   SERVER_UNLOCK (server);
00758   dbus_server_unref (server);
00759 }
00760 
00766 dbus_bool_t
00767 dbus_server_get_is_connected (DBusServer *server)
00768 {
00769   dbus_bool_t retval;
00770   
00771   _dbus_return_val_if_fail (server != NULL, FALSE);
00772 
00773   SERVER_LOCK (server);
00774   retval = !server->disconnected;
00775   SERVER_UNLOCK (server);
00776 
00777   return retval;
00778 }
00779 
00787 char*
00788 dbus_server_get_address (DBusServer *server)
00789 {
00790   char *retval;
00791   
00792   _dbus_return_val_if_fail (server != NULL, NULL);
00793 
00794   SERVER_LOCK (server);
00795   retval = _dbus_strdup (server->address);
00796   SERVER_UNLOCK (server);
00797 
00798   return retval;
00799 }
00800 
00821 void
00822 dbus_server_set_new_connection_function (DBusServer                *server,
00823                                          DBusNewConnectionFunction  function,
00824                                          void                      *data,
00825                                          DBusFreeFunction           free_data_function)
00826 {
00827   DBusFreeFunction old_free_function;
00828   void *old_data;
00829   
00830   _dbus_return_if_fail (server != NULL);
00831 
00832   SERVER_LOCK (server);
00833   old_free_function = server->new_connection_free_data_function;
00834   old_data = server->new_connection_data;
00835   
00836   server->new_connection_function = function;
00837   server->new_connection_data = data;
00838   server->new_connection_free_data_function = free_data_function;
00839   SERVER_UNLOCK (server);
00840     
00841   if (old_free_function != NULL)
00842     (* old_free_function) (old_data);
00843 }
00844 
00861 dbus_bool_t
00862 dbus_server_set_watch_functions (DBusServer              *server,
00863                                  DBusAddWatchFunction     add_function,
00864                                  DBusRemoveWatchFunction  remove_function,
00865                                  DBusWatchToggledFunction toggled_function,
00866                                  void                    *data,
00867                                  DBusFreeFunction         free_data_function)
00868 {
00869   dbus_bool_t result;
00870   DBusWatchList *watches;
00871   
00872   _dbus_return_val_if_fail (server != NULL, FALSE);
00873 
00874   SERVER_LOCK (server);
00875   watches = server->watches;
00876   server->watches = NULL;
00877   if (watches)
00878     {
00879       SERVER_UNLOCK (server);
00880       result = _dbus_watch_list_set_functions (watches,
00881                                                add_function,
00882                                                remove_function,
00883                                                toggled_function,
00884                                                data,
00885                                                free_data_function);
00886       SERVER_LOCK (server);
00887     }
00888   else
00889     {
00890       _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
00891       result = FALSE;
00892     }
00893   server->watches = watches;
00894   SERVER_UNLOCK (server);
00895   
00896   return result;
00897 }
00898 
00914 dbus_bool_t
00915 dbus_server_set_timeout_functions (DBusServer                *server,
00916                                    DBusAddTimeoutFunction     add_function,
00917                                    DBusRemoveTimeoutFunction  remove_function,
00918                                    DBusTimeoutToggledFunction toggled_function,
00919                                    void                      *data,
00920                                    DBusFreeFunction           free_data_function)
00921 {
00922   dbus_bool_t result;
00923   DBusTimeoutList *timeouts;
00924   
00925   _dbus_return_val_if_fail (server != NULL, FALSE);
00926 
00927   SERVER_LOCK (server);
00928   timeouts = server->timeouts;
00929   server->timeouts = NULL;
00930   if (timeouts)
00931     {
00932       SERVER_UNLOCK (server);
00933       result = _dbus_timeout_list_set_functions (timeouts,
00934                                                  add_function,
00935                                                  remove_function,
00936                                                  toggled_function,
00937                                                  data,
00938                                                  free_data_function);
00939       SERVER_LOCK (server);
00940     }
00941   else
00942     {
00943       _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
00944       result = FALSE;
00945     }
00946   server->timeouts = timeouts;
00947   SERVER_UNLOCK (server);
00948   
00949   return result;
00950 }
00951 
00965 dbus_bool_t
00966 dbus_server_set_auth_mechanisms (DBusServer  *server,
00967                                  const char **mechanisms)
00968 {
00969   char **copy;
00970 
00971   _dbus_return_val_if_fail (server != NULL, FALSE);
00972 
00973   SERVER_LOCK (server);
00974   
00975   if (mechanisms != NULL)
00976     {
00977       copy = _dbus_dup_string_array (mechanisms);
00978       if (copy == NULL)
00979         return FALSE;
00980     }
00981   else
00982     copy = NULL;
00983 
00984   dbus_free_string_array (server->auth_mechanisms);
00985   server->auth_mechanisms = copy;
00986 
00987   SERVER_UNLOCK (server);
00988   
00989   return TRUE;
00990 }
00991 
00992 
00993 static DBusDataSlotAllocator slot_allocator;
00994 _DBUS_DEFINE_GLOBAL_LOCK (server_slots);
00995 
01010 dbus_bool_t
01011 dbus_server_allocate_data_slot (dbus_int32_t *slot_p)
01012 {
01013   return _dbus_data_slot_allocator_alloc (&slot_allocator,
01014                                           (DBusMutex **)&_DBUS_LOCK_NAME (server_slots),
01015                                           slot_p);
01016 }
01017 
01029 void
01030 dbus_server_free_data_slot (dbus_int32_t *slot_p)
01031 {
01032   _dbus_return_if_fail (*slot_p >= 0);
01033   
01034   _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
01035 }
01036 
01050 dbus_bool_t
01051 dbus_server_set_data (DBusServer       *server,
01052                       int               slot,
01053                       void             *data,
01054                       DBusFreeFunction  free_data_func)
01055 {
01056   DBusFreeFunction old_free_func;
01057   void *old_data;
01058   dbus_bool_t retval;
01059 
01060   _dbus_return_val_if_fail (server != NULL, FALSE);
01061 
01062   SERVER_LOCK (server);
01063   
01064   retval = _dbus_data_slot_list_set (&slot_allocator,
01065                                      &server->slot_list,
01066                                      slot, data, free_data_func,
01067                                      &old_free_func, &old_data);
01068 
01069 
01070   SERVER_UNLOCK (server);
01071   
01072   if (retval)
01073     {
01074       /* Do the actual free outside the server lock */
01075       if (old_free_func)
01076         (* old_free_func) (old_data);
01077     }
01078 
01079   return retval;
01080 }
01081 
01090 void*
01091 dbus_server_get_data (DBusServer   *server,
01092                       int           slot)
01093 {
01094   void *res;
01095 
01096   _dbus_return_val_if_fail (server != NULL, NULL);
01097   
01098   SERVER_LOCK (server);
01099   
01100   res = _dbus_data_slot_list_get (&slot_allocator,
01101                                   &server->slot_list,
01102                                   slot);
01103 
01104   SERVER_UNLOCK (server);
01105   
01106   return res;
01107 }
01108 
01111 #ifdef DBUS_BUILD_TESTS
01112 #include "dbus-test.h"
01113 
01114 dbus_bool_t
01115 _dbus_server_test (void)
01116 {
01117   const char *valid_addresses[] = {
01118     "tcp:port=1234",
01119     "unix:path=./boogie",
01120     "tcp:host=localhost,port=1234",
01121     "tcp:host=localhost,port=1234;tcp:port=5678",
01122     "tcp:port=1234;unix:path=./boogie",
01123   };
01124 
01125   DBusServer *server;
01126   int i;
01127   
01128   for (i = 0; i < _DBUS_N_ELEMENTS (valid_addresses); i++)
01129     {
01130       DBusError error;
01131 
01132       /* FIXME um, how are the two tests here different? */
01133       
01134       dbus_error_init (&error);
01135       server = dbus_server_listen (valid_addresses[i], &error);
01136       if (server == NULL)
01137         {
01138           _dbus_warn ("server listen error: %s: %s\n", error.name, error.message);
01139           dbus_error_free (&error);
01140           _dbus_assert_not_reached ("Failed to listen for valid address.");
01141         }
01142 
01143       dbus_server_disconnect (server);
01144       dbus_server_unref (server);
01145 
01146       /* Try disconnecting before unreffing */
01147       server = dbus_server_listen (valid_addresses[i], &error);
01148       if (server == NULL)
01149         {
01150           _dbus_warn ("server listen error: %s: %s\n", error.name, error.message);
01151           dbus_error_free (&error);          
01152           _dbus_assert_not_reached ("Failed to listen for valid address.");
01153         }
01154 
01155       dbus_server_disconnect (server);
01156       dbus_server_unref (server);
01157     }
01158 
01159   return TRUE;
01160 }
01161 
01162 #endif /* DBUS_BUILD_TESTS */

Generated on Fri Sep 21 18:12:13 2007 for D-Bus by  doxygen 1.5.1