3 * Copyright (c) 2018-2019 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 * DNSServiceRegister API for SRP. See dns_sd.h for details on the API.
29 #include "../mDNSShared/dns_sd.h"
32 #include <arpa/inet.h>
37 #include "srp-crypto.h"
39 typedef struct client_state client_state_t
;
41 typedef struct service_addr service_addr_t
;
43 service_addr_t
*NULLABLE next
;
48 typedef struct _DNSServiceRef_t reg_state_t
;
49 typedef struct update_context
{
52 client_state_t
*NONNULL client
;
53 service_addr_t
*server
;
54 service_addr_t
*interfaces
;
55 size_t message_length
;
56 uint32_t next_retransmission_time
;
57 uint32_t next_attempt_time
;
59 uint32_t key_lease_time
;
61 bool notified
; // Callers have been notified.
62 bool connected
; // UDP context is connected.
63 bool removing
; // We are removing the current registration(s)
66 struct _DNSServiceRef_t
{
67 reg_state_t
*NULLABLE next
;
69 DNSServiceFlags flags
;
70 uint32_t interfaceIndex
;
72 char *NULLABLE regtype
;
73 char *NULLABLE domain
;
77 void *NULLABLE txtRecord
;
78 DNSServiceRegisterReply callback
;
81 void *NULLABLE context
;
86 reg_state_t
*registrations
;
88 int hostname_rename_number
; // If we've had a naming conflict, this will be nonzero.
89 srp_hostname_conflict_callback_t hostname_conflict_callback
;
93 uint32_t key_lease_time
;
94 uint32_t registration_serial
;
95 uint32_t srp_max_attempt_interval
;
96 uint32_t srp_max_retry_interval
;
97 service_addr_t stable_server
;
98 bool srp_server_synced
;
102 // Currently we only ever have one update in flight. If we decide we need to send another,
103 // we need to cancel the one we're currently doing.
104 update_context_t
*active_update
;
107 // Implementation of SRP network entry points, which can be called by the network implementation on the
110 static bool network_state_changed
= false;
111 static bool doing_refresh
= false;
112 static service_addr_t
*interfaces
;
113 static service_addr_t
*servers
;
114 static service_addr_t
*interface_refresh_state
;
115 static service_addr_t
*server_refresh_state
;
116 static uint8_t no_port
[2];
118 client_state_t
*clients
;
119 client_state_t
*current_client
;
121 // Forward references
122 static int do_srp_update(client_state_t
*client
, bool definite
);
123 static void udp_response(void *v_update_context
, void *v_message
, size_t message_length
);
124 static dns_wire_t
*NULLABLE
generate_srp_update(client_state_t
*client
, uint32_t update_lease_time
,
125 uint32_t update_key_lease_time
, size_t *NONNULL p_length
,
126 service_addr_t
*NONNULL server
, uint32_t serial
, bool remove
);
127 static bool srp_is_network_active(void);
129 #define VALIDATE_IP_ADDR \
130 if ((rrtype != dns_rrtype_a && rrtype != dns_rrtype_aaaa) || \
131 (rrtype == dns_rrtype_a && rdlen != 4) || \
132 (rrtype == dns_rrtype_aaaa && rdlen != 16)) { \
133 return kDNSServiceErr_Invalid; \
136 // Call this before calling anything else. Context will be passed back whenever the srp code
137 // calls any of the host functions.
139 srp_host_init(void *context
)
141 client_state_t
*new_client
= calloc(1, sizeof(*new_client
));
142 if (new_client
== NULL
) {
143 return kDNSServiceErr_NoMemory
;
145 new_client
->os_context
= context
;
146 new_client
->lease_time
= 3600; // 1 hour for registration leases
147 new_client
->key_lease_time
= 604800; // 7 days for key leases
148 new_client
->registration_serial
= 0;
149 new_client
->srp_max_attempt_interval
= 1000 * 60 * 60; // By default, never wait longer than an hour to do another
150 // registration attempt.
151 new_client
->srp_max_retry_interval
= 1000 * 15; // Default retry interval is 15 seconds--three attempts.
153 current_client
= new_client
;
154 new_client
->next
= clients
;
155 clients
= current_client
;
156 return kDNSServiceErr_NoError
;
160 srp_host_key_reset(void)
162 if (current_client
->key
!= NULL
) {
163 srp_keypair_free(current_client
->key
);
164 current_client
->key
= NULL
;
166 return srp_reset_key("com.apple.srp-client.host-key", current_client
->os_context
);
170 srp_set_lease_times(uint32_t new_lease_time
, uint32_t new_key_lease_time
)
172 current_client
->lease_time
= new_lease_time
;
173 current_client
->key_lease_time
= new_key_lease_time
;
174 return kDNSServiceErr_NoError
;
178 sync_from_stable_storage(update_context_t
*update
)
180 service_addr_t
*server
;
181 client_state_t
*client
= update
->client
;
182 if (!client
->srp_server_synced
) {
183 client
->srp_server_synced
=
184 srp_get_last_server(&client
->stable_server
.rr
.type
, (uint8_t *)&client
->stable_server
.rr
.data
,
185 sizeof(client
->stable_server
.rr
.data
), &client
->stable_server
.port
[0],
188 if (!client
->srp_server_synced
) {
192 if (update
->server
!= NULL
) {
197 // See if one of the advertised servers is the one we last updated.
198 for (server
= servers
; server
; server
= server
->next
) {
199 if (server
->rr
.type
== client
->stable_server
.rr
.type
&&
200 !memcmp(&server
->port
, &client
->stable_server
.port
, 2) &&
201 ((server
->rr
.type
== dns_rrtype_a
&& !memcmp(&server
->rr
.data
, &client
->stable_server
.rr
.data
, 4)) ||
202 (server
->rr
.type
== dns_rrtype_aaaa
&& !memcmp(&server
->rr
.data
, &client
->stable_server
.rr
.data
, 16))))
204 update
->server
= server
;
211 sync_to_stable_storage(update_context_t
*update
)
213 client_state_t
*client
= update
->client
;
214 if (!client
->srp_server_synced
) {
215 client
->srp_server_synced
=
216 srp_save_last_server(client
->stable_server
.rr
.type
, (uint8_t *)&client
->stable_server
.rr
.data
,
217 client
->stable_server
.rr
.type
== dns_rrtype_a
? 4 : 16,
218 client
->stable_server
.port
, client
->os_context
);
222 // Find an address on a list of addresses.
223 static service_addr_t
**
224 find_address(service_addr_t
**addrs
, const uint8_t *port
, uint16_t rrtype
, const uint8_t *rdata
, uint16_t rdlen
)
226 service_addr_t
*addr
, **p_addr
= addrs
;
228 while (*p_addr
!= NULL
) {
230 if (addr
->rr
.type
== rrtype
&& !memcmp(&addr
->rr
.data
, rdata
, rdlen
) && !memcmp(addr
->port
, port
, 2)) {
233 p_addr
= &addr
->next
;
238 // Worker function to add an address and notice whether the network state has changed (so as to trigger a
241 add_address(service_addr_t
**list
, service_addr_t
**refresh
,
242 const uint8_t *port
, uint16_t rrtype
, const uint8_t *rdata
, uint16_t rdlen
)
244 service_addr_t
*addr
, **p_addr
, **p_refresh
;
248 // See if the address is on the refresh list.
249 p_refresh
= find_address(refresh
, port
, rrtype
, rdata
, rdlen
);
251 // See also if it's on the address list (shouldn't be on both). This also finds the end of the list.
252 p_addr
= find_address(list
, port
, rrtype
, rdata
, rdlen
);
253 if (*p_addr
!= NULL
) {
254 return kDNSServiceErr_NoError
;
257 if (*p_refresh
!= NULL
) {
260 // This shouldn't happen, but if it does, free the old address.
261 if (*p_addr
!= NULL
) {
262 ERROR("duplicate address during refresh!");
264 return kDNSServiceErr_NoError
;
267 *p_refresh
= addr
->next
;
271 // In this case, the network state has not changed.
272 return kDNSServiceErr_NoError
;
275 addr
= calloc(1, sizeof *addr
);
277 return kDNSServiceErr_NoMemory
;
279 addr
->rr
.type
= rrtype
;
280 addr
->rr
.qclass
= dns_qclass_in
;
281 memcpy(&addr
->rr
.data
, rdata
, rdlen
);
282 memcpy(&addr
->port
, port
, 2);
284 network_state_changed
= true;
286 // Print IPv6 address directly here because the code has to be portable for ADK, and OpenThread environment
287 // has no support for INET6_ADDRSTRLEN.
288 INFO("added " PUB_S_SRP
289 " address: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x port %u (%04x)",
290 *list
== servers
? "server" : "interface",
291 rdata
[0], rdata
[1], rdata
[2], rdata
[3], rdata
[4], rdata
[5], rdata
[6], rdata
[7],
292 rdata
[8], rdata
[9], rdata
[10], rdata
[11], rdata
[12], rdata
[13], rdata
[14], rdata
[15],
293 port
!= NULL
? (port
[0] << 8 | port
[1]) : 0, port
!= NULL
? (port
[0] << 8 | port
[1]) : 0);
295 return kDNSServiceErr_NoError
;
298 // Called when a new address is configured that should be advertised. This can be called during a refresh,
299 // in which case it doesn't mark the network state as changed if the address was already present.
301 srp_add_interface_address(uint16_t rrtype
, const uint8_t *NONNULL rdata
, uint16_t rdlen
)
303 return add_address(&interfaces
, &interface_refresh_state
, no_port
, rrtype
, rdata
, rdlen
);
306 // Called whenever the SRP server address changes or the SRP server becomes newly reachable. This can be
307 // called during a refresh, in which case it doesn't mark the network state as changed if the address was
310 srp_add_server_address(const uint8_t *port
, uint16_t rrtype
, const uint8_t *NONNULL rdata
, uint16_t rdlen
)
314 return add_address(&servers
, &server_refresh_state
, port
, rrtype
, rdata
, rdlen
);
317 // Called when the node knows its hostname (usually once). The callback is called if we try to do an SRP
318 // update and find out that the hostname is in use; in this case, the callback is expected to generate a new
319 // hostname and re-register it. It is permitted to call srp_set_hostname() from the callback.
320 // If the hostname is changed by the callback, then it is used immediately on return from the callback;
321 // if the hostname is changed in any other situation, nothing is done with the new name until
322 // srp_network_state_stable() is called.
324 srp_set_hostname(const char *NONNULL name
, srp_hostname_conflict_callback_t callback
)
326 if (current_client
->hostname
!= NULL
) {
327 free(current_client
->hostname
);
329 current_client
->hostname
= strdup(name
);
330 if (current_client
->hostname
== NULL
) {
331 return kDNSServiceErr_NoMemory
;
333 current_client
->hostname_conflict_callback
= callback
;
334 network_state_changed
= true;
335 return kDNSServiceErr_NoError
;
338 // Called when a network state change is complete (that is, all new addresses have been saved and
339 // any update to the SRP server address has been provided). This is only needed when not using the
340 // refresh mechanism.
342 srp_is_network_active(void)
344 INFO("srp_is_network_active: nsc = %d servers = %p interfaces = %p, hostname = " PRI_S_SRP
,
345 network_state_changed
, servers
, interfaces
,
346 current_client
->hostname
? current_client
->hostname
: "<not set>");
347 return servers
!= NULL
&& interfaces
!= NULL
&& current_client
->hostname
!= NULL
;
351 srp_network_state_stable(void)
353 client_state_t
*client
;
354 int status
= kDNSServiceErr_NoError
;
355 if (network_state_changed
&& srp_is_network_active()) {
356 network_state_changed
= false;
357 for (client
= clients
; client
; client
= client
->next
) {
358 int ret
= do_srp_update(client
, false);
359 // In the normal case, there will only be one client, and therefore one return status. For testing,
360 // we allow more than one client; if we get an error here, we return it, but we still launch all the
362 if (ret
!= kDNSServiceErr_NoError
&& status
== kDNSServiceErr_NoError
) {
367 return kDNSServiceErr_NoError
;
370 // Worker function to delete a server or interface address that was previously configured.
372 delete_address(service_addr_t
**list
, const uint8_t *port
, uint16_t rrtype
, const uint8_t *NONNULL rdata
,
375 service_addr_t
*addr
, **p_addr
;
377 // Delete API and refresh API are incompatible.
379 return kDNSServiceErr_BadState
;
383 // See if we know this address.
384 p_addr
= find_address(list
, port
, rrtype
, rdata
, rdlen
);
385 if (*p_addr
!= NULL
) {
387 *p_addr
= addr
->next
;
389 network_state_changed
= true;
390 return kDNSServiceErr_NoError
;
392 return kDNSServiceErr_NoSuchRecord
;
395 // Delete a previously-configured SRP server address. This should not be done during a refresh.
397 srp_delete_interface_address(uint16_t rrtype
, const uint8_t *NONNULL rdata
, uint16_t rdlen
)
399 return delete_address(&interfaces
, no_port
, rrtype
, rdata
, rdlen
);
402 // Delete a previously-configured SRP server address. This should not be done during a refresh.
404 srp_delete_server_address(uint16_t rrtype
, const uint8_t *port
, const uint8_t *NONNULL rdata
, uint16_t rdlen
)
406 return delete_address(&servers
, port
, rrtype
, rdata
, rdlen
);
409 // Call this to start an address refresh. This makes sense to do in cases where the caller
410 // is not tracking changes, but rather is just doing a full refresh whenever the network state
411 // is seen to have changed. When the refresh is done, if any addresses were added or removed,
412 // network_state_changed will be true, and so a call to dnssd_network_state_change_finished()
413 // will trigger an update; if nothing changed, no update will be sent.
415 srp_start_address_refresh(void)
418 return kDNSServiceErr_BadState
;
420 doing_refresh
= true;
421 interface_refresh_state
= interfaces
;
422 server_refresh_state
= servers
;
425 network_state_changed
= false;
426 return kDNSServiceErr_NoError
;
429 // Call this when the address refresh is done. This invokes srp_network_state_stable().
431 srp_finish_address_refresh(void)
433 service_addr_t
*addr
, *next
;
435 if (!doing_refresh
) {
436 return kDNSServiceErr_BadState
;
438 for (i
= 0; i
< 2; i
++) {
440 next
= server_refresh_state
;
441 server_refresh_state
= NULL
;
443 next
= interface_refresh_state
;
444 interface_refresh_state
= NULL
;
447 network_state_changed
= true;
450 uint8_t *rdata
= (uint8_t *)&next
->rr
.data
;
451 // Print IPv6 address directly here because the code has to be portable for ADK, and OpenThread environment
452 // has no support for INET6_ADDRSTRLEN.
453 INFO("deleted " PUB_S_SRP
454 " address: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x port %u (%x)",
455 i
? "interface" : "server",
456 rdata
[0], rdata
[1], rdata
[2], rdata
[3], rdata
[4], rdata
[5], rdata
[6], rdata
[7],
457 rdata
[8], rdata
[9], rdata
[10], rdata
[11], rdata
[12], rdata
[13], rdata
[14], rdata
[15],
458 (next
->port
[0] << 8) | next
->port
[1], (next
->port
[0] << 8) | next
->port
[1]);
464 doing_refresh
= false;
465 return srp_network_state_stable();
468 // Implementation of the API that the application will call to update the TXT record after having registered
469 // a service previously with a different TXT record. In principle this can also update a record added with
470 // DNSServiceAddRecord or DNSServiceRegisterRecord, but we don't support those APIs at present.
473 DNSServiceUpdateRecord(DNSServiceRef sdRef
, DNSRecordRef RecordRef
, DNSServiceFlags flags
,
474 uint16_t rdlen
, const void *rdata
, uint32_t ttl
)
476 reg_state_t
*registration
;
477 void *txtRecord
= NULL
;
483 if (sdRef
== NULL
|| RecordRef
!= NULL
|| rdata
== NULL
) {
484 return kDNSServiceErr_Invalid
;
487 // Add it to the list (so it will appear valid to DNSServiceRefDeallocate()).
488 for (registration
= current_client
->registrations
; registration
!= NULL
; registration
= registration
->next
) {
489 if (registration
== sdRef
) {
493 if (registration
== NULL
) {
494 return kDNSServiceErr_BadReference
;
498 txtRecord
= malloc(rdlen
);
499 if (txtRecord
== NULL
) {
500 return kDNSServiceErr_NoMemory
;
502 memcpy(txtRecord
, rdata
, rdlen
);
504 registration
->txtRecord
= NULL
;
507 if (registration
->txtRecord
!= NULL
) {
508 free(registration
->txtRecord
);
511 registration
->txtRecord
= txtRecord
;
512 registration
->txtLen
= rdlen
;
513 network_state_changed
= true;
514 return kDNSServiceErr_NoError
;
517 // Implementation of the API that applications will call to register services. This is independent of the
518 // hosting platform API.
520 DNSServiceRegister(DNSServiceRef
*sdRef
, DNSServiceFlags flags
, uint32_t interfaceIndex
,
521 const char *NULLABLE name
, const char *NULLABLE regtype
, const char *NULLABLE domain
,
522 const char *NULLABLE host
, uint16_t port
,
523 uint16_t txtLen
, const void *txtRecord
,
524 DNSServiceRegisterReply callBack
, void *context
)
526 reg_state_t
**rp
, *reg
= calloc(1, sizeof *reg
);
528 return kDNSServiceErr_NoMemory
;
531 // Add it to the list (so it will appear valid to DNSServiceRefDeallocate()).
532 rp
= ¤t_client
->registrations
;
538 // If we don't already have a hostname, use the one from the registration.
539 if (current_client
->hostname
== NULL
) {
540 srp_set_hostname(host
, NULL
);
543 reg
->serial
= current_client
->registration_serial
++;
545 reg
->interfaceIndex
= interfaceIndex
;
546 reg
->called_back
= true;
547 #define stashName(thing) \
548 if (thing != NULL) { \
549 reg->thing = strdup(thing); \
550 if (reg->thing == NULL) { \
551 DNSServiceRefDeallocate(reg); \
552 return kDNSServiceErr_NoMemory; \
562 reg
->txtLen
= txtLen
;
564 reg
->txtRecord
= malloc(txtLen
);
565 if (reg
->txtRecord
== NULL
) {
566 DNSServiceRefDeallocate(reg
);
567 return kDNSServiceErr_NoMemory
;
569 memcpy(reg
->txtRecord
, txtRecord
, txtLen
);
571 reg
->txtRecord
= NULL
;
573 reg
->callback
= callBack
;
574 reg
->context
= context
;
576 network_state_changed
= true;
577 return kDNSServiceErr_NoError
;
581 DNSServiceRefDeallocate(DNSServiceRef sdRef
)
583 reg_state_t
**rp
, *reg
= NULL
;
585 client_state_t
*client
;
591 for (client
= clients
; client
; client
= client
->next
) {
592 // Remove it from the list.
593 rp
= &client
->registrations
;
610 // This avoids a bogus free.
611 if (!found
|| reg
== NULL
) {
614 if (reg
->name
!= NULL
) {
617 if (reg
->regtype
!= NULL
) {
620 if (reg
->domain
!= NULL
) {
623 if (reg
->host
!= NULL
) {
626 if (reg
->txtRecord
!= NULL
) {
627 free(reg
->txtRecord
);
633 update_finalize(update_context_t
*update
)
635 client_state_t
*client
= update
->client
;
636 if (update
->udp_context
!= NULL
) {
637 srp_deactivate_udp_context(client
->os_context
, update
->udp_context
);
639 if (update
->message
!= NULL
) {
640 free(update
->message
);
642 if (update
->interfaces
!= NULL
) {
643 free(update
->interfaces
);
649 do_callbacks(client_state_t
*client
, uint32_t serial
, int err
, bool succeeded
)
654 // The callback can modify the list, so we use a marker to remember where we are in the list rather
655 // than remembering a pointer which could be invalidated. If a callback adds a registration, that
656 // registration doesn't get called because called_back is set to true when a registration is added.
657 for (rp
= client
->registrations
; rp
; rp
= rp
->next
) {
658 if (rp
->serial
<= serial
) {
659 rp
->called_back
= false;
664 for (rp
= client
->registrations
; rp
; rp
= rp
->next
) {
665 if (rp
->serial
> serial
|| rp
->callback
== NULL
|| rp
->called_back
) {
669 rp
->called_back
= true;
670 if (rp
->callback
!= NULL
) {
671 rp
->callback(rp
, kDNSServiceFlagsAdd
, err
, rp
->name
, rp
->regtype
, rp
->domain
, rp
->context
);
674 rp
->succeeded
= true;
681 udp_retransmit(void *v_update_context
)
683 update_context_t
*context
= v_update_context
;
684 client_state_t
*client
;
685 service_addr_t
*next_server
= NULL
;
688 client
= context
->client
;
690 if (!srp_is_network_active()) {
691 INFO("udp_retransmit: network is down, discontinuing renewals.");
692 if (client
->active_update
!= NULL
) {
693 update_finalize(client
->active_update
);
694 client
->active_update
= NULL
;
698 // It shouldn't be possible for this to happen.
699 if (client
->active_update
== NULL
) {
700 INFO("udp_retransmit: no active update for " PRI_S_SRP
" (%p).",
701 client
->hostname
? client
->hostname
: "<null>", client
);
704 INFO("udp_retransmit: next_attempt %" PRIu32
" next_retransmission %" PRIu32
" for " PRI_S_SRP
" (%p)",
705 context
->next_attempt_time
, context
->next_retransmission_time
,
706 client
->hostname
? client
->hostname
: "<null>", client
);
708 // If next retransmission time is zero, this means that we gave up our last attempt to register, and have
709 // now waited long enough to try again. We will then use an exponential backoff for 90 seconds before giving
710 // up again; if we give up again, we will wait longer to retry, up to an hour.
711 if (context
->next_retransmission_time
== 0) {
712 // If there are no servers, we don't need to schedule a re-attempt: when a server is seen, we will do
713 // an update immediately.
714 if (servers
== NULL
) {
717 next_server
= servers
;
719 // If this attempt fails, don't try again for a while longer, but limit the retry interval to an hour.
720 context
->next_attempt_time
*= 2;
721 if (context
->next_attempt_time
> client
->srp_max_attempt_interval
) {
722 context
->next_attempt_time
= client
->srp_max_attempt_interval
;
724 context
->next_retransmission_time
= 2000; // Next retry will be in two seconds.
726 // If this would be our fourth retry on a particular server, try the next server.
727 else if (context
->next_retransmission_time
> client
->srp_max_retry_interval
) {
728 // If we are removing, there is no point in trying the next server--just give up and report a timeout.
729 if (context
->removing
) {
730 do_callbacks(client
, context
->serial
, kDNSServiceErr_Timeout
, false);
731 // Once the goodbye retransmission has timed out, we're done.
734 for (next_server
= servers
; next_server
; next_server
= next_server
->next
) {
735 if (next_server
== context
->server
) {
736 // We're going to use the next server after the one we just tried. If we run out of servers,
737 // we'll give up for a while.
738 next_server
= next_server
->next
;
743 // If we run off the end of the list, give up for a bit.
744 if (next_server
== NULL
) {
745 context
->next_retransmission_time
= 0;
747 context
->next_retransmission_time
= 2000;
750 // Otherwise, we are still trying to win with a particular server, so back off exponentially.
752 context
->next_retransmission_time
*= 2;
755 // If we are giving up on the current server, get rid of any udp state.
756 if (context
->next_retransmission_time
== 0 || next_server
!= NULL
) {
757 if (next_server
!= NULL
) {
758 context
->server
= next_server
;
760 srp_disconnect_udp(context
->udp_context
);
761 context
->connected
= false;
762 if (context
->message
!= NULL
) {
763 free(context
->message
);
765 context
->message
= NULL
;
766 context
->message_length
= 0;
769 // If we are not giving up, send the next packet.
770 if (context
->server
!= NULL
&& context
->next_retransmission_time
!= 0) {
771 if (!context
->connected
) {
772 // Create a UDP context for this transaction.
773 err
= srp_connect_udp(context
->udp_context
, context
->server
->port
, servers
->rr
.type
,
774 (uint8_t *)&context
->server
->rr
.data
,
775 context
->server
->rr
.type
== dns_rrtype_a
? 4 : 16);
776 // In principle if it fails here, it might succeed later, so we just don't send a packet and let
777 // the timeout take care of it.
778 if (err
!= kDNSServiceErr_NoError
) {
779 ERROR("udp_retransmit: error %d creating udp context.", err
);
781 context
->connected
= true;
785 if (context
->message
== NULL
) {
786 context
->message
= generate_srp_update(client
, client
->lease_time
, client
->key_lease_time
, &context
->message_length
,
787 context
->server
, context
->serial
, context
->removing
);
788 if (context
->message
== NULL
) {
789 ERROR("No memory for message.");
794 if (context
->connected
) {
795 // Send the datagram to the server
796 err
= srp_send_datagram(client
->os_context
, context
->udp_context
, context
->message
, context
->message_length
);
797 if (err
!= kDNSServiceErr_NoError
) {
798 ERROR("udp_retransmit: error %d sending a datagram.", err
);
803 // If we've given up for now, schedule a next attempt; otherwise, schedule the next retransmission.
804 if (context
->next_retransmission_time
== 0) {
805 err
= srp_set_wakeup(client
->os_context
, context
->udp_context
, context
->next_attempt_time
, udp_retransmit
);
807 err
= srp_set_wakeup(client
->os_context
, context
->udp_context
,
808 context
->next_retransmission_time
- 512 + srp_random16() % 1024, udp_retransmit
);
810 if (err
!= kDNSServiceErr_NoError
) {
811 INFO("udp_retransmit: error %d setting wakeup", err
);
817 renew_callback(void *v_update_context
)
819 update_context_t
*context
= v_update_context
;
820 client_state_t
*client
= context
->client
;
821 INFO("renew callback");
822 do_srp_update(client
, true);
825 // This function will, if hostname_rename_number is nonzero, create a hostname using the chosen hostname plus
826 // space plus the number as ascii text. The caller is responsible for freeing the return value if it's not NULL.
828 conflict_print(client_state_t
*client
, dns_towire_state_t
*towire
, char **return_hostname
, char *chosen_hostname
)
830 char *conflict_hostname
;
833 if (client
->hostname_rename_number
== 0) {
834 *return_hostname
= chosen_hostname
;
838 hostname_len
= strlen(chosen_hostname
);
839 // 7 is max length of decimal short (5) plus space plus NUL
840 if (hostname_len
+ 7 > DNS_MAX_LABEL_SIZE
) {
841 hostname_len
= DNS_MAX_LABEL_SIZE
- 7;
843 conflict_hostname
= malloc(hostname_len
+ 7);
844 if (conflict_hostname
== NULL
) {
845 if (towire
!= NULL
) {
846 towire
->line
= __LINE__
;
847 towire
->outer_line
= -1;
848 towire
->error
= true;
850 *return_hostname
= chosen_hostname
;
854 memcpy(conflict_hostname
, chosen_hostname
, hostname_len
);
855 snprintf(conflict_hostname
+ hostname_len
, 7, " %d", client
->hostname_rename_number
);
856 *return_hostname
= conflict_hostname
;
857 return conflict_hostname
;
861 udp_response(void *v_update_context
, void *v_message
, size_t message_length
)
863 update_context_t
*context
= v_update_context
;
864 client_state_t
*client
= context
->client
;
865 dns_wire_t
*message
= v_message
;
867 int rcode
= dns_rcode_get(message
);
868 (void)message_length
;
869 uint32_t new_lease_time
;
870 reg_state_t
*registration
;
871 const uint8_t *p
= message
->data
;
872 const uint8_t *end
= (const uint8_t *)v_message
+ message_length
;
873 bool resolve_name_conflict
= false;
874 char *conflict_hostname
= NULL
, *chosen_hostname
;
877 INFO("Got a response for %p, rcode = %d", client
, dns_rcode_get(message
));
879 // Cancel the retransmit wakeup.
880 err
= srp_cancel_wakeup(client
->os_context
, context
->udp_context
);
881 if (err
!= kDNSServiceErr_NoError
) {
882 INFO("udp_response: %d", err
);
884 // We want a different UDP source port for each transaction, so cancel the current UDP state.
885 srp_disconnect_udp(context
->udp_context
);
886 context
->connected
= false;
888 // When we are doing a remove, we don't actually care what the result is--if we get back an answer, we call
890 if (context
->removing
) {
891 do_callbacks(client
, context
->serial
, kDNSServiceErr_NoSuchRecord
, false);
895 // Deal with the response.
897 case dns_rcode_noerror
:
898 // Remember the server we connected with. active_update and active_update->server should always be
900 if (client
->active_update
!= NULL
&& client
->active_update
->server
!= NULL
) {
901 // If the new server is not the one that's mentioned in stable_server, then update the one
903 if (client
->active_update
->server
->rr
.type
!= client
->stable_server
.rr
.type
||
904 (client
->stable_server
.rr
.type
== dns_rrtype_a
905 ? memcmp(&client
->stable_server
.rr
.data
, &client
->active_update
->server
->rr
.data
, 4)
906 : (client
->stable_server
.rr
.type
== dns_rrtype_aaaa
907 ? memcmp(&client
->stable_server
.rr
.data
, &client
->active_update
->server
->rr
.data
, 16)
909 memcmp(client
->stable_server
.port
, client
->active_update
->server
->port
, 2))
911 memcpy(&client
->stable_server
, client
->active_update
->server
, sizeof(client
->stable_server
));
912 client
->srp_server_synced
= false;
914 sync_to_stable_storage(client
->active_update
);
917 // Get the renewal time
918 // At present, there's no code to actually parse a real DNS packet in the client, so
919 // we rely on the server returning just an EDNS0 option; if this assumption fails, we
921 if (message
->qdcount
== 0 && message
->ancount
== 0 &&
922 message
->nscount
== 0 && ntohs(message
->arcount
) == 1 &&
924 // We expect the edns0 option to be:
925 // root label - 1 byte
929 // rdlength = 2 bytes
930 // lease option code = 2
931 // lease option length = 2
935 end
- p
== 23 && // right number of bytes for an EDNS0 OPT containing an update lease option
936 *p
== 0 && // root label
937 p
[1] == (dns_rrtype_opt
>> 8) && p
[2] == (dns_rrtype_opt
& 255) &&
938 // skip class and ttl, we don't care
939 p
[9] == 0 && p
[10] == 12 && // rdlength
940 p
[11] == (dns_opt_update_lease
>> 8) && p
[12] == (dns_opt_update_lease
& 255) &&
941 p
[13] == 0 && p
[14] == 8) // opt_length
943 new_lease_time
= (((uint32_t)p
[15] << 12) | ((uint32_t)p
[16] << 8) |
944 ((uint32_t)p
[17] << 8) | ((uint32_t)p
[18]));
945 INFO("Lease time set to %" PRIu32
, new_lease_time
);
947 new_lease_time
= context
->lease_time
;
948 INFO("Lease time defaults to %" PRIu32
, new_lease_time
);
949 DEBUG("len %ld qd %d an %d ns %d ar %d data %02x %02x %02x %02x %02x %02x %02x %02x %02x"
950 " %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
951 (unsigned long)(end
- p
), ntohs(message
->qdcount
), ntohs(message
->ancount
),
952 ntohs(message
->nscount
), ntohs(message
->arcount
),
953 p
[0], p
[1], p
[2], p
[3], p
[3], p
[5], p
[6], p
[7], p
[8], p
[9], p
[10], p
[11],
954 p
[12], p
[13], p
[14], p
[15], p
[16], p
[17], p
[18], p
[19], p
[20], p
[21], p
[22]);
957 // Set up to renew. Time is in milliseconds, and we want to renew at 80% of the lease time.
958 srp_set_wakeup(client
->os_context
, context
->udp_context
, (new_lease_time
* 1000) * 8 / 10, renew_callback
);
960 do_callbacks(client
, context
->serial
, kDNSServiceErr_NoError
, true);
962 case dns_rcode_yxdomain
:
963 // Get the actual hostname that we sent.
964 if (client
->hostname_conflict_callback
!= NULL
&& client
->hostname
!= NULL
) {
965 conflict_hostname
= conflict_print(client
, NULL
, &chosen_hostname
, client
->hostname
);
966 client
->hostname_conflict_callback(chosen_hostname
);
967 if (conflict_hostname
!= NULL
) {
968 free(conflict_hostname
);
971 resolve_name_conflict
= true;
974 bool resolve_with_callback
= true;
975 for (registration
= client
->registrations
; registration
; registration
= registration
->next
) {
976 if (registration
->callback
!= NULL
&& registration
->serial
<= context
->serial
&&
977 !(registration
->flags
& kDNSServiceFlagsNoAutoRename
))
979 resolve_with_callback
= false;
982 if (resolve_with_callback
) {
983 do_callbacks(client
, context
->serial
, kDNSServiceErr_NameConflict
, false);
985 resolve_name_conflict
= true;
988 if (resolve_name_conflict
) {
989 // If we get a name conflict, try using a low number to rename, but only twice; it's time consuming to do
990 // this, so if we get two conflicts, we switch to using a random number.
991 if (client
->hostname_rename_number
< 2) {
992 client
->hostname_rename_number
++;
994 client
->hostname_rename_number
= srp_random16();
996 // When we get a name conflict response, we need to re-do the update immediately
997 // (with a 0-500ms delay of course).
998 do_srp_update(client
, true);
1003 // Any other response has to be treated as a transient failure, so we need to retry
1004 // This sort of failure is essentially unacceptable in a real deployment--it indicates
1005 // that something is seriously broken. But it's not up to the client to debug that.
1006 retry_time
= context
->lease_time
* 4 / 5;
1007 // We don't want to retry _too_ often.
1008 if (retry_time
< 120) {
1011 srp_set_wakeup(client
->os_context
, context
->udp_context
, retry_time
* 1000, renew_callback
);
1016 // Generate a new SRP update message
1018 generate_srp_update(client_state_t
*client
, uint32_t update_lease_time
, uint32_t update_key_lease_time
,
1019 size_t *NONNULL p_length
, service_addr_t
*server
, uint32_t serial
, bool removing
)
1021 dns_wire_t
*message
;
1022 const char *zone_name
= "default.service.arpa";
1023 const char *service_type
= "_ipps._tcp";
1024 const char *txt_record
= "0";
1026 dns_towire_state_t towire
;
1027 dns_name_pointer_t p_host_name
;
1028 dns_name_pointer_t p_zone_name
;
1029 dns_name_pointer_t p_service_name
;
1030 dns_name_pointer_t p_service_instance_name
;
1032 service_addr_t
*addr
;
1034 char *conflict_hostname
= NULL
, *chosen_hostname
;
1036 #define INCREMENT(x) (x) = htons(ntohs(x) + 1)
1037 memset(&towire
, 0, sizeof towire
);
1039 // Get the key if we don't already have it.
1040 if (client
->key
== NULL
) {
1041 client
->key
= srp_get_key("com.apple.srp-client.host-key", client
->os_context
);
1042 if (client
->key
== NULL
) {
1043 INFO("No key gotten.");
1048 #define CH if (towire.error) { line = __LINE__; goto fail; }
1050 if (client
->hostname
== NULL
) {
1051 ERROR("generate_srp_update called with NULL hostname.");
1055 // Allocate a message buffer.
1056 message
= calloc(1, sizeof *message
);
1057 if (message
== NULL
) {
1060 towire
.p
= &message
->data
[0]; // We start storing RR data here.
1061 towire
.lim
= &message
->data
[DNS_DATA_SIZE
]; // This is the limit to how much we can store.
1062 towire
.message
= message
;
1064 // Generate a random UUID.
1065 message
->id
= srp_random16();
1066 message
->bitfield
= 0;
1067 dns_qr_set(message
, dns_qr_query
);
1068 dns_opcode_set(message
, dns_opcode_update
);
1070 message
->qdcount
= 0;
1071 // Copy in Zone name (and save pointer)
1074 dns_full_name_to_wire(&p_zone_name
, &towire
, zone_name
); CH
;
1075 dns_u16_to_wire(&towire
, dns_rrtype_soa
); CH
;
1076 dns_u16_to_wire(&towire
, dns_qclass_in
); CH
;
1077 INCREMENT(message
->qdcount
);
1079 message
->ancount
= 0;
1082 message
->nscount
= 0;
1085 // Host Description:
1086 // * Delete all RRsets from <hostname>; remember the pointer to hostname
1087 // NAME = hostname label followed by pointer to SOA name.
1093 conflict_hostname
= conflict_print(client
, &towire
, &chosen_hostname
, client
->hostname
); CH
;
1094 dns_name_to_wire(&p_host_name
, &towire
, chosen_hostname
); CH
;
1095 dns_pointer_to_wire(&p_host_name
, &towire
, &p_zone_name
); CH
;
1096 dns_u16_to_wire(&towire
, dns_rrtype_any
); CH
;
1097 dns_u16_to_wire(&towire
, dns_qclass_any
); CH
;
1098 dns_ttl_to_wire(&towire
, 0); CH
;
1099 dns_u16_to_wire(&towire
, 0); CH
;
1100 INCREMENT(message
->nscount
);
1102 // * Add addresses: A and/or AAAA RRsets, each of which contains one
1103 // or more A or AAAA RRs.
1104 // NAME = pointer to hostname from Delete (above)
1108 // RDLENGTH = number of RRs * RR length (4 or 16)
1109 // RDATA = <the data>
1110 for (pass
= 0; pass
< 2; pass
++) {
1111 bool have_good_address
= false;
1113 for (addr
= interfaces
; addr
; addr
= addr
->next
) {
1114 // If we have an IPv6 address that's on the same prefix as the server's address, send only that
1116 if (addr
->rr
.type
!= dns_rrtype_aaaa
||
1117 (addr
->rr
.type
== server
->rr
.type
&& !memcmp(&addr
->rr
.data
, &server
->rr
.data
, 8)))
1119 have_good_address
= true;
1121 if (have_good_address
|| pass
== 1) {
1122 dns_pointer_to_wire(NULL
, &towire
, &p_host_name
); CH
;
1123 dns_u16_to_wire(&towire
, addr
->rr
.type
); CH
;
1124 dns_u16_to_wire(&towire
, dns_qclass_in
); CH
;
1125 dns_ttl_to_wire(&towire
, 3600); CH
;
1126 dns_rdlength_begin(&towire
); CH
;
1127 dns_rdata_raw_data_to_wire(&towire
, &addr
->rr
.data
,
1128 addr
->rr
.type
== dns_rrtype_a
? 4 : 16); CH
;
1129 dns_rdlength_end(&towire
); CH
;
1130 INCREMENT(message
->nscount
);
1132 if (have_good_address
) {
1138 // * Exactly one KEY RR:
1139 // NAME = pointer to hostname from Delete (above)
1143 // RDLENGTH = length of key + 4 (32 bits)
1144 // RDATA = <flags(16) = 0000 0010 0000 0001, protocol(8) = 3, algorithm(8) = 8?, public key(variable)>
1145 dns_pointer_to_wire(NULL
, &towire
, &p_host_name
); CH
;
1146 dns_u16_to_wire(&towire
, dns_rrtype_key
); CH
;
1147 dns_u16_to_wire(&towire
, dns_qclass_in
); CH
;
1148 dns_ttl_to_wire(&towire
, 3600); CH
;
1149 dns_rdlength_begin(&towire
); CH
;
1150 key_tag
= dns_rdata_key_to_wire(&towire
, 0, 2, 1, client
->key
); CH
;
1151 dns_rdlength_end(&towire
); CH
;
1152 INCREMENT(message
->nscount
);
1154 // Emit any registrations.
1155 for (reg
= client
->registrations
; reg
; reg
= reg
->next
) {
1156 // Only remove the registrations that are actually registered. Normally this will be all of them, but it's
1157 // possible for a registration to be added but not to have been updated yet, and then for us to get a remove
1158 // call, in which case we don't need to remove it.
1159 if (removing
&& reg
->serial
> serial
) {
1165 // NAME = service name (_a._b.service.arpa)
1170 // RDATA = service instance name
1171 dns_name_to_wire(&p_service_name
, &towire
, reg
->regtype
== NULL
? service_type
: reg
->regtype
); CH
;
1172 dns_pointer_to_wire(&p_service_name
, &towire
, &p_zone_name
); CH
;
1173 dns_u16_to_wire(&towire
, dns_rrtype_ptr
); CH
;
1174 dns_u16_to_wire(&towire
, dns_qclass_in
); CH
;
1175 dns_ttl_to_wire(&towire
, 3600); CH
;
1176 dns_rdlength_begin(&towire
); CH
;
1177 if (reg
->name
!= NULL
) {
1178 char *service_instance_name
, *to_free
= conflict_print(client
, &towire
, &service_instance_name
, reg
->name
);
1179 dns_name_to_wire(&p_service_instance_name
, &towire
, service_instance_name
); CH
;
1180 if (to_free
!= NULL
) {
1184 dns_name_to_wire(&p_service_instance_name
, &towire
, chosen_hostname
); CH
;
1186 dns_pointer_to_wire(&p_service_instance_name
, &towire
, &p_service_name
); CH
;
1187 dns_rdlength_end(&towire
); CH
;
1188 INCREMENT(message
->nscount
);
1190 // Service Instance:
1191 // * Delete all RRsets from service instance name
1192 // NAME = service instance name (save pointer to service name, which is the second label)
1197 dns_pointer_to_wire(NULL
, &towire
, &p_service_instance_name
); CH
;
1198 dns_u16_to_wire(&towire
, dns_rrtype_any
); CH
;
1199 dns_u16_to_wire(&towire
, dns_qclass_any
); CH
;
1200 dns_ttl_to_wire(&towire
, 0); CH
;
1201 dns_u16_to_wire(&towire
, 0); CH
;
1202 INCREMENT(message
->nscount
);
1204 // * Add one SRV RRset pointing to Host Description
1205 // NAME = pointer to service instance name from above
1210 // RDATA = <priority(16) = 0, weight(16) = 0, port(16) = service port, target = pointer to hostname>
1211 dns_pointer_to_wire(NULL
, &towire
, &p_service_instance_name
); CH
;
1212 dns_u16_to_wire(&towire
, dns_rrtype_srv
); CH
;
1213 dns_u16_to_wire(&towire
, dns_qclass_in
); CH
;
1214 dns_ttl_to_wire(&towire
, 3600); CH
;
1215 dns_rdlength_begin(&towire
); CH
;
1216 dns_u16_to_wire(&towire
, 0); CH
; // priority
1217 dns_u16_to_wire(&towire
, 0); CH
; // weight
1218 dns_u16_to_wire(&towire
, reg
->port
); CH
; // port
1219 dns_pointer_to_wire(NULL
, &towire
, &p_host_name
); CH
;
1220 dns_rdlength_end(&towire
); CH
;
1221 INCREMENT(message
->nscount
);
1223 // * Add one or more TXT records
1224 // NAME = pointer to service instance name from above
1228 // RDLENGTH = <length of text>
1230 dns_pointer_to_wire(NULL
, &towire
, &p_service_instance_name
); CH
;
1231 dns_u16_to_wire(&towire
, dns_rrtype_txt
); CH
;
1232 dns_u16_to_wire(&towire
, dns_qclass_in
); CH
;
1233 dns_ttl_to_wire(&towire
, 3600); CH
;
1234 dns_rdlength_begin(&towire
); CH
;
1235 if (reg
->txtRecord
!= NULL
) {
1236 dns_rdata_raw_data_to_wire(&towire
, reg
->txtRecord
, reg
->txtLen
);
1238 dns_rdata_txt_to_wire(&towire
, txt_record
); CH
;
1240 dns_rdlength_end(&towire
); CH
;
1241 INCREMENT(message
->nscount
);
1244 // What about services with more than one name? Are these multiple service descriptions?
1251 message
->arcount
= 0;
1252 dns_edns0_header_to_wire(&towire
, DNS_MAX_UDP_PAYLOAD
, 0, 0, 1); CH
; // XRCODE = 0; VERSION = 0; DO=1
1253 dns_rdlength_begin(&towire
); CH
;
1254 dns_u16_to_wire(&towire
, dns_opt_update_lease
); CH
; // OPTION-CODE
1255 dns_edns0_option_begin(&towire
); CH
; // OPTION-LENGTH
1257 // If we are removing the record, lease time should be zero. Key_lease_time can be nonzero, but we
1258 // aren't currently offering a way to do that.
1259 dns_u32_to_wire(&towire
, 0); CH
;
1260 dns_u32_to_wire(&towire
, 0); CH
;
1262 dns_u32_to_wire(&towire
, update_lease_time
); CH
; // LEASE (e.g. 1 hour)
1263 dns_u32_to_wire(&towire
, update_key_lease_time
); CH
; // KEY-LEASE (7 days)
1265 dns_edns0_option_end(&towire
); CH
; // Now we know OPTION-LENGTH
1266 dns_rdlength_end(&towire
); CH
;
1267 INCREMENT(message
->arcount
);
1269 // The signature must be computed before counting the signature RR in the header counts.
1270 dns_sig0_signature_to_wire(&towire
, client
->key
, key_tag
, &p_host_name
, chosen_hostname
, zone_name
); CH
;
1271 INCREMENT(message
->arcount
);
1272 *p_length
= towire
.p
- (uint8_t *)message
;
1274 if (conflict_hostname
!= NULL
) {
1275 free(conflict_hostname
);
1280 if (conflict_hostname
!= NULL
) {
1281 free(conflict_hostname
);
1285 ERROR("Ran out of message space at srp-client.c:%d (%d, %d)",
1286 line
, towire
.line
, towire
.outer_line
);
1288 if (client
->active_update
!= NULL
) {
1289 update_finalize(client
->active_update
);
1290 client
->active_update
= NULL
;
1292 if (message
!= NULL
) {
1298 // Send SRP updates for host records that have changed.
1300 do_srp_update(client_state_t
*client
, bool definite
)
1303 service_addr_t
*server
;
1304 service_addr_t
*interface
, *registered
;
1306 // Cancel any ongoing active update.
1307 if (!definite
&& client
->active_update
!= NULL
) {
1308 bool server_changed
= true;
1309 bool interface_changed
= false;
1310 for (server
= servers
; server
!= NULL
; server
= server
->next
) {
1311 if (server
== client
->active_update
->server
) {
1312 server_changed
= false;
1315 for (registered
= client
->active_update
->interfaces
; registered
!= NULL
; registered
= registered
->next
) {
1316 for (interface
= interfaces
; interface
; interface
= interface
->next
) {
1317 if (interface
== registered
) {
1321 if (interface
== NULL
) {
1322 interface_changed
= true;
1326 if (!interface_changed
&& !server_changed
) {
1327 INFO("do_srp_update: addresses to register are the same; server is the same.");
1328 return kDNSServiceErr_NoError
;
1332 // Get rid of the previous update, if any.
1333 if (client
->active_update
!= NULL
) {
1334 update_finalize(client
->active_update
);
1335 client
->active_update
= NULL
;
1338 // Make an update context.
1339 update_context_t
*active_update
= calloc(1, sizeof(*active_update
));
1340 if (active_update
== NULL
) {
1341 err
= kDNSServiceErr_NoMemory
;
1343 // If possible, use the server we used last time.
1344 active_update
->client
= client
;
1345 sync_from_stable_storage(active_update
);
1346 if (active_update
->server
== NULL
) {
1347 active_update
->server
= servers
;
1349 active_update
->serial
= client
->registration_serial
;
1350 active_update
->message
= NULL
;
1351 active_update
->message_length
= 0;
1352 // If the initial transmission times out, start retrying at ~two seconds.
1353 active_update
->next_retransmission_time
= 2000;
1354 // If this update times out, try again in two minutes, backing off to an hour exponentially.
1355 active_update
->next_attempt_time
= 1000 * 2 * 60;
1356 active_update
->lease_time
= client
->lease_time
;
1357 active_update
->key_lease_time
= client
->key_lease_time
;
1358 active_update
->interfaces
= calloc(1, sizeof(*active_update
->interfaces
));
1359 if (active_update
->interfaces
== NULL
) {
1360 err
= kDNSServiceErr_NoMemory
;
1361 INFO("No memory for interface address");
1363 memcpy(active_update
->interfaces
, interfaces
, sizeof(*interfaces
));
1364 err
= srp_make_udp_context(client
->os_context
, &active_update
->udp_context
, udp_response
, active_update
);
1367 if (err
== kDNSServiceErr_NoError
) {
1368 // XXX use some random jitter on these times.
1369 active_update
->next_retransmission_time
= 2000;
1370 err
= srp_set_wakeup(client
->os_context
, active_update
->udp_context
, srp_random16() % 1023, udp_retransmit
);
1372 if (err
!= kDNSServiceErr_NoError
) {
1373 if (active_update
!= NULL
) {
1374 update_finalize(active_update
);
1375 active_update
= NULL
;
1378 client
->active_update
= active_update
;
1382 // Deregister all existing registrations.
1384 srp_deregister(void *os_context
)
1387 bool something_to_deregister
= false;
1388 client_state_t
*client
;
1390 for (client
= clients
; client
; client
= client
->next
) {
1391 if (client
->os_context
== os_context
) {
1395 if (client
== NULL
) {
1396 return kDNSServiceErr_Invalid
;
1399 if (client
->active_update
== NULL
) {
1400 INFO("srp_deregister: no active update.");
1401 return kDNSServiceErr_NoSuchRecord
;
1404 // See if there are any registrations that have succeeded.
1405 for (rp
= client
->registrations
; rp
; rp
= rp
->next
) {
1406 if (rp
->serial
<= client
->active_update
->serial
&& rp
->succeeded
) {
1407 something_to_deregister
= true;
1411 // If so, start a deregistration update; otherwise return NoSuchRecord.
1412 if (something_to_deregister
) {
1413 if (client
->active_update
->message
) {
1414 free(client
->active_update
->message
);
1415 client
->active_update
->message
= NULL
;
1417 client
->active_update
->removing
= true;
1418 client
->active_update
->next_retransmission_time
= 2000;
1419 client
->active_update
->next_attempt_time
= 1000 * 2 * 60;
1420 udp_retransmit(client
->active_update
);
1421 return kDNSServiceErr_NoError
;
1423 return kDNSServiceErr_NoSuchRecord
;
1430 // c-file-style: "bsd"
1431 // c-basic-offset: 4
1433 // indent-tabs-mode: nil