1 /*** 2 This file is part of avahi. 3 4 avahi is free software; you can redistribute it and/or modify it 5 under the terms of the GNU Lesser General Public License as 6 published by the Free Software Foundation; either version 2.1 of the 7 License, or (at your option) any later version. 8 9 avahi is distributed in the hope that it will be useful, but WITHOUT 10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 11 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 12 Public License for more details. 13 14 You should have received a copy of the GNU Lesser General Public 15 License along with avahi; if not, write to the Free Software 16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 17 USA. 18 ***/ 19 20 #ifdef HAVE_CONFIG_H 21 #include <config.h> 22 #endif 23 24 #include <stdlib.h> 25 #include <stdio.h> 26 #include <string.h> 27 28 #include <dbus/dbus.h> 29 30 #include <avahi-client/client.h> 31 #include <avahi-common/dbus.h> 32 #include <avahi-common/llist.h> 33 #include <avahi-common/error.h> 34 #include "avahi-common/avahi-malloc.h" 35 #include <avahi-common/domain.h> 36 37 #include "client.h" 38 #include "internal.h" 39 #include "xdg-config.h" 40 41 static void parse_environment(AvahiDomainBrowser *b) { 42 char buf[AVAHI_DOMAIN_NAME_MAX*3], *e, *t, *p; 43 44 assert(b); 45 46 if (!(e = getenv("AVAHI_BROWSE_DOMAINS"))) 47 return; 48 49 snprintf(buf, sizeof(buf), "%s", e); 50 51 for (t = strtok_r(buf, ":", &p); t; t = strtok_r(NULL, ":", &p)) { 52 char domain[AVAHI_DOMAIN_NAME_MAX]; 53 if (avahi_normalize_name(t, domain, sizeof(domain))) 54 b->static_browse_domains = avahi_string_list_add(b->static_browse_domains, domain); 55 } 56 } 57 58 static void parse_domain_file(AvahiDomainBrowser *b) { 59 FILE *f; 60 char buf[AVAHI_DOMAIN_NAME_MAX]; 61 62 assert(b); 63 64 if (!(f = avahi_xdg_config_open("avahi/browse-domains"))) 65 return; 66 67 68 while (fgets(buf, sizeof(buf)-1, f)) { 69 char domain[AVAHI_DOMAIN_NAME_MAX]; 70 buf[strcspn(buf, "\n\r")] = 0; 71 72 if (avahi_normalize_name(buf, domain, sizeof(domain))) 73 b->static_browse_domains = avahi_string_list_add(b->static_browse_domains, domain); 74 } 75 } 76 77 static void domain_browser_ref(AvahiDomainBrowser *db) { 78 assert(db); 79 assert(db->ref >= 1); 80 db->ref++; 81 } 82 83 static void defer_timeout_callback(AvahiTimeout *t, void *userdata) { 84 AvahiDomainBrowser *db = userdata; 85 AvahiStringList *l; 86 assert(t); 87 88 db->client->poll_api->timeout_free(db->defer_timeout); 89 db->defer_timeout = NULL; 90 91 domain_browser_ref(db); 92 93 for (l = db->static_browse_domains; l; l = l->next) { 94 95 if (db->ref <= 1) 96 break; 97 98 db->callback(db, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AVAHI_BROWSER_NEW, (char*) l->text, AVAHI_LOOKUP_RESULT_STATIC, db->userdata); 99 } 100 101 avahi_domain_browser_free(db); 102 } 103 104 AvahiDomainBrowser* avahi_domain_browser_new( 105 AvahiClient *client, 106 AvahiIfIndex interface, 107 AvahiProtocol protocol, 108 const char *domain, 109 AvahiDomainBrowserType btype, 110 AvahiLookupFlags flags, 111 AvahiDomainBrowserCallback callback, 112 void *userdata) { 113 114 AvahiDomainBrowser *db = NULL; 115 DBusMessage *message = NULL, *reply = NULL; 116 DBusError error; 117 char *path; 118 int32_t i_interface, i_protocol, bt; 119 uint32_t u_flags; 120 121 assert(client); 122 assert(callback); 123 124 dbus_error_init (&error); 125 126 if (!avahi_client_is_connected(client)) { 127 avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); 128 goto fail; 129 } 130 131 if (!domain) 132 domain = ""; 133 134 if (!(db = avahi_new (AvahiDomainBrowser, 1))) { 135 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 136 goto fail; 137 } 138 139 db->ref = 1; 140 db->client = client; 141 db->callback = callback; 142 db->userdata = userdata; 143 db->path = NULL; 144 db->interface = interface; 145 db->protocol = protocol; 146 db->static_browse_domains = NULL; 147 db->defer_timeout = NULL; 148 149 AVAHI_LLIST_PREPEND(AvahiDomainBrowser, domain_browsers, client->domain_browsers, db); 150 151 if (!(client->flags & AVAHI_CLIENT_IGNORE_USER_CONFIG)) { 152 parse_environment(db); 153 parse_domain_file(db); 154 } 155 156 db->static_browse_domains = avahi_string_list_reverse(db->static_browse_domains); 157 158 if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "DomainBrowserNew"))) { 159 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 160 goto fail; 161 } 162 163 i_interface = (int32_t) interface; 164 i_protocol = (int32_t) protocol; 165 u_flags = (uint32_t) flags; 166 bt = btype; 167 168 if (!(dbus_message_append_args( 169 message, 170 DBUS_TYPE_INT32, &i_interface, 171 DBUS_TYPE_INT32, &i_protocol, 172 DBUS_TYPE_STRING, &domain, 173 DBUS_TYPE_INT32, &bt, 174 DBUS_TYPE_UINT32, &u_flags, 175 DBUS_TYPE_INVALID))) { 176 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 177 goto fail; 178 } 179 180 if (!(reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error)) || 181 dbus_error_is_set(&error)) { 182 avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); 183 goto fail; 184 } 185 186 if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) || 187 dbus_error_is_set(&error) || 188 !path) { 189 avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); 190 goto fail; 191 } 192 193 if (!(db->path = avahi_strdup(path))) { 194 195 /* FIXME: We don't remove the object on the server side */ 196 197 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 198 goto fail; 199 } 200 201 if (db->static_browse_domains && btype == AVAHI_DOMAIN_BROWSER_BROWSE) { 202 struct timeval tv = { 0, 0 }; 203 204 if (!(db->defer_timeout = client->poll_api->timeout_new(client->poll_api, &tv, defer_timeout_callback, db))) { 205 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 206 goto fail; 207 } 208 } 209 210 dbus_message_unref(message); 211 dbus_message_unref(reply); 212 213 return db; 214 215 fail: 216 217 if (dbus_error_is_set(&error)) { 218 avahi_client_set_dbus_error(client, &error); 219 dbus_error_free(&error); 220 } 221 222 if (db) 223 avahi_domain_browser_free(db); 224 225 if (message) 226 dbus_message_unref(message); 227 228 if (reply) 229 dbus_message_unref(reply); 230 231 return NULL; 232 } 233 234 AvahiClient* avahi_domain_browser_get_client (AvahiDomainBrowser *b) { 235 assert(b); 236 return b->client; 237 } 238 239 int avahi_domain_browser_free (AvahiDomainBrowser *b) { 240 AvahiClient *client; 241 int r = AVAHI_OK; 242 243 assert(b); 244 assert(b->ref >= 1); 245 246 if (--(b->ref) >= 1) 247 return AVAHI_OK; 248 249 client = b->client; 250 251 if (b->path && avahi_client_is_connected(b->client)) 252 r = avahi_client_simple_method_call(client, b->path, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "Free"); 253 254 AVAHI_LLIST_REMOVE(AvahiDomainBrowser, domain_browsers, client->domain_browsers, b); 255 256 if (b->defer_timeout) 257 b->client->poll_api->timeout_free(b->defer_timeout); 258 259 avahi_string_list_free(b->static_browse_domains); 260 avahi_free(b->path); 261 avahi_free(b); 262 263 return r; 264 } 265 266 DBusHandlerResult avahi_domain_browser_event (AvahiClient *client, AvahiBrowserEvent event, DBusMessage *message) { 267 AvahiDomainBrowser *db = NULL; 268 DBusError error; 269 const char *path; 270 char *domain = NULL; 271 int32_t interface, protocol; 272 uint32_t flags = 0; 273 AvahiStringList *l; 274 275 assert(client); 276 assert(message); 277 278 dbus_error_init (&error); 279 280 if (!(path = dbus_message_get_path(message))) 281 goto fail; 282 283 for (db = client->domain_browsers; db; db = db->domain_browsers_next) 284 if (strcmp (db->path, path) == 0) 285 break; 286 287 if (!db) 288 goto fail; 289 290 interface = db->interface; 291 protocol = db->protocol; 292 293 switch (event) { 294 case AVAHI_BROWSER_NEW: 295 case AVAHI_BROWSER_REMOVE: 296 297 if (!dbus_message_get_args( 298 message, &error, 299 DBUS_TYPE_INT32, &interface, 300 DBUS_TYPE_INT32, &protocol, 301 DBUS_TYPE_STRING, &domain, 302 DBUS_TYPE_UINT32, &flags, 303 DBUS_TYPE_INVALID) || 304 dbus_error_is_set (&error)) { 305 fprintf(stderr, "Failed to parse browser event.\n"); 306 goto fail; 307 } 308 309 break; 310 311 case AVAHI_BROWSER_CACHE_EXHAUSTED: 312 case AVAHI_BROWSER_ALL_FOR_NOW: 313 break; 314 315 case AVAHI_BROWSER_FAILURE: { 316 char *etxt; 317 318 if (!dbus_message_get_args( 319 message, &error, 320 DBUS_TYPE_STRING, &etxt, 321 DBUS_TYPE_INVALID) || 322 dbus_error_is_set (&error)) { 323 fprintf(stderr, "Failed to parse browser event.\n"); 324 goto fail; 325 } 326 327 avahi_client_set_errno(db->client, avahi_error_dbus_to_number(etxt)); 328 break; 329 } 330 } 331 332 if (domain) 333 for (l = db->static_browse_domains; l; l = l->next) 334 if (avahi_domain_equal((char*) l->text, domain)) { 335 /* We had this entry already in the static entries */ 336 return DBUS_HANDLER_RESULT_HANDLED; 337 } 338 339 db->callback(db, (AvahiIfIndex) interface, (AvahiProtocol) protocol, event, domain, (AvahiLookupResultFlags) flags, db->userdata); 340 341 return DBUS_HANDLER_RESULT_HANDLED; 342 343 fail: 344 dbus_error_free (&error); 345 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 346 } 347 348 /* AvahiServiceTypeBrowser */ 349 350 AvahiServiceTypeBrowser* avahi_service_type_browser_new( 351 AvahiClient *client, 352 AvahiIfIndex interface, 353 AvahiProtocol protocol, 354 const char *domain, 355 AvahiLookupFlags flags, 356 AvahiServiceTypeBrowserCallback callback, 357 void *userdata) { 358 359 AvahiServiceTypeBrowser *b = NULL; 360 DBusMessage *message = NULL, *reply = NULL; 361 DBusError error; 362 char *path; 363 int32_t i_interface, i_protocol; 364 uint32_t u_flags; 365 366 assert(client); 367 assert(callback); 368 369 dbus_error_init(&error); 370 371 if (!avahi_client_is_connected(client)) { 372 avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); 373 goto fail; 374 } 375 376 if (!domain) 377 domain = ""; 378 379 if (!(b = avahi_new(AvahiServiceTypeBrowser, 1))) { 380 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 381 goto fail; 382 } 383 384 b->client = client; 385 b->callback = callback; 386 b->userdata = userdata; 387 b->path = NULL; 388 b->domain = NULL; 389 b->interface = interface; 390 b->protocol = protocol; 391 392 AVAHI_LLIST_PREPEND(AvahiServiceTypeBrowser, service_type_browsers, client->service_type_browsers, b); 393 394 if (domain[0]) 395 if (!(b->domain = avahi_strdup(domain))) { 396 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 397 goto fail; 398 } 399 400 if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "ServiceTypeBrowserNew"))) { 401 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 402 goto fail; 403 } 404 405 i_interface = (int32_t) interface; 406 i_protocol = (int32_t) protocol; 407 u_flags = (uint32_t) flags; 408 409 if (!dbus_message_append_args( 410 message, 411 DBUS_TYPE_INT32, &i_interface, 412 DBUS_TYPE_INT32, &i_protocol, 413 DBUS_TYPE_STRING, &domain, 414 DBUS_TYPE_UINT32, &u_flags, 415 DBUS_TYPE_INVALID)) { 416 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 417 goto fail; 418 } 419 420 if (!(reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error)) || 421 dbus_error_is_set(&error)) { 422 avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); 423 goto fail; 424 } 425 426 if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) || 427 dbus_error_is_set(&error) || 428 !path) { 429 avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); 430 goto fail; 431 } 432 433 if (!(b->path = avahi_strdup(path))) { 434 435 /* FIXME: We don't remove the object on the server side */ 436 437 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 438 goto fail; 439 } 440 441 dbus_message_unref(message); 442 dbus_message_unref(reply); 443 444 return b; 445 446 fail: 447 448 if (dbus_error_is_set(&error)) { 449 avahi_client_set_dbus_error(client, &error); 450 dbus_error_free(&error); 451 } 452 453 if (b) 454 avahi_service_type_browser_free(b); 455 456 if (message) 457 dbus_message_unref(message); 458 459 if (reply) 460 dbus_message_unref(reply); 461 462 return NULL; 463 } 464 465 AvahiClient* avahi_service_type_browser_get_client (AvahiServiceTypeBrowser *b) { 466 assert(b); 467 return b->client; 468 } 469 470 int avahi_service_type_browser_free (AvahiServiceTypeBrowser *b) { 471 AvahiClient *client; 472 int r = AVAHI_OK; 473 474 assert(b); 475 client = b->client; 476 477 if (b->path && avahi_client_is_connected(b->client)) 478 r = avahi_client_simple_method_call(client, b->path, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "Free"); 479 480 AVAHI_LLIST_REMOVE(AvahiServiceTypeBrowser, service_type_browsers, b->client->service_type_browsers, b); 481 482 avahi_free(b->path); 483 avahi_free(b->domain); 484 avahi_free(b); 485 return r; 486 } 487 488 DBusHandlerResult avahi_service_type_browser_event (AvahiClient *client, AvahiBrowserEvent event, DBusMessage *message) { 489 AvahiServiceTypeBrowser *b = NULL; 490 DBusError error; 491 const char *path; 492 char *domain, *type = NULL; 493 int32_t interface, protocol; 494 uint32_t flags = 0; 495 496 assert(client); 497 assert(message); 498 499 dbus_error_init (&error); 500 501 if (!(path = dbus_message_get_path(message))) 502 goto fail; 503 504 for (b = client->service_type_browsers; b; b = b->service_type_browsers_next) 505 if (strcmp (b->path, path) == 0) 506 break; 507 508 if (!b) 509 goto fail; 510 511 domain = b->domain; 512 interface = b->interface; 513 protocol = b->protocol; 514 515 switch (event) { 516 case AVAHI_BROWSER_NEW: 517 case AVAHI_BROWSER_REMOVE: 518 if (!dbus_message_get_args( 519 message, &error, 520 DBUS_TYPE_INT32, &interface, 521 DBUS_TYPE_INT32, &protocol, 522 DBUS_TYPE_STRING, &type, 523 DBUS_TYPE_STRING, &domain, 524 DBUS_TYPE_UINT32, &flags, 525 DBUS_TYPE_INVALID) || 526 dbus_error_is_set(&error)) { 527 fprintf(stderr, "Failed to parse browser event.\n"); 528 goto fail; 529 } 530 break; 531 532 case AVAHI_BROWSER_CACHE_EXHAUSTED: 533 case AVAHI_BROWSER_ALL_FOR_NOW: 534 break; 535 536 case AVAHI_BROWSER_FAILURE: { 537 char *etxt; 538 539 if (!dbus_message_get_args( 540 message, &error, 541 DBUS_TYPE_STRING, &etxt, 542 DBUS_TYPE_INVALID) || 543 dbus_error_is_set (&error)) { 544 fprintf(stderr, "Failed to parse browser event.\n"); 545 goto fail; 546 } 547 548 avahi_client_set_errno(b->client, avahi_error_dbus_to_number(etxt)); 549 break; 550 } 551 } 552 553 b->callback(b, (AvahiIfIndex) interface, (AvahiProtocol) protocol, event, type, domain, (AvahiLookupResultFlags) flags, b->userdata); 554 555 return DBUS_HANDLER_RESULT_HANDLED; 556 557 fail: 558 dbus_error_free (&error); 559 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 560 } 561 562 /* AvahiServiceBrowser */ 563 564 AvahiServiceBrowser* avahi_service_browser_new( 565 AvahiClient *client, 566 AvahiIfIndex interface, 567 AvahiProtocol protocol, 568 const char *type, 569 const char *domain, 570 AvahiLookupFlags flags, 571 AvahiServiceBrowserCallback callback, 572 void *userdata) { 573 574 AvahiServiceBrowser *b = NULL; 575 DBusMessage *message = NULL, *reply = NULL; 576 DBusError error; 577 char *path; 578 int32_t i_protocol, i_interface; 579 uint32_t u_flags; 580 581 assert(client); 582 assert(type); 583 assert(callback); 584 585 dbus_error_init(&error); 586 587 if (!avahi_client_is_connected(client)) { 588 avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); 589 goto fail; 590 } 591 592 if (!domain) 593 domain = ""; 594 595 if (!(b = avahi_new(AvahiServiceBrowser, 1))) { 596 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 597 goto fail; 598 } 599 600 b->client = client; 601 b->callback = callback; 602 b->userdata = userdata; 603 b->path = NULL; 604 b->type = b->domain = NULL; 605 b->interface = interface; 606 b->protocol = protocol; 607 608 AVAHI_LLIST_PREPEND(AvahiServiceBrowser, service_browsers, client->service_browsers, b); 609 610 if (!(b->type = avahi_strdup(type))) { 611 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 612 goto fail; 613 } 614 615 if (domain && domain[0]) 616 if (!(b->domain = avahi_strdup(domain))) { 617 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 618 goto fail; 619 } 620 621 if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "ServiceBrowserNew"))) { 622 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 623 goto fail; 624 } 625 626 i_interface = (int32_t) interface; 627 i_protocol = (int32_t) protocol; 628 u_flags = (uint32_t) flags; 629 630 if (!dbus_message_append_args( 631 message, 632 DBUS_TYPE_INT32, &i_interface, 633 DBUS_TYPE_INT32, &i_protocol, 634 DBUS_TYPE_STRING, &type, 635 DBUS_TYPE_STRING, &domain, 636 DBUS_TYPE_UINT32, &u_flags, 637 DBUS_TYPE_INVALID)) { 638 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 639 goto fail; 640 } 641 642 if (!(reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error)) || 643 dbus_error_is_set(&error)) { 644 avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); 645 goto fail; 646 } 647 648 if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) || 649 dbus_error_is_set(&error) || 650 !path) { 651 avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); 652 goto fail; 653 } 654 655 if (!(b->path = avahi_strdup(path))) { 656 657 /* FIXME: We don't remove the object on the server side */ 658 659 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 660 goto fail; 661 } 662 663 dbus_message_unref(message); 664 dbus_message_unref(reply); 665 666 return b; 667 668 fail: 669 if (dbus_error_is_set(&error)) { 670 avahi_client_set_dbus_error(client, &error); 671 dbus_error_free(&error); 672 } 673 674 if (b) 675 avahi_service_browser_free(b); 676 677 if (message) 678 dbus_message_unref(message); 679 680 if (reply) 681 dbus_message_unref(reply); 682 683 return NULL; 684 } 685 686 AvahiClient* avahi_service_browser_get_client (AvahiServiceBrowser *b) { 687 assert(b); 688 return b->client; 689 } 690 691 int avahi_service_browser_free (AvahiServiceBrowser *b) { 692 AvahiClient *client; 693 int r = AVAHI_OK; 694 695 assert(b); 696 client = b->client; 697 698 if (b->path && avahi_client_is_connected(b->client)) 699 r = avahi_client_simple_method_call(client, b->path, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "Free"); 700 701 AVAHI_LLIST_REMOVE(AvahiServiceBrowser, service_browsers, b->client->service_browsers, b); 702 703 avahi_free(b->path); 704 avahi_free(b->type); 705 avahi_free(b->domain); 706 avahi_free(b); 707 return r; 708 } 709 710 DBusHandlerResult avahi_service_browser_event(AvahiClient *client, AvahiBrowserEvent event, DBusMessage *message) { 711 AvahiServiceBrowser *b = NULL; 712 DBusError error; 713 const char *path; 714 char *name = NULL, *type, *domain; 715 int32_t interface, protocol; 716 uint32_t flags = 0; 717 718 dbus_error_init (&error); 719 720 if (!(path = dbus_message_get_path(message))) 721 goto fail; 722 723 for (b = client->service_browsers; b; b = b->service_browsers_next) 724 if (strcmp (b->path, path) == 0) 725 break; 726 727 if (!b) 728 goto fail; 729 730 type = b->type; 731 domain = b->domain; 732 interface = b->interface; 733 protocol = b->protocol; 734 735 switch (event) { 736 case AVAHI_BROWSER_NEW: 737 case AVAHI_BROWSER_REMOVE: 738 739 if (!dbus_message_get_args ( 740 message, &error, 741 DBUS_TYPE_INT32, &interface, 742 DBUS_TYPE_INT32, &protocol, 743 DBUS_TYPE_STRING, &name, 744 DBUS_TYPE_STRING, &type, 745 DBUS_TYPE_STRING, &domain, 746 DBUS_TYPE_UINT32, &flags, 747 DBUS_TYPE_INVALID) || 748 dbus_error_is_set(&error)) { 749 fprintf(stderr, "Failed to parse browser event.\n"); 750 goto fail; 751 } 752 break; 753 754 case AVAHI_BROWSER_CACHE_EXHAUSTED: 755 case AVAHI_BROWSER_ALL_FOR_NOW: 756 break; 757 758 case AVAHI_BROWSER_FAILURE: { 759 char *etxt; 760 761 if (!dbus_message_get_args( 762 message, &error, 763 DBUS_TYPE_STRING, &etxt, 764 DBUS_TYPE_INVALID) || 765 dbus_error_is_set (&error)) { 766 fprintf(stderr, "Failed to parse browser event.\n"); 767 goto fail; 768 } 769 770 avahi_client_set_errno(b->client, avahi_error_dbus_to_number(etxt)); 771 break; 772 } 773 } 774 775 b->callback(b, (AvahiIfIndex) interface, (AvahiProtocol) protocol, event, name, type, domain, (AvahiLookupResultFlags) flags, b->userdata); 776 777 return DBUS_HANDLER_RESULT_HANDLED; 778 779 fail: 780 dbus_error_free (&error); 781 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 782 } 783 784 /* AvahiRecordBrowser */ 785 786 AvahiRecordBrowser* avahi_record_browser_new( 787 AvahiClient *client, 788 AvahiIfIndex interface, 789 AvahiProtocol protocol, 790 const char *name, 791 uint16_t clazz, 792 uint16_t type, 793 AvahiLookupFlags flags, 794 AvahiRecordBrowserCallback callback, 795 void *userdata) { 796 797 AvahiRecordBrowser *b = NULL; 798 DBusMessage *message = NULL, *reply = NULL; 799 DBusError error; 800 char *path; 801 int32_t i_protocol, i_interface; 802 uint32_t u_flags; 803 804 assert(client); 805 assert(name); 806 assert(callback); 807 808 dbus_error_init(&error); 809 810 if (!avahi_client_is_connected(client)) { 811 avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); 812 goto fail; 813 } 814 815 if (!(b = avahi_new(AvahiRecordBrowser, 1))) { 816 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 817 goto fail; 818 } 819 820 b->client = client; 821 b->callback = callback; 822 b->userdata = userdata; 823 b->path = NULL; 824 b->name = NULL; 825 b->clazz = clazz; 826 b->type = type; 827 b->interface = interface; 828 b->protocol = protocol; 829 830 AVAHI_LLIST_PREPEND(AvahiRecordBrowser, record_browsers, client->record_browsers, b); 831 832 if (!(b->name = avahi_strdup(name))) { 833 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 834 goto fail; 835 } 836 837 if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "RecordBrowserNew"))) { 838 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 839 goto fail; 840 } 841 842 i_interface = (int32_t) interface; 843 i_protocol = (int32_t) protocol; 844 u_flags = (uint32_t) flags; 845 846 if (!dbus_message_append_args( 847 message, 848 DBUS_TYPE_INT32, &i_interface, 849 DBUS_TYPE_INT32, &i_protocol, 850 DBUS_TYPE_STRING, &name, 851 DBUS_TYPE_UINT16, &clazz, 852 DBUS_TYPE_UINT16, &type, 853 DBUS_TYPE_UINT32, &u_flags, 854 DBUS_TYPE_INVALID)) { 855 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 856 goto fail; 857 } 858 859 if (!(reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error)) || 860 dbus_error_is_set(&error)) { 861 avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); 862 goto fail; 863 } 864 865 if (!dbus_message_get_args (reply, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) || 866 dbus_error_is_set(&error) || 867 !path) { 868 avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); 869 goto fail; 870 } 871 872 if (!(b->path = avahi_strdup(path))) { 873 874 /* FIXME: We don't remove the object on the server side */ 875 876 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 877 goto fail; 878 } 879 880 dbus_message_unref(message); 881 dbus_message_unref(reply); 882 883 return b; 884 885 fail: 886 if (dbus_error_is_set(&error)) { 887 avahi_client_set_dbus_error(client, &error); 888 dbus_error_free(&error); 889 } 890 891 if (b) 892 avahi_record_browser_free(b); 893 894 if (message) 895 dbus_message_unref(message); 896 897 if (reply) 898 dbus_message_unref(reply); 899 900 return NULL; 901 } 902 903 AvahiClient* avahi_record_browser_get_client (AvahiRecordBrowser *b) { 904 assert(b); 905 return b->client; 906 } 907 908 int avahi_record_browser_free (AvahiRecordBrowser *b) { 909 AvahiClient *client; 910 int r = AVAHI_OK; 911 912 assert(b); 913 client = b->client; 914 915 if (b->path && avahi_client_is_connected(b->client)) 916 r = avahi_client_simple_method_call(client, b->path, AVAHI_DBUS_INTERFACE_RECORD_BROWSER, "Free"); 917 918 AVAHI_LLIST_REMOVE(AvahiRecordBrowser, record_browsers, b->client->record_browsers, b); 919 920 avahi_free(b->path); 921 avahi_free(b->name); 922 avahi_free(b); 923 return r; 924 } 925 926 DBusHandlerResult avahi_record_browser_event(AvahiClient *client, AvahiBrowserEvent event, DBusMessage *message) { 927 AvahiRecordBrowser *b = NULL; 928 DBusError error; 929 const char *path; 930 char *name; 931 int32_t interface, protocol; 932 uint32_t flags = 0; 933 uint16_t clazz, type; 934 void *rdata = NULL; 935 int rdata_size = 0; 936 937 dbus_error_init (&error); 938 939 if (!(path = dbus_message_get_path(message))) 940 goto fail; 941 942 for (b = client->record_browsers; b; b = b->record_browsers_next) 943 if (strcmp (b->path, path) == 0) 944 break; 945 946 if (!b) 947 goto fail; 948 949 interface = b->interface; 950 protocol = b->protocol; 951 clazz = b->clazz; 952 type = b->type; 953 name = b->name; 954 955 switch (event) { 956 case AVAHI_BROWSER_NEW: 957 case AVAHI_BROWSER_REMOVE: { 958 DBusMessageIter iter, sub; 959 int j; 960 961 if (!dbus_message_get_args ( 962 message, &error, 963 DBUS_TYPE_INT32, &interface, 964 DBUS_TYPE_INT32, &protocol, 965 DBUS_TYPE_STRING, &name, 966 DBUS_TYPE_UINT16, &clazz, 967 DBUS_TYPE_UINT16, &type, 968 DBUS_TYPE_INVALID) || 969 dbus_error_is_set(&error)) { 970 fprintf(stderr, "Failed to parse browser event.\n"); 971 goto fail; 972 } 973 974 975 dbus_message_iter_init(message, &iter); 976 977 for (j = 0; j < 5; j++) 978 dbus_message_iter_next(&iter); 979 980 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || 981 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE) 982 goto fail; 983 984 dbus_message_iter_recurse(&iter, &sub); 985 dbus_message_iter_get_fixed_array(&sub, &rdata, &rdata_size); 986 987 dbus_message_iter_next(&iter); 988 989 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) 990 goto fail; 991 992 dbus_message_iter_get_basic(&iter, &flags); 993 994 break; 995 } 996 997 case AVAHI_BROWSER_CACHE_EXHAUSTED: 998 case AVAHI_BROWSER_ALL_FOR_NOW: 999 break; 1000 1001 case AVAHI_BROWSER_FAILURE: { 1002 char *etxt; 1003 1004 if (!dbus_message_get_args( 1005 message, &error, 1006 DBUS_TYPE_STRING, &etxt, 1007 DBUS_TYPE_INVALID) || 1008 dbus_error_is_set (&error)) { 1009 fprintf(stderr, "Failed to parse browser event.\n"); 1010 goto fail; 1011 } 1012 1013 avahi_client_set_errno(b->client, avahi_error_dbus_to_number(etxt)); 1014 break; 1015 } 1016 } 1017 1018 b->callback(b, (AvahiIfIndex) interface, (AvahiProtocol) protocol, event, name, clazz, type, rdata, (size_t) rdata_size, (AvahiLookupResultFlags) flags, b->userdata); 1019 1020 return DBUS_HANDLER_RESULT_HANDLED; 1021 1022 fail: 1023 dbus_error_free (&error); 1024 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 1025 } 1026