1 /* dnssd-client.c 2 * 3 * Copyright (c) 2023-2024 Apple Inc. All rights reserved. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * https://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 * This file contains code to queue and send updates for Thread services. 18 */ 19 20 #ifndef LINUX 21 #include <netinet/in.h> 22 #include <net/if.h> 23 #include <netinet6/in6_var.h> 24 #include <netinet6/nd6.h> 25 #include <net/if_media.h> 26 #include <sys/stat.h> 27 #else 28 #define _GNU_SOURCE 29 #include <netinet/in.h> 30 #include <fcntl.h> 31 #include <bsd/stdlib.h> 32 #include <net/if.h> 33 #endif 34 #include <sys/socket.h> 35 #include <sys/ioctl.h> 36 #include <net/route.h> 37 #include <netinet/icmp6.h> 38 #include <stdio.h> 39 #include <unistd.h> 40 #include <errno.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <ctype.h> 44 #include <arpa/inet.h> 45 #include <stdlib.h> 46 #include <stddef.h> 47 #include <dns_sd.h> 48 #include <inttypes.h> 49 #include <signal.h> 50 51 #ifdef IOLOOP_MACOS 52 #include <xpc/xpc.h> 53 54 #include <TargetConditionals.h> 55 #include <SystemConfiguration/SystemConfiguration.h> 56 #include <SystemConfiguration/SCPrivate.h> 57 #include <SystemConfiguration/SCNetworkConfigurationPrivate.h> 58 #include <SystemConfiguration/SCNetworkSignature.h> 59 #include <network_information.h> 60 61 #include <CoreUtils/CoreUtils.h> 62 #include <mrc/private.h> 63 #endif // IOLOOP_MACOS 64 65 #include "srp.h" 66 #include "dns-msg.h" 67 #include "ioloop.h" 68 #include "srp-crypto.h" 69 70 #include "cti-services.h" 71 #include "srp-gw.h" 72 #include "srp-proxy.h" 73 #include "srp-mdns-proxy.h" 74 #include "adv-ctl-server.h" 75 #include "dnssd-proxy.h" 76 #include "srp-proxy.h" 77 #include "route.h" 78 79 #define STATE_MACHINE_IMPLEMENTATION 1 80 typedef enum { 81 dnssd_client_state_invalid, 82 dnssd_client_state_startup, 83 dnssd_client_state_not_client, 84 dnssd_client_state_probing, 85 dnssd_client_state_client, 86 } state_machine_state_t; 87 #define state_machine_state_invalid dnssd_client_state_invalid 88 89 #include "state-machine.h" 90 #include "thread-service.h" 91 #include "service-tracker.h" 92 #include "service-publisher.h" 93 94 #include "dnssd-client.h" 95 #include "thread-tracker.h" 96 #include "probe-srp.h" 97 98 typedef enum { 99 dnssd_client_dns_service_type_invalid = 0, 100 dnssd_client_dns_service_type_do53 = 1, 101 dnssd_client_dns_service_type_push = 2, 102 } dnssd_client_dns_service_type_t; 103 104 struct dnssd_client { 105 int ref_count; 106 state_machine_header_t state_header; 107 char *id; 108 srp_server_t *server_state; 109 wakeup_t *wakeup_timer; 110 cti_connection_t active_data_set_connection; 111 struct in6_addr mesh_local_prefix; 112 bool have_mesh_local_prefix; 113 bool first_time; 114 bool canceled; 115 dnssd_txn_t *shared_txn; 116 thread_service_t *published_service; 117 DNSServiceRef shared_connection; 118 mrc_dns_service_registration_t dns_service_registration; // DNS service registration handler. 119 dnssd_client_dns_service_type_t dns_service_registration_type; // The type of the registered DNS service. 120 int interface_index; 121 uint16_t dns_service_registration_port; // The port of the registered DNS service used. 122 }; 123 124 static uint64_t dnssd_client_serial_number; 125 126 static void 127 dnssd_client_finalize(dnssd_client_t *client) 128 { 129 thread_service_release(client->published_service); 130 ioloop_wakeup_release(client->wakeup_timer); 131 free(client->state_header.name); 132 free(client->id); 133 free(client); 134 } 135 136 RELEASE_RETAIN_FUNCS(dnssd_client); 137 138 static void 139 dnssd_client_context_release(void *context) 140 { 141 dnssd_client_t *client = context; 142 RELEASE_HERE(client, dnssd_client); 143 } 144 145 static void 146 dnssd_client_wait_expired(void *context) 147 { 148 dnssd_client_t *client = context; 149 state_machine_event_t *event = state_machine_event_create(state_machine_event_type_timeout, NULL); 150 if (event == NULL) { 151 ERROR("unable to allocate event to deliver"); 152 return; 153 } 154 state_machine_event_deliver(&client->state_header, event); 155 RELEASE_HERE(event, state_machine_event); 156 } 157 158 static void 159 dnssd_client_service_tracker_callback(void *context) 160 { 161 dnssd_client_t *client = context; 162 163 state_machine_event_t *event = state_machine_event_create(state_machine_event_type_service_list_changed, NULL); 164 if (event == NULL) { 165 ERROR("unable to allocate event to deliver"); 166 return; 167 } 168 state_machine_event_deliver(&client->state_header, event); 169 RELEASE_HERE(event, state_machine_event); 170 } 171 172 static void 173 dnssd_client_probe_callback(thread_service_t *UNUSED service, void *context, bool UNUSED succeeded) 174 { 175 dnssd_client_t *client = context; 176 state_machine_event_t *event = state_machine_event_create(state_machine_event_type_probe_completed, NULL); 177 if (event == NULL) { 178 ERROR("unable to allocate event to deliver"); 179 return; 180 } 181 state_machine_event_deliver(&client->state_header, event); 182 RELEASE_HERE(event, state_machine_event); 183 } 184 185 static void 186 dnssd_client_get_mesh_local_prefix_callback(void *context, const char *prefix_string, int status) 187 { 188 dnssd_client_t *client = context; 189 INFO(PUB_S_SRP " %d", prefix_string != NULL ? prefix_string : "<null>", status); 190 if (status != kCTIStatus_NoError || prefix_string == NULL) { 191 goto fail; 192 } 193 194 char prefix_buf[INET6_ADDRSTRLEN]; 195 196 const char *prefix_addr_string; 197 char *slash = strchr(prefix_string, '/'); 198 if (slash != NULL) { 199 size_t len = slash - prefix_string; 200 if (len == 0) { 201 ERROR("bogus prefix: " PRI_S_SRP, prefix_string); 202 goto fail; 203 } 204 if (len - 1 > sizeof(prefix_buf)) { 205 ERROR("prefix too long: " PRI_S_SRP, prefix_string); 206 goto fail; 207 } 208 memcpy(prefix_buf, prefix_string, len); 209 prefix_buf[len] = 0; 210 prefix_addr_string = prefix_buf; 211 } else { 212 prefix_addr_string = prefix_string; 213 } 214 if (!inet_pton(AF_INET6, prefix_addr_string, &client->mesh_local_prefix)) { 215 ERROR("prefix syntax incorrect: " PRI_S_SRP, prefix_addr_string); 216 goto fail; 217 } 218 client->have_mesh_local_prefix = true; 219 state_machine_event_t *event = state_machine_event_create(state_machine_event_type_got_mesh_local_prefix, NULL); 220 if (event == NULL) { 221 ERROR("unable to allocate event to deliver"); 222 return; 223 } 224 state_machine_event_deliver(&client->state_header, event); 225 RELEASE_HERE(event, state_machine_event); 226 fail: 227 RELEASE_HERE(client, dnssd_client); // was retained for callback, can only get one callback 228 return; 229 } 230 231 static state_machine_state_t 232 dnssd_client_remove_published_service(dnssd_client_t *client) 233 { 234 if (client->dns_service_registration != NULL) { 235 mrc_dns_service_registration_forget(&client->dns_service_registration); 236 } 237 return dnssd_client_state_not_client; 238 } 239 240 static state_machine_state_t 241 dnssd_client_service_unpublish(dnssd_client_t *client) 242 { 243 if (client->dns_service_registration != NULL) { 244 thread_service_note(client->id, client->published_service, "unpublishing service"); 245 } 246 dnssd_client_remove_published_service(client); 247 248 return dnssd_client_state_not_client; 249 } 250 251 static void 252 dnssd_client_dns_service_event_handler(const mrc_dns_service_registration_event_t mrc_event, const OSStatus event_err, 253 dnssd_client_t *client) 254 { 255 state_machine_event_t *event = NULL; 256 bool want_event = false; 257 switch(mrc_event) 258 { 259 case mrc_dns_service_registration_event_started: 260 INFO("DNS service registration started"); 261 break; 262 case mrc_dns_service_registration_event_interruption: 263 INFO("DNS service registration interrupted" ); 264 break; 265 266 case mrc_dns_service_registration_event_invalidation: 267 want_event = true; 268 if (event_err) { 269 ERROR("DNS service registration invalidated with error: %d", (int)event_err); 270 } else { 271 INFO("DNS service registration gracefully invalidated"); 272 } 273 event = state_machine_event_create(state_machine_event_type_dns_registration_invalidated, NULL); 274 break; 275 case mrc_dns_service_registration_event_connection_error: 276 want_event = true; 277 ERROR("Registered DNS Push connection failed on server with error: %d", (int)event_err); 278 event = state_machine_event_create(state_machine_event_type_dns_registration_bad_service, NULL); 279 break; 280 } 281 282 if (want_event) { 283 if (event == NULL) { 284 ERROR("unable to allocate event to deliver"); 285 } else { 286 state_machine_event_deliver(&client->state_header, event); 287 RELEASE_HERE(event, state_machine_event); 288 } 289 // Either event should be the last event we get. 290 RELEASE_HERE(client, dnssd_client); 291 } 292 } 293 294 295 static state_machine_state_t 296 dnssd_client_service_publish(dnssd_client_t *client) 297 { 298 dnssd_client_service_unpublish(client); 299 state_machine_state_t ret = dnssd_client_state_not_client; 300 301 OSStatus err; 302 mdns_dns_service_definition_t do53_definition = NULL; 303 mdns_dns_push_service_definition_t push_definition = NULL; 304 mdns_domain_name_t domain_name = NULL; 305 mdns_address_t server_address = NULL; 306 307 domain_name = mdns_domain_name_create("default.service.arpa.", mdns_domain_name_create_opts_none, &err); 308 require_noerr_action(err, out, ERROR("failed to create default.service.arpa.: %{darwin.errno}d", (int)err)); 309 310 const uint8_t *aaaa_data = NULL; 311 uint16_t port = 0; 312 // @TODO: Adds SRV service probing to determine the DoT port instead the default dns_service_registration_port. 313 if (client->published_service->service_type == unicast_service) { 314 aaaa_data = &client->published_service->u.unicast.address.s6_addr[0]; 315 } else if (client->published_service->service_type == anycast_service) { 316 aaaa_data = &client->published_service->u.anycast.address.s6_addr[0]; 317 } 318 port = client->dns_service_registration_port; 319 require_action(aaaa_data != NULL, out, ERROR("failed to get service address")); 320 321 SEGMENTED_IPv6_ADDR_GEN_SRP(aaaa_data, ipv6_addr_buf); 322 server_address = mdns_address_create_ipv6(aaaa_data, port, 0); 323 if (server_address == NULL) { 324 ERROR("failed to create address object -- address: " PRI_SEGMENTED_IPv6_ADDR_SRP, 325 SEGMENTED_IPv6_ADDR_PARAM_SRP(aaaa_data, ipv6_addr_buf)); 326 goto out; 327 } 328 if (client->dns_service_registration_type == dnssd_client_dns_service_type_push) { 329 push_definition = mdns_dns_push_service_definition_create(); 330 require_action(push_definition, out, ERROR("unable to allocate mdns_dns_push_service_definition object")); 331 332 err = mdns_dns_push_service_definition_add_domain(push_definition, domain_name); 333 require_noerr(err, out); 334 335 mdns_dns_push_service_definition_append_server_address(push_definition, server_address); 336 337 client->dns_service_registration = mrc_dns_service_registration_create_push(push_definition); 338 if (client->dns_service_registration) { 339 mrc_dns_service_registration_set_reports_connection_errors(client->dns_service_registration, 340 true); 341 } 342 } else if (client->dns_service_registration_type == dnssd_client_dns_service_type_do53) { 343 do53_definition = mdns_dns_service_definition_create(); 344 require_action(do53_definition, out, ERROR("unable to allocate mdns_dns_service_definition object")); 345 346 err = mdns_dns_service_definition_add_domain(do53_definition, domain_name); 347 require_noerr(err, out); 348 349 err = mdns_dns_service_definition_append_server_address(do53_definition, server_address); 350 require_noerr(err, out); 351 352 client->dns_service_registration = mrc_dns_service_registration_create(do53_definition); 353 } else { 354 ERROR("Unknown DNS service registration type: %d", client->dns_service_registration_type); 355 goto out; 356 } 357 require_action(client->dns_service_registration != NULL, out, ERROR("failed to create DNS service registration")); 358 mrc_dns_service_registration_set_queue(client->dns_service_registration, dispatch_get_main_queue()); 359 360 RETAIN_HERE(client, dnssd_client); // For the handler 361 mrc_dns_service_registration_set_event_handler(client->dns_service_registration, 362 ^(const mrc_dns_service_registration_event_t event, const OSStatus event_err) 363 { 364 dnssd_client_dns_service_event_handler(event, event_err, client); 365 }); 366 INFO("Publishing dnssd client service -- domain: " PRI_DNS_NAME_SRP ", address: " PRI_SEGMENTED_IPv6_ADDR_SRP, 367 mdns_domain_name_get_presentation(domain_name), SEGMENTED_IPv6_ADDR_PARAM_SRP(aaaa_data, ipv6_addr_buf)); 368 mrc_dns_service_registration_activate(client->dns_service_registration); 369 370 ret = dnssd_client_state_invalid; 371 out: 372 mdns_forget(&do53_definition); 373 mdns_forget(&push_definition); 374 mdns_forget(&domain_name); 375 mdns_forget(&server_address); 376 return ret; 377 } 378 379 static state_machine_state_t dnssd_client_action_startup(state_machine_header_t *state_header, 380 state_machine_event_t *event); 381 static state_machine_state_t dnssd_client_action_not_client(state_machine_header_t *state_header, 382 state_machine_event_t *event); 383 static state_machine_state_t dnssd_client_action_probing(state_machine_header_t *state_header, 384 state_machine_event_t *event); 385 static state_machine_state_t dnssd_client_action_client(state_machine_header_t *state_header, 386 state_machine_event_t *event); 387 388 // States: 389 // -- not_client: Not a client because server or because no service (in which case hopefully we are becoming server) 390 // -- client: Found a working service, configured as client 391 392 #define SERVICE_PUB_NAME_DECL(name) dnssd_client_state_##name, #name 393 static state_machine_decl_t dnssd_client_states[] = { 394 { SERVICE_PUB_NAME_DECL(invalid), NULL }, 395 { SERVICE_PUB_NAME_DECL(startup), dnssd_client_action_startup }, 396 { SERVICE_PUB_NAME_DECL(not_client), dnssd_client_action_not_client }, 397 { SERVICE_PUB_NAME_DECL(probing), dnssd_client_action_probing }, 398 { SERVICE_PUB_NAME_DECL(client), dnssd_client_action_client }, 399 }; 400 #define DNSSD_CLIENT_NUM_STATES ((sizeof(dnssd_client_states)) / (sizeof(state_machine_decl_t))) 401 402 #define STATE_MACHINE_HEADER_TO_CLIENT(state_header) \ 403 if (state_header->state_machine_type != state_machine_type_dnssd_client) { \ 404 ERROR("state header type isn't omr_client: %d", state_header->state_machine_type); \ 405 return dnssd_client_state_invalid; \ 406 } \ 407 dnssd_client_t *client = state_header->state_object 408 409 static bool 410 dnssd_client_should_be_client(dnssd_client_t *client) 411 { 412 bool might_publish = false; 413 bool associated = true; 414 bool should_be_client = false; 415 srp_server_t *server_state = client->server_state; 416 417 if (!service_publisher_could_publish(server_state->service_publisher)) { 418 should_be_client = true; 419 might_publish = true; 420 } 421 422 if (!thread_tracker_associated_get(server_state->thread_tracker, false)) { 423 associated = false; 424 should_be_client = false; 425 } 426 427 INFO(PUB_S_SRP PUB_S_SRP PUB_S_SRP, 428 should_be_client ? "could be client" : "can't be client", 429 might_publish ? " might publish" : " won't publish", 430 associated ? "" : " not associated "); 431 return should_be_client; 432 } 433 434 // We start in this state and remain here until we get a mesh-local prefix. 435 static state_machine_state_t 436 dnssd_client_action_startup(state_machine_header_t *state_header, state_machine_event_t *event) 437 { 438 STATE_MACHINE_HEADER_TO_CLIENT(state_header); 439 BR_STATE_ANNOUNCE(client, event); 440 441 if (client->have_mesh_local_prefix) { 442 return dnssd_client_state_not_client; 443 } 444 return dnssd_client_state_invalid; 445 } 446 447 // We get into this state when there is no SRP service published on the Thread network other than our own. 448 // If we stop publishing (because a BR-based service showed up), then we go to the probe state. 449 static state_machine_state_t 450 dnssd_client_action_not_client(state_machine_header_t *state_header, state_machine_event_t *event) 451 { 452 STATE_MACHINE_HEADER_TO_CLIENT(state_header); 453 BR_STATE_ANNOUNCE(client, event); 454 455 if (event == NULL) { 456 if (client->published_service != NULL) { 457 dnssd_client_service_unpublish(client); 458 } 459 return dnssd_client_state_invalid; 460 } 461 462 // We do the same thing here for any event we get, because we're just waiting for conditions to be right. 463 if (dnssd_client_should_be_client(client)) { 464 return dnssd_client_state_probing; 465 } 466 return dnssd_client_state_invalid; 467 } 468 469 // We get into this state when we've determined we should be a client 470 static state_machine_state_t 471 dnssd_client_action_probing(state_machine_header_t *state_header, state_machine_event_t *event) 472 { 473 STATE_MACHINE_HEADER_TO_CLIENT(state_header); 474 BR_STATE_ANNOUNCE(client, event); 475 476 thread_service_t *service; 477 srp_server_t *server_state = client->server_state; 478 479 // On arrival in this state, we start a timer. If we get to the publishing state, we cancel the timer. If the 480 // timer goes off when we're still probing, we tell the service publisher to publish any relevant cached 481 // services. The point of this is that it's fairly common at least in testing that we want to be able to 482 // control an accessory after joining the Thread network /because/ the BR went down, and in this case the BR's 483 // published service may take 120 seconds to time out from the thread network data. Publishing the cached 484 // services can potentially help with this. 485 if (event == NULL) { 486 ioloop_add_wake_event(client->wakeup_timer, client, dnssd_client_wait_expired, 487 dnssd_client_context_release, 5 * MSEC_PER_SEC); // Wait five seconds for probe to succeed. 488 RETAIN_HERE(client, dnssd_client); // for the wake event 489 } 490 491 // If we have been waiting for a second since we started probing and haven't succeeded, tell the service publisher 492 // to publish services. 493 else if (event->type == state_machine_event_type_timeout) { 494 if (server_state->service_publisher != NULL) { 495 INFO("server probe startup timeout expired--publishing cached data."); 496 service_publisher_re_advertise_matching(server_state->service_publisher); 497 } 498 return dnssd_client_state_invalid; 499 } 500 501 // If we no longer need to be a client, stop trying. 502 else { 503 if (!dnssd_client_should_be_client(client)) { 504 ioloop_cancel_wake_event(client->wakeup_timer); 505 return dnssd_client_state_not_client; 506 } 507 } 508 509 // See if we now have a service that's been successfully probed; if so, publish it. 510 service = service_tracker_verified_service_get(client->server_state->service_tracker); 511 if (service != NULL) { 512 if (client->published_service != NULL) { 513 thread_service_release(client->published_service); 514 } 515 client->published_service = service; 516 thread_service_retain(client->published_service); 517 518 // Tell the service publisher that we successfully probed a service. 519 INFO("server probe succeeded--unpublishing cached data."); 520 service_publisher_unadvertise_all(server_state->service_publisher); 521 522 // We no longer want a wakeup. Note that this is the only way out of the probing state, so it's not 523 // possible to exit the state without canceling the timer here. 524 ioloop_cancel_wake_event(client->wakeup_timer); 525 526 // Publish DNS Push service pointing to probed service. 527 return dnssd_client_state_client; 528 } 529 530 // Check to see if we can start a new probe 531 service = service_tracker_unverified_service_get(client->server_state->service_tracker, unicast_service); 532 if (service != NULL) { 533 if (service->checking) { 534 service_tracker_thread_service_note(client->server_state->service_tracker, service, 535 " is still being probed"); 536 return dnssd_client_state_invalid; 537 } 538 if (service->service_type == anycast_service) { 539 memcpy(&service->u.anycast.address, &client->mesh_local_prefix, 8); 540 memcpy(&service->u.anycast.address.s6_addr[8], thread_rloc_preamble, 6); 541 service->u.anycast.address.s6_addr[14] = service->rloc16 >> 8; 542 service->u.anycast.address.s6_addr[15] = service->rloc16 & 255; 543 } 544 RETAIN_HERE(client, dnssd_client); // For the probe 545 probe_srp_service(service, client, dnssd_client_probe_callback, dnssd_client_context_release); 546 return dnssd_client_state_invalid; 547 } 548 549 // This should only ever happen if we get the service list update before the service publisher gets it. 550 INFO("no service to publish"); 551 return dnssd_client_state_invalid; 552 } 553 554 555 // We get into this state when we've published a service. 556 static state_machine_state_t 557 dnssd_client_action_client(state_machine_header_t *state_header, state_machine_event_t *event) 558 { 559 STATE_MACHINE_HEADER_TO_CLIENT(state_header); 560 BR_STATE_ANNOUNCE(client, event); 561 562 if (event == NULL) { 563 // Publish the service. 564 dnssd_client_service_publish(client); 565 return dnssd_client_state_invalid; 566 } 567 568 if (event->type == state_machine_event_type_dns_registration_bad_service) { 569 if (client->published_service == NULL) { 570 INFO("bad service event received with no published service."); 571 } else { 572 client->published_service->ignore = true; // Don't consider this service when deciding what to advertise 573 client->published_service->responding = false; 574 thread_service_release(client->published_service); 575 client->published_service = NULL; 576 return dnssd_client_state_probing; // Go back to probing. 577 } 578 } 579 580 // This can happen if the daemon disconnects. 581 if (client->published_service == NULL) { 582 return dnssd_client_state_not_client; 583 } 584 585 // If we should no longer be client, unpublish the service and wait 586 if (!dnssd_client_should_be_client(client)) { 587 return dnssd_client_state_not_client; 588 } 589 590 if (service_tracker_verified_service_still_exists(client->server_state->service_tracker, 591 client->published_service)) { 592 return dnssd_client_state_invalid; 593 } 594 595 // If we get here, the service we have been publishing is no longer present. 596 return dnssd_client_state_not_client; 597 } 598 599 void 600 dnssd_client_cancel(dnssd_client_t *client) 601 { 602 if (client->server_state->service_tracker != NULL) { 603 service_tracker_cancel_probes(client->server_state->service_tracker); 604 service_tracker_callback_cancel(client->server_state->service_tracker, client); 605 } 606 if (client->server_state->thread_tracker != NULL) { 607 thread_tracker_callback_cancel(client->server_state->thread_tracker, client); 608 } 609 ioloop_cancel_wake_event(client->wakeup_timer); 610 if (client->active_data_set_connection != NULL) { 611 cti_events_discontinue(client->active_data_set_connection); 612 RELEASE_HERE(client, dnssd_client); // callback held reference 613 client->active_data_set_connection = NULL; 614 } 615 dnssd_client_remove_published_service(client); 616 state_machine_cancel(&client->state_header); 617 } 618 619 dnssd_client_t * 620 dnssd_client_create(srp_server_t *server_state) 621 { 622 dnssd_client_t *ret = NULL, *client = calloc(1, sizeof(*client)); 623 if (client == NULL) { 624 return client; 625 } 626 RETAIN_HERE(client, dnssd_client); 627 client->wakeup_timer = ioloop_wakeup_create(); 628 if (client->wakeup_timer == NULL) { 629 ERROR("wakeup timer alloc failed"); 630 goto out; 631 } 632 633 char client_id_buf[100]; 634 snprintf(client_id_buf, sizeof(client_id_buf), "[DC%lld]", ++dnssd_client_serial_number); 635 client->id = strdup(client_id_buf); 636 if (client->id == NULL) { 637 ERROR("no memory for client ID"); 638 goto out; 639 } 640 client->interface_index = -1; 641 client->dns_service_registration_type = dnssd_client_dns_service_type_push; 642 client->dns_service_registration_port = DNS_OVER_TLS_DEFAULT_PORT; 643 644 if (!state_machine_header_setup(&client->state_header, 645 client, client->id, 646 state_machine_type_dnssd_client, 647 dnssd_client_states, 648 DNSSD_CLIENT_NUM_STATES)) { 649 ERROR("header setup failed"); 650 goto out; 651 } 652 653 client->server_state = server_state; 654 if (!service_tracker_callback_add(server_state->service_tracker, dnssd_client_service_tracker_callback, 655 dnssd_client_context_release, client)) 656 { 657 goto out; 658 } 659 RETAIN_HERE(client, dnssd_client); // for service tracker 660 661 ret = client; 662 client = NULL; 663 out: 664 if (client != NULL) { 665 RELEASE_HERE(client, dnssd_client); 666 } 667 return ret; 668 } 669 670 static void 671 dnssd_client_get_tunnel_name_callback(void *context, const char *name, cti_status_t status) 672 { 673 dnssd_client_t *client = context; 674 if (status != kCTIStatus_NoError) { 675 INFO("didn't get tunnel name, error code %d", status); 676 goto fail; 677 } 678 client->interface_index = if_nametoindex(name); 679 fail: 680 RELEASE_HERE(client, dnssd_client); // was retained for callback, can only get one callback 681 } 682 683 static void 684 dnssd_client_active_data_set_changed_callback(void *context, cti_status_t status) 685 { 686 dnssd_client_t *client = context; 687 688 if (status != kCTIStatus_NoError) { 689 ERROR("error %d", status); 690 RELEASE_HERE(client, dnssd_client); // no more callbacks 691 cti_events_discontinue(client->active_data_set_connection); 692 client->active_data_set_connection = NULL; 693 return; 694 } 695 696 status = cti_get_mesh_local_prefix(client->server_state, client, dnssd_client_get_mesh_local_prefix_callback, NULL); 697 if (status != kCTIStatus_NoError) { 698 ERROR("cti_get_mesh_local_prefix failed with status %d", status); 699 } else { 700 RETAIN_HERE(client, dnssd_client); // for mesh-local callback 701 } 702 status = cti_get_tunnel_name(client->server_state, client, dnssd_client_get_tunnel_name_callback, NULL); 703 if (status != kCTIStatus_NoError) { 704 ERROR("cti_get_tunnel_name failed with status %d", status); 705 } else { 706 RETAIN_HERE(client, dnssd_client); // for tunnel name callback 707 } 708 } 709 710 void 711 dnssd_client_start(dnssd_client_t *client) 712 { 713 cti_track_active_data_set(client->server_state, &client->active_data_set_connection, 714 client, dnssd_client_active_data_set_changed_callback, NULL); 715 RETAIN_HERE(client, dnssd_client); // for callback 716 dnssd_client_active_data_set_changed_callback(client, kCTIStatus_NoError); // Get the initial state. 717 state_machine_next_state(&client->state_header, dnssd_client_state_startup); 718 } 719 720 // Local Variables: 721 // mode: C 722 // tab-width: 4 723 // c-file-style: "bsd" 724 // c-basic-offset: 4 725 // fill-column: 120 726 // indent-tabs-mode: nil 727 // End: 728