Main Page | Modules | Data Structures | 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 = 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->watches = _dbus_watch_list_new ();
00080   if (server->watches == NULL)
00081     goto failed;
00082 
00083   server->timeouts = _dbus_timeout_list_new ();
00084   if (server->timeouts == NULL)
00085     goto failed;
00086 
00087   _dbus_data_slot_list_init (&server->slot_list);
00088 
00089   _dbus_verbose ("Initialized server on address %s\n", server->address);
00090   
00091   return TRUE;
00092 
00093  failed:
00094   if (server->watches)
00095     {
00096       _dbus_watch_list_free (server->watches);
00097       server->watches = NULL;
00098     }
00099   if (server->timeouts)
00100     {
00101       _dbus_timeout_list_free (server->timeouts);
00102       server->timeouts = NULL;
00103     }
00104   if (server->address)
00105     {
00106       dbus_free (server->address);
00107       server->address = NULL;
00108     }
00109   
00110   return FALSE;
00111 }
00112 
00119 void
00120 _dbus_server_finalize_base (DBusServer *server)
00121 {
00122   /* calls out to application code... */
00123   _dbus_data_slot_list_free (&server->slot_list);
00124 
00125   dbus_server_set_new_connection_function (server, NULL, NULL, NULL);
00126 
00127   if (!server->disconnected)
00128     dbus_server_disconnect (server);
00129 
00130   _dbus_watch_list_free (server->watches);
00131   _dbus_timeout_list_free (server->timeouts);
00132 
00133   dbus_free (server->address);
00134 
00135   dbus_free_string_array (server->auth_mechanisms);
00136 }
00137 
00145 dbus_bool_t
00146 _dbus_server_add_watch (DBusServer *server,
00147                         DBusWatch  *watch)
00148 {
00149   return _dbus_watch_list_add_watch (server->watches, watch);
00150 }
00151 
00158 void
00159 _dbus_server_remove_watch  (DBusServer *server,
00160                             DBusWatch  *watch)
00161 {
00162   _dbus_watch_list_remove_watch (server->watches, watch);
00163 }
00164 
00174 void
00175 _dbus_server_toggle_watch (DBusServer  *server,
00176                            DBusWatch   *watch,
00177                            dbus_bool_t  enabled)
00178 {
00179   if (server->watches) /* null during finalize */
00180     _dbus_watch_list_toggle_watch (server->watches,
00181                                    watch, enabled);
00182 }
00183 
00193 dbus_bool_t
00194 _dbus_server_add_timeout (DBusServer  *server,
00195                           DBusTimeout *timeout)
00196 {
00197   return _dbus_timeout_list_add_timeout (server->timeouts, timeout);
00198 }
00199 
00206 void
00207 _dbus_server_remove_timeout (DBusServer  *server,
00208                              DBusTimeout *timeout)
00209 {
00210   _dbus_timeout_list_remove_timeout (server->timeouts, timeout);  
00211 }
00212 
00222 void
00223 _dbus_server_toggle_timeout (DBusServer  *server,
00224                              DBusTimeout *timeout,
00225                              dbus_bool_t  enabled)
00226 {
00227   if (server->timeouts) /* null during finalize */
00228     _dbus_timeout_list_toggle_timeout (server->timeouts,
00229                                        timeout, enabled);
00230 }
00231 
00232 
00270 DBusServer*
00271 dbus_server_listen (const char     *address,
00272                     DBusError      *error)
00273 {
00274   DBusServer *server;
00275   DBusAddressEntry **entries;
00276   int len, i;
00277   const char *address_problem_type;
00278   const char *address_problem_field;
00279   const char *address_problem_other;
00280 
00281   _dbus_return_val_if_fail (address != NULL, NULL);
00282   _dbus_return_val_if_error_is_set (error, NULL);
00283   
00284   if (!dbus_parse_address (address, &entries, &len, error))
00285     return NULL;
00286 
00287   server = NULL;
00288   address_problem_type = NULL;
00289   address_problem_field = NULL;
00290   address_problem_other = NULL;
00291   
00292   for (i = 0; i < len; i++)
00293     {
00294       const char *method = dbus_address_entry_get_method (entries[i]);
00295 
00296       if (strcmp (method, "unix") == 0)
00297         {
00298           const char *path = dbus_address_entry_get_value (entries[i], "path");
00299           const char *tmpdir = dbus_address_entry_get_value (entries[i], "tmpdir");
00300           const char *abstract = dbus_address_entry_get_value (entries[i], "abstract");
00301           
00302           if (path == NULL && tmpdir == NULL && abstract == NULL)
00303             {
00304               address_problem_type = "unix";
00305               address_problem_field = "path or tmpdir or abstract";
00306               goto bad_address;
00307             }
00308 
00309           if ((path && tmpdir) ||
00310               (path && abstract) ||
00311               (tmpdir && abstract))
00312             {
00313               address_problem_other = "cannot specify two of \"path\" and \"tmpdir\" and \"abstract\" at the same time";
00314               goto bad_address;
00315             }
00316 
00317           if (tmpdir != NULL)
00318             {
00319               DBusString full_path;
00320               DBusString filename;
00321               
00322               if (!_dbus_string_init (&full_path))
00323                 {
00324                   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00325                   goto out;
00326                 }
00327                   
00328               if (!_dbus_string_init (&filename))
00329                 {
00330                   _dbus_string_free (&full_path);
00331                   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00332                   goto out;
00333                 }
00334               
00335               if (!_dbus_string_append (&filename,
00336                                         "dbus-") ||
00337                   !_dbus_generate_random_ascii (&filename, 10) ||
00338                   !_dbus_string_append (&full_path, tmpdir) ||
00339                   !_dbus_concat_dir_and_file (&full_path, &filename))
00340                 {
00341                   _dbus_string_free (&full_path);
00342                   _dbus_string_free (&filename);
00343                   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00344                   goto out;
00345                 }
00346               
00347               /* FIXME - we will unconditionally unlink() the path if
00348                * we don't support abstract namespace.  unlink() does
00349                * not follow symlinks, but would like independent
00350                * confirmation this is safe enough. See also
00351                * _dbus_listen_unix_socket() and comments therein.
00352                */
00353 
00354               /* Always use abstract namespace if possible with tmpdir */
00355               
00356               server =
00357                 _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path),
00358 #ifdef HAVE_ABSTRACT_SOCKETS
00359                                                     TRUE,
00360 #else
00361                                                     FALSE,
00362 #endif
00363                                                     error);
00364 
00365               _dbus_string_free (&full_path);
00366               _dbus_string_free (&filename);
00367             }
00368           else
00369             {
00370               if (path)
00371                 server = _dbus_server_new_for_domain_socket (path, FALSE, error);
00372               else
00373                 server = _dbus_server_new_for_domain_socket (abstract, TRUE, error);
00374             }
00375         }
00376       else if (strcmp (method, "tcp") == 0)
00377         {
00378           const char *host = dbus_address_entry_get_value (entries[i], "host");
00379           const char *port = dbus_address_entry_get_value (entries[i], "port");
00380           DBusString  str;
00381           long lport;
00382           dbus_bool_t sresult;
00383           
00384           if (port == NULL)
00385             {
00386               address_problem_type = "tcp";
00387               address_problem_field = "port";
00388               goto bad_address;
00389             }
00390 
00391           _dbus_string_init_const (&str, port);
00392           sresult = _dbus_string_parse_int (&str, 0, &lport, NULL);
00393           _dbus_string_free (&str);
00394           
00395           if (sresult == FALSE || lport <= 0 || lport > 65535)
00396             {
00397               address_problem_other = "Port is not an integer between 0 and 65535";
00398               goto bad_address;
00399             }
00400           
00401           server = _dbus_server_new_for_tcp_socket (host, lport, error);
00402 
00403           if (server)
00404             break;
00405         }
00406 #ifdef DBUS_BUILD_TESTS
00407       else if (strcmp (method, "debug-pipe") == 0)
00408         {
00409           const char *name = dbus_address_entry_get_value (entries[i], "name");
00410 
00411           if (name == NULL)
00412             {
00413               address_problem_type = "debug-pipe";
00414               address_problem_field = "name";
00415               goto bad_address;
00416             }
00417 
00418           server = _dbus_server_debug_pipe_new (name, error);
00419         }
00420 #endif
00421       else
00422         {
00423           address_problem_other = "Unknown address type (examples of valid types are \"unix\" and \"tcp\")";
00424           goto bad_address;
00425         }
00426       
00427       if (server)
00428         break;
00429     }
00430 
00431  out:
00432   
00433   dbus_address_entries_free (entries);
00434   return server;
00435 
00436  bad_address:
00437   dbus_address_entries_free (entries);
00438   if (address_problem_type != NULL)
00439     dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
00440                     "Server address of type %s was missing argument %s",
00441                     address_problem_type, address_problem_field);
00442   else
00443     dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
00444                     "Could not parse server address: %s",
00445                     address_problem_other);
00446 
00447   return NULL;
00448 }
00449 
00456 DBusServer *
00457 dbus_server_ref (DBusServer *server)
00458 {
00459   _dbus_return_val_if_fail (server != NULL, NULL);
00460   
00461   server->refcount += 1;
00462 
00463   return server;
00464 }
00465 
00474 void
00475 dbus_server_unref (DBusServer *server)
00476 {
00477   _dbus_return_if_fail (server != NULL);
00478 
00479   _dbus_assert (server->refcount > 0);
00480 
00481   server->refcount -= 1;
00482   if (server->refcount == 0)
00483     {
00484       _dbus_assert (server->vtable->finalize != NULL);
00485       
00486       (* server->vtable->finalize) (server);
00487     }
00488 }
00489 
00498 void
00499 dbus_server_disconnect (DBusServer *server)
00500 {
00501   _dbus_return_if_fail (server != NULL);
00502   
00503   _dbus_assert (server->vtable->disconnect != NULL);
00504 
00505   if (server->disconnected)
00506     return;
00507   
00508   (* server->vtable->disconnect) (server);
00509   server->disconnected = TRUE;
00510 }
00511 
00517 dbus_bool_t
00518 dbus_server_get_is_connected (DBusServer *server)
00519 {
00520   _dbus_return_val_if_fail (server != NULL, FALSE);
00521   
00522   return !server->disconnected;
00523 }
00524 
00532 char*
00533 dbus_server_get_address (DBusServer *server)
00534 {
00535   _dbus_return_val_if_fail (server != NULL, NULL);
00536   
00537   return _dbus_strdup (server->address);
00538 }
00539 
00552 void
00553 dbus_server_set_new_connection_function (DBusServer                *server,
00554                                          DBusNewConnectionFunction  function,
00555                                          void                      *data,
00556                                          DBusFreeFunction           free_data_function)
00557 {
00558   _dbus_return_if_fail (server != NULL);
00559   
00560   if (server->new_connection_free_data_function != NULL)
00561     (* server->new_connection_free_data_function) (server->new_connection_data);
00562   
00563   server->new_connection_function = function;
00564   server->new_connection_data = data;
00565   server->new_connection_free_data_function = free_data_function;
00566 }
00567 
00584 dbus_bool_t
00585 dbus_server_set_watch_functions (DBusServer              *server,
00586                                  DBusAddWatchFunction     add_function,
00587                                  DBusRemoveWatchFunction  remove_function,
00588                                  DBusWatchToggledFunction toggled_function,
00589                                  void                    *data,
00590                                  DBusFreeFunction         free_data_function)
00591 {
00592   _dbus_return_val_if_fail (server != NULL, FALSE);
00593   
00594   return _dbus_watch_list_set_functions (server->watches,
00595                                          add_function,
00596                                          remove_function,
00597                                          toggled_function,
00598                                          data,
00599                                          free_data_function);
00600 }
00601 
00617 dbus_bool_t
00618 dbus_server_set_timeout_functions (DBusServer                *server,
00619                                    DBusAddTimeoutFunction     add_function,
00620                                    DBusRemoveTimeoutFunction  remove_function,
00621                                    DBusTimeoutToggledFunction toggled_function,
00622                                    void                      *data,
00623                                    DBusFreeFunction           free_data_function)
00624 {
00625   _dbus_return_val_if_fail (server != NULL, FALSE);
00626   
00627   return _dbus_timeout_list_set_functions (server->timeouts,
00628                                            add_function, remove_function,
00629                                            toggled_function,
00630                                            data, free_data_function); 
00631 }
00632 
00643 dbus_bool_t
00644 dbus_server_set_auth_mechanisms (DBusServer  *server,
00645                                  const char **mechanisms)
00646 {
00647   char **copy;
00648 
00649   _dbus_return_val_if_fail (server != NULL, FALSE);
00650   
00651   if (mechanisms != NULL)
00652     {
00653       copy = _dbus_dup_string_array (mechanisms);
00654       if (copy == NULL)
00655         return FALSE;
00656     }
00657   else
00658     copy = NULL;
00659 
00660   dbus_free_string_array (server->auth_mechanisms);
00661   server->auth_mechanisms = copy;
00662 
00663   return TRUE;
00664 }
00665 
00666 
00667 static DBusDataSlotAllocator slot_allocator;
00668 _DBUS_DEFINE_GLOBAL_LOCK (server_slots);
00669 
00684 dbus_bool_t
00685 dbus_server_allocate_data_slot (dbus_int32_t *slot_p)
00686 {
00687   return _dbus_data_slot_allocator_alloc (&slot_allocator,
00688                                           _DBUS_LOCK_NAME (server_slots),
00689                                           slot_p);
00690 }
00691 
00703 void
00704 dbus_server_free_data_slot (dbus_int32_t *slot_p)
00705 {
00706   _dbus_return_if_fail (*slot_p >= 0);
00707   
00708   _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
00709 }
00710 
00724 dbus_bool_t
00725 dbus_server_set_data (DBusServer       *server,
00726                       int               slot,
00727                       void             *data,
00728                       DBusFreeFunction  free_data_func)
00729 {
00730   DBusFreeFunction old_free_func;
00731   void *old_data;
00732   dbus_bool_t retval;
00733 
00734   _dbus_return_val_if_fail (server != NULL, FALSE);
00735   
00736 #if 0
00737   dbus_mutex_lock (server->mutex);
00738 #endif
00739   
00740   retval = _dbus_data_slot_list_set (&slot_allocator,
00741                                      &server->slot_list,
00742                                      slot, data, free_data_func,
00743                                      &old_free_func, &old_data);
00744 
00745 #if 0
00746   dbus_mutex_unlock (server->mutex);
00747 #endif
00748   
00749   if (retval)
00750     {
00751       /* Do the actual free outside the server lock */
00752       if (old_free_func)
00753         (* old_free_func) (old_data);
00754     }
00755 
00756   return retval;
00757 }
00758 
00767 void*
00768 dbus_server_get_data (DBusServer   *server,
00769                       int           slot)
00770 {
00771   void *res;
00772 
00773   _dbus_return_val_if_fail (server != NULL, NULL);
00774   
00775 #if 0
00776   dbus_mutex_lock (server->mutex);
00777 #endif
00778   
00779   res = _dbus_data_slot_list_get (&slot_allocator,
00780                                   &server->slot_list,
00781                                   slot);
00782 
00783 #if 0
00784   dbus_mutex_unlock (server->mutex);
00785 #endif
00786   
00787   return res;
00788 }
00789 
00792 #ifdef DBUS_BUILD_TESTS
00793 #include "dbus-test.h"
00794 
00795 dbus_bool_t
00796 _dbus_server_test (void)
00797 {
00798   const char *valid_addresses[] = {
00799     "tcp:port=1234",
00800     "unix:path=./boogie",
00801     "tcp:host=localhost,port=1234",
00802     "tcp:host=localhost,port=1234;tcp:port=5678",
00803     "tcp:port=1234;unix:path=./boogie",
00804   };
00805 
00806   DBusServer *server;
00807   int i;
00808   
00809   for (i = 0; i < _DBUS_N_ELEMENTS (valid_addresses); i++)
00810     {
00811       server = dbus_server_listen (valid_addresses[i], NULL);
00812       if (server == NULL)
00813         _dbus_assert_not_reached ("Failed to listen for valid address.");
00814 
00815       dbus_server_unref (server);
00816 
00817       /* Try disconnecting before unreffing */
00818       server = dbus_server_listen (valid_addresses[i], NULL);
00819       if (server == NULL)
00820         _dbus_assert_not_reached ("Failed to listen for valid address.");
00821 
00822       dbus_server_disconnect (server);
00823 
00824       dbus_server_unref (server);
00825     }
00826 
00827   return TRUE;
00828 }
00829 
00830 #endif /* DBUS_BUILD_TESTS */

Generated on Sat Sep 25 19:17:12 2004 for D-BUS by  doxygen 1.3.8-20040913