dbus-server.c revision ebb57e719c32becd95a1efe3dd269c21e5a011b6
1/* -*- mode: C; c-file-style: "gnu" -*- */ 2/* dbus-server.c DBusServer object 3 * 4 * Copyright (C) 2002, 2003 Red Hat Inc. 5 * 6 * Licensed under the Academic Free License version 1.2 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#ifdef DBUS_BUILD_TESTS 27#include "dbus-server-debug.h" 28#include "dbus-server-debug-pipe.h" 29#endif 30#include "dbus-address.h" 31 32/** 33 * @defgroup DBusServer DBusServer 34 * @ingroup DBus 35 * @brief Server that listens for new connections. 36 * 37 * Types and functions related to DBusServer. 38 * A DBusServer represents a server that other applications 39 * can connect to. Each connection from another application 40 * is represented by a DBusConnection. 41 * 42 * @todo Thread safety hasn't been looked at for #DBusServer 43 * @todo Need notification to apps of disconnection, may matter for some transports 44 */ 45 46/** 47 * @defgroup DBusServerInternals DBusServer implementation details 48 * @ingroup DBusInternals 49 * @brief Implementation details of DBusServer 50 * 51 * @{ 52 */ 53 54/** 55 * Initializes the members of the DBusServer base class. 56 * Chained up to by subclass constructors. 57 * 58 * @param server the server. 59 * @param vtable the vtable for the subclass. 60 * @returns #TRUE on success. 61 */ 62dbus_bool_t 63_dbus_server_init_base (DBusServer *server, 64 const DBusServerVTable *vtable) 65{ 66 server->vtable = vtable; 67 server->refcount = 1; 68 69 server->watches = _dbus_watch_list_new (); 70 if (server->watches == NULL) 71 return FALSE; 72 73 server->timeouts = _dbus_timeout_list_new (); 74 if (server->timeouts == NULL) 75 { 76 _dbus_watch_list_free (server->watches); 77 server->watches = NULL; 78 return FALSE; 79 } 80 81 server->connection_counter = _dbus_counter_new (); 82 if (server->connection_counter == NULL) 83 { 84 _dbus_watch_list_free (server->watches); 85 server->watches = NULL; 86 _dbus_timeout_list_free (server->timeouts); 87 server->timeouts = NULL; 88 89 return FALSE; 90 } 91 92 server->max_connections = 256; /* same as an X server, seems like a nice default */ 93 94 _dbus_data_slot_list_init (&server->slot_list); 95 96 return TRUE; 97} 98 99/** 100 * Finalizes the members of the DBusServer base class. 101 * Chained up to by subclass finalizers. 102 * 103 * @param server the server. 104 */ 105void 106_dbus_server_finalize_base (DBusServer *server) 107{ 108 /* calls out to application code... */ 109 _dbus_data_slot_list_free (&server->slot_list); 110 111 dbus_server_set_new_connection_function (server, NULL, NULL, NULL); 112 113 if (!server->disconnected) 114 dbus_server_disconnect (server); 115 116 _dbus_watch_list_free (server->watches); 117 _dbus_timeout_list_free (server->timeouts); 118 _dbus_counter_unref (server->connection_counter); 119} 120 121/** 122 * Adds a watch for this server, chaining out to application-provided 123 * watch handlers. 124 * 125 * @param server the server. 126 * @param watch the watch to add. 127 */ 128dbus_bool_t 129_dbus_server_add_watch (DBusServer *server, 130 DBusWatch *watch) 131{ 132 return _dbus_watch_list_add_watch (server->watches, watch); 133} 134 135/** 136 * Removes a watch previously added with _dbus_server_remove_watch(). 137 * 138 * @param server the server. 139 * @param watch the watch to remove. 140 */ 141void 142_dbus_server_remove_watch (DBusServer *server, 143 DBusWatch *watch) 144{ 145 _dbus_watch_list_remove_watch (server->watches, watch); 146} 147 148/** 149 * Toggles a watch and notifies app via server's 150 * DBusWatchToggledFunction if available. It's an error to call this 151 * function on a watch that was not previously added. 152 * 153 * @param server the server. 154 * @param watch the watch to toggle. 155 * @param enabled whether to enable or disable 156 */ 157void 158_dbus_server_toggle_watch (DBusServer *server, 159 DBusWatch *watch, 160 dbus_bool_t enabled) 161{ 162 if (server->watches) /* null during finalize */ 163 _dbus_watch_list_toggle_watch (server->watches, 164 watch, enabled); 165} 166 167/** 168 * Adds a timeout for this server, chaining out to 169 * application-provided timeout handlers. The timeout should be 170 * repeatedly handled with dbus_timeout_handle() at its given interval 171 * until it is removed. 172 * 173 * @param server the server. 174 * @param timeout the timeout to add. 175 */ 176dbus_bool_t 177_dbus_server_add_timeout (DBusServer *server, 178 DBusTimeout *timeout) 179{ 180 return _dbus_timeout_list_add_timeout (server->timeouts, timeout); 181} 182 183/** 184 * Removes a timeout previously added with _dbus_server_add_timeout(). 185 * 186 * @param server the server. 187 * @param timeout the timeout to remove. 188 */ 189void 190_dbus_server_remove_timeout (DBusServer *server, 191 DBusTimeout *timeout) 192{ 193 _dbus_timeout_list_remove_timeout (server->timeouts, timeout); 194} 195 196/** 197 * Toggles a timeout and notifies app via server's 198 * DBusTimeoutToggledFunction if available. It's an error to call this 199 * function on a timeout that was not previously added. 200 * 201 * @param server the server. 202 * @param timeout the timeout to toggle. 203 * @param enabled whether to enable or disable 204 */ 205void 206_dbus_server_toggle_timeout (DBusServer *server, 207 DBusTimeout *timeout, 208 dbus_bool_t enabled) 209{ 210 if (server->timeouts) /* null during finalize */ 211 _dbus_timeout_list_toggle_timeout (server->timeouts, 212 timeout, enabled); 213} 214 215 216/** @} */ 217 218/** 219 * @addtogroup DBusServer 220 * 221 * @{ 222 */ 223 224 225/** 226 * @typedef DBusServer 227 * 228 * An opaque object representing a server that listens for 229 * connections from other applications. Each time a connection 230 * is made, a new DBusConnection is created and made available 231 * via an application-provided DBusNewConnectionFunction. 232 * The DBusNewConnectionFunction is provided with 233 * dbus_server_set_new_connection_function(). 234 * 235 */ 236 237/** 238 * Listens for new connections on the given address. 239 * Returns #NULL if listening fails for any reason. 240 * Otherwise returns a new #DBusServer. 241 * dbus_server_set_new_connection_function() and 242 * dbus_server_set_watch_functions() should be called 243 * immediately to render the server fully functional. 244 * 245 * @todo error messages on bad address could really be better. 246 * DBusResultCode is a bit limiting here. 247 * 248 * @param address the address of this server. 249 * @param result location to store rationale for failure. 250 * @returns a new DBusServer, or #NULL on failure. 251 * 252 */ 253DBusServer* 254dbus_server_listen (const char *address, 255 DBusResultCode *result) 256{ 257 DBusServer *server; 258 DBusAddressEntry **entries; 259 int len, i; 260 261 if (!dbus_parse_address (address, &entries, &len, result)) 262 return NULL; 263 264 server = NULL; 265 266 for (i = 0; i < len; i++) 267 { 268 const char *method = dbus_address_entry_get_method (entries[i]); 269 270 if (strcmp (method, "unix") == 0) 271 { 272 const char *path = dbus_address_entry_get_value (entries[i], "path"); 273 274 if (path == NULL) 275 goto bad_address; 276 277 server = _dbus_server_new_for_domain_socket (path, result); 278 279 if (server) 280 break; 281 } 282 else if (strcmp (method, "tcp") == 0) 283 { 284 const char *host = dbus_address_entry_get_value (entries[i], "host"); 285 const char *port = dbus_address_entry_get_value (entries[i], "port"); 286 DBusString str; 287 long lport; 288 dbus_bool_t sresult; 289 290 if (port == NULL) 291 goto bad_address; 292 293 _dbus_string_init_const (&str, port); 294 sresult = _dbus_string_parse_int (&str, 0, &lport, NULL); 295 _dbus_string_free (&str); 296 297 if (sresult == FALSE || lport <= 0 || lport > 65535) 298 goto bad_address; 299 300 server = _dbus_server_new_for_tcp_socket (host, lport, result); 301 302 if (server) 303 break; 304 } 305#ifdef DBUS_BUILD_TESTS 306 else if (strcmp (method, "debug") == 0) 307 { 308 const char *name = dbus_address_entry_get_value (entries[i], "name"); 309 310 if (name == NULL) 311 goto bad_address; 312 313 server = _dbus_server_debug_new (name, result); 314 315 if (server) 316 break; 317 } 318 else if (strcmp (method, "debug-pipe") == 0) 319 { 320 const char *name = dbus_address_entry_get_value (entries[i], "name"); 321 322 if (name == NULL) 323 goto bad_address; 324 325 server = _dbus_server_debug_pipe_new (name, result); 326 327 if (server) 328 break; 329 } 330#endif 331 else 332 goto bad_address; 333 } 334 335 dbus_address_entries_free (entries); 336 return server; 337 338 bad_address: 339 dbus_address_entries_free (entries); 340 dbus_set_result (result, DBUS_RESULT_BAD_ADDRESS); 341 342 return NULL; 343} 344 345/** 346 * Increments the reference count of a DBusServer. 347 * 348 * @param server the server. 349 */ 350void 351dbus_server_ref (DBusServer *server) 352{ 353 server->refcount += 1; 354} 355 356/** 357 * Decrements the reference count of a DBusServer. Finalizes the 358 * server if the reference count reaches zero. The server connection 359 * will be closed as with dbus_server_disconnect() when the server is 360 * finalized. 361 * 362 * @param server the server. 363 */ 364void 365dbus_server_unref (DBusServer *server) 366{ 367 _dbus_assert (server != NULL); 368 _dbus_assert (server->refcount > 0); 369 370 server->refcount -= 1; 371 if (server->refcount == 0) 372 { 373 _dbus_assert (server->vtable->finalize != NULL); 374 375 (* server->vtable->finalize) (server); 376 } 377} 378 379/** 380 * Releases the server's address and stops listening for 381 * new clients. If called more than once, only the first 382 * call has an effect. Does not modify the server's 383 * reference count. 384 * 385 * @param server the server. 386 */ 387void 388dbus_server_disconnect (DBusServer *server) 389{ 390 _dbus_assert (server->vtable->disconnect != NULL); 391 392 if (server->disconnected) 393 return; 394 395 (* server->vtable->disconnect) (server); 396 server->disconnected = TRUE; 397} 398 399/** 400 * Returns #TRUE if the server is still listening for new connections. 401 * 402 * @param server the server. 403 */ 404dbus_bool_t 405dbus_server_get_is_connected (DBusServer *server) 406{ 407 return !server->disconnected; 408} 409 410/** 411 * Sets a function to be used for handling new connections. The given 412 * function is passed each new connection as the connection is 413 * created. If the new connection function increments the connection's 414 * reference count, the connection will stay alive. Otherwise, the 415 * connection will be unreferenced and closed. 416 * 417 * @param server the server. 418 * @param function a function to handle new connections. 419 * @param data data to pass to the new connection handler. 420 * @param free_data_function function to free the data. 421 */ 422void 423dbus_server_set_new_connection_function (DBusServer *server, 424 DBusNewConnectionFunction function, 425 void *data, 426 DBusFreeFunction free_data_function) 427{ 428 if (server->new_connection_free_data_function != NULL) 429 (* server->new_connection_free_data_function) (server->new_connection_data); 430 431 server->new_connection_function = function; 432 server->new_connection_data = data; 433 server->new_connection_free_data_function = free_data_function; 434} 435 436/** 437 * Sets the watch functions for the connection. These functions are 438 * responsible for making the application's main loop aware of file 439 * descriptors that need to be monitored for events. 440 * 441 * This function behaves exactly like dbus_connection_set_watch_functions(); 442 * see the documentation for that routine. 443 * 444 * @param server the server. 445 * @param add_function function to begin monitoring a new descriptor. 446 * @param remove_function function to stop monitoring a descriptor. 447 * @param toggled_function function to notify when the watch is enabled/disabled 448 * @param data data to pass to add_function and remove_function. 449 * @param free_data_function function to be called to free the data. 450 * @returns #FALSE on failure (no memory) 451 */ 452dbus_bool_t 453dbus_server_set_watch_functions (DBusServer *server, 454 DBusAddWatchFunction add_function, 455 DBusRemoveWatchFunction remove_function, 456 DBusWatchToggledFunction toggled_function, 457 void *data, 458 DBusFreeFunction free_data_function) 459{ 460 return _dbus_watch_list_set_functions (server->watches, 461 add_function, 462 remove_function, 463 toggled_function, 464 data, 465 free_data_function); 466} 467 468/** 469 * Sets the timeout functions for the connection. These functions are 470 * responsible for making the application's main loop aware of timeouts. 471 * 472 * This function behaves exactly like dbus_connection_set_timeout_functions(); 473 * see the documentation for that routine. 474 * 475 * @param server the server. 476 * @param add_function function to add a timeout. 477 * @param remove_function function to remove a timeout. 478 * @param toggled_function function to notify when the timeout is enabled/disabled 479 * @param data data to pass to add_function and remove_function. 480 * @param free_data_function function to be called to free the data. 481 * @returns #FALSE on failure (no memory) 482 */ 483dbus_bool_t 484dbus_server_set_timeout_functions (DBusServer *server, 485 DBusAddTimeoutFunction add_function, 486 DBusRemoveTimeoutFunction remove_function, 487 DBusTimeoutToggledFunction toggled_function, 488 void *data, 489 DBusFreeFunction free_data_function) 490{ 491 return _dbus_timeout_list_set_functions (server->timeouts, 492 add_function, remove_function, 493 toggled_function, 494 data, free_data_function); 495} 496 497/** 498 * Called to notify the server when a previously-added watch 499 * is ready for reading or writing, or has an exception such 500 * as a hangup. 501 * 502 * @param server the server. 503 * @param watch the watch. 504 * @param condition the current condition of the file descriptors being watched. 505 */ 506void 507dbus_server_handle_watch (DBusServer *server, 508 DBusWatch *watch, 509 unsigned int condition) 510{ 511 _dbus_assert (server->vtable->handle_watch != NULL); 512 513 _dbus_watch_sanitize_condition (watch, &condition); 514 515 (* server->vtable->handle_watch) (server, watch, condition); 516} 517 518/** 519 * Sets the maximum number of connections that can be open at one 520 * time for this server. If the maximum is reached, and another 521 * client tries to connect, then the oldest unauthenticated client 522 * will be dropped. If no unauthenticated client exists, then 523 * the new connection will be refused. 524 * 525 * If the maximum is set to a number lower than the current 526 * number of connections, no current connections are 527 * disconnected. 528 * 529 * @todo honoring max_connections has not been implemented 530 * yet. The only real work involved is keeping a list 531 * of live connections on the DBusServer so the oldest 532 * unauthenticated client can be located when required. 533 * 534 * @todo for a systemwide daemon, we need a max number of connections 535 * per user, since any user can authenticate a bunch of connections 536 * and create a DOS. 537 * 538 * @todo a single process might listen on multiple mechanisms 539 * (multiple DBusServer) and might want the max connections 540 * value to span all those servers. Should consider 541 * changing the API accordingly, though I'm inclined to 542 * punt this to the app that wants to do it instead of 543 * putting it in the library. 544 * 545 * @param server the server 546 * @param max_connections maximum number of connections allowed 547 */ 548void 549dbus_server_set_max_connections (DBusServer *server, 550 int max_connections) 551{ 552 server->max_connections = max_connections; 553} 554 555/** 556 * Gets the maximum number of connections that can be active 557 * at a time for this server. 558 * 559 * @param server the server 560 * @returns maximum number of connections at once 561 */ 562int 563dbus_server_get_max_connections (DBusServer *server) 564{ 565 return server->max_connections; 566} 567 568/** 569 * Gets the number of #DBusConnection to this server that 570 * have not yet been finalized. i.e. all #DBusConnection that 571 * were passed to #DBusNewConnectionFunction and have not yet been 572 * finalized will count in this total. 573 * 574 * @param server the server 575 * @returns the number of connections 576 */ 577int 578dbus_server_get_n_connections (DBusServer *server) 579{ 580 return _dbus_counter_get_value (server->connection_counter); 581} 582 583 584static DBusDataSlotAllocator slot_allocator; 585 586/** 587 * Initialize the mutex used for #DBusConnection data 588 * slot reservations. 589 * 590 * @returns the mutex 591 */ 592DBusMutex * 593_dbus_server_slots_init_lock (void) 594{ 595 if (!_dbus_data_slot_allocator_init (&slot_allocator)) 596 return NULL; 597 else 598 return slot_allocator.lock; 599} 600 601/** 602 * Allocates an integer ID to be used for storing application-specific 603 * data on any DBusServer. The allocated ID may then be used 604 * with dbus_server_set_data() and dbus_server_get_data(). 605 * If allocation fails, -1 is returned. Again, the allocated 606 * slot is global, i.e. all DBusServer objects will 607 * have a slot with the given integer ID reserved. 608 * 609 * @returns -1 on failure, otherwise the data slot ID 610 */ 611int 612dbus_server_allocate_data_slot (void) 613{ 614 return _dbus_data_slot_allocator_alloc (&slot_allocator); 615} 616 617/** 618 * Deallocates a global ID for server data slots. 619 * dbus_server_get_data() and dbus_server_set_data() 620 * may no longer be used with this slot. 621 * Existing data stored on existing DBusServer objects 622 * will be freed when the server is finalized, 623 * but may not be retrieved (and may only be replaced 624 * if someone else reallocates the slot). 625 * 626 * @param slot the slot to deallocate 627 */ 628void 629dbus_server_free_data_slot (int slot) 630{ 631 _dbus_data_slot_allocator_free (&slot_allocator, slot); 632} 633 634/** 635 * Stores a pointer on a DBusServer, along 636 * with an optional function to be used for freeing 637 * the data when the data is set again, or when 638 * the server is finalized. The slot number 639 * must have been allocated with dbus_server_allocate_data_slot(). 640 * 641 * @param server the server 642 * @param slot the slot number 643 * @param data the data to store 644 * @param free_data_func finalizer function for the data 645 * @returns #TRUE if there was enough memory to store the data 646 */ 647dbus_bool_t 648dbus_server_set_data (DBusServer *server, 649 int slot, 650 void *data, 651 DBusFreeFunction free_data_func) 652{ 653 DBusFreeFunction old_free_func; 654 void *old_data; 655 dbus_bool_t retval; 656 657#if 0 658 dbus_mutex_lock (server->mutex); 659#endif 660 661 retval = _dbus_data_slot_list_set (&slot_allocator, 662 &server->slot_list, 663 slot, data, free_data_func, 664 &old_free_func, &old_data); 665 666#if 0 667 dbus_mutex_unlock (server->mutex); 668#endif 669 670 if (retval) 671 { 672 /* Do the actual free outside the server lock */ 673 if (old_free_func) 674 (* old_free_func) (old_data); 675 } 676 677 return retval; 678} 679 680/** 681 * Retrieves data previously set with dbus_server_set_data(). 682 * The slot must still be allocated (must not have been freed). 683 * 684 * @param server the server 685 * @param slot the slot to get data from 686 * @returns the data, or #NULL if not found 687 */ 688void* 689dbus_server_get_data (DBusServer *server, 690 int slot) 691{ 692 void *res; 693 694#if 0 695 dbus_mutex_lock (server->mutex); 696#endif 697 698 res = _dbus_data_slot_list_get (&slot_allocator, 699 &server->slot_list, 700 slot); 701 702#if 0 703 dbus_mutex_unlock (server->mutex); 704#endif 705 706 return res; 707} 708 709/** @} */ 710 711