1 --- /usr/tmp/clean/avahi-0.6.12/avahi-core/entry.c 2006-03-02 01:30:17.000000000 +0000 2 +++ avahi-0.6.12/avahi-core/entry.c 2006-08-28 14:26:37.958555000 +0100 3 @@ -52,6 +52,33 @@ 4 #include "rr-util.h" 5 #include "domain-util.h" 6 7 +#ifdef HAVE_BONJOUR 8 + 9 +struct AvahiService { 10 + AvahiServer *server; 11 + AvahiSEntryGroup *group; 12 + 13 + int dead; 14 + 15 + AvahiPublishFlags flags; 16 + AvahiIfIndex interface; 17 + AvahiProtocol protocol; 18 + 19 + char *name; 20 + char *type; 21 + char *domain; 22 + char *host; 23 + uint16_t port; 24 + 25 + AvahiWatch *watch; 26 + DNSServiceRef client; 27 + size_t txtlen; 28 + uint8_t *txtrecord; 29 + 30 + AVAHI_LLIST_FIELDS(AvahiService, services); 31 +}; 32 +#endif 33 + 34 static void transport_flags_from_domain(AvahiServer *s, AvahiPublishFlags *flags, const char *domain) { 35 assert(flags); 36 assert(domain); 37 @@ -71,13 +98,146 @@ 38 *flags |= AVAHI_PUBLISH_USE_WIDE_AREA; 39 } 40 41 +#ifdef HAVE_BONJOUR 42 +static void register_service_reply(DNSServiceRef client, const DNSServiceFlags flags, DNSServiceErrorType errorCode, 43 + const char *name, const char *regtype, const char *domain, void *context) { 44 + AvahiService *as = context; 45 + 46 + switch (errorCode) { 47 + case kDNSServiceErr_NoError: 48 + as->group->n_probing--; 49 + if (as->group->n_probing == 0) { 50 + avahi_s_entry_group_change_state(as->group, AVAHI_ENTRY_GROUP_ESTABLISHED); 51 + } 52 + break; 53 + case kDNSServiceErr_NameConflict: 54 + avahi_s_entry_group_change_state(as->group, AVAHI_ENTRY_GROUP_COLLISION); 55 + break; 56 + default: 57 + avahi_s_entry_group_change_state(as->group, AVAHI_ENTRY_GROUP_FAILURE); 58 + } 59 +} 60 + 61 +static void register_service_socket_event(AvahiWatch *w, int fd, AvahiWatchEvent events, void *userdata) { 62 + AvahiService *as = userdata; 63 + DNSServiceErrorType ret; 64 + 65 + assert(w); 66 + assert(fd >= 0); 67 + assert(events & AVAHI_WATCH_IN); 68 + 69 + assert (fd == DNSServiceRefSockFD(as->client)); 70 + ret = DNSServiceProcessResult(as->client); 71 + if (ret != kDNSServiceErr_NoError) { 72 + if (as->watch) { 73 + as->server->poll_api->watch_free(as->watch); 74 + as->watch = NULL; 75 + } 76 + DNSServiceRefDeallocate(as->client); 77 + as->client = NULL; 78 + avahi_s_entry_group_change_state(as->group, AVAHI_ENTRY_GROUP_FAILURE); 79 + } 80 +} 81 + 82 +static void avahi_service_free(AvahiServer*s, AvahiService *as) { 83 + AvahiService *t; 84 + 85 + assert(s); 86 + assert(as); 87 + 88 + /* Remove from linked list */ 89 + AVAHI_LLIST_REMOVE(AvahiService, services, s->services, as); 90 + 91 + /* Remove from associated group */ 92 + if (as->group) 93 + AVAHI_LLIST_REMOVE(AvahiService, services, as->group->services, as); 94 + 95 + if (as->name) 96 + avahi_free(as->name); 97 + 98 + if (as->type) 99 + avahi_free(as->type); 100 + 101 + if (as->domain) 102 + avahi_free(as->domain); 103 + 104 + if (as->host) 105 + avahi_free(as->host); 106 + 107 + if (as->watch) 108 + s->poll_api->watch_free(as->watch); 109 + 110 + if (as->client) 111 + DNSServiceRefDeallocate (as->client); 112 + 113 + if (as->txtrecord) 114 + avahi_free(as->txtrecord); 115 + 116 + avahi_free(as); 117 +} 118 + 119 +static void avahi_register_service(AvahiServer *s, AvahiService *as) { 120 + DNSServiceErrorType ret; 121 + 122 + ret = DNSServiceRegister(&as->client, 123 + as->interface == AVAHI_IF_UNSPEC ? 124 + kDNSServiceInterfaceIndexAny : 125 + as->interface, 126 + 0, 127 + as->name, 128 + as->type, 129 + as->domain, 130 + as->host, 131 + htons(as->port), 132 + as->txtlen, 133 + as->txtrecord, 134 + register_service_reply, 135 + as); 136 + if (ret == kDNSServiceErr_NoError) { 137 + if (!as->client) { 138 + avahi_s_entry_group_change_state(as->group, AVAHI_ENTRY_GROUP_FAILURE); 139 + } else { 140 + as->group->n_probing++; 141 + as->watch = s->poll_api->watch_new(s->poll_api, DNSServiceRefSockFD(as->client), AVAHI_WATCH_IN, register_service_socket_event, as); 142 + } 143 + } else { 144 + if (ret == kDNSServiceErr_NameConflict) { 145 + avahi_s_entry_group_change_state(as->group, AVAHI_ENTRY_GROUP_COLLISION); 146 + } 147 + else { 148 + avahi_s_entry_group_change_state(as->group, AVAHI_ENTRY_GROUP_FAILURE); 149 + } 150 + } 151 +} 152 + 153 +static void register_record_reply(DNSServiceRef client, DNSRecordRef recordref, const DNSServiceFlags flags, DNSServiceErrorType errorCode, void *context) { 154 + AvahiEntry *e = context; 155 + DNSServiceErrorType ret; 156 + 157 + switch (errorCode) { 158 + case kDNSServiceErr_NoError: 159 + break; 160 + case kDNSServiceErr_NameConflict: 161 + e->recordref = NULL; 162 + avahi_server_set_errno(e->server, AVAHI_ERR_COLLISION); 163 + break; 164 + default: 165 + e->recordref = NULL; 166 + avahi_server_set_errno(e->server, AVAHI_ERR_FAILURE); 167 + break; 168 + } 169 +} 170 +#endif 171 + 172 void avahi_entry_free(AvahiServer*s, AvahiEntry *e) { 173 AvahiEntry *t; 174 175 assert(s); 176 assert(e); 177 178 +#ifndef HAVE_BONJOUR 179 avahi_goodbye_entry(s, e, 1, 1); 180 +#endif 181 182 /* Remove from linked list */ 183 AVAHI_LLIST_REMOVE(AvahiEntry, entries, s->entries, e); 184 @@ -104,6 +264,15 @@ 185 186 while (g->entries) 187 avahi_entry_free(s, g->entries); 188 +#ifdef HAVE_BONJOUR 189 + while (g->services) 190 + avahi_service_free(s, g->services); 191 + 192 + if (g->record_connection) { 193 + DNSServiceRefDeallocate(g->record_connection); 194 + g->record_connection = NULL; 195 + } 196 +#endif 197 198 if (g->register_time_event) 199 avahi_time_event_free(g->register_time_event); 200 @@ -141,6 +310,21 @@ 201 s->need_entry_cleanup = 0; 202 } 203 204 +#ifdef HAVE_BONJOUR 205 + if (s->need_service_cleanup) { 206 + AvahiService *as, *next; 207 + 208 + for (as = s->services; as; as = next) { 209 + next = as->services_next; 210 + 211 + if (as->dead) 212 + avahi_service_free(s, as); 213 + } 214 + 215 + s->need_service_cleanup = 0; 216 + } 217 +#endif 218 + 219 if (s->need_browser_cleanup) 220 avahi_browser_cleanup(s); 221 } 222 @@ -226,7 +410,7 @@ 223 int is_first = 1; 224 225 /* Update and existing record */ 226 - 227 + 228 /* Find the first matching entry */ 229 for (e = avahi_hashmap_lookup(s->entries_by_key, r->key); e; e = e->by_key_next) { 230 if (!e->dead && e->group == g && e->interface == interface && e->protocol == protocol) 231 @@ -237,8 +421,54 @@ 232 233 /* Hmm, nothing found? */ 234 if (!e) { 235 +#ifdef HAVE_BONJOUR 236 + /* 237 + * Assume that we are updating a service's primary TXT record 238 + * so find the service 239 + */ 240 + DNSServiceErrorType ret; 241 + uint16_t rlen; 242 + uint8_t rdata[AVAHI_DNS_RDATA_MAX]; 243 + size_t l; 244 + AvahiService *as; 245 + int found_as = 0; 246 + 247 + for (as = g->services; as; as = as->services_next) { 248 + int a_ret = AVAHI_OK; 249 + char svc_name[AVAHI_DOMAIN_NAME_MAX]; 250 + 251 + if ((a_ret = avahi_service_name_join(svc_name, sizeof(svc_name), as->name, as->type, as->domain ? as->domain : s->domain_name)) < 0) { 252 + avahi_server_set_errno(s, a_ret); 253 + return NULL; 254 + } 255 + if (!strcmp(svc_name, r->key->name)) { 256 + found_as = 1; 257 + break; 258 + } 259 + } 260 + 261 + if (!found_as) { 262 + avahi_server_set_errno(s, AVAHI_ERR_NOT_FOUND); 263 + return NULL; 264 + } 265 + if ((l = avahi_rdata_serialize(r, rdata, sizeof(rdata))) == (size_t) -1) { 266 + avahi_server_set_errno(s, AVAHI_ERR_FAILURE); 267 + return NULL; 268 + } 269 + ret = DNSServiceUpdateRecord(as->client, 270 + NULL, 271 + 0, 272 + l, 273 + rdata, 274 + r->ttl); 275 + if (ret != kDNSServiceErr_NoError) { 276 + avahi_server_set_errno(s, AVAHI_ERR_FAILURE); 277 + } 278 + return NULL; 279 +#else 280 avahi_server_set_errno(s, AVAHI_ERR_NOT_FOUND); 281 return NULL; 282 +#endif 283 } 284 285 /* Update the entry */ 286 @@ -248,6 +478,36 @@ 287 288 /* Announce our changes when needed */ 289 if (!avahi_record_equal_no_ttl(old_record, r) && (!g || g->state != AVAHI_ENTRY_GROUP_UNCOMMITED)) { 290 +#ifdef HAVE_BONJOUR 291 + DNSServiceErrorType ret; 292 + uint16_t rlen; 293 + uint8_t rdata[AVAHI_DNS_RDATA_MAX]; 294 + size_t l; 295 + 296 + if (!g->record_connection) { 297 + if (DNSServiceCreateConnection(&g->record_connection) != kDNSServiceErr_NoError) { 298 + avahi_entry_free(s, e); 299 + avahi_server_set_errno(s, AVAHI_ERR_FAILURE); 300 + return NULL; 301 + } 302 + } 303 + if ((l = avahi_rdata_serialize(r, rdata, sizeof(rdata))) == (size_t) -1) { 304 + avahi_entry_free(s, e); 305 + avahi_server_set_errno(s, AVAHI_ERR_FAILURE); 306 + return NULL; 307 + } 308 + ret = DNSServiceUpdateRecord(g->record_connection, 309 + e->recordref, 310 + 0, 311 + l, 312 + rdata, 313 + r->ttl); 314 + if (ret != kDNSServiceErr_NoError) { 315 + avahi_entry_free(s, e); 316 + avahi_server_set_errno(s, AVAHI_ERR_FAILURE); 317 + return NULL; 318 + } 319 +#else 320 321 /* Remove the old entry from all caches, if needed */ 322 if (!(e->flags & AVAHI_PUBLISH_UNIQUE)) 323 @@ -255,6 +515,7 @@ 324 325 /* Reannounce our updated entry */ 326 avahi_reannounce_entry(s, e); 327 +#endif 328 } 329 330 /* If we were the first entry in the list, we need to update the key */ 331 @@ -265,6 +526,14 @@ 332 333 } else { 334 AvahiEntry *t; 335 +#ifdef HAVE_BONJOUR 336 + DNSServiceErrorType ret; 337 + DNSServiceFlags bflags; 338 + uint16_t rlen; 339 + uint8_t rdata[AVAHI_DNS_RDATA_MAX]; 340 + size_t l; 341 + char *record_name; 342 +#endif 343 344 /* Add a new record */ 345 346 @@ -299,7 +568,69 @@ 347 if (g) 348 AVAHI_LLIST_PREPEND(AvahiEntry, by_group, g->entries, e); 349 350 +#ifdef HAVE_BONJOUR 351 + e->recordref = NULL; 352 + if (!g->record_connection) { 353 + if (DNSServiceCreateConnection(&g->record_connection) != kDNSServiceErr_NoError) { 354 + avahi_entry_free(s, e); 355 + avahi_server_set_errno(s, AVAHI_ERR_FAILURE); 356 + return NULL; 357 + } 358 + } 359 + bflags = 0; 360 + if (flags & AVAHI_PUBLISH_ALLOW_MULTIPLE) 361 + bflags |= kDNSServiceFlagsShared; 362 + else 363 + bflags |= kDNSServiceFlagsUnique; 364 + 365 + switch (r->key->type) { 366 + case AVAHI_DNS_TYPE_A: 367 + case AVAHI_DNS_TYPE_AAAA: 368 + record_name = avahi_strdup(r->key->name); 369 + break; 370 + default: 371 + record_name = avahi_malloc(strlen(r->key->name) + strlen(s->host_name_fqdn) + 2); 372 + strcpy(record_name, r->key->name); 373 + strcat(record_name, "."); 374 + strcat(record_name, s->host_name_fqdn); 375 + break; 376 + } 377 + 378 + if ((l = avahi_rdata_serialize(r, rdata, sizeof(rdata))) == (size_t) -1) { 379 + avahi_entry_free(s, e); 380 + avahi_server_set_errno(s, AVAHI_ERR_FAILURE); 381 + return NULL; 382 + } 383 + 384 + ret = DNSServiceRegisterRecord(g->record_connection, 385 + &e->recordref, 386 + bflags, 387 + interface == AVAHI_IF_UNSPEC ? 388 + kDNSServiceInterfaceIndexAny : 389 + interface, 390 + record_name, 391 + r->key->type, 392 + r->key->clazz, 393 + l, 394 + rdata, 395 + r->ttl, 396 + register_record_reply, 397 + e); 398 + if (ret == kDNSServiceErr_NoError) { 399 + ret = DNSServiceProcessResult(g->record_connection); 400 + if (ret != kDNSServiceErr_NoError || e->recordref == NULL) { 401 + avahi_entry_free(s, e); 402 + return NULL; 403 + } 404 + } else { 405 + avahi_entry_free(s, e); 406 + avahi_server_set_errno(s, AVAHI_ERR_FAILURE); 407 + return NULL; 408 + } 409 + avahi_free(record_name); 410 +#else 411 avahi_announce_entry(s, e); 412 +#endif 413 } 414 415 return e; 416 @@ -575,7 +906,10 @@ 417 AvahiRecord *r = NULL; 418 int ret = AVAHI_OK; 419 AvahiEntry *srv_entry = NULL, *txt_entry = NULL, *ptr_entry = NULL, *enum_entry = NULL; 420 - 421 +#ifdef HAVE_BONJOUR 422 + AvahiService *as; 423 +#endif 424 + 425 assert(s); 426 assert(type); 427 assert(name); 428 @@ -595,6 +929,36 @@ 429 if (!domain) 430 domain = s->domain_name; 431 432 +#ifdef HAVE_BONJOUR 433 + as = avahi_new (AvahiService, 1); 434 + as->server = s; 435 + as->group = g; 436 + as->dead = 0; 437 + as->flags = flags; 438 + as->interface = interface; 439 + as->protocol = protocol; 440 + as->name = avahi_strdup(name); 441 + as->type = avahi_strdup(type); 442 + as->domain = avahi_strdup(domain); 443 + as->host = avahi_strdup(host); 444 + as->port = port; 445 + as->watch = NULL; 446 + as->client = NULL; 447 + as->txtlen = avahi_string_list_serialize(strlst, NULL, 0); 448 + if (as->txtlen > 0) { 449 + as->txtrecord = avahi_new(uint8_t, as->txtlen); 450 + if (as->txtrecord == NULL) { 451 + as->txtlen = 0; 452 + ret = avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY); 453 + goto fail; 454 + } 455 + avahi_string_list_serialize(strlst, as->txtrecord, as->txtlen); 456 + } else 457 + as->txtrecord = NULL; 458 + 459 + AVAHI_LLIST_PREPEND(AvahiService, services, s->services, as); 460 + AVAHI_LLIST_PREPEND(AvahiService, services, g->services, as); 461 +#else 462 if (!host) 463 host = s->host_name_fqdn; 464 465 @@ -659,6 +1023,7 @@ 466 ret = avahi_server_errno(s); 467 goto fail; 468 } 469 +#endif 470 471 fail: 472 if (ret != AVAHI_OK && !(flags & AVAHI_PUBLISH_UPDATE)) { 473 @@ -938,6 +1303,18 @@ 474 return e; 475 } 476 477 +#ifdef HAVE_BONJOUR 478 +static void server_cleanup_time_event_callback(AVAHI_GCC_UNUSED AvahiTimeEvent *e, void* userdata) { 479 + AvahiServer *s = userdata; 480 + assert(s); 481 + 482 + avahi_time_event_free(s->cleanup_time_event); 483 + s->cleanup_time_event = NULL; 484 + 485 + avahi_cleanup_dead_entries(s); 486 +} 487 +#endif 488 + 489 int avahi_server_add_dns_server_address( 490 AvahiServer *s, 491 AvahiSEntryGroup *g, 492 @@ -1005,7 +1382,11 @@ 493 if (g->state == state) 494 return; 495 496 +#ifdef HAVE_BONJOUR 497 + assert(state <= AVAHI_ENTRY_GROUP_FAILURE); 498 +#else 499 assert(state <= AVAHI_ENTRY_GROUP_COLLISION); 500 +#endif 501 502 if (g->state == AVAHI_ENTRY_GROUP_ESTABLISHED) { 503 504 @@ -1050,6 +1431,10 @@ 505 g->register_time.tv_sec = 0; 506 g->register_time.tv_usec = 0; 507 AVAHI_LLIST_HEAD_INIT(AvahiEntry, g->entries); 508 +#ifdef HAVE_BONJOUR 509 + AVAHI_LLIST_HEAD_INIT(AvahiService, g->services); 510 + g->record_connection = NULL; 511 +#endif 512 513 AVAHI_LLIST_PREPEND(AvahiSEntryGroup, groups, s->groups, g); 514 return g; 515 @@ -1057,16 +1442,26 @@ 516 517 void avahi_s_entry_group_free(AvahiSEntryGroup *g) { 518 AvahiEntry *e; 519 +#ifdef HAVE_BONJOUR 520 + AvahiService *s; 521 +#endif 522 523 assert(g); 524 assert(g->server); 525 526 for (e = g->entries; e; e = e->by_group_next) { 527 if (!e->dead) { 528 +#ifndef HAVE_BONJOUR 529 avahi_goodbye_entry(g->server, e, 1, 1); 530 +#endif 531 e->dead = 1; 532 } 533 } 534 +#ifdef HAVE_BONJOUR 535 + for (s = g->services; s; s = s->services_next) { 536 + s->dead = 1; 537 + } 538 +#endif 539 540 if (g->register_time_event) { 541 avahi_time_event_free(g->register_time_event); 542 @@ -1077,9 +1472,17 @@ 543 544 g->server->need_group_cleanup = 1; 545 g->server->need_entry_cleanup = 1; 546 +#ifdef HAVE_BONJOUR 547 + g->server->need_service_cleanup = 1; 548 + if (!g->server->cleanup_time_event) 549 + g->server->cleanup_time_event = avahi_time_event_new(g->server->time_event_queue, NULL, server_cleanup_time_event_callback, g->server); 550 +#endif 551 } 552 553 static void entry_group_commit_real(AvahiSEntryGroup *g) { 554 +#ifdef HAVE_BONJOUR 555 + AvahiService *s; 556 +#endif 557 assert(g); 558 559 gettimeofday(&g->register_time, NULL); 560 @@ -1089,8 +1492,15 @@ 561 if (g->dead) 562 return; 563 564 +#ifdef HAVE_BONJOUR 565 + assert(g->server); 566 + for (s = g->services; s; s = s->services_next) 567 + if (!s->dead) 568 + avahi_register_service(g->server, s); 569 +#else 570 avahi_announce_group(g->server, g); 571 avahi_s_entry_group_check_probed(g, 0); 572 +#endif 573 } 574 575 static void entry_group_register_time_event_callback(AVAHI_GCC_UNUSED AvahiTimeEvent *e, void* userdata) { 576 @@ -1143,16 +1553,29 @@ 577 578 void avahi_s_entry_group_reset(AvahiSEntryGroup *g) { 579 AvahiEntry *e; 580 +#ifdef HAVE_BONJOUR 581 + AvahiService *s; 582 +#endif 583 assert(g); 584 585 for (e = g->entries; e; e = e->by_group_next) { 586 if (!e->dead) { 587 +#ifndef HAVE_BONJOUR 588 avahi_goodbye_entry(g->server, e, 1, 1); 589 +#endif 590 e->dead = 1; 591 } 592 } 593 g->server->need_entry_cleanup = 1; 594 595 +#ifdef HAVE_BONJOUR 596 + for (s = g->services; s; s = s->services_next) { 597 + s->dead = 1; 598 + } 599 + g->server->need_service_cleanup = 1; 600 + if (!g->server->cleanup_time_event) 601 + g->server->cleanup_time_event = avahi_time_event_new(g->server->time_event_queue, NULL, server_cleanup_time_event_callback, g->server); 602 +#endif 603 g->n_probing = 0; 604 605 avahi_s_entry_group_change_state(g, AVAHI_ENTRY_GROUP_UNCOMMITED); 606 @@ -1195,12 +1618,23 @@ 607 608 int avahi_s_entry_group_is_empty(AvahiSEntryGroup *g) { 609 AvahiEntry *e; 610 +#ifdef HAVE_BONJOUR 611 + AvahiService *s; 612 +#endif 613 + 614 assert(g); 615 616 +#ifdef HAVE_BONJOUR 617 + for (s = g->services; s; s = s->services_next) 618 + if (!s->dead) 619 + return 0; 620 +#else 621 /* Look for an entry that is not dead */ 622 for (e = g->entries; e; e = e->by_group_next) 623 if (!e->dead) 624 return 0; 625 +#endif 626 627 return 1; 628 } 629 + 630