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-common/dbus.h> 33#include <avahi-common/llist.h> 34#include <avahi-common/error.h> 35#include <avahi-common/dbus.h> 36#include <avahi-common/malloc.h> 37#include <avahi-common/dbus-watch-glue.h> 38 39#include "client.h" 40#include "internal.h" 41 42#define AVAHI_CLIENT_DBUS_API_SUPPORTED ((uint32_t) 0x0201) 43 44static int init_server(AvahiClient *client, int *ret_error); 45 46int avahi_client_set_errno (AvahiClient *client, int error) { 47 assert(client); 48 49 return client->error = error; 50} 51 52int avahi_client_set_dbus_error(AvahiClient *client, DBusError *error) { 53 assert(client); 54 assert(error); 55 56 return avahi_client_set_errno(client, avahi_error_dbus_to_number(error->name)); 57} 58 59static void client_set_state (AvahiClient *client, AvahiServerState state) { 60 assert(client); 61 62 if (client->state == state) 63 return; 64 65 client->state = state; 66 67 switch (client->state) { 68 case AVAHI_CLIENT_FAILURE: 69 if (client->bus) { 70#ifdef HAVE_DBUS_CONNECTION_CLOSE 71 dbus_connection_close(client->bus); 72#else 73 dbus_connection_disconnect(client->bus); 74#endif 75 dbus_connection_unref(client->bus); 76 client->bus = NULL; 77 } 78 79 /* Fall through */ 80 81 case AVAHI_CLIENT_S_COLLISION: 82 case AVAHI_CLIENT_S_REGISTERING: 83 84 /* Clear cached strings */ 85 avahi_free(client->host_name); 86 avahi_free(client->host_name_fqdn); 87 avahi_free(client->domain_name); 88 89 client->host_name = NULL; 90 client->host_name_fqdn = NULL; 91 client->domain_name = NULL; 92 break; 93 94 case AVAHI_CLIENT_S_RUNNING: 95 case AVAHI_CLIENT_CONNECTING: 96 break; 97 98 } 99 100 if (client->callback) 101 client->callback (client, state, client->userdata); 102} 103 104static DBusHandlerResult filter_func(DBusConnection *bus, DBusMessage *message, void *userdata) { 105 AvahiClient *client = userdata; 106 DBusError error; 107 108 assert(bus); 109 assert(message); 110 111 dbus_error_init(&error); 112 113/* fprintf(stderr, "dbus: interface=%s, path=%s, member=%s\n", */ 114/* dbus_message_get_interface (message), */ 115/* dbus_message_get_path (message), */ 116/* dbus_message_get_member (message)); */ 117 118 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) { 119 120 /* The DBUS server died or kicked us */ 121 avahi_client_set_errno(client, AVAHI_ERR_DISCONNECTED); 122 goto fail; 123 124 } else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameAcquired")) { 125 126 /* Ignore this message */ 127 128 } else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) { 129 char *name, *old, *new; 130 131 if (!dbus_message_get_args( 132 message, &error, 133 DBUS_TYPE_STRING, &name, 134 DBUS_TYPE_STRING, &old, 135 DBUS_TYPE_STRING, &new, 136 DBUS_TYPE_INVALID) || dbus_error_is_set(&error)) { 137 138 fprintf(stderr, "WARNING: Failed to parse NameOwnerChanged signal: %s\n", error.message); 139 avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); 140 goto fail; 141 } 142 143 if (strcmp(name, AVAHI_DBUS_NAME) == 0) { 144 145 if (avahi_client_is_connected(client)) { 146 147 /* Regardless if the server lost or acquired 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, (AvahiServerState) 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 482 avahi_init_i18n(); 483 484 dbus_error_init(&error); 485 486 if (!(client = avahi_new(AvahiClient, 1))) { 487 if (ret_error) 488 *ret_error = AVAHI_ERR_NO_MEMORY; 489 goto fail; 490 } 491 492 client->poll_api = poll_api; 493 client->error = AVAHI_OK; 494 client->callback = callback; 495 client->userdata = userdata; 496 client->state = (AvahiClientState) -1; 497 client->flags = flags; 498 499 client->host_name = NULL; 500 client->host_name_fqdn = NULL; 501 client->domain_name = NULL; 502 client->version_string = NULL; 503 client->local_service_cookie_valid = 0; 504 505 AVAHI_LLIST_HEAD_INIT(AvahiEntryGroup, client->groups); 506 AVAHI_LLIST_HEAD_INIT(AvahiDomainBrowser, client->domain_browsers); 507 AVAHI_LLIST_HEAD_INIT(AvahiServiceBrowser, client->service_browsers); 508 AVAHI_LLIST_HEAD_INIT(AvahiServiceTypeBrowser, client->service_type_browsers); 509 AVAHI_LLIST_HEAD_INIT(AvahiServiceResolver, client->service_resolvers); 510 AVAHI_LLIST_HEAD_INIT(AvahiHostNameResolver, client->host_name_resolvers); 511 AVAHI_LLIST_HEAD_INIT(AvahiAddressResolver, client->address_resolvers); 512 AVAHI_LLIST_HEAD_INIT(AvahiRecordBrowser, client->record_browsers); 513 514 if (!(client->bus = avahi_dbus_bus_get(&error)) || dbus_error_is_set(&error)) { 515 if (ret_error) 516 *ret_error = AVAHI_ERR_DBUS_ERROR; 517 goto fail; 518 } 519 520 if (avahi_dbus_connection_glue(client->bus, poll_api) < 0) { 521 if (ret_error) 522 *ret_error = AVAHI_ERR_NO_MEMORY; /* Not optimal */ 523 goto fail; 524 } 525 526 if (!dbus_connection_add_filter (client->bus, filter_func, client, NULL)) { 527 if (ret_error) 528 *ret_error = AVAHI_ERR_NO_MEMORY; 529 goto fail; 530 } 531 532 dbus_bus_add_match( 533 client->bus, 534 "type='signal', " 535 "interface='" AVAHI_DBUS_INTERFACE_SERVER "', " 536 "sender='" AVAHI_DBUS_NAME "', " 537 "path='" AVAHI_DBUS_PATH_SERVER "'", 538 &error); 539 540 if (dbus_error_is_set(&error)) 541 goto fail; 542 543 dbus_bus_add_match ( 544 client->bus, 545 "type='signal', " 546 "interface='" DBUS_INTERFACE_DBUS "', " 547 "sender='" DBUS_SERVICE_DBUS "', " 548 "path='" DBUS_PATH_DBUS "'", 549 &error); 550 551 if (dbus_error_is_set(&error)) 552 goto fail; 553 554 dbus_bus_add_match ( 555 client->bus, 556 "type='signal', " 557 "interface='" DBUS_INTERFACE_LOCAL "'", 558 &error); 559 560 if (dbus_error_is_set(&error)) 561 goto fail; 562 563 564 if (!(dbus_bus_name_has_owner(client->bus, AVAHI_DBUS_NAME, &error)) || 565 dbus_error_is_set(&error)) { 566 567 /* We free the error so its not set, that way the fail target 568 * will return the NO_DAEMON error rather than a DBUS error */ 569 dbus_error_free(&error); 570 571 if (!(flags & AVAHI_CLIENT_NO_FAIL)) { 572 573 if (ret_error) 574 *ret_error = AVAHI_ERR_NO_DAEMON; 575 576 goto fail; 577 } 578 579 /* The user doesn't want this call to fail if the daemon is not 580 * available, so let's return succesfully */ 581 client_set_state(client, AVAHI_CLIENT_CONNECTING); 582 583 } else { 584 585 if (init_server(client, ret_error) < 0) 586 goto fail; 587 } 588 589 return client; 590 591fail: 592 593 if (client) 594 avahi_client_free(client); 595 596 if (dbus_error_is_set(&error)) { 597 598 if (ret_error) { 599 if (strcmp(error.name, DBUS_ERROR_FILE_NOT_FOUND) == 0) 600 /* DBUS returns this error when the DBUS daemon is not running */ 601 *ret_error = AVAHI_ERR_NO_DAEMON; 602 else 603 *ret_error = avahi_error_dbus_to_number(error.name); 604 } 605 606 dbus_error_free(&error); 607 } 608 609 return NULL; 610} 611 612void avahi_client_free(AvahiClient *client) { 613 assert(client); 614 615 if (client->bus) 616 /* Disconnect in advance, so that the free() functions won't 617 * issue needless server calls */ 618#ifdef HAVE_DBUS_CONNECTION_CLOSE 619 dbus_connection_close(client->bus); 620#else 621 dbus_connection_disconnect(client->bus); 622#endif 623 624 while (client->groups) 625 avahi_entry_group_free(client->groups); 626 627 while (client->domain_browsers) 628 avahi_domain_browser_free(client->domain_browsers); 629 630 while (client->service_browsers) 631 avahi_service_browser_free(client->service_browsers); 632 633 while (client->service_type_browsers) 634 avahi_service_type_browser_free(client->service_type_browsers); 635 636 while (client->service_resolvers) 637 avahi_service_resolver_free(client->service_resolvers); 638 639 while (client->host_name_resolvers) 640 avahi_host_name_resolver_free(client->host_name_resolvers); 641 642 while (client->address_resolvers) 643 avahi_address_resolver_free(client->address_resolvers); 644 645 while (client->record_browsers) 646 avahi_record_browser_free(client->record_browsers); 647 648 if (client->bus) 649 dbus_connection_unref(client->bus); 650 651 avahi_free(client->version_string); 652 avahi_free(client->host_name); 653 avahi_free(client->host_name_fqdn); 654 avahi_free(client->domain_name); 655 656 avahi_free(client); 657} 658 659static char* avahi_client_get_string_reply_and_block (AvahiClient *client, const char *method, const char *param) { 660 DBusMessage *message = NULL, *reply = NULL; 661 DBusError error; 662 char *ret, *n; 663 664 assert(client); 665 assert(method); 666 667 dbus_error_init (&error); 668 669 if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, method))) { 670 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 671 goto fail; 672 } 673 674 if (param) { 675 if (!dbus_message_append_args (message, DBUS_TYPE_STRING, ¶m, DBUS_TYPE_INVALID)) { 676 avahi_client_set_errno (client, AVAHI_ERR_NO_MEMORY); 677 goto fail; 678 } 679 } 680 681 reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error); 682 683 if (!reply || dbus_error_is_set (&error)) 684 goto fail; 685 686 if (!dbus_message_get_args (reply, &error, DBUS_TYPE_STRING, &ret, DBUS_TYPE_INVALID) || 687 dbus_error_is_set (&error)) 688 goto fail; 689 690 if (!(n = avahi_strdup(ret))) { 691 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 692 goto fail; 693 } 694 695 dbus_message_unref(message); 696 dbus_message_unref(reply); 697 698 return n; 699 700fail: 701 702 if (message) 703 dbus_message_unref(message); 704 if (reply) 705 dbus_message_unref(reply); 706 707 if (dbus_error_is_set(&error)) { 708 avahi_client_set_dbus_error(client, &error); 709 dbus_error_free(&error); 710 } 711 712 return NULL; 713} 714 715const char* avahi_client_get_version_string(AvahiClient *client) { 716 assert(client); 717 718 if (!avahi_client_is_connected(client)) { 719 avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); 720 return NULL; 721 } 722 723 if (!client->version_string) 724 client->version_string = avahi_client_get_string_reply_and_block(client, "GetVersionString", NULL); 725 726 return client->version_string; 727} 728 729const char* avahi_client_get_domain_name(AvahiClient *client) { 730 assert(client); 731 732 if (!avahi_client_is_connected(client)) { 733 avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); 734 return NULL; 735 } 736 737 if (!client->domain_name) 738 client->domain_name = avahi_client_get_string_reply_and_block(client, "GetDomainName", NULL); 739 740 return client->domain_name; 741} 742 743const char* avahi_client_get_host_name(AvahiClient *client) { 744 assert(client); 745 746 if (!avahi_client_is_connected(client)) { 747 avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); 748 return NULL; 749 } 750 751 if (!client->host_name) 752 client->host_name = avahi_client_get_string_reply_and_block(client, "GetHostName", NULL); 753 754 return client->host_name; 755} 756 757const char* avahi_client_get_host_name_fqdn (AvahiClient *client) { 758 assert(client); 759 760 if (!avahi_client_is_connected(client)) { 761 avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); 762 return NULL; 763 } 764 765 if (!client->host_name_fqdn) 766 client->host_name_fqdn = avahi_client_get_string_reply_and_block(client, "GetHostNameFqdn", NULL); 767 768 return client->host_name_fqdn; 769} 770 771AvahiClientState avahi_client_get_state(AvahiClient *client) { 772 assert(client); 773 774 return client->state; 775} 776 777int avahi_client_errno(AvahiClient *client) { 778 assert(client); 779 780 return client->error; 781} 782 783/* Just for internal use */ 784int avahi_client_simple_method_call(AvahiClient *client, const char *path, const char *interface, const char *method) { 785 DBusMessage *message = NULL, *reply = NULL; 786 DBusError error; 787 int r = AVAHI_OK; 788 789 dbus_error_init(&error); 790 791 assert(client); 792 assert(path); 793 assert(interface); 794 assert(method); 795 796 if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, path, interface, method))) { 797 r = avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 798 goto fail; 799 } 800 801 if (!(reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error)) || 802 dbus_error_is_set (&error)) { 803 r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); 804 goto fail; 805 } 806 807 if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) || 808 dbus_error_is_set (&error)) { 809 r = avahi_client_set_errno(client, AVAHI_ERR_DBUS_ERROR); 810 goto fail; 811 } 812 813 dbus_message_unref(message); 814 dbus_message_unref(reply); 815 816 return AVAHI_OK; 817 818fail: 819 if (dbus_error_is_set(&error)) { 820 r = avahi_client_set_dbus_error(client, &error); 821 dbus_error_free(&error); 822 } 823 824 if (message) 825 dbus_message_unref(message); 826 827 if (reply) 828 dbus_message_unref(reply); 829 830 return r; 831} 832 833uint32_t avahi_client_get_local_service_cookie(AvahiClient *client) { 834 DBusMessage *message = NULL, *reply = NULL; 835 DBusError error; 836 assert(client); 837 838 if (!avahi_client_is_connected(client)) { 839 avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); 840 return AVAHI_SERVICE_COOKIE_INVALID; 841 } 842 843 if (client->local_service_cookie_valid) 844 return client->local_service_cookie; 845 846 dbus_error_init (&error); 847 848 if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "GetLocalServiceCookie"))) { 849 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 850 goto fail; 851 } 852 853 reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error); 854 855 if (!reply || dbus_error_is_set (&error)) 856 goto fail; 857 858 if (!dbus_message_get_args (reply, &error, DBUS_TYPE_UINT32, &client->local_service_cookie, DBUS_TYPE_INVALID) || 859 dbus_error_is_set (&error)) 860 goto fail; 861 862 dbus_message_unref(message); 863 dbus_message_unref(reply); 864 865 client->local_service_cookie_valid = 1; 866 return client->local_service_cookie; 867 868fail: 869 870 if (message) 871 dbus_message_unref(message); 872 if (reply) 873 dbus_message_unref(reply); 874 875 if (dbus_error_is_set(&error)) { 876 avahi_client_set_dbus_error(client, &error); 877 dbus_error_free(&error); 878 } 879 880 return AVAHI_SERVICE_COOKIE_INVALID; 881} 882 883int avahi_client_is_connected(AvahiClient *client) { 884 assert(client); 885 886 return 887 client->bus && 888 dbus_connection_get_is_connected(client->bus) && 889 (client->state == AVAHI_CLIENT_S_RUNNING || client->state == AVAHI_CLIENT_S_REGISTERING || client->state == AVAHI_CLIENT_S_COLLISION); 890} 891 892int avahi_client_set_host_name(AvahiClient* client, const char *name) { 893 DBusMessage *message = NULL, *reply = NULL; 894 DBusError error; 895 896 assert(client); 897 898 if (!avahi_client_is_connected(client)) 899 return avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); 900 901 dbus_error_init (&error); 902 903 if (!(message = dbus_message_new_method_call (AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "SetHostName"))) { 904 avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); 905 goto fail; 906 } 907 908 if (!dbus_message_append_args (message, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) { 909 avahi_client_set_errno (client, AVAHI_ERR_NO_MEMORY); 910 goto fail; 911 } 912 913 reply = dbus_connection_send_with_reply_and_block(client->bus, message, -1, &error); 914 915 if (!reply || dbus_error_is_set (&error)) 916 goto fail; 917 918 if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID) || 919 dbus_error_is_set (&error)) 920 goto fail; 921 922 dbus_message_unref(message); 923 dbus_message_unref(reply); 924 925 avahi_free(client->host_name); 926 client->host_name = NULL; 927 avahi_free(client->host_name_fqdn); 928 client->host_name_fqdn = NULL; 929 930 return 0; 931 932fail: 933 934 if (message) 935 dbus_message_unref(message); 936 if (reply) 937 dbus_message_unref(reply); 938 939 if (dbus_error_is_set(&error)) { 940 avahi_client_set_dbus_error(client, &error); 941 dbus_error_free(&error); 942 } 943 944 return client->error; 945} 946