Home | History | Annotate | Line # | Download | only in ServiceRegistration
srp-mdns-proxy.c revision 1.1
      1 /* srp-mdns-proxy.c
      2  *
      3  * Copyright (c) 2019-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 the SRP Advertising Proxy, which is an SRP Server
     18  * that offers registered addresses using mDNS.
     19  */
     20 
     21 #include <stdlib.h>
     22 #include <string.h>
     23 #include <stdio.h>
     24 #include <time.h>
     25 #include <unistd.h>
     26 #include <pwd.h>
     27 #include <errno.h>
     28 #include <sys/socket.h>
     29 #include <netinet/in.h>
     30 #include <arpa/inet.h>
     31 #include <fcntl.h>
     32 #include <time.h>
     33 #include <dns_sd.h>
     34 #include <net/if.h>
     35 #include <inttypes.h>
     36 #include <sys/resource.h>
     37 #include <ctype.h>
     38 #include <mdns/pf.h>
     39 
     40 #include "srp.h"
     41 #include "dns-msg.h"
     42 #include "srp-crypto.h"
     43 #include "ioloop.h"
     44 #include "srp-gw.h"
     45 #include "srp-proxy.h"
     46 #include "srp-mdns-proxy.h"
     47 #include "dnssd-proxy.h"
     48 #include "config-parse.h"
     49 #include "cti-services.h"
     50 #include "route.h"
     51 #include "adv-ctl-server.h"
     52 #include "srp-replication.h"
     53 #include "ioloop-common.h"
     54 #include "thread-device.h"
     55 #include "nat64-macos.h"
     56 #include "srp-dnssd.h"
     57 #include "ifpermit.h"
     58 #include "state-machine.h"
     59 #include "thread-service.h"
     60 #include "omr-watcher.h"
     61 #include "omr-publisher.h"
     62 #include "service-publisher.h"
     63 
     64 
     65 #if SRP_FEATURE_NAT64
     66 #include "nat64.h"
     67 #endif
     68 
     69 
     70 #ifdef SRP_TEST_SERVER
     71 #include "srp-test-runner.h"
     72 #endif
     73 
     74 #define ADDRESS_RECORD_TTL  4500
     75 #define OTHER_RECORD_TTL    4500
     76 
     77 #define _DNSSD_API_AVAILABLE_FALL_2024 (1)
     78 
     79 static const char local_suffix_ld[] = ".local";
     80 static const char *local_suffix = &local_suffix_ld[1];
     81 
     82 os_log_t global_os_log;
     83 void *dns_service_op_not_to_be_freed;
     84 srp_server_t *srp_servers;
     85 const uint8_t thread_anycast_preamble[7] = { 0, 0, 0, 0xff, 0xfe, 0, 0xfc };
     86 const uint8_t thread_rloc_preamble[6] = { 0, 0, 0, 0xff, 0xfe, 0 };
     87 
     88 extern int num_push_sessions;
     89 extern int dp_num_outstanding_queries;
     90 extern int num_push_sessions_dropped_for_load;
     91 extern int num_queries_dropped_for_load;
     92 
     93 //======================================================================================================================
     94 // MARK: - Forward references
     95 
     96 static bool register_host_record(adv_host_t *host, adv_record_t *record, const bool skipping);
     97 static void register_host_record_completion(DNSServiceRef sdref, DNSRecordRef rref,
     98                                             DNSServiceFlags flags, DNSServiceErrorType error_code, void *context);
     99 static bool register_instance(adv_instance_t *instance);
    100 static void register_instance_completion(DNSServiceRef sdref, DNSServiceFlags flags, DNSServiceErrorType error_code,
    101                                          const char *name, const char *regtype, const char *domain, void *context);
    102 static void update_from_host(adv_host_t *host);
    103 static void start_host_update(adv_host_t *host);
    104 static void prepare_update(adv_host_t *host, client_update_t *client_update);
    105 static void delete_host(void *context);
    106 static void lease_callback(void *context);
    107 static void adv_host_finalize(adv_host_t *host);
    108 static void adv_record_finalize(adv_record_t *record);
    109 static void adv_update_finalize(adv_update_t *update);
    110 
    111 //======================================================================================================================
    112 // MARK: - Functions
    113 
    114 void
    115 srp_mdns_shared_record_remove(srp_server_t *server_state, adv_record_t *record)
    116 {
    117     RETAIN_HERE(record, adv_record);
    118     if (record->rref != NULL) {
    119         if (record->shared_txn != 0 && record->shared_txn == (intptr_t)server_state->shared_registration_txn) {
    120             INFO("removing rref %p", record->rref);
    121             int err = dns_service_remove_record(server_state,
    122                                                 server_state->shared_registration_txn->sdref, record->rref, 0);
    123             // We can't release the record here if we got an error removing it, because if we get an error removing it,
    124             // it doesn't get removed from the list. This should never happen, but if it does, the record will leak.
    125             if (err == kDNSServiceErr_NoError) {
    126                 RELEASE_HERE(record, adv_record); // Release the DNSService callback's reference
    127             } else {
    128                 // At this point we should never see an error calling DNSServiceRemoveRecord, so if we do, call
    129                 // attention to it.
    130                 if (!record->update_pending) {
    131                     FAULT("DNSServiceRemoveRecord(%p, %p, %p, 0) returned %d",
    132                           server_state->shared_registration_txn->sdref, record, record->rref, err);
    133                 }
    134             }
    135         } else {
    136             INFO("didn't remove stale rref %p because %lx != %p",
    137                  record->rref, record->shared_txn, server_state->shared_registration_txn);
    138         }
    139         record->rref = NULL;
    140     }
    141     record->shared_txn = 0;
    142     RELEASE_HERE(record, adv_record);
    143 }
    144 
    145 
    146 static void
    147 adv_record_finalize(adv_record_t *record)
    148 {
    149     // We should not be able to get to the finalize function without having removed the rref, because the DNSService
    150     // callback always holds a reference to the record.
    151     if (record->update != NULL) {
    152         RELEASE_HERE(record->update, adv_update);
    153     }
    154     if (record->host != NULL) {
    155         RELEASE_HERE(record->host, adv_host);
    156     }
    157 
    158     free(record->rdata);
    159     free(record);
    160 }
    161 
    162 static void
    163 adv_instance_finalize(adv_instance_t *instance)
    164 {
    165     if (instance->txn != NULL) {
    166         ioloop_dnssd_txn_cancel_srp(instance->host->server_state, instance->txn);
    167         ioloop_dnssd_txn_release(instance->txn);
    168     }
    169     if (instance->txt_data != NULL) {
    170         free(instance->txt_data);
    171     }
    172     if (instance->instance_name != NULL) {
    173         free(instance->instance_name);
    174     }
    175     if (instance->service_type != NULL) {
    176         free(instance->service_type);
    177     }
    178     if (instance->host != NULL) {
    179         RELEASE_HERE(instance->host, adv_host);
    180         instance->host = NULL;
    181     }
    182     if (instance->message != NULL) {
    183         ioloop_message_release(instance->message);
    184         instance->message = NULL;
    185     }
    186     if (instance->update != NULL) {
    187         RELEASE_HERE(instance->update, adv_update);
    188         instance->update = NULL;
    189     }
    190     if (instance->retry_wakeup != NULL) {
    191         ioloop_wakeup_release(instance->retry_wakeup);
    192         instance->retry_wakeup = NULL;
    193     }
    194     free(instance);
    195 }
    196 
    197 void
    198 adv_instance_context_release(void *NONNULL context)
    199 {
    200     adv_instance_t *instance = context;
    201     RELEASE_HERE(instance, adv_instance);
    202 }
    203 
    204 void
    205 adv_instance_retain_(adv_instance_t *instance, const char *file, int line)
    206 {
    207     RETAIN(instance, adv_instance);
    208 }
    209 
    210 void
    211 adv_instance_release_(adv_instance_t *instance, const char *file, int line)
    212 {
    213     RELEASE(instance, adv_instance);
    214 }
    215 
    216 void
    217 adv_record_retain_(adv_record_t *record, const char *file, int line)
    218 {
    219     RETAIN(record, adv_record);
    220 }
    221 
    222 void
    223 adv_record_release_(adv_record_t *record, const char *file, int line)
    224 {
    225     RELEASE(record, adv_record);
    226 }
    227 
    228 #define DECLARE_VEC_CREATE(type)                        \
    229 static type ## _vec_t *                                 \
    230 type ## _vec_create(int size)                           \
    231 {                                                       \
    232     type ## _vec_t *vec;                                \
    233                                                         \
    234     vec = calloc(1, sizeof(*vec));                      \
    235     if (vec != NULL) {                                  \
    236         if (size == 0) {                                \
    237             size = 1;                                   \
    238         }                                               \
    239         vec->vec = calloc(size, sizeof (*(vec->vec)));  \
    240         if (vec->vec == NULL) {                         \
    241             free(vec);                                  \
    242             vec = NULL;                                 \
    243         } else {                                        \
    244             RETAIN_HERE(vec, type##_vec);               \
    245         }                                               \
    246     }                                                   \
    247     return vec;                                         \
    248 }
    249 
    250 #define DECLARE_VEC_COPY(type)                          \
    251 static type ## _vec_t *                                 \
    252 type ## _vec_copy(type ## _vec_t *vec)                  \
    253 {                                                       \
    254     type ## _vec_t *new_vec;                            \
    255     int i;                                              \
    256                                                         \
    257     new_vec = type ## _vec_create(vec->num);            \
    258     if (new_vec != NULL) {                              \
    259         for (i = 0; i < vec->num; i++) {                \
    260             if (vec->vec[i] != NULL) {                  \
    261                 new_vec->vec[i] = vec->vec[i];          \
    262                 RETAIN_HERE(new_vec->vec[i], type);     \
    263             }                                           \
    264         }                                               \
    265         new_vec->num = vec->num;                        \
    266     }                                                   \
    267     return new_vec;                                     \
    268 }
    269 
    270 #define DECLARE_VEC_FINALIZE(type)                              \
    271 static void                                                     \
    272 type ## _vec_finalize(type ## _vec_t *vec)                      \
    273 {                                                               \
    274     int i;                                                      \
    275                                                                 \
    276     for (i = 0; i < vec->num; i++) {                            \
    277         if (vec->vec[i] != NULL) {                              \
    278             RELEASE_HERE(vec->vec[i], type);                    \
    279             vec->vec[i] = NULL;                                 \
    280         }                                                       \
    281     }                                                           \
    282     free(vec->vec);                                             \
    283     free(vec);                                                  \
    284 }
    285 
    286 DECLARE_VEC_CREATE(adv_instance);
    287 DECLARE_VEC_COPY(adv_instance);
    288 DECLARE_VEC_FINALIZE(adv_instance);
    289 
    290 DECLARE_VEC_CREATE(adv_record);
    291 DECLARE_VEC_COPY(adv_record);
    292 DECLARE_VEC_FINALIZE(adv_record);
    293 
    294 static void
    295 srp_dump_server_stats(srp_server_t *server_state, bool full, bool periodic)
    296 {
    297     // For testing, emit a count of how many hosts, services and address records there are
    298     int host_count = 0;
    299     int a_record_count = 0;
    300     int aaaa_record_count = 0;
    301     int instance_count = 0;
    302     int matter_host_count = 0;
    303     int hap_host_count = 0;
    304     int64_t now = ioloop_timenow();
    305     static int last_num_push_sessions;
    306     static int last_dp_num_outstanding_queries;
    307     static int last_num_push_sessions_dropped_for_load;
    308     static int last_num_queries_dropped_for_load;
    309 
    310     for (adv_host_t *hp = server_state->hosts; hp != NULL; hp = hp->next) {
    311         if (hp->removed) {
    312             continue;
    313         }
    314         host_count++;
    315         int expiry;
    316         if (hp->lease_expiry < now) {
    317             expiry = -1;
    318         } else {
    319             expiry = (int)((hp->lease_expiry - now) / 1000); // This should never be >MAXINT
    320         }
    321         if (full) {
    322             INFO("host " PRI_S_SRP " key_id %xu stable %" PRIx64 " lease %d key_lease %d expiry %d" PUB_S_SRP PUB_S_SRP,
    323                  hp->name, hp->key_id, hp->server_stable_id, hp->lease_interval, hp->key_lease, expiry,
    324                  hp->removed ? " removed" : "", hp->update_pending ? " update-pending" : "");
    325         }
    326         if (hp->addresses != NULL) {
    327             for (int i = 0; i < hp->addresses->num; i++) {
    328                 if (hp->addresses->vec[i] != NULL) {
    329                     adv_record_t *record = hp->addresses->vec[i];
    330                     if (record->rrtype == dns_rrtype_a) {
    331                         if (full) {
    332                             IPv4_ADDR_GEN_SRP(record->rdata, addr_buf);
    333                             INFO("  IN    A " PRI_IPv4_ADDR_SRP PRI_S_SRP, IPv4_ADDR_PARAM_SRP(record->rdata, addr_buf),
    334                                  record->shared_txn == (intptr_t)server_state->shared_registration_txn ? " live" : "");
    335                         }
    336                         a_record_count++;
    337                     } else if (record->rrtype == dns_rrtype_aaaa) {
    338                         if (full) {
    339                             IPv6_ADDR_GEN_SRP((const uint8_t *)record->rdata, addr_buf);
    340                             INFO("  IN AAAA " PRI_IPv6_ADDR_SRP PRI_S_SRP, IPv6_ADDR_PARAM_SRP(record->rdata, addr_buf),
    341                                  record->shared_txn == (intptr_t)server_state->shared_registration_txn ? " live" : "");
    342                         }
    343                         aaaa_record_count++;
    344                     }
    345                 }
    346             }
    347         }
    348         bool matter_instance_present = false, hap_instance_present = false;
    349         if (hp->instances != NULL) {
    350             for (int i = 0; i < hp->instances->num; i++) {
    351                 adv_instance_t *instance = hp->instances->vec[i];
    352                 if (instance != NULL) {
    353                     if (full) {
    354                         char txt_buf[DNS_DATA_SIZE];
    355                         if (instance->txt_data != NULL) {
    356                             dns_txt_data_print(txt_buf, DNS_DATA_SIZE, instance->txt_length, instance->txt_data);
    357                         } else {
    358                             txt_buf[0] = 0;
    359                         }
    360                         const char *status = "removed";
    361                         if (!instance->removed) {
    362                             if (instance->txn == NULL) {
    363                                 status = "unregistered";
    364                             } else if (instance->shared_txn != (intptr_t)server_state->shared_registration_txn) {
    365                                 status = "stale";
    366                             } else {
    367                                 status = "live";
    368                             }
    369                         }
    370                         INFO("  " PUB_S_SRP " instance " PRI_S_SRP " " PRI_S_SRP " %d (" PRI_S_SRP ")",
    371                              status, instance->instance_name, instance->service_type, instance->port, txt_buf);
    372                     }
    373                     if (!instance->removed) {
    374                         instance_count++;
    375                         if (instance->service_type != NULL) {
    376                             const char matter_prefix[] = "_matter";
    377                             const char hap_prefix[] = "_hap._udp";
    378                             if (!strncmp(instance->service_type, matter_prefix, sizeof(matter_prefix) - 1)) {
    379                                 matter_instance_present = true;
    380                             } else if (!strncmp(instance->service_type, hap_prefix, sizeof(hap_prefix) - 1)) {
    381                                 hap_instance_present = true;
    382                             }
    383                         }
    384                     }
    385                 }
    386             }
    387         }
    388         if (matter_instance_present) {
    389             matter_host_count++;
    390         } else if (hap_instance_present) { // If both, only count matter.
    391             hap_host_count++;
    392         }
    393     }
    394     INFO(PUB_S_SRP "%d hosts (%d matter, %d hap), %d instances, %d a records, %d aaaa records at %.6lf",
    395          periodic ? "" : "after update, ", host_count, matter_host_count, hap_host_count, instance_count, a_record_count,
    396          aaaa_record_count, srp_fractional_time());
    397 
    398 #if STUB_ROUTER
    399     route_state_t *route_state = server_state->route_state;
    400     if (route_state) {
    401         SEGMENTED_IPv6_ADDR_GEN_SRP(&route_state->srp_listener_ip_address, addr_buf);
    402         // do we have an SRP listener?
    403         if (route_state->srp_listener != NULL) {
    404             INFO("have SRP listener on " PRI_SEGMENTED_IPv6_ADDR_SRP "/%d",
    405                  SEGMENTED_IPv6_ADDR_PARAM_SRP(&route_state->srp_listener_ip_address, addr_buf),
    406                  route_state->srp_service_listen_port);
    407         } else {
    408             INFO("no SRP listener");
    409         }
    410 
    411         // are we publishing anycast services?
    412         INFO(PUB_S_SRP "advertising anycast service", route_state->advertising_srp_anycast_service ? "" : "not ");
    413 
    414         // are we publishing unicast service?
    415         if (route_state->advertising_srp_unicast_service) {
    416             INFO("advertising unicast service on " PRI_SEGMENTED_IPv6_ADDR_SRP "/%d",
    417                  SEGMENTED_IPv6_ADDR_PARAM_SRP(&route_state->srp_listener_ip_address, addr_buf),
    418                  route_state->srp_service_listen_port);
    419         } else {
    420             INFO("not advertising unicast service");
    421         }
    422 
    423         // what SRP replication peers do we see? and how many are we actively connected to?
    424         srpl_dump_connection_states(server_state);
    425 
    426         // are we publishing OMR prefix?
    427         if (route_state->omr_publisher != NULL &&
    428             omr_publisher_publishing_prefix(route_state->omr_publisher))
    429         {
    430             omr_prefix_t *prefix = omr_publisher_published_prefix_get(route_state->omr_publisher);
    431             SEGMENTED_IPv6_ADDR_GEN_SRP(prefix->prefix.s6_addr, prefix_buf);
    432             INFO("publishing " PUB_S_SRP " OMR prefix " PRI_SEGMENTED_IPv6_ADDR_SRP "/%d",
    433                  omr_publisher_publishing_dhcp(route_state->omr_publisher) ? "dhcp" : "ula",
    434                  SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix->prefix.s6_addr, prefix_buf),
    435                  prefix->prefix_length);
    436         } else {
    437             INFO("not publishing OMR prefix");
    438         }
    439 
    440         // what prefixes do we see on Thread?
    441         if (route_state->omr_watcher != NULL) {
    442             omr_prefix_t *thread_prefixes = omr_watcher_prefixes_get(route_state->omr_watcher);
    443             for (struct omr_prefix *prefix = thread_prefixes; prefix != NULL; prefix = prefix->next) {
    444                 SEGMENTED_IPv6_ADDR_GEN_SRP(prefix->prefix.s6_addr, prefix_buf);
    445                 INFO("OMR prefix " PRI_SEGMENTED_IPv6_ADDR_SRP "/%d seen on thread" PUB_S_SRP PUB_S_SRP
    446                      PUB_S_SRP, SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix->prefix.s6_addr, prefix_buf),
    447                      prefix->prefix_length, prefix->user ? " (user)" : "", prefix->ncp ? " (ncp)": "",
    448                      prefix->stable ? " (stable)" : "");
    449             }
    450         }
    451 
    452         // are we publishing infrastructure prefix?
    453         interface_t *interface;
    454         bool is_advertising = false;
    455         for (interface = route_state->interfaces; interface; interface = interface->next) {
    456             if (interface->our_prefix_advertised) {
    457                SEGMENTED_IPv6_ADDR_GEN_SRP(interface->ipv6_prefix.s6_addr, ipv6_prefix_buf);
    458                INFO("advertising infrastructure prefix " PRI_SEGMENTED_IPv6_ADDR_SRP " on " PUB_S_SRP,
    459                     SEGMENTED_IPv6_ADDR_PARAM_SRP(interface->ipv6_prefix.s6_addr, ipv6_prefix_buf),
    460                     interface->name);
    461                is_advertising = true;
    462             }
    463         }
    464         if (!is_advertising) {
    465             INFO("not advertising infrastructure prefix");
    466         }
    467     }
    468 #endif // STUB_ROUTER
    469 
    470     // how many DNS push queries added since last state dump?
    471     // how many DNS queries seen since last state dump?
    472     // how many DNS queries dropped for load?
    473     // how many DNS Push connections dropped for load?
    474     INFO("%d push sessions and %d queries added, %d push sessions and %d queries dropped for load",
    475          num_push_sessions - last_num_push_sessions,
    476          dp_num_outstanding_queries - last_dp_num_outstanding_queries,
    477          num_push_sessions_dropped_for_load - last_num_push_sessions_dropped_for_load,
    478          num_queries_dropped_for_load - last_num_queries_dropped_for_load);
    479     last_num_push_sessions = num_push_sessions;
    480     last_dp_num_outstanding_queries = dp_num_outstanding_queries;
    481     last_num_push_sessions_dropped_for_load = num_push_sessions_dropped_for_load;
    482     last_num_queries_dropped_for_load = num_queries_dropped_for_load;
    483 }
    484 
    485 // We call advertise_finished when a client request has finished, successfully or otherwise.
    486 #if SRP_FEATURE_REPLICATION
    487 static bool
    488 srp_replication_advertise_finished(adv_host_t *host, char *hostname, srp_server_t *server_state,
    489                                    srpl_connection_t *srpl_connection, comm_t *connection, int rcode, bool last)
    490 {
    491 	if (server_state->srp_replication_enabled) {
    492         INFO("hostname = " PRI_S_SRP "  host = %p  server_state = %p  srpl_connection = %p  connection = %p  rcode = "
    493              PUB_S_SRP, hostname, host, server_state, srpl_connection, connection, dns_rcode_name(rcode));
    494         if (connection == NULL) {
    495             // connection is the SRP client connection on which an update arrived. If it's null,
    496             // this is an SRP replication update, not an actual client we're communicating with.
    497             INFO("replication advertise finished: host " PRI_S_SRP ": rcode = " PUB_S_SRP,
    498                  hostname, dns_rcode_name(rcode));
    499             if (srpl_connection != NULL) {
    500                 if (last) {
    501                     srpl_advertise_finished_event_send(hostname, rcode, server_state);
    502 #ifdef SRP_TEST_SERVER
    503                     if (srpl_connection->srpl_advertise_finished_callback != NULL) {
    504                         srpl_connection->srpl_advertise_finished_callback(srpl_connection);
    505                     }
    506 #endif
    507                 }
    508 
    509                 if (host != NULL && host->srpl_connection != NULL) {
    510                     if (rcode == dns_rcode_noerror) {
    511                         host->update_server_id = host->srpl_connection->remote_partner_id;
    512                         host->server_stable_id = host->srpl_connection->stashed_host.server_stable_id;
    513                         INFO("replicated host " PRI_S_SRP " server stable ID %" PRIx64, hostname, host->server_stable_id);
    514                     }
    515 
    516                     // This is the safest place to clear this pointer--we do not want the srpl_connection pointer to not
    517                     // get reset because of some weird sequence of events, leaving this host unable to be further updated
    518                     // or worse.
    519                     srpl_connection_release(host->srpl_connection);
    520                     host->srpl_connection = NULL;
    521                 } else {
    522                     if (host != NULL) {
    523                         INFO("disconnected host " PRI_S_SRP " server stable ID %" PRIx64, hostname, host->server_stable_id);
    524                     }
    525                 }
    526             } else {
    527                 if (host != NULL) {
    528                     INFO("context-free host " PRI_S_SRP " server stable ID %" PRIx64, hostname, host->server_stable_id);
    529                 }
    530             }
    531             return true;
    532         }
    533 
    534         if (host != NULL) {
    535             if (rcode == dns_rcode_noerror) {
    536                 memcpy(&host->server_stable_id, &host->server_state->ula_prefix, sizeof(host->server_stable_id));
    537             }
    538             INFO("local host " PRI_S_SRP " server stable ID %" PRIx64, hostname, host->server_stable_id);
    539             srpl_srp_client_update_finished_event_send(host, rcode);
    540             host->update_server_id = 0;
    541         }
    542     } else
    543     {
    544         if (host != NULL && host->server_state != NULL) {
    545             memcpy(&host->server_stable_id, &host->server_state->ula_prefix, sizeof(host->server_stable_id));
    546             host->update_server_id = 0;
    547         }
    548     }
    549     return false;
    550 }
    551 #endif // SRP_FEATURE_REPLICATION
    552 
    553 static void
    554 srp_ml_eid_mapping_callback(void *context, cti_status_t status)
    555 {
    556     adv_record_t *arec = context;
    557     adv_host_t *host = arec->host;
    558     SEGMENTED_IPv6_ADDR_GEN_SRP(arec->rdata, omr_buf);
    559     if (status == kCTIStatus_NoError) {
    560         if (host == NULL) {
    561             INFO("mapping for address " PRI_SEGMENTED_IPv6_ADDR_SRP " was orphaned.",
    562                  SEGMENTED_IPv6_ADDR_PARAM_SRP(arec->rdata, omr_buf));
    563         } else {
    564             INFO("mapping for address " PRI_SEGMENTED_IPv6_ADDR_SRP " to host " PRI_S_SRP " succeeded",
    565                  SEGMENTED_IPv6_ADDR_PARAM_SRP(arec->rdata, omr_buf), host->name);
    566         }
    567     } else {
    568         if (host == NULL) {
    569             INFO("orphaned mapping for address " PRI_SEGMENTED_IPv6_ADDR_SRP " failed: %d",
    570                  SEGMENTED_IPv6_ADDR_PARAM_SRP(arec->rdata, omr_buf), status);
    571         } else {
    572             INFO("mapping for address " PRI_SEGMENTED_IPv6_ADDR_SRP " to host " PRI_S_SRP " failed: %d",
    573                  SEGMENTED_IPv6_ADDR_PARAM_SRP(arec->rdata, omr_buf), host->name, status);
    574         }
    575     }
    576     RELEASE_HERE(arec, adv_record);
    577 }
    578 
    579 // We call advertise_finished when a client request has finished, successfully or otherwise.
    580 static void
    581 advertise_finished(adv_host_t *host, char *hostname, srp_server_t *server_state, srpl_connection_t *srpl_connection,
    582                    comm_t *connection, message_t *message, int rcode, client_update_t *client, bool send_response,
    583                    bool last)
    584 {
    585     struct iovec iov;
    586     dns_wire_t response;
    587 
    588 #if SRP_FEATURE_REPLICATION
    589     if (srp_replication_advertise_finished(host, hostname, server_state, srpl_connection, connection, rcode, last)) {
    590         return;
    591     }
    592 #else
    593     (void)host;
    594     (void)server_state;
    595     (void)srpl_connection;
    596     (void)last;
    597 #endif // SRP_FEATURE_REPLICATION
    598     INFO("host " PRI_S_SRP ": rcode = " PUB_S_SRP ", lease = %d, key_lease = %d  connection = %p", hostname, dns_rcode_name(rcode),
    599          client ? client->host_lease : 0, client ? client->key_lease : 0, connection);
    600 
    601     // This can happen if we turn off replication in the middle of an update of a replicated host.
    602     if (connection == NULL) {
    603         return;
    604     }
    605     if (!send_response) {
    606         INFO("not sending response.");
    607         return;
    608     }
    609 
    610     memset(&response, 0, DNS_HEADER_SIZE);
    611     response.id = message->wire.id;
    612     response.bitfield = message->wire.bitfield;
    613     dns_rcode_set(&response, rcode);
    614     dns_qr_set(&response, dns_qr_response);
    615 
    616     iov.iov_base = &response;
    617     // If this was a successful update, send back the lease time, which will either
    618     // be what the client asked for, or a shorter lease, depending on what limit has
    619     // been set.
    620     if (client != NULL) {
    621         dns_towire_state_t towire;
    622         memset(&towire, 0, sizeof towire);
    623         towire.p = &response.data[0];               // We start storing RR data here.
    624         towire.lim = &response.data[DNS_DATA_SIZE]; // This is the limit to how much we can store.
    625         towire.message = &response;
    626         response.qdcount = 0;
    627         response.ancount = 0;
    628         response.nscount = 0;
    629         response.arcount = htons(1);
    630         dns_edns0_header_to_wire(&towire, DNS_MAX_UDP_PAYLOAD, 0, 0, 1);
    631         dns_rdlength_begin(&towire);
    632         dns_u16_to_wire(&towire, dns_opt_update_lease);  // OPTION-CODE
    633         dns_edns0_option_begin(&towire);                 // OPTION-LENGTH
    634         dns_u32_to_wire(&towire, client->host_lease);    // LEASE (e.g. 1 hour)
    635         dns_u32_to_wire(&towire, client->key_lease);     // KEY-LEASE (7 days)
    636         dns_edns0_option_end(&towire);                   // Now we know OPTION-LENGTH
    637         dns_rdlength_end(&towire);
    638         // It should not be possible for this to happen; if it does, the client
    639         // might not renew its lease in a timely manner.
    640         if (towire.error) {
    641             ERROR("unexpectedly failed to send EDNS0 lease option.");
    642             iov.iov_len = DNS_HEADER_SIZE;
    643         } else {
    644             iov.iov_len = towire.p - (uint8_t *)&response;
    645         }
    646     } else {
    647         iov.iov_len = DNS_HEADER_SIZE;
    648     }
    649     ioloop_send_message(connection, message, &iov, 1);
    650 }
    651 
    652 static void
    653 retry_callback(void *context)
    654 {
    655     adv_host_t *host = (adv_host_t *)context;
    656     if (host->update == NULL) {
    657         update_from_host(host);
    658     } else {
    659         start_host_update(host);
    660     }
    661 }
    662 
    663 static void
    664 srp_adv_host_context_release(void *context)
    665 {
    666     adv_host_t *host = context;
    667     RELEASE_HERE(host, adv_host);
    668 }
    669 
    670 static void
    671 wait_retry(adv_host_t *host)
    672 {
    673     int64_t now = ioloop_timenow();
    674 #define MIN_HOST_RETRY_INTERVAL 15
    675 #define MAX_HOST_RETRY_INTERVAL 120
    676     // If we've been retrying long enough for the lease to expire, give up.
    677     if (!host->lease_expiry || host->lease_expiry < now) {
    678         INFO("host lease has expired, not retrying: lease_expiry = %" PRId64
    679              " now = %" PRId64 " difference = %" PRId64, host->lease_expiry, now, host->lease_expiry - now);
    680         delete_host(host);
    681         return;
    682     }
    683     if (host->retry_interval == 0) {
    684         host->retry_interval = MIN_HOST_RETRY_INTERVAL;
    685     } else if (host->retry_interval < MAX_HOST_RETRY_INTERVAL) {
    686         host->retry_interval *= 2;
    687     }
    688     INFO("waiting %d seconds...", host->retry_interval);
    689     ioloop_add_wake_event(host->retry_wakeup, host, retry_callback, srp_adv_host_context_release, host->retry_interval * 1000);
    690     RETAIN_HERE(host, adv_host);
    691 }
    692 
    693 static void
    694 shared_registration_fail(void *context, int UNUSED status)
    695 {
    696     srp_server_t *server_state = context;
    697     dnssd_txn_t *txn = server_state->shared_registration_txn;
    698     DNSServiceRef sdref = txn == NULL ? NULL : txn->sdref;
    699     INFO("shared registration failed: txn %p sdref %p", server_state->shared_registration_txn, sdref);
    700     if (txn != NULL) {
    701         ioloop_dnssd_txn_cancel(txn);
    702         ioloop_dnssd_txn_release(txn);
    703         server_state->shared_registration_txn = NULL;
    704     }
    705 }
    706 
    707 bool
    708 srp_mdns_shared_registration_txn_setup(srp_server_t *server_state)
    709 {
    710     if (server_state->shared_registration_txn == NULL) {
    711         DNSServiceRef sdref;
    712         int err = DNSServiceCreateConnection(&sdref);
    713         if (err != kDNSServiceErr_NoError) {
    714             return false;
    715         }
    716         server_state->shared_registration_txn = ioloop_dnssd_txn_add(sdref, server_state, NULL, shared_registration_fail);
    717         if (server_state->shared_registration_txn == NULL) {
    718             ERROR("unable to create shared connection for registration.");
    719             dns_service_op_not_to_be_freed = NULL;
    720             DNSServiceRefDeallocate(sdref);
    721             return false;
    722         }
    723         dns_service_op_not_to_be_freed = server_state->shared_registration_txn->sdref;
    724         INFO("server_state->shared_registration_txn = %p  sdref = %p", server_state->shared_registration_txn, sdref);
    725     }
    726     return true;
    727 }
    728 
    729 static void
    730 record_txn_forget(adv_record_t *record, intptr_t affected_service_pointer,
    731                   const char *parent_type, const void *parent_pointer, const char *hostname)
    732 {
    733     if (record == NULL) {
    734         return;
    735     }
    736     if (record->rref != NULL && record->shared_txn == affected_service_pointer) {
    737         INFO("forgetting rref %p on " PUB_S_SRP " %p " PRI_S_SRP, record->rref, parent_type, parent_pointer, hostname);
    738         record->rref = NULL;
    739     }
    740 }
    741 
    742 static void
    743 record_vec_txns_forget(adv_record_vec_t *records, intptr_t affected_service_pointer,
    744                        const char *parent_type, const void *parent_pointer, const char *hostname)
    745 {
    746     if (records == NULL) {
    747         return;
    748     }
    749     for (int i = 0; i < records->num; i++) {
    750         record_txn_forget(records->vec[i], affected_service_pointer, parent_type, parent_pointer, hostname);
    751     }
    752 }
    753 
    754 static void
    755 instance_vec_txns_forget(adv_instance_vec_t *instances, intptr_t affected_service_pointer,
    756                          const char *parent_type, const void *parent_pointer, const char *hostname)
    757 {
    758     if (instances == NULL) {
    759         return;
    760     }
    761     for (int i = 0; i < instances->num; i++) {
    762         adv_instance_t *instance = instances->vec[i];
    763         if (instance != NULL && instance->txn != NULL && instance->txn->sdref != NULL &&
    764             instance->shared_txn == affected_service_pointer)
    765         {
    766             INFO("forgetting sdref %p on " PUB_S_SRP " %p " PRI_S_SRP " instance " PRI_S_SRP " . " PRI_S_SRP,
    767                  instance->txn->sdref,
    768                  parent_type, parent_pointer, hostname, instance->instance_name, instance->service_type);
    769             instance->txn->sdref = NULL;
    770         }
    771     }
    772 }
    773 
    774 static void
    775 host_txns_forget(adv_host_t *host, intptr_t affected_service_pointer)
    776 {
    777     // We call this when the shared transaction fails for some reason. That failure invalidates all the subsidiary
    778     // RecordRefs and ServiceRefs hanging off of the shared transaction; to avoid holding on to invalid pointers,
    779     // we traverse the registration database and NULL out all the rrefs and sdrefs that relate to the subsidiary
    780     // service pointer.
    781     record_vec_txns_forget(host->addresses, affected_service_pointer, "host", host, host->name);
    782     instance_vec_txns_forget(host->instances, affected_service_pointer, "host", host, host->name);
    783     record_txn_forget(host->key_record, affected_service_pointer, "host key", host, host->name);
    784     if (host->update != NULL) {
    785         record_vec_txns_forget(host->update->remove_addresses, affected_service_pointer,
    786                                "host update remove addresses", host->update, host->name);
    787         record_vec_txns_forget(host->update->add_addresses, affected_service_pointer,
    788                                "host update add addresses", host->update, host->name);
    789         record_txn_forget(host->update->key, affected_service_pointer, "host update key", host->update, host->name);
    790         instance_vec_txns_forget(host->update->update_instances, affected_service_pointer,
    791                                  "host update update instances", host->update, host->name);
    792         instance_vec_txns_forget(host->update->remove_instances, affected_service_pointer,
    793                                  "host update remove instances", host->update, host->name);
    794         instance_vec_txns_forget(host->update->renew_instances, affected_service_pointer,
    795                                  "host update renew instances", host->update, host->name);
    796         instance_vec_txns_forget(host->update->add_instances, affected_service_pointer,
    797                                  "host update add instances", host->update, host->name);
    798     }
    799 }
    800 
    801 static void
    802 service_disconnected(srp_server_t *server_state, intptr_t service_pointer)
    803 {
    804     if (service_pointer == (intptr_t)server_state->shared_registration_txn &&
    805         server_state->shared_registration_txn != NULL)
    806     {
    807         INFO("server_state->shared_registration_txn = %p  sdref = %p",
    808              server_state->shared_registration_txn, server_state->shared_registration_txn->sdref);
    809         // For every host that's active right now that has transactions on this shared transaction, forget all those
    810         // transactions. The txn_cancel following this will free all of the memory in the client stub.
    811         for (adv_host_t *host = server_state->hosts; host != NULL; host = host->next) {
    812             host_txns_forget(host, service_pointer);
    813         }
    814         dns_service_op_not_to_be_freed = NULL;
    815         ioloop_dnssd_txn_cancel(server_state->shared_registration_txn);
    816         ioloop_dnssd_txn_release(server_state->shared_registration_txn);
    817         server_state->shared_registration_txn = NULL;
    818     }
    819 }
    820 
    821 static void
    822 adv_record_vec_remove_update(adv_record_vec_t *vec, adv_update_t *update)
    823 {
    824     for (int i = 0; i < vec->num; i++) {
    825         if (vec->vec[i] != NULL && vec->vec[i]->update != NULL && vec->vec[i]->update == update) {
    826             RELEASE_HERE(vec->vec[i]->update, adv_update);
    827             vec->vec[i]->update = NULL;
    828         }
    829     }
    830 }
    831 
    832 static void
    833 adv_instance_vec_remove_update(adv_instance_vec_t *vec, adv_update_t *update)
    834 {
    835     for (int i = 0; i < vec->num; i++) {
    836         if (vec->vec[i] != NULL && vec->vec[i]->update != NULL && vec->vec[i]->update == update) {
    837             RELEASE_HERE(vec->vec[i]->update, adv_update);
    838             vec->vec[i]->update = NULL;
    839         }
    840     }
    841 }
    842 
    843 static void
    844 adv_instances_cancel(adv_instance_vec_t *instances)
    845 {
    846     for (int i = 0; i < instances->num; i++) {
    847         adv_instance_t *instance = instances->vec[i];
    848         if (instance != NULL) {
    849             if (instance->txn != NULL) {
    850                 ioloop_dnssd_txn_cancel_srp(instance->host->server_state, instance->txn);
    851                 ioloop_dnssd_txn_release(instance->txn);
    852                 instance->txn = NULL;
    853             }
    854             if (instance->retry_wakeup != NULL) {
    855                 ioloop_cancel_wake_event(instance->retry_wakeup);
    856                 ioloop_wakeup_release(instance->retry_wakeup);
    857                 instance->retry_wakeup = NULL;
    858             }
    859         }
    860     }
    861 }
    862 
    863 static void
    864 adv_update_free_instance_vectors(adv_update_t *NONNULL update)
    865 {
    866     if (update->update_instances != NULL) {
    867         adv_instance_vec_remove_update(update->update_instances, update);
    868         adv_instances_cancel(update->update_instances);
    869         RELEASE_HERE(update->update_instances, adv_instance_vec);
    870         update->update_instances = NULL;
    871     }
    872     if (update->remove_instances != NULL) {
    873         adv_instance_vec_remove_update(update->remove_instances, update);
    874         RELEASE_HERE(update->remove_instances, adv_instance_vec);
    875         update->remove_instances = NULL;
    876     }
    877     if (update->renew_instances != NULL) {
    878         adv_instance_vec_remove_update(update->renew_instances, update);
    879         RELEASE_HERE(update->renew_instances, adv_instance_vec);
    880         update->renew_instances = NULL;
    881     }
    882     if (update->add_instances != NULL) {
    883         adv_instance_vec_remove_update(update->add_instances, update);
    884         adv_instances_cancel(update->add_instances);
    885         RELEASE_HERE(update->add_instances, adv_instance_vec);
    886         update->add_instances = NULL;
    887     }
    888 }
    889 
    890 static void
    891 adv_update_finalize(adv_update_t *NONNULL update)
    892 {
    893     if (update->host != NULL) {
    894         RELEASE_HERE(update->host, adv_host);
    895     }
    896 
    897     if (update->client != NULL) {
    898         srp_parse_client_updates_free(update->client);
    899         update->client = NULL;
    900     }
    901 
    902     if (update->remove_addresses != NULL) {
    903         adv_record_vec_remove_update(update->remove_addresses, update);
    904         RELEASE_HERE(update->remove_addresses, adv_record_vec);
    905     }
    906 
    907     if (update->add_addresses != NULL) {
    908         adv_record_vec_remove_update(update->add_addresses, update);
    909         RELEASE_HERE(update->add_addresses, adv_record_vec);
    910     }
    911 
    912     adv_update_free_instance_vectors(update);
    913     if (update->key != NULL) {
    914         RELEASE_HERE(update->key, adv_record);
    915     }
    916     free(update);
    917 }
    918 
    919 static void
    920 adv_update_cancel(adv_update_t *NONNULL update)
    921 {
    922     adv_host_t *host = update->host;
    923     bool faulted = false;
    924 
    925     RETAIN_HERE(update, adv_update); // ensure that update remains valid for the duration of this function call.
    926 
    927     if (host != NULL) {
    928         RETAIN_HERE(host, adv_host); // in case the update is holding the last reference to the host
    929         RELEASE_HERE(update->host, adv_host);
    930         update->host = NULL;
    931 
    932         INFO("cancelling update %p for host " PRI_S_SRP, update, host->registered_name);
    933 
    934         if (host->update == update) {
    935             RELEASE_HERE(host->update, adv_update);
    936             host->update = NULL;
    937         }
    938 
    939         // In case we needed to re-register some of the host's addresses, remove the update pointer from them.
    940         if (host->addresses != NULL) {
    941             for (int i = 0; i < host->addresses->num; i++) {
    942                 adv_record_t *record = host->addresses->vec[i];
    943                 if (record->update == update) {
    944                     RELEASE_HERE(host->addresses->vec[i]->update, adv_update);
    945                     record->update = NULL;
    946                 }
    947             }
    948         }
    949     } else {
    950         INFO("canceling update with no host.");
    951     }
    952 
    953     adv_update_free_instance_vectors(update);
    954 
    955     if (update->add_addresses != NULL) {
    956         // Any record that we attempted to add as part of this update should be removed because the update failed.
    957         for (int i = 0; i < update->add_addresses->num; i++) {
    958             adv_record_t *record = update->add_addresses->vec[i];
    959             if (record != NULL) {
    960                 if (host == NULL) {
    961                     if (!faulted) {
    962                         FAULT("unable to clean up host address registration because host object is gone from update.");
    963                         faulted = true;
    964                     }
    965                 } else {
    966                     if (record->rref != NULL) {
    967                         srp_mdns_shared_record_remove(host->server_state, record);
    968                     }
    969                 }
    970             }
    971         }
    972         adv_record_vec_remove_update(update->add_addresses, update);
    973         RELEASE_HERE(update->add_addresses, adv_record_vec);
    974         update->add_addresses = NULL;
    975     }
    976 
    977     if (update->remove_addresses != NULL) {
    978         adv_record_vec_remove_update(update->remove_addresses, update);
    979         RELEASE_HERE(update->remove_addresses, adv_record_vec);
    980         update->remove_addresses = NULL;
    981     }
    982 
    983     if (update->key != NULL) {
    984         if (update->key->update != NULL) {
    985             RELEASE_HERE(update->key->update, adv_update);
    986             update->key->update = NULL;
    987         }
    988         // Any record that we attempted to add as part of this update should be removed because the update failed.
    989         if (update->key->rref != NULL) {
    990             if (host == NULL) {
    991                 if (!faulted) {
    992                     FAULT("unable to clean up host key registration because host object is gone from update.");
    993                     faulted = true;
    994                 }
    995             } else {
    996                 srp_mdns_shared_record_remove(host->server_state, update->key);
    997             }
    998         }
    999         RELEASE_HERE(update->key, adv_record);
   1000         update->key = NULL;
   1001     }
   1002     if (host != NULL) {
   1003         RELEASE_HERE(host, adv_host);
   1004     }
   1005     RELEASE_HERE(update, adv_update);
   1006 }
   1007 
   1008 static void
   1009 update_failed(adv_update_t *update, int rcode, bool expire, bool send_response)
   1010 {
   1011     // Retain the update for the life of this function call, since we may well release the last other reference to it.
   1012     RETAIN_HERE(update, adv_update);
   1013 
   1014     // If we still have a client waiting for the result of this update, tell it we failed.
   1015     // Updates that have never worked are abandoned when the client is notified.
   1016     if (update->client != NULL) {
   1017         adv_host_t *host = update->host;
   1018         client_update_t *client = update->client;
   1019         adv_update_cancel(update);
   1020         advertise_finished(host, host->name, host->server_state, host->srpl_connection,
   1021                            client->connection, client->message, rcode, NULL, send_response, true);
   1022         srp_parse_client_updates_free(client);
   1023         update->client = NULL;
   1024         // If we don't have a lease yet, or the old lease has expired, remove the host.
   1025         // However, if the expire flag is false, it's because we're already finalizing the
   1026         // host, so doing an expiry here would double free the host. In this case, we leave
   1027         // it to the caller to do the expiry (really, to finalize the host).
   1028         if (expire && (host->lease_expiry == 0 || host->lease_expiry <= ioloop_timenow())) {
   1029             delete_host(host);
   1030         }
   1031         RELEASE_HERE(update, adv_update);
   1032         return;
   1033     }
   1034     adv_update_cancel(update);
   1035     RELEASE_HERE(update, adv_update);
   1036 }
   1037 
   1038 static void
   1039 host_addr_free(adv_host_t *host)
   1040 {
   1041     int i;
   1042 
   1043     // We can't actually deallocate the address vector until the host object is collected, so deallocate the address
   1044     // records.
   1045     if (host->addresses != NULL) {
   1046         for (i = 0; i < host->addresses->num; i++) {
   1047             if (host->addresses->vec[i] != NULL) {
   1048                 INFO("Removing AAAA record for " PRI_S_SRP, host->registered_name);
   1049                 srp_mdns_shared_record_remove(host->server_state, host->addresses->vec[i]);
   1050                 RELEASE_HERE(host->addresses->vec[i], adv_record);
   1051                 host->addresses->vec[i] = NULL;
   1052             }
   1053         }
   1054         host->addresses->num = 0;
   1055     }
   1056 }
   1057 
   1058 // Free just those parts that are no longer needed when the host is no longer valid.
   1059 static void
   1060 host_invalidate(adv_host_t *host)
   1061 {
   1062     // Get rid of the retry wake event.
   1063     if (host->retry_wakeup != NULL) {
   1064         ioloop_cancel_wake_event(host->retry_wakeup);
   1065     }
   1066     if (host->re_register_wakeup != NULL) {
   1067         ioloop_cancel_wake_event(host->re_register_wakeup);
   1068     }
   1069 
   1070     // Remove the address records.
   1071     host_addr_free(host);
   1072 
   1073     // Remove the services.
   1074     if (host->instances != NULL) {
   1075         adv_instances_cancel(host->instances);
   1076         RELEASE_HERE(host->instances, adv_instance_vec);
   1077         host->instances = NULL;
   1078     }
   1079 
   1080     if (host->update != NULL) {
   1081         RELEASE_HERE(host->update, adv_update);
   1082         host->update = NULL;
   1083     }
   1084     if (host->key_record != NULL) {
   1085         srp_mdns_shared_record_remove(host->server_state, host->key_record);
   1086         RELEASE_HERE(host->key_record, adv_record);
   1087         host->key_record = NULL;
   1088     }
   1089     host->update = NULL;
   1090     host->removed = true;
   1091 }
   1092 
   1093 // Free everything associated with the host, including the host object.
   1094 static void
   1095 adv_host_finalize(adv_host_t *host)
   1096 {
   1097     // Just in case this hasn't happened yet, free the non-identifying host data and cancel any outstanding
   1098     // transactions.
   1099     host_invalidate(host);
   1100 
   1101     if (host->addresses != NULL) {
   1102         RELEASE_HERE(host->addresses, adv_record_vec);
   1103         host->addresses = NULL;
   1104     }
   1105 
   1106     if (host->key_rdata != NULL) {
   1107         free(host->key_rdata);
   1108         host->key_rdata = NULL;
   1109     }
   1110     if (host->key_record != NULL) {
   1111         RELEASE_HERE(host->key_record, adv_record);
   1112         host->key_record = NULL;
   1113     }
   1114 
   1115     if (host->message != NULL) {
   1116         ioloop_message_release(host->message);
   1117         host->message = NULL;
   1118     }
   1119 
   1120     // We definitely don't want a lease callback at this point.
   1121     if (host->lease_wakeup != NULL) {
   1122         ioloop_cancel_wake_event(host->lease_wakeup);
   1123         ioloop_wakeup_release(host->lease_wakeup);
   1124         host->lease_wakeup = NULL; // this will make us crash if we use it after free
   1125     }
   1126     // Get rid of the retry wake event.
   1127     if (host->retry_wakeup != NULL) {
   1128         ioloop_cancel_wake_event(host->retry_wakeup);
   1129         ioloop_wakeup_release(host->retry_wakeup);
   1130         host->retry_wakeup = NULL;
   1131     }
   1132 
   1133     if (host->re_register_wakeup != NULL) {
   1134         ioloop_cancel_wake_event(host->re_register_wakeup);
   1135         ioloop_wakeup_release(host->re_register_wakeup);
   1136         host->re_register_wakeup = NULL;
   1137     }
   1138     INFO("removed " PRI_S_SRP ", key_id %x", host->name ? host->name : "<null>", host->key_id);
   1139 
   1140     // In the default case, host->name and host->registered_name point to the same memory: we don't want a double free.
   1141     if (host->registered_name == host->name) {
   1142         host->registered_name = NULL;
   1143     }
   1144     if (host->name != NULL) {
   1145         free(host->name);
   1146     }
   1147     if (host->registered_name != NULL) {
   1148         free(host->registered_name);
   1149     }
   1150     free(host);
   1151 }
   1152 
   1153 void
   1154 srp_adv_host_release_(adv_host_t *host, const char *file, int line)
   1155 {
   1156     RELEASE(host, adv_host);
   1157 }
   1158 
   1159 void
   1160 srp_adv_host_retain_(adv_host_t *host, const char *file, int line)
   1161 {
   1162     RETAIN(host, adv_host);
   1163 }
   1164 
   1165 bool
   1166 srp_adv_host_valid(adv_host_t *host)
   1167 {
   1168     // If the host has been removed, it's not valid.
   1169     if (host->removed) {
   1170         return false;
   1171     }
   1172     // If there is no key data, the host is invalid.
   1173     if (host->key_rdata == NULL) {
   1174         return false;
   1175     }
   1176     return true;
   1177 }
   1178 
   1179 int
   1180 srp_current_valid_host_count(srp_server_t *server_state)
   1181 {
   1182     adv_host_t *host;
   1183     int count = 0;
   1184     for (host = server_state->hosts; host; host = host->next) {
   1185         if (srp_adv_host_valid(host)) {
   1186             count++;
   1187         }
   1188     }
   1189     return count;
   1190 }
   1191 
   1192 int
   1193 srp_hosts_to_array(srp_server_t *server_state, adv_host_t **host_array, int max)
   1194 {
   1195     int count = 0;
   1196     for (adv_host_t *host = server_state->hosts; count < max && host != NULL; host = host->next) {
   1197         if (srp_adv_host_valid(host)) {
   1198             host_array[count] = host;
   1199             RETAIN_HERE(host_array[count], adv_host);
   1200             count++;
   1201         }
   1202     }
   1203     return count;
   1204 }
   1205 
   1206 adv_host_t *
   1207 srp_adv_host_copy_(srp_server_t *server_state, dns_name_t *name, const char *file, int line)
   1208 {
   1209     for (adv_host_t *host = server_state->hosts; host; host = host->next) {
   1210         if (srp_adv_host_valid(host) && dns_names_equal_text(name, host->name)) {
   1211             RETAIN(host, adv_host);
   1212             return host;
   1213         }
   1214     }
   1215     return NULL;
   1216 }
   1217 
   1218 static void
   1219 host_remove(adv_host_t *host)
   1220 {
   1221     // This host is no longer valid. Get rid of the associated transactions and other stuff that's not required to
   1222     // identify it, and then release the host list reference to it.
   1223     host_invalidate(host);
   1224     // Note that while adv_host_finalize calls host_invalidate, adv_host_finalize won't necessarily be called here because there
   1225     // may be outstanding references on the host. It's okay to call host_invalidate twice--the second time it should be
   1226     // a no-op.
   1227     RELEASE_HERE(host, adv_host);
   1228 }
   1229 
   1230 static adv_host_t **
   1231 host_ready(adv_host_t *host)
   1232 {
   1233     adv_host_t **p_hosts;
   1234 
   1235     // Find the host on the list of hosts.
   1236     for (p_hosts = &host->server_state->hosts; *p_hosts != NULL; p_hosts = &(*p_hosts)->next) {
   1237         if (*p_hosts == host) {
   1238             break;
   1239         }
   1240     }
   1241     if (*p_hosts == NULL) {
   1242         ERROR("called with nonexistent host.");
   1243         return NULL;
   1244     }
   1245 
   1246     // It's possible that we got an update to this host, but haven't processed it yet.  In this
   1247     // case, we don't want to get rid of the host, but we do want to get rid of it later if the
   1248     // update fails.  So postpone the removal for a bit.
   1249     if (host->update != NULL) {
   1250         INFO("reached with pending updates on host " PRI_S_SRP ".", host->registered_name);
   1251         ioloop_add_wake_event(host->lease_wakeup, host, lease_callback, srp_adv_host_context_release, 10 * 1000);
   1252         RETAIN_HERE(host, adv_host);
   1253         host->lease_expiry = ioloop_timenow() + 10 * 1000; // ten seconds
   1254         return NULL;
   1255     }
   1256 
   1257     return p_hosts;
   1258 }
   1259 
   1260 static void
   1261 lease_callback(void *context)
   1262 {
   1263     int64_t now = ioloop_timenow();
   1264     adv_host_t **p_hosts, *host = context;
   1265     int i, num_instances = 0;
   1266 
   1267     p_hosts = host_ready(host);
   1268     if (p_hosts == NULL) {
   1269         INFO("host expired");
   1270         return;
   1271     }
   1272 
   1273     INFO("host " PRI_S_SRP, host->name);
   1274 
   1275     // If the host entry lease has expired, any instance leases have also.
   1276     if (host->lease_expiry < now) {
   1277         delete_host(host);
   1278         return;
   1279     }
   1280 
   1281     INFO("host " PRI_S_SRP " is still alive", host->name);
   1282 
   1283     if (host->instances == NULL) {
   1284         INFO("no instances");
   1285         return;
   1286     }
   1287 
   1288     // Find instances that have expired and release them.
   1289     for (i = 0; i < host->instances->num; i++) {
   1290         adv_instance_t *instance = host->instances->vec[i];
   1291         if (instance == NULL) {
   1292             continue;
   1293         }
   1294         if (instance->lease_expiry < now) {
   1295             INFO("host " PRI_S_SRP " instance " PRI_S_SRP "." PRI_S_SRP " has expired",
   1296                  host->name, instance->instance_name, instance->service_type);
   1297             // We have to release the transaction so that we can release the reference the transaction has to the instance.
   1298             if (instance->txn != NULL) {
   1299                 dnssd_txn_t *txn = instance->txn;
   1300                 instance->txn = NULL;
   1301                 ioloop_dnssd_txn_release(txn);
   1302             }
   1303             host->instances->vec[i] = NULL;
   1304             RELEASE_HERE(instance, adv_instance);
   1305             continue;
   1306         } else {
   1307             INFO("host " PRI_S_SRP " instance " PRI_S_SRP "." PRI_S_SRP " has not expired",
   1308                  host->name, instance->instance_name, instance->service_type);
   1309         }
   1310         num_instances++;
   1311     }
   1312 
   1313     int64_t next_lease_expiry = host->lease_expiry;
   1314 
   1315     // Get rid of holes in the host instance vector and compute the next lease callback time
   1316     int j = 0;
   1317 
   1318     for (i = 0; i < host->instances->num; i++) {
   1319         if (host->instances->vec[i] != NULL) {
   1320             adv_instance_t *instance = host->instances->vec[i];
   1321             host->instances->vec[j++] = instance;
   1322             if (next_lease_expiry > instance->lease_expiry) {
   1323                 next_lease_expiry = instance->lease_expiry;
   1324             }
   1325         }
   1326     }
   1327     INFO("host " PRI_S_SRP " lost %d instances", host->name, host->instances->num - j);
   1328     host->instances->num = j;
   1329 
   1330     // Now set a timer for the next lease expiry event
   1331     uint64_t when = next_lease_expiry - now;
   1332     if (when > INT32_MAX) {
   1333         when = INT32_MAX;
   1334     }
   1335 
   1336     ioloop_add_wake_event(host->lease_wakeup, host, lease_callback, srp_adv_host_context_release, (uint32_t)when);
   1337     RETAIN_HERE(host, adv_host);
   1338 }
   1339 
   1340 // Called when we definitely want to make all the advertisements associated with a host go away.
   1341 static void
   1342 delete_host(void *context)
   1343 {
   1344     adv_host_t **p_hosts, *host = context;
   1345 
   1346 
   1347     p_hosts = host_ready(host);
   1348     if (p_hosts == NULL) {
   1349         return;
   1350     }
   1351 
   1352     INFO("deleting host " PRI_S_SRP, host->name);
   1353 
   1354     // De-link the host.
   1355     *p_hosts = host->next;
   1356 
   1357     // Get rid of any transactions attached to the host, any timer events, and any other associated data.
   1358     host_remove(host);
   1359 }
   1360 
   1361 // We remember the message that produced this instance so that if we get an update that doesn't update everything,
   1362 // we know which instances /were/ updated by this particular message. instance->recent_message is a copy of the pointer
   1363 // to the message that most recently updated this instance. When we set instance->recent_message, we don't yet know
   1364 // if the update is going to succeed; if it fails, we can't have changed update->message. If it succeeds, then when we
   1365 // get down to srp_mdns_update_finished, we can compare the message that did the update to instance->recent_message; if they
   1366 // are the same, then we set the message on the instance.
   1367 // Note that we only set instance->recent_message during register_instance_completion, so there's no timing race that
   1368 // could happen as a result of receiving a second update to the same instance before the first has been processed.
   1369 static void
   1370 set_instance_message(adv_instance_t *instance, message_t *message)
   1371 {
   1372     if (message != NULL && (ptrdiff_t)message == instance->recent_message) {
   1373         if (instance->message != NULL) {
   1374             ioloop_message_release(instance->message);
   1375         }
   1376         instance->message = message;
   1377         ioloop_message_retain(instance->message);
   1378         instance->recent_message = 0;
   1379     }
   1380 }
   1381 
   1382 void
   1383 srp_mdns_update_finished(adv_update_t *update)
   1384 {
   1385     adv_host_t *host = update->host;
   1386     client_update_t *client = update->client;
   1387     int num_addresses = 0;
   1388     adv_record_vec_t *addresses = NULL;
   1389     int num_instances = 0;
   1390     adv_instance_vec_t *instances = NULL;
   1391     int i, j;
   1392     int num_host_addresses = 0;
   1393     int num_add_addresses = 0;
   1394     int num_host_instances = 0;
   1395     int num_add_instances = 0;
   1396     message_t *message = NULL;
   1397     client_update_t *remaining_updates = NULL;
   1398     srp_server_t *server_state = host->server_state;
   1399 
   1400     // Get the message that produced the update, if any
   1401     if (client != NULL) {
   1402         message = client->message;
   1403     }
   1404 
   1405     // Once an update has finished, we need to apply all of the proposed changes to the host object.
   1406     if (host->addresses != NULL) {
   1407         for (i = 0; i < host->addresses->num; i++) {
   1408             if (host->addresses->vec[i] != NULL &&
   1409                 (update->remove_addresses == NULL || update->remove_addresses->vec[i] == NULL))
   1410             {
   1411                 num_host_addresses++;
   1412             }
   1413         }
   1414     }
   1415 
   1416     if (update->add_addresses != NULL) {
   1417         for (i = 0; i < update->add_addresses->num; i++) {
   1418             if (update->add_addresses->vec[i] != NULL) {
   1419                 num_add_addresses++;
   1420             }
   1421         }
   1422     }
   1423 
   1424     num_addresses = num_host_addresses + num_add_addresses;
   1425     if (num_addresses > 0) {
   1426         addresses = adv_record_vec_create(num_addresses);
   1427         if (addresses == NULL) {
   1428             update_failed(update, dns_rcode_servfail, true, true);
   1429             return;
   1430         }
   1431 
   1432         j = 0;
   1433 
   1434         if (host->addresses != NULL) {
   1435             for (i = 0; i < host->addresses->num; i++) {
   1436                 adv_record_t *rec = host->addresses->vec[i];
   1437                 if (rec != NULL && (update->remove_addresses == NULL || update->remove_addresses->vec[i] == NULL))
   1438                 {
   1439 #ifdef DEBUG_VERBOSE
   1440                     uint8_t *rdp = rec->rdata;
   1441                     if (rec->rrtype == dns_rrtype_aaaa) {
   1442                         SEGMENTED_IPv6_ADDR_GEN_SRP(rdp, rdp_buf);
   1443                         INFO("retaining " PRI_SEGMENTED_IPv6_ADDR_SRP "on host " PRI_S_SRP,
   1444                              SEGMENTED_IPv6_ADDR_PARAM_SRP(rdp, rdp_buf), host->registered_name);
   1445                     } else {
   1446                         IPv4_ADDR_GEN_SRP(rdp, rdp_buf);
   1447                         INFO("retaining " PRI_IPv4_ADDR_SRP "on host " PRI_S_SRP,
   1448                              IPv4_ADDR_PARAM_SRP(rdp, rdp_buf), host->registered_name);
   1449                     }
   1450 #endif
   1451                     addresses->vec[j] = rec;
   1452                     RETAIN_HERE(addresses->vec[j], adv_record);
   1453                     j++;
   1454                 }
   1455             }
   1456         }
   1457         if (update->add_addresses != NULL) {
   1458             for (i = 0; i < update->add_addresses->num; i++) {
   1459                 adv_record_t *rec = update->add_addresses->vec[i];
   1460                 if (rec != NULL) {
   1461 #ifdef DEBUG_VERBOSE
   1462                     uint8_t *rdp = rec->rdata;
   1463                     if (rec->rrtype == dns_rrtype_aaaa) {
   1464                         SEGMENTED_IPv6_ADDR_GEN_SRP(rdp, rdp_buf);
   1465                         INFO("adding " PRI_SEGMENTED_IPv6_ADDR_SRP "to host " PRI_S_SRP,
   1466                              SEGMENTED_IPv6_ADDR_PARAM_SRP(rdp, rdp_buf), host->registered_name);
   1467                     } else {
   1468                         IPv4_ADDR_GEN_SRP(rdp, rdp_buf);
   1469                         INFO("adding " PRI_IPv4_ADDR_SRP "to host " PRI_S_SRP,
   1470                              IPv4_ADDR_PARAM_SRP(rdp, rdp_buf), host->registered_name);
   1471                     }
   1472 #endif
   1473                     addresses->vec[j] = rec;
   1474                     RETAIN_HERE(addresses->vec[j], adv_record);
   1475                     j++;
   1476                     if (rec->update != NULL) {
   1477                         RELEASE_HERE(update->add_addresses->vec[i]->update, adv_update);
   1478                         update->add_addresses->vec[i]->update = NULL;
   1479                     }
   1480                     RELEASE_HERE(update->add_addresses->vec[i], adv_record);
   1481                     update->add_addresses->vec[i] = NULL;
   1482                 }
   1483             }
   1484         }
   1485         addresses->num = j;
   1486     }
   1487 
   1488     // Do the same for instances.
   1489     if (host->instances != NULL) {
   1490         for (i = 0; i < host->instances->num; i++) {
   1491             // We're counting the number of non-NULL instances in the host instance vector, which is probably always
   1492             // going to be the same as host->instances->num, but we are not relying on this.
   1493             if (host->instances->vec[i] != NULL) {
   1494                 num_host_instances++;
   1495             }
   1496         }
   1497     }
   1498 
   1499     if (update->add_instances != NULL) {
   1500         for (i = 0; i < update->add_instances->num; i++) {
   1501             if (update->add_instances->vec[i] != NULL) {
   1502                 num_add_instances++;
   1503             }
   1504         }
   1505     }
   1506 
   1507     num_instances = num_add_instances + num_host_instances;
   1508     instances = adv_instance_vec_create(num_instances);
   1509     if (instances == NULL) {
   1510         if (addresses != NULL) {
   1511             RELEASE_HERE(addresses, adv_record_vec);
   1512             addresses = NULL;
   1513         }
   1514         update_failed(update, dns_rcode_servfail, true, true);
   1515         return;
   1516     }
   1517 
   1518     j = 0;
   1519     if (host->instances != NULL) {
   1520         for (i = 0; i < host->instances->num; i++) {
   1521             if (j == num_instances) {
   1522                 FAULT("j (%d) == num_instances (%d)", j, num_instances);
   1523                 break;
   1524             }
   1525             if (update->update_instances != NULL && update->update_instances->vec[i] != NULL) {
   1526                 adv_instance_t *instance = update->update_instances->vec[i];
   1527                 if (update->remove_instances != NULL && update->remove_instances->vec[i] != NULL) {
   1528                     adv_instance_t *removed_instance = update->remove_instances->vec[i];
   1529                     INFO("removed instance " PRI_S_SRP " " PRI_S_SRP " %d",
   1530                          removed_instance->instance_name, removed_instance->service_type, removed_instance->port);
   1531                     INFO("added instance " PRI_S_SRP " " PRI_S_SRP " %d",
   1532                          instance->instance_name, instance->service_type, instance->port);
   1533                 } else {
   1534                     INFO("updated instance " PRI_S_SRP " " PRI_S_SRP " %d",
   1535                          instance->instance_name, instance->service_type, instance->port);
   1536                 }
   1537                 instances->vec[j] = instance;
   1538                 RETAIN_HERE(instances->vec[j], adv_instance);
   1539                 j++;
   1540                 RELEASE_HERE(update->update_instances->vec[i], adv_instance);
   1541                 update->update_instances->vec[i] = NULL;
   1542                 if (instance->update != NULL) {
   1543                     RELEASE_HERE(instance->update, adv_update);
   1544                     instance->update = NULL;
   1545                 }
   1546                 set_instance_message(instance, message);
   1547             } else {
   1548                 if (update->remove_instances != NULL && update->remove_instances->vec[i] != NULL) {
   1549                     adv_instance_t *instance = update->remove_instances->vec[i];
   1550                     INFO("removed instance " PRI_S_SRP " " PRI_S_SRP " %d",
   1551                          instance->instance_name, instance->service_type, instance->port);
   1552                     instances->vec[j] = instance;
   1553                     RETAIN_HERE(instances->vec[j], adv_instance);
   1554                     j++;
   1555                     instance->removed = true;
   1556                     if (message != NULL) {
   1557                         if (instance->message != NULL) {
   1558                             ioloop_message_release(instance->message);
   1559                         }
   1560                         instance->message = message;
   1561                         ioloop_message_retain(instance->message);
   1562                     }
   1563                     if (instance->txn == NULL) {
   1564                         ERROR("instance " PRI_S_SRP "." PRI_S_SRP " for host " PRI_S_SRP " has no connection.",
   1565                               instance->instance_name, instance->service_type, host->name);
   1566                     } else {
   1567                         ioloop_dnssd_txn_cancel_srp(host->server_state, instance->txn);
   1568                         ioloop_dnssd_txn_release(instance->txn);
   1569                         instance->txn = NULL;
   1570                     }
   1571                 } else {
   1572                     if (host->instances->vec[i] != NULL) {
   1573                         adv_instance_t *instance = host->instances->vec[i];
   1574                         INFO("kept instance " PRI_S_SRP " " PRI_S_SRP " %d, instance->message = %p",
   1575                              instance->instance_name, instance->service_type, instance->port, instance->message);
   1576                         instances->vec[j] = instance;
   1577                         RETAIN_HERE(instances->vec[j], adv_instance);
   1578                         j++;
   1579                         set_instance_message(instance, message);
   1580                     }
   1581                 }
   1582             }
   1583         }
   1584     }
   1585 
   1586     // Set the message on all of the instances that were renewed to the current message.
   1587     if (update->renew_instances != NULL) {
   1588         for (i = 0; i < update->renew_instances->num; i++) {
   1589             adv_instance_t *instance = update->renew_instances->vec[i];
   1590             if (instance != NULL) {
   1591                 if (message != NULL) { // Should never not be NULL for a renew, of course.
   1592                     if (instance->message != NULL) {
   1593                         ioloop_message_release(instance->message);
   1594                     }
   1595                     instance->message = message;
   1596                     ioloop_message_retain(instance->message);
   1597                 }
   1598                 instance->recent_message = 0;
   1599                 INFO("renewed instance " PRI_S_SRP " " PRI_S_SRP " %d",
   1600                      instance->instance_name, instance->service_type, instance->port);
   1601             }
   1602         }
   1603     }
   1604 
   1605     if (update->add_instances != NULL) {
   1606         for (i = 0; i < update->add_instances->num; i++) {
   1607             adv_instance_t *instance = update->add_instances->vec[i];
   1608             if (instance != NULL) {
   1609                 INFO("added instance " PRI_S_SRP " " PRI_S_SRP " %d",
   1610                       instance->instance_name, instance->service_type, instance->port);
   1611                 instances->vec[j] = instance;
   1612                 RETAIN_HERE(instances->vec[j], adv_instance);
   1613                 j++;
   1614                 RELEASE_HERE(update->add_instances->vec[i], adv_instance);
   1615                 update->add_instances->vec[i] = NULL;
   1616                 if (instance->update != NULL) {
   1617                     RELEASE_HERE(instance->update, adv_update);
   1618                     instance->update = NULL;
   1619                 }
   1620                 set_instance_message(instance, message);
   1621             }
   1622         }
   1623     }
   1624     instances->num = j;
   1625     // Clear "skip update" flag on instances.
   1626     for (i = 0; i < instances->num; i++) {
   1627         if (instances->vec[i] != NULL) {
   1628             instances->vec[i]->skip_update = false;
   1629         }
   1630     }
   1631 
   1632     // At this point we can safely modify the host object because we aren't doing any more
   1633     // allocations.
   1634     if (host->addresses != NULL) {
   1635         RELEASE_HERE(host->addresses, adv_record_vec);
   1636     }
   1637     host->addresses = addresses; // Either NULL or else returned retained by adv_record_vec_create().
   1638 
   1639     if (host->instances != NULL) {
   1640         for (i = 0; i < host->instances->num; i++) {
   1641             adv_instance_t *instance = host->instances->vec[i];
   1642             if (instance != NULL) {
   1643                 INFO("old host instance %d " PRI_S_SRP "." PRI_S_SRP " for host " PRI_S_SRP " has ref_count %d",
   1644                      i, instance->instance_name, instance->service_type, host->name, instance->ref_count);
   1645             } else {
   1646                 INFO("old host instance %d is NULL", i);
   1647             }
   1648         }
   1649         RELEASE_HERE(host->instances, adv_instance_vec);
   1650     }
   1651     host->instances = instances;
   1652 
   1653     if (host->key_record != NULL && update->key != NULL && host->key_record != update->key) {
   1654         srp_mdns_shared_record_remove(host->server_state, host->key_record);
   1655         RELEASE_HERE(host->key_record, adv_record);
   1656         host->key_record = NULL;
   1657     }
   1658     if (host->key_record == NULL && update->key != NULL) {
   1659         host->key_record = update->key;
   1660         RETAIN_HERE(host->key_record, adv_record);
   1661         if (update->key->update != NULL) {
   1662             RELEASE_HERE(update->key->update, adv_update);
   1663             update->key->update = NULL;
   1664         }
   1665     }
   1666 
   1667     // Remove any instances that are to be removed
   1668     if (update->remove_addresses != NULL) {
   1669         for (i = 0; i < update->remove_addresses->num; i++) {
   1670             adv_record_t *record = update->remove_addresses->vec[i];
   1671             if (record != NULL) {
   1672                 srp_mdns_shared_record_remove(host->server_state, record);
   1673             }
   1674         }
   1675     }
   1676 
   1677     time_t lease_offset = 0;
   1678 
   1679     if (client) {
   1680         if (host->message != NULL) {
   1681             ioloop_message_release(host->message);
   1682         }
   1683         host->message = client->message;
   1684         ioloop_message_retain(host->message);
   1685         advertise_finished(host, host->name, host->server_state, host->srpl_connection,
   1686                            client->connection, client->message, dns_rcode_noerror, client, true,
   1687                            client->next == NULL);
   1688         remaining_updates = client->next;
   1689         client->next = NULL;
   1690         srp_parse_client_updates_free(client);
   1691         update->client = NULL;
   1692         if (host->message->received_time != 0) {
   1693             host->update_time = host->message->received_time;
   1694             lease_offset = srp_time() - host->update_time;
   1695             INFO("setting host update time based on message received time: %ld, lease offset = %ld",
   1696                  host->update_time, lease_offset);
   1697         } else {
   1698             INFO("setting host update time based on current time: %ld", host->message->received_time);
   1699             host->update_time = srp_time();
   1700         }
   1701     } else {
   1702         INFO("lease offset = %ld", lease_offset);
   1703         lease_offset = srp_time() - host->update_time;
   1704     }
   1705     RETAIN_HERE(update, adv_update); // We need to hold a reference to the update since this might be the last.
   1706 
   1707     // The update should still be on the host.
   1708     if (host->update == NULL) {
   1709         ERROR("p_update is null.");
   1710     } else {
   1711         RELEASE_HERE(host->update, adv_update);
   1712         host->update = NULL;
   1713     }
   1714 
   1715     // Reset the retry interval, since we succeeded in updating.
   1716     host->retry_interval = 0;
   1717 
   1718     // Set the lease time based on this update. Even if we scheduled an update for the next time we
   1719     // enter the dispatch loop, we still want to schedule a lease expiry here, because it's possible
   1720     // that in the process of returning to the dispatch loop, the scheduled update will be removed.
   1721     if (0) {
   1722 #if STUB_ROUTER
   1723     } else if (server_state->stub_router_enabled) {
   1724         host->lease_interval = update->host_lease;
   1725         host->key_lease = update->key_lease;
   1726 #endif
   1727     } else {
   1728         // For the Thread in Mobile use case, use the duration of the key lease to determine when to expire host
   1729         // entries, rather than expiring them when the host lease expires. This is technically out of spec, but
   1730         // accomplishes part of the stated goal of keeping usable cached data around for use immediately after
   1731         // connecting to a Thread mesh.
   1732         host->lease_interval = update->key_lease;
   1733         host->key_lease = update->key_lease;
   1734     }
   1735 
   1736     // It would probably be harmless to set this for replications, since the value currently wouldn't change,
   1737     // but to avoid future issues we only set this if it's a direct SRP update and not a replicated update.
   1738     // We know it's a direct SRP update because host->message->lease is zero. It would not be zero if we
   1739     // had received this as an SRP update, but is always zero when received directly via UDP.
   1740     INFO("host->message->lease = %d, host->lease_interval = %d, host->key_lease = %d",
   1741          host->message->lease, host->lease_interval, host->key_lease);
   1742     if (host->message->lease == 0) {
   1743         host->message->lease = host->lease_interval;
   1744         host->message->key_lease = host->key_lease;
   1745     }
   1746 
   1747     // We want the lease expiry event to fire the next time the lease on any instance expires, or
   1748     // at the time the lease for the current update would expire, whichever is sooner.
   1749     int64_t next_lease_expiry = INT64_MAX;
   1750     int64_t now = ioloop_timenow();
   1751 
   1752 #define LEASE_EXPIRY_DEBUGGING 1
   1753     // update->lease_expiry is nonzero if we are re-doing a previous registration.
   1754     if (update->lease_expiry != 0) {
   1755         if (update->lease_expiry < now) {
   1756 #ifdef LEASE_EXPIRY_DEBUGGING
   1757             ERROR("lease expiry for host " PRI_S_SRP " happened %" PRIu64 " milliseconds ago.",
   1758                   host->registered_name, now - update->lease_expiry);
   1759 #endif
   1760             // Expire the lease when next we hit the run loop
   1761             next_lease_expiry = now;
   1762         } else {
   1763 #ifdef LEASE_EXPIRY_DEBUGGING
   1764             INFO("lease_expiry (1) for host " PRI_S_SRP " set to %" PRId64, host->name,
   1765                  (int64_t)(update->lease_expiry - now));
   1766 #endif
   1767             next_lease_expiry = update->lease_expiry;
   1768         }
   1769         host->lease_expiry = update->lease_expiry;
   1770     }
   1771     // This is the more usual case.
   1772     else {
   1773 #ifdef LEASE_EXPIRY_DEBUGGING
   1774         INFO("lease_expiry (2) for host " PRI_S_SRP " set to %ld", host->name, (host->lease_interval - lease_offset) * 1000);
   1775 #endif
   1776         next_lease_expiry = now + (host->lease_interval - lease_offset) * 1000;
   1777         if (next_lease_expiry < now) {
   1778             next_lease_expiry = now;
   1779         }
   1780         host->lease_expiry = next_lease_expiry;
   1781     }
   1782 
   1783     // We're doing two things here: setting the lease expiry on instances that were touched by the current
   1784     // update, and also finding the soonest update.
   1785     for (i = 0; i < host->instances->num; i++) {
   1786         adv_instance_t *instance = host->instances->vec[i];
   1787 
   1788         if (instance != NULL) {
   1789             // This instance was updated by the current update, so set its lease time to
   1790             // next_lease_expiry.
   1791             if (instance->message == message) {
   1792                 if (instance->removed) {
   1793 #ifdef LEASE_EXPIRY_DEBUGGING
   1794                     INFO("lease_expiry (7) for host " PRI_S_SRP " removed instance " PRI_S_SRP "." PRI_S_SRP
   1795                          " left at %" PRId64, host->name, instance->instance_name, instance->service_type,
   1796                          (int64_t)(instance->lease_expiry - now));
   1797 #endif
   1798                 } else {
   1799 #ifdef LEASE_EXPIRY_DEBUGGING
   1800                     INFO("lease_expiry (4) for host " PRI_S_SRP " instance " PRI_S_SRP "." PRI_S_SRP " set to %" PRId64,
   1801                          host->name, instance->instance_name, instance->service_type,
   1802                          (int64_t)(host->lease_expiry - now));
   1803 #endif
   1804                     instance->lease_expiry = host->lease_expiry;
   1805                 }
   1806             }
   1807             // Instance was not updated by this update, so see if it expires sooner than this update
   1808             // (which is likely).
   1809             else if (instance->lease_expiry > now && instance->lease_expiry < next_lease_expiry) {
   1810 #ifdef LEASE_EXPIRY_DEBUGGING
   1811                 INFO("lease_expiry (3) for host " PRI_S_SRP " instance " PRI_S_SRP "." PRI_S_SRP " set to %" PRId64,
   1812                      host->name, instance->instance_name, instance->service_type,
   1813                      (int64_t)(instance->lease_expiry - now));
   1814 #endif
   1815                 next_lease_expiry = instance->lease_expiry;
   1816             } else {
   1817                 if (instance->lease_expiry <= now) {
   1818 #ifdef LEASE_EXPIRY_DEBUGGING
   1819                     INFO("lease_expiry (5) for host " PRI_S_SRP " instance " PRI_S_SRP "." PRI_S_SRP
   1820                          " in the past at %" PRId64,
   1821                          host->name, instance->instance_name, instance->service_type,
   1822                          (int64_t)(now - instance->lease_expiry));
   1823 #endif
   1824                     next_lease_expiry = now;
   1825 #ifdef LEASE_EXPIRY_DEBUGGING
   1826                 } else {
   1827                     INFO("lease_expiry (6) for host " PRI_S_SRP " instance " PRI_S_SRP "." PRI_S_SRP
   1828                          " is later than next_lease_expiry by %" PRId64, host->name, instance->instance_name,
   1829                          instance->service_type, (int64_t)(next_lease_expiry - instance->lease_expiry));
   1830 
   1831 #endif
   1832                 }
   1833             }
   1834         }
   1835     }
   1836 
   1837     // Now set a timer for the next lease expiry.
   1838     uint64_t when = next_lease_expiry - now;
   1839     if (when > INT32_MAX) {
   1840         when = INT32_MAX;
   1841     }
   1842 
   1843     if (next_lease_expiry == now) {
   1844         INFO("scheduling immediate call to lease_callback in the run loop for " PRI_S_SRP, host->name);
   1845         ioloop_run_async(lease_callback, host);
   1846     } else {
   1847         INFO("scheduling wakeup to lease_callback in %" PRIu64 " for host " PRI_S_SRP,
   1848              when / 1000, host->name);
   1849         ioloop_add_wake_event(host->lease_wakeup, host, lease_callback, srp_adv_host_context_release, (uint32_t)when);
   1850         RETAIN_HERE(host, adv_host);
   1851     }
   1852 
   1853     // Instance vectors can hold circular references to the update object, which won't get freed until we call
   1854     // adv_update_finalize, which we will never do because of the circular reference. So break any remaining
   1855     // circular references before releasing the update.
   1856     adv_update_free_instance_vectors(update);
   1857 
   1858     // This is letting go of the reference we retained earlier in this function, not some outstanding reference retained elsewhere.
   1859     RELEASE_HERE(update, adv_update);
   1860 
   1861     // If we were processing an SRP update, we may have additional updates to do. Start the next one now if so.
   1862     if (remaining_updates != NULL) {
   1863         srp_update_start(remaining_updates);
   1864     } else {
   1865         srp_dump_server_stats(server_state, false, false);
   1866     }
   1867 }
   1868 
   1869 #ifdef USE_DNSSERVICE_QUEUING
   1870 static void
   1871 process_dnsservice_error(adv_update_t *update, int err)
   1872 {
   1873     if (err != kDNSServiceErr_NoError) {
   1874         update_failed(update, dns_rcode_servfail, true, true);
   1875         if (err == kDNSServiceErr_ServiceNotRunning || err == kDNSServiceErr_DefunctConnection || err == 1) {
   1876             if (err == 1) {
   1877                 FAULT("bogus error code 1");
   1878             }
   1879             if (update->host != NULL) {
   1880                 if (update->host->server_state != NULL) {
   1881                     service_disconnected(update->host->server_state,
   1882                                          (intptr_t)update->host->server_state->shared_registration_txn);
   1883                 }
   1884                 wait_retry(update->host);
   1885             }
   1886         }
   1887     }
   1888 }
   1889 #endif // USE_DNSSERVICE_QUEUING
   1890 
   1891 #define GENERATE_WAKEUP(ptr)                  \
   1892     if ((*ptr) == NULL) {                     \
   1893         (*ptr) = ioloop_wakeup_create();      \
   1894     }                                         \
   1895     if ((*ptr) == NULL) {                     \
   1896         ERROR("unable to make wakeup " #ptr); \
   1897     } else
   1898 
   1899 static void
   1900 srp_instance_retry_callback(void *context)
   1901 {
   1902     adv_instance_t *instance = context;
   1903     adv_host_t *host = instance->host;
   1904     if (host == NULL || host->removed) {
   1905         INFO("no longer updating instance %p because host is no longer valid.", instance);
   1906         return;
   1907     }
   1908     INFO("re-registering updating instance %p.", instance);
   1909     register_instance(instance);
   1910 }
   1911 
   1912 static void
   1913 srp_schedule_instance_retry(adv_instance_t *instance)
   1914 {
   1915     GENERATE_WAKEUP(&instance->retry_wakeup) {
   1916         if (instance->wakeup_interval == 0) {
   1917             instance->wakeup_interval = 5 * 1000;
   1918         } else {
   1919             instance->wakeup_interval *= 2;
   1920         }
   1921         unsigned interval = instance->wakeup_interval * 1.5 - (srp_random32() % instance->wakeup_interval);
   1922         RETAIN_HERE(instance, adv_instance);
   1923         ioloop_add_wake_event(instance->retry_wakeup, instance, srp_instance_retry_callback, adv_instance_context_release, interval);
   1924         INFO("will attempt to reregister instance %p in %.3lf seconds", instance, ((double)interval) / 1000.0);
   1925     }
   1926 }
   1927 
   1928 static void
   1929 srp_host_record_retry_callback(void *context)
   1930 {
   1931     adv_host_t *host = context;
   1932     if (host != NULL) {
   1933         host->re_register_pending = false;
   1934     }
   1935     if (host == NULL || host->removed) {
   1936         INFO("no longer updating host %p because host is no longer valid.", host);
   1937         return;
   1938     }
   1939 
   1940     if (host->addresses != NULL) {
   1941         for (int i = 0; i < host->addresses->num; i++) {
   1942             adv_record_t *record = host->addresses->vec[i];
   1943             if (record != NULL) {
   1944                 INFO("re-registering host record %p.", record);
   1945                 register_host_record(host, record, false);
   1946             }
   1947         }
   1948     }
   1949     if (host->key_record != NULL) {
   1950         INFO("re-registering host record %p.", host->key_record);
   1951         register_host_record(host, host->key_record, false);
   1952     }
   1953 }
   1954 
   1955 static void
   1956 srp_schedule_host_record_retry(adv_record_t *record)
   1957 {
   1958     // If the host isn't valid or we're already re-registering, don't schedule a retry.
   1959     if (record->host == NULL || record->host->removed) {
   1960         INFO("will not attempt to reregister record %p", record);
   1961         return;
   1962     }
   1963     if (record->host->re_register_pending) {
   1964         INFO("already scheduled attempt to reregister record %p", record);
   1965         return;
   1966     }
   1967 
   1968     adv_host_t *host = record->host;
   1969     GENERATE_WAKEUP(&host->re_register_wakeup) {
   1970         if (host->wakeup_interval == 0) {
   1971             host->wakeup_interval = 5 * 1000;
   1972         } else {
   1973             host->wakeup_interval *= 2;
   1974         }
   1975         unsigned interval = host->wakeup_interval * 1.5 - (srp_random32() % host->wakeup_interval);
   1976         RETAIN_HERE(host, adv_host);
   1977         ioloop_add_wake_event(host->re_register_wakeup, host, srp_host_record_retry_callback, srp_adv_host_context_release, interval);
   1978         INFO("will attempt to reregister record %p in %.3lf seconds", record, ((double)interval) / 1000.0);
   1979     }
   1980 }
   1981 
   1982 
   1983 // When the host registration has completed, we get this callback.   Completion either means that we succeeded in
   1984 // registering the record, or that something went wrong and the registration has failed.
   1985 static void
   1986 register_instance_completion(DNSServiceRef sdref, DNSServiceFlags flags, DNSServiceErrorType error_code,
   1987                              const char *name, const char *regtype, const char *domain, void *context)
   1988 {
   1989     (void)flags;
   1990     (void)sdref;
   1991     adv_instance_t *instance = context;
   1992     adv_update_t *update = instance->update;
   1993     adv_host_t *host = instance->host;
   1994 
   1995     // Retain the instance for the life of this function, just in case we release stuff that is holding the last reference to it.
   1996     RETAIN_HERE(instance, adv_instance);
   1997 
   1998     // It's possible that we could restart a host update due to an error while a callback is still pending on a stale
   1999     // update.  In this case, we just cancel all of the work that's been done on the stale update (it's probably already
   2000     // moot anyway.
   2001     if (update != NULL && host->update != update) {
   2002         INFO("registration for service " PRI_S_SRP "." PRI_S_SRP " completed with invalid state.", name, regtype);
   2003         RELEASE_HERE(instance->update, adv_update);
   2004         instance->update = NULL;
   2005         RELEASE_HERE(instance, adv_instance);
   2006         return;
   2007     }
   2008 
   2009     // We will generally get a callback on success or failure of the initial registration; this is what causes
   2010     // the update to complete or fail. We may get subsequent callbacks because of name conflicts. So the first
   2011     // time we get a callback, instance->update will always be valid; thereafter, it will not, so null it out.
   2012     if (update != NULL) {
   2013         RETAIN_HERE(update, adv_update); // We need to hold onto this until we are done with the update.
   2014         RELEASE_HERE(instance->update, adv_update);
   2015         instance->update = NULL;
   2016     }
   2017 
   2018     if (error_code == kDNSServiceErr_NoError || error_code == kDNSServiceErr_NameConflict) {
   2019         INFO("registration for service " PRI_S_SRP "." PRI_S_SRP "." PRI_S_SRP " -> "
   2020              PRI_S_SRP " has completed" PUB_S_SRP ".", instance->instance_name, instance->service_type, domain,
   2021              host->registered_name, error_code == kDNSServiceErr_NoError ? ":" : " with a conflict");
   2022         INFO("registration is under " PRI_S_SRP "." PRI_S_SRP PRI_S_SRP, name, regtype,
   2023              domain);
   2024 
   2025         if (error_code != kDNSServiceErr_NoError) {
   2026             if (instance->txn == NULL) {
   2027                 FAULT("instance->txn is NULL for instance %p!", instance);
   2028             } else {
   2029                 ioloop_dnssd_txn_cancel_srp(host->server_state, instance->txn);
   2030                 ioloop_dnssd_txn_release(instance->txn);
   2031                 instance->txn = NULL;
   2032             }
   2033             srp_schedule_instance_retry(instance);
   2034         }
   2035 
   2036         // In principle update->instance should always be non-NULL here because a no-error response should
   2037         // only happen once or not at all. But just to be safe...
   2038         if (update != NULL) {
   2039             if (instance->update_pending) {
   2040                 if (update->client != NULL) {
   2041                     instance->recent_message = (ptrdiff_t)update->client->message; // for comparison later in srp_mdns_update_finished
   2042                 }
   2043                 update->num_instances_completed++;
   2044                 if (update->num_records_completed == update->num_records_started &&
   2045                     update->num_instances_completed == update->num_instances_started)
   2046                 {
   2047                     srp_mdns_update_finished(update);
   2048                 }
   2049                 RELEASE_HERE(update, adv_update);
   2050                 instance->update_pending = false;
   2051                 update = NULL;
   2052             }
   2053         } else {
   2054             INFO("re-update succeeded for instance " PRI_S_SRP " (" PRI_S_SRP
   2055                   " " PRI_S_SRP " " PRI_S_SRP ")", instance->instance_name, name, regtype, domain);
   2056         }
   2057     } else {
   2058         INFO("registration for service " PRI_S_SRP "." PRI_S_SRP "." PRI_S_SRP " -> "
   2059              PRI_S_SRP " failed with code %d", instance->instance_name, instance->service_type, domain,
   2060              host->registered_name, error_code);
   2061 
   2062         // If the reason this failed is that we couldn't talk to mDNSResponder, or mDNSResponder disconnected, then we want to retry
   2063         // later on in the hopes that mDNSResponder will come back.
   2064         if (error_code == kDNSServiceErr_ServiceNotRunning || error_code == kDNSServiceErr_DefunctConnection) {
   2065             service_disconnected(host->server_state, instance->shared_txn);
   2066             instance->shared_txn = 0;
   2067             wait_retry(host);
   2068         } else {
   2069             if (update != NULL) {
   2070                 update_failed(update, (error_code == kDNSServiceErr_NameConflict
   2071                                        ? dns_rcode_yxdomain
   2072                                        : dns_rcode_servfail), true, true);
   2073                 if (instance->update != NULL) {
   2074                     RELEASE_HERE(instance->update, adv_update);
   2075                     instance->update = NULL;
   2076                 }
   2077                 RELEASE_HERE(update, adv_update);
   2078             } else {
   2079             }
   2080         }
   2081 
   2082         // The transaction still holds a reference to the instance. instance->txn should never be NULL here. When we cancel
   2083         // the transaction, the reference the transaction held on the instance will be released.
   2084         if (instance->txn == NULL) {
   2085             FAULT("instance->txn is NULL for instance %p!", instance);
   2086         } else {
   2087             ioloop_dnssd_txn_cancel_srp(host->server_state, instance->txn);
   2088             ioloop_dnssd_txn_release(instance->txn);
   2089             instance->txn = NULL;
   2090         }
   2091     }
   2092     RELEASE_HERE(instance, adv_instance);
   2093 }
   2094 
   2095 static bool
   2096 extract_instance_name(char *instance_name, size_t instance_name_max,
   2097                       char *service_type, size_t service_type_max, service_instance_t *instance)
   2098 {
   2099     dns_name_t *end_of_service_type = instance->service->rr->name->next;
   2100     size_t service_index;
   2101     service_t *service, *base_type;
   2102     if (end_of_service_type != NULL) {
   2103         if (end_of_service_type->next != NULL) {
   2104             end_of_service_type = end_of_service_type->next;
   2105         }
   2106     }
   2107     dns_name_print_to_limit(instance->service->rr->name, end_of_service_type, service_type, service_type_max);
   2108 
   2109     // It's possible that the registration might include subtypes. If so, we need to convert them to the
   2110     // format that DNSServiceRegister expects: service_type,subtype,subtype...
   2111     service_index = strlen(service_type);
   2112     base_type = instance->service->base_type;
   2113     for (service = instance->service->next; service != NULL && service->base_type == base_type; service = service->next)
   2114     {
   2115         if (service_index + service->rr->name->len + 2 > service_type_max) {
   2116             ERROR("service name: " PRI_S_SRP " is too long for additional subtype " PRI_S_SRP,
   2117                   service_type, service->rr->name->data);
   2118             return false;
   2119         }
   2120         service_type[service_index++] = ',';
   2121         memcpy(&service_type[service_index], service->rr->name->data, service->rr->name->len + 1);
   2122         service_index += service->rr->name->len;
   2123     }
   2124 
   2125     // Make a presentation-format version of the service instance name.
   2126     dns_name_print_to_limit(instance->name, instance->name != NULL ? instance->name->next : NULL,
   2127                             instance_name, instance_name_max);
   2128     return true;
   2129 }
   2130 
   2131 void
   2132 srp_format_time_offset(char *buf, size_t buf_len, time_t offset)
   2133 {
   2134     struct tm tm_now;
   2135     time_t when = time(NULL) - offset;
   2136     localtime_r(&when, &tm_now);
   2137     strftime(buf, buf_len, "%F %T", &tm_now);
   2138 }
   2139 
   2140 DNSServiceAttributeRef
   2141 srp_message_tsr_attribute_generate(message_t *message, uint32_t key_id, char *time_buf, size_t time_buf_size)
   2142 {
   2143     DNSServiceAttributeRef attribute = DNSServiceAttributeCreate();
   2144     if (attribute == NULL) {
   2145         ERROR("Failed to create new DNSServiceAttributeRef");
   2146     } else {
   2147         uint32_t offset = 0;
   2148 
   2149         if (message != NULL && message->received_time != 0) {
   2150             offset = (uint32_t)(srp_time() - message->received_time);
   2151             srp_format_time_offset(time_buf, time_buf_size, offset);
   2152         } else {
   2153             static char msg[] = "now";
   2154             if (time_buf_size < sizeof(msg)) {
   2155                 FAULT("bogus time buf size %zd", time_buf_size);
   2156                 time_buf[0] = 0;
   2157             } else {
   2158                 memcpy(time_buf, msg, sizeof(msg));
   2159             }
   2160         }
   2161         if (_DNSSD_API_AVAILABLE_FALL_2024) {
   2162             DNSServiceAttributeSetHostKeyHash(attribute, key_id);
   2163         }
   2164         DNSServiceAttributeSetTimestamp(attribute, offset);
   2165     }
   2166     return attribute;
   2167 }
   2168 
   2169 DNSServiceAttributeRef
   2170 srp_adv_instance_tsr_attribute_generate(adv_instance_t *instance, char *time_buf, size_t time_buf_size)
   2171 {
   2172     message_t *message = NULL;
   2173     if (instance->update != NULL && instance->update->client != NULL && instance->update->client->message != NULL) {
   2174         message = instance->update->client->message;
   2175     } else if (instance->update == NULL && instance->message != NULL) {
   2176         message = instance->message;
   2177     }
   2178     return srp_message_tsr_attribute_generate(message, instance->host->key_id, time_buf, time_buf_size);
   2179 }
   2180 
   2181 static bool
   2182 register_instance(adv_instance_t *instance)
   2183 {
   2184     int err = kDNSServiceErr_Unknown;
   2185     bool exit_status = false;
   2186     srp_server_t *server_state = instance->host->server_state;
   2187 
   2188     // If we don't yet have a shared connection, create one.
   2189     if (!srp_mdns_shared_registration_txn_setup(server_state)) {
   2190         goto exit;
   2191     }
   2192     DNSServiceRef service_ref = server_state->shared_registration_txn->sdref;
   2193 
   2194     INFO(PUB_S_SRP "DNSServiceRegister(%p, " PRI_S_SRP ", " PRI_S_SRP ", " PRI_S_SRP ", %d, %p)",
   2195          instance->skip_update ? "skipping " : "", service_ref, instance->instance_name, instance->service_type,
   2196          instance->host->registered_name, instance->port, instance);
   2197 
   2198     if (instance->skip_update) {
   2199         if (instance->update->client != NULL) {
   2200             instance->recent_message = (ptrdiff_t)instance->update->client->message; // for comparison later in srp_mdns_update_finished
   2201         }
   2202         exit_status = true;
   2203         goto exit;
   2204     }
   2205 
   2206     char time_buf[TSR_TIMESTAMP_STRING_LEN];
   2207     DNSServiceAttributeRef tsr_attribute =
   2208         srp_adv_instance_tsr_attribute_generate(instance, time_buf, sizeof(time_buf));
   2209     if (tsr_attribute == NULL) {
   2210         err = kDNSServiceErr_NoMemory;
   2211     } else {
   2212         uint32_t flags = kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename;
   2213         if (_DNSSD_API_AVAILABLE_FALL_2024) {
   2214             flags |= kDNSServiceFlagsKnownUnique;
   2215         }
   2216         err = dns_service_register_wa(server_state, &service_ref, flags,
   2217                                       server_state->advertise_interface,
   2218                                       instance->instance_name, instance->service_type, local_suffix,
   2219                                       instance->host->registered_name, htons(instance->port), instance->txt_length,
   2220                                       instance->txt_data, tsr_attribute, register_instance_completion, instance);
   2221         DNSServiceAttributeDeallocate(tsr_attribute);
   2222         if (err == kDNSServiceErr_NoError) {
   2223             INFO("DNSServiceRegister, TSR for instance " PRI_S_SRP " host " PRI_S_SRP " set to " PUB_S_SRP
   2224                  "(instance %p sdref %p)", instance->instance_name,
   2225                  instance->host->name == NULL ? "<null>" : instance->host->name, time_buf, instance, service_ref);
   2226         }
   2227     }
   2228 
   2229     // This would happen if we pass NULL for regtype, which we don't, or if we run out of memory, or if
   2230     // the server isn't running; in the second two cases, we can always try again later.
   2231     if (err != kDNSServiceErr_NoError) {
   2232         if (err == kDNSServiceErr_ServiceNotRunning || err == kDNSServiceErr_DefunctConnection ||
   2233             err == kDNSServiceErr_BadParam || err == kDNSServiceErr_BadReference || err == 1)
   2234         {
   2235             if (err == 1) {
   2236                 FAULT("bogus error code 1");
   2237             }
   2238             INFO("DNSServiceRegister failed: " PUB_S_SRP " (instance %p)",
   2239                  err == kDNSServiceErr_ServiceNotRunning ? "not running" : "defunct", instance);
   2240             service_disconnected(server_state, (intptr_t)server_state->shared_registration_txn);
   2241         } else {
   2242             INFO("DNSServiceRegister failed: %d (instance %p)", err, instance);
   2243         }
   2244         goto exit;
   2245     }
   2246     if (instance->update != NULL) {
   2247         instance->update->num_instances_started++;
   2248         instance->update_pending = true;
   2249     }
   2250     // After DNSServiceRegister succeeds, it creates a copy of DNSServiceRef that indirectly uses the shared connection,
   2251     // so we update it here.
   2252     instance->txn = ioloop_dnssd_txn_add_subordinate(service_ref, instance, adv_instance_context_release, NULL);
   2253     if (instance->txn == NULL) {
   2254         ERROR("no memory for instance transaction.");
   2255         goto exit;
   2256     }
   2257     instance->shared_txn = (intptr_t)server_state->shared_registration_txn;
   2258     RETAIN_HERE(instance, adv_instance); // for the callback
   2259     exit_status = true;
   2260 
   2261 exit:
   2262     return exit_status;
   2263 }
   2264 
   2265 // When we get a late name conflict on the hostname, we need to update the host registration and all of the
   2266 // service registrations. To do this, we construct an update and then apply it. If there is already an update
   2267 // in progress, we put this update at the end of the list.
   2268 static void
   2269 update_from_host(adv_host_t *host)
   2270 {
   2271     adv_update_t *update = NULL;
   2272     int i;
   2273 
   2274     if (host->update != NULL) {
   2275         ERROR("already have an update.");
   2276     }
   2277 
   2278     // Allocate the update structure.
   2279     update = calloc(1, sizeof *update);
   2280     if (update == NULL) {
   2281         ERROR("no memory for update.");
   2282         goto fail;
   2283     }
   2284     RETAIN_HERE(update, adv_update);
   2285 
   2286     if (host->addresses != NULL) {
   2287         update->add_addresses = adv_record_vec_copy(host->addresses);
   2288         if (update->add_addresses == NULL) {
   2289             ERROR("no memory for addresses");
   2290             goto fail;
   2291         }
   2292         for (i = 0; i < update->add_addresses->num; i++) {
   2293             if (update->add_addresses->vec[i] != NULL) {
   2294                 update->add_addresses->vec[i]->update = update;
   2295                 RETAIN_HERE(update, adv_update);
   2296             }
   2297         }
   2298     }
   2299 
   2300     // We can never update more instances than currently exist for this host.
   2301     if (host->instances != NULL) {
   2302         update->update_instances = adv_instance_vec_copy(host->instances);
   2303         if (update->update_instances == NULL) {
   2304             ERROR("no memory for update_instances");
   2305             goto fail;
   2306         }
   2307         for (i = 0; i < update->update_instances->num; i++) {
   2308             if (update->update_instances->vec[i] != NULL) {
   2309                 update->update_instances->vec[i]->update = update;
   2310                 RETAIN_HERE(update, adv_update);
   2311             }
   2312         }
   2313 
   2314         // We aren't actually adding or deleting any instances, but...
   2315         update->remove_instances = adv_instance_vec_create(host->instances->num);
   2316         if (update->remove_instances == NULL) {
   2317             ERROR("no memory for remove_instances");
   2318             goto fail;
   2319         }
   2320         update->remove_instances->num = host->instances->num;
   2321 
   2322         update->add_instances = adv_instance_vec_create(host->instances->num);
   2323         if (update->add_instances == NULL) {
   2324             ERROR("no memory for add_instances");
   2325             goto fail;
   2326         }
   2327         update->add_instances->num = host->instances->num;
   2328     }
   2329 
   2330 
   2331     // At this point we have figured out all the work we need to do, so hang it off an update structure.
   2332     update->host = host;
   2333     RETAIN_HERE(update->host, adv_host);
   2334     update->host_lease = host->lease_interval;
   2335     update->key_lease = host->key_lease;
   2336     update->lease_expiry = host->lease_expiry;
   2337 
   2338     // Stash the update on the host.
   2339     host->update = update;
   2340     RETAIN_HERE(host->update, adv_update);  // host gets a reference
   2341     RELEASE_HERE(update, adv_update);       // we're done with our reference.
   2342     start_host_update(host);
   2343     return;
   2344 
   2345 fail:
   2346     if (update != NULL) {
   2347         adv_update_cancel(update);
   2348         RELEASE_HERE(update, adv_update);
   2349     }
   2350     wait_retry(host);
   2351     return;
   2352 }
   2353 
   2354 // When the host registration has completed, we get this callback.   Completion either means that we succeeded in
   2355 // registering the record, or that something went wrong and the registration has failed.
   2356 static void
   2357 register_host_record_completion(DNSServiceRef sdref, DNSRecordRef rref,
   2358                                 DNSServiceFlags flags, DNSServiceErrorType error_code, void *context)
   2359 {
   2360     adv_record_t *record = context;
   2361     adv_host_t *host = NULL;
   2362     adv_update_t *update = NULL;
   2363     (void)sdref;
   2364     (void)rref;
   2365     (void)error_code;
   2366     (void)flags;
   2367 
   2368     // This can happen if for some reason DNSServiceRemoveRecord returns something other than success. In this case, all
   2369     // the cleanup that can be done has already been done, and all we can do is ignore the problem.
   2370     if (record->rref == NULL) {
   2371         ERROR("null rref");
   2372         return;
   2373     }
   2374     // For analyzer, can't actually happen.
   2375     if (record == NULL) {
   2376         ERROR("null record");
   2377         return;
   2378     }
   2379     host = record->host;
   2380     if (host == NULL) {
   2381         ERROR("no host");
   2382         return;
   2383     }
   2384 
   2385     // Make sure record remains valid for the duration of this call.
   2386     RETAIN_HERE(record, adv_record);
   2387 
   2388     // It's possible that we could restart a host update due to an error while a callback is still pending on a stale
   2389     // update.  In this case, we just cancel all of the work that's been done on the stale update (it's probably already
   2390     // moot anyway.
   2391     if (record->update != NULL && host->update != record->update) {
   2392         INFO("registration for host record completed with invalid state.");
   2393         adv_update_cancel(record->update);
   2394         RELEASE_HERE(record->update, adv_update);
   2395         record->update = NULL;
   2396         srp_mdns_shared_record_remove(host->server_state, record); // This will prevent further callbacks and release the reference held by the transaction.
   2397         RELEASE_HERE(record, adv_record); // The callback has a reference to the record.
   2398         RELEASE_HERE(record, adv_record); // Release the reference to the record that we retained at the beginning
   2399         return;
   2400 
   2401     }
   2402     update = record->update;
   2403     if (update != NULL) {
   2404         RETAIN_HERE(update, adv_update);
   2405     }
   2406 
   2407     if (error_code == kDNSServiceErr_NoError || error_code == kDNSServiceErr_NameConflict) {
   2408         // If the update is pending, it means that we just finished registering this record for the first time,
   2409         // so we can count it as complete and check to see if there is any work left to do; if not, we call
   2410         // srp_mdns_update_finished to apply the update to the host object.
   2411         const char *note = " has completed.";
   2412         if (record->update_pending) {
   2413             record->update_pending = false;
   2414             if (update != NULL) {
   2415                 update->num_records_completed++;
   2416                 if (update->num_records_completed == update->num_records_started &&
   2417                     update->num_instances_completed == update->num_instances_started)
   2418                 {
   2419                     srp_mdns_update_finished(update);
   2420                 }
   2421             }
   2422         } else {
   2423             note = " got spurious success callback after completion.";
   2424         }
   2425 
   2426         if (error_code != kDNSServiceErr_NoError) {
   2427             // Shared record is no longer good.
   2428             srp_mdns_shared_record_remove(host->server_state, record);
   2429             note = " completed with conflict.";
   2430             srp_schedule_host_record_retry(record);
   2431         }
   2432 
   2433         if (record->rrtype == dns_rrtype_a) {
   2434             IPv4_ADDR_GEN_SRP(record->rdata, addr_buf);
   2435             INFO("registration for host " PRI_S_SRP " address " PRI_IPv4_ADDR_SRP PUB_S_SRP,
   2436                  host->registered_name, IPv4_ADDR_PARAM_SRP(record->rdata, addr_buf), note);
   2437         } else if (record->rrtype == dns_rrtype_aaaa) {
   2438             SEGMENTED_IPv6_ADDR_GEN_SRP(record->rdata, addr_buf);
   2439             INFO("registration for host " PRI_S_SRP " address " PRI_SEGMENTED_IPv6_ADDR_SRP PUB_S_SRP,
   2440                  host->registered_name, SEGMENTED_IPv6_ADDR_PARAM_SRP(record->rdata, addr_buf), note);
   2441         } else if (record->rrtype == dns_rrtype_key) {
   2442             INFO("registration for host " PRI_S_SRP " key" PUB_S_SRP, host->registered_name, note);
   2443         } else {
   2444             INFO("registration for host " PRI_S_SRP " unknown record type %d " PUB_S_SRP, host->registered_name, record->rrtype, note);
   2445         }
   2446     } else {
   2447         if (record->rrtype == dns_rrtype_a) {
   2448             IPv4_ADDR_GEN_SRP(record->rdata, addr_buf);
   2449             INFO("registration for host " PRI_S_SRP " address " PRI_IPv4_ADDR_SRP " failed, error code = %d.",
   2450              host->registered_name, IPv4_ADDR_PARAM_SRP(record->rdata, addr_buf), error_code);
   2451         } else if (record->rrtype == dns_rrtype_aaaa) {
   2452             SEGMENTED_IPv6_ADDR_GEN_SRP(record->rdata, addr_buf);
   2453             INFO("registration for host " PRI_S_SRP " address " PRI_SEGMENTED_IPv6_ADDR_SRP " failed, error code = %d.",
   2454                  host->registered_name, SEGMENTED_IPv6_ADDR_PARAM_SRP(record->rdata, addr_buf), error_code);
   2455         } else if (record->rrtype == dns_rrtype_key) {
   2456             INFO("registration for host " PRI_S_SRP " key failed, error code = %d.", host->registered_name, error_code);
   2457         } else {
   2458             INFO("registration for host " PRI_S_SRP " unknown record type %d failed, error code = %d.",
   2459                  host->registered_name, record->rrtype, error_code);
   2460         }
   2461 
   2462         // If the reason this failed is that we couldn't talk to mDNSResponder, or mDNSResponder disconnected, then we want to retry
   2463         // later on in the hopes that mDNSResponder will come back.
   2464         if (error_code == kDNSServiceErr_ServiceNotRunning || error_code == kDNSServiceErr_DefunctConnection) {
   2465             service_disconnected(host->server_state, record->shared_txn);
   2466             if (update != NULL) {
   2467                 wait_retry(host);
   2468             }
   2469         } else {
   2470             // The other error we could get is a name conflict. This means that some other advertising proxy or host on
   2471             // the network is advertising the hostname we chose, and either got there first with no TSR record, or got
   2472             // its copy of the host information later than ours. So if we get a name conflict, it's up to the client or
   2473             // the replication peer to make the next move.
   2474 
   2475             if (update != NULL) {
   2476                 update_failed(update, (error_code == kDNSServiceErr_NameConflict
   2477                                        ? dns_rcode_yxdomain
   2478                                        : dns_rcode_servfail), true, true);
   2479             } else {
   2480             }
   2481         }
   2482         // Regardless of what else happens, this transaction is dead, so get rid of our references to it.
   2483         srp_mdns_shared_record_remove(host->server_state, record);
   2484     }
   2485     if (update != NULL) {
   2486         RELEASE_HERE(update, adv_update);
   2487     }
   2488     RELEASE_HERE(record, adv_record); // Release the reference to the record that we retained at the beginning
   2489 }
   2490 
   2491 static adv_instance_t *
   2492 adv_instance_create(service_instance_t *raw, adv_host_t *host, adv_update_t *update)
   2493 {
   2494     char service_type[DNS_MAX_LABEL_SIZE_ESCAPED * 2 + 2]; // sizeof '.' + sizeof '\0'.
   2495     char instance_name[DNS_MAX_NAME_SIZE_ESCAPED + 1];
   2496     uint8_t *txt_data;
   2497 
   2498     // Allocate the raw registration
   2499     adv_instance_t *instance = calloc(1, sizeof *instance);
   2500     if (instance == NULL) {
   2501         ERROR("adv_instance:create: unable to allocate raw registration struct.");
   2502         return NULL;
   2503     }
   2504     RETAIN_HERE(instance, adv_instance);
   2505     instance->host = host;
   2506     RETAIN_HERE(instance->host, adv_host);
   2507     instance->update = update;
   2508     RETAIN_HERE(instance->update, adv_update);
   2509 
   2510     // SRV records have priority, weight and port, but DNSServiceRegister only uses port.
   2511     instance->port = (raw->srv == NULL) ? 0 : raw->srv->data.srv.port;
   2512 
   2513     // Make a presentation-format version of the service name.
   2514     if (!extract_instance_name(instance_name, sizeof instance_name, service_type, sizeof service_type, raw)) {
   2515         RELEASE_HERE(instance, adv_instance);
   2516         return NULL;
   2517     }
   2518 
   2519     instance->instance_name = strdup(instance_name);
   2520     if (instance->instance_name == NULL) {
   2521         ERROR("adv_instance:create: unable to allocate instance name.");
   2522         RELEASE_HERE(instance, adv_instance);
   2523         return NULL;
   2524     }
   2525     instance->service_type = strdup(service_type);
   2526     if (instance->service_type == NULL) {
   2527         ERROR("adv_instance:create: unable to allocate instance type.");
   2528         RELEASE_HERE(instance, adv_instance);
   2529         return NULL;
   2530     }
   2531 
   2532     // Allocate the text record buffer
   2533     if (raw->txt != NULL) {
   2534         txt_data = malloc(raw->txt->data.txt.len);
   2535         if (txt_data == NULL) {
   2536             RELEASE_HERE(instance, adv_instance);
   2537             ERROR("adv_instance:create: unable to allocate txt_data buffer");
   2538             return NULL;
   2539         }
   2540         // Format the txt buffer as required by DNSServiceRegister().
   2541         memcpy(txt_data, raw->txt->data.txt.data, raw->txt->data.txt.len);
   2542         instance->txt_data = txt_data;
   2543         instance->txt_length = raw->txt->data.txt.len;
   2544     } else {
   2545         instance->txt_data = NULL;
   2546         instance->txt_length = 0;
   2547     }
   2548 
   2549     // If the service_instance_t is marked to skip updating, mark the adv_instance_t as well.
   2550     instance->skip_update = raw->skip_update;
   2551 
   2552     return instance;
   2553 }
   2554 
   2555 #define adv_record_create(rrtype, rdlen, rdata, host) \
   2556     adv_record_create_(rrtype, rdlen, rdata, host, __FILE__, __LINE__)
   2557 static adv_record_t *
   2558 adv_record_create_(uint16_t rrtype, uint16_t rdlen, uint8_t *rdata, adv_host_t *host, const char *file, int line)
   2559 {
   2560 
   2561     adv_record_t *new_record = calloc(1, sizeof(*new_record) + rdlen - 1);
   2562     if (new_record == NULL) {
   2563         ERROR("no memory for new_record");
   2564         return NULL;
   2565     }
   2566     new_record->rdata = malloc(rdlen);
   2567     if (new_record->rdata == NULL) {
   2568         ERROR("no memory for new_record->rdata");
   2569         free(new_record);
   2570         return NULL;
   2571     }
   2572     new_record->host = host;
   2573     RETAIN(host, adv_host);
   2574     new_record->rrtype = rrtype;
   2575     new_record->rdlen = rdlen;
   2576     memcpy(new_record->rdata, rdata, rdlen);
   2577     RETAIN(new_record, adv_record);
   2578     return new_record;
   2579 }
   2580 
   2581 // Given a pair of service types which may or may not have subtypes, e.g. _foo._tcp, which doesn't have subtypes, or
   2582 // _foo.tcp,bar, which does, return true if type1 matches the type2 for the base type, ignoring subtypes.
   2583 static bool
   2584 service_types_equal(const char *type1, const char *type2)
   2585 {
   2586     size_t len1;
   2587     char *comma1 = strchr(type1, ',');
   2588     if (comma1 == NULL) {
   2589         len1 = strlen(type1);
   2590     } else {
   2591         len1 = comma1 - type1;
   2592     }
   2593     char *comma2 = strchr(type2, ',');
   2594     size_t len2;
   2595     if (comma2 != NULL) {
   2596         len2 = comma2 - type2;
   2597     } else {
   2598         len2 = strlen(type2);
   2599     }
   2600     if (len1 != len2) {
   2601         return false;
   2602     }
   2603     if (memcmp(type2, type1, len1)) {
   2604         return false;
   2605     }
   2606     return true;
   2607 }
   2608 
   2609 DNSServiceAttributeRef
   2610 srp_adv_host_tsr_attribute_generate(adv_host_t *host, char *time_buf, size_t time_buf_size)
   2611 {
   2612     message_t *message = NULL;
   2613     if (host->update != NULL && host->update->client != NULL && host->update->client->message != NULL) {
   2614         message = host->update->client->message;
   2615     } else if (host->update == NULL && host->message != NULL) {
   2616         message = host->message;
   2617     }
   2618     return srp_message_tsr_attribute_generate(message, host->key_id, time_buf, time_buf_size);
   2619 }
   2620 
   2621 static bool
   2622 register_host_record(adv_host_t *host, adv_record_t *record, bool skipping)
   2623 {
   2624     int err;
   2625 
   2626     // If this record is already registered, get rid of the old transaction.
   2627     if (record->rref != NULL && !skipping) {
   2628         srp_mdns_shared_record_remove(host->server_state, record);
   2629     }
   2630 
   2631     // If we don't yet have a shared connection, create one.
   2632     if (!srp_mdns_shared_registration_txn_setup(host->server_state)) {
   2633         return false;
   2634     }
   2635 
   2636     const DNSServiceRef service_ref = host->server_state->shared_registration_txn->sdref;
   2637 
   2638     if (record->rrtype == dns_rrtype_a) {
   2639         IPv4_ADDR_GEN_SRP(record->rdata, rdata_buf);
   2640         INFO(PUB_S_SRP "DNSServiceRegisterRecord(%p %p %d %d %s %d %d %d " PRI_IPv4_ADDR_SRP " %d %p %p)",
   2641              skipping ? "skipping " : "", service_ref, &record->rref, kDNSServiceFlagsShared,
   2642              host->server_state->advertise_interface, host->registered_name, record->rrtype, dns_qclass_in,
   2643              record->rdlen, IPv4_ADDR_PARAM_SRP(record->rdata, rdata_buf),
   2644              ADDRESS_RECORD_TTL, register_host_record_completion, record);
   2645     } else if (record->rrtype == dns_rrtype_aaaa) {
   2646         SEGMENTED_IPv6_ADDR_GEN_SRP(record->rdata, rdata_buf);
   2647         INFO(PUB_S_SRP "DNSServiceRegisterRecord(%p %p %d %d %s %d %d %d " PRI_SEGMENTED_IPv6_ADDR_SRP " %d %p %p)",
   2648              skipping ? "skipping " : "", service_ref, &record->rref, kDNSServiceFlagsShared,
   2649              host->server_state->advertise_interface, host->registered_name, record->rrtype, dns_qclass_in,
   2650              record->rdlen, SEGMENTED_IPv6_ADDR_PARAM_SRP(record->rdata, rdata_buf),
   2651              ADDRESS_RECORD_TTL, register_host_record_completion, record);
   2652     } else {
   2653         INFO(PUB_S_SRP "DNSServiceRegisterRecord(%p %p %d %d %s %d %d %d %p %d %p %p)",
   2654              skipping ? "skipping " : "", service_ref, &record->rref,
   2655              kDNSServiceFlagsShared,
   2656              host->server_state->advertise_interface, host->registered_name,
   2657              record->rrtype, dns_qclass_in, record->rdlen, record->rdata, ADDRESS_RECORD_TTL,
   2658              register_host_record_completion, record);
   2659     }
   2660     // If we're skipping, we don't actually have to do any work.
   2661     if (skipping) {
   2662         return true;
   2663     }
   2664 
   2665     char time_buf[TSR_TIMESTAMP_STRING_LEN];
   2666     DNSServiceAttributeRef tsr_attribute =
   2667         srp_adv_host_tsr_attribute_generate(host, time_buf, sizeof(time_buf));
   2668     if (tsr_attribute == NULL) {
   2669         ERROR("Failed to create new DNSServiceAttributeRef");
   2670         return false;
   2671     } else {
   2672         err = dns_service_register_record_wa(host->server_state, service_ref, &record->rref,
   2673                                              kDNSServiceFlagsKnownUnique,
   2674                                              host->server_state->advertise_interface, host->registered_name,
   2675                                              record->rrtype, dns_qclass_in, record->rdlen, record->rdata,
   2676                                              ADDRESS_RECORD_TTL, tsr_attribute, register_host_record_completion,
   2677                                              record);
   2678         DNSServiceAttributeDeallocate(tsr_attribute);
   2679         if (err == kDNSServiceErr_NoError) {
   2680             INFO("DNSServiceRegisterRecord for " PRI_S_SRP ", TSR set to " PUB_S_SRP " (record %p rref %p)",
   2681                  host->name, time_buf, record, record->rref);
   2682         }
   2683     }
   2684 
   2685     if (err != kDNSServiceErr_NoError) {
   2686         if (err == kDNSServiceErr_ServiceNotRunning || err == kDNSServiceErr_DefunctConnection ||
   2687             err == kDNSServiceErr_BadParam || err == kDNSServiceErr_BadReference || err == 1)
   2688         {
   2689             if (err == 1) { // This is for an old bug that probably doesn't happen anymore.
   2690                 FAULT("bogus error code 1");
   2691             }
   2692             INFO("DNSServiceRegisterRecord failed on host " PUB_S_SRP ": " PUB_S_SRP " (record %p)", host->name,
   2693                  err == kDNSServiceErr_ServiceNotRunning ? "not running" : "defunct", record);
   2694             service_disconnected(host->server_state, (intptr_t)host->server_state->shared_registration_txn);
   2695         } else {
   2696             INFO("DNSServiceRegisterRecord failed: %d (record %p)", err, record);
   2697         }
   2698         return false;
   2699     }
   2700     record->shared_txn = (intptr_t)host->server_state->shared_registration_txn;
   2701     RETAIN_HERE(record, adv_record); // for the callback
   2702     if (host->update != NULL) {
   2703         record->update_pending = true;
   2704     }
   2705     return true;
   2706 }
   2707 
   2708 static bool
   2709 update_instance_tsr(adv_instance_t *instance, adv_instance_t *new_instance)
   2710 {
   2711     int err = kDNSServiceErr_NoError;
   2712     bool success = false;
   2713 
   2714     if (instance->txn == NULL) {
   2715         ERROR("txn is NULL updating instance TSR.");
   2716         goto out;
   2717     }
   2718     if (instance->txn->sdref == NULL) {
   2719         ERROR("sdref is NULL when updating instance TSR.");
   2720         goto out;
   2721     }
   2722     // Currently if we want to update the rdata, we need to do that separately from the TSR.
   2723     if (new_instance != NULL) {
   2724         if (instance->skip_update) {
   2725             err = kDNSServiceErr_NoError;
   2726         } else {
   2727             err = dns_service_update_record(instance->host->server_state, instance->txn->sdref,
   2728                                             NULL, 0, new_instance->txt_length, new_instance->txt_data, 0);
   2729         }
   2730         if (err != kDNSServiceErr_NoError) {
   2731             INFO("DNSServiceUpdateRecord for instance " PRI_S_SRP " TXT record failed: %d (instance %p)",
   2732                  instance->instance_name, err, instance);
   2733             goto out;
   2734         } else {
   2735             INFO("updated TXT record for " PRI_S_SRP " . " PRI_S_SRP " (instance %p sdref %p).",
   2736                  instance->instance_name, instance->service_type, instance, instance->txn->sdref);
   2737             success = true;
   2738         }
   2739     }
   2740 
   2741     DNSServiceAttributeRef attr;
   2742 
   2743     if (instance->skip_update) {
   2744         INFO("skipping DNSServiceUpdateRecord for instance " PRI_S_SRP " TSR (instance %p)",
   2745              instance->instance_name, instance);
   2746     } else {
   2747         success = false;
   2748         attr = DNSServiceAttributeCreate();
   2749         if (attr == NULL) {
   2750             ERROR("failed to create new DNSServiceAttributeRef");
   2751         } else {
   2752             uint32_t offset = 0;
   2753             char time_buf[TSR_TIMESTAMP_STRING_LEN];
   2754             if (instance->update != NULL && instance->update->client != NULL && instance->update->client->message != NULL &&
   2755                 instance->update->client->message->received_time != 0)
   2756             {
   2757                 offset = (uint32_t)(srp_time() - instance->update->client->message->received_time);
   2758                 srp_format_time_offset(time_buf, sizeof(time_buf), offset);
   2759             } else {
   2760                 static char msg[] = "now";
   2761                 memcpy(time_buf, msg, sizeof(msg));
   2762             }
   2763             if (_DNSSD_API_AVAILABLE_FALL_2024) {
   2764                 DNSServiceAttributeSetHostKeyHash(attr, instance->host->key_id);
   2765             }
   2766             DNSServiceAttributeSetTimestamp(attr, offset);
   2767             err = dns_service_update_record_wa(instance->host->server_state,
   2768                                                instance->txn->sdref, NULL, 0, 0, NULL, 0, attr);
   2769             DNSServiceAttributeDeallocate(attr);
   2770             if (err == kDNSServiceErr_NoError) {
   2771                 INFO("DNSServiceUpdateRecord for " PRI_S_SRP ", TSR set to " PUB_S_SRP " (instance %p sdref %p)",
   2772                      instance->host == NULL ? "<null>" : instance->host->name, time_buf, instance, instance->txn->sdref);
   2773                 success = true;
   2774             } else {
   2775                 INFO("DNSServiceUpdateRecord for instance " PRI_S_SRP ", TSR failed: %d (instance %p sdref %p)",
   2776                      instance->instance_name, err, instance, instance->txn->sdref);
   2777             }
   2778         }
   2779     }
   2780 
   2781 out:
   2782     if (success == false) {
   2783         if (instance->txn != NULL) {
   2784             // We should never get a bad reference error.
   2785             if (err == kDNSServiceErr_BadReference || err == kDNSServiceErr_BadParam) {
   2786                 FAULT("we got a bad reference error: why?");
   2787             }
   2788             // For all errors, we should cancel and release the transaction.
   2789             ioloop_dnssd_txn_cancel_srp(instance->host->server_state, instance->txn);
   2790             ioloop_dnssd_txn_release(instance->txn);
   2791             instance->txn = NULL;
   2792         }
   2793     } else if (new_instance != NULL) {
   2794         // If we have new_instance, the caller is going to get rid of it, so we need to
   2795         // steal the (possibly changed) data from it and put it on instance.
   2796         free(instance->txt_data);
   2797         instance->txt_data = new_instance->txt_data;
   2798         instance->txt_length = new_instance->txt_length;
   2799         new_instance->txt_data = NULL;
   2800         new_instance->txt_length = 0;
   2801     }
   2802     return success;
   2803 }
   2804 
   2805 static void
   2806 update_host_tsr(adv_record_t *record, adv_update_t *update)
   2807 {
   2808     DNSServiceAttributeRef attr;
   2809     int err;
   2810     dnssd_txn_t *shared_txn;
   2811 
   2812     if (record->host == NULL || record->rref == NULL) {
   2813         ERROR("record->host[%p], record->rref[%p] when we update host TSR.", record->host, record->rref);
   2814         return;
   2815     }
   2816 
   2817     shared_txn = record->host->server_state->shared_registration_txn;
   2818     if (shared_txn == NULL) {
   2819         ERROR("shared_txn is NULL when we update host TSR.");
   2820         return;
   2821     }
   2822     if (shared_txn->sdref == NULL) {
   2823         ERROR("shared_txn->sdref is NULL when we update host TSR.");
   2824         return;
   2825     }
   2826 
   2827     attr = DNSServiceAttributeCreate();
   2828     if (attr == NULL) {
   2829         ERROR("failed to create new DNSServiceAttributeRef");
   2830     } else {
   2831         uint32_t offset = 0;
   2832         char time_buf[TSR_TIMESTAMP_STRING_LEN];
   2833         if (update->client != NULL && update->client->message != NULL && update->client->message->received_time != 0) {
   2834             offset = (uint32_t)(srp_time() - update->client->message->received_time);
   2835             srp_format_time_offset(time_buf, sizeof(time_buf), offset);
   2836         } else {
   2837             static char msg[] = "now";
   2838             memcpy(time_buf, msg, sizeof(msg));
   2839         }
   2840         if (_DNSSD_API_AVAILABLE_FALL_2024) {
   2841             DNSServiceAttributeSetHostKeyHash(attr, record->host->key_id);
   2842         }
   2843         DNSServiceAttributeSetTimestamp(attr, offset);
   2844         err = dns_service_update_record_wa(record->host->server_state,
   2845                                            shared_txn->sdref, record->rref, 0, 0, NULL, 0, attr);
   2846         DNSServiceAttributeDeallocate(attr);
   2847         if (err == kDNSServiceErr_NoError) {
   2848             INFO("DNSServiceUpdateRecord TSR for " PRI_S_SRP " set to " PUB_S_SRP " (record %p rref %p)",
   2849                  record->host == NULL ? "<null>" : record->host->name, time_buf, record, record->rref);
   2850         } else {
   2851             INFO("DNSServiceUpdateRecordWithAttribute for host tsr failed: %d (record %p rref %p)",
   2852                  err, record, record->rref);
   2853         }
   2854     }
   2855 }
   2856 
   2857 // When we need to register a host with mDNSResponder, start_host_update is called.   This can be either because
   2858 // we just got a new registration for a host, or if the daemon dies and we need to re-do the host registration.
   2859 // This just registers the host; if that succeeds, then we register the service instances.
   2860 static void
   2861 start_host_update(adv_host_t *host)
   2862 {
   2863     adv_update_t *update = host->update;
   2864 #ifdef USE_DNSSERVICE_QUEUING
   2865     int err;
   2866 #endif
   2867     int i;
   2868 
   2869     // No work to do?
   2870     if (update == NULL) {
   2871         ERROR("start_host_update: no work to do for host " PRI_S_SRP, host->registered_name);
   2872         return;
   2873     }
   2874 
   2875     bool skip_host_updates = (update->client != NULL && update->client->skip_host_updates);
   2876 
   2877 
   2878     update->num_records_started = 0;
   2879 
   2880     // Add all of the addresses that have been registered.
   2881     if (update->add_addresses != NULL) {
   2882         for (i = 0; i < update->add_addresses->num; i++) {
   2883             if (update->add_addresses->vec[i] != NULL) {
   2884                 if (!register_host_record(host, update->add_addresses->vec[i], skip_host_updates)) {
   2885                     update_failed(update, dns_rcode_servfail, true, true);
   2886                     return;
   2887                 } else if (!skip_host_updates) {
   2888                     update->num_records_started++;
   2889                 }
   2890             }
   2891         }
   2892     }
   2893 
   2894     // It's possible that some existing addresses are no longer registered because of a service disconnect. Check all the
   2895     // existing addresses for this situation: if an existing address has no rref, and does not appear in update->remove_addrs,
   2896     // then re-register it.
   2897     if (host->addresses != NULL) {
   2898         for (i = 0; i < host->addresses->num; i++) {
   2899             adv_record_t *record = host->addresses->vec[i];
   2900             adv_record_t *remove_address = NULL;
   2901             if (update->remove_addresses != NULL) {
   2902                 remove_address = update->remove_addresses->vec[i];
   2903             }
   2904             if (remove_address == NULL && record != NULL && record->rref == NULL) {
   2905                 host->addresses->vec[i]->update = update;
   2906                 RETAIN_HERE(host->addresses->vec[i]->update, adv_update);
   2907                 if (!register_host_record(host, record, skip_host_updates)) {
   2908                     update_failed(update, dns_rcode_servfail, true, true);
   2909                     return;
   2910                 } else if (!skip_host_updates) {
   2911                     update->num_records_started++;
   2912                 }
   2913             }
   2914         }
   2915     }
   2916 
   2917     if (update->key != NULL) {
   2918         if (!register_host_record(host, update->key, skip_host_updates)) {
   2919             update_failed(update, dns_rcode_servfail, true, true);
   2920             return;
   2921         } else if (!skip_host_updates) {
   2922             update->num_records_started++;
   2923         }
   2924     }
   2925 
   2926     // If the shared transaction has changed since the key record was added, add it again.
   2927     if (update->key == NULL && host->key_record != NULL &&
   2928         (host->key_record->shared_txn != (intptr_t)host->server_state->shared_registration_txn ||
   2929          host->key_record->rref == NULL))
   2930     {
   2931         update->key = host->key_record;
   2932         RETAIN_HERE(update->key, adv_record);
   2933         RELEASE_HERE(host->key_record, adv_record);
   2934         host->key_record = NULL;
   2935         update->key->rref = NULL;
   2936         update->key->update = update;
   2937         RETAIN_HERE(update, adv_update);
   2938         if (!register_host_record(host, update->key, skip_host_updates)) {
   2939             update_failed(update, dns_rcode_servfail, true, true);
   2940             return;
   2941         } else if (!skip_host_updates) {
   2942             update->num_records_started++;
   2943         }
   2944     }
   2945 
   2946     if (update->num_records_started == 0) {
   2947         adv_record_t *record = update->key != NULL ? update->key : (host->key_record != NULL ? host->key_record : NULL);
   2948         if (record == NULL) {
   2949         } else {
   2950             if (record->rref == NULL) {
   2951                 if (!register_host_record(host, record, skip_host_updates)) {
   2952                     update_failed(update, dns_rcode_servfail, true, true);
   2953                     return;
   2954                 } else if (!skip_host_updates) {
   2955                     update->num_records_started++;
   2956                 }
   2957             } else if (!skip_host_updates) {
   2958                 update_host_tsr(record, update);
   2959             }
   2960         }
   2961     }
   2962 
   2963     if (host->instances != NULL) {
   2964         // For each service instance that's being added, register it.
   2965         if (update->add_instances != NULL) {
   2966             for (i = 0; i < update->add_instances->num; i++) {
   2967                 if (update->add_instances->vec[i] != NULL) {
   2968                     if (!register_instance(update->add_instances->vec[i])) {
   2969                         update_failed(update, dns_rcode_servfail, true, true);
   2970                         return;
   2971                     }
   2972                 }
   2973             }
   2974         }
   2975 
   2976         // For each service instance that's being renewed, update its TSR if the original registration still exist,
   2977         // Otherwise re-register the instance.
   2978         if (update->renew_instances != NULL) {
   2979             for (i = 0; i < update->renew_instances->num; i++) {
   2980                 if (update->renew_instances->vec[i] != NULL) {
   2981                     adv_instance_t *instance = update->renew_instances->vec[i];
   2982                     bool must_update = true;
   2983                     bool renew_failed = instance->txn != NULL;
   2984                     if (instance->txn != NULL) {
   2985                         bool must_remove = false;
   2986                         // Make sure the instance is still registered and is registered on the current shared connection.
   2987                         if (instance->txn->sdref != NULL) {
   2988                             if (((intptr_t)host->server_state->shared_registration_txn == instance->shared_txn)) {
   2989                                 if (update_instance_tsr(instance, NULL)) {
   2990                                     must_remove = false;
   2991                                     must_update = false;
   2992                                     instance->recent_message = (ptrdiff_t)update->client->message;
   2993                                 } else {
   2994                                     INFO("instance " PRI_S_SRP " (%p) tsr update failed, re-registering",
   2995                                          instance->instance_name, instance);
   2996                                     must_remove = true;
   2997                                 }
   2998                             } else {
   2999                                 // If the shared transaction has changed, then the registration no longer exists, and
   3000                                 // the sdref is no longer valid.
   3001                                 INFO("instance " PRI_S_SRP " (%p) shared connection (%" PRIxPTR ") is stale, re-registering",
   3002                                      instance->instance_name, instance, instance->shared_txn);
   3003                                 instance->txn->sdref = NULL;
   3004                                 must_remove = true;
   3005                                 must_update = true;
   3006                                 renew_failed = false;
   3007                             }
   3008                         }
   3009                         if (must_remove) {
   3010                             // If not, dispose of the transaction and re-register.
   3011                             if (instance->txn != NULL) {
   3012                                 ioloop_dnssd_txn_cancel_srp(host->server_state, instance->txn);
   3013                                 ioloop_dnssd_txn_release(instance->txn);
   3014                                 instance->txn = NULL;
   3015                             }
   3016                         }
   3017                     }
   3018                     if (must_update) {
   3019                         if (renew_failed) {
   3020                             INFO(PRI_S_SRP " (%p): failed to update TSR, re-registering", instance->instance_name, instance);
   3021                         }
   3022                         if (!register_instance(update->renew_instances->vec[i])) {
   3023                             update_failed(update, dns_rcode_servfail, true, true);
   3024                             return;
   3025                         }
   3026                     }
   3027                 }
   3028             }
   3029         }
   3030 
   3031         // Sanity check that the instance vector sizes match between host and update.
   3032         if (update->update_instances != NULL && update->update_instances->num != host->instances->num) {
   3033             FAULT("update instance count %d differs from host instance count %d",
   3034                   update->update_instances->num, host->instances->num);
   3035             update_failed(update, dns_rcode_servfail, true, true);
   3036             return;
   3037         }
   3038         if (update->remove_instances != NULL && update->remove_instances->num != host->instances->num) {
   3039             FAULT("delete instance count %d differs from host instance count %d",
   3040                   update->remove_instances->num, host->instances->num);
   3041             update_failed(update, dns_rcode_servfail, true, true);
   3042             return;
   3043         }
   3044         for (i = 0; i < host->instances->num; i++) {
   3045             adv_instance_t *update_instance = update->update_instances->vec[i];
   3046             if (update_instance != NULL && !update_instance->removed) {
   3047                 adv_instance_t *host_instance = host->instances->vec[i];
   3048                 bool must_register = true;
   3049                 // Check to see if just the TXT record changes; in this case use DNSServiceUpdateRecord rather than re-registering
   3050                 // the instance. If we can't update, we have to remove and then add. We could do this as a pair of atomic transactions
   3051                 // if we used DNSServiceRegisterRecord rather than DNSServiceRegister, but currently we don't do that.
   3052                 // Of course if the previous registration is no longer valid, re-register.
   3053                 if (host_instance->txn != NULL && host_instance->txn->sdref != NULL && host->server_state != NULL &&
   3054                     ((intptr_t)host->server_state->shared_registration_txn == host_instance->shared_txn))
   3055                 {
   3056                     if (update_instance->port == host_instance->port &&
   3057                         update_instance->txt_length != 0 &&
   3058                         memcmp(update_instance->txt_data, host_instance->txt_data, update_instance->txt_length))
   3059                     {
   3060                         // If we are able to update the TXT record using DNSServiceUpdateRecord, we don't actually need
   3061                         // this update instance.
   3062                         if (update_instance_tsr(host_instance, update_instance)) {
   3063                             host_instance->recent_message = (ptrdiff_t)update->client->message;
   3064                             RELEASE_HERE(update->update_instances->vec[i], adv_instance);
   3065                             update_instance = NULL;
   3066                             update->update_instances->vec[i] = NULL;
   3067                             must_register = false;
   3068                         }
   3069                     }
   3070                 }
   3071                 if (must_register) {
   3072                     if (host_instance->txn != NULL) {
   3073                         ioloop_dnssd_txn_cancel_srp(host->server_state, host->instances->vec[i]->txn);
   3074                         ioloop_dnssd_txn_release(host->instances->vec[i]->txn);
   3075                         host->instances->vec[i]->txn = NULL;
   3076                     }
   3077 
   3078                     if (!register_instance(update->update_instances->vec[i])) {
   3079                         INFO("register instance failed.");
   3080                         update_failed(update, dns_rcode_servfail, true, true);
   3081                         return;
   3082                     }
   3083                 }
   3084             }
   3085         }
   3086     }
   3087 
   3088     if (update->num_instances_started == 0 && update->num_records_started == 0) {
   3089         INFO("no service or record updates, so we're finished.");
   3090         srp_mdns_update_finished(update);
   3091         return;
   3092     }
   3093 
   3094 }
   3095 
   3096 // When a host has no update in progress, and there is a client update ready to process, we need to analyze
   3097 // the client update to see what work needs to be done.  This work is constructed as an translation from the
   3098 // raw update sent by the client (host->clients) into a prepared update that can be used directly to
   3099 // register the information with mDNSResponder.
   3100 //
   3101 // Normally a host will only have one prepared update in progress; however, if we lose our connection to
   3102 // mDNSResponder, then we need to re-create the host advertisement.  If there was an update in progress when
   3103 // this happened, we then need to reapply that as well.  In this case an update is constructed from the host, to
   3104 // get the host into the intended state, and the in-progress update is pushed below that; when the host has
   3105 // been re-created on the daemon, the pending update is popped back off the stack and restarted.
   3106 static void
   3107 prepare_update(adv_host_t *host, client_update_t *client_update)
   3108 {
   3109     host_addr_t *addr;
   3110     int i, j;
   3111     service_instance_t *instance;
   3112     adv_record_vec_t *remove_addrs = NULL;
   3113     int num_remove_addrs = 0;
   3114     adv_record_vec_t *add_addrs = NULL;
   3115     int num_add_addrs = 0;
   3116     int num_update_instances = 0;
   3117     int num_add_instances = 0;
   3118     int num_remove_instances = 0;
   3119     int num_renew_instances = 0;
   3120     adv_instance_vec_t *update_instances = NULL, *add_instances = NULL;
   3121     adv_instance_vec_t *remove_instances = NULL, *renew_instances = NULL;
   3122     adv_update_t *update = NULL;
   3123 
   3124     // Work to do:
   3125     // - Figure out what address records to add and what address records to delete.
   3126     // - Because we can only have one address record at a time currently, figure out which address record we want
   3127     // - If we already have an address record published, and it's the same, do nothing
   3128     //   - else if we already have an address record published, and it's changed to a different address, do an update
   3129     //   - else if we have a new address record, publish it
   3130     //   - else publish the key to hold the name
   3131     // - Go through the set of service instances, identifying deletes, changes and adds
   3132     //   - We don't currently allow deletes, but what that would look like would be an instance with no SRV or TXT
   3133     //     record.
   3134     //   - What about a delete that keeps the name but un-advertises the service?   How would we indicate that?
   3135     //     Maybe if there's no service PTR for the service?
   3136     //   - Changes means that the contents of the text record changed, or the contents of the SRV record
   3137     //     changed (but not the hostname) or both.
   3138     //   - New means that we don't have a service with that service instance name on the host (and we previously
   3139     //     eliminated the possibility that it exists on some other host).
   3140 
   3141     // Allocate the update structure.
   3142     update = calloc(1, sizeof *update);
   3143     if (update == NULL) {
   3144         ERROR("no memory for update.");
   3145         goto fail;
   3146     }
   3147     RETAIN_HERE(update, adv_update); // For the lifetime of this function
   3148 
   3149     if (host->re_register_wakeup != NULL) {
   3150         ioloop_cancel_wake_event(host->re_register_wakeup);
   3151     }
   3152     host->re_register_pending = false;
   3153     update->start_time = srp_time();
   3154 
   3155     // The maximum number of addresses we could be deleting is all the ones the host currently has.
   3156     if (host->addresses == NULL || host->addresses->num == 0) {
   3157         num_remove_addrs = 0;
   3158         remove_addrs = NULL;
   3159     } else {
   3160         num_remove_addrs = host->addresses->num;
   3161         if (num_remove_addrs != 0) {
   3162             remove_addrs = adv_record_vec_create(num_remove_addrs);
   3163             // If we can't allocate space, just wait a bit.
   3164             if (remove_addrs == NULL) {
   3165                 ERROR("no memory for remove_addrs");
   3166                 goto fail;
   3167             }
   3168             remove_addrs->num = num_remove_addrs;
   3169         }
   3170     }
   3171 
   3172     num_add_addrs = 0;
   3173     for (addr = client_update->host->addrs; addr != NULL; addr = addr->next) {
   3174         num_add_addrs++;
   3175     }
   3176     add_addrs = adv_record_vec_create(num_add_addrs);
   3177     if (add_addrs == NULL) {
   3178         ERROR("no memory for add_addrs");
   3179         goto fail;
   3180     }
   3181 
   3182     // Copy all of the addresses in the update into add_addresses
   3183     num_add_addrs = 0;
   3184     for (addr = client_update->host->addrs; addr; addr = addr->next) {
   3185         bool add = true;
   3186         for (i = 0; i < num_add_addrs; i++) {
   3187             // If the client sends duplicate addresses, only add one of them.
   3188             if (add_addrs->vec[i] != NULL &&
   3189                 add_addrs->vec[i]->rrtype == addr->rr.type &&
   3190                 add_addrs->vec[i]->rdlen == (addr->rr.type == dns_rrtype_a ? 4 : 16) &&
   3191                 !memcmp(add_addrs->vec[i]->rdata, (uint8_t *)&addr->rr.data, add_addrs->vec[i]->rdlen))
   3192             {
   3193                 add = false;
   3194             }
   3195         }
   3196         if (add) {
   3197             adv_record_t *prepared_address = adv_record_create(addr->rr.type, addr->rr.type == dns_rrtype_a ? 4 : 16,
   3198                                                                (uint8_t *)&addr->rr.data, host);
   3199             if (prepared_address == NULL) {
   3200                 ERROR("No memory for prepared address");
   3201                 goto fail;
   3202             }
   3203             add_addrs->vec[num_add_addrs++] = prepared_address;
   3204         }
   3205     }
   3206     add_addrs->num = num_add_addrs;
   3207     for (i = 0; i < add_addrs->num; i++) {
   3208         if (add_addrs->vec[i] != NULL) {
   3209             add_addrs->vec[i]->update = update;
   3210             RETAIN_HERE(add_addrs->vec[i]->update, adv_update);
   3211         }
   3212     }
   3213 
   3214 #ifdef DEBUG_HOST_RECORDS_VERBOSE
   3215     for (i = 0; i < 2; i++) {
   3216         for (j = 0; j < (i ? num_add_addrs : num_remove_addrs); j++) {
   3217             adv_record_t *address = i ? add_addrs->vec[j] : (host->addresses != NULL ? host->addresses->vec[j] : NULL);
   3218             if (address == NULL) {
   3219                 INFO(PUB_S_SRP " before: %d NULL", i ? "add" : "rmv", j);
   3220             } else {
   3221                 char foobuf[385], *foop = foobuf;
   3222                 for (unsigned long k = 0; k < address->rdlen && k * 3 + 1 < sizeof(foobuf); k++) {
   3223                     snprintf(foop, 4, k ? ":%02x" : "%02x", address->rdata[k]);
   3224                     foop += k ? 3 : 2;
   3225                 }
   3226                 *foop = 0;
   3227                 INFO(PUB_S_SRP " before: %d rrtype %d rdlen %d rdata " PRI_S_SRP, i ? "add" : "rmv", j,
   3228                      address->rrtype, address->rdlen, foobuf);
   3229             }
   3230         }
   3231     }
   3232 #endif // DEBUG_HOST_RECORDS_VERBOSE
   3233 
   3234     // For every host address, see if it's in add_addresses.   If it's not, it needs to be removed.
   3235     // If it is, it doesn't need to be added.
   3236     if (num_remove_addrs != 0) {
   3237         for (i = 0; i < num_remove_addrs; i++) {
   3238             if (host->addresses != NULL && host->addresses->vec[i] != NULL) {
   3239                 remove_addrs->vec[i] = host->addresses->vec[i];
   3240                 RETAIN_HERE(remove_addrs->vec[i], adv_record);
   3241             }
   3242             for (j = 0; j < num_add_addrs; j++) {
   3243                 // If the address is present in both places, and has a valid registration, remove it from the list of
   3244                 // addresses to add, and also remove it from the list of addresses to remove.  When we're done, all that
   3245                 // will be remaining in the list to remove will be addresses that weren't present in the add list.
   3246                 if (remove_addrs->vec[i] != NULL && add_addrs->vec[j] != NULL &&
   3247                     remove_addrs->vec[i]->rref != NULL && host->server_state != NULL &&
   3248                     (intptr_t)host->server_state->shared_registration_txn == remove_addrs->vec[i]->shared_txn &&
   3249                     add_addrs->vec[j]->rrtype == remove_addrs->vec[i]->rrtype &&
   3250                     add_addrs->vec[j]->rdlen == remove_addrs->vec[i]->rdlen &&
   3251                     !memcmp(add_addrs->vec[j]->rdata, remove_addrs->vec[i]->rdata, remove_addrs->vec[i]->rdlen))
   3252                 {
   3253                     RELEASE_HERE(remove_addrs->vec[i], adv_record);
   3254                     remove_addrs->vec[i] = NULL;
   3255                     RELEASE_HERE(add_addrs->vec[j], adv_record);
   3256                     add_addrs->vec[j] = NULL;
   3257                 }
   3258             }
   3259         }
   3260         remove_addrs->num = num_remove_addrs;
   3261     }
   3262 
   3263 #ifdef DEBUG_HOST_RECORDS_VERBOSE
   3264     for (i = 0; i < 2; i++) {
   3265         for (j = 0; j < (i ? num_add_addrs : num_remove_addrs); j++) {
   3266             adv_record_t *address = i ? add_addrs->vec[j] : (remove_addrs != NULL ? remove_addrs->vec[j] : NULL);
   3267             if (address == NULL) {
   3268                 INFO(PUB_S_SRP "  after: %d NULL", i ? "add" : "rmv", j);
   3269             } else {
   3270                 char foobuf[385], *foop = foobuf;
   3271                 for (unsigned long k = 0; k < address->rdlen && k * 3 + 1 < sizeof(foobuf); k++) {
   3272                     snprintf(foop, 4, k ? ":%02x" : "%02x", address->rdata[k]);
   3273                     foop += k ? 3 : 2;
   3274                 }
   3275                 *foop = 0;
   3276                 INFO(PUB_S_SRP "  after: %d rrtype %d rdlen %d rdata " PRI_S_SRP, i ? "add" : "rmv", j,
   3277                      address->rrtype, address->rdlen, foobuf);
   3278             }
   3279         }
   3280     }
   3281 #endif // DEBUG_HOST_RECORDS_VERBOSE
   3282 
   3283     // Make a key record
   3284     if (host->key_record == NULL) {
   3285         update->key = adv_record_create(dns_rrtype_key, host->key_rdlen, host->key_rdata, host);
   3286         if (update->key == NULL) {
   3287             ERROR("no memory for key record");
   3288             goto fail;
   3289         }
   3290         update->key->update = update;
   3291         RETAIN_HERE(update->key->update, adv_update);
   3292     }
   3293 
   3294     // We can never update more instances than currently exist for this host.
   3295     num_update_instances = host->instances->num;
   3296     num_remove_instances = host->instances->num;
   3297     num_renew_instances = host->instances->num;
   3298 
   3299     update_instances = adv_instance_vec_create(num_update_instances);
   3300     if (update_instances == NULL) {
   3301         ERROR("no memory for update_instances");
   3302         goto fail;
   3303     }
   3304     update_instances->num = num_update_instances;
   3305 
   3306     remove_instances = adv_instance_vec_create(num_remove_instances);
   3307     if (remove_instances == NULL) {
   3308         ERROR("no memory for remove_instances");
   3309         goto fail;
   3310     }
   3311     remove_instances->num = num_remove_instances;
   3312 
   3313     renew_instances = adv_instance_vec_create(num_renew_instances);
   3314     if (renew_instances == NULL) {
   3315         ERROR("no memory for renew_instances");
   3316         goto fail;
   3317     }
   3318     renew_instances->num = num_renew_instances;
   3319 
   3320     // Handle removes. Service instance removes have to remove the whole service instance, not some subset.
   3321     for (delete_t *dp = client_update->removes; dp; dp = dp->next) {
   3322         // Removes can be for services or service instances. Because we're acting as an
   3323         // Advertising Proxy and not a regular name server, we don't track service instances,
   3324         // and so we don't need to match them here. This if statement checks to see if the
   3325         // name could possibly be a service instance name followed by a service type. We
   3326         // can then extract the putative service instance name and service type and compare;
   3327         // if they match, they are in fact those things, and if they don't, we don't care.
   3328         if (dp->name != NULL && dp->name->next != NULL && dp->name->next->next != NULL) {
   3329             char instance_name[DNS_MAX_LABEL_SIZE_ESCAPED + 1];
   3330             char service_type[DNS_MAX_LABEL_SIZE_ESCAPED + 2];
   3331 
   3332             dns_name_print_to_limit(dp->name, dp->name->next, instance_name, sizeof(instance_name));
   3333             dns_name_print_to_limit(dp->name->next, dp->name->next->next->next, service_type, sizeof(service_type));
   3334 
   3335             for (i = 0; i < host->instances->num; i++) {
   3336                 adv_instance_t *remove_instance = host->instances->vec[i];
   3337                 if (remove_instance != NULL) {
   3338                     if (!strcmp(instance_name, remove_instance->instance_name) &&
   3339                         service_types_equal(service_type, remove_instance->service_type))
   3340                     {
   3341                         remove_instances->vec[i] = remove_instance;
   3342                         RETAIN_HERE(remove_instances->vec[i], adv_instance);
   3343                         break;
   3344                     }
   3345                 }
   3346             }
   3347         }
   3348     }
   3349 
   3350     // The number of instances to add can be as many as there are instances in the update.
   3351     num_add_instances = 0;
   3352     for (instance = client_update->instances; instance; instance = instance->next) {
   3353         num_add_instances++;
   3354     }
   3355     add_instances = adv_instance_vec_create(num_add_instances);
   3356     if (add_instances == NULL) {
   3357         ERROR("prepare_update: no memory for add_instances");
   3358         goto fail;
   3359     }
   3360 
   3361     // Convert all of the instances in the client update to adv_instance_t structures for easy comparison.
   3362     // Any that are unchanged will have to be freed--oh well.
   3363     i = 0;
   3364     for (instance = client_update->instances; instance != NULL; instance = instance->next) {
   3365         adv_instance_t *prepared_instance = adv_instance_create(instance, host, update);
   3366         if (prepared_instance == NULL) {
   3367             // prepare_instance logs.
   3368             goto fail;
   3369         }
   3370         if (i >= num_add_instances) {
   3371             FAULT("while preparing client update instances, i >= num_add_instances");
   3372             RELEASE_HERE(prepared_instance, adv_instance);
   3373             prepared_instance = NULL;
   3374             goto fail;
   3375         }
   3376 
   3377         prepared_instance->anycast = false;
   3378         if (client_update != NULL && client_update->connection != NULL) {
   3379             const struct sockaddr *server_addr = connection_get_local_address(client_update->message);
   3380             if (server_addr && server_addr->sa_family == AF_INET6) {
   3381                 const struct in6_addr *const ipv6_address = &(((const struct sockaddr_in6 *)server_addr)->sin6_addr);
   3382                 uint16_t server_port = ntohs(((const struct sockaddr_in6 *)server_addr)->sin6_port);
   3383                 SEGMENTED_IPv6_ADDR_GEN_SRP(ipv6_address, addr_buf);
   3384                 INFO("server address " PRI_SEGMENTED_IPv6_ADDR_SRP "; server port %d",
   3385                       SEGMENTED_IPv6_ADDR_PARAM_SRP(ipv6_address, addr_buf), server_port);
   3386                 if (is_thread_mesh_anycast_address(ipv6_address) && server_port == 53) {
   3387                     prepared_instance->anycast = true;
   3388                 }
   3389             }
   3390         }
   3391         add_instances->vec[i++] = prepared_instance;
   3392     }
   3393     add_instances->num = i;
   3394 
   3395     // The instances in the update are now in add_instances.  If they are updates, move them to update_instances.  If
   3396     // they are unchanged, free them and null them out, and remember the current instance in renew_instances.  If they
   3397     // are adds, leave them.
   3398     for (i = 0; i < num_add_instances; i++) {
   3399         adv_instance_t *add_instance = add_instances->vec[i];
   3400 
   3401         if (add_instance != NULL) {
   3402             for (j = 0; j < host->instances->num; j++) {
   3403                 adv_instance_t *host_instance = host->instances->vec[j];
   3404 
   3405                 // See if the instance names match.
   3406                 if (host_instance != NULL &&
   3407                     !strcmp(add_instance->instance_name, host_instance->instance_name) &&
   3408                     service_types_equal(add_instance->service_type, host_instance->service_type))
   3409                 {
   3410                     // If the rdata is the same, and the service type is the same (including subtypes), and it's not
   3411                     // deleted, it's not an add or an update.
   3412                     if (!host_instance->removed && add_instance->txt_length == host_instance->txt_length &&
   3413                         add_instance->port == host_instance->port &&
   3414                         !strcmp(add_instance->service_type, host_instance->service_type) &&
   3415                         (add_instance->txt_length == 0 ||
   3416                          !memcmp(add_instance->txt_data, host_instance->txt_data, add_instance->txt_length)))
   3417                     {
   3418                         RELEASE_HERE(add_instances->vec[i], adv_instance);
   3419                         add_instances->vec[i] = NULL;
   3420                         renew_instances->vec[j] = host_instance;
   3421                         RETAIN_HERE(host_instance, adv_instance);
   3422                         renew_instances->vec[j]->update = update;
   3423                         RETAIN_HERE(renew_instances->vec[j]->update, adv_update);
   3424                         INFO(PRI_S_SRP "." PRI_S_SRP " renewed for host " PRI_S_SRP,
   3425                              host_instance->instance_name, host_instance->service_type, host->name);
   3426                     } else {
   3427                         update_instances->vec[j] = add_instance;
   3428                         RETAIN_HERE(update_instances->vec[j], adv_instance);
   3429                         RELEASE_HERE(add_instances->vec[i], adv_instance);
   3430                         add_instances->vec[i] = NULL;
   3431                     }
   3432                     break;
   3433                 }
   3434             }
   3435         }
   3436     }
   3437 
   3438     // At this point we have figured out all the work we need to do, so hang it off an update structure.
   3439     update->host = host;
   3440     RETAIN_HERE(update->host, adv_host);
   3441     update->client = client_update;
   3442     update->remove_addresses = remove_addrs;
   3443     update->add_addresses = add_addrs;
   3444     update->remove_instances = remove_instances;
   3445     update->add_instances = add_instances;
   3446     update->update_instances = update_instances;
   3447     update->renew_instances = renew_instances;
   3448     update->host_lease = client_update->host_lease;
   3449     update->key_lease = client_update->key_lease;
   3450 
   3451     // Register any added addresses with threadradiod before we actually advertise them, to avoid a spurious
   3452     // address query.
   3453 
   3454     host->update = update;
   3455     RETAIN_HERE(host->update, adv_update);
   3456     RELEASE_HERE(update, adv_update);
   3457     update = NULL;
   3458 
   3459 
   3460     start_host_update(host);
   3461     return;
   3462 
   3463 fail:
   3464     if (client_update != NULL) {
   3465         srp_parse_client_updates_free(client_update);
   3466         client_update = NULL;
   3467     }
   3468     if (remove_addrs != NULL) {
   3469         // Addresses in remove_addrs are owned by the host and don't need to be freed.
   3470         RELEASE_HERE(remove_addrs, adv_record_vec);
   3471         remove_addrs = NULL;
   3472     }
   3473     if (add_addrs != NULL) {
   3474         RELEASE_HERE(add_addrs, adv_record_vec);
   3475         add_addrs = NULL;
   3476     }
   3477     if (add_instances != NULL) {
   3478         RELEASE_HERE(add_instances, adv_instance_vec);
   3479         add_instances = NULL;
   3480     }
   3481     if (remove_instances != NULL) {
   3482         RELEASE_HERE(remove_instances, adv_instance_vec);
   3483         remove_instances = NULL;
   3484     }
   3485     if (update_instances != NULL) {
   3486         RELEASE_HERE(update_instances, adv_instance_vec);
   3487         update_instances = NULL;
   3488     }
   3489     if (update) {
   3490         RELEASE_HERE(update, adv_update);
   3491     }
   3492 }
   3493 
   3494 typedef enum { missed, match, conflict } instance_outcome_t;
   3495 static instance_outcome_t
   3496 compare_instance(adv_instance_t *instance,
   3497                  dns_host_description_t *new_host, adv_host_t *host,
   3498                  char *instance_name, char *service_type)
   3499 {
   3500     if (instance == NULL) {
   3501         return missed;
   3502     }
   3503     if (host->removed) {
   3504         return missed;
   3505     }
   3506     if (!strcmp(instance_name, instance->instance_name) && service_types_equal(service_type, instance->service_type)) {
   3507         if (!dns_names_equal_text(new_host->name, host->name)) {
   3508             return conflict;
   3509         }
   3510         return match;
   3511     }
   3512     return missed;
   3513 }
   3514 
   3515 bool
   3516 srp_update_start(client_update_t *client_update)
   3517 {
   3518     dns_host_description_t *new_host = client_update->host;
   3519     char new_host_name[DNS_MAX_NAME_SIZE_ESCAPED + 1];
   3520     srp_server_t *server_state = client_update->server_state;
   3521     uint32_t key_id = 0;
   3522     dns_name_print(new_host->name, new_host_name, sizeof new_host_name);
   3523     adv_host_t *host = NULL;
   3524     srpl_connection_t *srpl_connection = client_update->srpl_connection;
   3525     message_t *raw_message = client_update->message;
   3526     comm_t *connection = client_update->connection;
   3527 
   3528 
   3529     // Compute a checksum on the key, ignoring up to three bytes at the end.
   3530     for (client_update_t *update = client_update; update != NULL; update = update->next) {
   3531         dns_host_description_t *update_host = update->host;
   3532 
   3533         uint32_t update_key_id = 0;
   3534         for (unsigned i = 0; i < update_host->key->data.key.len; i += 4) {
   3535             update_key_id += ((update_host->key->data.key.key[i] << 24) | (update_host->key->data.key.key[i + 1] << 16) |
   3536                               (update_host->key->data.key.key[i + 2] << 8) | (update_host->key->data.key.key[i + 3]));
   3537         }
   3538         if (update == client_update) {
   3539             key_id = update_key_id;
   3540         } else if (key_id != update_key_id) {
   3541             ERROR("update contains multiple key ids %x and %x", key_id, update_key_id);
   3542             advertise_finished(NULL, new_host_name, server_state,
   3543                                srpl_connection, NULL, raw_message, dns_rcode_refused, NULL, false, true);
   3544             goto cleanup;
   3545         }
   3546     }
   3547 
   3548     char seenbuf[200];
   3549     char *already_seen = seenbuf;
   3550     const char *plural = "";
   3551 
   3552     // For replicated updates, check the transaction IDs to make sure we aren't applying an update we've already gotten.
   3553     if (srpl_connection != NULL) {
   3554         for (host = server_state->hosts; host != NULL; host = host->next) {
   3555             if (host->key_id == key_id && !strcmp(host->name, new_host_name)) {
   3556                 break;
   3557             }
   3558         }
   3559 
   3560         if (host != NULL) {
   3561             bool replay = true;
   3562             while (client_update != NULL && replay) {
   3563                 replay = false;
   3564                 if (host->message != NULL && host->message->wire.id == client_update->message->wire.id) {
   3565                     replay = true;
   3566                 } else if (host->instances != NULL) {
   3567                     for (int i = 0; i < host->instances->num; i++) {
   3568                         adv_instance_t *instance = host->instances->vec[i];
   3569                         if (instance != NULL) {
   3570                             if (instance->message != NULL &&
   3571                                 instance->message->wire.id == client_update->message->wire.id)
   3572                             {
   3573                                 replay = true;
   3574                                 break;
   3575                             }
   3576                         }
   3577                     }
   3578                 }
   3579                 if (replay) {
   3580                     client_update_t *skip_update = client_update;
   3581                     client_update = client_update->next;
   3582                     if (already_seen != seenbuf) {
   3583                         plural = "s";
   3584                     }
   3585                     if (already_seen + 6 < &seenbuf[sizeof(seenbuf)]) {
   3586                         snprintf(already_seen, 6, " %04x", skip_update->message->wire.id);
   3587                         already_seen += 5;
   3588                     }
   3589                     skip_update->next = NULL;
   3590                     srp_parse_client_updates_free(skip_update);
   3591                     if (client_update != NULL) {
   3592                         new_host = client_update->host;
   3593                     } else {
   3594                         new_host = NULL;
   3595                     }
   3596                 }
   3597             }
   3598         }
   3599     }
   3600     if (already_seen != seenbuf) {
   3601         INFO("host update for " PRI_S_SRP ", key id %" PRIx32 " " PUB_S_SRP " (skipped xid" PUB_S_SRP PUB_S_SRP ")",
   3602              new_host_name, key_id, srpl_connection == NULL ? "" : srpl_connection->name, plural, seenbuf);
   3603     } else {
   3604         INFO("host update for " PRI_S_SRP ", key id %" PRIx32 " " PUB_S_SRP,
   3605              new_host_name, key_id, srpl_connection == NULL ? "" : srpl_connection->name);
   3606     }
   3607     if (client_update == NULL) {
   3608         advertise_finished(host, new_host_name, server_state, srpl_connection,
   3609                            NULL, raw_message, dns_rcode_noerror, NULL, false, true);
   3610         return true; // It's safe to just return here because we've freed all the client updates.
   3611     }
   3612 
   3613     service_instance_t *instances = client_update->instances;
   3614     delete_t *removes = client_update->removes;
   3615     adv_host_t **p_hosts = NULL;
   3616     char pres_name[DNS_MAX_NAME_SIZE_ESCAPED + 1];
   3617     service_instance_t *new_instance;
   3618     instance_outcome_t outcome = missed;
   3619     char instance_name[DNS_MAX_LABEL_SIZE_ESCAPED + 1];
   3620     char service_type[DNS_MAX_LABEL_SIZE_ESCAPED * 2 + 2];
   3621     host_addr_t *addr;
   3622     const bool remove = client_update->host_lease == 0;
   3623     const char *updatestr = client_update->host_lease == 0 ? "remove" : "update";
   3624     delete_t *dp;
   3625 
   3626 
   3627     for (addr = new_host->addrs; addr != NULL; addr = addr->next) {
   3628         if (addr->rr.type == dns_rrtype_a) {
   3629             IPv4_ADDR_GEN_SRP(&addr->rr.data.a.s_addr, addr_buf);
   3630             INFO("host " PUB_S_SRP " for " PRI_S_SRP ", address " PRI_IPv4_ADDR_SRP " " PUB_S_SRP, updatestr,
   3631                  new_host_name, IPv4_ADDR_PARAM_SRP(&addr->rr.data.a.s_addr, addr_buf),
   3632                  srpl_connection == NULL ? "" : srpl_connection->name);
   3633         } else {
   3634             SEGMENTED_IPv6_ADDR_GEN_SRP(addr->rr.data.aaaa.s6_addr, addr_buf);
   3635             INFO("host " PUB_S_SRP " for " PRI_S_SRP ", address " PRI_SEGMENTED_IPv6_ADDR_SRP " " PUB_S_SRP,
   3636                  updatestr, new_host_name, SEGMENTED_IPv6_ADDR_PARAM_SRP(addr->rr.data.aaaa.s6_addr, addr_buf),
   3637                  srpl_connection == NULL ? "" : srpl_connection->name);
   3638         }
   3639     }
   3640     for (new_instance = instances; new_instance != NULL; new_instance = new_instance->next) {
   3641         extract_instance_name(instance_name, sizeof instance_name, service_type, sizeof service_type, new_instance);
   3642         INFO("host " PUB_S_SRP " for " PRI_S_SRP ", instance name " PRI_S_SRP ", type " PRI_S_SRP
   3643              ", port %d " PUB_S_SRP, updatestr, new_host_name, instance_name, service_type,
   3644              new_instance->srv != NULL ? new_instance->srv->data.srv.port : -1,
   3645              srpl_connection == NULL ? "" : srpl_connection->name);
   3646         if (new_instance->txt != NULL) {
   3647             char txt_buf[DNS_DATA_SIZE];
   3648             dns_txt_data_print(txt_buf, DNS_DATA_SIZE, new_instance->txt->data.txt.len, new_instance->txt->data.txt.data);
   3649             INFO("text data for instance " PRI_S_SRP ": " PRI_S_SRP, instance_name, txt_buf);
   3650         }
   3651     }
   3652 
   3653     // Look for matching service instance names.   A service instance name that matches, but has a different
   3654     // hostname, means that there is a conflict.   We have to look through all the entries; the presence of
   3655     // a matching hostname doesn't mean we are done UNLESS there's a matching service instance name pointing
   3656     // to that hostname.
   3657     for (host = server_state->hosts; host; host = host->next) {
   3658         // If a host has been removed, it won't have any instances to compare against. Later on, if we find that
   3659         // there is no matching host for this update, we look through the host list again and remove the
   3660         // "removed" host if it has the same name, so we don't need to do anything further here.
   3661         if (host->removed) {
   3662             continue;
   3663         }
   3664         // We need to look for matches both in the registered instances for this registration, and also in
   3665         // the list of new instances, in case we get a duplicate update while a previous update is in progress.
   3666         for (new_instance = instances; new_instance; new_instance = new_instance->next) {
   3667             extract_instance_name(instance_name, sizeof instance_name, service_type, sizeof service_type, new_instance);
   3668 
   3669             // First check for a match or conflict in the host itself.
   3670             for (int i = 0; i < host->instances->num; i++) {
   3671                 outcome = compare_instance(host->instances->vec[i], new_host, host,
   3672                                            instance_name, service_type);
   3673                 if (outcome != missed) {
   3674                     goto found_something;
   3675                 }
   3676             }
   3677 
   3678             // Then look for the same thing in any subsequent updates that have been baked.
   3679             if (host->update != NULL) {
   3680                 if (host->update->add_instances != NULL) {
   3681                     for (int i = 0; i < host->update->add_instances->num; i++) {
   3682                         outcome = compare_instance(host->update->add_instances->vec[i], new_host, host,
   3683                                                    instance_name, service_type);
   3684                         if (outcome != missed) {
   3685                             goto found_something;
   3686                         }
   3687                     }
   3688                 }
   3689             }
   3690         }
   3691     }
   3692 found_something:
   3693     if (outcome == conflict) {
   3694         ERROR("service instance name " PRI_S_SRP "/" PRI_S_SRP " already pointing to host "
   3695               PRI_S_SRP ", not host " PRI_S_SRP, instance_name, service_type, host->name, new_host_name);
   3696         advertise_finished(NULL, host->name,
   3697                            server_state, srpl_connection, connection, raw_message, dns_rcode_yxdomain, NULL, true, true);
   3698         goto cleanup;
   3699     }
   3700 
   3701     // We may have received removes for individual records. In this case, we need to make sure they only remove
   3702     // records that have been added to the host that matches.
   3703     for (adv_host_t *rhp = server_state->hosts; rhp != NULL; rhp = rhp->next) {
   3704         if (rhp->removed) {
   3705             continue;
   3706         }
   3707 
   3708         // Look for removes that conflict
   3709         for (dp = removes; dp != NULL; dp = dp->next) {
   3710             // We only need to do this for service instance names. We don't really know what is and isn't a
   3711             // service instance name, but if it /could/ be a service instance name, we compare; if it matches,
   3712             // it is a service instance name, and if not, no problem.
   3713             if (dp->name != NULL && dp->name->next != NULL && dp->name->next->next != NULL) {
   3714                 dns_name_print_to_limit(dp->name, dp->name->next, instance_name, sizeof(instance_name));
   3715                 dns_name_print_to_limit(dp->name->next, dp->name->next->next->next, service_type, sizeof(service_type));
   3716 
   3717                 // See if the delete deletes an instance on the host
   3718                 for (int i = 0; i < rhp->instances->num; i++) {
   3719                     adv_instance_t *instance = rhp->instances->vec[i];
   3720                     if (instance != NULL) {
   3721                         if (!strcmp(instance_name, instance->instance_name) &&
   3722                             service_types_equal(service_type, instance->service_type))
   3723                         {
   3724                             if (!strcmp(new_host_name, rhp->name)) {
   3725                                 ERROR("remove for " PRI_S_SRP "." PRI_S_SRP " matches instance on host " PRI_S_SRP,
   3726                                       instance_name, service_type, rhp->name);
   3727                                 dp->consumed = true;
   3728                             } else {
   3729                                 ERROR("remove for " PRI_S_SRP "." PRI_S_SRP " conflicts with instance on host " PRI_S_SRP,
   3730                                       instance_name, service_type, rhp->name);
   3731                                 advertise_finished(NULL, rhp->name, server_state, srpl_connection,
   3732                                                    connection, raw_message, dns_rcode_formerr, NULL, true, true);
   3733                                 goto cleanup;
   3734                             }
   3735                         }
   3736                     }
   3737                 }
   3738 
   3739                 // See if the remove removes an instance on an update on the host
   3740                 if (rhp->update) {
   3741                     if (rhp->update->add_instances != NULL) {
   3742                         for (int i = 0; i < rhp->update->add_instances->num; i++) {
   3743                             adv_instance_t *instance = rhp->update->add_instances->vec[i];
   3744                             if (instance != NULL) {
   3745                                 if (!strcmp(instance_name, instance->instance_name) &&
   3746                                     service_types_equal(service_type, instance->service_type))
   3747                                 {
   3748                                     if (!strcmp(new_host_name, rhp->name)) {
   3749                                         dp->consumed = true;
   3750                                     } else {
   3751                                         ERROR("remove for " PRI_S_SRP " conflicts with instance on update to host " PRI_S_SRP,
   3752                                               instance->instance_name, rhp->name);
   3753                                         advertise_finished(NULL, rhp->name, server_state, srpl_connection,
   3754                                                            connection, raw_message, dns_rcode_formerr, NULL, true, true);
   3755                                         goto cleanup;
   3756                                     }
   3757                                 }
   3758                             }
   3759                         }
   3760                     }
   3761                 }
   3762             }
   3763         }
   3764     }
   3765 
   3766     // Log any unmatched deletes, but we don't consider these to be errors.
   3767     for (dp = removes; dp != NULL; dp = dp->next) {
   3768         if (!dp->consumed) {
   3769             DNS_NAME_GEN_SRP(dp->name, name_buf);
   3770             INFO("remove for " PRI_DNS_NAME_SRP " doesn't match any instance on any host.",
   3771                  DNS_NAME_PARAM_SRP(dp->name, name_buf));
   3772         }
   3773     }
   3774 
   3775     // If we fall off the end looking for a matching service instance, there isn't a matching
   3776     // service instance, but there may be a matching host, so look for that.
   3777     if (outcome == missed) {
   3778         // Search for the new hostname in the list of hosts, which is sorted.
   3779         for (p_hosts = &server_state->hosts; *p_hosts; p_hosts = &host->next) {
   3780             host = *p_hosts;
   3781             int comparison = strcasecmp(new_host_name, host->name);
   3782             if (comparison == 0) {
   3783                 // If we get an update for a host that was removed, and it's not also a remove,
   3784                 // remove the host entry that's marking the remove. If this is a remove, just flag
   3785                 // it as a miss.
   3786                 if (host->removed) {
   3787                     outcome = missed;
   3788                     if (remove) {
   3789                         break;
   3790                     }
   3791                     // if remove is more recent than this message (for example, we firt receive remove
   3792                     // from the actual client and then receive a stale update message from a replication
   3793                     // peer), we don't apply this message and end processing here.
   3794                     if (host->remove_received_time > client_update->message->received_time) {
   3795                         INFO("update for host " PRI_S_SRP " which has been deleted.", host->name);
   3796                         advertise_finished(NULL, host->name, server_state, srpl_connection,
   3797                                            connection, raw_message, dns_rcode_servfail, NULL, true, true);
   3798                         goto cleanup;
   3799                     }
   3800                     *p_hosts = host->next;
   3801                     host_invalidate(host);
   3802                     RELEASE_HERE(host, adv_host);
   3803                     host = NULL;
   3804                     break;
   3805                 }
   3806                 if (key_id == host->key_id && dns_keys_rdata_equal(new_host->key, &host->key)) {
   3807                     outcome = match;
   3808                     break;
   3809                 }
   3810                 ERROR("update for host " PRI_S_SRP " has key id %" PRIx32
   3811                       " which doesn't match host key id %" PRIx32 ".",
   3812                       host->name, key_id, host->key_id);
   3813                 advertise_finished(NULL, host->name, server_state, srpl_connection,
   3814                                    connection, raw_message, dns_rcode_yxdomain, NULL, true, true);
   3815                 goto cleanup;
   3816             } else if (comparison < 0) {
   3817                 break;
   3818             }
   3819         }
   3820     } else {
   3821         if (key_id != host->key_id || !dns_keys_rdata_equal(new_host->key, &host->key)) {
   3822             ERROR("new host with name " PRI_S_SRP " and key id %" PRIx32
   3823                   " conflicts with existing host " PRI_S_SRP " with key id %" PRIx32,
   3824                   new_host_name, key_id, host->name, host->key_id);
   3825             advertise_finished(NULL, host->name, server_state, srpl_connection,
   3826                                connection, raw_message, dns_rcode_yxdomain, NULL, true, true);
   3827             goto cleanup;
   3828         }
   3829     }
   3830 
   3831     // If we didn't find a matching host, we can make a new one.   When we create it, it just has
   3832     // a name and no records.  The update that we then construct will have the missing records.
   3833     // We don't want to do this for a remove, obviously.
   3834     if (outcome == missed) {
   3835         if (remove) {
   3836             ERROR("Remove for host " PRI_S_SRP " which doesn't exist.", new_host_name);
   3837             advertise_finished(NULL, new_host_name, server_state, srpl_connection,
   3838                                connection, raw_message, dns_rcode_noerror, NULL, true, true);
   3839             goto cleanup;
   3840         }
   3841         host = calloc(1, sizeof *host);
   3842         if (host == NULL) {
   3843             ERROR("no memory for host data structure.");
   3844             advertise_finished(NULL, new_host_name, server_state, srpl_connection,
   3845                                connection, raw_message, dns_rcode_servfail, NULL, true, true);
   3846             goto cleanup;
   3847         }
   3848         RETAIN_HERE(host, adv_host);
   3849         host->server_state = server_state;
   3850         host->instances = adv_instance_vec_create(0);
   3851         if (host->instances == NULL) {
   3852             ERROR("no memory for host instance vector.");
   3853             advertise_finished(NULL, new_host_name, server_state, srpl_connection,
   3854                                connection, raw_message, dns_rcode_servfail, NULL, true, true);
   3855             RELEASE_HERE(host, adv_host);
   3856             host = NULL;
   3857             goto cleanup;
   3858         }
   3859         host->addresses = adv_record_vec_create(0);
   3860         if (host->addresses == NULL) {
   3861             ERROR("no memory for host address vector.");
   3862             advertise_finished(NULL, new_host_name, server_state, srpl_connection,
   3863                                connection, raw_message, dns_rcode_servfail, NULL, true, true);
   3864             RELEASE_HERE(host, adv_host);
   3865             host = NULL;
   3866             goto cleanup;
   3867         }
   3868 
   3869         host->retry_wakeup = ioloop_wakeup_create();
   3870         if (host->retry_wakeup != NULL) {
   3871             host->lease_wakeup = ioloop_wakeup_create();
   3872         }
   3873         if (host->lease_wakeup == NULL) {
   3874             ERROR("no memory for wake event on host");
   3875             advertise_finished(NULL, new_host_name, server_state, srpl_connection,
   3876                                connection, raw_message, dns_rcode_servfail, NULL, true, true);
   3877             RELEASE_HERE(host, adv_host);
   3878             host = NULL;
   3879             goto cleanup;
   3880         }
   3881         dns_name_print(new_host->name, pres_name, sizeof pres_name);
   3882         host->name = strdup(pres_name);
   3883         if (host->name == NULL) {
   3884             RELEASE_HERE(host, adv_host);
   3885             host = NULL;
   3886             ERROR("no memory for hostname.");
   3887             advertise_finished(NULL, new_host_name, server_state, srpl_connection,
   3888                                connection, raw_message, dns_rcode_servfail, NULL, true, true);
   3889             goto cleanup;
   3890         }
   3891         host->key = *new_host->key;
   3892 #ifndef __clang_analyzer__
   3893         // Normally this would be invalid, but we never use the name of the key record.
   3894         host->key.name = NULL;
   3895 #endif
   3896         host->key_rdlen = new_host->key->data.key.len + 4;
   3897         host->key_rdata = malloc(host->key_rdlen);
   3898         if (host->key_rdata == NULL) {
   3899             RELEASE_HERE(host, adv_host);
   3900             host = NULL;
   3901             ERROR("no memory for host key.");
   3902             advertise_finished(NULL, new_host_name, server_state, srpl_connection,
   3903                                connection, raw_message, dns_rcode_servfail, NULL, true, true);
   3904             goto cleanup;
   3905         }
   3906         memcpy(host->key_rdata, &new_host->key->data.key.flags, 2);
   3907         host->key_rdata[2] = new_host->key->data.key.protocol;
   3908         host->key_rdata[3] = new_host->key->data.key.algorithm;
   3909         memcpy(&host->key_rdata[4], new_host->key->data.key.key, new_host->key->data.key.len);
   3910         host->key.data.key.key = &host->key_rdata[4];
   3911         host->key_id = key_id;
   3912 
   3913         // Insert this in the list where it would have sorted.  The if test is because the optimizer doesn't notice that
   3914         // p_hosts can never be null here--it will always be pointing to the end of the list of hosts if we get here.
   3915         if (p_hosts != NULL) {
   3916             host->next = *p_hosts;
   3917             *p_hosts = host;
   3918         }
   3919         p_hosts = NULL;
   3920     }
   3921 
   3922     // If we are already updating this host, either this is a retransmission, or it's a new transaction. In the case
   3923     // of a retransmission, we need to keep doing the work we've been asked to do, and hopefully we'll reply before the
   3924     // client gives up. In the case of a new request, we aren't ready for it yet; the client really shouldn't have sent
   3925     // it so quickly, but if it's behaving correctly, we should be done with the current update before it retransmits,
   3926     // so we can safely ignore it. If we're getting a replication update, it can't be newer than the current update.
   3927     // So we can ignore it--we'll send a replication update when we're done processing the client update.
   3928     if (host->update != NULL) {
   3929 #ifdef SRP_DETECT_STALLS
   3930         time_t now = srp_time();
   3931         // It's possible that we could get an update that stalls due to a problem communicating with mDNSResponder
   3932         // and that a timing race prevents this from being detected correctly. In this case, cancel the update and
   3933         // let the retry go through. We don't want to do this unless there's a clear stall, so we're allowing ten
   3934         // seconds.
   3935         if (now - host->update->start_time > 10) {
   3936             INFO("update has stalled, failing it silently.");
   3937             update_failed(host->update, dns_rcode_servfail, false, false);
   3938             service_disconnected(server_state, (intptr_t)server_state->shared_registration_txn);
   3939         } else {
   3940 #endif // SRP_DETECT_STALLS
   3941             INFO("dropping retransmission of in-progress update for host " PRI_S_SRP, host->name);
   3942 #if SRP_FEATURE_REPLICATION
   3943             srp_replication_advertise_finished(host, host->name, server_state, srpl_connection,
   3944                                                connection, dns_rcode_servfail, true);
   3945 #endif
   3946         cleanup:
   3947             srp_parse_client_updates_free(client_update);
   3948             return false;
   3949 #ifdef SRP_DETECT_STALLS
   3950         }
   3951 #endif
   3952     }
   3953 
   3954     // If this is a remove, remove the host registrations and mark the host removed. We keep it around until the
   3955     // lease expires to prevent replication accidentally re-adding a removed host as a result of a bad timing
   3956     // coincidence.
   3957     if (remove) {
   3958         host_invalidate(host);
   3959         // We need to propagate the remove message.
   3960         if (host->message != NULL) {
   3961             ioloop_message_release(host->message);
   3962         }
   3963         host->message = raw_message;
   3964         // remember the time when the message that removes the host was received
   3965         host->remove_received_time = host->message->received_time;
   3966         ioloop_message_retain(host->message);
   3967         advertise_finished(host, new_host_name, server_state, srpl_connection,
   3968                            connection, raw_message, dns_rcode_noerror, NULL, true, true);
   3969         goto cleanup;
   3970     }
   3971 
   3972     // At this point we have an update and a host to which to apply it.  We may already be doing an earlier
   3973     // update, or not.  Create a client update structure to hold the communication, so that when we are done,
   3974     // we can respond.
   3975     if (outcome == missed) {
   3976         INFO("New host " PRI_S_SRP ", key id %" PRIx32 , host->name, host->key_id);
   3977     } else {
   3978         if (host->registered_name != host->name) {
   3979             INFO("Renewing host " PRI_S_SRP ", alias " PRI_S_SRP ", key id %" PRIx32,
   3980                  host->name, host->registered_name, host->key_id);
   3981         } else {
   3982             INFO("Renewing host " PRI_S_SRP ", key id %" PRIx32, host->name, host->key_id);
   3983         }
   3984     }
   3985 
   3986     if (host->registered_name == NULL) {
   3987         host->registered_name = host->name;
   3988     }
   3989 
   3990     // We have to take the lease from the SRP update--the original registrar negotiated it, and if it's out
   3991     // of our range, that's too bad (ish).
   3992     if (raw_message->lease != 0) {
   3993         INFO("basing lease time on message: raw_message->lease = %d, raw_message->key_lease = %d",
   3994              raw_message->lease, raw_message->key_lease);
   3995         client_update->host_lease = raw_message->lease;
   3996         client_update->key_lease = raw_message->key_lease;
   3997     } else {
   3998         if (client_update->host_lease < server_state->max_lease_time) {
   3999             if (client_update->host_lease < server_state->min_lease_time) {
   4000                 INFO("basing lease time on server_state->min_lease_time: %d", server_state->min_lease_time);
   4001                 client_update->host_lease = server_state->min_lease_time;
   4002             } else {
   4003                 INFO("basing lease time on client_update->host_lease: %d", client_update->host_lease);
   4004                 // client_update->host_lease = client_update->host_lease;
   4005             }
   4006         } else {
   4007             client_update->host_lease = server_state->max_lease_time;
   4008                 INFO("basing lease time on server_state->max_lease_time: %d", server_state->max_lease_time);
   4009         }
   4010         if (client_update->key_lease < server_state->key_max_lease_time) {
   4011             if (client_update->key_lease < server_state->key_min_lease_time) {
   4012                 client_update->key_lease = server_state->key_min_lease_time;
   4013             } else {
   4014                 // client_update->key_lease = client_update->key_lease;
   4015             }
   4016         } else {
   4017             client_update->key_lease = server_state->key_max_lease_time;
   4018         }
   4019     }
   4020 
   4021 #if SRP_FEATURE_REPLICATION
   4022     if (srpl_connection != NULL) {
   4023         host->srpl_connection = srpl_connection;
   4024         srpl_connection_retain(host->srpl_connection);
   4025     }
   4026 #endif // SRP_FEATURE_REPLICATION
   4027 
   4028     // Apply the update.
   4029     prepare_update(host, client_update);
   4030     return true;
   4031 }
   4032 
   4033 void
   4034 srp_mdns_flush(srp_server_t *server_state)
   4035 {
   4036     adv_host_t *host, *host_next;
   4037 
   4038     INFO("flushing all host entries.");
   4039     for (host = server_state->hosts; host; host = host_next) {
   4040         INFO("Flushing services and host entry for " PRI_S_SRP " (" PRI_S_SRP ")",
   4041              host->name, host->registered_name);
   4042         // Get rid of the updates before calling delete_host, which will fail if update is not NULL.
   4043         if (host->update != NULL) {
   4044             update_failed(host->update, dns_rcode_refused, false, true);
   4045         }
   4046         host_next = host->next;
   4047         host_remove(host);
   4048     }
   4049     server_state->hosts = NULL;
   4050 }
   4051 
   4052 static void
   4053 usage(void)
   4054 {
   4055     ERROR("srp-mdns-proxy [--max-lease-time <seconds>] [--min-lease-time <seconds>] [--log-stderr]");
   4056     ERROR("               [--enable-replication | --disable-replication]");
   4057 #if SRP_FEATURE_NAT64
   4058     ERROR("               [--enable-nat64 | --disable-nat64]");
   4059 #endif
   4060     exit(1);
   4061 }
   4062 
   4063 srp_server_t *
   4064 server_state_create(const char *name, int max_lease_time, int min_lease_time,
   4065                     int key_max_lease_time, int key_min_lease_time)
   4066 {
   4067     srp_server_t *server_state = calloc(1, sizeof(*server_state));
   4068     if (server_state == NULL || (server_state->name = strdup(name)) == NULL) {
   4069         ERROR("no memory for server state");
   4070         free(server_state);
   4071         return NULL;
   4072     }
   4073     server_state->max_lease_time = max_lease_time;
   4074     server_state->min_lease_time = min_lease_time;
   4075     server_state->key_max_lease_time = key_max_lease_time;
   4076     server_state->key_min_lease_time = key_min_lease_time;
   4077     server_state->priority = PRIORITY_DEFAULT;
   4078 #if TARGET_OS_TV
   4079 #endif
   4080     INFO("priority set to %d", server_state->priority);
   4081     return server_state;
   4082 }
   4083 
   4084 static void
   4085 object_allocation_stats_dump_callback(void *context)
   4086 {
   4087     srp_server_t *server_state = context;
   4088 
   4089     ioloop_dump_object_allocation_stats();
   4090 
   4091     if (server_state->full_dump_count == 0) {
   4092         srp_dump_server_stats(server_state, true, true);
   4093         server_state->full_dump_count = 12;
   4094     } else {
   4095         srp_dump_server_stats(server_state, false, true);
   4096     }
   4097     --server_state->full_dump_count;
   4098 
   4099     // Do the next object memory allocation statistics dump in five minutes
   4100     ioloop_add_wake_event(server_state->object_allocation_stats_dump_wakeup, server_state,
   4101                           object_allocation_stats_dump_callback, NULL, 5 * 60 * 1000);
   4102 }
   4103 
   4104 int
   4105 main(int argc, char **argv)
   4106 {
   4107     int i;
   4108     char *end;
   4109     int log_stderr = false;
   4110 #ifdef SRP_TEST_SERVER
   4111     char *test_to_run = NULL;
   4112     bool normal_srp_startup = false;
   4113 #else
   4114     bool normal_srp_startup = true;
   4115 #endif
   4116 #if STUB_ROUTER
   4117     bool stub_router_enabled = false;
   4118 #endif
   4119     bool thread_device_enabled = false;
   4120 
   4121     srp_servers = server_state_create("srp-mdns-proxy",
   4122                                       3600 * 27,     // max lease time one day plus 20%
   4123                                       30,            // min lease time 30 seconds
   4124                                       3600 * 24 * 7, // max key lease 7 days
   4125                                       30);           // min key lease time 30s
   4126     if (srp_servers == NULL) {
   4127         return 1;
   4128     }
   4129 
   4130     if (normal_srp_startup) {
   4131         srp_servers->srp_replication_enabled = true;
   4132 #  if SRP_FEATURE_NAT64
   4133         srp_servers->srp_nat64_enabled = true;
   4134 #  endif
   4135     }
   4136 
   4137 
   4138     // Set the advertise interface
   4139     if (0) {
   4140 #if STUB_ROUTER
   4141     } else if (stub_router_enabled) {
   4142         srp_servers->advertise_interface = kDNSServiceInterfaceIndexAny;
   4143 #endif
   4144     } else {
   4145         srp_servers->advertise_interface = if_nametoindex("lo0");
   4146     }
   4147     for (i = 1; i < argc; i++) {
   4148         if (!strcmp(argv[i], "--max-lease-time")) {
   4149             if (i + 1 == argc) {
   4150                 usage();
   4151             }
   4152             srp_servers->max_lease_time = (uint32_t)strtoul(argv[i + 1], &end, 10);
   4153             if (end == argv[i + 1] || end[0] != 0) {
   4154                 usage();
   4155             }
   4156             i++;
   4157         } else if (!strcmp(argv[i], "--min-lease-time")) {
   4158             if (i + 1 == argc) {
   4159                 usage();
   4160             }
   4161             srp_servers->min_lease_time = (uint32_t)strtoul(argv[i + 1], &end, 10);
   4162             if (end == argv[i + 1] || end[0] != 0) {
   4163                 usage();
   4164             }
   4165             i++;
   4166         } else if (!strcmp(argv[i], "--log-stderr")) {
   4167             log_stderr = true;
   4168 #ifdef LOG_FPRINTF_STDERR
   4169         } else if (!strcmp(argv[i], "--log-relative-timestamp")) {
   4170             srp_log_timestamp_relative = true;
   4171 #endif
   4172         } else if (!strcmp(argv[i], "--enable-replication")) {
   4173             srp_servers->srp_replication_enabled = true;
   4174         } else if (!strcmp(argv[i], "--disable-replication")) {
   4175             srp_servers->srp_replication_enabled = false;
   4176         } else if (!strcmp(argv[i], "--fake-xpanid")) {
   4177             if (i + 1 == argc) {
   4178                 usage();
   4179             }
   4180             srp_servers->xpanid = strtoul(argv[i + 1], &end, 16);
   4181             if (end == argv[i + 1] || end[0] != 0) {
   4182                 usage();
   4183             }
   4184 #ifdef SRP_TEST_SERVER
   4185         } else if (!strcmp(argv[i], "--test")) {
   4186             if (i + 1 == argc) {
   4187                 usage();
   4188             }
   4189             test_to_run = argv[i + 1];
   4190             i++;
   4191 #endif
   4192 #if SRP_FEATURE_NAT64
   4193         } else if (!strcmp(argv[i], "--enable-nat64")) {
   4194             srp_servers->srp_nat64_enabled = true;
   4195         } else if (!strcmp(argv[i], "--disable-nat64")) {
   4196             srp_servers->srp_nat64_enabled = false;
   4197 #endif
   4198         } else {
   4199             usage();
   4200         }
   4201     }
   4202 
   4203     // Setup log category for srp-mdns-prox and dnssd-proxy.
   4204     OPENLOG("srp-mdns-proxy", log_stderr);
   4205 
   4206 #ifdef SRP_TEST_SERVER
   4207     INFO("srp-test-server starting, compiled on " PUB_S_SRP ", " PUB_S_SRP, __DATE__, __TIME__);
   4208 #else
   4209     INFO("--------------------------------"
   4210          "srp-mdns-proxy starting, compiled on " PUB_S_SRP ", " PUB_S_SRP
   4211          "--------------------------------", __DATE__, __TIME__);
   4212 #endif
   4213 
   4214     if (!ioloop_init()) {
   4215         return 1;
   4216     }
   4217 
   4218     if (normal_srp_startup) {
   4219 #if THREAD_DEVICE
   4220         if (0) {
   4221 #if STUB_ROUTER
   4222         } else if (stub_router_enabled) {
   4223             srp_servers->route_state = route_state_create(srp_servers, "srp-mdns-proxy");
   4224             if (srp_servers->route_state == NULL) {
   4225                 return 1;
   4226             }
   4227 #endif // STUB_ROUTER
   4228         }
   4229 
   4230         if (!srp_mdns_shared_registration_txn_setup(srp_servers)) {
   4231             return 1;
   4232         }
   4233         dns_service_op_not_to_be_freed = srp_servers->shared_registration_txn->sdref;
   4234 #endif // THREAD_DEVICE
   4235 
   4236 #if STUB_ROUTER
   4237         if (stub_router_enabled) {
   4238             // Set up the ULA early just in case we get an early registration, nat64 will use the ula
   4239             route_ula_setup(srp_servers->route_state);
   4240         }
   4241 #endif
   4242 
   4243 
   4244 #if (SRP_FEATURE_COMBINED_SRP_DNSSD_PROXY)
   4245         if (!init_dnssd_proxy(srp_servers)) {
   4246             ERROR("failed to setup dnssd-proxy");
   4247         }
   4248 #endif // #if (SRP_FEATURE_COMBINED_SRP_DNSSD_PROXY)
   4249 
   4250 #if STUB_ROUTER
   4251         if (stub_router_enabled) {
   4252             if (!start_icmp_listener()) {
   4253                 ERROR("failed to start icmp listener");
   4254             }
   4255         }
   4256 #endif
   4257 
   4258 
   4259         infrastructure_network_startup(srp_servers->route_state);
   4260 
   4261         if (adv_ctl_init(srp_servers) != kDNSServiceErr_NoError) {
   4262             ERROR("Can't start advertising proxy control server.");
   4263         }
   4264 
   4265         // We require one open file per service and one per instance.
   4266         struct rlimit limits;
   4267         if (getrlimit(RLIMIT_NOFILE, &limits) < 0) {
   4268             ERROR("getrlimit failed: " PUB_S_SRP, strerror(errno));
   4269         }
   4270 
   4271         if (limits.rlim_cur < 1024) {
   4272             if (limits.rlim_max < 1024) {
   4273                 INFO("file descriptor hard limit is %llu", (unsigned long long)limits.rlim_max);
   4274                 if (limits.rlim_cur != limits.rlim_max) {
   4275                     limits.rlim_cur = limits.rlim_max;
   4276                 }
   4277             } else {
   4278                 limits.rlim_cur = 1024;
   4279             }
   4280             if (setrlimit(RLIMIT_NOFILE, &limits) < 0) {
   4281                 ERROR("setrlimit failed: " PUB_S_SRP, strerror(errno));
   4282             }
   4283         }
   4284 
   4285         srp_proxy_init("local");
   4286 #ifdef SRP_TEST_SERVER
   4287     } else  {
   4288         ioloop_run_async(srp_test_server_run_test, test_to_run);
   4289 #endif
   4290     }
   4291 
   4292     srp_servers->object_allocation_stats_dump_wakeup = ioloop_wakeup_create();
   4293     if (srp_servers->object_allocation_stats_dump_wakeup == NULL) {
   4294         INFO("no memory for srp_servers->object_allocation_stats_dump_wakeup");
   4295     } else {
   4296         // Do an object memory allocation statistics dump every five minutes, and a full database dump every half hour
   4297         // starting after the first five minutes
   4298         srp_servers->full_dump_count = 1;
   4299         object_allocation_stats_dump_callback(srp_servers);
   4300     }
   4301 
   4302     ioloop();
   4303 }
   4304 
   4305 // Local Variables:
   4306 // mode: C
   4307 // tab-width: 4
   4308 // c-file-style: "bsd"
   4309 // c-basic-offset: 4
   4310 // fill-column: 120
   4311 // indent-tabs-mode: nil
   4312 // End:
   4313