Main Page | Modules | Data Structures | Directories | File List | Data Fields | Related Pages

dbus-server.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-server.c DBusServer object
00003  *
00004  * Copyright (C) 2002, 2003, 2004 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 
00064 dbus_bool_t
00065 _dbus_server_init_base (DBusServer             *server,
00066                         const DBusServerVTable *vtable,
00067                         const DBusString       *address)
00068 {
00069   server->vtable = vtable;
00070   server->refcount.value = 1;
00071 
00072   server->address = NULL;
00073   server->watches = NULL;
00074   server->timeouts = NULL;
00075   
00076   if (!_dbus_string_copy_data (address, &server->address))
00077     goto failed;
00078 
00079   server->mutex = dbus_mutex_new ();
00080   if (server->mutex == NULL)
00081     goto failed;
00082   
00083   server->watches = _dbus_watch_list_new ();
00084   if (server->watches == NULL)
00085     goto failed;
00086 
00087   server->timeouts = _dbus_timeout_list_new ();
00088   if (server->timeouts == NULL)
00089     goto failed;
00090 
00091   _dbus_data_slot_list_init (&server->slot_list);
00092 
00093   _dbus_verbose ("Initialized server on address %s\n", server->address);
00094   
00095   return TRUE;
00096 
00097  failed:
00098   if (server->mutex)
00099     {
00100       dbus_mutex_free (server->mutex);
00101       server->mutex = NULL;
00102     }
00103   if (server->watches)
00104     {
00105       _dbus_watch_list_free (server->watches);
00106       server->watches = NULL;
00107     }
00108   if (server->timeouts)
00109     {
00110       _dbus_timeout_list_free (server->timeouts);
00111       server->timeouts = NULL;
00112     }
00113   if (server->address)
00114     {
00115       dbus_free (server->address);
00116       server->address = NULL;
00117     }
00118   
00119   return FALSE;
00120 }
00121 
00128 void
00129 _dbus_server_finalize_base (DBusServer *server)
00130 {  
00131   /* calls out to application code... */
00132   _dbus_data_slot_list_free (&server->slot_list);
00133 
00134   dbus_server_set_new_connection_function (server, NULL, NULL, NULL);
00135 
00136   if (!server->disconnected)
00137     dbus_server_disconnect (server);
00138 
00139   _dbus_watch_list_free (server->watches);
00140   _dbus_timeout_list_free (server->timeouts);
00141 
00142   dbus_mutex_free (server->mutex);
00143   
00144   dbus_free (server->address);
00145 
00146   dbus_free_string_array (server->auth_mechanisms);
00147 }
00148 
00156 dbus_bool_t
00157 _dbus_server_add_watch (DBusServer *server,
00158                         DBusWatch  *watch)
00159 {
00160   HAVE_LOCK_CHECK (server);
00161   return _dbus_watch_list_add_watch (server->watches, watch);
00162 }
00163 
00170 void
00171 _dbus_server_remove_watch  (DBusServer *server,
00172                             DBusWatch  *watch)
00173 {
00174   HAVE_LOCK_CHECK (server);
00175   _dbus_watch_list_remove_watch (server->watches, watch);
00176 }
00177 
00187 void
00188 _dbus_server_toggle_watch (DBusServer  *server,
00189                            DBusWatch   *watch,
00190                            dbus_bool_t  enabled)
00191 {
00192   HAVE_LOCK_CHECK (server);
00193   
00194   if (server->watches) /* null during finalize */
00195     _dbus_watch_list_toggle_watch (server->watches,
00196                                    watch, enabled);
00197 }
00198 
00208 dbus_bool_t
00209 _dbus_server_add_timeout (DBusServer  *server,
00210                           DBusTimeout *timeout)
00211 {
00212   HAVE_LOCK_CHECK (server);
00213   
00214   return _dbus_timeout_list_add_timeout (server->timeouts, timeout);
00215 }
00216 
00223 void
00224 _dbus_server_remove_timeout (DBusServer  *server,
00225                              DBusTimeout *timeout)
00226 {
00227   HAVE_LOCK_CHECK (server);
00228   
00229   _dbus_timeout_list_remove_timeout (server->timeouts, timeout);  
00230 }
00231 
00241 void
00242 _dbus_server_toggle_timeout (DBusServer  *server,
00243                              DBusTimeout *timeout,
00244                              dbus_bool_t  enabled)
00245 {
00246   HAVE_LOCK_CHECK (server);
00247   
00248   if (server->timeouts) /* null during finalize */
00249     _dbus_timeout_list_toggle_timeout (server->timeouts,
00250                                        timeout, enabled);
00251 }
00252 
00253 
00291 DBusServer*
00292 dbus_server_listen (const char     *address,
00293                     DBusError      *error)
00294 {
00295   DBusServer *server;
00296   DBusAddressEntry **entries;
00297   int len, i;
00298   const char *address_problem_type;
00299   const char *address_problem_field;
00300   const char *address_problem_other;
00301 
00302   _dbus_return_val_if_fail (address != NULL, NULL);
00303   _dbus_return_val_if_error_is_set (error, NULL);
00304   
00305   if (!dbus_parse_address (address, &entries, &len, error))
00306     return NULL;
00307 
00308   server = NULL;
00309   address_problem_type = NULL;
00310   address_problem_field = NULL;
00311   address_problem_other = NULL;
00312   
00313   for (i = 0; i < len; i++)
00314     {
00315       const char *method = dbus_address_entry_get_method (entries[i]);
00316 
00317       if (strcmp (method, "unix") == 0)
00318         {
00319           const char *path = dbus_address_entry_get_value (entries[i], "path");
00320           const char *tmpdir = dbus_address_entry_get_value (entries[i], "tmpdir");
00321           const char *abstract = dbus_address_entry_get_value (entries[i], "abstract");
00322           
00323           if (path == NULL && tmpdir == NULL && abstract == NULL)
00324             {
00325               address_problem_type = "unix";
00326               address_problem_field = "path or tmpdir or abstract";
00327               goto bad_address;
00328             }
00329 
00330           if ((path && tmpdir) ||
00331               (path && abstract) ||
00332               (tmpdir && abstract))
00333             {
00334               address_problem_other = "cannot specify two of \"path\" and \"tmpdir\" and \"abstract\" at the same time";
00335               goto bad_address;
00336             }
00337 
00338           if (tmpdir != NULL)
00339             {
00340               DBusString full_path;
00341               DBusString filename;
00342               
00343               if (!_dbus_string_init (&full_path))
00344                 {
00345                   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00346                   goto out;
00347                 }
00348                   
00349               if (!_dbus_string_init (&filename))
00350                 {
00351                   _dbus_string_free (&full_path);
00352                   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00353                   goto out;
00354                 }
00355               
00356               if (!_dbus_string_append (&filename,
00357                                         "dbus-") ||
00358                   !_dbus_generate_random_ascii (&filename, 10) ||
00359                   !_dbus_string_append (&full_path, tmpdir) ||
00360                   !_dbus_concat_dir_and_file (&full_path, &filename))
00361                 {
00362                   _dbus_string_free (&full_path);
00363                   _dbus_string_free (&filename);
00364                   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00365                   goto out;
00366                 }
00367               
00368               /* FIXME - we will unconditionally unlink() the path if
00369                * we don't support abstract namespace.  unlink() does
00370                * not follow symlinks, but would like independent
00371                * confirmation this is safe enough. See also
00372                * _dbus_listen_unix_socket() and comments therein.
00373                */
00374 
00375               /* Always use abstract namespace if possible with tmpdir */
00376               
00377               server =
00378                 _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path),
00379 #ifdef HAVE_ABSTRACT_SOCKETS
00380                                                     TRUE,
00381 #else
00382                                                     FALSE,
00383 #endif
00384                                                     error);
00385 
00386               _dbus_string_free (&full_path);
00387               _dbus_string_free (&filename);
00388             }
00389           else
00390             {
00391               if (path)
00392                 server = _dbus_server_new_for_domain_socket (path, FALSE, error);
00393               else
00394                 server = _dbus_server_new_for_domain_socket (abstract, TRUE, error);
00395             }
00396         }
00397       else if (strcmp (method, "tcp") == 0)
00398         {
00399           const char *host = dbus_address_entry_get_value (entries[i], "host");
00400           const char *port = dbus_address_entry_get_value (entries[i], "port");
00401           DBusString  str;
00402           long lport;
00403           dbus_bool_t sresult;
00404           
00405           if (port == NULL)
00406             {
00407               address_problem_type = "tcp";
00408               address_problem_field = "port";
00409               goto bad_address;
00410             }
00411 
00412           _dbus_string_init_const (&str, port);
00413           sresult = _dbus_string_parse_int (&str, 0, &lport, NULL);
00414           _dbus_string_free (&str);
00415           
00416           if (sresult == FALSE || lport <= 0 || lport > 65535)
00417             {
00418               address_problem_other = "Port is not an integer between 0 and 65535";
00419               goto bad_address;
00420             }
00421           
00422           server = _dbus_server_new_for_tcp_socket (host, lport, error);
00423 
00424           if (server)
00425             break;
00426         }
00427 #ifdef DBUS_BUILD_TESTS
00428       else if (strcmp (method, "debug-pipe") == 0)
00429         {
00430           const char *name = dbus_address_entry_get_value (entries[i], "name");
00431 
00432           if (name == NULL)
00433             {
00434               address_problem_type = "debug-pipe";
00435               address_problem_field = "name";
00436               goto bad_address;
00437             }
00438 
00439           server = _dbus_server_debug_pipe_new (name, error);
00440         }
00441 #endif
00442       else
00443         {
00444           address_problem_other = "Unknown address type (examples of valid types are \"unix\" and \"tcp\")";
00445           goto bad_address;
00446         }
00447       
00448       if (server)
00449         break;
00450     }
00451 
00452  out:
00453   
00454   dbus_address_entries_free (entries);
00455   return server;
00456 
00457  bad_address:
00458   dbus_address_entries_free (entries);
00459   if (address_problem_type != NULL)
00460     dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
00461                     "Server address of type %s was missing argument %s",
00462                     address_problem_type, address_problem_field);
00463   else
00464     dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
00465                     "Could not parse server address: %s",
00466                     address_problem_other);
00467 
00468   return NULL;
00469 }
00470 
00477 DBusServer *
00478 dbus_server_ref (DBusServer *server)
00479 {
00480   _dbus_return_val_if_fail (server != NULL, NULL);
00481 
00482 #ifdef DBUS_HAVE_ATOMIC_INT
00483   _dbus_atomic_inc (&server->refcount);
00484 #else
00485   SERVER_LOCK (server);
00486   _dbus_assert (server->refcount.value > 0);
00487 
00488   server->refcount.value += 1;
00489   SERVER_UNLOCK (server);
00490 #endif
00491 
00492   return server;
00493 }
00494 
00503 void
00504 dbus_server_unref (DBusServer *server)
00505 {
00506   dbus_bool_t last_unref;
00507   
00508   _dbus_return_if_fail (server != NULL);
00509 
00510 #ifdef DBUS_HAVE_ATOMIC_INT
00511   last_unref = (_dbus_atomic_dec (&server->refcount) == 1);
00512 #else
00513   SERVER_LOCK (server);
00514   
00515   _dbus_assert (server->refcount.value > 0);
00516 
00517   server->refcount.value -= 1;
00518   last_unref = (server->refcount.value == 0);
00519   
00520   SERVER_UNLOCK (server);
00521 #endif
00522   
00523   if (last_unref)
00524     {
00525       _dbus_assert (server->vtable->finalize != NULL);
00526       
00527       (* server->vtable->finalize) (server);
00528     }
00529 }
00530 
00536 void
00537 _dbus_server_ref_unlocked (DBusServer *server)
00538 {
00539   HAVE_LOCK_CHECK (server);
00540 
00541 #ifdef DBUS_HAVE_ATOMIC_INT
00542   _dbus_atomic_inc (&server->refcount);
00543 #else
00544   _dbus_assert (server->refcount.value > 0);
00545 
00546   server->refcount.value += 1;
00547 #endif
00548 }
00549 
00558 void
00559 dbus_server_disconnect (DBusServer *server)
00560 {
00561   _dbus_return_if_fail (server != NULL);
00562 
00563   SERVER_LOCK (server);
00564   
00565   _dbus_assert (server->vtable->disconnect != NULL);
00566 
00567   if (server->disconnected)
00568     return;
00569   
00570   (* server->vtable->disconnect) (server);
00571   server->disconnected = TRUE;
00572 
00573   SERVER_UNLOCK (server);
00574 }
00575 
00581 dbus_bool_t
00582 dbus_server_get_is_connected (DBusServer *server)
00583 {
00584   dbus_bool_t retval;
00585   
00586   _dbus_return_val_if_fail (server != NULL, FALSE);
00587 
00588   SERVER_LOCK (server);
00589   retval = !server->disconnected;
00590   SERVER_UNLOCK (server);
00591 
00592   return retval;
00593 }
00594 
00602 char*
00603 dbus_server_get_address (DBusServer *server)
00604 {
00605   char *retval;
00606   
00607   _dbus_return_val_if_fail (server != NULL, NULL);
00608 
00609   SERVER_LOCK (server);
00610   retval = _dbus_strdup (server->address);
00611   SERVER_UNLOCK (server);
00612 
00613   return retval;
00614 }
00615 
00628 void
00629 dbus_server_set_new_connection_function (DBusServer                *server,
00630                                          DBusNewConnectionFunction  function,
00631                                          void                      *data,
00632                                          DBusFreeFunction           free_data_function)
00633 {
00634   DBusFreeFunction old_free_function;
00635   void *old_data;
00636   
00637   _dbus_return_if_fail (server != NULL);
00638 
00639   SERVER_LOCK (server);
00640   old_free_function = server->new_connection_free_data_function;
00641   old_data = server->new_connection_data;
00642   
00643   server->new_connection_function = function;
00644   server->new_connection_data = data;
00645   server->new_connection_free_data_function = free_data_function;
00646   SERVER_UNLOCK (server);
00647     
00648   if (old_free_function != NULL)
00649     (* old_free_function) (old_data);
00650 }
00651 
00668 dbus_bool_t
00669 dbus_server_set_watch_functions (DBusServer              *server,
00670                                  DBusAddWatchFunction     add_function,
00671                                  DBusRemoveWatchFunction  remove_function,
00672                                  DBusWatchToggledFunction toggled_function,
00673                                  void                    *data,
00674                                  DBusFreeFunction         free_data_function)
00675 {
00676   dbus_bool_t result;
00677   DBusWatchList *watches;
00678   
00679   _dbus_return_val_if_fail (server != NULL, FALSE);
00680 
00681   SERVER_LOCK (server);
00682   watches = server->watches;
00683   server->watches = NULL;
00684   if (watches)
00685     {
00686       SERVER_UNLOCK (server);
00687       result = _dbus_watch_list_set_functions (watches,
00688                                                add_function,
00689                                                remove_function,
00690                                                toggled_function,
00691                                                data,
00692                                                free_data_function);
00693       SERVER_LOCK (server);
00694     }
00695   else
00696     {
00697       _dbus_warn ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
00698       result = FALSE;
00699     }
00700   server->watches = watches;
00701   SERVER_UNLOCK (server);
00702   
00703   return result;
00704 }
00705 
00721 dbus_bool_t
00722 dbus_server_set_timeout_functions (DBusServer                *server,
00723                                    DBusAddTimeoutFunction     add_function,
00724                                    DBusRemoveTimeoutFunction  remove_function,
00725                                    DBusTimeoutToggledFunction toggled_function,
00726                                    void                      *data,
00727                                    DBusFreeFunction           free_data_function)
00728 {
00729   dbus_bool_t result;
00730   DBusTimeoutList *timeouts;
00731   
00732   _dbus_return_val_if_fail (server != NULL, FALSE);
00733 
00734   SERVER_LOCK (server);
00735   timeouts = server->timeouts;
00736   server->timeouts = NULL;
00737   if (timeouts)
00738     {
00739       SERVER_UNLOCK (server);
00740       result = _dbus_timeout_list_set_functions (timeouts,
00741                                                  add_function,
00742                                                  remove_function,
00743                                                  toggled_function,
00744                                                  data,
00745                                                  free_data_function);
00746       SERVER_LOCK (server);
00747     }
00748   else
00749     {
00750       _dbus_warn ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
00751       result = FALSE;
00752     }
00753   server->timeouts = timeouts;
00754   SERVER_UNLOCK (server);
00755   
00756   return result;
00757 }
00758 
00769 dbus_bool_t
00770 dbus_server_set_auth_mechanisms (DBusServer  *server,
00771                                  const char **mechanisms)
00772 {
00773   char **copy;
00774 
00775   _dbus_return_val_if_fail (server != NULL, FALSE);
00776 
00777   SERVER_LOCK (server);
00778   
00779   if (mechanisms != NULL)
00780     {
00781       copy = _dbus_dup_string_array (mechanisms);
00782       if (copy == NULL)
00783         return FALSE;
00784     }
00785   else
00786     copy = NULL;
00787 
00788   dbus_free_string_array (server->auth_mechanisms);
00789   server->auth_mechanisms = copy;
00790 
00791   SERVER_UNLOCK (server);
00792   
00793   return TRUE;
00794 }
00795 
00796 
00797 static DBusDataSlotAllocator slot_allocator;
00798 _DBUS_DEFINE_GLOBAL_LOCK (server_slots);
00799 
00814 dbus_bool_t
00815 dbus_server_allocate_data_slot (dbus_int32_t *slot_p)
00816 {
00817   return _dbus_data_slot_allocator_alloc (&slot_allocator,
00818                                           _DBUS_LOCK_NAME (server_slots),
00819                                           slot_p);
00820 }
00821 
00833 void
00834 dbus_server_free_data_slot (dbus_int32_t *slot_p)
00835 {
00836   _dbus_return_if_fail (*slot_p >= 0);
00837   
00838   _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
00839 }
00840 
00854 dbus_bool_t
00855 dbus_server_set_data (DBusServer       *server,
00856                       int               slot,
00857                       void             *data,
00858                       DBusFreeFunction  free_data_func)
00859 {
00860   DBusFreeFunction old_free_func;
00861   void *old_data;
00862   dbus_bool_t retval;
00863 
00864   _dbus_return_val_if_fail (server != NULL, FALSE);
00865 
00866   SERVER_LOCK (server);
00867   
00868   retval = _dbus_data_slot_list_set (&slot_allocator,
00869                                      &server->slot_list,
00870                                      slot, data, free_data_func,
00871                                      &old_free_func, &old_data);
00872 
00873 
00874   SERVER_UNLOCK (server);
00875   
00876   if (retval)
00877     {
00878       /* Do the actual free outside the server lock */
00879       if (old_free_func)
00880         (* old_free_func) (old_data);
00881     }
00882 
00883   return retval;
00884 }
00885 
00894 void*
00895 dbus_server_get_data (DBusServer   *server,
00896                       int           slot)
00897 {
00898   void *res;
00899 
00900   _dbus_return_val_if_fail (server != NULL, NULL);
00901   
00902   SERVER_LOCK (server);
00903   
00904   res = _dbus_data_slot_list_get (&slot_allocator,
00905                                   &server->slot_list,
00906                                   slot);
00907 
00908   SERVER_UNLOCK (server);
00909   
00910   return res;
00911 }
00912 
00915 #ifdef DBUS_BUILD_TESTS
00916 #include "dbus-test.h"
00917 
00918 dbus_bool_t
00919 _dbus_server_test (void)
00920 {
00921   const char *valid_addresses[] = {
00922     "tcp:port=1234",
00923     "unix:path=./boogie",
00924     "tcp:host=localhost,port=1234",
00925     "tcp:host=localhost,port=1234;tcp:port=5678",
00926     "tcp:port=1234;unix:path=./boogie",
00927   };
00928 
00929   DBusServer *server;
00930   int i;
00931   
00932   for (i = 0; i < _DBUS_N_ELEMENTS (valid_addresses); i++)
00933     {
00934       server = dbus_server_listen (valid_addresses[i], NULL);
00935       if (server == NULL)
00936         _dbus_assert_not_reached ("Failed to listen for valid address.");
00937 
00938       dbus_server_unref (server);
00939 
00940       /* Try disconnecting before unreffing */
00941       server = dbus_server_listen (valid_addresses[i], NULL);
00942       if (server == NULL)
00943         _dbus_assert_not_reached ("Failed to listen for valid address.");
00944 
00945       dbus_server_disconnect (server);
00946 
00947       dbus_server_unref (server);
00948     }
00949 
00950   return TRUE;
00951 }
00952 
00953 #endif /* DBUS_BUILD_TESTS */

Generated on Mon Apr 4 04:40:47 2005 for D-BUS by  doxygen 1.4.0