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-common/dbus.h> 31#include <avahi-common/llist.h> 32#include <avahi-common/error.h> 33#include <avahi-common/dbus.h> 34#include <avahi-common/malloc.h> 35#include <avahi-common/dbus-watch-glue.h> 36#include <avahi-common/i18n.h> 37 38#include "client.h" 39#include "internal.h" 40 41#define AVAHI_CLIENT_DBUS_API_SUPPORTED ((uint32_t) 0x0201) 42 43static int init_server(AvahiClient *client, int *ret_error); 44 45int avahi_client_set_errno (AvahiClient *client, int error) { 46 assert(client); 47 48 return client->error = error; 49} 50 51int avahi_client_set_dbus_error(AvahiClient *client, DBusError *error) { 52 assert(client); 53 assert(error); 54 55 return avahi_client_set_errno(client, avahi_error_dbus_to_number(error->name)); 56} 57 58static void client_set_state(AvahiClient *client, AvahiClientState state) { 59 assert(client); 60 61 if (client->state == state) 62 return; 63 64 client->state = state; 65 66 switch (client->state) { 67 case AVAHI_CLIENT_FAILURE: 68 if (client->bus) { 69#ifdef HAVE_DBUS_CONNECTION_CLOSE 70 dbus_connection_close(client->bus); 71#else 72 dbus_connection_disconnect(client->bus); 73#endif 74 dbus_connection_unref(client->bus); 75 client->bus = NULL; 76 } 77 78 /* Fall through */ 79 80 case AVAHI_CLIENT_S_COLLISION: 81 case AVAHI_CLIENT_S_REGISTERING: 82 83 /* Clear cached strings */ 84 avahi_free(client->host_name); 85 avahi_free(client->host_name_fqdn); 86 avahi_free(client->domain_name); 87 88 client->host_name = NULL; 89 client->host_name_fqdn = NULL; 90 client->domain_name = NULL; 91 break; 92 93 case AVAHI_CLIENT_S_RUNNING: 94 case AVAHI_CLIENT_CONNECTING: 95 break; 96 97 } 98 99 if (client->callback) 100 client->callback (client, state, client->userdata); 101} 102 103static DBusHandlerResult filter_func(DBusConnection *bus, DBusMessage *message, void *userdata) { 104 AvahiClient *client = userdata; 105 DBusError error; 106 107 assert(bus); 108 assert(message); 109 110 dbus_error_init(&error); 111 112/* fprintf(stderr, "dbus: interface=%s, path=%s, member=%s\n", */ 113/* dbus_message_get_interface (message), */ 114/* dbus_message_get_path (message), */ 115/* dbus_message_get_member (message)); */ 116 117 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) { 118 119 /* The DBUS server died or kicked us */ 120 avahi_client_set_errno(client, AVAHI_ERR_DISCONNECTED); 121 goto fail; 122 123 } else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameAcquired")) { 124 125 /* Ignore this message */ 126 127 } else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) { 128 char *name, *old, *new; 129 130 if (!dbus_message_get_args( 131 message, &error, 132 DBUS_TYPE_STRING, &name, 133 DBUS_TYPE_STRING, &old, 134 DBUS_TYPE_STRING, &new, 135 DBUS_TYPE_INVALID) || dbus_error_is_set(&error)) { 136 137 fprintf(stderr, "WARNING: Failed to parse NameOwnerChanged signal: %s\n", error.message); 138 avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); 139 goto fail; 140 } 141 142 if (strcmp(name, AVAHI_DBUS_NAME) == 0) { 143 144 if (old[0] && 145 avahi_client_is_connected(client)) { 146 147 /* Regardless if the server lost its name or 148 * if the name was transfered: our services are no longer 149 * available, so we disconnect ourselves */ 150 avahi_client_set_errno(client, AVAHI_ERR_DISCONNECTED); 151 goto fail; 152 153 } else if (client->state == AVAHI_CLIENT_CONNECTING && (!old || *old == 0)) { 154 int ret; 155 156 /* Server appeared */ 157 158 if ((ret = init_server(client, NULL)) < 0) { 159 avahi_client_set_errno(client, ret); 160 goto fail; 161 } 162 } 163 } 164 165 } else if (!avahi_client_is_connected(client)) { 166 167 /* Ignore messages we get in unconnected state */ 168 169 } else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_SERVER, "StateChanged")) { 170 int32_t state; 171 char *e = NULL; 172 int c; 173 174 if (!dbus_message_get_args( 175 message, &error, 176 DBUS_TYPE_INT32, &state, 177 DBUS_TYPE_STRING, &e, 178 DBUS_TYPE_INVALID) || dbus_error_is_set (&error)) { 179 180 fprintf(stderr, "WARNING: Failed to parse Server.StateChanged signal: %s\n", error.message); 181 avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); 182 goto fail; 183 } 184 185 if ((c = avahi_error_dbus_to_number(e)) != AVAHI_OK) 186 avahi_client_set_errno(client, c); 187 188 client_set_state(client, (AvahiClientState) state); 189 190 } else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_ENTRY_GROUP, "StateChanged")) { 191 const char *path; 192 AvahiEntryGroup *g; 193 path = dbus_message_get_path(message); 194 195 for (g = client->groups; g; g = g->groups_next) 196 if (strcmp(g->path, path) == 0) 197 break; 198 199 if (g) { 200 int32_t state; 201 char *e; 202 int c; 203 204 if (!dbus_message_get_args( 205 message, &error, 206 DBUS_TYPE_INT32, &state, 207 DBUS_TYPE_STRING, &e, 208 DBUS_TYPE_INVALID) || 209 dbus_error_is_set(&error)) { 210 211 fprintf(stderr, "WARNING: Failed to parse EntryGroup.StateChanged signal: %s\n", error.message); 212 avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); 213 goto fail; 214 } 215 216 if ((c = avahi_error_dbus_to_number(e)) != AVAHI_OK) 217 avahi_client_set_errno(client, c); 218 219 avahi_entry_group_set_state(g, state); 220 } 221 222 } else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "ItemNew")) 223 return avahi_domain_browser_event(client, AVAHI_BROWSER_NEW, message); 224 else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "ItemRemove")) 225 return avahi_domain_browser_event(client, AVAHI_BROWSER_REMOVE, message); 226 else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "CacheExhausted")) 227 return avahi_domain_browser_event(client, AVAHI_BROWSER_CACHE_EXHAUSTED, message); 228 else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "AllForNow")) 229 return avahi_domain_browser_event(client, AVAHI_BROWSER_ALL_FOR_NOW, message); 230 else if (dbus_message_is_signal (message, AVAHI_DBUS_INTERFACE_DOMAIN_BROWSER, "Failure")) 231 return avahi_domain_browser_event(client, AVAHI_BROWSER_FAILURE, message); 232 233 else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "ItemNew")) 234 return avahi_service_type_browser_event (client, AVAHI_BROWSER_NEW, message); 235 else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "ItemRemove")) 236 return avahi_service_type_browser_event (client, AVAHI_BROWSER_REMOVE, message); 237 else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "CacheExhausted")) 238 return avahi_service_type_browser_event (client, AVAHI_BROWSER_CACHE_EXHAUSTED, message); 239 else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "AllForNow")) 240 return avahi_service_type_browser_event (client, AVAHI_BROWSER_ALL_FOR_NOW, message); 241 else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_TYPE_BROWSER, "Failure")) 242 return avahi_service_type_browser_event (client, AVAHI_BROWSER_FAILURE, message); 243 244 else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "ItemNew")) 245 return avahi_service_browser_event (client, AVAHI_BROWSER_NEW, message); 246 else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "ItemRemove")) 247 return avahi_service_browser_event (client, AVAHI_BROWSER_REMOVE, message); 248 else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "CacheExhausted")) 249 return avahi_service_browser_event (client, AVAHI_BROWSER_CACHE_EXHAUSTED, message); 250 else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "AllForNow")) 251 return avahi_service_browser_event (client, AVAHI_BROWSER_ALL_FOR_NOW, message); 252 else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_BROWSER, "Failure")) 253 return avahi_service_browser_event (client, AVAHI_BROWSER_FAILURE, message); 254 255 else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_RESOLVER, "Found")) 256 return avahi_service_resolver_event (client, AVAHI_RESOLVER_FOUND, message); 257 else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_SERVICE_RESOLVER, "Failure")) 258 return avahi_service_resolver_event (client, AVAHI_RESOLVER_FAILURE, message); 259 260 else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_HOST_NAME_RESOLVER, "Found")) 261 return avahi_host_name_resolver_event (client, AVAHI_RESOLVER_FOUND, message); 262 else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_HOST_NAME_RESOLVER, "Failure")) 263 return avahi_host_name_resolver_event (client, AVAHI_RESOLVER_FAILURE, message); 264 265 else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_ADDRESS_RESOLVER, "Found")) 266 return avahi_address_resolver_event (client, AVAHI_RESOLVER_FOUND, message); 267 else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_ADDRESS_RESOLVER, "Failure")) 268 return avahi_address_resolver_event (client, AVAHI_RESOLVER_FAILURE, message); 269 270 else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_RECORD_BROWSER, "ItemNew")) 271 return avahi_record_browser_event (client, AVAHI_BROWSER_NEW, message); 272 else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_RECORD_BROWSER, "ItemRemove")) 273 return avahi_record_browser_event (client, AVAHI_BROWSER_REMOVE, message); 274 else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_RECORD_BROWSER, "CacheExhausted")) 275 return avahi_record_browser_event (client, AVAHI_BROWSER_CACHE_EXHAUSTED, message); 276 else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_RECORD_BROWSER, "AllForNow")) 277 return avahi_record_browser_event (client, AVAHI_BROWSER_ALL_FOR_NOW, message); 278 else if (dbus_message_is_signal(message, AVAHI_DBUS_INTERFACE_RECORD_BROWSER, "Failure")) 279 return avahi_record_browser_event (client, AVAHI_BROWSER_FAILURE, message); 280 281 else { 282 283 fprintf(stderr, "WARNING: Unhandled message: interface=%s, path=%s, member=%s\n", 284 dbus_message_get_interface(message), 285 dbus_message_get_path(message), 286 dbus_message_get_member(message)); 287 288 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 289 } 290 291 return DBUS_HANDLER_RESULT_HANDLED; 292 293fail: 294 295 if (dbus_error_is_set(&error)) { 296 avahi_client_set_errno(client, avahi_error_dbus_to_number(error.name)); 297 dbus_error_free(&error); 298 } 299 300 client_set_state(client, AVAHI_CLIENT_FAILURE); 301 302 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 303} 304 305static int get_server_state(AvahiClient *client, int *ret_error) { 306 DBusMessage *message = NULL, *reply = NULL; 307 DBusError error; 308 int32_t state; 309 int e = AVAHI_ERR_NO_MEMORY; 310 311 assert(client); 312 313 dbus_error_init(&error); 314 315 if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "GetState"))) 316 goto fail; 317 318 reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error); 319 320 if (!reply || dbus_error_is_set (&error)) 321 goto fail; 322 323 if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INT32, &state, DBUS_TYPE_INVALID) || 324 dbus_error_is_set (&error)) 325 goto fail; 326 327 client_set_state(client, (AvahiClientState) state); 328 329 dbus_message_unref(message); 330 dbus_message_unref(reply); 331 332 return AVAHI_OK; 333 334fail: 335 if (dbus_error_is_set(&error)) { 336 e = avahi_error_dbus_to_number (error.name); 337 dbus_error_free(&error); 338 } 339 340 if (ret_error) 341 *ret_error = e; 342 343 if (message) 344 dbus_message_unref(message); 345 if (reply) 346 dbus_message_unref(reply); 347 348 return e; 349} 350 351static int check_version(AvahiClient *client, int *ret_error) { 352 DBusMessage *message = NULL, *reply = NULL; 353 DBusError error; 354 uint32_t version; 355 int e = AVAHI_ERR_NO_MEMORY; 356 357 assert(client); 358 359 dbus_error_init(&error); 360 361 if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "GetAPIVersion"))) 362 goto fail; 363 364 reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error); 365 366 if (!reply || dbus_error_is_set (&error)) { 367 char *version_str; 368 369 if (!dbus_error_is_set(&error) || strcmp(error.name, DBUS_ERROR_UNKNOWN_METHOD)) 370 goto fail; 371 372 /* If the method GetAPIVersion is not known, we look if 373 * GetVersionString matches "avahi 0.6" which is the only 374 * version we support which doesn't have GetAPIVersion() .*/ 375 376 dbus_message_unref(message); 377 if (reply) dbus_message_unref(reply); 378 dbus_error_free(&error); 379 380 if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "GetVersionString"))) 381 goto fail; 382 383 reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error); 384 385 if (!reply || dbus_error_is_set (&error)) 386 goto fail; 387 388 if (!dbus_message_get_args (reply, &error, DBUS_TYPE_STRING, &version_str, DBUS_TYPE_INVALID) || 389 dbus_error_is_set (&error)) 390 goto fail; 391 392 version = strcmp(version_str, "avahi 0.6") == 0 ? 0x0201 : 0x0000; 393 394 } else { 395 396 if (!dbus_message_get_args (reply, &error, DBUS_TYPE_UINT32, &version, DBUS_TYPE_INVALID) || 397 dbus_error_is_set(&error)) 398 goto fail; 399 } 400 401 /*fprintf(stderr, "API Version 0x%04x\n", version);*/ 402 403 if ((version & 0xFF00) != (AVAHI_CLIENT_DBUS_API_SUPPORTED & 0xFF00) || 404 (version & 0x00FF) < (AVAHI_CLIENT_DBUS_API_SUPPORTED & 0x00FF)) { 405 e = AVAHI_ERR_VERSION_MISMATCH; 406 goto fail; 407 } 408 409 dbus_message_unref(message); 410 dbus_message_unref(reply); 411 412 return AVAHI_OK; 413 414fail: 415 if (dbus_error_is_set(&error)) { 416 e = avahi_error_dbus_to_number (error.name); 417 dbus_error_free(&error); 418 } 419 420 if (ret_error) 421 *ret_error = e; 422 423 if (message) 424 dbus_message_unref(message); 425 if (reply) 426 dbus_message_unref(reply); 427 428 return e; 429} 430 431static int init_server(AvahiClient *client, int *ret_error) { 432 int r; 433 434 if ((r = check_version(client, ret_error)) < 0) 435 return r; 436 437 if ((r = get_server_state(client, ret_error)) < 0) 438 return r; 439 440 return AVAHI_OK; 441} 442 443/* This function acts like dbus_bus_get but creates a private 444 * connection instead. */ 445static DBusConnection* avahi_dbus_bus_get(DBusError *error) { 446 DBusConnection *c; 447 448#ifdef HAVE_DBUS_BUS_GET_PRIVATE 449 if (!(c = dbus_bus_get_private(DBUS_BUS_SYSTEM, error))) 450 return NULL; 451 452 dbus_connection_set_exit_on_disconnect(c, FALSE); 453#else 454 const char *a; 455 456 if (!(a = getenv("DBUS_SYSTEM_BUS_ADDRESS")) || !*a) 457 a = DBUS_SYSTEM_BUS_DEFAULT_ADDRESS; 458 459 if (!(c = dbus_connection_open_private(a, error))) 460 return NULL; 461 462 dbus_connection_set_exit_on_disconnect(c, FALSE); 463 464 if (!dbus_bus_register(c, error)) { 465#ifdef HAVE_DBUS_CONNECTION_CLOSE 466 dbus_connection_close(c); 467#else 468 dbus_connection_disconnect(c); 469#endif 470 dbus_connection_unref(c); 471 return NULL; 472 } 473#endif 474 475 return c; 476} 477 478AvahiClient *avahi_client_new(const AvahiPoll *poll_api, AvahiClientFlags flags, AvahiClientCallback callback, void *userdata, int *ret_error) { 479 AvahiClient *client = NULL; 480 DBusError error; 481 DBusMessage *message = NULL, *reply = NULL; 482 483 avahi_init_i18n(); 484 485 dbus_error_init(&error); 486 487 if (!(client = avahi_new(AvahiClient, 1))) { 488 if (ret_error) 489 *ret_error = AVAHI_ERR_NO_MEMORY; 490 goto fail; 491 } 492 493 client->poll_api = poll_api; 494 client->error = AVAHI_OK; 495 client->callback = callback; 496 client->userdata = userdata; 497 client->state = (AvahiClientState) -1; 498 client->flags = flags; 499 500 client->host_name = NULL; 501 client->host_name_fqdn = NULL; 502 client->domain_name = NULL; 503 client->version_string = NULL; 504 client->local_service_cookie_valid = 0; 505 506 AVAHI_LLIST_HEAD_INIT(AvahiEntryGroup, client->groups); 507 AVAHI_LLIST_HEAD_INIT(AvahiDomainBrowser, client->domain_browsers); 508 AVAHI_LLIST_HEAD_INIT(AvahiServiceBrowser, client->service_browsers); 509 AVAHI_LLIST_HEAD_INIT(AvahiServiceTypeBrowser, client->service_type_browsers); 510 AVAHI_LLIST_HEAD_INIT(AvahiServiceResolver, client->service_resolvers); 511 AVAHI_LLIST_HEAD_INIT(AvahiHostNameResolver, client->host_name_resolvers); 512 AVAHI_LLIST_HEAD_INIT(AvahiAddressResolver, client->address_resolvers); 513 AVAHI_LLIST_HEAD_INIT(AvahiRecordBrowser, client->record_browsers); 514 515 if (!(client->bus = avahi_dbus_bus_get(&error)) || dbus_error_is_set(&error)) { 516 if (ret_error) 517 *ret_error = AVAHI_ERR_DBUS_ERROR; 518 goto fail; 519 } 520 521 if (avahi_dbus_connection_glue(client->bus, poll_api) < 0) { 522 if (ret_error) 523 *ret_error = AVAHI_ERR_NO_MEMORY; /* Not optimal */ 524 goto fail; 525 } 526 527 if (!dbus_connection_add_filter(client->bus, filter_func, client, NULL)) { 528 if (ret_error) 529 *ret_error = AVAHI_ERR_NO_MEMORY; 530 goto fail; 531 } 532 533 dbus_bus_add_match( 534 client->bus, 535 "type='signal', " 536 "interface='" AVAHI_DBUS_INTERFACE_SERVER "', " 537 "sender='" AVAHI_DBUS_NAME "', " 538 "path='" AVAHI_DBUS_PATH_SERVER "'", 539 &error); 540 541 if (dbus_error_is_set(&error)) 542 goto fail; 543 544 dbus_bus_add_match ( 545 client->bus, 546 "type='signal', " 547 "interface='" DBUS_INTERFACE_DBUS "', " 548 "sender='" DBUS_SERVICE_DBUS "', " 549 "path='" DBUS_PATH_DBUS "'", 550 &error); 551 552 if (dbus_error_is_set(&error)) 553 goto fail; 554 555 dbus_bus_add_match( 556 client->bus, 557 "type='signal', " 558 "interface='" DBUS_INTERFACE_LOCAL "'", 559 &error); 560 561 if (dbus_error_is_set(&error)) 562 goto fail; 563 564 if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, "org.freedesktop.DBus.Peer", "Ping"))) 565 goto fail; 566 567 reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error); 568 569 if (!reply || dbus_error_is_set (&error)) { 570 /* We free the error so its not set, that way the fail target 571 * will return the NO_DAEMON error rather than a DBUS error */ 572 dbus_error_free(&error); 573 574 if (!(flags & AVAHI_CLIENT_NO_FAIL)) { 575 576 if (ret_error) 577 *ret_error = AVAHI_ERR_NO_DAEMON; 578 579 goto fail; 580 } 581 582 /* The user doesn't want this call to fail if the daemon is not 583 * available, so let's return succesfully */ 584 client_set_state(client, AVAHI_CLIENT_CONNECTING); 585 586 } else { 587 588 if (init_server(client, ret_error) < 0) 589 goto fail; 590 } 591 592 dbus_message_unref(message); 593 594 if (reply) 595 dbus_message_unref(reply); 596 597 return client; 598 599fail: 600 601 if (message) 602 dbus_message_unref(message); 603 if (reply) 604 dbus_message_unref(reply); 605 606 if (client) 607 avahi_client_free(client); 608 609 if (dbus_error_is_set(&error)) { 610 611 if (ret_error) { 612 if (strcmp(error.name, DBUS_ERROR_FILE_NOT_FOUND) == 0) 613 /* DBUS returns this error when the DBUS daemon is not running */ 614 *ret_error = AVAHI_ERR_NO_DAEMON; 615 else 616 *ret_error = avahi_error_dbus_to_number(error.name); 617 } 618 619 dbus_error_free(&error); 620 } 621 622 return NULL; 623} 624 625void avahi_client_free(AvahiClient *client) { 626 assert(client); 627 628 if (client->bus) 629 /* Disconnect in advance, so that the free() functions won't 630 * issue needless server calls */ 631#ifdef HAVE_DBUS_CONNECTION_CLOSE 632 dbus_connection_close(client->bus); 633#else 634 dbus_connection_disconnect(client->bus); 635#endif 636 637 while (client->groups) 638 avahi_entry_group_free(client->groups); 639 640 while (client->domain_browsers) 641 avahi_domain_browser_free(client->domain_browsers); 642 643 while (client->service_browsers) 644 avahi_service_browser_free(client->service_browsers); 645 646 while (client->service_type_browsers) 647 avahi_service_type_browser_free(client->service_type_browsers); 648 649 while (client->service_resolvers) 650 avahi_service_resolver_free(client->service_resolvers); 651 652 while (client->host_name_resolvers) 653 avahi_host_name_resolver_free(client->host_name_resolvers); 654 655 while (client->address_resolvers) 656 avahi_address_resolver_free(client->address_resolvers); 657 658 while (client->record_browsers) 659 avahi_record_browser_free(client->record_browsers); 660 661 if (client->bus) 662 dbus_connection_unref(client->bus); 663 664 avahi_free(client->version_string); 665 avahi_free(client->host_name); 666 avahi_free(client->host_name_fqdn); 667 avahi_free(client->domain_name); 668 669 avahi_free(client); 670} 671 672static char* avahi_client_get_string_reply_and_block (AvahiClient *client, const char *method, const char *param) { 673 DBusMessage *message = NULL, *reply = NULL; 674 DBusError error; 675 char *ret, *n; 676 677 assert(client); 678 assert(method); 679 680 dbus_error_init (&error); 681 682 if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, method))) { 683 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 684 goto fail; 685 } 686 687 if (param) { 688 if (!dbus_message_append_args (message, DBUS_TYPE_STRING, ¶m, DBUS_TYPE_INVALID)) { 689 avahi_client_set_errno (client, AVAHI_ERR_NO_MEMORY); 690 goto fail; 691 } 692 } 693 694 reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error); 695 696 if (!reply || dbus_error_is_set (&error)) 697 goto fail; 698 699 if (!dbus_message_get_args (reply, &error, DBUS_TYPE_STRING, &ret, DBUS_TYPE_INVALID) || 700 dbus_error_is_set (&error)) 701 goto fail; 702 703 if (!(n = avahi_strdup(ret))) { 704 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 705 goto fail; 706 } 707 708 dbus_message_unref(message); 709 dbus_message_unref(reply); 710 711 return n; 712 713fail: 714 715 if (message) 716 dbus_message_unref(message); 717 if (reply) 718 dbus_message_unref(reply); 719 720 if (dbus_error_is_set(&error)) { 721 avahi_client_set_dbus_error(client, &error); 722 dbus_error_free(&error); 723 } 724 725 return NULL; 726} 727 728const char* avahi_client_get_version_string(AvahiClient *client) { 729 assert(client); 730 731 if (!avahi_client_is_connected(client)) { 732 avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); 733 return NULL; 734 } 735 736 if (!client->version_string) 737 client->version_string = avahi_client_get_string_reply_and_block(client, "GetVersionString", NULL); 738 739 return client->version_string; 740} 741 742const char* avahi_client_get_domain_name(AvahiClient *client) { 743 assert(client); 744 745 if (!avahi_client_is_connected(client)) { 746 avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); 747 return NULL; 748 } 749 750 if (!client->domain_name) 751 client->domain_name = avahi_client_get_string_reply_and_block(client, "GetDomainName", NULL); 752 753 return client->domain_name; 754} 755 756const char* avahi_client_get_host_name(AvahiClient *client) { 757 assert(client); 758 759 if (!avahi_client_is_connected(client)) { 760 avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); 761 return NULL; 762 } 763 764 if (!client->host_name) 765 client->host_name = avahi_client_get_string_reply_and_block(client, "GetHostName", NULL); 766 767 return client->host_name; 768} 769 770const char* avahi_client_get_host_name_fqdn (AvahiClient *client) { 771 assert(client); 772 773 if (!avahi_client_is_connected(client)) { 774 avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); 775 return NULL; 776 } 777 778 if (!client->host_name_fqdn) 779 client->host_name_fqdn = avahi_client_get_string_reply_and_block(client, "GetHostNameFqdn", NULL); 780 781 return client->host_name_fqdn; 782} 783 784AvahiClientState avahi_client_get_state(AvahiClient *client) { 785 assert(client); 786 787 return client->state; 788} 789 790int avahi_client_errno(AvahiClient *client) { 791 assert(client); 792 793 return client->error; 794} 795 796/* Just for internal use */ 797int avahi_client_simple_method_call(AvahiClient *client, const char *path, const char *interface, const char *method) { 798 DBusMessage *message = NULL, *reply = NULL; 799 DBusError error; 800 int r = AVAHI_OK; 801 802 dbus_error_init(&error); 803 804 assert(client); 805 assert(path); 806 assert(interface); 807 assert(method); 808 809 if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, path, interface, method))) { 810 r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 811 goto fail; 812 } 813 814 if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) || 815 dbus_error_is_set (&error)) { 816 r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); 817 goto fail; 818 } 819 820 if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) || 821 dbus_error_is_set (&error)) { 822 r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); 823 goto fail; 824 } 825 826 dbus_message_unref(message); 827 dbus_message_unref(reply); 828 829 return AVAHI_OK; 830 831fail: 832 if (dbus_error_is_set(&error)) { 833 r = avahi_client_set_dbus_error(client, &error); 834 dbus_error_free(&error); 835 } 836 837 if (message) 838 dbus_message_unref(message); 839 840 if (reply) 841 dbus_message_unref(reply); 842 843 return r; 844} 845 846uint32_t avahi_client_get_local_service_cookie(AvahiClient *client) { 847 DBusMessage *message = NULL, *reply = NULL; 848 DBusError error; 849 assert(client); 850 851 if (!avahi_client_is_connected(client)) { 852 avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); 853 return AVAHI_SERVICE_COOKIE_INVALID; 854 } 855 856 if (client->local_service_cookie_valid) 857 return client->local_service_cookie; 858 859 dbus_error_init (&error); 860 861 if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "GetLocalServiceCookie"))) { 862 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 863 goto fail; 864 } 865 866 reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error); 867 868 if (!reply || dbus_error_is_set (&error)) 869 goto fail; 870 871 if (!dbus_message_get_args (reply, &error, DBUS_TYPE_UINT32, &client->local_service_cookie, DBUS_TYPE_INVALID) || 872 dbus_error_is_set (&error)) 873 goto fail; 874 875 dbus_message_unref(message); 876 dbus_message_unref(reply); 877 878 client->local_service_cookie_valid = 1; 879 return client->local_service_cookie; 880 881fail: 882 883 if (message) 884 dbus_message_unref(message); 885 if (reply) 886 dbus_message_unref(reply); 887 888 if (dbus_error_is_set(&error)) { 889 avahi_client_set_dbus_error(client, &error); 890 dbus_error_free(&error); 891 } 892 893 return AVAHI_SERVICE_COOKIE_INVALID; 894} 895 896int avahi_client_is_connected(AvahiClient *client) { 897 assert(client); 898 899 return 900 client->bus && 901 dbus_connection_get_is_connected(client->bus) && 902 (client->state == AVAHI_CLIENT_S_RUNNING || client->state == AVAHI_CLIENT_S_REGISTERING || client->state == AVAHI_CLIENT_S_COLLISION); 903} 904 905int avahi_client_set_host_name(AvahiClient* client, const char *name) { 906 DBusMessage *message = NULL, *reply = NULL; 907 DBusError error; 908 909 assert(client); 910 911 if (!avahi_client_is_connected(client)) 912 return avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); 913 914 dbus_error_init (&error); 915 916 if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "SetHostName"))) { 917 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 918 goto fail; 919 } 920 921 if (!dbus_message_append_args (message, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) { 922 avahi_client_set_errno (client, AVAHI_ERR_NO_MEMORY); 923 goto fail; 924 } 925 926 reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error); 927 928 if (!reply || dbus_error_is_set (&error)) 929 goto fail; 930 931 if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) || 932 dbus_error_is_set (&error)) 933 goto fail; 934 935 dbus_message_unref(message); 936 dbus_message_unref(reply); 937 938 avahi_free(client->host_name); 939 client->host_name = NULL; 940 avahi_free(client->host_name_fqdn); 941 client->host_name_fqdn = NULL; 942 943 return 0; 944 945fail: 946 947 if (message) 948 dbus_message_unref(message); 949 if (reply) 950 dbus_message_unref(reply); 951 952 if (dbus_error_is_set(&error)) { 953 avahi_client_set_dbus_error(client, &error); 954 dbus_error_free(&error); 955 } 956 957 return client->error; 958} 959