driver.c revision c5020ac870c5990a36c3576453cc23431213e8bf
1/* -*- mode: C; c-file-style: "gnu" -*- */ 2/* driver.c Bus client (driver) 3 * 4 * Copyright (C) 2003 CodeFactory AB 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 "activation.h" 25#include "connection.h" 26#include "driver.h" 27#include "dispatch.h" 28#include "services.h" 29#include "utils.h" 30#include <dbus/dbus-string.h> 31#include <dbus/dbus-internals.h> 32#include <string.h> 33 34static dbus_bool_t bus_driver_send_welcome_message (DBusConnection *connection, 35 DBusMessage *hello_message, 36 BusTransaction *transaction, 37 DBusError *error); 38 39dbus_bool_t 40bus_driver_send_service_deleted (const char *service_name, 41 BusTransaction *transaction, 42 DBusError *error) 43{ 44 DBusMessage *message; 45 dbus_bool_t retval; 46 47 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 48 49 _dbus_verbose ("sending service deleted: %s\n", service_name); 50 51 message = dbus_message_new (DBUS_SERVICE_BROADCAST, 52 DBUS_MESSAGE_SERVICE_DELETED); 53 if (message == NULL) 54 { 55 BUS_SET_OOM (error); 56 return FALSE; 57 } 58 59 if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS) || 60 !dbus_message_append_args (message, 61 DBUS_TYPE_STRING, service_name, 62 0)) 63 { 64 dbus_message_unref (message); 65 BUS_SET_OOM (error); 66 return FALSE; 67 } 68 69 retval = bus_dispatch_broadcast_message (transaction, message, error); 70 dbus_message_unref (message); 71 72 return retval; 73} 74 75dbus_bool_t 76bus_driver_send_service_created (const char *service_name, 77 BusTransaction *transaction, 78 DBusError *error) 79{ 80 DBusMessage *message; 81 dbus_bool_t retval; 82 83 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 84 85 message = dbus_message_new (DBUS_SERVICE_BROADCAST, 86 DBUS_MESSAGE_SERVICE_CREATED); 87 if (message == NULL) 88 { 89 BUS_SET_OOM (error); 90 return FALSE; 91 } 92 93 if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS)) 94 { 95 dbus_message_unref (message); 96 BUS_SET_OOM (error); 97 return FALSE; 98 } 99 100 if (!dbus_message_append_args (message, 101 DBUS_TYPE_STRING, service_name, 102 0)) 103 { 104 dbus_message_unref (message); 105 BUS_SET_OOM (error); 106 return FALSE; 107 } 108 109 retval = bus_dispatch_broadcast_message (transaction, message, error); 110 dbus_message_unref (message); 111 112 return retval; 113} 114 115dbus_bool_t 116bus_driver_send_service_lost (DBusConnection *connection, 117 const char *service_name, 118 BusTransaction *transaction, 119 DBusError *error) 120{ 121 DBusMessage *message; 122 123 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 124 125 message = dbus_message_new (bus_connection_get_name (connection), 126 DBUS_MESSAGE_SERVICE_LOST); 127 if (message == NULL) 128 { 129 BUS_SET_OOM (error); 130 return FALSE; 131 } 132 133 if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS)) 134 { 135 dbus_message_unref (message); 136 BUS_SET_OOM (error); 137 return FALSE; 138 } 139 140 if (!dbus_message_append_args (message, 141 DBUS_TYPE_STRING, service_name, 142 0)) 143 { 144 dbus_message_unref (message); 145 BUS_SET_OOM (error); 146 return FALSE; 147 } 148 149 if (!bus_transaction_send_message (transaction, connection, message)) 150 { 151 dbus_message_unref (message); 152 BUS_SET_OOM (error); 153 return FALSE; 154 } 155 else 156 { 157 dbus_message_unref (message); 158 return TRUE; 159 } 160} 161 162dbus_bool_t 163bus_driver_send_service_acquired (DBusConnection *connection, 164 const char *service_name, 165 BusTransaction *transaction, 166 DBusError *error) 167{ 168 DBusMessage *message; 169 170 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 171 172 message = dbus_message_new (bus_connection_get_name (connection), 173 DBUS_MESSAGE_SERVICE_ACQUIRED); 174 if (message == NULL) 175 { 176 BUS_SET_OOM (error); 177 return FALSE; 178 } 179 180 if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS)) 181 { 182 dbus_message_unref (message); 183 BUS_SET_OOM (error); 184 return FALSE; 185 } 186 187 if (!dbus_message_append_args (message, 188 DBUS_TYPE_STRING, service_name, 189 0)) 190 { 191 dbus_message_unref (message); 192 BUS_SET_OOM (error); 193 return FALSE; 194 } 195 196 if (!bus_transaction_send_message (transaction, connection, message)) 197 { 198 dbus_message_unref (message); 199 BUS_SET_OOM (error); 200 return FALSE; 201 } 202 else 203 { 204 dbus_message_unref (message); 205 return TRUE; 206 } 207} 208 209static dbus_bool_t 210create_unique_client_name (BusRegistry *registry, 211 DBusString *str) 212{ 213 /* We never want to use the same unique client name twice, because 214 * we want to guarantee that if you send a message to a given unique 215 * name, you always get the same application. So we use two numbers 216 * for INT_MAX * INT_MAX combinations, should be pretty safe against 217 * wraparound. 218 */ 219 static int next_major_number = 0; 220 static int next_minor_number = 0; 221 int len; 222 223 len = _dbus_string_get_length (str); 224 225 while (TRUE) 226 { 227 /* start out with 1-0, go to 1-1, 1-2, 1-3, 228 * up to 1-MAXINT, then 2-0, 2-1, etc. 229 */ 230 if (next_minor_number <= 0) 231 { 232 next_major_number += 1; 233 next_minor_number = 0; 234 if (next_major_number <= 0) 235 _dbus_assert_not_reached ("INT_MAX * INT_MAX clients were added"); 236 } 237 238 _dbus_assert (next_major_number > 0); 239 _dbus_assert (next_minor_number >= 0); 240 241 /* appname:MAJOR-MINOR */ 242 243 if (!_dbus_string_append (str, ":")) 244 return FALSE; 245 246 if (!_dbus_string_append_int (str, next_major_number)) 247 return FALSE; 248 249 if (!_dbus_string_append (str, "-")) 250 return FALSE; 251 252 if (!_dbus_string_append_int (str, next_minor_number)) 253 return FALSE; 254 255 next_minor_number += 1; 256 257 /* Check if a client with the name exists */ 258 if (bus_registry_lookup (registry, str) == NULL) 259 break; 260 261 /* drop the number again, try the next one. */ 262 _dbus_string_set_length (str, len); 263 } 264 265 return TRUE; 266} 267 268static dbus_bool_t 269bus_driver_handle_hello (DBusConnection *connection, 270 BusTransaction *transaction, 271 DBusMessage *message, 272 DBusError *error) 273{ 274 DBusString unique_name; 275 BusService *service; 276 dbus_bool_t retval; 277 BusRegistry *registry; 278 279 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 280 281 if (!_dbus_string_init (&unique_name)) 282 { 283 BUS_SET_OOM (error); 284 return FALSE; 285 } 286 287 retval = FALSE; 288 289 registry = bus_connection_get_registry (connection); 290 291 if (!create_unique_client_name (registry, &unique_name)) 292 { 293 BUS_SET_OOM (error); 294 goto out_0; 295 } 296 297 if (!bus_connection_set_name (connection, &unique_name)) 298 { 299 BUS_SET_OOM (error); 300 goto out_0; 301 } 302 303 if (!dbus_message_set_sender (message, 304 bus_connection_get_name (connection))) 305 { 306 BUS_SET_OOM (error); 307 goto out_0; 308 } 309 310 if (!bus_driver_send_welcome_message (connection, message, transaction, error)) 311 goto out_0; 312 313 /* Create the service */ 314 service = bus_registry_ensure (registry, 315 &unique_name, connection, transaction, error); 316 if (service == NULL) 317 goto out_0; 318 319 bus_service_set_prohibit_replacement (service, TRUE); 320 321 retval = TRUE; 322 323 out_0: 324 _dbus_string_free (&unique_name); 325 return retval; 326} 327 328static dbus_bool_t 329bus_driver_send_welcome_message (DBusConnection *connection, 330 DBusMessage *hello_message, 331 BusTransaction *transaction, 332 DBusError *error) 333{ 334 DBusMessage *welcome; 335 const char *name; 336 337 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 338 339 name = bus_connection_get_name (connection); 340 _dbus_assert (name != NULL); 341 342 welcome = dbus_message_new_reply (hello_message); 343 if (welcome == NULL) 344 { 345 BUS_SET_OOM (error); 346 return FALSE; 347 } 348 349 if (!dbus_message_set_sender (welcome, DBUS_SERVICE_DBUS)) 350 { 351 dbus_message_unref (welcome); 352 BUS_SET_OOM (error); 353 return FALSE; 354 } 355 356 if (!dbus_message_append_args (welcome, 357 DBUS_TYPE_STRING, name, 358 NULL)) 359 { 360 dbus_message_unref (welcome); 361 BUS_SET_OOM (error); 362 return FALSE; 363 } 364 365 if (!bus_transaction_send_message (transaction, connection, welcome)) 366 { 367 dbus_message_unref (welcome); 368 BUS_SET_OOM (error); 369 return FALSE; 370 } 371 else 372 { 373 dbus_message_unref (welcome); 374 return TRUE; 375 } 376} 377 378static dbus_bool_t 379bus_driver_handle_list_services (DBusConnection *connection, 380 BusTransaction *transaction, 381 DBusMessage *message, 382 DBusError *error) 383{ 384 DBusMessage *reply; 385 int len; 386 char **services; 387 BusRegistry *registry; 388 389 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 390 391 registry = bus_connection_get_registry (connection); 392 393 reply = dbus_message_new_reply (message); 394 if (reply == NULL) 395 { 396 BUS_SET_OOM (error); 397 return FALSE; 398 } 399 400 if (!bus_registry_list_services (registry, &services, &len)) 401 { 402 dbus_message_unref (reply); 403 BUS_SET_OOM (error); 404 return FALSE; 405 } 406 407 if (!dbus_message_append_args (reply, 408 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, services, len, 409 0)) 410 { 411 dbus_free_string_array (services); 412 dbus_message_unref (reply); 413 BUS_SET_OOM (error); 414 return FALSE; 415 } 416 417 dbus_free_string_array (services); 418 419 if (!bus_transaction_send_message (transaction, connection, reply)) 420 { 421 dbus_message_unref (reply); 422 BUS_SET_OOM (error); 423 return FALSE; 424 } 425 else 426 { 427 dbus_message_unref (reply); 428 return TRUE; 429 } 430} 431 432static dbus_bool_t 433bus_driver_handle_acquire_service (DBusConnection *connection, 434 BusTransaction *transaction, 435 DBusMessage *message, 436 DBusError *error) 437{ 438 DBusMessage *reply; 439 DBusString service_name; 440 BusService *service; 441 char *name; 442 int service_reply; 443 int flags; 444 dbus_bool_t retval; 445 DBusConnection *old_owner; 446 DBusConnection *current_owner; 447 BusRegistry *registry; 448 449 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 450 451 registry = bus_connection_get_registry (connection); 452 453 if (!dbus_message_get_args (message, error, 454 DBUS_TYPE_STRING, &name, 455 DBUS_TYPE_UINT32, &flags, 456 0)) 457 return FALSE; 458 459 _dbus_verbose ("Trying to own service %s with flags 0x%x\n", name, flags); 460 461 if (*name == ':') 462 { 463 /* Not allowed; only base services can start with ':' */ 464 dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, 465 "Cannot acquire a service starting with ':' such as \"%s\"", 466 name); 467 468 goto out; 469 } 470 471 retval = FALSE; 472 reply = NULL; 473 474 _dbus_string_init_const (&service_name, name); 475 476 service = bus_registry_lookup (registry, &service_name); 477 478 if (service != NULL) 479 old_owner = bus_service_get_primary_owner (service); 480 else 481 old_owner = NULL; 482 483 reply = dbus_message_new_reply (message); 484 if (reply == NULL) 485 { 486 BUS_SET_OOM (error); 487 goto out; 488 } 489 490 if (!dbus_message_set_sender (reply, DBUS_SERVICE_DBUS)) 491 { 492 BUS_SET_OOM (error); 493 goto out; 494 } 495 496 if (service == NULL) 497 { 498 service = bus_registry_ensure (registry, 499 &service_name, connection, transaction, error); 500 if (service == NULL) 501 goto out; 502 } 503 504 current_owner = bus_service_get_primary_owner (service); 505 506 if (old_owner == NULL) 507 { 508 _dbus_assert (current_owner == connection); 509 510 bus_service_set_prohibit_replacement (service, 511 (flags & DBUS_SERVICE_FLAG_PROHIBIT_REPLACEMENT)); 512 513 service_reply = DBUS_SERVICE_REPLY_PRIMARY_OWNER; 514 } 515 else if (old_owner == connection) 516 service_reply = DBUS_SERVICE_REPLY_ALREADY_OWNER; 517 else if (!((flags & DBUS_SERVICE_FLAG_REPLACE_EXISTING))) 518 service_reply = DBUS_SERVICE_REPLY_SERVICE_EXISTS; 519 else if (bus_service_get_prohibit_replacement (service)) 520 { 521 /* Queue the connection */ 522 if (!bus_service_add_owner (service, connection, 523 transaction, error)) 524 goto out; 525 526 service_reply = DBUS_SERVICE_REPLY_IN_QUEUE; 527 } 528 else 529 { 530 /* Replace the current owner */ 531 532 /* We enqueue the new owner and remove the first one because 533 * that will cause ServiceAcquired and ServiceLost messages to 534 * be sent. 535 */ 536 537 /* FIXME this is broken, if the remove_owner fails 538 * we don't undo the add_owner 539 * (easiest fix is probably to move all this to 540 * services.c and have a single routine for it) 541 */ 542 543 if (!bus_service_add_owner (service, connection, 544 transaction, error)) 545 goto out; 546 547 if (!bus_service_remove_owner (service, old_owner, 548 transaction, error)) 549 goto out; 550 551 _dbus_assert (connection == bus_service_get_primary_owner (service)); 552 service_reply = DBUS_SERVICE_REPLY_PRIMARY_OWNER; 553 } 554 555 if (!dbus_message_append_args (reply, DBUS_TYPE_UINT32, service_reply, 0)) 556 { 557 BUS_SET_OOM (error); 558 goto out; 559 } 560 561 if (!bus_transaction_send_message (transaction, connection, reply)) 562 { 563 BUS_SET_OOM (error); 564 goto out; 565 } 566 567 retval = TRUE; 568 569 out: 570 dbus_free (name); 571 if (reply) 572 dbus_message_unref (reply); 573 return retval; 574} 575 576static dbus_bool_t 577bus_driver_handle_service_exists (DBusConnection *connection, 578 BusTransaction *transaction, 579 DBusMessage *message, 580 DBusError *error) 581{ 582 DBusMessage *reply; 583 DBusString service_name; 584 BusService *service; 585 char *name; 586 dbus_bool_t retval; 587 BusRegistry *registry; 588 589 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 590 591 registry = bus_connection_get_registry (connection); 592 593 if (!dbus_message_get_args (message, error, 594 DBUS_TYPE_STRING, &name, 595 0)) 596 return FALSE; 597 598 retval = FALSE; 599 600 _dbus_string_init_const (&service_name, name); 601 service = bus_registry_lookup (registry, &service_name); 602 603 reply = dbus_message_new_reply (message); 604 if (reply == NULL) 605 { 606 BUS_SET_OOM (error); 607 goto out; 608 } 609 610 if (!dbus_message_set_sender (reply, DBUS_SERVICE_DBUS)) 611 { 612 BUS_SET_OOM (error); 613 goto out; 614 } 615 616 if (!dbus_message_append_args (reply, 617 DBUS_TYPE_UINT32, service != NULL, 618 0)) 619 { 620 BUS_SET_OOM (error); 621 goto out; 622 } 623 624 if (!bus_transaction_send_message (transaction, connection, reply)) 625 { 626 BUS_SET_OOM (error); 627 goto out; 628 } 629 630 retval = TRUE; 631 632 out: 633 if (reply) 634 dbus_message_unref (reply); 635 dbus_free (name); 636 637 return retval; 638} 639 640static dbus_bool_t 641bus_driver_handle_activate_service (DBusConnection *connection, 642 BusTransaction *transaction, 643 DBusMessage *message, 644 DBusError *error) 645{ 646 dbus_uint32_t flags; 647 char *name; 648 dbus_bool_t retval; 649 BusActivation *activation; 650 651 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 652 653 activation = bus_connection_get_activation (connection); 654 655 if (!dbus_message_get_args (message, error, 656 DBUS_TYPE_STRING, &name, 657 DBUS_TYPE_UINT32, &flags, 658 0)) 659 return FALSE; 660 661 retval = FALSE; 662 663 if (!bus_activation_activate_service (activation, connection, transaction, 664 message, name, error)) 665 goto out; 666 667 retval = TRUE; 668 669 out: 670 dbus_free (name); 671 return retval; 672} 673 674/* For speed it might be useful to sort this in order of 675 * frequency of use (but doesn't matter with only a few items 676 * anyhow) 677 */ 678struct 679{ 680 const char *name; 681 dbus_bool_t (* handler) (DBusConnection *connection, 682 BusTransaction *transaction, 683 DBusMessage *message, 684 DBusError *error); 685} message_handlers[] = { 686 { DBUS_MESSAGE_ACQUIRE_SERVICE, bus_driver_handle_acquire_service }, 687 { DBUS_MESSAGE_ACTIVATE_SERVICE, bus_driver_handle_activate_service }, 688 { DBUS_MESSAGE_HELLO, bus_driver_handle_hello }, 689 { DBUS_MESSAGE_SERVICE_EXISTS, bus_driver_handle_service_exists }, 690 { DBUS_MESSAGE_LIST_SERVICES, bus_driver_handle_list_services } 691}; 692 693dbus_bool_t 694bus_driver_handle_message (DBusConnection *connection, 695 BusTransaction *transaction, 696 DBusMessage *message, 697 DBusError *error) 698{ 699 const char *name, *sender; 700 int i; 701 702 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 703 704 _dbus_verbose ("Driver got a message: %s\n", 705 dbus_message_get_name (message)); 706 707 name = dbus_message_get_name (message); 708 sender = dbus_message_get_sender (message); 709 710 if (sender == NULL && (strcmp (name, DBUS_MESSAGE_HELLO) != 0)) 711 { 712 dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, 713 "Client tried to send a message other than %s without being registered", 714 DBUS_MESSAGE_HELLO); 715 716 dbus_connection_disconnect (connection); 717 return FALSE; 718 } 719 720 i = 0; 721 while (i < _DBUS_N_ELEMENTS (message_handlers)) 722 { 723 if (strcmp (message_handlers[i].name, name) == 0) 724 { 725 if ((* message_handlers[i].handler) (connection, transaction, message, error)) 726 return TRUE; 727 else 728 return FALSE; 729 } 730 731 ++i; 732 } 733 734 dbus_set_error (error, DBUS_ERROR_UNKNOWN_MESSAGE, 735 "%s does not understand message %s", 736 DBUS_SERVICE_DBUS, name); 737 738 return FALSE; 739} 740 741void 742bus_driver_remove_connection (DBusConnection *connection) 743{ 744 /* FIXME Does nothing for now, should unregister the connection 745 * with the bus driver. 746 */ 747} 748