00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
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)
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)
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
00369
00370
00371
00372
00373
00374
00375
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
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
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