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., 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 = DBUS_ERROR_INIT;
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   handled_once = FALSE;
00557 
00558   for (i = 0; i < len; i++)
00559     {
00560       int j;
00561 
00562       for (j = 0; j < (int) _DBUS_N_ELEMENTS (listen_funcs); ++j)
00563         {
00564           DBusServerListenResult result;
00565           DBusError tmp_error = DBUS_ERROR_INIT;
00566 
00567           result = (* listen_funcs[j].func) (entries[i],
00568                                              &server,
00569                                              &tmp_error);
00570 
00571           if (result == DBUS_SERVER_LISTEN_OK)
00572             {
00573               _dbus_assert (server != NULL);
00574               _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
00575               handled_once = TRUE;
00576               goto out;
00577             }
00578           else if (result == DBUS_SERVER_LISTEN_BAD_ADDRESS)
00579             {
00580               _dbus_assert (server == NULL);
00581               _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
00582               dbus_move_error (&tmp_error, error);
00583               handled_once = TRUE;
00584               goto out;
00585             }
00586           else if (result == DBUS_SERVER_LISTEN_NOT_HANDLED)
00587             {
00588               _dbus_assert (server == NULL);
00589               _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
00590 
00591               /* keep trying addresses */
00592             }
00593           else if (result == DBUS_SERVER_LISTEN_DID_NOT_CONNECT)
00594             {
00595               _dbus_assert (server == NULL);
00596               _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
00597               if (!dbus_error_is_set (&first_connect_error))
00598                 dbus_move_error (&tmp_error, &first_connect_error);
00599               else
00600                 dbus_error_free (&tmp_error);
00601 
00602               handled_once = TRUE;
00603               
00604               /* keep trying addresses */
00605             }
00606         }
00607 
00608       _dbus_assert (server == NULL);
00609       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00610     }
00611 
00612  out:
00613 
00614   if (!handled_once)
00615     {
00616       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00617       if (len > 0)
00618         dbus_set_error (error,
00619                        DBUS_ERROR_BAD_ADDRESS,
00620                        "Unknown address type '%s'",
00621                        dbus_address_entry_get_method (entries[0]));
00622       else
00623         dbus_set_error (error,
00624                         DBUS_ERROR_BAD_ADDRESS,
00625                         "Empty address '%s'",
00626                         address);
00627     }
00628   
00629   dbus_address_entries_free (entries);
00630 
00631   if (server == NULL)
00632     {
00633       _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error) ||
00634                    dbus_error_is_set (error));
00635       
00636       if (error && dbus_error_is_set (error))
00637         {
00638           /* already set the error */
00639         }
00640       else
00641         {
00642           /* didn't set the error but either error should be
00643            * NULL or first_connect_error should be set.
00644            */
00645           _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error));
00646           dbus_move_error (&first_connect_error, error);
00647         }
00648 
00649       _DBUS_ASSERT_ERROR_IS_CLEAR (&first_connect_error); /* be sure we freed it */
00650       _DBUS_ASSERT_ERROR_IS_SET (error);
00651 
00652       return NULL;
00653     }
00654   else
00655     {
00656       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00657       return server;
00658     }
00659 }
00660 
00667 DBusServer *
00668 dbus_server_ref (DBusServer *server)
00669 {
00670   _dbus_return_val_if_fail (server != NULL, NULL);
00671   _dbus_return_val_if_fail (server->refcount.value > 0, NULL);
00672 
00673 #ifdef DBUS_HAVE_ATOMIC_INT
00674   _dbus_atomic_inc (&server->refcount);
00675 #else
00676   SERVER_LOCK (server);
00677   _dbus_assert (server->refcount.value > 0);
00678 
00679   server->refcount.value += 1;
00680   SERVER_UNLOCK (server);
00681 #endif
00682 
00683   return server;
00684 }
00685 
00694 void
00695 dbus_server_unref (DBusServer *server)
00696 {
00697   dbus_bool_t last_unref;
00698 
00699   /* keep this in sync with unref_unlocked */
00700   
00701   _dbus_return_if_fail (server != NULL);
00702   _dbus_return_if_fail (server->refcount.value > 0);
00703 
00704 #ifdef DBUS_HAVE_ATOMIC_INT
00705   last_unref = (_dbus_atomic_dec (&server->refcount) == 1);
00706 #else
00707   SERVER_LOCK (server);
00708   
00709   _dbus_assert (server->refcount.value > 0);
00710 
00711   server->refcount.value -= 1;
00712   last_unref = (server->refcount.value == 0);
00713   
00714   SERVER_UNLOCK (server);
00715 #endif
00716   
00717   if (last_unref)
00718     {
00719       /* lock not held! */
00720       _dbus_assert (server->disconnected);
00721       
00722       _dbus_assert (server->vtable->finalize != NULL);
00723       
00724       (* server->vtable->finalize) (server);
00725     }
00726 }
00727 
00736 void
00737 dbus_server_disconnect (DBusServer *server)
00738 {
00739   _dbus_return_if_fail (server != NULL);
00740   _dbus_return_if_fail (server->refcount.value > 0);
00741 
00742   SERVER_LOCK (server);
00743   _dbus_server_ref_unlocked (server);
00744   
00745   _dbus_assert (server->vtable->disconnect != NULL);
00746 
00747   if (!server->disconnected)
00748     {
00749       /* this has to be first so recursive calls to disconnect don't happen */
00750       server->disconnected = TRUE;
00751       
00752       (* server->vtable->disconnect) (server);
00753     }
00754 
00755   SERVER_UNLOCK (server);
00756   dbus_server_unref (server);
00757 }
00758 
00764 dbus_bool_t
00765 dbus_server_get_is_connected (DBusServer *server)
00766 {
00767   dbus_bool_t retval;
00768   
00769   _dbus_return_val_if_fail (server != NULL, FALSE);
00770 
00771   SERVER_LOCK (server);
00772   retval = !server->disconnected;
00773   SERVER_UNLOCK (server);
00774 
00775   return retval;
00776 }
00777 
00785 char*
00786 dbus_server_get_address (DBusServer *server)
00787 {
00788   char *retval;
00789   
00790   _dbus_return_val_if_fail (server != NULL, NULL);
00791 
00792   SERVER_LOCK (server);
00793   retval = _dbus_strdup (server->address);
00794   SERVER_UNLOCK (server);
00795 
00796   return retval;
00797 }
00798 
00821 char*
00822 dbus_server_get_id (DBusServer *server)
00823 {
00824   char *retval;
00825   
00826   _dbus_return_val_if_fail (server != NULL, NULL);
00827 
00828   SERVER_LOCK (server);
00829   retval = NULL;
00830   _dbus_string_copy_data (&server->guid_hex, &retval);
00831   SERVER_UNLOCK (server);
00832 
00833   return retval;
00834 }
00835 
00856 void
00857 dbus_server_set_new_connection_function (DBusServer                *server,
00858                                          DBusNewConnectionFunction  function,
00859                                          void                      *data,
00860                                          DBusFreeFunction           free_data_function)
00861 {
00862   DBusFreeFunction old_free_function;
00863   void *old_data;
00864   
00865   _dbus_return_if_fail (server != NULL);
00866 
00867   SERVER_LOCK (server);
00868   old_free_function = server->new_connection_free_data_function;
00869   old_data = server->new_connection_data;
00870   
00871   server->new_connection_function = function;
00872   server->new_connection_data = data;
00873   server->new_connection_free_data_function = free_data_function;
00874   SERVER_UNLOCK (server);
00875     
00876   if (old_free_function != NULL)
00877     (* old_free_function) (old_data);
00878 }
00879 
00896 dbus_bool_t
00897 dbus_server_set_watch_functions (DBusServer              *server,
00898                                  DBusAddWatchFunction     add_function,
00899                                  DBusRemoveWatchFunction  remove_function,
00900                                  DBusWatchToggledFunction toggled_function,
00901                                  void                    *data,
00902                                  DBusFreeFunction         free_data_function)
00903 {
00904   dbus_bool_t result;
00905   DBusWatchList *watches;
00906   
00907   _dbus_return_val_if_fail (server != NULL, FALSE);
00908 
00909   SERVER_LOCK (server);
00910   watches = server->watches;
00911   server->watches = NULL;
00912   if (watches)
00913     {
00914       SERVER_UNLOCK (server);
00915       result = _dbus_watch_list_set_functions (watches,
00916                                                add_function,
00917                                                remove_function,
00918                                                toggled_function,
00919                                                data,
00920                                                free_data_function);
00921       SERVER_LOCK (server);
00922     }
00923   else
00924     {
00925       _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
00926       result = FALSE;
00927     }
00928   server->watches = watches;
00929   SERVER_UNLOCK (server);
00930   
00931   return result;
00932 }
00933 
00949 dbus_bool_t
00950 dbus_server_set_timeout_functions (DBusServer                *server,
00951                                    DBusAddTimeoutFunction     add_function,
00952                                    DBusRemoveTimeoutFunction  remove_function,
00953                                    DBusTimeoutToggledFunction toggled_function,
00954                                    void                      *data,
00955                                    DBusFreeFunction           free_data_function)
00956 {
00957   dbus_bool_t result;
00958   DBusTimeoutList *timeouts;
00959   
00960   _dbus_return_val_if_fail (server != NULL, FALSE);
00961 
00962   SERVER_LOCK (server);
00963   timeouts = server->timeouts;
00964   server->timeouts = NULL;
00965   if (timeouts)
00966     {
00967       SERVER_UNLOCK (server);
00968       result = _dbus_timeout_list_set_functions (timeouts,
00969                                                  add_function,
00970                                                  remove_function,
00971                                                  toggled_function,
00972                                                  data,
00973                                                  free_data_function);
00974       SERVER_LOCK (server);
00975     }
00976   else
00977     {
00978       _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
00979       result = FALSE;
00980     }
00981   server->timeouts = timeouts;
00982   SERVER_UNLOCK (server);
00983   
00984   return result;
00985 }
00986 
01000 dbus_bool_t
01001 dbus_server_set_auth_mechanisms (DBusServer  *server,
01002                                  const char **mechanisms)
01003 {
01004   char **copy;
01005 
01006   _dbus_return_val_if_fail (server != NULL, FALSE);
01007 
01008   SERVER_LOCK (server);
01009   
01010   if (mechanisms != NULL)
01011     {
01012       copy = _dbus_dup_string_array (mechanisms);
01013       if (copy == NULL)
01014         return FALSE;
01015     }
01016   else
01017     copy = NULL;
01018 
01019   dbus_free_string_array (server->auth_mechanisms);
01020   server->auth_mechanisms = copy;
01021 
01022   SERVER_UNLOCK (server);
01023   
01024   return TRUE;
01025 }
01026 
01027 
01028 static DBusDataSlotAllocator slot_allocator;
01029 _DBUS_DEFINE_GLOBAL_LOCK (server_slots);
01030 
01045 dbus_bool_t
01046 dbus_server_allocate_data_slot (dbus_int32_t *slot_p)
01047 {
01048   return _dbus_data_slot_allocator_alloc (&slot_allocator,
01049                                           (DBusMutex **)&_DBUS_LOCK_NAME (server_slots),
01050                                           slot_p);
01051 }
01052 
01064 void
01065 dbus_server_free_data_slot (dbus_int32_t *slot_p)
01066 {
01067   _dbus_return_if_fail (*slot_p >= 0);
01068   
01069   _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
01070 }
01071 
01085 dbus_bool_t
01086 dbus_server_set_data (DBusServer       *server,
01087                       int               slot,
01088                       void             *data,
01089                       DBusFreeFunction  free_data_func)
01090 {
01091   DBusFreeFunction old_free_func;
01092   void *old_data;
01093   dbus_bool_t retval;
01094 
01095   _dbus_return_val_if_fail (server != NULL, FALSE);
01096 
01097   SERVER_LOCK (server);
01098   
01099   retval = _dbus_data_slot_list_set (&slot_allocator,
01100                                      &server->slot_list,
01101                                      slot, data, free_data_func,
01102                                      &old_free_func, &old_data);
01103 
01104 
01105   SERVER_UNLOCK (server);
01106   
01107   if (retval)
01108     {
01109       /* Do the actual free outside the server lock */
01110       if (old_free_func)
01111         (* old_free_func) (old_data);
01112     }
01113 
01114   return retval;
01115 }
01116 
01125 void*
01126 dbus_server_get_data (DBusServer   *server,
01127                       int           slot)
01128 {
01129   void *res;
01130 
01131   _dbus_return_val_if_fail (server != NULL, NULL);
01132   
01133   SERVER_LOCK (server);
01134   
01135   res = _dbus_data_slot_list_get (&slot_allocator,
01136                                   &server->slot_list,
01137                                   slot);
01138 
01139   SERVER_UNLOCK (server);
01140   
01141   return res;
01142 }
01143 
01146 #ifdef DBUS_BUILD_TESTS
01147 #include "dbus-test.h"
01148 #include <string.h>
01149 
01150 dbus_bool_t
01151 _dbus_server_test (void)
01152 {
01153   const char *valid_addresses[] = {
01154     "tcp:port=1234",
01155     "tcp:host=localhost,port=1234",
01156     "tcp:host=localhost,port=1234;tcp:port=5678",
01157 #ifdef DBUS_UNIX
01158     "unix:path=./boogie",
01159     "tcp:port=1234;unix:path=./boogie",
01160 #endif
01161   };
01162 
01163   DBusServer *server;
01164   int i;
01165   
01166   for (i = 0; i < _DBUS_N_ELEMENTS (valid_addresses); i++)
01167     {
01168       DBusError error = DBUS_ERROR_INIT;
01169       char *address;
01170       char *id;
01171 
01172       server = dbus_server_listen (valid_addresses[i], &error);
01173       if (server == NULL)
01174         {
01175           _dbus_warn ("server listen error: %s: %s\n", error.name, error.message);
01176           dbus_error_free (&error);
01177           _dbus_assert_not_reached ("Failed to listen for valid address.");
01178         }
01179 
01180       id = dbus_server_get_id (server);
01181       _dbus_assert (id != NULL);
01182       address = dbus_server_get_address (server);
01183       _dbus_assert (address != NULL);
01184 
01185       if (strstr (address, id) == NULL)
01186         {
01187           _dbus_warn ("server id '%s' is not in the server address '%s'\n",
01188                       id, address);
01189           _dbus_assert_not_reached ("bad server id or address");
01190         }
01191 
01192       dbus_free (id);
01193       dbus_free (address);
01194       
01195       dbus_server_disconnect (server);
01196       dbus_server_unref (server);
01197     }
01198 
01199   return TRUE;
01200 }
01201 
01202 #endif /* DBUS_BUILD_TESTS */

Generated on Sat Dec 6 19:43:44 2008 for D-Bus by  doxygen 1.5.1