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 Tue Oct 12 02:07:53 2004 for D-BUS by doxygen 1.3.7