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 <string.h> 27#include <unistd.h> 28#include <errno.h> 29#include <stdio.h> 30#include <assert.h> 31#include <stdlib.h> 32 33#include <arpa/inet.h> 34 35#include <sys/utsname.h> 36#include <sys/types.h> 37#include <sys/socket.h> 38 39#include <avahi-common/domain.h> 40#include <avahi-common/timeval.h> 41#include <avahi-common/malloc.h> 42#include <avahi-common/error.h> 43#include <avahi-common/domain.h> 44 45#include "internal.h" 46#include "iface.h" 47#include "socket.h" 48#include "browse.h" 49#include "log.h" 50#include "util.h" 51#include "dns-srv-rr.h" 52#include "rr-util.h" 53#include "domain-util.h" 54 55static void transport_flags_from_domain(AvahiServer *s, AvahiPublishFlags *flags, const char *domain) { 56 assert(flags); 57 assert(domain); 58 59 assert(!((*flags & AVAHI_PUBLISH_USE_MULTICAST) && (*flags & AVAHI_PUBLISH_USE_WIDE_AREA))); 60 61 if (*flags & (AVAHI_PUBLISH_USE_MULTICAST|AVAHI_PUBLISH_USE_WIDE_AREA)) 62 return; 63 64 if (!s->wide_area_lookup_engine || 65 !avahi_wide_area_has_servers(s->wide_area_lookup_engine) || 66 avahi_domain_ends_with(domain, AVAHI_MDNS_SUFFIX_LOCAL) || 67 avahi_domain_ends_with(domain, AVAHI_MDNS_SUFFIX_ADDR_IPV4) || 68 avahi_domain_ends_with(domain, AVAHI_MDNS_SUFFIX_ADDR_IPV6)) 69 *flags |= AVAHI_PUBLISH_USE_MULTICAST; 70 else 71 *flags |= AVAHI_PUBLISH_USE_WIDE_AREA; 72} 73 74void avahi_entry_free(AvahiServer*s, AvahiEntry *e) { 75 AvahiEntry *t; 76 77 assert(s); 78 assert(e); 79 80 avahi_goodbye_entry(s, e, 1, 1); 81 82 /* Remove from linked list */ 83 AVAHI_LLIST_REMOVE(AvahiEntry, entries, s->entries, e); 84 85 /* Remove from hash table indexed by name */ 86 t = avahi_hashmap_lookup(s->entries_by_key, e->record->key); 87 AVAHI_LLIST_REMOVE(AvahiEntry, by_key, t, e); 88 if (t) 89 avahi_hashmap_replace(s->entries_by_key, t->record->key, t); 90 else 91 avahi_hashmap_remove(s->entries_by_key, e->record->key); 92 93 /* Remove from associated group */ 94 if (e->group) 95 AVAHI_LLIST_REMOVE(AvahiEntry, by_group, e->group->entries, e); 96 97 avahi_record_unref(e->record); 98 avahi_free(e); 99} 100 101void avahi_entry_group_free(AvahiServer *s, AvahiSEntryGroup *g) { 102 assert(s); 103 assert(g); 104 105 while (g->entries) 106 avahi_entry_free(s, g->entries); 107 108 if (g->register_time_event) 109 avahi_time_event_free(g->register_time_event); 110 111 AVAHI_LLIST_REMOVE(AvahiSEntryGroup, groups, s->groups, g); 112 avahi_free(g); 113} 114 115void avahi_cleanup_dead_entries(AvahiServer *s) { 116 assert(s); 117 118 if (s->need_group_cleanup) { 119 AvahiSEntryGroup *g, *next; 120 121 for (g = s->groups; g; g = next) { 122 next = g->groups_next; 123 124 if (g->dead) 125 avahi_entry_group_free(s, g); 126 } 127 128 s->need_group_cleanup = 0; 129 } 130 131 if (s->need_entry_cleanup) { 132 AvahiEntry *e, *next; 133 134 for (e = s->entries; e; e = next) { 135 next = e->entries_next; 136 137 if (e->dead) 138 avahi_entry_free(s, e); 139 } 140 141 s->need_entry_cleanup = 0; 142 } 143 144 if (s->need_browser_cleanup) 145 avahi_browser_cleanup(s); 146} 147 148static int check_record_conflict(AvahiServer *s, AvahiIfIndex interface, AvahiProtocol protocol, AvahiRecord *r, AvahiPublishFlags flags) { 149 AvahiEntry *e; 150 151 assert(s); 152 assert(r); 153 154 for (e = avahi_hashmap_lookup(s->entries_by_key, r->key); e; e = e->by_key_next) { 155 if (e->dead) 156 continue; 157 158 if (!(flags & AVAHI_PUBLISH_UNIQUE) && !(e->flags & AVAHI_PUBLISH_UNIQUE)) 159 continue; 160 161 if ((flags & AVAHI_PUBLISH_ALLOW_MULTIPLE) && (e->flags & AVAHI_PUBLISH_ALLOW_MULTIPLE) ) 162 continue; 163 164 if (avahi_record_equal_no_ttl(r, e->record)) { 165 /* The records are the same, not a conflict in any case */ 166 continue; 167 } 168 169 if ((interface <= 0 || 170 e->interface <= 0 || 171 e->interface == interface) && 172 (protocol == AVAHI_PROTO_UNSPEC || 173 e->protocol == AVAHI_PROTO_UNSPEC || 174 e->protocol == protocol)) 175 176 return -1; 177 } 178 179 return 0; 180} 181 182static AvahiEntry * server_add_internal( 183 AvahiServer *s, 184 AvahiSEntryGroup *g, 185 AvahiIfIndex interface, 186 AvahiProtocol protocol, 187 AvahiPublishFlags flags, 188 AvahiRecord *r) { 189 190 AvahiEntry *e; 191 192 assert(s); 193 assert(r); 194 195 AVAHI_CHECK_VALIDITY_RETURN_NULL(s, s->state != AVAHI_SERVER_FAILURE && s->state != AVAHI_SERVER_INVALID, AVAHI_ERR_BAD_STATE); 196 AVAHI_CHECK_VALIDITY_RETURN_NULL(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); 197 AVAHI_CHECK_VALIDITY_RETURN_NULL(s, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL); 198 AVAHI_CHECK_VALIDITY_RETURN_NULL(s, AVAHI_FLAGS_VALID( 199 flags, 200 AVAHI_PUBLISH_NO_ANNOUNCE| 201 AVAHI_PUBLISH_NO_PROBE| 202 AVAHI_PUBLISH_UNIQUE| 203 AVAHI_PUBLISH_ALLOW_MULTIPLE| 204 AVAHI_PUBLISH_UPDATE| 205 AVAHI_PUBLISH_USE_WIDE_AREA| 206 AVAHI_PUBLISH_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS); 207 AVAHI_CHECK_VALIDITY_RETURN_NULL(s, avahi_is_valid_domain_name(r->key->name), AVAHI_ERR_INVALID_HOST_NAME); 208 AVAHI_CHECK_VALIDITY_RETURN_NULL(s, r->ttl != 0, AVAHI_ERR_INVALID_TTL); 209 AVAHI_CHECK_VALIDITY_RETURN_NULL(s, !avahi_key_is_pattern(r->key), AVAHI_ERR_IS_PATTERN); 210 AVAHI_CHECK_VALIDITY_RETURN_NULL(s, avahi_record_is_valid(r), AVAHI_ERR_INVALID_RECORD); 211 AVAHI_CHECK_VALIDITY_RETURN_NULL(s, r->key->clazz == AVAHI_DNS_CLASS_IN, AVAHI_ERR_INVALID_DNS_CLASS); 212 AVAHI_CHECK_VALIDITY_RETURN_NULL(s, 213 (r->key->type != 0) && 214 (r->key->type != AVAHI_DNS_TYPE_ANY) && 215 (r->key->type != AVAHI_DNS_TYPE_OPT) && 216 (r->key->type != AVAHI_DNS_TYPE_TKEY) && 217 (r->key->type != AVAHI_DNS_TYPE_TSIG) && 218 (r->key->type != AVAHI_DNS_TYPE_IXFR) && 219 (r->key->type != AVAHI_DNS_TYPE_AXFR), AVAHI_ERR_INVALID_DNS_TYPE); 220 221 transport_flags_from_domain(s, &flags, r->key->name); 222 AVAHI_CHECK_VALIDITY_RETURN_NULL(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED); 223 AVAHI_CHECK_VALIDITY_RETURN_NULL(s, !s->config.disable_publishing, AVAHI_ERR_NOT_PERMITTED); 224 AVAHI_CHECK_VALIDITY_RETURN_NULL(s, 225 !g || 226 (g->state != AVAHI_ENTRY_GROUP_ESTABLISHED && g->state != AVAHI_ENTRY_GROUP_REGISTERING) || 227 (flags & AVAHI_PUBLISH_UPDATE), AVAHI_ERR_BAD_STATE); 228 229 if (flags & AVAHI_PUBLISH_UPDATE) { 230 AvahiRecord *old_record; 231 int is_first = 1; 232 233 /* Update and existing record */ 234 235 /* Find the first matching entry */ 236 for (e = avahi_hashmap_lookup(s->entries_by_key, r->key); e; e = e->by_key_next) { 237 if (!e->dead && e->group == g && e->interface == interface && e->protocol == protocol) 238 break; 239 240 is_first = 0; 241 } 242 243 /* Hmm, nothing found? */ 244 if (!e) { 245 avahi_server_set_errno(s, AVAHI_ERR_NOT_FOUND); 246 return NULL; 247 } 248 249 /* Update the entry */ 250 old_record = e->record; 251 e->record = avahi_record_ref(r); 252 e->flags = flags; 253 254 /* Announce our changes when needed */ 255 if (!avahi_record_equal_no_ttl(old_record, r) && (!g || g->state != AVAHI_ENTRY_GROUP_UNCOMMITED)) { 256 257 /* Remove the old entry from all caches, if needed */ 258 if (!(e->flags & AVAHI_PUBLISH_UNIQUE)) 259 avahi_goodbye_entry(s, e, 1, 0); 260 261 /* Reannounce our updated entry */ 262 avahi_reannounce_entry(s, e); 263 } 264 265 /* If we were the first entry in the list, we need to update the key */ 266 if (is_first) 267 avahi_hashmap_replace(s->entries_by_key, e->record->key, e); 268 269 avahi_record_unref(old_record); 270 271 } else { 272 AvahiEntry *t; 273 274 /* Add a new record */ 275 276 if (check_record_conflict(s, interface, protocol, r, flags) < 0) { 277 avahi_server_set_errno(s, AVAHI_ERR_COLLISION); 278 return NULL; 279 } 280 281 if (!(e = avahi_new(AvahiEntry, 1))) { 282 avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); 283 return NULL; 284 } 285 286 e->server = s; 287 e->record = avahi_record_ref(r); 288 e->group = g; 289 e->interface = interface; 290 e->protocol = protocol; 291 e->flags = flags; 292 e->dead = 0; 293 294 AVAHI_LLIST_HEAD_INIT(AvahiAnnouncer, e->announcers); 295 296 AVAHI_LLIST_PREPEND(AvahiEntry, entries, s->entries, e); 297 298 /* Insert into hash table indexed by name */ 299 t = avahi_hashmap_lookup(s->entries_by_key, e->record->key); 300 AVAHI_LLIST_PREPEND(AvahiEntry, by_key, t, e); 301 avahi_hashmap_replace(s->entries_by_key, e->record->key, t); 302 303 /* Insert into group list */ 304 if (g) 305 AVAHI_LLIST_PREPEND(AvahiEntry, by_group, g->entries, e); 306 307 avahi_announce_entry(s, e); 308 } 309 310 return e; 311} 312 313int avahi_server_add( 314 AvahiServer *s, 315 AvahiSEntryGroup *g, 316 AvahiIfIndex interface, 317 AvahiProtocol protocol, 318 AvahiPublishFlags flags, 319 AvahiRecord *r) { 320 321 if (!server_add_internal(s, g, interface, protocol, flags, r)) 322 return avahi_server_errno(s); 323 324 return AVAHI_OK; 325} 326 327const AvahiRecord *avahi_server_iterate(AvahiServer *s, AvahiSEntryGroup *g, void **state) { 328 AvahiEntry **e = (AvahiEntry**) state; 329 assert(s); 330 assert(e); 331 332 if (!*e) 333 *e = g ? g->entries : s->entries; 334 335 while (*e && (*e)->dead) 336 *e = g ? (*e)->by_group_next : (*e)->entries_next; 337 338 if (!*e) 339 return NULL; 340 341 return avahi_record_ref((*e)->record); 342} 343 344int avahi_server_dump(AvahiServer *s, AvahiDumpCallback callback, void* userdata) { 345 AvahiEntry *e; 346 347 assert(s); 348 assert(callback); 349 350 callback(";;; ZONE DUMP FOLLOWS ;;;", userdata); 351 352 for (e = s->entries; e; e = e->entries_next) { 353 char *t; 354 char ln[256]; 355 356 if (e->dead) 357 continue; 358 359 if (!(t = avahi_record_to_string(e->record))) 360 return avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); 361 362 snprintf(ln, sizeof(ln), "%s ; iface=%i proto=%i", t, e->interface, e->protocol); 363 avahi_free(t); 364 365 callback(ln, userdata); 366 } 367 368 avahi_dump_caches(s->monitor, callback, userdata); 369 370 if (s->wide_area_lookup_engine) 371 avahi_wide_area_cache_dump(s->wide_area_lookup_engine, callback, userdata); 372 return AVAHI_OK; 373} 374 375static AvahiEntry *server_add_ptr_internal( 376 AvahiServer *s, 377 AvahiSEntryGroup *g, 378 AvahiIfIndex interface, 379 AvahiProtocol protocol, 380 AvahiPublishFlags flags, 381 uint32_t ttl, 382 const char *name, 383 const char *dest) { 384 385 AvahiRecord *r; 386 AvahiEntry *e; 387 388 assert(s); 389 assert(dest); 390 391 AVAHI_CHECK_VALIDITY_RETURN_NULL(s, !name || avahi_is_valid_domain_name(name), AVAHI_ERR_INVALID_HOST_NAME); 392 AVAHI_CHECK_VALIDITY_RETURN_NULL(s, avahi_is_valid_domain_name(dest), AVAHI_ERR_INVALID_HOST_NAME); 393 394 if (!name) 395 name = s->host_name_fqdn; 396 397 if (!(r = avahi_record_new_full(name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_PTR, ttl))) { 398 avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); 399 return NULL; 400 } 401 402 r->data.ptr.name = avahi_normalize_name_strdup(dest); 403 e = server_add_internal(s, g, interface, protocol, flags, r); 404 avahi_record_unref(r); 405 return e; 406} 407 408int avahi_server_add_ptr( 409 AvahiServer *s, 410 AvahiSEntryGroup *g, 411 AvahiIfIndex interface, 412 AvahiProtocol protocol, 413 AvahiPublishFlags flags, 414 uint32_t ttl, 415 const char *name, 416 const char *dest) { 417 418 AvahiEntry *e; 419 420 assert(s); 421 422 if (!(e = server_add_ptr_internal(s, g, interface, protocol, flags, ttl, name, dest))) 423 return avahi_server_errno(s); 424 425 return AVAHI_OK; 426} 427 428int avahi_server_add_address( 429 AvahiServer *s, 430 AvahiSEntryGroup *g, 431 AvahiIfIndex interface, 432 AvahiProtocol protocol, 433 AvahiPublishFlags flags, 434 const char *name, 435 AvahiAddress *a) { 436 437 char n[AVAHI_DOMAIN_NAME_MAX]; 438 int ret = AVAHI_OK; 439 AvahiEntry *entry = NULL, *reverse = NULL; 440 AvahiRecord *r; 441 442 assert(s); 443 assert(a); 444 445 AVAHI_CHECK_VALIDITY(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); 446 AVAHI_CHECK_VALIDITY(s, AVAHI_PROTO_VALID(protocol) && AVAHI_PROTO_VALID(a->proto), AVAHI_ERR_INVALID_PROTOCOL); 447 AVAHI_CHECK_VALIDITY(s, AVAHI_FLAGS_VALID(flags, 448 AVAHI_PUBLISH_NO_REVERSE| 449 AVAHI_PUBLISH_NO_ANNOUNCE| 450 AVAHI_PUBLISH_NO_PROBE| 451 AVAHI_PUBLISH_UPDATE| 452 AVAHI_PUBLISH_USE_WIDE_AREA| 453 AVAHI_PUBLISH_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS); 454 AVAHI_CHECK_VALIDITY(s, !name || avahi_is_valid_fqdn(name), AVAHI_ERR_INVALID_HOST_NAME); 455 456 /* Prepare the host naem */ 457 458 if (!name) 459 name = s->host_name_fqdn; 460 else { 461 AVAHI_ASSERT_TRUE(avahi_normalize_name(name, n, sizeof(n))); 462 name = n; 463 } 464 465 transport_flags_from_domain(s, &flags, name); 466 AVAHI_CHECK_VALIDITY(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED); 467 468 /* Create the A/AAAA record */ 469 470 if (a->proto == AVAHI_PROTO_INET) { 471 472 if (!(r = avahi_record_new_full(name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_A, AVAHI_DEFAULT_TTL_HOST_NAME))) { 473 ret = avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); 474 goto finish; 475 } 476 477 r->data.a.address = a->data.ipv4; 478 479 } else { 480 assert(a->proto == AVAHI_PROTO_INET6); 481 482 if (!(r = avahi_record_new_full(name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_AAAA, AVAHI_DEFAULT_TTL_HOST_NAME))) { 483 ret = avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); 484 goto finish; 485 } 486 487 r->data.aaaa.address = a->data.ipv6; 488 } 489 490 entry = server_add_internal(s, g, interface, protocol, (flags & ~ AVAHI_PUBLISH_NO_REVERSE) | AVAHI_PUBLISH_UNIQUE | AVAHI_PUBLISH_ALLOW_MULTIPLE, r); 491 avahi_record_unref(r); 492 493 if (!entry) { 494 ret = avahi_server_errno(s); 495 goto finish; 496 } 497 498 /* Create the reverse lookup entry */ 499 500 if (!(flags & AVAHI_PUBLISH_NO_REVERSE)) { 501 char reverse_n[AVAHI_DOMAIN_NAME_MAX]; 502 avahi_reverse_lookup_name(a, reverse_n, sizeof(reverse_n)); 503 504 if (!(reverse = server_add_ptr_internal(s, g, interface, protocol, flags | AVAHI_PUBLISH_UNIQUE, AVAHI_DEFAULT_TTL_HOST_NAME, reverse_n, name))) { 505 ret = avahi_server_errno(s); 506 goto finish; 507 } 508 } 509 510finish: 511 512 if (ret != AVAHI_OK && !(flags & AVAHI_PUBLISH_UPDATE)) { 513 if (entry) 514 avahi_entry_free(s, entry); 515 if (reverse) 516 avahi_entry_free(s, reverse); 517 } 518 519 return ret; 520} 521 522static AvahiEntry *server_add_txt_strlst_nocopy( 523 AvahiServer *s, 524 AvahiSEntryGroup *g, 525 AvahiIfIndex interface, 526 AvahiProtocol protocol, 527 AvahiPublishFlags flags, 528 uint32_t ttl, 529 const char *name, 530 AvahiStringList *strlst) { 531 532 AvahiRecord *r; 533 AvahiEntry *e; 534 535 assert(s); 536 537 if (!(r = avahi_record_new_full(name ? name : s->host_name_fqdn, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_TXT, ttl))) { 538 avahi_string_list_free(strlst); 539 avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); 540 return NULL; 541 } 542 543 r->data.txt.string_list = strlst; 544 e = server_add_internal(s, g, interface, protocol, flags, r); 545 avahi_record_unref(r); 546 547 return e; 548} 549 550static AvahiStringList *add_magic_cookie( 551 AvahiServer *s, 552 AvahiStringList *strlst) { 553 554 assert(s); 555 556 if (!s->config.add_service_cookie) 557 return strlst; 558 559 if (avahi_string_list_find(strlst, AVAHI_SERVICE_COOKIE)) 560 /* This string list already contains a magic cookie */ 561 return strlst; 562 563 return avahi_string_list_add_printf(strlst, AVAHI_SERVICE_COOKIE"=%u", s->local_service_cookie); 564} 565 566static int server_add_service_strlst_nocopy( 567 AvahiServer *s, 568 AvahiSEntryGroup *g, 569 AvahiIfIndex interface, 570 AvahiProtocol protocol, 571 AvahiPublishFlags flags, 572 const char *name, 573 const char *type, 574 const char *domain, 575 const char *host, 576 uint16_t port, 577 AvahiStringList *strlst) { 578 579 char ptr_name[AVAHI_DOMAIN_NAME_MAX], svc_name[AVAHI_DOMAIN_NAME_MAX], enum_ptr[AVAHI_DOMAIN_NAME_MAX], *h = NULL; 580 AvahiRecord *r = NULL; 581 int ret = AVAHI_OK; 582 AvahiEntry *srv_entry = NULL, *txt_entry = NULL, *ptr_entry = NULL, *enum_entry = NULL; 583 584 assert(s); 585 assert(type); 586 assert(name); 587 588 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); 589 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL); 590 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_FLAGS_VALID(flags, 591 AVAHI_PUBLISH_NO_COOKIE| 592 AVAHI_PUBLISH_UPDATE| 593 AVAHI_PUBLISH_USE_WIDE_AREA| 594 AVAHI_PUBLISH_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS); 595 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_name(name), AVAHI_ERR_INVALID_SERVICE_NAME); 596 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_type_strict(type), AVAHI_ERR_INVALID_SERVICE_TYPE); 597 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME); 598 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, !host || avahi_is_valid_fqdn(host), AVAHI_ERR_INVALID_HOST_NAME); 599 600 if (!domain) 601 domain = s->domain_name; 602 603 if (!host) 604 host = s->host_name_fqdn; 605 606 transport_flags_from_domain(s, &flags, domain); 607 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED); 608 609 if (!(h = avahi_normalize_name_strdup(host))) { 610 ret = avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); 611 goto fail; 612 } 613 614 if ((ret = avahi_service_name_join(svc_name, sizeof(svc_name), name, type, domain)) < 0 || 615 (ret = avahi_service_name_join(ptr_name, sizeof(ptr_name), NULL, type, domain)) < 0 || 616 (ret = avahi_service_name_join(enum_ptr, sizeof(enum_ptr), NULL, "_services._dns-sd._udp", domain)) < 0) { 617 avahi_server_set_errno(s, ret); 618 goto fail; 619 } 620 621 /* Add service enumeration PTR record */ 622 623 if (!(ptr_entry = server_add_ptr_internal(s, g, interface, protocol, 0, AVAHI_DEFAULT_TTL, ptr_name, svc_name))) { 624 ret = avahi_server_errno(s); 625 goto fail; 626 } 627 628 /* Add SRV record */ 629 630 if (!(r = avahi_record_new_full(svc_name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_SRV, AVAHI_DEFAULT_TTL_HOST_NAME))) { 631 ret = avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); 632 goto fail; 633 } 634 635 r->data.srv.priority = 0; 636 r->data.srv.weight = 0; 637 r->data.srv.port = port; 638 r->data.srv.name = h; 639 h = NULL; 640 srv_entry = server_add_internal(s, g, interface, protocol, AVAHI_PUBLISH_UNIQUE, r); 641 avahi_record_unref(r); 642 643 if (!srv_entry) { 644 ret = avahi_server_errno(s); 645 goto fail; 646 } 647 648 /* Add TXT record */ 649 650 if (!(flags & AVAHI_PUBLISH_NO_COOKIE)) 651 strlst = add_magic_cookie(s, strlst); 652 653 txt_entry = server_add_txt_strlst_nocopy(s, g, interface, protocol, AVAHI_PUBLISH_UNIQUE, AVAHI_DEFAULT_TTL, svc_name, strlst); 654 strlst = NULL; 655 656 if (!txt_entry) { 657 ret = avahi_server_errno(s); 658 goto fail; 659 } 660 661 /* Add service type enumeration record */ 662 663 if (!(enum_entry = server_add_ptr_internal(s, g, interface, protocol, 0, AVAHI_DEFAULT_TTL, enum_ptr, ptr_name))) { 664 ret = avahi_server_errno(s); 665 goto fail; 666 } 667 668fail: 669 if (ret != AVAHI_OK && !(flags & AVAHI_PUBLISH_UPDATE)) { 670 if (srv_entry) 671 avahi_entry_free(s, srv_entry); 672 if (txt_entry) 673 avahi_entry_free(s, txt_entry); 674 if (ptr_entry) 675 avahi_entry_free(s, ptr_entry); 676 if (enum_entry) 677 avahi_entry_free(s, enum_entry); 678 } 679 680 avahi_string_list_free(strlst); 681 avahi_free(h); 682 683 return ret; 684} 685 686int avahi_server_add_service_strlst( 687 AvahiServer *s, 688 AvahiSEntryGroup *g, 689 AvahiIfIndex interface, 690 AvahiProtocol protocol, 691 AvahiPublishFlags flags, 692 const char *name, 693 const char *type, 694 const char *domain, 695 const char *host, 696 uint16_t port, 697 AvahiStringList *strlst) { 698 699 assert(s); 700 assert(type); 701 assert(name); 702 703 return server_add_service_strlst_nocopy(s, g, interface, protocol, flags, name, type, domain, host, port, avahi_string_list_copy(strlst)); 704} 705 706int avahi_server_add_service( 707 AvahiServer *s, 708 AvahiSEntryGroup *g, 709 AvahiIfIndex interface, 710 AvahiProtocol protocol, 711 AvahiPublishFlags flags, 712 const char *name, 713 const char *type, 714 const char *domain, 715 const char *host, 716 uint16_t port, 717 ... ){ 718 719 va_list va; 720 int ret; 721 722 va_start(va, port); 723 ret = server_add_service_strlst_nocopy(s, g, interface, protocol, flags, name, type, domain, host, port, avahi_string_list_new_va(va)); 724 va_end(va); 725 726 return ret; 727} 728 729static int server_update_service_txt_strlst_nocopy( 730 AvahiServer *s, 731 AvahiSEntryGroup *g, 732 AvahiIfIndex interface, 733 AvahiProtocol protocol, 734 AvahiPublishFlags flags, 735 const char *name, 736 const char *type, 737 const char *domain, 738 AvahiStringList *strlst) { 739 740 char svc_name[AVAHI_DOMAIN_NAME_MAX]; 741 int ret = AVAHI_OK; 742 AvahiEntry *e; 743 744 assert(s); 745 assert(type); 746 assert(name); 747 748 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); 749 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL); 750 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_FLAGS_VALID(flags, 751 AVAHI_PUBLISH_NO_COOKIE| 752 AVAHI_PUBLISH_USE_WIDE_AREA| 753 AVAHI_PUBLISH_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS); 754 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_name(name), AVAHI_ERR_INVALID_SERVICE_NAME); 755 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_type_strict(type), AVAHI_ERR_INVALID_SERVICE_TYPE); 756 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME); 757 758 if (!domain) 759 domain = s->domain_name; 760 761 transport_flags_from_domain(s, &flags, domain); 762 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED); 763 764 if ((ret = avahi_service_name_join(svc_name, sizeof(svc_name), name, type, domain)) < 0) { 765 avahi_server_set_errno(s, ret); 766 goto fail; 767 } 768 769 /* Add TXT record */ 770 if (!(flags & AVAHI_PUBLISH_NO_COOKIE)) 771 strlst = add_magic_cookie(s, strlst); 772 773 e = server_add_txt_strlst_nocopy(s, g, interface, protocol, AVAHI_PUBLISH_UNIQUE | AVAHI_PUBLISH_UPDATE, AVAHI_DEFAULT_TTL, svc_name, strlst); 774 strlst = NULL; 775 776 if (!e) 777 ret = avahi_server_errno(s); 778 779fail: 780 781 avahi_string_list_free(strlst); 782 783 return ret; 784} 785 786int avahi_server_update_service_txt_strlst( 787 AvahiServer *s, 788 AvahiSEntryGroup *g, 789 AvahiIfIndex interface, 790 AvahiProtocol protocol, 791 AvahiPublishFlags flags, 792 const char *name, 793 const char *type, 794 const char *domain, 795 AvahiStringList *strlst) { 796 797 return server_update_service_txt_strlst_nocopy(s, g, interface, protocol, flags, name, type, domain, avahi_string_list_copy(strlst)); 798} 799 800/** Update the TXT record for a service with the NULL termonate list of strings */ 801int avahi_server_update_service_txt( 802 AvahiServer *s, 803 AvahiSEntryGroup *g, 804 AvahiIfIndex interface, 805 AvahiProtocol protocol, 806 AvahiPublishFlags flags, 807 const char *name, 808 const char *type, 809 const char *domain, 810 ...) { 811 812 va_list va; 813 int ret; 814 815 va_start(va, domain); 816 ret = server_update_service_txt_strlst_nocopy(s, g, interface, protocol, flags, name, type, domain, avahi_string_list_new_va(va)); 817 va_end(va); 818 819 return ret; 820} 821 822int avahi_server_add_service_subtype( 823 AvahiServer *s, 824 AvahiSEntryGroup *g, 825 AvahiIfIndex interface, 826 AvahiProtocol protocol, 827 AvahiPublishFlags flags, 828 const char *name, 829 const char *type, 830 const char *domain, 831 const char *subtype) { 832 833 int ret = AVAHI_OK; 834 char svc_name[AVAHI_DOMAIN_NAME_MAX], ptr_name[AVAHI_DOMAIN_NAME_MAX]; 835 836 assert(name); 837 assert(type); 838 assert(subtype); 839 840 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); 841 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL); 842 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_FLAGS_VALID(flags, AVAHI_PUBLISH_USE_MULTICAST|AVAHI_PUBLISH_USE_WIDE_AREA), AVAHI_ERR_INVALID_FLAGS); 843 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_name(name), AVAHI_ERR_INVALID_SERVICE_NAME); 844 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_type_strict(type), AVAHI_ERR_INVALID_SERVICE_TYPE); 845 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME); 846 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_subtype(subtype), AVAHI_ERR_INVALID_SERVICE_SUBTYPE); 847 848 if (!domain) 849 domain = s->domain_name; 850 851 transport_flags_from_domain(s, &flags, domain); 852 AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED); 853 854 if ((ret = avahi_service_name_join(svc_name, sizeof(svc_name), name, type, domain)) < 0 || 855 (ret = avahi_service_name_join(ptr_name, sizeof(ptr_name), NULL, subtype, domain)) < 0) { 856 avahi_server_set_errno(s, ret); 857 goto fail; 858 } 859 860 if ((ret = avahi_server_add_ptr(s, g, interface, protocol, 0, AVAHI_DEFAULT_TTL, ptr_name, svc_name)) < 0) 861 goto fail; 862 863fail: 864 865 return ret; 866} 867 868static void hexstring(char *s, size_t sl, const void *p, size_t pl) { 869 static const char hex[] = "0123456789abcdef"; 870 int b = 0; 871 const uint8_t *k = p; 872 873 while (sl > 1 && pl > 0) { 874 *(s++) = hex[(b ? *k : *k >> 4) & 0xF]; 875 876 if (b) { 877 k++; 878 pl--; 879 } 880 881 b = !b; 882 883 sl--; 884 } 885 886 if (sl > 0) 887 *s = 0; 888} 889 890static AvahiEntry *server_add_dns_server_name( 891 AvahiServer *s, 892 AvahiSEntryGroup *g, 893 AvahiIfIndex interface, 894 AvahiProtocol protocol, 895 AvahiPublishFlags flags, 896 const char *domain, 897 AvahiDNSServerType type, 898 const char *name, 899 uint16_t port /** should be 53 */) { 900 901 AvahiEntry *e; 902 char t[AVAHI_DOMAIN_NAME_MAX], normalized_d[AVAHI_DOMAIN_NAME_MAX], *n; 903 904 AvahiRecord *r; 905 906 assert(s); 907 assert(name); 908 909 AVAHI_CHECK_VALIDITY_RETURN_NULL(s, AVAHI_FLAGS_VALID(flags, AVAHI_PUBLISH_USE_WIDE_AREA|AVAHI_PUBLISH_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS); 910 AVAHI_CHECK_VALIDITY_RETURN_NULL(s, type == AVAHI_DNS_SERVER_UPDATE || type == AVAHI_DNS_SERVER_RESOLVE, AVAHI_ERR_INVALID_FLAGS); 911 AVAHI_CHECK_VALIDITY_RETURN_NULL(s, port != 0, AVAHI_ERR_INVALID_PORT); 912 AVAHI_CHECK_VALIDITY_RETURN_NULL(s, avahi_is_valid_fqdn(name), AVAHI_ERR_INVALID_HOST_NAME); 913 AVAHI_CHECK_VALIDITY_RETURN_NULL(s, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME); 914 915 if (!domain) 916 domain = s->domain_name; 917 918 transport_flags_from_domain(s, &flags, domain); 919 AVAHI_CHECK_VALIDITY_RETURN_NULL(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED); 920 921 if (!(n = avahi_normalize_name_strdup(name))) { 922 avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); 923 return NULL; 924 } 925 926 AVAHI_ASSERT_TRUE(avahi_normalize_name(domain, normalized_d, sizeof(normalized_d))); 927 928 snprintf(t, sizeof(t), "%s.%s", type == AVAHI_DNS_SERVER_RESOLVE ? "_domain._udp" : "_dns-update._udp", normalized_d); 929 930 if (!(r = avahi_record_new_full(t, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_SRV, AVAHI_DEFAULT_TTL_HOST_NAME))) { 931 avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); 932 avahi_free(n); 933 return NULL; 934 } 935 936 r->data.srv.priority = 0; 937 r->data.srv.weight = 0; 938 r->data.srv.port = port; 939 r->data.srv.name = n; 940 e = server_add_internal(s, g, interface, protocol, 0, r); 941 avahi_record_unref(r); 942 943 return e; 944} 945 946int avahi_server_add_dns_server_address( 947 AvahiServer *s, 948 AvahiSEntryGroup *g, 949 AvahiIfIndex interface, 950 AvahiProtocol protocol, 951 AvahiPublishFlags flags, 952 const char *domain, 953 AvahiDNSServerType type, 954 const AvahiAddress *address, 955 uint16_t port /** should be 53 */) { 956 957 AvahiRecord *r; 958 char n[64], h[64]; 959 AvahiEntry *a_entry, *s_entry; 960 961 assert(s); 962 assert(address); 963 964 AVAHI_CHECK_VALIDITY(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE); 965 AVAHI_CHECK_VALIDITY(s, AVAHI_PROTO_VALID(protocol) && AVAHI_PROTO_VALID(address->proto), AVAHI_ERR_INVALID_PROTOCOL); 966 AVAHI_CHECK_VALIDITY(s, AVAHI_FLAGS_VALID(flags, AVAHI_PUBLISH_USE_MULTICAST|AVAHI_PUBLISH_USE_WIDE_AREA), AVAHI_ERR_INVALID_FLAGS); 967 AVAHI_CHECK_VALIDITY(s, type == AVAHI_DNS_SERVER_UPDATE || type == AVAHI_DNS_SERVER_RESOLVE, AVAHI_ERR_INVALID_FLAGS); 968 AVAHI_CHECK_VALIDITY(s, port != 0, AVAHI_ERR_INVALID_PORT); 969 AVAHI_CHECK_VALIDITY(s, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME); 970 971 if (!domain) 972 domain = s->domain_name; 973 974 transport_flags_from_domain(s, &flags, domain); 975 AVAHI_CHECK_VALIDITY(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED); 976 977 if (address->proto == AVAHI_PROTO_INET) { 978 hexstring(h, sizeof(h), &address->data, sizeof(AvahiIPv4Address)); 979 snprintf(n, sizeof(n), "ip-%s.%s", h, domain); 980 r = avahi_record_new_full(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_A, AVAHI_DEFAULT_TTL_HOST_NAME); 981 r->data.a.address = address->data.ipv4; 982 } else { 983 hexstring(h, sizeof(h), &address->data, sizeof(AvahiIPv6Address)); 984 snprintf(n, sizeof(n), "ip6-%s.%s", h, domain); 985 r = avahi_record_new_full(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_AAAA, AVAHI_DEFAULT_TTL_HOST_NAME); 986 r->data.aaaa.address = address->data.ipv6; 987 } 988 989 if (!r) 990 return avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); 991 992 a_entry = server_add_internal(s, g, interface, protocol, AVAHI_PUBLISH_UNIQUE | AVAHI_PUBLISH_ALLOW_MULTIPLE, r); 993 avahi_record_unref(r); 994 995 if (!a_entry) 996 return avahi_server_errno(s); 997 998 if (!(s_entry = server_add_dns_server_name(s, g, interface, protocol, flags, domain, type, n, port))) { 999 if (!(flags & AVAHI_PUBLISH_UPDATE)) 1000 avahi_entry_free(s, a_entry); 1001 return avahi_server_errno(s); 1002 } 1003 1004 return AVAHI_OK; 1005} 1006 1007void avahi_s_entry_group_change_state(AvahiSEntryGroup *g, AvahiEntryGroupState state) { 1008 assert(g); 1009 1010 if (g->state == state) 1011 return; 1012 1013 assert(state <= AVAHI_ENTRY_GROUP_COLLISION); 1014 1015 if (g->state == AVAHI_ENTRY_GROUP_ESTABLISHED) { 1016 1017 /* If the entry group was established for a time longer then 1018 * 5s, reset the establishment trial counter */ 1019 1020 if (avahi_age(&g->established_at) > 5000000) 1021 g->n_register_try = 0; 1022 } else if (g->state == AVAHI_ENTRY_GROUP_REGISTERING) { 1023 if (g->register_time_event) { 1024 avahi_time_event_free(g->register_time_event); 1025 g->register_time_event = NULL; 1026 } 1027 } 1028 1029 if (state == AVAHI_ENTRY_GROUP_ESTABLISHED) 1030 1031 /* If the entry group is now established, remember the time 1032 * this happened */ 1033 1034 gettimeofday(&g->established_at, NULL); 1035 1036 g->state = state; 1037 1038 if (g->callback) 1039 g->callback(g->server, g, state, g->userdata); 1040} 1041 1042AvahiSEntryGroup *avahi_s_entry_group_new(AvahiServer *s, AvahiSEntryGroupCallback callback, void* userdata) { 1043 AvahiSEntryGroup *g; 1044 1045 assert(s); 1046 1047 if (!(g = avahi_new(AvahiSEntryGroup, 1))) { 1048 avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); 1049 return NULL; 1050 } 1051 1052 g->server = s; 1053 g->callback = callback; 1054 g->userdata = userdata; 1055 g->dead = 0; 1056 g->state = AVAHI_ENTRY_GROUP_UNCOMMITED; 1057 g->n_probing = 0; 1058 g->n_register_try = 0; 1059 g->register_time_event = NULL; 1060 g->register_time.tv_sec = 0; 1061 g->register_time.tv_usec = 0; 1062 AVAHI_LLIST_HEAD_INIT(AvahiEntry, g->entries); 1063 1064 AVAHI_LLIST_PREPEND(AvahiSEntryGroup, groups, s->groups, g); 1065 return g; 1066} 1067 1068void avahi_s_entry_group_free(AvahiSEntryGroup *g) { 1069 AvahiEntry *e; 1070 1071 assert(g); 1072 assert(g->server); 1073 1074 for (e = g->entries; e; e = e->by_group_next) { 1075 if (!e->dead) { 1076 avahi_goodbye_entry(g->server, e, 1, 1); 1077 e->dead = 1; 1078 } 1079 } 1080 1081 if (g->register_time_event) { 1082 avahi_time_event_free(g->register_time_event); 1083 g->register_time_event = NULL; 1084 } 1085 1086 g->dead = 1; 1087 1088 g->server->need_group_cleanup = 1; 1089 g->server->need_entry_cleanup = 1; 1090} 1091 1092static void entry_group_commit_real(AvahiSEntryGroup *g) { 1093 assert(g); 1094 1095 gettimeofday(&g->register_time, NULL); 1096 1097 avahi_s_entry_group_change_state(g, AVAHI_ENTRY_GROUP_REGISTERING); 1098 1099 if (g->dead) 1100 return; 1101 1102 avahi_announce_group(g->server, g); 1103 avahi_s_entry_group_check_probed(g, 0); 1104} 1105 1106static void entry_group_register_time_event_callback(AVAHI_GCC_UNUSED AvahiTimeEvent *e, void* userdata) { 1107 AvahiSEntryGroup *g = userdata; 1108 assert(g); 1109 1110 avahi_time_event_free(g->register_time_event); 1111 g->register_time_event = NULL; 1112 1113 /* Holdoff time passed, so let's start probing */ 1114 entry_group_commit_real(g); 1115} 1116 1117int avahi_s_entry_group_commit(AvahiSEntryGroup *g) { 1118 struct timeval now; 1119 1120 assert(g); 1121 assert(!g->dead); 1122 1123 if (g->state != AVAHI_ENTRY_GROUP_UNCOMMITED && g->state != AVAHI_ENTRY_GROUP_COLLISION) 1124 return avahi_server_set_errno(g->server, AVAHI_ERR_BAD_STATE); 1125 1126 if (avahi_s_entry_group_is_empty(g)) 1127 return avahi_server_set_errno(g->server, AVAHI_ERR_IS_EMPTY); 1128 1129 g->n_register_try++; 1130 1131 avahi_timeval_add(&g->register_time, 1132 1000*(g->n_register_try >= AVAHI_RR_RATE_LIMIT_COUNT ? 1133 AVAHI_RR_HOLDOFF_MSEC_RATE_LIMIT : 1134 AVAHI_RR_HOLDOFF_MSEC)); 1135 1136 gettimeofday(&now, NULL); 1137 1138 if (avahi_timeval_compare(&g->register_time, &now) <= 0) { 1139 1140 /* Holdoff time passed, so let's start probing */ 1141 entry_group_commit_real(g); 1142 } else { 1143 1144 /* Holdoff time has not yet passed, so let's wait */ 1145 assert(!g->register_time_event); 1146 g->register_time_event = avahi_time_event_new(g->server->time_event_queue, &g->register_time, entry_group_register_time_event_callback, g); 1147 1148 avahi_s_entry_group_change_state(g, AVAHI_ENTRY_GROUP_REGISTERING); 1149 } 1150 1151 return AVAHI_OK; 1152} 1153 1154void avahi_s_entry_group_reset(AvahiSEntryGroup *g) { 1155 AvahiEntry *e; 1156 assert(g); 1157 1158 for (e = g->entries; e; e = e->by_group_next) { 1159 if (!e->dead) { 1160 avahi_goodbye_entry(g->server, e, 1, 1); 1161 e->dead = 1; 1162 } 1163 } 1164 g->server->need_entry_cleanup = 1; 1165 1166 g->n_probing = 0; 1167 1168 avahi_s_entry_group_change_state(g, AVAHI_ENTRY_GROUP_UNCOMMITED); 1169} 1170 1171int avahi_entry_is_commited(AvahiEntry *e) { 1172 assert(e); 1173 assert(!e->dead); 1174 1175 return !e->group || 1176 e->group->state == AVAHI_ENTRY_GROUP_REGISTERING || 1177 e->group->state == AVAHI_ENTRY_GROUP_ESTABLISHED; 1178} 1179 1180AvahiEntryGroupState avahi_s_entry_group_get_state(AvahiSEntryGroup *g) { 1181 assert(g); 1182 assert(!g->dead); 1183 1184 return g->state; 1185} 1186 1187void avahi_s_entry_group_set_data(AvahiSEntryGroup *g, void* userdata) { 1188 assert(g); 1189 1190 g->userdata = userdata; 1191} 1192 1193void* avahi_s_entry_group_get_data(AvahiSEntryGroup *g) { 1194 assert(g); 1195 1196 return g->userdata; 1197} 1198 1199int avahi_s_entry_group_is_empty(AvahiSEntryGroup *g) { 1200 AvahiEntry *e; 1201 assert(g); 1202 1203 /* Look for an entry that is not dead */ 1204 for (e = g->entries; e; e = e->by_group_next) 1205 if (!e->dead) 1206 return 0; 1207 1208 return 1; 1209} 1210