dbus-server.c revision ee27481d7b7d6d9a4f41b7d641a2618dedf676dd
1/* -*- mode: C; c-file-style: "gnu" -*- */ 2/* dbus-server.c DBusServer object 3 * 4 * Copyright (C) 2002, 2003, 2004, 2005 Red Hat Inc. 5 * 6 * Licensed under the Academic Free License version 2.1 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 */ 23 24#include "dbus-server.h" 25#include "dbus-server-unix.h" 26#include "dbus-string.h" 27#ifdef DBUS_BUILD_TESTS 28#include "dbus-server-debug-pipe.h" 29#endif 30#include "dbus-address.h" 31#include "dbus-protocol.h" 32 33/** 34 * @defgroup DBusServer DBusServer 35 * @ingroup DBus 36 * @brief Server that listens for new connections. 37 * 38 * Types and functions related to DBusServer. 39 * A DBusServer represents a server that other applications 40 * can connect to. Each connection from another application 41 * is represented by a DBusConnection. 42 * 43 * @todo Thread safety hasn't been looked at for #DBusServer 44 * @todo Need notification to apps of disconnection, may matter for some transports 45 */ 46 47/** 48 * @defgroup DBusServerInternals DBusServer implementation details 49 * @ingroup DBusInternals 50 * @brief Implementation details of DBusServer 51 * 52 * @{ 53 */ 54 55static void 56init_guid (DBusGUID *guid) 57{ 58 long now; 59 char *p; 60 int ts_size; 61 62 _dbus_get_current_time (&now, NULL); 63 64 guid->as_uint32s[0] = now; 65 66 ts_size = sizeof (guid->as_uint32s[0]); 67 p = ((char*)guid->as_bytes) + ts_size; 68 69 _dbus_generate_random_bytes_buffer (p, 70 sizeof (guid->as_bytes) - ts_size); 71} 72 73/* this is a little fragile since it assumes the address doesn't 74 * already have a guid, but it shouldn't 75 */ 76static char* 77copy_address_with_guid_appended (const DBusString *address, 78 const DBusString *guid_hex) 79{ 80 DBusString with_guid; 81 char *retval; 82 83 if (!_dbus_string_init (&with_guid)) 84 return NULL; 85 86 if (!_dbus_string_copy (address, 0, &with_guid, 87 _dbus_string_get_length (&with_guid)) || 88 !_dbus_string_append (&with_guid, ",guid=") || 89 !_dbus_string_copy (guid_hex, 0, 90 &with_guid, _dbus_string_get_length (&with_guid))) 91 { 92 _dbus_string_free (&with_guid); 93 return NULL; 94 } 95 96 retval = NULL; 97 _dbus_string_steal_data (&with_guid, &retval); 98 99 _dbus_string_free (&with_guid); 100 101 return retval; /* may be NULL if steal_data failed */ 102} 103 104/** 105 * Initializes the members of the DBusServer base class. 106 * Chained up to by subclass constructors. 107 * 108 * @param server the server. 109 * @param vtable the vtable for the subclass. 110 * @param address the server's address 111 * @returns #TRUE on success. 112 */ 113dbus_bool_t 114_dbus_server_init_base (DBusServer *server, 115 const DBusServerVTable *vtable, 116 const DBusString *address) 117{ 118 DBusString guid_raw; 119 120 server->vtable = vtable; 121 server->refcount.value = 1; 122 123 server->address = NULL; 124 server->watches = NULL; 125 server->timeouts = NULL; 126 127 if (!_dbus_string_init (&server->guid_hex)) 128 return FALSE; 129 130 init_guid (&server->guid); 131 132 _dbus_string_init_const_len (&guid_raw, server->guid.as_bytes, 133 sizeof (server->guid.as_bytes)); 134 if (!_dbus_string_hex_encode (&guid_raw, 0, 135 &server->guid_hex, 136 _dbus_string_get_length (&server->guid_hex))) 137 goto failed; 138 139 server->address = copy_address_with_guid_appended (address, 140 &server->guid_hex); 141 if (server->address == NULL) 142 goto failed; 143 144 server->mutex = _dbus_mutex_new (); 145 if (server->mutex == NULL) 146 goto failed; 147 148 server->watches = _dbus_watch_list_new (); 149 if (server->watches == NULL) 150 goto failed; 151 152 server->timeouts = _dbus_timeout_list_new (); 153 if (server->timeouts == NULL) 154 goto failed; 155 156 _dbus_data_slot_list_init (&server->slot_list); 157 158 _dbus_verbose ("Initialized server on address %s\n", server->address); 159 160 return TRUE; 161 162 failed: 163 if (server->mutex) 164 { 165 _dbus_mutex_free (server->mutex); 166 server->mutex = NULL; 167 } 168 if (server->watches) 169 { 170 _dbus_watch_list_free (server->watches); 171 server->watches = NULL; 172 } 173 if (server->timeouts) 174 { 175 _dbus_timeout_list_free (server->timeouts); 176 server->timeouts = NULL; 177 } 178 if (server->address) 179 { 180 dbus_free (server->address); 181 server->address = NULL; 182 } 183 _dbus_string_free (&server->guid_hex); 184 185 return FALSE; 186} 187 188/** 189 * Finalizes the members of the DBusServer base class. 190 * Chained up to by subclass finalizers. 191 * 192 * @param server the server. 193 */ 194void 195_dbus_server_finalize_base (DBusServer *server) 196{ 197 /* We don't have the lock, but nobody should be accessing 198 * concurrently since they don't have a ref 199 */ 200#ifndef DBUS_DISABLE_CHECKS 201 _dbus_assert (!server->have_server_lock); 202#endif 203 _dbus_assert (server->disconnected); 204 205 /* calls out to application code... */ 206 _dbus_data_slot_list_free (&server->slot_list); 207 208 dbus_server_set_new_connection_function (server, NULL, NULL, NULL); 209 210 _dbus_watch_list_free (server->watches); 211 _dbus_timeout_list_free (server->timeouts); 212 213 _dbus_mutex_free (server->mutex); 214 215 dbus_free (server->address); 216 217 dbus_free_string_array (server->auth_mechanisms); 218 219 _dbus_string_free (&server->guid_hex); 220} 221 222 223typedef dbus_bool_t (* DBusWatchAddFunction) (DBusWatchList *list, 224 DBusWatch *watch); 225typedef void (* DBusWatchRemoveFunction) (DBusWatchList *list, 226 DBusWatch *watch); 227typedef void (* DBusWatchToggleFunction) (DBusWatchList *list, 228 DBusWatch *watch, 229 dbus_bool_t enabled); 230 231static dbus_bool_t 232protected_change_watch (DBusServer *server, 233 DBusWatch *watch, 234 DBusWatchAddFunction add_function, 235 DBusWatchRemoveFunction remove_function, 236 DBusWatchToggleFunction toggle_function, 237 dbus_bool_t enabled) 238{ 239 DBusWatchList *watches; 240 dbus_bool_t retval; 241 242 HAVE_LOCK_CHECK (server); 243 244 /* This isn't really safe or reasonable; a better pattern is the "do 245 * everything, then drop lock and call out" one; but it has to be 246 * propagated up through all callers 247 */ 248 249 watches = server->watches; 250 if (watches) 251 { 252 server->watches = NULL; 253 _dbus_server_ref_unlocked (server); 254 SERVER_UNLOCK (server); 255 256 if (add_function) 257 retval = (* add_function) (watches, watch); 258 else if (remove_function) 259 { 260 retval = TRUE; 261 (* remove_function) (watches, watch); 262 } 263 else 264 { 265 retval = TRUE; 266 (* toggle_function) (watches, watch, enabled); 267 } 268 269 SERVER_LOCK (server); 270 server->watches = watches; 271 _dbus_server_unref_unlocked (server); 272 273 return retval; 274 } 275 else 276 return FALSE; 277} 278 279/** 280 * Adds a watch for this server, chaining out to application-provided 281 * watch handlers. 282 * 283 * @param server the server. 284 * @param watch the watch to add. 285 */ 286dbus_bool_t 287_dbus_server_add_watch (DBusServer *server, 288 DBusWatch *watch) 289{ 290 HAVE_LOCK_CHECK (server); 291 return protected_change_watch (server, watch, 292 _dbus_watch_list_add_watch, 293 NULL, NULL, FALSE); 294} 295 296/** 297 * Removes a watch previously added with _dbus_server_remove_watch(). 298 * 299 * @param server the server. 300 * @param watch the watch to remove. 301 */ 302void 303_dbus_server_remove_watch (DBusServer *server, 304 DBusWatch *watch) 305{ 306 HAVE_LOCK_CHECK (server); 307 protected_change_watch (server, watch, 308 NULL, 309 _dbus_watch_list_remove_watch, 310 NULL, FALSE); 311} 312 313/** 314 * Toggles a watch and notifies app via server's 315 * DBusWatchToggledFunction if available. It's an error to call this 316 * function on a watch that was not previously added. 317 * 318 * @param server the server. 319 * @param watch the watch to toggle. 320 * @param enabled whether to enable or disable 321 */ 322void 323_dbus_server_toggle_watch (DBusServer *server, 324 DBusWatch *watch, 325 dbus_bool_t enabled) 326{ 327 _dbus_assert (watch != NULL); 328 329 HAVE_LOCK_CHECK (server); 330 protected_change_watch (server, watch, 331 NULL, NULL, 332 _dbus_watch_list_toggle_watch, 333 enabled); 334} 335 336 337typedef dbus_bool_t (* DBusTimeoutAddFunction) (DBusTimeoutList *list, 338 DBusTimeout *timeout); 339typedef void (* DBusTimeoutRemoveFunction) (DBusTimeoutList *list, 340 DBusTimeout *timeout); 341typedef void (* DBusTimeoutToggleFunction) (DBusTimeoutList *list, 342 DBusTimeout *timeout, 343 dbus_bool_t enabled); 344 345 346static dbus_bool_t 347protected_change_timeout (DBusServer *server, 348 DBusTimeout *timeout, 349 DBusTimeoutAddFunction add_function, 350 DBusTimeoutRemoveFunction remove_function, 351 DBusTimeoutToggleFunction toggle_function, 352 dbus_bool_t enabled) 353{ 354 DBusTimeoutList *timeouts; 355 dbus_bool_t retval; 356 357 HAVE_LOCK_CHECK (server); 358 359 /* This isn't really safe or reasonable; a better pattern is the "do everything, then 360 * drop lock and call out" one; but it has to be propagated up through all callers 361 */ 362 363 timeouts = server->timeouts; 364 if (timeouts) 365 { 366 server->timeouts = NULL; 367 _dbus_server_ref_unlocked (server); 368 SERVER_UNLOCK (server); 369 370 if (add_function) 371 retval = (* add_function) (timeouts, timeout); 372 else if (remove_function) 373 { 374 retval = TRUE; 375 (* remove_function) (timeouts, timeout); 376 } 377 else 378 { 379 retval = TRUE; 380 (* toggle_function) (timeouts, timeout, enabled); 381 } 382 383 SERVER_LOCK (server); 384 server->timeouts = timeouts; 385 _dbus_server_unref_unlocked (server); 386 387 return retval; 388 } 389 else 390 return FALSE; 391} 392 393/** 394 * Adds a timeout for this server, chaining out to 395 * application-provided timeout handlers. The timeout should be 396 * repeatedly handled with dbus_timeout_handle() at its given interval 397 * until it is removed. 398 * 399 * @param server the server. 400 * @param timeout the timeout to add. 401 */ 402dbus_bool_t 403_dbus_server_add_timeout (DBusServer *server, 404 DBusTimeout *timeout) 405{ 406 return protected_change_timeout (server, timeout, 407 _dbus_timeout_list_add_timeout, 408 NULL, NULL, FALSE); 409} 410 411/** 412 * Removes a timeout previously added with _dbus_server_add_timeout(). 413 * 414 * @param server the server. 415 * @param timeout the timeout to remove. 416 */ 417void 418_dbus_server_remove_timeout (DBusServer *server, 419 DBusTimeout *timeout) 420{ 421 protected_change_timeout (server, timeout, 422 NULL, 423 _dbus_timeout_list_remove_timeout, 424 NULL, FALSE); 425} 426 427/** 428 * Toggles a timeout and notifies app via server's 429 * DBusTimeoutToggledFunction if available. It's an error to call this 430 * function on a timeout that was not previously added. 431 * 432 * @param server the server. 433 * @param timeout the timeout to toggle. 434 * @param enabled whether to enable or disable 435 */ 436void 437_dbus_server_toggle_timeout (DBusServer *server, 438 DBusTimeout *timeout, 439 dbus_bool_t enabled) 440{ 441 protected_change_timeout (server, timeout, 442 NULL, NULL, 443 _dbus_timeout_list_toggle_timeout, 444 enabled); 445} 446 447 448/** @} */ 449 450/** 451 * @addtogroup DBusServer 452 * 453 * @{ 454 */ 455 456 457/** 458 * @typedef DBusServer 459 * 460 * An opaque object representing a server that listens for 461 * connections from other applications. Each time a connection 462 * is made, a new DBusConnection is created and made available 463 * via an application-provided DBusNewConnectionFunction. 464 * The DBusNewConnectionFunction is provided with 465 * dbus_server_set_new_connection_function(). 466 * 467 */ 468 469/** 470 * Listens for new connections on the given address. 471 * Returns #NULL if listening fails for any reason. 472 * Otherwise returns a new #DBusServer. 473 * dbus_server_set_new_connection_function() and 474 * dbus_server_set_watch_functions() should be called 475 * immediately to render the server fully functional. 476 * 477 * @todo error messages on bad address could really be better. 478 * DBusResultCode is a bit limiting here. 479 * 480 * @param address the address of this server. 481 * @param error location to store rationale for failure. 482 * @returns a new DBusServer, or #NULL on failure. 483 * 484 */ 485DBusServer* 486dbus_server_listen (const char *address, 487 DBusError *error) 488{ 489 DBusServer *server; 490 DBusAddressEntry **entries; 491 int len, i; 492 const char *address_problem_type; 493 const char *address_problem_field; 494 const char *address_problem_other; 495 496 _dbus_return_val_if_fail (address != NULL, NULL); 497 _dbus_return_val_if_error_is_set (error, NULL); 498 499 if (!dbus_parse_address (address, &entries, &len, error)) 500 return NULL; 501 502 server = NULL; 503 address_problem_type = NULL; 504 address_problem_field = NULL; 505 address_problem_other = NULL; 506 507 for (i = 0; i < len; i++) 508 { 509 const char *method; 510 511 method = dbus_address_entry_get_method (entries[i]); 512 513 if (strcmp (method, "unix") == 0) 514 { 515 const char *path = dbus_address_entry_get_value (entries[i], "path"); 516 const char *tmpdir = dbus_address_entry_get_value (entries[i], "tmpdir"); 517 const char *abstract = dbus_address_entry_get_value (entries[i], "abstract"); 518 519 if (path == NULL && tmpdir == NULL && abstract == NULL) 520 { 521 address_problem_type = "unix"; 522 address_problem_field = "path or tmpdir or abstract"; 523 goto bad_address; 524 } 525 526 if ((path && tmpdir) || 527 (path && abstract) || 528 (tmpdir && abstract)) 529 { 530 address_problem_other = "cannot specify two of \"path\" and \"tmpdir\" and \"abstract\" at the same time"; 531 goto bad_address; 532 } 533 534 if (tmpdir != NULL) 535 { 536 DBusString full_path; 537 DBusString filename; 538 539 if (!_dbus_string_init (&full_path)) 540 { 541 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 542 goto out; 543 } 544 545 if (!_dbus_string_init (&filename)) 546 { 547 _dbus_string_free (&full_path); 548 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 549 goto out; 550 } 551 552 if (!_dbus_string_append (&filename, 553 "dbus-") || 554 !_dbus_generate_random_ascii (&filename, 10) || 555 !_dbus_string_append (&full_path, tmpdir) || 556 !_dbus_concat_dir_and_file (&full_path, &filename)) 557 { 558 _dbus_string_free (&full_path); 559 _dbus_string_free (&filename); 560 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 561 goto out; 562 } 563 564 /* FIXME - we will unconditionally unlink() the path if 565 * we don't support abstract namespace. unlink() does 566 * not follow symlinks, but would like independent 567 * confirmation this is safe enough. See also 568 * _dbus_listen_unix_socket() and comments therein. 569 */ 570 571 /* Always use abstract namespace if possible with tmpdir */ 572 573 server = 574 _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path), 575#ifdef HAVE_ABSTRACT_SOCKETS 576 TRUE, 577#else 578 FALSE, 579#endif 580 error); 581 582 _dbus_string_free (&full_path); 583 _dbus_string_free (&filename); 584 } 585 else 586 { 587 if (path) 588 server = _dbus_server_new_for_domain_socket (path, FALSE, error); 589 else 590 server = _dbus_server_new_for_domain_socket (abstract, TRUE, error); 591 } 592 } 593 else if (strcmp (method, "tcp") == 0) 594 { 595 const char *host = dbus_address_entry_get_value (entries[i], "host"); 596 const char *port = dbus_address_entry_get_value (entries[i], "port"); 597 DBusString str; 598 long lport; 599 dbus_bool_t sresult; 600 601 if (port == NULL) 602 { 603 address_problem_type = "tcp"; 604 address_problem_field = "port"; 605 goto bad_address; 606 } 607 608 _dbus_string_init_const (&str, port); 609 sresult = _dbus_string_parse_int (&str, 0, &lport, NULL); 610 _dbus_string_free (&str); 611 612 if (sresult == FALSE || lport <= 0 || lport > 65535) 613 { 614 address_problem_other = "Port is not an integer between 0 and 65535"; 615 goto bad_address; 616 } 617 618 server = _dbus_server_new_for_tcp_socket (host, lport, error); 619 620 if (server) 621 break; 622 } 623#ifdef DBUS_BUILD_TESTS 624 else if (strcmp (method, "debug-pipe") == 0) 625 { 626 const char *name = dbus_address_entry_get_value (entries[i], "name"); 627 628 if (name == NULL) 629 { 630 address_problem_type = "debug-pipe"; 631 address_problem_field = "name"; 632 goto bad_address; 633 } 634 635 server = _dbus_server_debug_pipe_new (name, error); 636 } 637#endif 638 else 639 { 640 address_problem_other = "Unknown address type (examples of valid types are \"unix\" and \"tcp\")"; 641 goto bad_address; 642 } 643 644 if (server) 645 break; 646 } 647 648 out: 649 650 dbus_address_entries_free (entries); 651 return server; 652 653 bad_address: 654 dbus_address_entries_free (entries); 655 if (address_problem_type != NULL) 656 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, 657 "Server address of type %s was missing argument %s", 658 address_problem_type, address_problem_field); 659 else 660 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, 661 "Could not parse server address: %s", 662 address_problem_other); 663 664 return NULL; 665} 666 667/** 668 * Increments the reference count of a DBusServer. 669 * 670 * @param server the server. 671 * @returns the server 672 */ 673DBusServer * 674dbus_server_ref (DBusServer *server) 675{ 676 _dbus_return_val_if_fail (server != NULL, NULL); 677 _dbus_return_val_if_fail (server->refcount.value > 0, NULL); 678 679#ifdef DBUS_HAVE_ATOMIC_INT 680 _dbus_atomic_inc (&server->refcount); 681#else 682 SERVER_LOCK (server); 683 _dbus_assert (server->refcount.value > 0); 684 685 server->refcount.value += 1; 686 SERVER_UNLOCK (server); 687#endif 688 689 return server; 690} 691 692/** 693 * Decrements the reference count of a DBusServer. Finalizes the 694 * server if the reference count reaches zero. 695 * 696 * The server must be disconnected before the refcount reaches zero. 697 * 698 * @param server the server. 699 */ 700void 701dbus_server_unref (DBusServer *server) 702{ 703 dbus_bool_t last_unref; 704 705 _dbus_return_if_fail (server != NULL); 706 _dbus_return_if_fail (server->refcount.value > 0); 707 708#ifdef DBUS_HAVE_ATOMIC_INT 709 last_unref = (_dbus_atomic_dec (&server->refcount) == 1); 710#else 711 SERVER_LOCK (server); 712 713 _dbus_assert (server->refcount.value > 0); 714 715 server->refcount.value -= 1; 716 last_unref = (server->refcount.value == 0); 717 718 SERVER_UNLOCK (server); 719#endif 720 721 if (last_unref) 722 { 723 /* lock not held! */ 724 _dbus_assert (server->disconnected); 725 726 _dbus_assert (server->vtable->finalize != NULL); 727 728 (* server->vtable->finalize) (server); 729 } 730} 731 732/** 733 * Like dbus_server_ref() but does not acquire the lock (must already be held) 734 * 735 * @param server the server. 736 */ 737void 738_dbus_server_ref_unlocked (DBusServer *server) 739{ 740 _dbus_assert (server != NULL); 741 _dbus_assert (server->refcount.value > 0); 742 743 HAVE_LOCK_CHECK (server); 744 745#ifdef DBUS_HAVE_ATOMIC_INT 746 _dbus_atomic_inc (&server->refcount); 747#else 748 _dbus_assert (server->refcount.value > 0); 749 750 server->refcount.value += 1; 751#endif 752} 753 754/** 755 * Like dbus_server_unref() but does not acquire the lock (must already be held) 756 * 757 * @param server the server. 758 */ 759void 760_dbus_server_unref_unlocked (DBusServer *server) 761{ 762 dbus_bool_t last_unref; 763 764 _dbus_assert (server != NULL); 765 _dbus_assert (server->refcount.value > 0); 766 767 HAVE_LOCK_CHECK (server); 768 769#ifdef DBUS_HAVE_ATOMIC_INT 770 last_unref = (_dbus_atomic_dec (&server->refcount) == 1); 771#else 772 _dbus_assert (server->refcount.value > 0); 773 774 server->refcount.value -= 1; 775 last_unref = (server->refcount.value == 0); 776#endif 777 778 if (last_unref) 779 { 780 _dbus_assert (server->disconnected); 781 782 SERVER_UNLOCK (server); 783 784 _dbus_assert (server->vtable->finalize != NULL); 785 786 (* server->vtable->finalize) (server); 787 } 788} 789 790/** 791 * Releases the server's address and stops listening for 792 * new clients. If called more than once, only the first 793 * call has an effect. Does not modify the server's 794 * reference count. 795 * 796 * @param server the server. 797 */ 798void 799dbus_server_disconnect (DBusServer *server) 800{ 801 _dbus_return_if_fail (server != NULL); 802 _dbus_return_if_fail (server->refcount.value > 0); 803 804 SERVER_LOCK (server); 805 _dbus_server_ref_unlocked (server); 806 807 _dbus_assert (server->vtable->disconnect != NULL); 808 809 if (!server->disconnected) 810 { 811 /* this has to be first so recursive calls to disconnect don't happen */ 812 server->disconnected = TRUE; 813 814 (* server->vtable->disconnect) (server); 815 } 816 817 SERVER_UNLOCK (server); 818 dbus_server_unref (server); 819} 820 821/** 822 * Returns #TRUE if the server is still listening for new connections. 823 * 824 * @param server the server. 825 */ 826dbus_bool_t 827dbus_server_get_is_connected (DBusServer *server) 828{ 829 dbus_bool_t retval; 830 831 _dbus_return_val_if_fail (server != NULL, FALSE); 832 833 SERVER_LOCK (server); 834 retval = !server->disconnected; 835 SERVER_UNLOCK (server); 836 837 return retval; 838} 839 840/** 841 * Returns the address of the server, as a newly-allocated 842 * string which must be freed by the caller. 843 * 844 * @param server the server 845 * @returns the address or #NULL if no memory 846 */ 847char* 848dbus_server_get_address (DBusServer *server) 849{ 850 char *retval; 851 852 _dbus_return_val_if_fail (server != NULL, NULL); 853 854 SERVER_LOCK (server); 855 retval = _dbus_strdup (server->address); 856 SERVER_UNLOCK (server); 857 858 return retval; 859} 860 861/** 862 * Sets a function to be used for handling new connections. The given 863 * function is passed each new connection as the connection is 864 * created. If the new connection function increments the connection's 865 * reference count, the connection will stay alive. Otherwise, the 866 * connection will be unreferenced and closed. 867 * 868 * @param server the server. 869 * @param function a function to handle new connections. 870 * @param data data to pass to the new connection handler. 871 * @param free_data_function function to free the data. 872 */ 873void 874dbus_server_set_new_connection_function (DBusServer *server, 875 DBusNewConnectionFunction function, 876 void *data, 877 DBusFreeFunction free_data_function) 878{ 879 DBusFreeFunction old_free_function; 880 void *old_data; 881 882 _dbus_return_if_fail (server != NULL); 883 884 SERVER_LOCK (server); 885 old_free_function = server->new_connection_free_data_function; 886 old_data = server->new_connection_data; 887 888 server->new_connection_function = function; 889 server->new_connection_data = data; 890 server->new_connection_free_data_function = free_data_function; 891 SERVER_UNLOCK (server); 892 893 if (old_free_function != NULL) 894 (* old_free_function) (old_data); 895} 896 897/** 898 * Sets the watch functions for the connection. These functions are 899 * responsible for making the application's main loop aware of file 900 * descriptors that need to be monitored for events. 901 * 902 * This function behaves exactly like dbus_connection_set_watch_functions(); 903 * see the documentation for that routine. 904 * 905 * @param server the server. 906 * @param add_function function to begin monitoring a new descriptor. 907 * @param remove_function function to stop monitoring a descriptor. 908 * @param toggled_function function to notify when the watch is enabled/disabled 909 * @param data data to pass to add_function and remove_function. 910 * @param free_data_function function to be called to free the data. 911 * @returns #FALSE on failure (no memory) 912 */ 913dbus_bool_t 914dbus_server_set_watch_functions (DBusServer *server, 915 DBusAddWatchFunction add_function, 916 DBusRemoveWatchFunction remove_function, 917 DBusWatchToggledFunction toggled_function, 918 void *data, 919 DBusFreeFunction free_data_function) 920{ 921 dbus_bool_t result; 922 DBusWatchList *watches; 923 924 _dbus_return_val_if_fail (server != NULL, FALSE); 925 926 SERVER_LOCK (server); 927 watches = server->watches; 928 server->watches = NULL; 929 if (watches) 930 { 931 SERVER_UNLOCK (server); 932 result = _dbus_watch_list_set_functions (watches, 933 add_function, 934 remove_function, 935 toggled_function, 936 data, 937 free_data_function); 938 SERVER_LOCK (server); 939 } 940 else 941 { 942 _dbus_warn ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME); 943 result = FALSE; 944 } 945 server->watches = watches; 946 SERVER_UNLOCK (server); 947 948 return result; 949} 950 951/** 952 * Sets the timeout functions for the connection. These functions are 953 * responsible for making the application's main loop aware of timeouts. 954 * 955 * This function behaves exactly like dbus_connection_set_timeout_functions(); 956 * see the documentation for that routine. 957 * 958 * @param server the server. 959 * @param add_function function to add a timeout. 960 * @param remove_function function to remove a timeout. 961 * @param toggled_function function to notify when the timeout is enabled/disabled 962 * @param data data to pass to add_function and remove_function. 963 * @param free_data_function function to be called to free the data. 964 * @returns #FALSE on failure (no memory) 965 */ 966dbus_bool_t 967dbus_server_set_timeout_functions (DBusServer *server, 968 DBusAddTimeoutFunction add_function, 969 DBusRemoveTimeoutFunction remove_function, 970 DBusTimeoutToggledFunction toggled_function, 971 void *data, 972 DBusFreeFunction free_data_function) 973{ 974 dbus_bool_t result; 975 DBusTimeoutList *timeouts; 976 977 _dbus_return_val_if_fail (server != NULL, FALSE); 978 979 SERVER_LOCK (server); 980 timeouts = server->timeouts; 981 server->timeouts = NULL; 982 if (timeouts) 983 { 984 SERVER_UNLOCK (server); 985 result = _dbus_timeout_list_set_functions (timeouts, 986 add_function, 987 remove_function, 988 toggled_function, 989 data, 990 free_data_function); 991 SERVER_LOCK (server); 992 } 993 else 994 { 995 _dbus_warn ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME); 996 result = FALSE; 997 } 998 server->timeouts = timeouts; 999 SERVER_UNLOCK (server); 1000 1001 return result; 1002} 1003 1004/** 1005 * Sets the authentication mechanisms that this server offers 1006 * to clients, as a list of SASL mechanisms. This function 1007 * only affects connections created *after* it is called. 1008 * Pass #NULL instead of an array to use all available mechanisms. 1009 * 1010 * @param server the server 1011 * @param mechanisms #NULL-terminated array of mechanisms 1012 * @returns #FALSE if no memory 1013 */ 1014dbus_bool_t 1015dbus_server_set_auth_mechanisms (DBusServer *server, 1016 const char **mechanisms) 1017{ 1018 char **copy; 1019 1020 _dbus_return_val_if_fail (server != NULL, FALSE); 1021 1022 SERVER_LOCK (server); 1023 1024 if (mechanisms != NULL) 1025 { 1026 copy = _dbus_dup_string_array (mechanisms); 1027 if (copy == NULL) 1028 return FALSE; 1029 } 1030 else 1031 copy = NULL; 1032 1033 dbus_free_string_array (server->auth_mechanisms); 1034 server->auth_mechanisms = copy; 1035 1036 SERVER_UNLOCK (server); 1037 1038 return TRUE; 1039} 1040 1041 1042static DBusDataSlotAllocator slot_allocator; 1043_DBUS_DEFINE_GLOBAL_LOCK (server_slots); 1044 1045/** 1046 * Allocates an integer ID to be used for storing application-specific 1047 * data on any DBusServer. The allocated ID may then be used 1048 * with dbus_server_set_data() and dbus_server_get_data(). 1049 * The slot must be initialized with -1. If a nonnegative 1050 * slot is passed in, the refcount is incremented on that 1051 * slot, rather than creating a new slot. 1052 * 1053 * The allocated slot is global, i.e. all DBusServer objects will have 1054 * a slot with the given integer ID reserved. 1055 * 1056 * @param slot_p address of global variable storing the slot ID 1057 * @returns #FALSE on no memory 1058 */ 1059dbus_bool_t 1060dbus_server_allocate_data_slot (dbus_int32_t *slot_p) 1061{ 1062 return _dbus_data_slot_allocator_alloc (&slot_allocator, 1063 _DBUS_LOCK_NAME (server_slots), 1064 slot_p); 1065} 1066 1067/** 1068 * Deallocates a global ID for server data slots. 1069 * dbus_server_get_data() and dbus_server_set_data() 1070 * may no longer be used with this slot. 1071 * Existing data stored on existing DBusServer objects 1072 * will be freed when the server is finalized, 1073 * but may not be retrieved (and may only be replaced 1074 * if someone else reallocates the slot). 1075 * 1076 * @param slot_p address of the slot to deallocate 1077 */ 1078void 1079dbus_server_free_data_slot (dbus_int32_t *slot_p) 1080{ 1081 _dbus_return_if_fail (*slot_p >= 0); 1082 1083 _dbus_data_slot_allocator_free (&slot_allocator, slot_p); 1084} 1085 1086/** 1087 * Stores a pointer on a DBusServer, along 1088 * with an optional function to be used for freeing 1089 * the data when the data is set again, or when 1090 * the server is finalized. The slot number 1091 * must have been allocated with dbus_server_allocate_data_slot(). 1092 * 1093 * @param server the server 1094 * @param slot the slot number 1095 * @param data the data to store 1096 * @param free_data_func finalizer function for the data 1097 * @returns #TRUE if there was enough memory to store the data 1098 */ 1099dbus_bool_t 1100dbus_server_set_data (DBusServer *server, 1101 int slot, 1102 void *data, 1103 DBusFreeFunction free_data_func) 1104{ 1105 DBusFreeFunction old_free_func; 1106 void *old_data; 1107 dbus_bool_t retval; 1108 1109 _dbus_return_val_if_fail (server != NULL, FALSE); 1110 1111 SERVER_LOCK (server); 1112 1113 retval = _dbus_data_slot_list_set (&slot_allocator, 1114 &server->slot_list, 1115 slot, data, free_data_func, 1116 &old_free_func, &old_data); 1117 1118 1119 SERVER_UNLOCK (server); 1120 1121 if (retval) 1122 { 1123 /* Do the actual free outside the server lock */ 1124 if (old_free_func) 1125 (* old_free_func) (old_data); 1126 } 1127 1128 return retval; 1129} 1130 1131/** 1132 * Retrieves data previously set with dbus_server_set_data(). 1133 * The slot must still be allocated (must not have been freed). 1134 * 1135 * @param server the server 1136 * @param slot the slot to get data from 1137 * @returns the data, or #NULL if not found 1138 */ 1139void* 1140dbus_server_get_data (DBusServer *server, 1141 int slot) 1142{ 1143 void *res; 1144 1145 _dbus_return_val_if_fail (server != NULL, NULL); 1146 1147 SERVER_LOCK (server); 1148 1149 res = _dbus_data_slot_list_get (&slot_allocator, 1150 &server->slot_list, 1151 slot); 1152 1153 SERVER_UNLOCK (server); 1154 1155 return res; 1156} 1157 1158/** @} */ 1159 1160#ifdef DBUS_BUILD_TESTS 1161#include "dbus-test.h" 1162 1163dbus_bool_t 1164_dbus_server_test (void) 1165{ 1166 const char *valid_addresses[] = { 1167 "tcp:port=1234", 1168 "unix:path=./boogie", 1169 "tcp:host=localhost,port=1234", 1170 "tcp:host=localhost,port=1234;tcp:port=5678", 1171 "tcp:port=1234;unix:path=./boogie", 1172 }; 1173 1174 DBusServer *server; 1175 int i; 1176 1177 for (i = 0; i < _DBUS_N_ELEMENTS (valid_addresses); i++) 1178 { 1179 server = dbus_server_listen (valid_addresses[i], NULL); 1180 if (server == NULL) 1181 _dbus_assert_not_reached ("Failed to listen for valid address."); 1182 1183 dbus_server_disconnect (server); 1184 dbus_server_unref (server); 1185 1186 /* Try disconnecting before unreffing */ 1187 server = dbus_server_listen (valid_addresses[i], NULL); 1188 if (server == NULL) 1189 _dbus_assert_not_reached ("Failed to listen for valid address."); 1190 1191 dbus_server_disconnect (server); 1192 dbus_server_unref (server); 1193 } 1194 1195 return TRUE; 1196} 1197 1198#endif /* DBUS_BUILD_TESTS */ 1199