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