1 /* service-publisher.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 #endif // IOLOOP_MACOS 63 64 #include "srp.h" 65 #include "dns-msg.h" 66 #include "ioloop.h" 67 #include "srp-crypto.h" 68 69 #include "cti-services.h" 70 #include "srp-gw.h" 71 #include "srp-proxy.h" 72 #include "srp-mdns-proxy.h" 73 #include "adv-ctl-server.h" 74 #include "dnssd-proxy.h" 75 #include "srp-proxy.h" 76 #include "route.h" 77 #include "ifpermit.h" 78 #include "srp-dnssd.h" 79 80 #define STATE_MACHINE_IMPLEMENTATION 1 81 typedef enum { 82 service_publisher_state_invalid, 83 service_publisher_state_startup, 84 service_publisher_state_waiting_to_publish, 85 service_publisher_state_not_publishing, 86 service_publisher_state_start_listeners, 87 service_publisher_state_publishing, 88 } state_machine_state_t; 89 #define state_machine_state_invalid service_publisher_state_invalid 90 91 #include "state-machine.h" 92 #include "thread-service.h" 93 #include "service-tracker.h" 94 95 #include "service-publisher.h" 96 #include "thread-tracker.h" 97 #include "node-type-tracker.h" 98 99 // This is pretty short because our normal use case is connecting to a single device, so we don't actually anticipate 100 // normally seeing a service. But if we do, we don't suffer power events, so we don't need to desynchronize from other 101 // devices booting at the same time. So we just want to wait long enough that if there's already a service published, 102 // we see it and don't publish. 103 #define SERVICE_PUBLISHER_START_WAIT 750 104 105 // When a competing service is lost, we want to wait a bit longer. 106 #define SERVICE_PUBLISHER_LOST_WAIT 5000 107 108 // When the listener restarts, we don't actually want to wait. 109 #define SERVICE_PUBLISHER_LISTENER_RESTART_WAIT 1 110 111 #define ADDRESS_RECORD_TTL 4500 112 #define OTHER_RECORD_TTL 4500 113 114 struct service_publisher { 115 int ref_count; 116 state_machine_header_t state_header; 117 char *id; 118 char *thread_interface_name; 119 srp_server_t *server_state; 120 wakeup_t *NULLABLE wakeup_timer; 121 wakeup_t *NULLABLE sed_timeout; 122 comm_t *srp_listener; 123 void (*reconnect_callback)(void *context); 124 thread_service_t *published_unicast_service; 125 thread_service_t *published_anycast_service; 126 thread_service_t *publication_queue; 127 cti_connection_t active_data_set_connection; 128 cti_connection_t wed_tracker_connection; 129 cti_connection_t neighbor_tracker_connection; 130 struct in6_addr thread_mesh_local_address; 131 struct in6_addr wed_ml_eid; 132 struct in6_addr neighbor_ml_eid; 133 char *NULLABLE wed_ext_address_string; 134 char *NULLABLE wed_ml_eid_string; 135 char *NULLABLE neighbor_ml_eid_string; 136 int startup_delay_range; 137 int retry_interval; // Retry interval in seconds for re-publishing service(s) 138 uint16_t srp_listener_port; 139 bool have_ml_eid; 140 bool first_time; 141 bool force_publication; 142 bool canceled; 143 bool have_srp_listener; 144 bool seen_service_list; 145 bool stopped; 146 bool have_thread_interface_name; 147 bool have_unicast_in_net_data, have_anycast_in_net_data; 148 bool cached_services_published, started_stale_service_timeout; 149 }; 150 151 static uint64_t service_publisher_serial_number; 152 153 static void service_publisher_queue_run(service_publisher_t *publisher); 154 155 void 156 service_publisher_unadvertise_all(service_publisher_t *publisher) 157 { 158 srp_server_t *server_state = publisher->server_state; 159 160 publisher->cached_services_published = false; 161 for (adv_host_t *host = server_state->hosts; host; host = host->next) { 162 // If we have an outstanding update, finish it. 163 if (host->update != NULL) { 164 srp_mdns_update_finished(host->update); 165 } 166 if (host->addresses != NULL) { 167 for (int i = 0; i < host->addresses->num; i++) { 168 adv_record_t *record = host->addresses->vec[i]; 169 if (record != NULL) { 170 if (record->rrtype == dns_rrtype_aaaa && record->rdlen == 16) { 171 SEGMENTED_IPv6_ADDR_GEN_SRP(record->rdata, rdata_buf); 172 INFO("unadvertising " PRI_S_SRP " IN AAAA " PRI_SEGMENTED_IPv6_ADDR_SRP " rec %p rref %p", 173 host->name, SEGMENTED_IPv6_ADDR_PARAM_SRP(record->rdata, rdata_buf), 174 record, record->rref); 175 } 176 srp_mdns_shared_record_remove(server_state, record); 177 // DNSServiceRemoveRecord should clear the cache, but it doesn't. 178 DNSServiceReconfirmRecord(0, server_state->advertise_interface, host->name, record->rrtype, 179 dns_qclass_in, record->rdlen, record->rdata); 180 } 181 } 182 } 183 if (host->key_record != NULL) { 184 srp_mdns_shared_record_remove(server_state, host->key_record); 185 } 186 if (host->instances != NULL) { 187 for (int i = 0; i < host->instances->num; i++) { 188 adv_instance_t *instance = host->instances->vec[i]; 189 if (instance != NULL && instance->txn != NULL) { 190 INFO("unadvertising " PRI_S_SRP "." PRI_S_SRP " instance %p sdref %p", 191 instance->instance_name, instance->service_type, instance, instance->txn->sdref); 192 ioloop_dnssd_txn_cancel(instance->txn); 193 ioloop_dnssd_txn_release(instance->txn); 194 instance->txn = NULL; 195 } 196 } 197 } 198 } 199 } 200 201 static void 202 service_publisher_instance_callback(DNSServiceRef UNUSED sdref, DNSServiceFlags UNUSED flags, DNSServiceErrorType error_code, 203 const char *name, const char *regtype, const char *domain, void *context) 204 { 205 adv_instance_t *instance = context; 206 if (error_code != kDNSServiceErr_NoError) { 207 INFO("DNSServiceRegister failed: " PUB_S_SRP "." PUB_S_SRP " host " PRI_S_SRP ": %d (instance %p sdref %p)", 208 name, regtype, domain, error_code, instance, instance->txn == NULL ? 0 : instance->txn->sdref); 209 ioloop_dnssd_txn_cancel(instance->txn); 210 ioloop_dnssd_txn_release(instance->txn); 211 instance->txn = NULL; 212 } else { 213 INFO("DNSServiceRegister succeeded: " PUB_S_SRP "." PUB_S_SRP " host " PRI_S_SRP " (instance %p sdref %p)", 214 instance->instance_name, instance->service_type, instance->host->registered_name, 215 instance, instance->txn == NULL ? 0 : instance->txn->sdref); 216 } 217 } 218 219 static void 220 service_publisher_re_advertise_instance(srp_server_t *server_state, adv_host_t *host, adv_instance_t *instance) 221 { 222 DNSServiceRef service_ref = server_state->shared_registration_txn->sdref; 223 224 // Make sure we don't double-register. 225 if (instance->txn != NULL) { 226 if (instance->txn->sdref != NULL) { 227 if (instance->shared_txn == (intptr_t)server_state->shared_registration_txn) { 228 INFO("instance is already registered: " PUB_S_SRP "." PUB_S_SRP " host " PRI_S_SRP 229 " (instance %p sdref %p)", 230 instance->instance_name, instance->service_type, host->registered_name, 231 instance, instance->txn->sdref); 232 return; 233 } 234 INFO("instance registration is stale: " PUB_S_SRP "." PUB_S_SRP " host " PRI_S_SRP 235 " (instance %p sdref %p)", 236 instance->instance_name, instance->service_type, host->registered_name, 237 instance, instance->txn->sdref); 238 instance->txn->sdref = NULL; 239 } 240 ioloop_dnssd_txn_release(instance->txn); 241 instance->txn = NULL; 242 } 243 244 // Get the TSR attribute for the host object. 245 char time_buf[TSR_TIMESTAMP_STRING_LEN]; 246 DNSServiceAttributeRef tsr_attribute = srp_message_tsr_attribute_generate(NULL, host->key_id, 247 time_buf, sizeof(time_buf)); 248 249 int err = dns_service_register_wa(server_state, &service_ref, 250 (kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename | 251 kDNSServiceFlagsKnownUnique), server_state->advertise_interface, 252 instance->instance_name, instance->service_type, NULL, 253 host->registered_name, htons(instance->port), instance->txt_length, 254 instance->txt_data, tsr_attribute, service_publisher_instance_callback, instance); 255 256 // This would happen if we pass NULL for regtype, which we don't, or if we run out of memory, or if 257 // the server isn't running; in the second two cases, we can always try again later. 258 if (err != kDNSServiceErr_NoError) { 259 INFO("DNSServiceRegister failed: " PUB_S_SRP "." PUB_S_SRP " host " PRI_S_SRP ": %d (instance %p)", 260 instance->instance_name, instance->service_type, host->registered_name, err, instance); 261 } else { 262 INFO("DNSServiceRegister succeeded: " PUB_S_SRP "." PUB_S_SRP " host " PRI_S_SRP " at " PUB_S_SRP 263 " (instance %p sdref %p)", 264 instance->instance_name, instance->service_type, host->registered_name, time_buf, 265 instance, service_ref); 266 instance->txn = ioloop_dnssd_txn_add_subordinate(service_ref, instance, adv_instance_context_release, NULL); 267 if (instance->txn == NULL) { 268 ERROR("no memory for instance transaction."); 269 DNSServiceRefDeallocate(service_ref); 270 return; 271 } 272 instance->shared_txn = (intptr_t)server_state->shared_registration_txn; 273 adv_instance_retain(instance); // for the callback 274 } 275 } 276 277 static void 278 service_publisher_record_callback(DNSServiceRef UNUSED sdref, DNSRecordRef rref, 279 DNSServiceFlags UNUSED flags, DNSServiceErrorType error_code, void *context) 280 { 281 adv_record_t *record = context; 282 const char *host_name = record->host != NULL ? record->host->name : "<null>"; 283 if (error_code != kDNSServiceErr_NoError) { 284 ERROR("re-registration for " PRI_S_SRP " (record %p rref %p) failed with code %d", 285 host_name, record, rref, error_code); 286 record->rref = NULL; 287 record->shared_txn = 0; 288 adv_record_release(record); // no more callbacks. 289 } else { 290 INFO("re-registration for " PRI_S_SRP " (record %p rref %p) succeeded.", host_name, record, rref); 291 // could get more callbacks. 292 } 293 } 294 295 static void 296 service_publisher_re_advertise_record(srp_server_t *server_state, adv_host_t *host, adv_record_t *record) 297 { 298 const DNSServiceRef service_ref = host->server_state->shared_registration_txn->sdref; 299 300 // Make sure we don't double register. 301 if (record->rref != NULL) { 302 if (record->shared_txn == (intptr_t)server_state->shared_registration_txn) { 303 INFO("host is already registered: " PUB_S_SRP " (record %p rref %p)", 304 host->registered_name, record, record->rref); 305 return; 306 } 307 INFO("host registration is stale: " PUB_S_SRP " (record %p rref %p)", 308 host->registered_name, record, record->rref); 309 srp_mdns_shared_record_remove(host->server_state, record); 310 } 311 312 // Get the TSR attribute for the host object. 313 char time_buf[TSR_TIMESTAMP_STRING_LEN]; 314 DNSServiceAttributeRef tsr_attribute = srp_message_tsr_attribute_generate(NULL, host->key_id, 315 time_buf, sizeof(time_buf)); 316 317 int err = dns_service_register_record_wa(server_state, service_ref, &record->rref, kDNSServiceFlagsKnownUnique, 318 server_state->advertise_interface, host->registered_name, 319 record->rrtype, dns_qclass_in, record->rdlen, record->rdata, ADDRESS_RECORD_TTL, 320 tsr_attribute, service_publisher_record_callback, record); 321 if (err != kDNSServiceErr_NoError) { 322 INFO("DNSServiceRegisterRecord failed on host " PUB_S_SRP ": %d (record %p)", host->name, err, record); 323 } else { 324 INFO("DNSServiceRegisterRecord succeeded on host " PUB_S_SRP " at " PUB_S_SRP " (record %p rref %p)", 325 host->name, time_buf, record, record->rref); 326 record->shared_txn = (intptr_t)host->server_state->shared_registration_txn; 327 adv_record_retain(record); // for the callback 328 } 329 } 330 331 // Re-advertise records that match the address of the WED device we're bonded to if we're bonded to a WED device, or 332 // that match the mesh-local prefix of our mesh-local address. This is a best effort--if it fails, we log it, but it 333 // just means that our cached info isn't discoverable and we have to wait for a new registration, which should come soon 334 // or else the cached data wasn't valid. 335 void 336 service_publisher_re_advertise_matching(service_publisher_t *publisher) 337 { 338 if (publisher->state_header.state == service_publisher_state_invalid) { 339 INFO("publisher is in an invalid state, so we shouldn't re-advertise anything."); 340 return; 341 } 342 343 srp_server_t *server_state = publisher->server_state; 344 345 // If we don't yet have a shared connection, create one. 346 if (!srp_mdns_shared_registration_txn_setup(server_state)) { 347 return; 348 } 349 350 for (adv_host_t *host = server_state->hosts; host; host = host->next) { 351 bool matched = false; 352 353 if (host->addresses != NULL) { 354 for (int i = 0; i < host->addresses->num; i++) { 355 adv_record_t *record = host->addresses->vec[i]; 356 // A match means that if we are in WED p2p mode, the ML-EID of the WED matches the record. If not, then 357 // it means that the record is on the mesh-local prefix. In both cases, the record has to be a valid 358 // AAAA record, of course. 359 if (record != NULL && record->rrtype == dns_rrtype_aaaa && record->rdlen == 16 && 360 (publisher->wed_ml_eid_string != NULL 361 ? !in6addr_compare(&publisher->wed_ml_eid, (struct in6_addr *)record->rdata) 362 : !in6prefix_compare(&publisher->thread_mesh_local_address, (struct in6_addr *)record->rdata, 8))) 363 { 364 SEGMENTED_IPv6_ADDR_GEN_SRP(record->rdata, rdata_buf); 365 INFO("re-advertising " PRI_S_SRP " IN AAAA " PRI_SEGMENTED_IPv6_ADDR_SRP, 366 host->name, SEGMENTED_IPv6_ADDR_PARAM_SRP(record->rdata, rdata_buf)); 367 service_publisher_re_advertise_record(server_state, host, record); 368 matched = true; 369 } 370 } 371 } 372 if (matched) { 373 if (host->key_record != NULL) { 374 service_publisher_re_advertise_record(server_state, host, host->key_record); 375 } 376 if (host->instances != NULL) { 377 for (int i = 0; i < host->instances->num; i++) { 378 adv_instance_t *instance = host->instances->vec[i]; 379 if (instance != NULL && instance->txn == NULL) { 380 service_publisher_re_advertise_instance(server_state, host, instance); 381 } 382 } 383 } 384 } 385 } 386 387 publisher->cached_services_published = true; 388 } 389 390 bool 391 service_publisher_is_address_mesh_local(service_publisher_t *publisher, addr_t *address) 392 { 393 if (address->sa.sa_family == AF_INET) { 394 IPv4_ADDR_GEN_SRP(&address->sin.sin_addr, addr_buf); 395 if (!IN_LOOPBACK(address->sin.sin_addr.s_addr)) { 396 INFO(PRI_IPv4_ADDR_SRP "is not mesh-local", IPv4_ADDR_PARAM_SRP(&address->sin.sin_addr, addr_buf)); 397 return false; 398 } 399 INFO(PRI_IPv4_ADDR_SRP "is the IPv4 loopback address", IPv4_ADDR_PARAM_SRP(&address->sin.sin_addr, addr_buf)); 400 return true; 401 } 402 if (address->sa.sa_family != AF_INET6) { 403 INFO("address family %d can't be mesh-local", address->sa.sa_family); 404 return false; 405 } 406 407 uint8_t *addr_ptr = (uint8_t *)&address->sin6.sin6_addr; 408 SEGMENTED_IPv6_ADDR_GEN_SRP(addr_ptr, addr_buf); 409 if (IN6_IS_ADDR_LOOPBACK(&address->sin6.sin6_addr)) { 410 INFO(PRI_SEGMENTED_IPv6_ADDR_SRP " is the IPv6 loopback address.", 411 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr_ptr, addr_buf)); 412 return true; 413 } 414 static const uint8_t ipv4mapped_loopback[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 127, 0, 0, 1 }; 415 if (!memcmp(&address->sin6.sin6_addr, ipv4mapped_loopback, sizeof(ipv4mapped_loopback))) { 416 INFO(PRI_SEGMENTED_IPv6_ADDR_SRP " is the IPv4-mapped loopback address.", 417 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr_ptr, addr_buf)); 418 return true; 419 } 420 421 if (!publisher->have_ml_eid) { 422 INFO(PRI_SEGMENTED_IPv6_ADDR_SRP "is not mesh-local", 423 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr_ptr, addr_buf)); 424 return false; 425 } 426 427 SEGMENTED_IPv6_ADDR_GEN_SRP(&publisher->thread_mesh_local_address, mle_buf); 428 if (in6prefix_compare(&address->sin6.sin6_addr, &publisher->thread_mesh_local_address, 8)) { 429 INFO(PRI_SEGMENTED_IPv6_ADDR_SRP 430 " is not on the same prefix as mesh-local address " PRI_SEGMENTED_IPv6_ADDR_SRP ".", 431 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr_ptr, addr_buf), 432 SEGMENTED_IPv6_ADDR_PARAM_SRP(&publisher->thread_mesh_local_address, mle_buf)); 433 return false; 434 } 435 INFO(PRI_SEGMENTED_IPv6_ADDR_SRP "is on the same prefix as mesh-local address " PRI_SEGMENTED_IPv6_ADDR_SRP ".", 436 SEGMENTED_IPv6_ADDR_PARAM_SRP(addr_ptr, addr_buf), 437 SEGMENTED_IPv6_ADDR_PARAM_SRP(&publisher->thread_mesh_local_address, mle_buf)); 438 return true; 439 } 440 441 static void 442 service_publisher_finalize(service_publisher_t *publisher) 443 { 444 thread_service_release(publisher->published_unicast_service); 445 thread_service_release(publisher->published_anycast_service); 446 thread_service_list_release(&publisher->publication_queue); 447 448 free(publisher->state_header.name); 449 free(publisher->wed_ext_address_string); 450 free(publisher->wed_ml_eid_string); 451 free(publisher->neighbor_ml_eid_string); 452 free(publisher->id); 453 ioloop_wakeup_release(publisher->wakeup_timer); 454 free(publisher); 455 } 456 457 RELEASE_RETAIN_FUNCS(service_publisher); 458 459 static void 460 service_publisher_context_release(void *context) 461 { 462 service_publisher_t *publisher = context; 463 RELEASE_HERE(publisher, service_publisher); 464 } 465 466 static void 467 service_publisher_update_callback(void *context, cti_status_t status) 468 { 469 service_publisher_t *publisher = context; 470 thread_service_t *service = publisher->publication_queue; 471 472 if (publisher->canceled) { 473 RELEASE_HERE(publisher, service_publisher); 474 return; 475 } 476 477 if (service == NULL) { 478 ERROR("no pending service update"); 479 return; 480 } 481 char status_buf[256]; 482 snprintf(status_buf, sizeof(status_buf), "is in state %s, status = %d", 483 thread_service_publication_state_name_get(service->publication_state), status); 484 thread_service_note(publisher->id, service, status_buf); 485 if (status == kCTIStatus_NoError) { 486 if (service->publication_state == add_pending) { 487 service->publication_state = add_complete; 488 } else if (service->publication_state == delete_pending) { 489 service->publication_state = delete_complete; 490 } 491 } else { 492 if (service->publication_state == add_pending) { 493 service->publication_state = add_failed; 494 } else if (service->publication_state == delete_pending) { 495 service->publication_state = delete_failed; 496 } 497 } 498 publisher->publication_queue = service->next; 499 thread_service_release(service); 500 if (!publisher->canceled) { 501 service_publisher_queue_run(publisher); 502 } 503 RELEASE_HERE(publisher, service_publisher); 504 } 505 506 static cti_status_t 507 service_publisher_service_update(service_publisher_t *publisher, thread_service_t *service, bool add) 508 { 509 uint8_t service_data[20]; 510 uint8_t server_data[20]; 511 size_t service_data_length, server_data_length; 512 switch(service->service_type) { 513 default: 514 return kCTIStatus_Invalid; 515 case unicast_service: 516 service_data[0] = THREAD_SRP_SERVER_OPTION; 517 service_data_length = 1; 518 memcpy(server_data, &service->u.unicast.address, 16); 519 memcpy(&server_data[16], service->u.unicast.port, 2); 520 server_data_length = 18; 521 break; 522 case anycast_service: 523 service_data[0] = THREAD_SRP_SERVER_ANYCAST_OPTION; 524 service_data[1] = service->u.anycast.sequence_number; 525 service_data_length = 2; 526 server_data_length = 0; 527 break; 528 case pref_id: 529 return kCTIStatus_BadParam; // Not supported anymore. 530 } 531 532 if (add) { 533 return cti_add_service(publisher->server_state, publisher, service_publisher_update_callback, NULL, 534 THREAD_ENTERPRISE_NUMBER, service_data, service_data_length, server_data, server_data_length); 535 } else { 536 return cti_remove_service(publisher->server_state, publisher, service_publisher_update_callback, NULL, 537 THREAD_ENTERPRISE_NUMBER, service_data, service_data_length); 538 } 539 } 540 541 static void 542 service_publisher_queue_run(service_publisher_t *publisher) 543 { 544 thread_service_t *service = publisher->publication_queue; 545 if (service == NULL) { 546 INFO("the queue is empty."); 547 return; 548 } 549 if (service->publication_state == delete_pending || service->publication_state == add_pending) { 550 INFO("there is a pending update at the head of the queue."); 551 return; 552 } 553 if (service->publication_state == want_delete) { 554 cti_status_t status = service_publisher_service_update(publisher, service, false); 555 if (status != kCTIStatus_NoError) { 556 ERROR("cti_remove_service failed: %d", status); 557 // For removes, we'll leave it on the queue 558 } else { 559 service->publication_state = delete_pending; 560 RETAIN_HERE(publisher, service_publisher); // for the callback 561 } 562 } else if (service->publication_state == want_add) { 563 cti_status_t status = service_publisher_service_update(publisher, service, true); 564 if (status != kCTIStatus_NoError) { 565 ERROR("cti_add_service failed: %d", status); 566 publisher->publication_queue = service->next; 567 thread_service_release(service); 568 } else { 569 service->publication_state = add_pending; 570 RETAIN_HERE(publisher, service_publisher); // for the callback 571 } 572 } else { 573 char status_buf[256]; 574 snprintf(status_buf, sizeof(status_buf), "is in unexpected state %s on the publication queue", 575 thread_service_publication_state_name_get(service->publication_state)); 576 thread_service_note(publisher->id, service, status_buf); 577 publisher->publication_queue = service->next; 578 thread_service_release(service); 579 } 580 } 581 582 static void 583 service_publisher_queue_update(service_publisher_t *publisher, thread_service_t *service, 584 thread_service_publication_state_t initial_state) 585 { 586 thread_service_t **ppref; 587 588 thread_service_t **p_published; 589 if (service->service_type == unicast_service) { 590 p_published = &publisher->published_unicast_service; 591 } else if (service->service_type == unicast_service) { 592 p_published = &publisher->published_unicast_service; 593 } else { 594 ERROR("unsupported service type %d", service->service_type); 595 return; 596 } 597 if (thread_service_equal(*p_published, service)) { 598 FAULT("published service still present: %p", *p_published); 599 } 600 service->publication_state = initial_state; 601 if (initial_state == want_add) { 602 *p_published = service; 603 thread_service_retain(*p_published); 604 } 605 // Find the end of the queue 606 for (ppref = &publisher->publication_queue; *ppref != NULL; ppref = &(*ppref)->next) 607 ; 608 *ppref = service; 609 // Retain the service on the queue. 610 thread_service_retain(*ppref); 611 service_publisher_queue_run(publisher); 612 } 613 614 static thread_service_t * 615 service_publisher_create_service_for_queue(thread_service_t *service) 616 { 617 switch(service->service_type) { 618 case unicast_service: 619 return thread_service_unicast_create(service->rloc16, service->u.unicast.address.s6_addr, 620 service->u.unicast.port, service->service_id); 621 case anycast_service: 622 return thread_service_anycast_create(service->rloc16, service->u.anycast.sequence_number, service->service_id); 623 case pref_id: 624 return thread_service_pref_id_create(service->rloc16, service->u.pref_id.partition_id, 625 service->u.pref_id.prefix, service->service_id); 626 default: 627 return NULL; 628 } 629 } 630 631 static void UNUSED 632 service_publisher_service_publish(service_publisher_t *publisher, thread_service_t *service) 633 { 634 service_publisher_queue_update(publisher, service, want_add); 635 } 636 637 static void UNUSED 638 service_publisher_service_unpublish(service_publisher_t *publisher, thread_service_type_t service_type, bool enqueue) 639 { 640 thread_service_t *service; 641 642 if (service_type == unicast_service) { 643 service = publisher->published_unicast_service; 644 publisher->published_unicast_service = NULL; 645 } else if (service_type == anycast_service) { 646 service = publisher->published_anycast_service; 647 publisher->published_anycast_service = NULL; 648 } else { 649 ERROR("unsupported service type %d", service_type); 650 return; 651 } 652 if (service == NULL) { 653 ERROR("request to unpublished service that's not present"); 654 return; 655 } 656 657 if (enqueue) { 658 thread_service_t *to_delete = service_publisher_create_service_for_queue(service); 659 service_publisher_queue_update(publisher, to_delete, want_delete); 660 thread_service_release(to_delete); // service_publisher_queue_update explicitly retains the references it makes. 661 thread_service_release(service); // No longer published. 662 } 663 } 664 665 static void 666 service_publisher_unpublish_stale_service(service_publisher_t *publisher, thread_service_t *service) 667 { 668 // If there's a stale service, don't try to publish the real service until we see the stale service go away. 669 INFO("setting seen_service_list to false"); 670 publisher->seen_service_list = false; 671 672 thread_service_t *to_delete = service_publisher_create_service_for_queue(service); 673 674 if (to_delete == NULL) { 675 thread_service_note(publisher->id, service, "no memory for service to delete"); 676 } else { 677 service_publisher_queue_update(publisher, to_delete, want_delete); 678 thread_service_release(to_delete); // service_publisher_queue_update explicitly retains all the references it makes 679 service->ignore = true; 680 } 681 } 682 683 static void 684 service_publisher_wait_expired(void *context) 685 { 686 service_publisher_t *publisher = context; 687 state_machine_event_t *event = state_machine_event_create(state_machine_event_type_timeout, NULL); 688 if (event == NULL) { 689 ERROR("unable to allocate event to deliver"); 690 return; 691 } 692 state_machine_event_deliver(&publisher->state_header, event); 693 RELEASE_HERE(event, state_machine_event); 694 } 695 696 static void 697 service_publisher_start_wait(service_publisher_t *publisher, int32_t milliseconds) 698 { 699 ioloop_add_wake_event(publisher->wakeup_timer, publisher, service_publisher_wait_expired, 700 service_publisher_context_release, milliseconds); 701 RETAIN_HERE(publisher, service_publisher); // For wakeup 702 } 703 704 static bool 705 service_publisher_have_competing_unicast_service(service_publisher_t *publisher, bool want_stale_service_timeout) 706 { 707 thread_service_t *NULLABLE published_service = publisher->published_unicast_service; 708 bool competing_service_present = false; 709 710 for (thread_service_t *service = service_tracker_services_get(publisher->server_state->service_tracker); 711 service != NULL; service = service->next) 712 { 713 if (service->ignore) { 714 continue; 715 } 716 if (service->service_type == unicast_service) { 717 if (published_service == NULL) { 718 if (service->rloc16 == publisher->server_state->rloc16 || 719 (publisher->have_ml_eid && 720 !in6addr_compare(&service->u.unicast.address, &publisher->thread_mesh_local_address))) 721 { 722 thread_service_note(publisher->id, service, 723 "is on our ml-eid or rloc16 but we aren't publishing it, so it's stale."); 724 service_publisher_unpublish_stale_service(publisher, service); 725 726 if (want_stale_service_timeout && 727 !publisher->cached_services_published && !publisher->started_stale_service_timeout) 728 { 729 INFO("starting wakeup timer to publish cached services after stale service timeout."); 730 publisher->started_stale_service_timeout = true; 731 service_publisher_start_wait(publisher, 2000); 732 } 733 continue; 734 } 735 thread_service_note(publisher->id, service, "is not ours and we aren't publishing."); 736 competing_service_present = true; 737 // First check to see if the other service is on the mesh-local prefix. If it's not, it wins. 738 } else if (in6prefix_compare(&service->u.unicast.address, &published_service->u.unicast.address, 8)) { 739 competing_service_present = true; 740 thread_service_note(publisher->id, service, "is a competing service."); 741 } else { 742 int cmp = in6addr_compare(&service->u.unicast.address, &published_service->u.unicast.address); 743 744 // If equal, compare ports... 745 if (!cmp) { 746 cmp = memcmp(service->u.unicast.port, published_service->u.unicast.port, 747 sizeof(service->u.unicast.port)); 748 // If the port doesn't match our published service, it's a weird stale service (this probably can't 749 // happen); 750 if (cmp) { 751 thread_service_note(publisher->id, service, 752 "is on our ml-eid but is not the one we are publishing, so it's stale."); 753 service_publisher_unpublish_stale_service(publisher, service); 754 continue; 755 } else { 756 thread_service_note(publisher->id, service, "is the one we are publishing."); 757 } 758 } else { 759 // This is a stale service published on our RLOC16 with a different ML-EID. 760 if (service->rloc16 == publisher->server_state->rloc16) { 761 thread_service_note(publisher->id, service, 762 "is a stale service published on our rloc16 with a different ml-eid."); 763 service_publisher_unpublish_stale_service(publisher, service); 764 continue; 765 } else if (cmp < 0) { 766 competing_service_present = true; 767 thread_service_note(publisher->id, service, "is not ours and wins against ours."); 768 } else { 769 thread_service_note(publisher->id, service, "is not ours and loses against ours."); 770 } 771 } 772 } 773 } 774 } 775 return competing_service_present; 776 } 777 778 static bool 779 service_publisher_have_anycast_service(service_publisher_t *publisher) 780 { 781 bool anycast_service_present = false; 782 783 for (thread_service_t *service = service_tracker_services_get(publisher->server_state->service_tracker); 784 service != NULL; service = service->next) 785 { 786 if (service->ignore) { 787 continue; 788 } 789 if (service->service_type == anycast_service) { 790 thread_service_note(publisher->id, service, "is present and supersedes our unicast service"); 791 anycast_service_present = true; 792 } 793 } 794 return anycast_service_present; 795 } 796 797 void 798 service_publisher_wanted_service_added(service_publisher_t *publisher) 799 { 800 state_machine_event_t *event = state_machine_event_create(state_machine_event_type_srp_needed, NULL); 801 if (event == NULL) { 802 ERROR("unable to allocate event to deliver"); 803 return; 804 } 805 state_machine_event_deliver(&publisher->state_header, event); 806 RELEASE_HERE(event, state_machine_event); 807 } 808 809 static void 810 service_publisher_sed_timeout_expired(void *context) 811 { 812 service_publisher_t *publisher = context; 813 814 if (publisher->sed_timeout != NULL) { 815 ioloop_wakeup_release(publisher->sed_timeout); 816 publisher->sed_timeout = NULL; 817 } 818 if (publisher->neighbor_ml_eid_string == NULL) { 819 publisher->neighbor_ml_eid_string = strdup("none"); 820 memset(&publisher->neighbor_ml_eid, 0, sizeof(publisher->neighbor_ml_eid)); 821 } 822 state_machine_event_t *event = state_machine_event_create(state_machine_event_type_neighbor_ml_eid_changed, NULL); 823 if (event == NULL) { 824 ERROR("unable to allocate event to deliver"); 825 } else { 826 state_machine_event_deliver(&publisher->state_header, event); 827 RELEASE_HERE(event, state_machine_event); 828 } 829 } 830 831 static void 832 service_publisher_service_tracker_callback(void *context) 833 { 834 service_publisher_t *publisher = context; 835 836 // If we get a service list update when we're associated, set the seen_service-list flag to true. This tells us we can proceed 837 // with publishing a service if we just associated to the thread network. 838 if (thread_tracker_associated_get(publisher->server_state->thread_tracker, false)) { 839 INFO("setting seen_service_list to true"); 840 publisher->seen_service_list = true; 841 } 842 843 state_machine_event_t *event = state_machine_event_create(state_machine_event_type_service_list_changed, NULL); 844 if (event == NULL) { 845 ERROR("unable to allocate event to deliver"); 846 return; 847 } 848 state_machine_event_deliver(&publisher->state_header, event); 849 RELEASE_HERE(event, state_machine_event); 850 } 851 852 static void 853 service_publisher_thread_tracker_callback(void *context) 854 { 855 service_publisher_t *publisher = context; 856 857 // This is a temporary hack because right now we won't get a prefix list event on associate, and we need 858 // the (presumably empty) prefix list event to trigger an immediate service advertisement. 859 // IMPORTANT: when this is fixed, make sure to start the service_tracker in thread-device.c again. 860 // To work around this issue, we stop service list events in the service tracker when we dissociate, and 861 // restart events when we re-associate. 862 // Hack is tracked in rdar://109266343 (Optimize SRP registration time) 863 if (!thread_tracker_associated_get(publisher->server_state->thread_tracker, false)) { 864 service_tracker_stop(publisher->server_state->service_tracker); 865 } else { 866 service_tracker_start(publisher->server_state->service_tracker); 867 } 868 869 state_machine_event_t *event = state_machine_event_create(state_machine_event_type_thread_network_state_changed, NULL); 870 if (event == NULL) { 871 ERROR("unable to allocate event to deliver"); 872 return; 873 } 874 state_machine_event_deliver(&publisher->state_header, event); 875 RELEASE_HERE(event, state_machine_event); 876 } 877 878 static void 879 service_publisher_node_type_tracker_callback(void *context) 880 { 881 service_publisher_t *publisher = context; 882 state_machine_event_t *event = state_machine_event_create(state_machine_event_type_thread_node_type_changed, NULL); 883 if (event == NULL) { 884 ERROR("unable to allocate event to deliver"); 885 return; 886 } 887 state_machine_event_deliver(&publisher->state_header, event); 888 RELEASE_HERE(event, state_machine_event); 889 } 890 891 // Service publisher states 892 // 893 // <startup> 894 // on entry: start timer for a random amount of time 895 // timer event: -> <waiting to publish> 896 // other events: ignore 897 // <waiting to publish> 898 // on entry: check for service present 899 // yes: -> <not publishing> 900 // check for ML-EID present 901 // yes: -> <start listeners> 902 // ML-EID shows up: -> <start listeners> 903 // service shows up: -> <not publishing> 904 // <not publishing> 905 // on entry: do nothing 906 // last service advertisement goes away: -> <waiting to publish> 907 // <start listeners> 908 // on entry: start listeners 909 // listener ready: -> <publishing> 910 // <publishing> 911 // on entry: publish the service 912 // start wait timer 913 // on timery expiry: publish the service again 914 // our service shows up: stop the timer 915 // winning service shows up: stop advertising 916 // -> <not publishing> 917 918 static state_machine_state_t service_publisher_action_startup(state_machine_header_t *state_header, 919 state_machine_event_t *event); 920 static state_machine_state_t service_publisher_action_waiting_to_publish(state_machine_header_t *state_header, 921 state_machine_event_t *event); 922 static state_machine_state_t service_publisher_action_not_publishing(state_machine_header_t *state_header, 923 state_machine_event_t *event); 924 static state_machine_state_t service_publisher_action_start_listeners(state_machine_header_t *state_header, 925 state_machine_event_t *event); 926 static state_machine_state_t service_publisher_action_publishing(state_machine_header_t *state_header, 927 state_machine_event_t *event); 928 929 #define SERVICE_PUB_NAME_DECL(name) service_publisher_state_##name, #name 930 static state_machine_decl_t service_publisher_states[] = { 931 { SERVICE_PUB_NAME_DECL(invalid), NULL }, 932 { SERVICE_PUB_NAME_DECL(startup), service_publisher_action_startup }, 933 { SERVICE_PUB_NAME_DECL(waiting_to_publish), service_publisher_action_waiting_to_publish }, 934 { SERVICE_PUB_NAME_DECL(not_publishing), service_publisher_action_not_publishing }, 935 { SERVICE_PUB_NAME_DECL(start_listeners), service_publisher_action_start_listeners }, 936 { SERVICE_PUB_NAME_DECL(publishing), service_publisher_action_publishing }, 937 }; 938 #define SERVICE_PUBLISHER_NUM_STATES ((sizeof(service_publisher_states)) / (sizeof(state_machine_decl_t))) 939 940 #define STATE_MACHINE_HEADER_TO_PUBLISHER(state_header) \ 941 if (state_header->state_machine_type != state_machine_type_service_publisher) { \ 942 ERROR("state header type isn't service_publisher: %d", state_header->state_machine_type); \ 943 return service_publisher_state_invalid; \ 944 } \ 945 service_publisher_t *publisher = state_header->state_object 946 947 // In the startup state, we wait for a timeout to expire before doing anything. This gives other devices on the Thread mesh 948 // an opportunity to publish as well. 949 static state_machine_state_t 950 service_publisher_action_startup(state_machine_header_t *state_header, state_machine_event_t *event) 951 { 952 STATE_MACHINE_HEADER_TO_PUBLISHER(state_header); 953 BR_STATE_ANNOUNCE(publisher, event); 954 955 if (event == NULL) { 956 // We only need a random startup delay for stub routers, which are generally powered devices that can synchronize 957 // on restart after a power failure. 958 #if STUB_ROUTER 959 if (publisher->server_state->stub_router_enabled) { 960 service_publisher_start_wait(publisher, publisher->startup_delay_range + srp_random16() % publisher->startup_delay_range); 961 RETAIN_HERE(publisher, service_publisher); // For wakeup 962 return service_publisher_state_invalid; 963 } 964 #endif 965 return service_publisher_state_waiting_to_publish; 966 } 967 968 // The only way out of the startup state is for the timer to expire--we don't care about prefixes showing up or 969 // going away. 970 if (event->type == state_machine_event_type_timeout) { 971 INFO("startup timeout"); 972 return service_publisher_state_waiting_to_publish; 973 } 974 975 BR_UNEXPECTED_EVENT(publisher, event); 976 } 977 978 static bool 979 service_publisher_can_publish(service_publisher_t *publisher) 980 { 981 bool no_anycast_service = true; 982 bool no_competing_service = true; 983 bool associated = true; 984 bool router = false; 985 bool have_ml_eid = true; 986 bool have_thread_interface_name = true; 987 bool can_publish = true; 988 bool sleepy_router = false; 989 bool sleepy_end_device = false; 990 bool have_node_type = false; 991 bool have_wed_ml_eid = true; 992 bool have_neighbor_ml_eid = true; 993 994 // Check the conditions that prevent publication. 995 if (service_publisher_have_competing_unicast_service(publisher, false)) { 996 no_competing_service = false; 997 can_publish = false; 998 } 999 if (service_publisher_have_anycast_service(publisher)) { 1000 no_anycast_service = false; 1001 can_publish = false; 1002 } 1003 srp_server_t *server_state = publisher->server_state; 1004 if (!thread_tracker_associated_get(server_state->thread_tracker, false)) { 1005 associated = false; 1006 can_publish = false; 1007 INFO("setting seen_service_list to false"); 1008 publisher->seen_service_list = false; 1009 } 1010 1011 thread_node_type_t node_type = node_type_tracker_thread_node_type_get(server_state->node_type_tracker, false); 1012 switch(node_type) { 1013 case node_type_router: 1014 case node_type_leader: 1015 router = true; 1016 have_node_type = true; 1017 break; 1018 case node_type_sleepy_router: 1019 sleepy_router = true; 1020 have_node_type = true; 1021 break; 1022 case node_type_unknown: 1023 have_node_type = false; 1024 can_publish = false; 1025 break; 1026 case node_type_sleepy_end_device: 1027 case node_type_synchronized_sleepy_end_device: 1028 sleepy_end_device = true; 1029 have_node_type = true; 1030 break; 1031 default: 1032 have_node_type = true; 1033 break; 1034 } 1035 1036 if (!publisher->have_ml_eid) { 1037 have_ml_eid = false; 1038 can_publish = false; 1039 } 1040 if (!publisher->have_thread_interface_name) { 1041 have_thread_interface_name = false; 1042 can_publish = false; 1043 } 1044 if (!publisher->seen_service_list) { 1045 can_publish = false; 1046 } 1047 if (publisher->stopped) { 1048 can_publish = false; 1049 } 1050 if (publisher->wed_ml_eid_string == NULL) { 1051 have_wed_ml_eid = false; 1052 if (sleepy_router) { 1053 can_publish = false; 1054 } 1055 } 1056 if (publisher->neighbor_ml_eid_string == NULL) { 1057 have_neighbor_ml_eid = false; 1058 if (sleepy_end_device) { 1059 if (publisher->sed_timeout == NULL) { 1060 publisher->sed_timeout = ioloop_wakeup_create(); 1061 if (publisher->sed_timeout != NULL) { 1062 ioloop_add_wake_event(publisher->sed_timeout, publisher, service_publisher_sed_timeout_expired, 1063 service_publisher_context_release, 500); 1064 RETAIN_HERE(publisher, service_publisher); 1065 } 1066 } 1067 can_publish = false; 1068 } 1069 } 1070 1071 INFO(PUB_S_SRP PUB_S_SRP PUB_S_SRP PUB_S_SRP PUB_S_SRP PUB_S_SRP PUB_S_SRP PUB_S_SRP PUB_S_SRP PUB_S_SRP PUB_S_SRP PUB_S_SRP PUB_S_SRP PUB_S_SRP, 1072 can_publish ? "can publish" : "can't publish", 1073 publisher->seen_service_list ? "" : " have not seen service list", 1074 no_competing_service ? "" : " competing service present", 1075 no_anycast_service ? "" : " anycast service present", 1076 associated ? "" : " not associated ", 1077 router ? "" : " not a router ", 1078 sleepy_router ? "" : " not a sleepy router", 1079 sleepy_end_device ? "" : " not a sleepy end device", 1080 have_node_type ? "" : " don't have node type", 1081 have_ml_eid ? "" : " no ml-eid ", 1082 have_wed_ml_eid ? "" : " no wed ml-eid ", 1083 have_neighbor_ml_eid ? "" : " no neighbor ml-eid ", 1084 have_thread_interface_name ? "" : " no thread interface name ", 1085 publisher->stopped ? " stopped" : ""); 1086 return can_publish; 1087 } 1088 1089 // This function tells the caller whether the service publisher could publish a service. This will be the case either 1090 // because it actually is publishing a service, or because it's in the process of finding out if it can publish a 1091 // service, or preparing to publish a service. In practice, this means that the only state for which the answer is false 1092 // at present is the "not_publishing" state. 1093 bool 1094 service_publisher_could_publish(service_publisher_t *publisher) 1095 { 1096 if (publisher == NULL) { 1097 return false; 1098 } 1099 if (publisher->state_header.state == service_publisher_state_startup || 1100 publisher->state_header.state == service_publisher_state_waiting_to_publish || 1101 publisher->state_header.state == service_publisher_state_start_listeners || 1102 publisher->state_header.state == service_publisher_state_publishing) 1103 { 1104 return true; 1105 } 1106 return false; 1107 } 1108 1109 void 1110 service_publisher_stop_publishing(service_publisher_t *publisher) 1111 { 1112 publisher->stopped = true; 1113 state_machine_event_t *event = state_machine_event_create(state_machine_event_type_stop, NULL); 1114 if (event == NULL) { 1115 ERROR("unable to allocate event to deliver"); 1116 return; 1117 } 1118 state_machine_event_deliver(&publisher->state_header, event); 1119 RELEASE_HERE(event, state_machine_event); 1120 } 1121 1122 // We go to this state whenever we think we might need to publish, but are not yet publishing. So this state 1123 // acts as a gatekeeper: if there is already a service published, we go straight to not_publishing. If we don't 1124 // yet have an ML-EID, we have to wait until we get one to publish. If, while we are waiting for the ML-EID, 1125 // we see a service show up, we go to not_publishing. Otherwise, when the ML-EID comes, we go to the listener_start 1126 // page. 1127 static state_machine_state_t 1128 service_publisher_action_waiting_to_publish(state_machine_header_t *state_header, state_machine_event_t *event) 1129 { 1130 STATE_MACHINE_HEADER_TO_PUBLISHER(state_header); 1131 BR_STATE_ANNOUNCE(publisher, event); 1132 1133 // We do the same thing here whether we've gotten an event or just on entry, so no need to check. 1134 if (service_publisher_can_publish(publisher)) { 1135 ioloop_cancel_wake_event(publisher->wakeup_timer); 1136 publisher->started_stale_service_timeout = false; 1137 return service_publisher_state_start_listeners; 1138 } 1139 if (service_publisher_have_competing_unicast_service(publisher, true)) { 1140 ioloop_cancel_wake_event(publisher->wakeup_timer); 1141 publisher->started_stale_service_timeout = false; 1142 return service_publisher_state_not_publishing; 1143 } 1144 // If we saw a stale service, we'll get a timeout event here. 1145 if (event != NULL && event->type == state_machine_event_type_timeout && !publisher->cached_services_published) { 1146 service_publisher_re_advertise_matching(publisher); 1147 } 1148 return service_publisher_state_invalid; 1149 } 1150 1151 // We get into this state when there is a competing service that wins the election against our service. 1152 // We only leave the state when there is no longer a competing prefix. 1153 static state_machine_state_t 1154 service_publisher_action_not_publishing(state_machine_header_t *state_header, state_machine_event_t *event) 1155 { 1156 STATE_MACHINE_HEADER_TO_PUBLISHER(state_header); 1157 BR_STATE_ANNOUNCE(publisher, event); 1158 1159 if (event == NULL) { 1160 if (publisher->published_unicast_service != NULL) { 1161 service_publisher_service_unpublish(publisher, unicast_service, true); 1162 } 1163 return service_publisher_state_invalid; 1164 } 1165 1166 // We do the same thing here for any event we get, because we're just waiting for conditions to be right. 1167 if (service_publisher_can_publish(publisher)) { 1168 publisher->startup_delay_range = SERVICE_PUBLISHER_LOST_WAIT; 1169 return service_publisher_state_startup; 1170 } 1171 return service_publisher_state_invalid; 1172 } 1173 1174 static void 1175 service_publisher_listener_cancel_callback(comm_t *UNUSED listener, void *context) 1176 { 1177 srp_server_t *server_state = context; 1178 service_publisher_t *publisher = server_state->service_publisher; 1179 if (publisher != NULL) { 1180 state_machine_event_t *event = state_machine_event_create(state_machine_event_type_listener_canceled, NULL); 1181 if (event == NULL) { 1182 ERROR("unable to allocate event to deliver"); 1183 return; 1184 } 1185 state_machine_event_deliver(&publisher->state_header, event); 1186 RELEASE_HERE(event, state_machine_event); 1187 } 1188 } 1189 1190 static void 1191 service_publisher_listener_cancel(service_publisher_t *publisher) 1192 { 1193 if (publisher->srp_listener != NULL) { 1194 ioloop_listener_cancel(publisher->srp_listener); 1195 ioloop_comm_release(publisher->srp_listener); 1196 publisher->srp_listener = NULL; 1197 } 1198 publisher->have_srp_listener = false; 1199 service_publisher_unadvertise_all(publisher); 1200 } 1201 1202 static void 1203 service_publisher_listener_ready(void *context, uint16_t port) 1204 { 1205 srp_server_t *server_state = context; 1206 service_publisher_t *publisher = server_state->service_publisher; 1207 if (publisher != NULL) { 1208 state_machine_event_t *event = state_machine_event_create(state_machine_event_type_listener_ready, NULL); 1209 if (event == NULL) { 1210 ERROR("unable to allocate event to deliver"); 1211 return; 1212 } 1213 publisher->have_srp_listener = true; 1214 publisher->srp_listener_port = port; 1215 state_machine_event_deliver(&publisher->state_header, event); 1216 RELEASE_HERE(event, state_machine_event); 1217 } 1218 } 1219 1220 static void 1221 service_publisher_listener_start(service_publisher_t *publisher) 1222 { 1223 if (publisher->srp_listener) { 1224 FAULT("listener still present"); 1225 service_publisher_listener_cancel(publisher); 1226 } 1227 publisher->srp_listener = srp_proxy_listen(NULL, 0, publisher->thread_interface_name, service_publisher_listener_ready, 1228 service_publisher_listener_cancel_callback, NULL, 1229 NULL, publisher->server_state); 1230 if (publisher->srp_listener == NULL) { 1231 ERROR("failed to setup SRP listener"); 1232 } 1233 service_publisher_re_advertise_matching(publisher); 1234 } 1235 1236 // We go to this state when we have decided to publish, but perhaps do not currently have an SRP listener 1237 // running. 1238 static state_machine_state_t 1239 service_publisher_action_start_listeners(state_machine_header_t *state_header, state_machine_event_t *event) 1240 { 1241 STATE_MACHINE_HEADER_TO_PUBLISHER(state_header); 1242 BR_STATE_ANNOUNCE(publisher, event); 1243 1244 if (event == NULL) { 1245 if (publisher->have_srp_listener) { 1246 if (publisher->srp_listener != NULL) { 1247 return service_publisher_state_publishing; 1248 } 1249 FAULT("have_srp_listener is true but there's no listener!"); 1250 publisher->have_srp_listener = false; 1251 } 1252 service_publisher_listener_start(publisher); 1253 return service_publisher_state_invalid; 1254 } 1255 1256 // If we get a competing service while we're waiting for the listener to start, cancel the listener. 1257 // We do the same thing here for any event we get, because we're just waiting for conditions to be right. 1258 if (!service_publisher_can_publish(publisher)) { 1259 service_publisher_listener_cancel(publisher); 1260 return service_publisher_state_not_publishing; 1261 } 1262 1263 // If the listener is ready, we can publish. 1264 if (event->type == state_machine_event_type_listener_ready) { 1265 return service_publisher_state_publishing; 1266 } 1267 1268 return service_publisher_state_invalid; 1269 } 1270 1271 static state_machine_state_t 1272 service_publisher_published_services_seen(service_publisher_t *publisher) 1273 { 1274 return ((publisher->published_unicast_service == NULL || publisher->have_unicast_in_net_data) && 1275 (publisher->published_anycast_service == NULL || publisher->have_anycast_in_net_data)); 1276 } 1277 1278 static bool 1279 service_publisher_wanted_service_missing(service_publisher_t *publisher) 1280 { 1281 srp_server_t *server_state = publisher->server_state; 1282 1283 // If we get here, the named service instance is not represented in the current set of services 1284 // about which we have information. 1285 #if STUB_ROUTER 1286 if (server_state->stub_router_enabled) { 1287 return true; // always publish when stub router 1288 } 1289 #endif 1290 if (server_state->srp_service_needed) { 1291 INFO("srp_service_needed == true -> true"); 1292 return true; // srp service unconditionally requested 1293 } 1294 1295 for (wanted_service_t *service = server_state->wanted_services; service != NULL; service = service->next) { 1296 for (adv_host_t *host = server_state->hosts; host != NULL; host = host->next) { 1297 if (host->instances != NULL) { 1298 for (int i = 0; i < host->instances->num; i++) { 1299 adv_instance_t *instance = host->instances->vec[i]; 1300 if (instance != NULL) { 1301 if (!strcasecmp(instance->instance_name, service->name) && 1302 !adv_ctl_service_types_compare(service->service_type, instance->service_type)) 1303 { 1304 if (host->addresses != NULL) { 1305 for (int j = 0; j < host->addresses->num; j++) { 1306 adv_record_t *address = host->addresses->vec[j]; 1307 if (address != NULL) { 1308 if (address->rdlen == 16 && 1309 !in6prefix_compare((struct in6_addr *)address->rdata, 1310 &publisher->thread_mesh_local_address, 8)) 1311 { 1312 goto instance_found; 1313 } 1314 } 1315 } 1316 INFO("srp service " PRI_S_SRP "." PRI_S_SRP " present as " PRI_S_SRP 1317 " but has no address on local mesh -> true", 1318 service->name, service->service_type, instance->instance_name); 1319 return true; // There is no valid address for this instance in the cache. 1320 } 1321 INFO("srp service " PRI_S_SRP "." PRI_S_SRP " present but no addresses -> true", 1322 service->name, service->service_type); 1323 return true; // We didn't find the named instance in the database 1324 } 1325 } 1326 } 1327 } 1328 } 1329 INFO("service " PRI_S_SRP "." PRI_S_SRP " host not present -> true", service->name, service->service_type); 1330 return true; 1331 instance_found: 1332 INFO("service " PRI_S_SRP "." PRI_S_SRP " is present", service->name, service->service_type); 1333 } 1334 INFO("all needed services present -> false"); 1335 return false; // There weren't any named instances for which we don't have a usable registration. 1336 } 1337 1338 // We enter this state when we have an SRP listener and no competing unicast services. On entry, we publish our unicast service. 1339 // If a competing service shows up that wins, we stop publishing and cancel the listener. Otherwise we remain in this state. 1340 static state_machine_state_t 1341 service_publisher_action_publishing(state_machine_header_t *state_header, state_machine_event_t *event) 1342 { 1343 STATE_MACHINE_HEADER_TO_PUBLISHER(state_header); 1344 BR_STATE_ANNOUNCE(publisher, event); 1345 1346 if (event == NULL || event->type == state_machine_event_type_timeout || 1347 event->type == state_machine_event_type_srp_needed) 1348 { 1349 if (publisher->published_unicast_service != NULL) { 1350 // We shouldn't see a published service on state entry. 1351 if (event == NULL) { 1352 ERROR("unicast service still published!"); 1353 } 1354 // Only actually enqueue a delete if we aren't retrying. 1355 service_publisher_service_unpublish(publisher, unicast_service, event == NULL); 1356 } 1357 1358 // On non-BR devices, don't actually publish the service until we get a signal that it's needed. 1359 if (!publisher->server_state->srp_on_demand || service_publisher_wanted_service_missing(publisher)) { 1360 uint8_t port[] = { publisher->srp_listener_port >> 8, publisher->srp_listener_port & 255 }; 1361 thread_service_t *service = thread_service_unicast_create(publisher->server_state->rloc16, 1362 (uint8_t *)&publisher->thread_mesh_local_address, 1363 port, 0); 1364 service_publisher_service_publish(publisher, service); 1365 thread_service_release(service); // service_publisher_publish retains the references it keeps. 1366 1367 // Set up a retransmit timer in case the service publication fails. 1368 if (event == NULL) { 1369 publisher->retry_interval = 5; // First retry after five seconds 1370 } else { 1371 // Maybe the service tracker is wedged, so restart it 1372 service_tracker_start(publisher->server_state->service_tracker); 1373 1374 // Exponential backoff. 1375 if (publisher->retry_interval < 3600) { 1376 publisher->retry_interval *= 2; 1377 } 1378 } 1379 service_publisher_start_wait(publisher, (publisher->retry_interval * MSEC_PER_SEC + 1380 srp_random32() % (publisher->retry_interval * MSEC_PER_SEC) / 2)); 1381 } 1382 1383 return service_publisher_state_invalid; 1384 } 1385 1386 // If the listener got canceled for some reason, restart it. 1387 if (event->type == state_machine_event_type_listener_canceled) { 1388 service_publisher_service_unpublish(publisher, unicast_service, true); 1389 publisher->startup_delay_range = SERVICE_PUBLISHER_LISTENER_RESTART_WAIT; 1390 return service_publisher_state_startup; 1391 } 1392 1393 // Any other event triggers a re-evaluation. 1394 if (event->type == state_machine_event_type_ml_eid_changed) { 1395 service_publisher_listener_cancel(publisher); 1396 service_publisher_service_unpublish(publisher, unicast_service, true); 1397 return service_publisher_state_startup; 1398 } 1399 1400 if (!service_publisher_can_publish(publisher)) { 1401 service_publisher_listener_cancel(publisher); 1402 service_publisher_service_unpublish(publisher, unicast_service, true); 1403 return service_publisher_state_not_publishing; 1404 } 1405 1406 // If we haven't yet seen all the services we are publishing in the network data, check to see if it showed up. 1407 if (event->type == state_machine_event_type_service_list_changed && 1408 !service_publisher_published_services_seen(publisher)) 1409 { 1410 publisher->have_unicast_in_net_data = false; 1411 publisher->have_anycast_in_net_data = false; 1412 for (thread_service_t *service = service_tracker_services_get(publisher->server_state->service_tracker); 1413 service != NULL; service = service->next) 1414 { 1415 if (service->service_type == unicast_service && service->ncp && 1416 publisher->published_unicast_service != NULL && 1417 !in6addr_compare(&service->u.unicast.address, &publisher->published_unicast_service->u.unicast.address) && 1418 !memcmp(service->u.unicast.port, publisher->published_unicast_service->u.unicast.port, 2)) 1419 { 1420 publisher->have_unicast_in_net_data = true; 1421 } 1422 else if (service->service_type == anycast_service && service->ncp && 1423 publisher->server_state->have_rloc16 && service->rloc16 == publisher->server_state->rloc16 && 1424 publisher->published_anycast_service != NULL && 1425 service->u.anycast.sequence_number == publisher->published_anycast_service->u.anycast.sequence_number) 1426 { 1427 publisher->have_anycast_in_net_data = true; 1428 } 1429 } 1430 1431 // If all of the services we are publishing are showing up in NCP, we can cancel the timer and go to the publishing state. 1432 if (service_publisher_published_services_seen(publisher)) { 1433 ioloop_cancel_wake_event(publisher->wakeup_timer); 1434 return service_publisher_state_invalid; 1435 } 1436 } 1437 return service_publisher_state_invalid; 1438 } 1439 1440 void 1441 service_publisher_cancel(service_publisher_t *publisher) 1442 { 1443 ioloop_cancel_wake_event(publisher->wakeup_timer); 1444 service_publisher_listener_cancel(publisher); 1445 service_tracker_callback_cancel(publisher->server_state->service_tracker, publisher); 1446 thread_tracker_callback_cancel(publisher->server_state->thread_tracker, publisher); 1447 node_type_tracker_callback_cancel(publisher->server_state->node_type_tracker, publisher); 1448 if (publisher->active_data_set_connection != NULL) { 1449 cti_events_discontinue(publisher->active_data_set_connection); 1450 publisher->active_data_set_connection = NULL; 1451 RELEASE_HERE(publisher, service_publisher); 1452 } 1453 if (publisher->wed_tracker_connection != NULL) { 1454 cti_events_discontinue(publisher->wed_tracker_connection); 1455 publisher->wed_tracker_connection = NULL; 1456 RELEASE_HERE(publisher, service_publisher); 1457 } 1458 if (publisher->neighbor_tracker_connection != NULL) { 1459 cti_events_discontinue(publisher->neighbor_tracker_connection); 1460 publisher->neighbor_tracker_connection = NULL; 1461 RELEASE_HERE(publisher, service_publisher); 1462 } 1463 state_machine_cancel(&publisher->state_header); 1464 } 1465 1466 service_publisher_t * 1467 service_publisher_create(srp_server_t *server_state) 1468 { 1469 service_publisher_t *ret = NULL, *publisher = calloc(1, sizeof(*publisher)); 1470 if (publisher == NULL) { 1471 return publisher; 1472 } 1473 RETAIN_HERE(publisher, service_publisher); 1474 publisher->wakeup_timer = ioloop_wakeup_create(); 1475 if (publisher->wakeup_timer == NULL) { 1476 ERROR("wakeup timer alloc failed"); 1477 goto out; 1478 } 1479 1480 char server_id_buf[100]; 1481 snprintf(server_id_buf, sizeof(server_id_buf), "[SP%lld]", ++service_publisher_serial_number); 1482 publisher->id = strdup(server_id_buf); 1483 if (publisher->id == NULL) { 1484 ERROR("no memory for server ID"); 1485 goto out; 1486 } 1487 1488 if (!state_machine_header_setup(&publisher->state_header, 1489 publisher, publisher->id, 1490 state_machine_type_service_publisher, 1491 service_publisher_states, 1492 SERVICE_PUBLISHER_NUM_STATES)) { 1493 ERROR("header setup failed"); 1494 goto out; 1495 } 1496 1497 publisher->server_state = server_state; 1498 if (!service_tracker_callback_add(server_state->service_tracker, service_publisher_service_tracker_callback, 1499 service_publisher_context_release, publisher)) 1500 { 1501 goto out; 1502 } 1503 RETAIN_HERE(publisher, service_publisher); // for service tracker 1504 1505 if (!thread_tracker_callback_add(server_state->thread_tracker, service_publisher_thread_tracker_callback, 1506 service_publisher_context_release, publisher)) 1507 { 1508 goto out; 1509 } 1510 RETAIN_HERE(publisher, service_publisher); // for thread network state tracker 1511 1512 if (!node_type_tracker_callback_add(server_state->node_type_tracker, service_publisher_node_type_tracker_callback, 1513 service_publisher_context_release, publisher)) 1514 { 1515 goto out; 1516 } 1517 RETAIN_HERE(publisher, service_publisher); // for thread network state tracker 1518 1519 // Set the first_time flag so that we'll know to remove any locally-published on-mesh prefixes. 1520 publisher->first_time = true; 1521 publisher->startup_delay_range = SERVICE_PUBLISHER_START_WAIT; 1522 ret = publisher; 1523 publisher = NULL; 1524 out: 1525 if (publisher != NULL) { 1526 RELEASE_HERE(publisher, service_publisher); 1527 } 1528 return ret; 1529 } 1530 1531 static void 1532 service_publisher_get_mesh_local_address_callback(void *context, const char *address_string, cti_status_t status) 1533 { 1534 service_publisher_t *publisher = context; 1535 1536 if (status == kCTIStatus_Disconnected || status == kCTIStatus_DaemonNotRunning) { 1537 INFO("disconnected"); 1538 if (publisher->reconnect_callback != NULL) { 1539 publisher->reconnect_callback(publisher->server_state); 1540 } 1541 goto fail; 1542 } 1543 1544 INFO(PUB_S_SRP " %d", address_string != NULL ? address_string : "<null>", status); 1545 if (status != kCTIStatus_NoError || address_string == NULL) { 1546 goto fail; 1547 } 1548 1549 struct in6_addr new_mesh_local_address; 1550 if (!inet_pton(AF_INET6, address_string, &new_mesh_local_address)) { 1551 ERROR("address syntax incorrect: " PRI_S_SRP, address_string); 1552 goto fail; 1553 } 1554 1555 if (publisher->have_ml_eid && !in6addr_compare(&new_mesh_local_address, &publisher->thread_mesh_local_address)) { 1556 INFO("address didn't change"); 1557 return; 1558 } 1559 publisher->thread_mesh_local_address = new_mesh_local_address; 1560 publisher->have_ml_eid = true; 1561 1562 for (thread_service_t *service = service_tracker_services_get(publisher->server_state->service_tracker); 1563 service != NULL; service = service->next) 1564 { 1565 if (service->ignore) { 1566 continue; 1567 } 1568 if (service->service_type == unicast_service) { 1569 if (publisher->published_unicast_service == NULL) { 1570 if (service->rloc16 == publisher->server_state->rloc16 || 1571 (publisher->have_ml_eid && 1572 !in6addr_compare(&service->u.unicast.address, &publisher->thread_mesh_local_address))) 1573 { 1574 thread_service_note(publisher->id, service, 1575 "is on our ml-eid or rloc16 but we aren't publishing it, so it's stale."); 1576 service_publisher_unpublish_stale_service(publisher, service); 1577 continue; 1578 } 1579 } 1580 } 1581 } 1582 1583 state_machine_event_t *event = state_machine_event_create(state_machine_event_type_ml_eid_changed, NULL); 1584 if (event == NULL) { 1585 ERROR("unable to allocate event to deliver"); 1586 return; 1587 } 1588 state_machine_event_deliver(&publisher->state_header, event); 1589 RELEASE_HERE(event, state_machine_event); 1590 RELEASE_HERE(publisher, service_publisher); // callback held a reference. 1591 return; 1592 fail: 1593 RELEASE_HERE(publisher, service_publisher); // callback held a reference. 1594 publisher->have_ml_eid = false; 1595 return; 1596 } 1597 1598 static void 1599 service_publisher_active_data_set_changed_callback(void *context, cti_status_t status) 1600 { 1601 service_publisher_t *publisher = context; 1602 1603 if (status != kCTIStatus_NoError) { 1604 ERROR("error %d", status); 1605 RELEASE_HERE(publisher, service_publisher); // no more callbacks 1606 cti_events_discontinue(publisher->active_data_set_connection); 1607 publisher->active_data_set_connection = NULL; 1608 return; 1609 } 1610 1611 status = cti_get_mesh_local_address(publisher->server_state, publisher, 1612 service_publisher_get_mesh_local_address_callback, NULL); 1613 if (status != kCTIStatus_NoError) { 1614 ERROR("cti_get_mesh_local_address failed with status %d", status); 1615 } else { 1616 RETAIN_HERE(publisher, service_publisher); // for mesh-local callback 1617 } 1618 } 1619 1620 static void 1621 service_publisher_tunnel_name_callback(void *context, const char *name, cti_status_t status) 1622 { 1623 service_publisher_t *publisher = context; 1624 if (status == kCTIStatus_Disconnected || status == kCTIStatus_DaemonNotRunning) { 1625 INFO("disconnected"); 1626 goto out; 1627 } 1628 1629 if (status != kCTIStatus_NoError) { 1630 INFO(PUB_S_SRP " %d", name != NULL ? name : "<null>", status); 1631 goto out; 1632 } 1633 publisher->have_thread_interface_name = true; 1634 1635 // Get rid of the old interface name if it's changed. 1636 bool changed = true; 1637 if (publisher->thread_interface_name != NULL) { 1638 if (!strcmp(name, publisher->thread_interface_name)) { 1639 changed = false; 1640 } else { 1641 free(publisher->thread_interface_name); 1642 publisher->thread_interface_name = NULL; 1643 } 1644 } 1645 1646 // Store the new interface name if it's changed. 1647 if (changed) { 1648 publisher->thread_interface_name = strdup(name); 1649 1650 INFO("thread interface at " PUB_S_SRP, name); 1651 } 1652 1653 if (publisher->thread_interface_name == NULL) { 1654 ERROR("No memory to save thread interface name " PUB_S_SRP, name); 1655 } 1656 1657 state_machine_event_t *event = state_machine_event_create(state_machine_event_type_thread_interface_changed, NULL); 1658 if (event == NULL) { 1659 ERROR("unable to allocate event to deliver"); 1660 goto out; 1661 } 1662 state_machine_event_deliver(&publisher->state_header, event); 1663 RELEASE_HERE(event, state_machine_event); 1664 out: 1665 RELEASE_HERE(publisher, service_publisher); // callback held a reference. 1666 } 1667 1668 static void 1669 service_publisher_wed_callback(void *context, const char *ext_address, const char *ml_eid, bool added, int status) 1670 { 1671 service_publisher_t *publisher = context; 1672 if (status == kCTIStatus_Disconnected || status == kCTIStatus_DaemonNotRunning) { 1673 INFO("disconnected"); 1674 goto out; 1675 } 1676 1677 const char *none = "<none>"; 1678 const char *ea = none; 1679 if (ext_address != NULL) { 1680 ea = ext_address; 1681 } 1682 const char *mle = none; 1683 if (ml_eid != NULL) { 1684 int ret = inet_pton(AF_INET6, ml_eid, &publisher->wed_ml_eid); 1685 if (ret) { 1686 mle = ml_eid; 1687 } 1688 } 1689 1690 INFO("ext_address: " PRI_S_SRP " ml_eid: " PRI_S_SRP PUB_S_SRP " %d", ea, mle, added ? " added" : " removed", status); 1691 if (status != kCTIStatus_NoError) { 1692 goto out; 1693 } 1694 1695 if (publisher->wed_ext_address_string != NULL) { 1696 free(publisher->wed_ext_address_string); 1697 publisher->wed_ext_address_string = NULL; 1698 } 1699 1700 if (publisher->wed_ml_eid_string != NULL) { 1701 free(publisher->wed_ml_eid_string); 1702 publisher->wed_ml_eid_string = NULL; 1703 } 1704 1705 // API guarantees addresses are non-NULL if added is true. 1706 if (added) { 1707 if (ea != none) { 1708 publisher->wed_ext_address_string = strdup(ea); 1709 if (publisher->wed_ext_address_string == NULL) { 1710 ERROR("no memory for wed_ext_address string!"); 1711 } 1712 } 1713 if (mle != none) { 1714 publisher->wed_ml_eid_string = strdup(mle); 1715 if (publisher->wed_ml_eid_string == NULL) { 1716 ERROR("no memory for wed_ml_eid string!"); 1717 memset(&publisher->wed_ml_eid, 0, sizeof(publisher->wed_ml_eid)); 1718 } 1719 } else { 1720 memset(&publisher->wed_ml_eid, 0, sizeof(publisher->wed_ml_eid)); 1721 } 1722 } 1723 state_machine_event_t *event = state_machine_event_create(state_machine_event_type_wed_ml_eid_changed, NULL); 1724 if (event == NULL) { 1725 ERROR("unable to allocate event to deliver"); 1726 goto out; 1727 } 1728 state_machine_event_deliver(&publisher->state_header, event); 1729 RELEASE_HERE(event, state_machine_event); 1730 out: 1731 ; 1732 } 1733 1734 static void 1735 service_publisher_neighbor_callback(void *context, const char *ml_eid, cti_status_t status) 1736 { 1737 service_publisher_t *publisher = context; 1738 if (status == kCTIStatus_Disconnected || status == kCTIStatus_DaemonNotRunning) { 1739 INFO("disconnected"); 1740 goto out; 1741 } 1742 1743 const char *none = "<none>"; 1744 const char *mle = none; 1745 if (ml_eid != NULL) { 1746 if (!strcmp(ml_eid, "none")) { 1747 mle = ml_eid; 1748 memset(&publisher->neighbor_ml_eid, 0, sizeof(publisher->neighbor_ml_eid)); 1749 } else { 1750 int ret = inet_pton(AF_INET6, ml_eid, &publisher->neighbor_ml_eid); 1751 if (ret) { 1752 mle = ml_eid; 1753 } 1754 } 1755 } 1756 1757 INFO("ml_eid: " PRI_S_SRP ", status %d", mle, status); 1758 if (status != kCTIStatus_NoError) { 1759 goto out; 1760 } 1761 1762 1763 if (publisher->neighbor_ml_eid_string != NULL) { 1764 free(publisher->neighbor_ml_eid_string); 1765 publisher->neighbor_ml_eid_string = NULL; 1766 } 1767 1768 if (mle != none) { 1769 publisher->neighbor_ml_eid_string = strdup(mle); 1770 if (publisher->neighbor_ml_eid_string == NULL) { 1771 ERROR("no memory for neighbor_ml_eid string!"); 1772 memset(&publisher->neighbor_ml_eid, 0, sizeof(publisher->neighbor_ml_eid)); 1773 } 1774 } else { 1775 memset(&publisher->neighbor_ml_eid, 0, sizeof(publisher->neighbor_ml_eid)); 1776 } 1777 state_machine_event_t *event = state_machine_event_create(state_machine_event_type_neighbor_ml_eid_changed, NULL); 1778 if (event == NULL) { 1779 ERROR("unable to allocate event to deliver"); 1780 goto out; 1781 } 1782 state_machine_event_deliver(&publisher->state_header, event); 1783 RELEASE_HERE(event, state_machine_event); 1784 1785 if (publisher->sed_timeout != NULL) { 1786 ioloop_cancel_wake_event(publisher->sed_timeout); 1787 ioloop_wakeup_release(publisher->sed_timeout); 1788 publisher->sed_timeout = NULL; 1789 } 1790 out: 1791 ; 1792 } 1793 1794 void 1795 service_publisher_start(service_publisher_t *publisher) 1796 { 1797 cti_status_t status = cti_track_active_data_set(publisher->server_state, &publisher->active_data_set_connection, 1798 publisher, service_publisher_active_data_set_changed_callback, 1799 NULL); 1800 if (status != kCTIStatus_NoError) { 1801 ERROR("unable to start tracking active dataset: %d", status); 1802 } else { 1803 RETAIN_HERE(publisher, service_publisher); // for active dataset callback 1804 } 1805 1806 status = cti_get_tunnel_name(publisher->server_state, publisher, service_publisher_tunnel_name_callback, NULL); 1807 if (status != kCTIStatus_NoError) { 1808 ERROR("unable to get tunnel name: %d", status); 1809 } else { 1810 RETAIN_HERE(publisher, service_publisher); // for tunnel name callback 1811 } 1812 1813 1814 status = cti_track_wed_status(publisher->server_state, &publisher->wed_tracker_connection, 1815 publisher, service_publisher_wed_callback, NULL); 1816 if (status != kCTIStatus_NoError) { 1817 FAULT("can't track WED status: %d", status); 1818 } else { 1819 RETAIN_HERE(publisher, service_publisher); 1820 } 1821 1822 status = cti_track_neighbor_ml_eid(publisher->server_state, &publisher->neighbor_tracker_connection, 1823 publisher, service_publisher_neighbor_callback, NULL); 1824 if (status != kCTIStatus_NoError) { 1825 FAULT("can't track WED status: %d", status); 1826 } else { 1827 RETAIN_HERE(publisher, service_publisher); 1828 } 1829 1830 service_publisher_active_data_set_changed_callback(publisher, kCTIStatus_NoError); // Get the initial state. 1831 state_machine_next_state(&publisher->state_header, service_publisher_state_startup); 1832 } 1833 1834 bool 1835 service_publisher_get_ml_eid(service_publisher_t *publisher, struct in6_addr *ml_eid) 1836 { 1837 if (publisher != NULL && publisher->have_ml_eid) { 1838 in6addr_copy(ml_eid, &publisher->thread_mesh_local_address); 1839 return true; 1840 } 1841 return false; 1842 } 1843 1844 // Local Variables: 1845 // mode: C 1846 // tab-width: 4 1847 // c-file-style: "bsd" 1848 // c-basic-offset: 4 1849 // fill-column: 120 1850 // indent-tabs-mode: nil 1851 // End: 1852