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-string.h"
00027 #ifdef DBUS_BUILD_TESTS
00028 #include "dbus-server-debug-pipe.h"
00029 #endif
00030 #include "dbus-address.h"
00031 #include "dbus-protocol.h"
00032 
00055 static void
00056 init_guid (DBusGUID *guid)
00057 {
00058   long now;
00059   char *p;
00060   int ts_size;
00061 
00062   _dbus_get_current_time (&now, NULL);
00063 
00064   guid->as_uint32s[0] = now;
00065 
00066   ts_size = sizeof (guid->as_uint32s[0]);
00067   p = ((char*)guid->as_bytes) + ts_size;
00068   
00069   _dbus_generate_random_bytes_buffer (p,
00070                                       sizeof (guid->as_bytes) - ts_size);
00071 }
00072 
00073 /* this is a little fragile since it assumes the address doesn't
00074  * already have a guid, but it shouldn't
00075  */
00076 static char*
00077 copy_address_with_guid_appended (const DBusString *address,
00078                                  const DBusString *guid_hex)
00079 {
00080   DBusString with_guid;
00081   char *retval;
00082   
00083   if (!_dbus_string_init (&with_guid))
00084     return NULL;
00085 
00086   if (!_dbus_string_copy (address, 0, &with_guid,
00087                           _dbus_string_get_length (&with_guid)) ||
00088       !_dbus_string_append (&with_guid, ",guid=") ||
00089       !_dbus_string_copy (guid_hex, 0,
00090                           &with_guid, _dbus_string_get_length (&with_guid)))
00091     {
00092       _dbus_string_free (&with_guid);
00093       return NULL;
00094     }
00095 
00096   retval = NULL;
00097   _dbus_string_steal_data (&with_guid, &retval);
00098 
00099   _dbus_string_free (&with_guid);
00100       
00101   return retval; /* may be NULL if steal_data failed */
00102 }
00103 
00113 dbus_bool_t
00114 _dbus_server_init_base (DBusServer             *server,
00115                         const DBusServerVTable *vtable,
00116                         const DBusString       *address)
00117 {
00118   DBusString guid_raw;
00119   
00120   server->vtable = vtable;
00121   server->refcount.value = 1;
00122 
00123   server->address = NULL;
00124   server->watches = NULL;
00125   server->timeouts = NULL;
00126 
00127   if (!_dbus_string_init (&server->guid_hex))
00128     return FALSE;
00129 
00130   init_guid (&server->guid);
00131 
00132   _dbus_string_init_const_len (&guid_raw, (signed char*) server->guid.as_bytes,
00133                                sizeof (server->guid.as_bytes));
00134   if (!_dbus_string_hex_encode (&guid_raw, 0,
00135                                 &server->guid_hex,
00136                                 _dbus_string_get_length (&server->guid_hex)))
00137     goto failed;
00138   
00139   server->address = copy_address_with_guid_appended (address,
00140                                                      &server->guid_hex);
00141   if (server->address == NULL)
00142     goto failed;
00143   
00144   _dbus_mutex_new_at_location (&server->mutex);
00145   if (server->mutex == NULL)
00146     goto failed;
00147   
00148   server->watches = _dbus_watch_list_new ();
00149   if (server->watches == NULL)
00150     goto failed;
00151 
00152   server->timeouts = _dbus_timeout_list_new ();
00153   if (server->timeouts == NULL)
00154     goto failed;
00155 
00156   _dbus_data_slot_list_init (&server->slot_list);
00157 
00158   _dbus_verbose ("Initialized server on address %s\n", server->address);
00159   
00160   return TRUE;
00161 
00162  failed:
00163   _dbus_mutex_free_at_location (&server->mutex);
00164   server->mutex = NULL;
00165   if (server->watches)
00166     {
00167       _dbus_watch_list_free (server->watches);
00168       server->watches = NULL;
00169     }
00170   if (server->timeouts)
00171     {
00172       _dbus_timeout_list_free (server->timeouts);
00173       server->timeouts = NULL;
00174     }
00175   if (server->address)
00176     {
00177       dbus_free (server->address);
00178       server->address = NULL;
00179     }
00180   _dbus_string_free (&server->guid_hex);
00181   
00182   return FALSE;
00183 }
00184 
00191 void
00192 _dbus_server_finalize_base (DBusServer *server)
00193 {
00194   /* We don't have the lock, but nobody should be accessing
00195    * concurrently since they don't have a ref
00196    */
00197 #ifndef DBUS_DISABLE_CHECKS
00198   _dbus_assert (!server->have_server_lock);
00199 #endif
00200   _dbus_assert (server->disconnected);
00201   
00202   /* calls out to application code... */
00203   _dbus_data_slot_list_free (&server->slot_list);
00204 
00205   dbus_server_set_new_connection_function (server, NULL, NULL, NULL);
00206 
00207   _dbus_watch_list_free (server->watches);
00208   _dbus_timeout_list_free (server->timeouts);
00209 
00210   _dbus_mutex_free_at_location (&server->mutex);
00211   
00212   dbus_free (server->address);
00213 
00214   dbus_free_string_array (server->auth_mechanisms);
00215 
00216   _dbus_string_free (&server->guid_hex);
00217 }
00218 
00219 
00220 typedef dbus_bool_t (* DBusWatchAddFunction)     (DBusWatchList *list,
00221                                                   DBusWatch     *watch);
00222 typedef void        (* DBusWatchRemoveFunction)  (DBusWatchList *list,
00223                                                   DBusWatch     *watch);
00224 typedef void        (* DBusWatchToggleFunction)  (DBusWatchList *list,
00225                                                   DBusWatch     *watch,
00226                                                   dbus_bool_t    enabled);
00227 
00228 static dbus_bool_t
00229 protected_change_watch (DBusServer             *server,
00230                         DBusWatch              *watch,
00231                         DBusWatchAddFunction    add_function,
00232                         DBusWatchRemoveFunction remove_function,
00233                         DBusWatchToggleFunction toggle_function,
00234                         dbus_bool_t             enabled)
00235 {
00236   DBusWatchList *watches;
00237   dbus_bool_t retval;
00238   
00239   HAVE_LOCK_CHECK (server);
00240 
00241   /* This isn't really safe or reasonable; a better pattern is the "do
00242    * everything, then drop lock and call out" one; but it has to be
00243    * propagated up through all callers
00244    */
00245   
00246   watches = server->watches;
00247   if (watches)
00248     {
00249       server->watches = NULL;
00250       _dbus_server_ref_unlocked (server);
00251       SERVER_UNLOCK (server);
00252 
00253       if (add_function)
00254         retval = (* add_function) (watches, watch);
00255       else if (remove_function)
00256         {
00257           retval = TRUE;
00258           (* remove_function) (watches, watch);
00259         }
00260       else
00261         {
00262           retval = TRUE;
00263           (* toggle_function) (watches, watch, enabled);
00264         }
00265       
00266       SERVER_LOCK (server);
00267       server->watches = watches;
00268       _dbus_server_unref_unlocked (server);
00269 
00270       return retval;
00271     }
00272   else
00273     return FALSE;
00274 }
00275 
00283 dbus_bool_t
00284 _dbus_server_add_watch (DBusServer *server,
00285                         DBusWatch  *watch)
00286 {
00287   HAVE_LOCK_CHECK (server);
00288   return protected_change_watch (server, watch,
00289                                  _dbus_watch_list_add_watch,
00290                                  NULL, NULL, FALSE);
00291 }
00292 
00299 void
00300 _dbus_server_remove_watch  (DBusServer *server,
00301                             DBusWatch  *watch)
00302 {
00303   HAVE_LOCK_CHECK (server);
00304   protected_change_watch (server, watch,
00305                           NULL,
00306                           _dbus_watch_list_remove_watch,
00307                           NULL, FALSE);
00308 }
00309 
00319 void
00320 _dbus_server_toggle_watch (DBusServer  *server,
00321                            DBusWatch   *watch,
00322                            dbus_bool_t  enabled)
00323 {
00324   _dbus_assert (watch != NULL);
00325 
00326   HAVE_LOCK_CHECK (server);
00327   protected_change_watch (server, watch,
00328                           NULL, NULL,
00329                           _dbus_watch_list_toggle_watch,
00330                           enabled);
00331 }
00332 
00333 
00334 typedef dbus_bool_t (* DBusTimeoutAddFunction)    (DBusTimeoutList *list,
00335                                                    DBusTimeout     *timeout);
00336 typedef void        (* DBusTimeoutRemoveFunction) (DBusTimeoutList *list,
00337                                                    DBusTimeout     *timeout);
00338 typedef void        (* DBusTimeoutToggleFunction) (DBusTimeoutList *list,
00339                                                    DBusTimeout     *timeout,
00340                                                    dbus_bool_t      enabled);
00341 
00342 
00343 static dbus_bool_t
00344 protected_change_timeout (DBusServer               *server,
00345                           DBusTimeout              *timeout,
00346                           DBusTimeoutAddFunction    add_function,
00347                           DBusTimeoutRemoveFunction remove_function,
00348                           DBusTimeoutToggleFunction toggle_function,
00349                           dbus_bool_t               enabled)
00350 {
00351   DBusTimeoutList *timeouts;
00352   dbus_bool_t retval;
00353   
00354   HAVE_LOCK_CHECK (server);
00355 
00356   /* This isn't really safe or reasonable; a better pattern is the "do everything, then
00357    * drop lock and call out" one; but it has to be propagated up through all callers
00358    */
00359   
00360   timeouts = server->timeouts;
00361   if (timeouts)
00362     {
00363       server->timeouts = NULL;
00364       _dbus_server_ref_unlocked (server);
00365       SERVER_UNLOCK (server);
00366 
00367       if (add_function)
00368         retval = (* add_function) (timeouts, timeout);
00369       else if (remove_function)
00370         {
00371           retval = TRUE;
00372           (* remove_function) (timeouts, timeout);
00373         }
00374       else
00375         {
00376           retval = TRUE;
00377           (* toggle_function) (timeouts, timeout, enabled);
00378         }
00379       
00380       SERVER_LOCK (server);
00381       server->timeouts = timeouts;
00382       _dbus_server_unref_unlocked (server);
00383 
00384       return retval;
00385     }
00386   else
00387     return FALSE;
00388 }
00389 
00399 dbus_bool_t
00400 _dbus_server_add_timeout (DBusServer  *server,
00401                           DBusTimeout *timeout)
00402 {
00403   return protected_change_timeout (server, timeout,
00404                                    _dbus_timeout_list_add_timeout,
00405                                    NULL, NULL, FALSE);
00406 }
00407 
00414 void
00415 _dbus_server_remove_timeout (DBusServer  *server,
00416                              DBusTimeout *timeout)
00417 {
00418   protected_change_timeout (server, timeout,
00419                             NULL,
00420                             _dbus_timeout_list_remove_timeout,
00421                             NULL, FALSE);
00422 }
00423 
00433 void
00434 _dbus_server_toggle_timeout (DBusServer  *server,
00435                              DBusTimeout *timeout,
00436                              dbus_bool_t  enabled)
00437 {
00438   protected_change_timeout (server, timeout,
00439                             NULL, NULL,
00440                             _dbus_timeout_list_toggle_timeout,
00441                             enabled);
00442 }
00443 
00444 
00482 DBusServer*
00483 dbus_server_listen (const char     *address,
00484                     DBusError      *error)
00485 {
00486   DBusServer *server;
00487   DBusAddressEntry **entries;
00488   int len, i;
00489   const char *address_problem_type;
00490   const char *address_problem_field;
00491   const char *address_problem_other;
00492 
00493   _dbus_return_val_if_fail (address != NULL, NULL);
00494   _dbus_return_val_if_error_is_set (error, NULL);
00495   
00496   if (!dbus_parse_address (address, &entries, &len, error))
00497     return NULL;
00498 
00499   server = NULL;
00500   address_problem_type = NULL;
00501   address_problem_field = NULL;
00502   address_problem_other = NULL;
00503   
00504   for (i = 0; i < len; i++)
00505     {
00506       const char *method;
00507 
00508       method = dbus_address_entry_get_method (entries[i]);
00509 
00510       if (strcmp (method, "unix") == 0)
00511         {
00512           const char *path = dbus_address_entry_get_value (entries[i], "path");
00513           const char *tmpdir = dbus_address_entry_get_value (entries[i], "tmpdir");
00514           const char *abstract = dbus_address_entry_get_value (entries[i], "abstract");
00515           
00516           if (path == NULL && tmpdir == NULL && abstract == NULL)
00517             {
00518               address_problem_type = "unix";
00519               address_problem_field = "path or tmpdir or abstract";
00520               goto bad_address;
00521             }
00522 
00523           if ((path && tmpdir) ||
00524               (path && abstract) ||
00525               (tmpdir && abstract))
00526             {
00527               address_problem_other = "cannot specify two of \"path\" and \"tmpdir\" and \"abstract\" at the same time";
00528               goto bad_address;
00529             }
00530 
00531           if (tmpdir != NULL)
00532             {
00533               DBusString full_path;
00534               DBusString filename;
00535               
00536               if (!_dbus_string_init (&full_path))
00537                 {
00538                   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00539                   goto out;
00540                 }
00541                   
00542               if (!_dbus_string_init (&filename))
00543                 {
00544                   _dbus_string_free (&full_path);
00545                   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00546                   goto out;
00547                 }
00548               
00549               if (!_dbus_string_append (&filename,
00550                                         "dbus-") ||
00551                   !_dbus_generate_random_ascii (&filename, 10) ||
00552                   !_dbus_string_append (&full_path, tmpdir) ||
00553                   !_dbus_concat_dir_and_file (&full_path, &filename))
00554                 {
00555                   _dbus_string_free (&full_path);
00556                   _dbus_string_free (&filename);
00557                   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00558                   goto out;
00559                 }
00560               
00561               /* Always use abstract namespace if possible with tmpdir */
00562               
00563               server =
00564                 _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path),
00565 #ifdef HAVE_ABSTRACT_SOCKETS
00566                                                     TRUE,
00567 #else
00568                                                     FALSE,
00569 #endif
00570                                                     error);
00571 
00572               _dbus_string_free (&full_path);
00573               _dbus_string_free (&filename);
00574             }
00575           else
00576             {
00577               if (path)
00578                 server = _dbus_server_new_for_domain_socket (path, FALSE, error);
00579               else
00580                 server = _dbus_server_new_for_domain_socket (abstract, TRUE, error);
00581             }
00582         }
00583       else if (strcmp (method, "tcp") == 0)
00584         {
00585           const char *host = dbus_address_entry_get_value (entries[i], "host");
00586           const char *port = dbus_address_entry_get_value (entries[i], "port");
00587           DBusString  str;
00588           long lport;
00589           dbus_bool_t sresult;
00590           
00591           if (port == NULL)
00592             {
00593               address_problem_type = "tcp";
00594               address_problem_field = "port";
00595               goto bad_address;
00596             }
00597 
00598           _dbus_string_init_const (&str, port);
00599           sresult = _dbus_string_parse_int (&str, 0, &lport, NULL);
00600           _dbus_string_free (&str);
00601           
00602           if (sresult == FALSE || lport <= 0 || lport > 65535)
00603             {
00604               address_problem_other = "Port is not an integer between 0 and 65535";
00605               goto bad_address;
00606             }
00607           
00608           server = _dbus_server_new_for_tcp_socket (host, lport, error);
00609 
00610           if (server)
00611             break;
00612         }
00613 #ifdef DBUS_BUILD_TESTS
00614       else if (strcmp (method, "debug-pipe") == 0)
00615         {
00616           const char *name = dbus_address_entry_get_value (entries[i], "name");
00617 
00618           if (name == NULL)
00619             {
00620               address_problem_type = "debug-pipe";
00621               address_problem_field = "name";
00622               goto bad_address;
00623             }
00624 
00625           server = _dbus_server_debug_pipe_new (name, error);
00626         }
00627 #endif
00628       else
00629         {
00630           address_problem_other = "Unknown address type (examples of valid types are \"unix\" and \"tcp\")";
00631           goto bad_address;
00632         }
00633       
00634       if (server)
00635         break;
00636     }
00637 
00638  out:
00639   
00640   dbus_address_entries_free (entries);
00641   return server;
00642 
00643  bad_address:
00644   dbus_address_entries_free (entries);
00645   if (address_problem_type != NULL)
00646     dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
00647                     "Server address of type %s was missing argument %s",
00648                     address_problem_type, address_problem_field);
00649   else
00650     dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
00651                     "Could not parse server address: %s",
00652                     address_problem_other);
00653 
00654   return NULL;
00655 }
00656 
00663 DBusServer *
00664 dbus_server_ref (DBusServer *server)
00665 {
00666   _dbus_return_val_if_fail (server != NULL, NULL);
00667   _dbus_return_val_if_fail (server->refcount.value > 0, NULL);
00668 
00669 #ifdef DBUS_HAVE_ATOMIC_INT
00670   _dbus_atomic_inc (&server->refcount);
00671 #else
00672   SERVER_LOCK (server);
00673   _dbus_assert (server->refcount.value > 0);
00674 
00675   server->refcount.value += 1;
00676   SERVER_UNLOCK (server);
00677 #endif
00678 
00679   return server;
00680 }
00681 
00690 void
00691 dbus_server_unref (DBusServer *server)
00692 {
00693   dbus_bool_t last_unref;
00694   
00695   _dbus_return_if_fail (server != NULL);
00696   _dbus_return_if_fail (server->refcount.value > 0);
00697 
00698 #ifdef DBUS_HAVE_ATOMIC_INT
00699   last_unref = (_dbus_atomic_dec (&server->refcount) == 1);
00700 #else
00701   SERVER_LOCK (server);
00702   
00703   _dbus_assert (server->refcount.value > 0);
00704 
00705   server->refcount.value -= 1;
00706   last_unref = (server->refcount.value == 0);
00707   
00708   SERVER_UNLOCK (server);
00709 #endif
00710   
00711   if (last_unref)
00712     {
00713       /* lock not held! */
00714       _dbus_assert (server->disconnected);
00715       
00716       _dbus_assert (server->vtable->finalize != NULL);
00717       
00718       (* server->vtable->finalize) (server);
00719     }
00720 }
00721 
00727 void
00728 _dbus_server_ref_unlocked (DBusServer *server)
00729 {
00730   _dbus_assert (server != NULL);
00731   _dbus_assert (server->refcount.value > 0);
00732   
00733   HAVE_LOCK_CHECK (server);
00734 
00735 #ifdef DBUS_HAVE_ATOMIC_INT
00736   _dbus_atomic_inc (&server->refcount);
00737 #else
00738   _dbus_assert (server->refcount.value > 0);
00739 
00740   server->refcount.value += 1;
00741 #endif
00742 }
00743 
00749 void
00750 _dbus_server_unref_unlocked (DBusServer *server)
00751 {
00752   dbus_bool_t last_unref;
00753   
00754   _dbus_assert (server != NULL);
00755   _dbus_assert (server->refcount.value > 0);
00756 
00757   HAVE_LOCK_CHECK (server);
00758   
00759 #ifdef DBUS_HAVE_ATOMIC_INT
00760   last_unref = (_dbus_atomic_dec (&server->refcount) == 1);
00761 #else
00762   _dbus_assert (server->refcount.value > 0);
00763 
00764   server->refcount.value -= 1;
00765   last_unref = (server->refcount.value == 0);
00766 #endif
00767   
00768   if (last_unref)
00769     {
00770       _dbus_assert (server->disconnected);
00771       
00772       SERVER_UNLOCK (server);
00773       
00774       _dbus_assert (server->vtable->finalize != NULL);
00775       
00776       (* server->vtable->finalize) (server);
00777     }
00778 }
00779 
00788 void
00789 dbus_server_disconnect (DBusServer *server)
00790 {
00791   _dbus_return_if_fail (server != NULL);
00792   _dbus_return_if_fail (server->refcount.value > 0);
00793 
00794   SERVER_LOCK (server);
00795   _dbus_server_ref_unlocked (server);
00796   
00797   _dbus_assert (server->vtable->disconnect != NULL);
00798 
00799   if (!server->disconnected)
00800     {
00801       /* this has to be first so recursive calls to disconnect don't happen */
00802       server->disconnected = TRUE;
00803       
00804       (* server->vtable->disconnect) (server);
00805     }
00806 
00807   SERVER_UNLOCK (server);
00808   dbus_server_unref (server);
00809 }
00810 
00816 dbus_bool_t
00817 dbus_server_get_is_connected (DBusServer *server)
00818 {
00819   dbus_bool_t retval;
00820   
00821   _dbus_return_val_if_fail (server != NULL, FALSE);
00822 
00823   SERVER_LOCK (server);
00824   retval = !server->disconnected;
00825   SERVER_UNLOCK (server);
00826 
00827   return retval;
00828 }
00829 
00837 char*
00838 dbus_server_get_address (DBusServer *server)
00839 {
00840   char *retval;
00841   
00842   _dbus_return_val_if_fail (server != NULL, NULL);
00843 
00844   SERVER_LOCK (server);
00845   retval = _dbus_strdup (server->address);
00846   SERVER_UNLOCK (server);
00847 
00848   return retval;
00849 }
00850 
00863 void
00864 dbus_server_set_new_connection_function (DBusServer                *server,
00865                                          DBusNewConnectionFunction  function,
00866                                          void                      *data,
00867                                          DBusFreeFunction           free_data_function)
00868 {
00869   DBusFreeFunction old_free_function;
00870   void *old_data;
00871   
00872   _dbus_return_if_fail (server != NULL);
00873 
00874   SERVER_LOCK (server);
00875   old_free_function = server->new_connection_free_data_function;
00876   old_data = server->new_connection_data;
00877   
00878   server->new_connection_function = function;
00879   server->new_connection_data = data;
00880   server->new_connection_free_data_function = free_data_function;
00881   SERVER_UNLOCK (server);
00882     
00883   if (old_free_function != NULL)
00884     (* old_free_function) (old_data);
00885 }
00886 
00903 dbus_bool_t
00904 dbus_server_set_watch_functions (DBusServer              *server,
00905                                  DBusAddWatchFunction     add_function,
00906                                  DBusRemoveWatchFunction  remove_function,
00907                                  DBusWatchToggledFunction toggled_function,
00908                                  void                    *data,
00909                                  DBusFreeFunction         free_data_function)
00910 {
00911   dbus_bool_t result;
00912   DBusWatchList *watches;
00913   
00914   _dbus_return_val_if_fail (server != NULL, FALSE);
00915 
00916   SERVER_LOCK (server);
00917   watches = server->watches;
00918   server->watches = NULL;
00919   if (watches)
00920     {
00921       SERVER_UNLOCK (server);
00922       result = _dbus_watch_list_set_functions (watches,
00923                                                add_function,
00924                                                remove_function,
00925                                                toggled_function,
00926                                                data,
00927                                                free_data_function);
00928       SERVER_LOCK (server);
00929     }
00930   else
00931     {
00932       _dbus_warn ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
00933       result = FALSE;
00934     }
00935   server->watches = watches;
00936   SERVER_UNLOCK (server);
00937   
00938   return result;
00939 }
00940 
00956 dbus_bool_t
00957 dbus_server_set_timeout_functions (DBusServer                *server,
00958                                    DBusAddTimeoutFunction     add_function,
00959                                    DBusRemoveTimeoutFunction  remove_function,
00960                                    DBusTimeoutToggledFunction toggled_function,
00961                                    void                      *data,
00962                                    DBusFreeFunction           free_data_function)
00963 {
00964   dbus_bool_t result;
00965   DBusTimeoutList *timeouts;
00966   
00967   _dbus_return_val_if_fail (server != NULL, FALSE);
00968 
00969   SERVER_LOCK (server);
00970   timeouts = server->timeouts;
00971   server->timeouts = NULL;
00972   if (timeouts)
00973     {
00974       SERVER_UNLOCK (server);
00975       result = _dbus_timeout_list_set_functions (timeouts,
00976                                                  add_function,
00977                                                  remove_function,
00978                                                  toggled_function,
00979                                                  data,
00980                                                  free_data_function);
00981       SERVER_LOCK (server);
00982     }
00983   else
00984     {
00985       _dbus_warn ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
00986       result = FALSE;
00987     }
00988   server->timeouts = timeouts;
00989   SERVER_UNLOCK (server);
00990   
00991   return result;
00992 }
00993 
01004 dbus_bool_t
01005 dbus_server_set_auth_mechanisms (DBusServer  *server,
01006                                  const char **mechanisms)
01007 {
01008   char **copy;
01009 
01010   _dbus_return_val_if_fail (server != NULL, FALSE);
01011 
01012   SERVER_LOCK (server);
01013   
01014   if (mechanisms != NULL)
01015     {
01016       copy = _dbus_dup_string_array (mechanisms);
01017       if (copy == NULL)
01018         return FALSE;
01019     }
01020   else
01021     copy = NULL;
01022 
01023   dbus_free_string_array (server->auth_mechanisms);
01024   server->auth_mechanisms = copy;
01025 
01026   SERVER_UNLOCK (server);
01027   
01028   return TRUE;
01029 }
01030 
01031 
01032 static DBusDataSlotAllocator slot_allocator;
01033 _DBUS_DEFINE_GLOBAL_LOCK (server_slots);
01034 
01049 dbus_bool_t
01050 dbus_server_allocate_data_slot (dbus_int32_t *slot_p)
01051 {
01052   return _dbus_data_slot_allocator_alloc (&slot_allocator,
01053                                           (DBusMutex **)&_DBUS_LOCK_NAME (server_slots),
01054                                           slot_p);
01055 }
01056 
01068 void
01069 dbus_server_free_data_slot (dbus_int32_t *slot_p)
01070 {
01071   _dbus_return_if_fail (*slot_p >= 0);
01072   
01073   _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
01074 }
01075 
01089 dbus_bool_t
01090 dbus_server_set_data (DBusServer       *server,
01091                       int               slot,
01092                       void             *data,
01093                       DBusFreeFunction  free_data_func)
01094 {
01095   DBusFreeFunction old_free_func;
01096   void *old_data;
01097   dbus_bool_t retval;
01098 
01099   _dbus_return_val_if_fail (server != NULL, FALSE);
01100 
01101   SERVER_LOCK (server);
01102   
01103   retval = _dbus_data_slot_list_set (&slot_allocator,
01104                                      &server->slot_list,
01105                                      slot, data, free_data_func,
01106                                      &old_free_func, &old_data);
01107 
01108 
01109   SERVER_UNLOCK (server);
01110   
01111   if (retval)
01112     {
01113       /* Do the actual free outside the server lock */
01114       if (old_free_func)
01115         (* old_free_func) (old_data);
01116     }
01117 
01118   return retval;
01119 }
01120 
01129 void*
01130 dbus_server_get_data (DBusServer   *server,
01131                       int           slot)
01132 {
01133   void *res;
01134 
01135   _dbus_return_val_if_fail (server != NULL, NULL);
01136   
01137   SERVER_LOCK (server);
01138   
01139   res = _dbus_data_slot_list_get (&slot_allocator,
01140                                   &server->slot_list,
01141                                   slot);
01142 
01143   SERVER_UNLOCK (server);
01144   
01145   return res;
01146 }
01147 
01150 #ifdef DBUS_BUILD_TESTS
01151 #include "dbus-test.h"
01152 
01153 dbus_bool_t
01154 _dbus_server_test (void)
01155 {
01156   const char *valid_addresses[] = {
01157     "tcp:port=1234",
01158     "unix:path=./boogie",
01159     "tcp:host=localhost,port=1234",
01160     "tcp:host=localhost,port=1234;tcp:port=5678",
01161     "tcp:port=1234;unix:path=./boogie",
01162   };
01163 
01164   DBusServer *server;
01165   int i;
01166   
01167   for (i = 0; i < _DBUS_N_ELEMENTS (valid_addresses); i++)
01168     {
01169       server = dbus_server_listen (valid_addresses[i], NULL);
01170       if (server == NULL)
01171         _dbus_assert_not_reached ("Failed to listen for valid address.");
01172 
01173       dbus_server_disconnect (server);
01174       dbus_server_unref (server);
01175 
01176       /* Try disconnecting before unreffing */
01177       server = dbus_server_listen (valid_addresses[i], NULL);
01178       if (server == NULL)
01179         _dbus_assert_not_reached ("Failed to listen for valid address.");
01180 
01181       dbus_server_disconnect (server);
01182       dbus_server_unref (server);
01183     }
01184 
01185   return TRUE;
01186 }
01187 
01188 #endif /* DBUS_BUILD_TESTS */

Generated on Wed Jan 3 04:58:29 2007 for D-Bus by  doxygen 1.4.7