1 /* test-dnssd.c 2 * 3 * Copyright (c) 2023-2024 Apple Inc. All rights reserved. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * https://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 * DNSSD intercept API for testing srp-mdns-proxy 18 */ 19 20 #include <dns_sd.h> 21 #include "srp.h" 22 #include "srp-test-runner.h" 23 #include "srp-api.h" 24 #include "dns-msg.h" 25 #include "ioloop.h" 26 #include "srp-proxy.h" 27 #include "srp-dnssd.h" 28 #include "srp-mdns-proxy.h" 29 #include "test-api.h" 30 #include "test-dnssd.h" 31 32 static char * 33 dns_service_rdata_to_text(test_state_t *state, int rrtype, const uint8_t *rdata, uint16_t rdlen, char *outbuf, size_t buflen) 34 { 35 dns_rr_t rr; 36 unsigned offp = 0; 37 38 rr.type = rrtype; 39 TEST_FAIL_CHECK(state, dns_rdata_parse_data(&rr, rdata, &offp, rdlen, rdlen, 0), "rr parse failed"); 40 dns_rdata_dump_to_buf(&rr, outbuf, buflen); 41 return outbuf; 42 } 43 44 static void 45 dns_service_dump_event(test_state_t *state, dns_service_event_t *event, dns_service_event_t *events) 46 { 47 char rrbuf[1024]; 48 char *rr_printed; 49 int rrtype = 0; 50 uint16_t rdlen; 51 uint8_t *rdata; 52 #define STR_OR_NULL(str) ((str) != NULL ? str : "<null>") 53 switch(event->event_type) { 54 case dns_service_event_type_register: 55 rr_printed = dns_service_rdata_to_text(state, dns_rrtype_txt, event->rdata, event->rdlen, rrbuf, sizeof(rrbuf)); 56 INFO(" register: %s.%s.%s port %d IN %s (%p %p) -> %d", STR_OR_NULL(event->name), 57 STR_OR_NULL(event->regtype), STR_OR_NULL(event->domain), event->port, STR_OR_NULL(rr_printed), 58 (char *)event->sdref, (char *)event->parent_sdref, event->status); 59 break; 60 case dns_service_event_type_register_record: 61 rr_printed = dns_service_rdata_to_text(state, event->rrtype, event->rdata, event->rdlen, rrbuf, sizeof(rrbuf)); 62 INFO(" register record: %s IN %s (%p %p) -> %d", STR_OR_NULL(event->name), 63 STR_OR_NULL(rr_printed), (char *)event->rref, (char *)event->sdref, event->status); 64 break; 65 case dns_service_event_type_remove_record: 66 INFO(" remove record: (%p %p) -> %d", (char *)event->rref, (char *)event->sdref, event->status); 67 break; 68 case dns_service_event_type_update_record: 69 // Get the rrtype from the previous event. 70 rdata = event->rdata; 71 rdlen = event->rdlen; 72 for (dns_service_event_t *ep = events; ep != NULL; ep = ep->next) { 73 if (ep->event_type == dns_service_event_type_register_record && ep->rref == event->rref) { 74 rrtype = ep->rrtype; 75 // When updating the TSR record, we send rdlen=0 and no rdata, which means just update the 76 // TSR and don't change the RR. But that would cause a parse failure, so we need the data 77 // as well as the rrtype from the RegisterRecord event. 78 if (rdlen == 0 && ep->rdlen != 0) { 79 rdata = ep->rdata; 80 rdlen = ep->rdlen; 81 } 82 break; 83 } 84 } 85 rr_printed = dns_service_rdata_to_text(state, rrtype, rdata, rdlen, rrbuf, sizeof(rrbuf)); 86 INFO(" update record: %s (%p %p) -> %d", STR_OR_NULL(rr_printed), (char *)event->rref, (char *)event->sdref, 87 event->status); 88 break; 89 case dns_service_event_type_ref_deallocate: 90 INFO(" ref deallocate: (%p %p) -> %d", (char *)event->sdref, (char *)event->parent_sdref, event->status); 91 break; 92 case dns_service_event_type_register_callback: 93 INFO(" reg callback: (%p %p) -> %d", (char *)event->sdref, (char *)event->parent_sdref, event->status); 94 break; 95 case dns_service_event_type_register_record_callback: 96 INFO(" regrec callback: (%p %p) -> %d", (char *)event->rref, (char *)event->sdref, event->status); 97 break; 98 } 99 } 100 101 bool 102 dns_service_dump_unexpected_events(test_state_t *test_state, srp_server_t *server_state) 103 { 104 bool ret = true; 105 for (dns_service_event_t *event = server_state->dns_service_events; event; event = event->next) { 106 if (!event->consumed) { 107 dns_service_dump_event(test_state, event, server_state->dns_service_events); 108 ret = false; 109 } 110 } 111 return ret; 112 } 113 114 dns_service_event_t * 115 dns_service_find_first_register_event_by_name_and_type(srp_server_t *state, const char *name, 116 const char *regtype) 117 { 118 for (dns_service_event_t *event = state->dns_service_events; event; event = event->next) { 119 if (event->event_type == dns_service_event_type_register && 120 event->name != NULL && event->regtype != NULL && !event->consumed) 121 { 122 INFO("event->name %s name %s event->regtype %s regtype %s", 123 event->name, name, event->regtype, regtype); 124 if (!strcmp(event->name, name) && !strcmp(event->regtype, regtype)) { 125 return event; 126 } 127 } 128 } 129 return NULL; 130 } 131 132 dns_service_event_t * 133 dns_service_find_first_register_record_event_by_name(srp_server_t *state, const char *name) 134 { 135 for (dns_service_event_t *event = state->dns_service_events; event; event = event->next) { 136 if (event->event_type == dns_service_event_type_register_record && 137 event->name != NULL && !event->consumed && !strcmp(name, event->name)) 138 { 139 return event; 140 } 141 } 142 return NULL; 143 } 144 145 dns_service_event_t * 146 dns_service_find_callback_for_registration(srp_server_t *state, dns_service_event_t *register_event) 147 { 148 for (dns_service_event_t *event = state->dns_service_events; event; event = event->next) { 149 if (event->event_type == dns_service_event_type_register_callback && 150 register_event->event_type == dns_service_event_type_register && 151 register_event->sdref == event->sdref && !event->consumed) 152 { 153 return event; 154 } 155 if (event->event_type == dns_service_event_type_register_record_callback && 156 register_event->event_type == dns_service_event_type_register_record && 157 register_event->rref == event->rref && !event->consumed) 158 { 159 return event; 160 } 161 } 162 return NULL; 163 } 164 165 dns_service_event_t * 166 dns_service_find_ref_deallocate_event(srp_server_t *state) 167 { 168 for (dns_service_event_t *event = state->dns_service_events; event; event = event->next) { 169 if (event->event_type == dns_service_event_type_ref_deallocate) { 170 return event; 171 } 172 } 173 return NULL; 174 } 175 176 // Find a DNSServiceUpdateRecord that corresponds to a DNSServiceRegister or DNSServiceRegisterRecord event. 177 // For a DNSServiceRegister update, event->rref will be NULL. 178 dns_service_event_t * 179 dns_service_find_update_for_register_event(srp_server_t *state, dns_service_event_t *register_event, 180 dns_service_event_t *after_event) 181 { 182 bool after_event_matched = after_event == NULL ? true : false; 183 for (dns_service_event_t *event = state->dns_service_events; event != NULL; event = event->next) { 184 // If we are past any after_event and this is an update_record event, see if it's for the same 185 // registration. 186 if (after_event_matched && event->event_type == dns_service_event_type_update_record && 187 ((register_event->rref == 0 && event->sdref == register_event->sdref) || 188 (register_event->rref != 0 && event->rref == register_event->rref))) 189 { 190 return event; 191 } 192 // Don't match events that are prior to after_event (so that we can skip an event if it's not the right one 193 if (event == after_event) { 194 after_event_matched = true; 195 } 196 } 197 return NULL; 198 } 199 200 // Find a DNSServiceRemoveRecord 201 dns_service_event_t * 202 dns_service_find_remove_for_register_event(srp_server_t *state, dns_service_event_t *register_event, 203 dns_service_event_t *after_event) 204 { 205 bool after_event_matched = after_event == NULL ? true : false; 206 for (dns_service_event_t *event = state->dns_service_events; event != NULL; event = event->next) { 207 // If we are past any after_event and this is an update_record event, see if it's for the same 208 // registration. 209 if (after_event_matched && event->event_type == dns_service_event_type_remove_record && 210 ((register_event->rref == 0 && event->sdref == register_event->sdref) || 211 (register_event->rref != 0 && event->rref == register_event->rref))) 212 { 213 return event; 214 } 215 // Don't match events that are prior to after_event (so that we can skip an event if it's not the right one) 216 if (event == after_event) { 217 after_event_matched = true; 218 } 219 } 220 return NULL; 221 } 222 223 static dns_service_ref_t * 224 dns_service_ref_create(srp_server_t *server_state, 225 DNSServiceRef *target, int flags, void *context) 226 { 227 dns_service_ref_t *ret = calloc(1, sizeof(*ret)); 228 TEST_FAIL_CHECK(server_state->test_state, ret != NULL, "no memory for dns_service_ref_t"); 229 if (flags & kDNSServiceFlagsShareConnection) { 230 ret->sdref = *target; 231 } 232 ret->server_state = server_state; 233 ret->context = context; 234 return ret; 235 } 236 237 static dns_service_ref_t * 238 dns_service_ref_create_for_register(srp_server_t *server_state, 239 DNSServiceRef *target, int flags, void *context, DNSServiceRegisterReply callback) 240 { 241 dns_service_ref_t *ret = dns_service_ref_create(server_state, target, flags, context); 242 if (ret != NULL) { 243 ret->callback.register_reply = callback; 244 } 245 return ret; 246 } 247 248 static dns_service_ref_t * 249 dns_service_ref_create_for_query_record(srp_server_t *server_state, 250 DNSServiceRef *target, int flags, void *context, DNSServiceQueryRecordReply callback) 251 { 252 dns_service_ref_t *ret = dns_service_ref_create(server_state, target, flags, context); 253 if (ret != NULL) { 254 ret->callback.query_record_reply = callback; 255 } 256 return ret; 257 } 258 259 static dns_record_ref_t * 260 dns_record_ref_create(srp_server_t *server_state, void *context, DNSServiceRegisterRecordReply callback) 261 { 262 dns_record_ref_t *ret = calloc(1, sizeof(*ret)); 263 TEST_FAIL_CHECK(server_state->test_state, ret != NULL, "no memory for dns_record_ref_t"); 264 ret->server_state = server_state; 265 ret->context = context; 266 ret->callback = callback; 267 return ret; 268 } 269 270 static char * 271 dns_service_string_dup(const char *src) 272 { 273 if (src == NULL) { 274 return NULL; 275 } 276 return strdup(src); 277 } 278 279 static dns_service_event_t * 280 dns_service_event_append(srp_server_t *state, dns_service_event_type_t event_type, DNSServiceRef sdref, 281 DNSServiceRef in_sdref, DNSRecordRef rref, DNSServiceFlags flags, uint32_t interfaceIndex, 282 const char *name, const char *regtype, const char *domain, const char *host, uint16_t port, 283 uint16_t rdlen, const void *rdata, uint16_t rrtype, uint16_t rrclass, uint32_t ttl, void *attr, 284 void *callBack, void *context, DNSServiceErrorType status) 285 { 286 TEST_FAIL_CHECK(NULL, state != NULL, "invalid server state"); 287 dns_service_event_t **ep = &state->dns_service_events; 288 while (*ep) { 289 ep = &(*ep)->next; 290 } 291 dns_service_event_t *event = calloc(1, sizeof(*event)); 292 TEST_FAIL_CHECK(state->test_state, event != NULL, "no memory for dns service event"); 293 *ep = event; 294 event->server_state = state; 295 event->event_type = event_type; 296 event->sdref = (intptr_t)sdref; 297 if (in_sdref != NULL && (flags & kDNSServiceFlagsShareConnection)) { 298 event->parent_sdref = (intptr_t)in_sdref; 299 } 300 event->rref = (intptr_t)rref; 301 event->flags = flags; 302 event->interface_index = interfaceIndex; 303 event->name = dns_service_string_dup(name); 304 event->regtype = dns_service_string_dup(regtype); 305 event->domain = dns_service_string_dup(domain); 306 event->host = dns_service_string_dup(host); 307 event->port = port; 308 event->rdlen = rdlen; 309 if (rdata != NULL) { 310 event->rdata = malloc(rdlen); 311 TEST_FAIL_CHECK(state->test_state, event->rdata != NULL, "no memory to save rdata"); 312 memcpy(event->rdata, rdata, rdlen); 313 } 314 event->rrclass = rrclass; 315 event->rrtype = rrtype; 316 event->ttl = ttl; 317 event->attr = (intptr_t)attr; 318 event->callBack = (intptr_t)callBack; 319 event->context = (intptr_t)context; 320 event->status = status; 321 return event; 322 } 323 324 static void 325 dns_service_register_callback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, 326 const char *name, const char *regtype, const char *domain, void *context) 327 { 328 dns_service_ref_t *ref = context; 329 dns_service_event_append(ref->server_state, dns_service_event_type_register_callback, sdRef, NULL, NULL, flags, 0, 330 name, regtype, domain, NULL, 0, 0, NULL, 0, 0, 0, NULL, NULL, context, errorCode); 331 DNSServiceRegisterReply callback = ref->callback.register_reply; 332 if (callback != NULL) { 333 callback(ref, flags, errorCode, name, regtype, domain, ref->context); 334 } 335 } 336 337 DNSServiceErrorType 338 dns_service_register(srp_server_t *state, DNSServiceRef *sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, 339 const char *name, const char *regtype, const char *domain, const char *host, uint16_t port, 340 uint16_t txtLen, const void *txtRecord, DNSServiceRegisterReply callBack, void *context) 341 { 342 return dns_service_register_wa(state, sdRef, flags, interfaceIndex, name, regtype, domain, host, port, txtLen, 343 txtRecord, NULL, callBack, context); 344 } 345 346 DNSServiceErrorType 347 dns_service_register_wa(srp_server_t *state, DNSServiceRef *sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, 348 const char *name, const char *regtype, const char *domain, const char *host, uint16_t port, 349 uint16_t txtLen, const void *txtRecord, DNSServiceAttributeRef attr, 350 DNSServiceRegisterReply callBack, void *context) 351 { 352 #undef DNSServiceRegisterWithAttribute 353 dns_service_ref_t *ret = dns_service_ref_create_for_register(state, sdRef, flags, context, callBack); 354 char updated_name[DNS_MAX_NAME_SIZE + 1]; 355 snprintf(updated_name, sizeof(updated_name), "%d-%s", state->server_id, name); 356 int status = DNSServiceRegisterWithAttribute(&ret->sdref, flags, interfaceIndex, updated_name, regtype, domain, host, port, 357 txtLen, txtRecord, attr, dns_service_register_callback, ret); 358 dns_service_event_append(state, dns_service_event_type_register, ret->sdref, *sdRef, NULL, flags, 359 interfaceIndex, name, regtype, domain, host, port, txtLen, txtRecord, 360 0, 0, 0, attr, callBack, context, status); 361 if (status != kDNSServiceErr_NoError) { 362 free(ret); 363 } 364 *sdRef = ret; 365 return status; 366 } 367 368 static void 369 dns_service_register_record_callback(DNSServiceRef sdRef, DNSRecordRef RecordRef, DNSServiceFlags flags, 370 DNSServiceErrorType errorCode, void *context) 371 { 372 dns_record_ref_t *ref = context; 373 dns_service_event_append(ref->server_state, dns_service_event_type_register_record_callback, sdRef, NULL, 374 RecordRef, flags, 0, NULL, NULL, NULL, NULL, 0, 0, NULL, 0, 0, 0, NULL, NULL, 375 context, errorCode); 376 if (ref->callback != NULL) { 377 ref->callback(sdRef, ref, flags, errorCode, ref->context); 378 } 379 } 380 381 DNSServiceErrorType 382 dns_service_register_record(srp_server_t *state, DNSServiceRef sdRef, DNSRecordRef *RecordRef, DNSServiceFlags flags, 383 uint32_t interfaceIndex, const char *fullname, uint16_t rrtype, uint16_t rrclass, 384 uint16_t rdlen, const void *rdata, uint32_t ttl, DNSServiceRegisterRecordReply callBack, 385 void *context) 386 { 387 return dns_service_register_record_wa(state, sdRef, RecordRef, flags, interfaceIndex, fullname, rrtype, rrclass, rdlen, 388 rdata, ttl, NULL, callBack, context); 389 } 390 391 DNSServiceErrorType 392 dns_service_register_record_wa(srp_server_t *state, DNSServiceRef sdRef, DNSRecordRef *RecordRef, DNSServiceFlags flags, 393 uint32_t interfaceIndex, const char *fullname, uint16_t rrtype, uint16_t rrclass, 394 uint16_t rdlen, const void *rdata, uint32_t ttl, DNSServiceAttributeRef attr, 395 DNSServiceRegisterRecordReply callBack, 396 void *context) 397 { 398 #undef DNSServiceRegisterRecordWithAttribute 399 dns_record_ref_t *ret = dns_record_ref_create(state, context, callBack); 400 401 // Since in testing multiple srp servers share the same mDNSResponder, 402 // we intentionally rename the record by prepending the server_id 403 // to the record name when registering with mDNSResponder, so that 404 // it will not generate conflict for replicated records. 405 char updated_name[DNS_MAX_NAME_SIZE + 1]; 406 snprintf(updated_name, sizeof(updated_name), "%d-%s", state->server_id, fullname); 407 int status = DNSServiceRegisterRecordWithAttribute(sdRef, &ret->rref, flags, interfaceIndex, updated_name, rrtype, 408 rrclass, rdlen, rdata, ttl, attr, 409 dns_service_register_record_callback, ret); 410 dns_service_event_append(state, dns_service_event_type_register_record, sdRef, NULL, ret->rref, flags, 411 interfaceIndex, fullname, NULL, NULL, NULL, 0, rdlen, rdata, rrtype, rrclass, ttl, attr, 412 callBack, context, status); 413 if (status != kDNSServiceErr_NoError) { 414 free(ret); 415 } 416 *RecordRef = ret; 417 return status; 418 } 419 420 // Note that this will not work with a recordref returned by DNSServiceAddRecord(), which we aren't currently intercepting 421 // because we don't use it. 422 DNSServiceErrorType 423 dns_service_remove_record(srp_server_t *state, DNSServiceRef sdRef, DNSRecordRef RecordRef, DNSServiceFlags flags) 424 { 425 #undef DNSServiceRemoveRecord 426 int ret = DNSServiceRemoveRecord(sdRef, RecordRef->rref, flags); 427 dns_service_event_append(state, dns_service_event_type_remove_record, sdRef->sdref, NULL, RecordRef->rref, 428 flags, 0, NULL, NULL, NULL, NULL, 0, 0, NULL, 0, 0, 0, NULL, NULL, NULL, ret); 429 return ret; 430 } 431 432 DNSServiceErrorType 433 dns_service_update_record(srp_server_t *state, DNSServiceRef sdRef, DNSRecordRef RecordRef, DNSServiceFlags flags, 434 uint16_t rdlen, const void *rdata, uint32_t ttl) 435 { 436 return dns_service_update_record_wa(state, sdRef, RecordRef, flags, rdlen, rdata, ttl, NULL); 437 } 438 439 DNSServiceErrorType 440 dns_service_update_record_wa(srp_server_t *state, DNSServiceRef sdRef, DNSRecordRef RecordRef, DNSServiceFlags flags, 441 uint16_t rdlen, const void *rdata, uint32_t ttl, DNSServiceAttributeRef attr) 442 { 443 #undef DNSServiceUpdateRecordWithAttribute 444 int ret; 445 if (RecordRef != NULL) { 446 ret = DNSServiceUpdateRecordWithAttribute(sdRef, RecordRef->rref, flags, rdlen, rdata, ttl, attr); 447 dns_service_event_append(state, dns_service_event_type_update_record, sdRef, NULL, RecordRef->rref, flags, 0, 448 NULL, NULL, NULL, NULL, 0, rdlen, rdata, 0, 0, ttl, NULL, NULL, NULL, ret); 449 } else { 450 ret = DNSServiceUpdateRecordWithAttribute(sdRef->sdref, NULL, flags, rdlen, rdata, ttl, attr); 451 dns_service_event_append(state, dns_service_event_type_update_record, sdRef->sdref, NULL, NULL, flags, 0, 452 NULL, NULL, NULL, NULL, 0, rdlen, rdata, 0, 0, ttl, NULL, NULL, NULL, ret); 453 } 454 return ret; 455 } 456 457 static void 458 dns_service_query_record_callback(DNSServiceRef UNUSED sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, 459 DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype, 460 uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context) 461 { 462 dns_service_ref_t *ref = context; 463 srp_server_t *server_state = ref->server_state; 464 test_state_t *state = server_state->test_state; 465 bool call_callback = true; 466 dns_service_query_record_callback_intercept_t intercept = state->dns_service_query_callback_intercept; 467 if (intercept != NULL) { 468 call_callback = intercept(ref, flags, interfaceIndex, errorCode, fullname, rrtype, rrclass, rdlen, rdata, ttl, ref->context); 469 } 470 if (call_callback) { 471 DNSServiceQueryRecordReply callback = ref->callback.query_record_reply; 472 callback(ref, flags, interfaceIndex, errorCode, fullname, rrtype, rrclass, rdlen, rdata, ttl, ref->context); 473 } 474 } 475 476 DNSServiceErrorType 477 dns_service_query_record(srp_server_t *NULLABLE srp_server, DNSServiceRef NONNULL *NULLABLE sdRef, 478 DNSServiceFlags flags, uint32_t interfaceIndex, const char *NONNULL fullname, 479 uint16_t rrtype, uint16_t rrclass, DNSServiceQueryRecordReply NONNULL callBack, 480 void *NULLABLE context) 481 { 482 return dns_service_query_record_wa(srp_server, sdRef, flags, interfaceIndex, fullname, rrtype, rrclass, 483 NULL, callBack, context); 484 } 485 486 DNSServiceErrorType 487 dns_service_query_record_wa(srp_server_t *NULLABLE srp_server, DNSServiceRef NONNULL *NULLABLE sdRef, 488 DNSServiceFlags flags, uint32_t interfaceIndex, const char *NONNULL fullname, 489 uint16_t rrtype, uint16_t rrclass, DNSServiceAttribute const *NULLABLE attr, 490 DNSServiceQueryRecordReply NONNULL callBack, void *NULLABLE context) 491 { 492 dns_service_ref_t *ret = dns_service_ref_create_for_query_record(srp_server, sdRef, flags, context, callBack); 493 test_state_t *state = srp_server->test_state; 494 int status; 495 if (state->query_record_intercept != NULL) { 496 status = state->query_record_intercept(state, &ret->sdref, flags, interfaceIndex, fullname, rrtype, rrclass, 497 attr, dns_service_query_record_callback, ret); 498 } else { 499 status = DNSServiceQueryRecordWithAttribute(&ret->sdref, flags, interfaceIndex, fullname, rrtype, rrclass, 500 attr, dns_service_query_record_callback, ret); 501 } 502 if (status != kDNSServiceErr_NoError) { 503 free(ret); 504 } 505 *sdRef = ret; 506 return status; 507 } 508 509 dnssd_txn_t *NULLABLE 510 dns_service_ioloop_txn_add(srp_server_t UNUSED *NULLABLE srp_server, DNSServiceRef NONNULL sdref, 511 void *NULLABLE context, dnssd_txn_finalize_callback_t NULLABLE finalize_callback, 512 dnssd_txn_failure_callback_t NULLABLE failure_callback) 513 { 514 return ioloop_dnssd_txn_add(sdref->sdref, context, finalize_callback, failure_callback); 515 } 516 517 void 518 dns_service_ref_deallocate(srp_server_t *state, DNSServiceRef sdRef) 519 { 520 #undef DNSServiceRefDeallocate 521 dns_service_event_append(state, dns_service_event_type_ref_deallocate, sdRef, NULL, NULL, 522 0, 0, NULL, NULL, NULL, NULL, 0, 0, NULL, 0, 0, 0, NULL, NULL, NULL, 0); 523 DNSServiceRefDeallocate(sdRef->sdref); 524 free(sdRef); 525 } 526 527 528 // Local Variables: 529 // mode: C 530 // tab-width: 4 531 // c-file-style: "bsd" 532 // c-basic-offset: 4 533 // fill-column: 108 534 // indent-tabs-mode: nil 535 // End: 536