1 /* -*- Mode: C; tab-width: 4 -*- 2 * 3 * Copyright (c) 2003-2015 Apple Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its 14 * contributors may be used to endorse or promote products derived from this 15 * software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <errno.h> 30 #include <stdlib.h> 31 #include <fcntl.h> 32 33 #include "dnssd_ipc.h" 34 35 #if APPLE_OSX_mDNSResponder 36 #include <mach-o/dyld.h> 37 #include <uuid/uuid.h> 38 #include <TargetConditionals.h> 39 #include "dns_sd_internal.h" 40 #endif 41 42 #if defined(_WIN32) 43 44 #define _SSIZE_T 45 #include <CommonServices.h> 46 #include <DebugServices.h> 47 #include <winsock2.h> 48 #include <ws2tcpip.h> 49 #include <windows.h> 50 #include <stdarg.h> 51 #include <stdio.h> 52 53 #define sockaddr_mdns sockaddr_in 54 #define AF_MDNS AF_INET 55 56 // Disable warning: "'type cast' : from data pointer 'void *' to function pointer" 57 #pragma warning(disable:4055) 58 59 // Disable warning: "nonstandard extension, function/data pointer conversion in expression" 60 #pragma warning(disable:4152) 61 62 extern BOOL IsSystemServiceDisabled(); 63 64 #define sleep(X) Sleep((X) * 1000) 65 66 static int g_initWinsock = 0; 67 #define LOG_WARNING kDebugLevelWarning 68 #define LOG_INFO kDebugLevelInfo 69 static void syslog( int priority, const char * message, ...) 70 { 71 va_list args; 72 int len; 73 char * buffer; 74 DWORD err = WSAGetLastError(); 75 (void) priority; 76 va_start( args, message ); 77 len = _vscprintf( message, args ) + 1; 78 buffer = malloc( len * sizeof(char) ); 79 if ( buffer ) { vsnprintf( buffer, len, message, args ); OutputDebugString( buffer ); free( buffer ); } 80 WSASetLastError( err ); 81 } 82 #else 83 84 #include <sys/fcntl.h> // For O_RDWR etc. 85 #include <sys/time.h> 86 #include <sys/socket.h> 87 #include <syslog.h> 88 89 #define sockaddr_mdns sockaddr_un 90 #define AF_MDNS AF_LOCAL 91 92 #endif 93 94 // <rdar://problem/4096913> Specifies how many times we'll try and connect to the server. 95 96 #define DNSSD_CLIENT_MAXTRIES 4 97 98 // Uncomment the line below to use the old error return mechanism of creating a temporary named socket (e.g. in /var/tmp) 99 //#define USE_NAMED_ERROR_RETURN_SOCKET 1 100 101 // If the UDS client has not received a response from the daemon in 60 secs, it is unlikely to get one 102 // Note: Timeout of 3 secs should be sufficient in normal scenarios, but 60 secs is chosen as a safeguard since 103 // some clients may come up before mDNSResponder itself after a BOOT and on rare ocassions IOPM/Keychain/D2D calls 104 // in mDNSResponder's INIT may take a much longer time to return 105 #define DNSSD_CLIENT_TIMEOUT 60 106 107 #ifndef CTL_PATH_PREFIX 108 #define CTL_PATH_PREFIX "/var/tmp/dnssd_result_socket." 109 #endif 110 111 typedef struct 112 { 113 ipc_msg_hdr ipc_hdr; 114 DNSServiceFlags cb_flags; 115 uint32_t cb_interface; 116 DNSServiceErrorType cb_err; 117 } CallbackHeader; 118 119 typedef struct _DNSServiceRef_t DNSServiceOp; 120 typedef struct _DNSRecordRef_t DNSRecord; 121 122 #if !defined(_WIN32) 123 typedef struct 124 { 125 void *AppCallback; // Client callback function and context 126 void *AppContext; 127 } SleepKAContext; 128 #endif 129 130 // client stub callback to process message from server and deliver results to client application 131 typedef void (*ProcessReplyFn)(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *msg, const char *const end); 132 133 #define ValidatorBits 0x12345678 134 #define DNSServiceRefValid(X) (dnssd_SocketValid((X)->sockfd) && (((X)->sockfd ^ (X)->validator) == ValidatorBits)) 135 136 // When using kDNSServiceFlagsShareConnection, there is one primary _DNSServiceOp_t, and zero or more subordinates 137 // For the primary, the 'next' field points to the first subordinate, and its 'next' field points to the next, and so on. 138 // For the primary, the 'primary' field is NULL; for subordinates the 'primary' field points back to the associated primary 139 // 140 // _DNS_SD_LIBDISPATCH is defined where libdispatch/GCD is available. This does not mean that the application will use the 141 // DNSServiceSetDispatchQueue API. Hence any new code guarded with _DNS_SD_LIBDISPATCH should still be backwards compatible. 142 struct _DNSServiceRef_t 143 { 144 DNSServiceOp *next; // For shared connection 145 DNSServiceOp *primary; // For shared connection 146 dnssd_sock_t sockfd; // Connected socket between client and daemon 147 dnssd_sock_t validator; // Used to detect memory corruption, double disposals, etc. 148 client_context_t uid; // For shared connection requests, each subordinate DNSServiceRef has its own ID, 149 // unique within the scope of the same shared parent DNSServiceRef 150 uint32_t op; // request_op_t or reply_op_t 151 uint32_t max_index; // Largest assigned record index - 0 if no additional records registered 152 uint32_t logcounter; // Counter used to control number of syslog messages we write 153 int *moreptr; // Set while DNSServiceProcessResult working on this particular DNSServiceRef 154 ProcessReplyFn ProcessReply; // Function pointer to the code to handle received messages 155 void *AppCallback; // Client callback function and context 156 void *AppContext; 157 DNSRecord *rec; 158 #if _DNS_SD_LIBDISPATCH 159 dispatch_source_t disp_source; 160 dispatch_queue_t disp_queue; 161 #endif 162 void *kacontext; 163 }; 164 165 struct _DNSRecordRef_t 166 { 167 DNSRecord *recnext; 168 void *AppContext; 169 DNSServiceRegisterRecordReply AppCallback; 170 DNSRecordRef recref; 171 uint32_t record_index; // index is unique to the ServiceDiscoveryRef 172 client_context_t uid; // For demultiplexing multiple DNSServiceRegisterRecord calls 173 DNSServiceOp *sdr; 174 }; 175 176 #if !defined(USE_TCP_LOOPBACK) 177 static void SetUDSPath(struct sockaddr_un *saddr, const char *path) 178 { 179 size_t pathLen; 180 181 pathLen = strlen(path); 182 if (pathLen < sizeof(saddr->sun_path)) 183 memcpy(saddr->sun_path, path, pathLen + 1); 184 else 185 saddr->sun_path[0] = '\0'; 186 } 187 #endif 188 189 // Write len bytes. Return 0 on success, -1 on error 190 static int write_all(dnssd_sock_t sd, char *buf, size_t len) 191 { 192 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead. 193 //if (send(sd, buf, len, MSG_WAITALL) != len) return -1; 194 while (len) 195 { 196 ssize_t num_written = send(sd, buf, (long)len, 0); 197 if (num_written < 0 || (size_t)num_written > len) 198 { 199 // Check whether socket has gone defunct, 200 // otherwise, an error here indicates some OS bug 201 // or that the mDNSResponder daemon crashed (which should never happen). 202 #if !defined(__ppc__) && defined(SO_ISDEFUNCT) 203 int defunct = 0; 204 socklen_t dlen = sizeof (defunct); 205 if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0) 206 syslog(LOG_WARNING, "dnssd_clientstub write_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); 207 if (!defunct) 208 syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd, 209 (long)num_written, (long)len, 210 (num_written < 0) ? dnssd_errno : 0, 211 (num_written < 0) ? dnssd_strerror(dnssd_errno) : ""); 212 else 213 syslog(LOG_INFO, "dnssd_clientstub write_all(%d) DEFUNCT", sd); 214 #else 215 syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd, 216 (long)num_written, (long)len, 217 (num_written < 0) ? dnssd_errno : 0, 218 (num_written < 0) ? dnssd_strerror(dnssd_errno) : ""); 219 #endif 220 return -1; 221 } 222 buf += num_written; 223 len -= num_written; 224 } 225 return 0; 226 } 227 228 enum { read_all_success = 0, read_all_fail = -1, read_all_wouldblock = -2 }; 229 230 // Read len bytes. Return 0 on success, read_all_fail on error, or read_all_wouldblock for 231 static int read_all(dnssd_sock_t sd, char *buf, int len) 232 { 233 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead. 234 //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1; 235 236 while (len) 237 { 238 ssize_t num_read = recv(sd, buf, len, 0); 239 // It is valid to get an interrupted system call error e.g., somebody attaching 240 // in a debugger, retry without failing 241 if ((num_read < 0) && (errno == EINTR)) 242 { 243 syslog(LOG_INFO, "dnssd_clientstub read_all: EINTR continue"); 244 continue; 245 } 246 if ((num_read == 0) || (num_read < 0) || (num_read > len)) 247 { 248 int printWarn = 0; 249 int defunct = 0; 250 251 // Check whether socket has gone defunct, 252 // otherwise, an error here indicates some OS bug 253 // or that the mDNSResponder daemon crashed (which should never happen). 254 #if defined(WIN32) 255 // <rdar://problem/7481776> Suppress logs for "A non-blocking socket operation 256 // could not be completed immediately" 257 if (WSAGetLastError() != WSAEWOULDBLOCK) 258 printWarn = 1; 259 #endif 260 #if !defined(__ppc__) && defined(SO_ISDEFUNCT) 261 { 262 socklen_t dlen = sizeof (defunct); 263 if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0) 264 syslog(LOG_WARNING, "dnssd_clientstub read_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); 265 } 266 if (!defunct) 267 printWarn = 1; 268 #endif 269 if (printWarn) 270 syslog(LOG_WARNING, "dnssd_clientstub read_all(%d) failed %ld/%ld %d %s", sd, 271 (long)num_read, (long)len, 272 (num_read < 0) ? dnssd_errno : 0, 273 (num_read < 0) ? dnssd_strerror(dnssd_errno) : ""); 274 else if (defunct) 275 syslog(LOG_INFO, "dnssd_clientstub read_all(%d) DEFUNCT", sd); 276 return (num_read < 0 && dnssd_errno == dnssd_EWOULDBLOCK) ? read_all_wouldblock : read_all_fail; 277 } 278 buf += num_read; 279 len -= num_read; 280 } 281 return read_all_success; 282 } 283 284 // Returns 1 if more bytes remain to be read on socket descriptor sd, 0 otherwise 285 static int more_bytes(dnssd_sock_t sd) 286 { 287 struct timeval tv = { 0, 0 }; 288 fd_set readfds; 289 fd_set *fs; 290 int ret; 291 292 #if defined(_WIN32) 293 fs = &readfds; 294 FD_ZERO(fs); 295 FD_SET(sd, fs); 296 ret = select((int)sd+1, fs, (fd_set*)NULL, (fd_set*)NULL, &tv); 297 #else 298 if (sd < FD_SETSIZE) 299 { 300 fs = &readfds; 301 FD_ZERO(fs); 302 } 303 else 304 { 305 // Compute the number of integers needed for storing "sd". Internally fd_set is stored 306 // as an array of ints with one bit for each fd and hence we need to compute 307 // the number of ints needed rather than the number of bytes. If "sd" is 32, we need 308 // two ints and not just one. 309 int nfdbits = sizeof (int) * 8; 310 int nints = (sd/nfdbits) + 1; 311 fs = (fd_set *)calloc(nints, (size_t)sizeof(int)); 312 if (fs == NULL) 313 { 314 syslog(LOG_WARNING, "dnssd_clientstub more_bytes: malloc failed"); 315 return 0; 316 } 317 } 318 FD_SET(sd, fs); 319 ret = select((int)sd+1, fs, (fd_set*)NULL, (fd_set*)NULL, &tv); 320 if (fs != &readfds) 321 free(fs); 322 #endif 323 return (ret > 0); 324 } 325 326 // set_waitlimit() implements a timeout using select. It is called from deliver_request() before recv() OR accept() 327 // to ensure the UDS clients are not blocked in these system calls indefinitely. 328 // Note: Ideally one should never be blocked here, because it indicates either mDNSResponder daemon is not yet up/hung/ 329 // superbusy/crashed or some other OS bug. For eg: On Windows which suffers from 3rd party software 330 // (primarily 3rd party firewall software) interfering with proper functioning of the TCP protocol stack it is possible 331 // the next operation on this socket(recv/accept) is blocked since we depend on TCP to communicate with the system service. 332 static int set_waitlimit(dnssd_sock_t sock, int timeout) 333 { 334 int gDaemonErr = kDNSServiceErr_NoError; 335 336 // To prevent stack corruption since select does not work with timeout if fds > FD_SETSIZE(1024) 337 if (!gDaemonErr && sock < FD_SETSIZE) 338 { 339 struct timeval tv; 340 fd_set set; 341 342 FD_ZERO(&set); 343 FD_SET(sock, &set); 344 tv.tv_sec = timeout; 345 tv.tv_usec = 0; 346 if (!select((int)(sock + 1), &set, NULL, NULL, &tv)) 347 { 348 // Ideally one should never hit this case: See comments before set_waitlimit() 349 syslog(LOG_WARNING, "dnssd_clientstub set_waitlimit:_daemon timed out (%d secs) without any response: Socket %d", timeout, sock); 350 gDaemonErr = kDNSServiceErr_Timeout; 351 } 352 } 353 return gDaemonErr; 354 } 355 356 /* create_hdr 357 * 358 * allocate and initialize an ipc message header. Value of len should initially be the 359 * length of the data, and is set to the value of the data plus the header. data_start 360 * is set to point to the beginning of the data section. SeparateReturnSocket should be 361 * non-zero for calls that can't receive an immediate error return value on their primary 362 * socket, and therefore require a separate return path for the error code result. 363 * if zero, the path to a control socket is appended at the beginning of the message buffer. 364 * data_start is set past this string. 365 */ 366 static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int SeparateReturnSocket, DNSServiceOp *ref) 367 { 368 char *msg = NULL; 369 ipc_msg_hdr *hdr; 370 int datalen; 371 #if !defined(USE_TCP_LOOPBACK) 372 char ctrl_path[64] = ""; // "/var/tmp/dnssd_result_socket.xxxxxxxxxx-xxx-xxxxxx" 373 #endif 374 375 if (SeparateReturnSocket) 376 { 377 #if defined(USE_TCP_LOOPBACK) 378 *len += 2; // Allocate space for two-byte port number 379 #elif defined(USE_NAMED_ERROR_RETURN_SOCKET) 380 struct timeval tv; 381 if (gettimeofday(&tv, NULL) < 0) 382 { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: gettimeofday failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); return NULL; } 383 snprintf(ctrl_path, sizeof(ctrl_path), "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(), 384 (unsigned long)(tv.tv_sec & 0xFFF), (unsigned long)(tv.tv_usec)); 385 *len += strlen(ctrl_path) + 1; 386 #else 387 *len += 1; // Allocate space for single zero byte (empty C string) 388 #endif 389 } 390 391 datalen = (int) *len; 392 *len += sizeof(ipc_msg_hdr); 393 394 // Write message to buffer 395 msg = malloc(*len); 396 if (!msg) { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: malloc failed"); return NULL; } 397 398 memset(msg, 0, *len); 399 hdr = (ipc_msg_hdr *)msg; 400 hdr->version = VERSION; 401 hdr->datalen = datalen; 402 hdr->ipc_flags = 0; 403 hdr->op = op; 404 hdr->client_context = ref->uid; 405 hdr->reg_index = 0; 406 *data_start = msg + sizeof(ipc_msg_hdr); 407 #if defined(USE_TCP_LOOPBACK) 408 // Put dummy data in for the port, since we don't know what it is yet. 409 // The data will get filled in before we send the message. This happens in deliver_request(). 410 if (SeparateReturnSocket) put_uint16(0, data_start); 411 #else 412 if (SeparateReturnSocket) put_string(ctrl_path, data_start); 413 #endif 414 return hdr; 415 } 416 417 static void FreeDNSRecords(DNSServiceOp *sdRef) 418 { 419 DNSRecord *rec = sdRef->rec; 420 while (rec) 421 { 422 DNSRecord *next = rec->recnext; 423 free(rec); 424 rec = next; 425 } 426 } 427 428 static void FreeDNSServiceOp(DNSServiceOp *x) 429 { 430 // We don't use our DNSServiceRefValid macro here because if we're cleaning up after a socket() call failed 431 // then sockfd could legitimately contain a failing value (e.g. dnssd_InvalidSocket) 432 if ((x->sockfd ^ x->validator) != ValidatorBits) 433 { 434 static DNSServiceOp *op_were_not_going_to_free_but_we_need_to_fool_the_analyzer; 435 syslog(LOG_WARNING, "dnssd_clientstub attempt to dispose invalid DNSServiceRef %p %08X %08X", x, x->sockfd, x->validator); 436 op_were_not_going_to_free_but_we_need_to_fool_the_analyzer = x; 437 } 438 else 439 { 440 x->next = NULL; 441 x->primary = NULL; 442 x->sockfd = dnssd_InvalidSocket; 443 x->validator = 0xDDDDDDDD; 444 x->op = request_op_none; 445 x->max_index = 0; 446 x->logcounter = 0; 447 x->moreptr = NULL; 448 x->ProcessReply = NULL; 449 x->AppCallback = NULL; 450 x->AppContext = NULL; 451 #if _DNS_SD_LIBDISPATCH 452 if (x->disp_source) dispatch_release(x->disp_source); 453 x->disp_source = NULL; 454 x->disp_queue = NULL; 455 #endif 456 // DNSRecords may have been added to subordinate sdRef e.g., DNSServiceRegister/DNSServiceAddRecord 457 // or on the main sdRef e.g., DNSServiceCreateConnection/DNSServiceRegisterRecord. 458 // DNSRecords may have been freed if the application called DNSRemoveRecord. 459 FreeDNSRecords(x); 460 if (x->kacontext) 461 { 462 free(x->kacontext); 463 x->kacontext = NULL; 464 } 465 free(x); 466 } 467 } 468 469 // Return a connected service ref (deallocate with DNSServiceRefDeallocate) 470 static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags flags, uint32_t op, ProcessReplyFn ProcessReply, void *AppCallback, void *AppContext) 471 { 472 int NumTries = 0; 473 474 dnssd_sockaddr_t saddr; 475 DNSServiceOp *sdr; 476 477 if (!ref) 478 { 479 syslog(LOG_WARNING, "dnssd_clientstub DNSService operation with NULL DNSServiceRef"); 480 return kDNSServiceErr_BadParam; 481 } 482 483 if (flags & kDNSServiceFlagsShareConnection) 484 { 485 if (!*ref) 486 { 487 syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with NULL DNSServiceRef"); 488 return kDNSServiceErr_BadParam; 489 } 490 if (!DNSServiceRefValid(*ref) || ((*ref)->op != connection_request && (*ref)->op != connection_delegate_request) || (*ref)->primary) 491 { 492 syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with invalid DNSServiceRef %p %08X %08X op %d", 493 (*ref), (*ref)->sockfd, (*ref)->validator, (*ref)->op); 494 *ref = NULL; 495 return kDNSServiceErr_BadReference; 496 } 497 } 498 499 #if defined(_WIN32) 500 if (!g_initWinsock) 501 { 502 WSADATA wsaData; 503 g_initWinsock = 1; 504 if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { *ref = NULL; return kDNSServiceErr_ServiceNotRunning; } 505 } 506 // <rdar://problem/4096913> If the system service is disabled, we only want to try to connect once 507 if (IsSystemServiceDisabled()) 508 NumTries = DNSSD_CLIENT_MAXTRIES; 509 #endif 510 511 sdr = malloc(sizeof(DNSServiceOp)); 512 if (!sdr) 513 { 514 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: malloc failed"); 515 *ref = NULL; 516 return kDNSServiceErr_NoMemory; 517 } 518 sdr->next = NULL; 519 sdr->primary = NULL; 520 sdr->sockfd = dnssd_InvalidSocket; 521 sdr->validator = sdr->sockfd ^ ValidatorBits; 522 sdr->op = op; 523 sdr->max_index = 0; 524 sdr->logcounter = 0; 525 sdr->moreptr = NULL; 526 sdr->uid.u32[0] = 0; 527 sdr->uid.u32[1] = 0; 528 sdr->ProcessReply = ProcessReply; 529 sdr->AppCallback = AppCallback; 530 sdr->AppContext = AppContext; 531 sdr->rec = NULL; 532 #if _DNS_SD_LIBDISPATCH 533 sdr->disp_source = NULL; 534 sdr->disp_queue = NULL; 535 #endif 536 sdr->kacontext = NULL; 537 538 if (flags & kDNSServiceFlagsShareConnection) 539 { 540 DNSServiceOp **p = &(*ref)->next; // Append ourselves to end of primary's list 541 while (*p) 542 p = &(*p)->next; 543 *p = sdr; 544 // Preincrement counter before we use it -- it helps with debugging if we know the all-zeroes ID should never appear 545 if (++(*ref)->uid.u32[0] == 0) 546 ++(*ref)->uid.u32[1]; // In parent DNSServiceOp increment UID counter 547 sdr->primary = *ref; // Set our primary pointer 548 sdr->sockfd = (*ref)->sockfd; // Inherit primary's socket 549 sdr->validator = (*ref)->validator; 550 sdr->uid = (*ref)->uid; 551 //printf("ConnectToServer sharing socket %d\n", sdr->sockfd); 552 } 553 else 554 { 555 #ifdef SO_NOSIGPIPE 556 const unsigned long optval = 1; 557 #endif 558 #ifndef USE_TCP_LOOPBACK 559 char* uds_serverpath = getenv(MDNS_UDS_SERVERPATH_ENVVAR); 560 if (uds_serverpath == NULL) 561 uds_serverpath = MDNS_UDS_SERVERPATH; 562 else if (strlen(uds_serverpath) >= MAX_CTLPATH) 563 { 564 uds_serverpath = MDNS_UDS_SERVERPATH; 565 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: using default path since env len is invalid"); 566 } 567 #endif 568 *ref = NULL; 569 sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0); 570 sdr->validator = sdr->sockfd ^ ValidatorBits; 571 if (!dnssd_SocketValid(sdr->sockfd)) 572 { 573 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: socket failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); 574 FreeDNSServiceOp(sdr); 575 return kDNSServiceErr_NoMemory; 576 } 577 #ifdef SO_NOSIGPIPE 578 // Some environments (e.g. OS X) support turning off SIGPIPE for a socket 579 if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0) 580 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_NOSIGPIPE failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); 581 #endif 582 #if defined(USE_TCP_LOOPBACK) 583 saddr.sin_family = AF_INET; 584 saddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR); 585 saddr.sin_port = htons(MDNS_TCP_SERVERPORT); 586 #else 587 saddr.sun_family = AF_LOCAL; 588 SetUDSPath(&saddr, uds_serverpath); 589 #if !defined(__ppc__) && defined(SO_DEFUNCTOK) 590 { 591 int defunct = 1; 592 if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0) 593 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); 594 } 595 #endif 596 #endif 597 598 while (1) 599 { 600 int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr)); 601 if (!err) 602 break; // If we succeeded, return sdr 603 // If we failed, then it may be because the daemon is still launching. 604 // This can happen for processes that launch early in the boot process, while the 605 // daemon is still coming up. Rather than fail here, we wait 1 sec and try again. 606 // If, after DNSSD_CLIENT_MAXTRIES, we still can't connect to the daemon, 607 // then we give up and return a failure code. 608 if (++NumTries < DNSSD_CLIENT_MAXTRIES) 609 { 610 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect()-> No of tries: %d", NumTries); 611 sleep(1); // Sleep a bit, then try again 612 } 613 else 614 { 615 #if !defined(USE_TCP_LOOPBACK) 616 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect() failed path:%s Socket:%d Err:%d Errno:%d %s", 617 uds_serverpath, sdr->sockfd, err, dnssd_errno, dnssd_strerror(dnssd_errno)); 618 #endif 619 dnssd_close(sdr->sockfd); 620 FreeDNSServiceOp(sdr); 621 return kDNSServiceErr_ServiceNotRunning; 622 } 623 } 624 //printf("ConnectToServer opened socket %d\n", sdr->sockfd); 625 } 626 627 *ref = sdr; 628 return kDNSServiceErr_NoError; 629 } 630 631 #define deliver_request_bailout(MSG) \ 632 syslog(LOG_WARNING, "dnssd_clientstub deliver_request: %s failed %d (%s)", (MSG), dnssd_errno, dnssd_strerror(dnssd_errno)); goto cleanup 633 634 static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) 635 { 636 uint32_t datalen; 637 dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket; 638 DNSServiceErrorType err = kDNSServiceErr_Unknown; // Default for the "goto cleanup" cases 639 int MakeSeparateReturnSocket; 640 #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET) 641 char *data; 642 #endif 643 644 if (!hdr) 645 { 646 syslog(LOG_WARNING, "dnssd_clientstub deliver_request: !hdr"); 647 return kDNSServiceErr_Unknown; 648 } 649 650 datalen = hdr->datalen; // We take a copy here because we're going to convert hdr->datalen to network byte order 651 #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET) 652 data = (char *)hdr + sizeof(ipc_msg_hdr); 653 #endif 654 655 // Note: need to check hdr->op, not sdr->op. 656 // hdr->op contains the code for the specific operation we're currently doing, whereas sdr->op 657 // contains the original parent DNSServiceOp (e.g. for an add_record_request, hdr->op will be 658 // add_record_request but the parent sdr->op will be connection_request or reg_service_request) 659 MakeSeparateReturnSocket = (sdr->primary || 660 hdr->op == reg_record_request || hdr->op == add_record_request || hdr->op == update_record_request || hdr->op == remove_record_request); 661 662 if (!DNSServiceRefValid(sdr)) 663 { 664 if (hdr) 665 free(hdr); 666 syslog(LOG_WARNING, "dnssd_clientstub deliver_request: invalid DNSServiceRef %p %08X %08X", sdr, sdr->sockfd, sdr->validator); 667 return kDNSServiceErr_BadReference; 668 } 669 670 if (MakeSeparateReturnSocket) 671 { 672 #if defined(USE_TCP_LOOPBACK) 673 { 674 union { uint16_t s; u_char b[2]; } port; 675 dnssd_sockaddr_t caddr; 676 dnssd_socklen_t len = (dnssd_socklen_t) sizeof(caddr); 677 listenfd = socket(AF_DNSSD, SOCK_STREAM, 0); 678 if (!dnssd_SocketValid(listenfd)) { 679 deliver_request_bailout("TCP socket"); 680 } 681 682 caddr.sin_family = AF_INET; 683 caddr.sin_port = 0; 684 caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR); 685 if (bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr)) < 0) { 686 deliver_request_bailout("TCP bind"); 687 } 688 if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) { 689 deliver_request_bailout("TCP getsockname"); 690 } 691 if (listen(listenfd, 1) < 0) { 692 deliver_request_bailout("TCP listen"); 693 } 694 port.s = caddr.sin_port; 695 data[0] = port.b[0]; // don't switch the byte order, as the 696 data[1] = port.b[1]; // daemon expects it in network byte order 697 } 698 #elif defined(USE_NAMED_ERROR_RETURN_SOCKET) 699 { 700 mode_t mask; 701 int bindresult; 702 dnssd_sockaddr_t caddr; 703 listenfd = socket(AF_DNSSD, SOCK_STREAM, 0); 704 if (!dnssd_SocketValid(listenfd)) { 705 deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET socket"); 706 } 707 708 caddr.sun_family = AF_LOCAL; 709 // According to Stevens (section 3.2), there is no portable way to 710 // determine whether sa_len is defined on a particular platform. 711 #ifndef NOT_HAVE_SA_LEN 712 caddr.sun_len = sizeof(struct sockaddr_un); 713 #endif 714 SetUDSPath(&caddr, data); 715 mask = umask(0); 716 bindresult = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr)); 717 umask(mask); 718 if (bindresult < 0) { 719 deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET bind"); 720 } 721 if (listen(listenfd, 1) < 0) { 722 deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET listen"); 723 } 724 } 725 #else 726 { 727 dnssd_sock_t sp[2]; 728 if (socketpair(AF_DNSSD, SOCK_STREAM, 0, sp) < 0) { 729 deliver_request_bailout("socketpair"); 730 } 731 else 732 { 733 errsd = sp[0]; // We'll read our four-byte error code from sp[0] 734 listenfd = sp[1]; // We'll send sp[1] to the daemon 735 #if !defined(__ppc__) && defined(SO_DEFUNCTOK) 736 { 737 int defunct = 1; 738 if (setsockopt(errsd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0) 739 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); 740 } 741 #endif 742 } 743 } 744 #endif 745 } 746 747 #if !defined(USE_TCP_LOOPBACK) && !defined(USE_NAMED_ERROR_RETURN_SOCKET) 748 // If we're going to make a separate error return socket, and pass it to the daemon 749 // using sendmsg, then we'll hold back one data byte to go with it. 750 // On some versions of Unix (including Leopard) sending a control message without 751 // any associated data does not work reliably -- e.g. one particular issue we ran 752 // into is that if the receiving program is in a kqueue loop waiting to be notified 753 // of the received message, it doesn't get woken up when the control message arrives. 754 if (MakeSeparateReturnSocket || sdr->op == send_bpf) 755 datalen--; // Okay to use sdr->op when checking for op == send_bpf 756 #endif 757 758 // At this point, our listening socket is set up and waiting, if necessary, for the daemon to connect back to 759 ConvertHeaderBytes(hdr); 760 //syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %lu bytes", (unsigned long)(datalen + sizeof(ipc_msg_hdr))); 761 //if (MakeSeparateReturnSocket) syslog(LOG_WARNING, "dnssd_clientstub deliver_request name is %s", data); 762 #if TEST_SENDING_ONE_BYTE_AT_A_TIME 763 unsigned int i; 764 for (i=0; i<datalen + sizeof(ipc_msg_hdr); i++) 765 { 766 syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %d", i); 767 if (write_all(sdr->sockfd, ((char *)hdr)+i, 1) < 0) 768 { syslog(LOG_WARNING, "write_all (byte %u) failed", i); goto cleanup; } 769 usleep(10000); 770 } 771 #else 772 if (write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr)) < 0) 773 { 774 // write_all already prints an error message if there is an error writing to 775 // the socket except for DEFUNCT. Logging here is unnecessary and also wrong 776 // in the case of DEFUNCT sockets 777 syslog(LOG_INFO, "dnssd_clientstub deliver_request ERROR: write_all(%d, %lu bytes) failed", 778 sdr->sockfd, (unsigned long)(datalen + sizeof(ipc_msg_hdr))); 779 goto cleanup; 780 } 781 #endif 782 783 if (!MakeSeparateReturnSocket) 784 errsd = sdr->sockfd; 785 if (MakeSeparateReturnSocket || sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf 786 { 787 #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET) 788 // At this point we may wait in accept for a few milliseconds waiting for the daemon to connect back to us, 789 // but that's okay -- the daemon should not take more than a few milliseconds to respond. 790 // set_waitlimit() ensures we do not block indefinitely just in case something is wrong 791 dnssd_sockaddr_t daddr; 792 dnssd_socklen_t len = sizeof(daddr); 793 if ((err = set_waitlimit(listenfd, DNSSD_CLIENT_TIMEOUT)) != kDNSServiceErr_NoError) 794 goto cleanup; 795 errsd = accept(listenfd, (struct sockaddr *)&daddr, &len); 796 if (!dnssd_SocketValid(errsd)) { 797 deliver_request_bailout("accept"); 798 } 799 #else 800 801 struct iovec vec = { ((char *)hdr) + sizeof(ipc_msg_hdr) + datalen, 1 }; // Send the last byte along with the SCM_RIGHTS 802 struct msghdr msg; 803 struct cmsghdr *cmsg; 804 char cbuf[CMSG_SPACE(4 * sizeof(dnssd_sock_t))]; 805 806 msg.msg_name = 0; 807 msg.msg_namelen = 0; 808 msg.msg_iov = &vec; 809 msg.msg_iovlen = 1; 810 msg.msg_flags = 0; 811 if (MakeSeparateReturnSocket || sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf 812 { 813 if (sdr->op == send_bpf) 814 { 815 int i; 816 char p[12]; // Room for "/dev/bpf999" with terminating null 817 for (i=0; i<100; i++) 818 { 819 snprintf(p, sizeof(p), "/dev/bpf%d", i); 820 listenfd = open(p, O_RDWR, 0); 821 //if (dnssd_SocketValid(listenfd)) syslog(LOG_WARNING, "Sending fd %d for %s", listenfd, p); 822 if (!dnssd_SocketValid(listenfd) && dnssd_errno != EBUSY) 823 syslog(LOG_WARNING, "Error opening %s %d (%s)", p, dnssd_errno, dnssd_strerror(dnssd_errno)); 824 if (dnssd_SocketValid(listenfd) || dnssd_errno != EBUSY) break; 825 } 826 } 827 msg.msg_control = cbuf; 828 msg.msg_controllen = CMSG_LEN(sizeof(dnssd_sock_t)); 829 830 cmsg = CMSG_FIRSTHDR(&msg); 831 cmsg->cmsg_len = CMSG_LEN(sizeof(dnssd_sock_t)); 832 cmsg->cmsg_level = SOL_SOCKET; 833 cmsg->cmsg_type = SCM_RIGHTS; 834 *((dnssd_sock_t *)CMSG_DATA(cmsg)) = listenfd; 835 } 836 837 #if TEST_KQUEUE_CONTROL_MESSAGE_BUG 838 sleep(1); 839 #endif 840 841 #if DEBUG_64BIT_SCM_RIGHTS 842 syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d %ld %ld %ld/%ld/%ld/%ld", 843 errsd, listenfd, sizeof(dnssd_sock_t), sizeof(void*), 844 sizeof(struct cmsghdr) + sizeof(dnssd_sock_t), 845 CMSG_LEN(sizeof(dnssd_sock_t)), (long)CMSG_SPACE(sizeof(dnssd_sock_t)), 846 (long)((char*)CMSG_DATA(cmsg) + 4 - cbuf)); 847 #endif // DEBUG_64BIT_SCM_RIGHTS 848 849 if (sendmsg(sdr->sockfd, &msg, 0) < 0) 850 { 851 syslog(LOG_WARNING, "dnssd_clientstub deliver_request ERROR: sendmsg failed read sd=%d write sd=%d errno %d (%s)", 852 errsd, listenfd, dnssd_errno, dnssd_strerror(dnssd_errno)); 853 err = kDNSServiceErr_Incompatible; 854 goto cleanup; 855 } 856 857 #if DEBUG_64BIT_SCM_RIGHTS 858 syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d okay", errsd, listenfd); 859 #endif // DEBUG_64BIT_SCM_RIGHTS 860 861 #endif 862 // Close our end of the socketpair *before* calling read_all() to get the four-byte error code. 863 // Otherwise, if the daemon closes our socket (or crashes), we will have to wait for a timeout 864 // in read_all() because the socket is not closed (we still have an open reference to it) 865 // Note: listenfd is overwritten in the case of send_bpf above and that will be closed here 866 // for send_bpf operation. 867 dnssd_close(listenfd); 868 listenfd = dnssd_InvalidSocket; // Make sure we don't close it a second time in the cleanup handling below 869 } 870 871 // At this point we may wait in read_all for a few milliseconds waiting for the daemon to send us the error code, 872 // but that's okay -- the daemon should not take more than a few milliseconds to respond. 873 // set_waitlimit() ensures we do not block indefinitely just in case something is wrong 874 if (sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf 875 err = kDNSServiceErr_NoError; 876 else if ((err = set_waitlimit(errsd, DNSSD_CLIENT_TIMEOUT)) == kDNSServiceErr_NoError) 877 { 878 if (read_all(errsd, (char*)&err, (int)sizeof(err)) < 0) 879 err = kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us 880 else 881 err = ntohl(err); 882 } 883 //syslog(LOG_WARNING, "dnssd_clientstub deliver_request: retrieved error code %d", err); 884 885 cleanup: 886 if (MakeSeparateReturnSocket) 887 { 888 if (dnssd_SocketValid(listenfd)) dnssd_close(listenfd); 889 if (dnssd_SocketValid(errsd)) dnssd_close(errsd); 890 #if defined(USE_NAMED_ERROR_RETURN_SOCKET) 891 // syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removing UDS: %s", data); 892 if (unlink(data) != 0) 893 syslog(LOG_WARNING, "dnssd_clientstub WARNING: unlink(\"%s\") failed errno %d (%s)", data, dnssd_errno, dnssd_strerror(dnssd_errno)); 894 // else syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removed UDS: %s", data); 895 #endif 896 } 897 898 free(hdr); 899 return err; 900 } 901 902 dnssd_sock_t DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef) 903 { 904 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with NULL DNSServiceRef"); return dnssd_InvalidSocket; } 905 906 if (!DNSServiceRefValid(sdRef)) 907 { 908 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with invalid DNSServiceRef %p %08X %08X", 909 sdRef, sdRef->sockfd, sdRef->validator); 910 return dnssd_InvalidSocket; 911 } 912 913 if (sdRef->primary) 914 { 915 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef); 916 return dnssd_InvalidSocket; 917 } 918 919 return sdRef->sockfd; 920 } 921 922 #if _DNS_SD_LIBDISPATCH 923 static void CallbackWithError(DNSServiceRef sdRef, DNSServiceErrorType error) 924 { 925 DNSServiceOp *sdr = sdRef; 926 DNSServiceOp *sdrNext; 927 DNSRecord *rec; 928 DNSRecord *recnext; 929 int morebytes; 930 931 while (sdr) 932 { 933 // We can't touch the sdr after the callback as it can be deallocated in the callback 934 sdrNext = sdr->next; 935 morebytes = 1; 936 sdr->moreptr = &morebytes; 937 switch (sdr->op) 938 { 939 case resolve_request: 940 if (sdr->AppCallback) ((DNSServiceResolveReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, sdr->AppContext); 941 break; 942 case query_request: 943 if (sdr->AppCallback) ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, 0, sdr->AppContext); 944 break; 945 case addrinfo_request: 946 if (sdr->AppCallback) ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, NULL, 0, sdr->AppContext); 947 break; 948 case browse_request: 949 if (sdr->AppCallback) ((DNSServiceBrowseReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, NULL, sdr->AppContext); 950 break; 951 case reg_service_request: 952 if (sdr->AppCallback) ((DNSServiceRegisterReply) sdr->AppCallback)(sdr, 0, error, NULL, 0, NULL, sdr->AppContext); 953 break; 954 case enumeration_request: 955 if (sdr->AppCallback) ((DNSServiceDomainEnumReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, sdr->AppContext); 956 break; 957 case connection_request: 958 case connection_delegate_request: 959 // This means Register Record, walk the list of DNSRecords to do the callback 960 rec = sdr->rec; 961 while (rec) 962 { 963 recnext = rec->recnext; 964 if (rec->AppCallback) ((DNSServiceRegisterRecordReply)rec->AppCallback)(sdr, 0, 0, error, rec->AppContext); 965 // The Callback can call DNSServiceRefDeallocate which in turn frees sdr and all the records. 966 // Detect that and return early 967 if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:Record: CallbackwithError morebytes zero"); return;} 968 rec = recnext; 969 } 970 break; 971 case port_mapping_request: 972 if (sdr->AppCallback) ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, 0, 0, error, 0, 0, 0, 0, 0, sdr->AppContext); 973 break; 974 default: 975 syslog(LOG_WARNING, "dnssd_clientstub CallbackWithError called with bad op %d", sdr->op); 976 } 977 // If DNSServiceRefDeallocate was called in the callback, morebytes will be zero. As the sdRef 978 // (and its subordinates) have been freed, we should not proceed further. Note that when we 979 // call the callback with a subordinate sdRef the application can call DNSServiceRefDeallocate 980 // on the main sdRef and DNSServiceRefDeallocate handles this case by walking all the sdRefs and 981 // clears the moreptr so that we can terminate here. 982 // 983 // If DNSServiceRefDeallocate was not called in the callback, then set moreptr to NULL so that 984 // we don't access the stack variable after we return from this function. 985 if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:sdRef: CallbackwithError morebytes zero sdr %p", sdr); return;} 986 else {sdr->moreptr = NULL;} 987 sdr = sdrNext; 988 } 989 } 990 #endif // _DNS_SD_LIBDISPATCH 991 992 // Handle reply from server, calling application client callback. If there is no reply 993 // from the daemon on the socket contained in sdRef, the call will block. 994 DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef) 995 { 996 int morebytes = 0; 997 998 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; } 999 1000 if (!DNSServiceRefValid(sdRef)) 1001 { 1002 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator); 1003 return kDNSServiceErr_BadReference; 1004 } 1005 1006 if (sdRef->primary) 1007 { 1008 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef); 1009 return kDNSServiceErr_BadReference; 1010 } 1011 1012 if (!sdRef->ProcessReply) 1013 { 1014 static int num_logs = 0; 1015 if (num_logs < 10) syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function"); 1016 if (num_logs < 1000) num_logs++;else sleep(1); 1017 return kDNSServiceErr_BadReference; 1018 } 1019 1020 do 1021 { 1022 CallbackHeader cbh; 1023 char *data; 1024 1025 // return NoError on EWOULDBLOCK. This will handle the case 1026 // where a non-blocking socket is told there is data, but it was a false positive. 1027 // On error, read_all will write a message to syslog for us, so don't need to duplicate that here 1028 // Note: If we want to properly support using non-blocking sockets in the future 1029 int result = read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr)); 1030 if (result == read_all_fail) 1031 { 1032 // Set the ProcessReply to NULL before callback as the sdRef can get deallocated 1033 // in the callback. 1034 sdRef->ProcessReply = NULL; 1035 #if _DNS_SD_LIBDISPATCH 1036 // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult 1037 // is not called by the application and hence need to communicate the error. Cancel the 1038 // source so that we don't get any more events 1039 // Note: read_all fails if we could not read from the daemon which can happen if the 1040 // daemon dies or the file descriptor is disconnected (defunct). 1041 if (sdRef->disp_source) 1042 { 1043 dispatch_source_cancel(sdRef->disp_source); 1044 dispatch_release(sdRef->disp_source); 1045 sdRef->disp_source = NULL; 1046 CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning); 1047 } 1048 #endif 1049 // Don't touch sdRef anymore as it might have been deallocated 1050 return kDNSServiceErr_ServiceNotRunning; 1051 } 1052 else if (result == read_all_wouldblock) 1053 { 1054 if (morebytes && sdRef->logcounter < 100) 1055 { 1056 sdRef->logcounter++; 1057 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult error: select indicated data was waiting but read_all returned EWOULDBLOCK"); 1058 } 1059 return kDNSServiceErr_NoError; 1060 } 1061 1062 ConvertHeaderBytes(&cbh.ipc_hdr); 1063 if (cbh.ipc_hdr.version != VERSION) 1064 { 1065 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult daemon version %d does not match client version %d", cbh.ipc_hdr.version, VERSION); 1066 sdRef->ProcessReply = NULL; 1067 return kDNSServiceErr_Incompatible; 1068 } 1069 1070 data = malloc(cbh.ipc_hdr.datalen); 1071 if (!data) return kDNSServiceErr_NoMemory; 1072 if (read_all(sdRef->sockfd, data, cbh.ipc_hdr.datalen) < 0) // On error, read_all will write a message to syslog for us 1073 { 1074 // Set the ProcessReply to NULL before callback as the sdRef can get deallocated 1075 // in the callback. 1076 sdRef->ProcessReply = NULL; 1077 #if _DNS_SD_LIBDISPATCH 1078 // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult 1079 // is not called by the application and hence need to communicate the error. Cancel the 1080 // source so that we don't get any more events 1081 if (sdRef->disp_source) 1082 { 1083 dispatch_source_cancel(sdRef->disp_source); 1084 dispatch_release(sdRef->disp_source); 1085 sdRef->disp_source = NULL; 1086 CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning); 1087 } 1088 #endif 1089 // Don't touch sdRef anymore as it might have been deallocated 1090 free(data); 1091 return kDNSServiceErr_ServiceNotRunning; 1092 } 1093 else 1094 { 1095 const char *ptr = data; 1096 cbh.cb_flags = get_flags (&ptr, data + cbh.ipc_hdr.datalen); 1097 cbh.cb_interface = get_uint32 (&ptr, data + cbh.ipc_hdr.datalen); 1098 cbh.cb_err = get_error_code(&ptr, data + cbh.ipc_hdr.datalen); 1099 1100 // CAUTION: We have to handle the case where the client calls DNSServiceRefDeallocate from within the callback function. 1101 // To do this we set moreptr to point to morebytes. If the client does call DNSServiceRefDeallocate(), 1102 // then that routine will clear morebytes for us, and cause us to exit our loop. 1103 morebytes = more_bytes(sdRef->sockfd); 1104 if (morebytes) 1105 { 1106 cbh.cb_flags |= kDNSServiceFlagsMoreComing; 1107 sdRef->moreptr = &morebytes; 1108 } 1109 if (ptr) sdRef->ProcessReply(sdRef, &cbh, ptr, data + cbh.ipc_hdr.datalen); 1110 // Careful code here: 1111 // If morebytes is non-zero, that means we set sdRef->moreptr above, and the operation was not 1112 // cancelled out from under us, so now we need to clear sdRef->moreptr so we don't leave a stray 1113 // dangling pointer pointing to a long-gone stack variable. 1114 // If morebytes is zero, then one of two thing happened: 1115 // (a) morebytes was 0 above, so we didn't set sdRef->moreptr, so we don't need to clear it 1116 // (b) morebytes was 1 above, and we set sdRef->moreptr, but the operation was cancelled (with DNSServiceRefDeallocate()), 1117 // so we MUST NOT try to dereference our stale sdRef pointer. 1118 if (morebytes) sdRef->moreptr = NULL; 1119 } 1120 free(data); 1121 } while (morebytes); 1122 1123 return kDNSServiceErr_NoError; 1124 } 1125 1126 void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef) 1127 { 1128 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with NULL DNSServiceRef"); return; } 1129 1130 if (!DNSServiceRefValid(sdRef)) // Also verifies dnssd_SocketValid(sdRef->sockfd) for us too 1131 { 1132 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator); 1133 return; 1134 } 1135 1136 // If we're in the middle of a DNSServiceProcessResult() invocation for this DNSServiceRef, clear its morebytes flag to break it out of its while loop 1137 if (sdRef->moreptr) *(sdRef->moreptr) = 0; 1138 1139 if (sdRef->primary) // If this is a subordinate DNSServiceOp, just send a 'stop' command 1140 { 1141 DNSServiceOp **p = &sdRef->primary->next; 1142 while (*p && *p != sdRef) p = &(*p)->next; 1143 if (*p) 1144 { 1145 char *ptr; 1146 size_t len = 0; 1147 ipc_msg_hdr *hdr = create_hdr(cancel_request, &len, &ptr, 0, sdRef); 1148 if (hdr) 1149 { 1150 ConvertHeaderBytes(hdr); 1151 write_all(sdRef->sockfd, (char *)hdr, len); 1152 free(hdr); 1153 } 1154 *p = sdRef->next; 1155 FreeDNSServiceOp(sdRef); 1156 } 1157 } 1158 else // else, make sure to terminate all subordinates as well 1159 { 1160 #if _DNS_SD_LIBDISPATCH 1161 // The cancel handler will close the fd if a dispatch source has been set 1162 if (sdRef->disp_source) 1163 { 1164 // By setting the ProcessReply to NULL, we make sure that we never call 1165 // the application callbacks ever, after returning from this function. We 1166 // assume that DNSServiceRefDeallocate is called from the serial queue 1167 // that was passed to DNSServiceSetDispatchQueue. Hence, dispatch_source_cancel 1168 // should cancel all the blocks on the queue and hence there should be no more 1169 // callbacks when we return from this function. Setting ProcessReply to NULL 1170 // provides extra protection. 1171 sdRef->ProcessReply = NULL; 1172 shutdown(sdRef->sockfd, SHUT_WR); 1173 dispatch_source_cancel(sdRef->disp_source); 1174 dispatch_release(sdRef->disp_source); 1175 sdRef->disp_source = NULL; 1176 } 1177 // if disp_queue is set, it means it used the DNSServiceSetDispatchQueue API. In that case, 1178 // when the source was cancelled, the fd was closed in the handler. Currently the source 1179 // is cancelled only when the mDNSResponder daemon dies 1180 else if (!sdRef->disp_queue) dnssd_close(sdRef->sockfd); 1181 #else 1182 dnssd_close(sdRef->sockfd); 1183 #endif 1184 // Free DNSRecords added in DNSRegisterRecord if they have not 1185 // been freed in DNSRemoveRecord 1186 while (sdRef) 1187 { 1188 DNSServiceOp *p = sdRef; 1189 sdRef = sdRef->next; 1190 // When there is an error reading from the daemon e.g., bad fd, CallbackWithError 1191 // is called which sets moreptr. It might set the moreptr on a subordinate sdRef 1192 // but the application might call DNSServiceRefDeallocate with the main sdRef from 1193 // the callback. Hence, when we loop through the subordinate sdRefs, we need 1194 // to clear the moreptr so that CallbackWithError can terminate itself instead of 1195 // walking through the freed sdRefs. 1196 if (p->moreptr) *(p->moreptr) = 0; 1197 FreeDNSServiceOp(p); 1198 } 1199 } 1200 } 1201 1202 DNSServiceErrorType DNSSD_API DNSServiceGetProperty(const char *property, void *result, uint32_t *size) 1203 { 1204 DNSServiceErrorType err; 1205 char *ptr; 1206 size_t len; 1207 ipc_msg_hdr *hdr; 1208 DNSServiceOp *tmp; 1209 uint32_t actualsize; 1210 1211 if (!property || !result || !size) 1212 return kDNSServiceErr_BadParam; 1213 1214 len = strlen(property) + 1; 1215 err = ConnectToServer(&tmp, 0, getproperty_request, NULL, NULL, NULL); 1216 if (err) return err; 1217 1218 hdr = create_hdr(getproperty_request, &len, &ptr, 0, tmp); 1219 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; } 1220 1221 put_string(property, &ptr); 1222 err = deliver_request(hdr, tmp); // Will free hdr for us 1223 if (err) { DNSServiceRefDeallocate(tmp); return err; } 1224 1225 if (read_all(tmp->sockfd, (char*)&actualsize, (int)sizeof(actualsize)) < 0) 1226 { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; } 1227 1228 actualsize = ntohl(actualsize); 1229 if (read_all(tmp->sockfd, (char*)result, actualsize < *size ? actualsize : *size) < 0) 1230 { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; } 1231 DNSServiceRefDeallocate(tmp); 1232 1233 // Swap version result back to local process byte order 1234 if (!strcmp(property, kDNSServiceProperty_DaemonVersion) && *size >= 4) 1235 *(uint32_t*)result = ntohl(*(uint32_t*)result); 1236 1237 *size = actualsize; 1238 return kDNSServiceErr_NoError; 1239 } 1240 1241 DNSServiceErrorType DNSSD_API DNSServiceGetPID(const uint16_t srcport, int32_t *pid) 1242 { 1243 char *ptr; 1244 ipc_msg_hdr *hdr; 1245 DNSServiceOp *tmp = NULL; 1246 size_t len = sizeof(int32_t); 1247 1248 DNSServiceErrorType err = ConnectToServer(&tmp, 0, getpid_request, NULL, NULL, NULL); 1249 if (err) return err; 1250 1251 hdr = create_hdr(getpid_request, &len, &ptr, 0, tmp); 1252 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; } 1253 1254 put_uint16(srcport, &ptr); 1255 err = deliver_request(hdr, tmp); // Will free hdr for us 1256 if (err) { DNSServiceRefDeallocate(tmp); return err; } 1257 1258 if (read_all(tmp->sockfd, (char*)pid, sizeof(int32_t)) < 0) 1259 { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; } 1260 1261 DNSServiceRefDeallocate(tmp); 1262 return kDNSServiceErr_NoError; 1263 } 1264 1265 static void handle_resolve_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *end) 1266 { 1267 char fullname[kDNSServiceMaxDomainName]; 1268 char target[kDNSServiceMaxDomainName]; 1269 uint16_t txtlen; 1270 union { uint16_t s; u_char b[2]; } port; 1271 unsigned char *txtrecord; 1272 1273 get_string(&data, end, fullname, kDNSServiceMaxDomainName); 1274 get_string(&data, end, target, kDNSServiceMaxDomainName); 1275 if (!data || data + 2 > end) goto fail; 1276 1277 port.b[0] = *data++; 1278 port.b[1] = *data++; 1279 txtlen = get_uint16(&data, end); 1280 txtrecord = (unsigned char *)get_rdata(&data, end, txtlen); 1281 1282 if (!data) goto fail; 1283 ((DNSServiceResolveReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, fullname, target, port.s, txtlen, txtrecord, sdr->AppContext); 1284 return; 1285 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 1286 fail: 1287 syslog(LOG_WARNING, "dnssd_clientstub handle_resolve_response: error reading result from daemon"); 1288 } 1289 1290 #if TARGET_OS_EMBEDDED 1291 1292 static int32_t libSystemVersion = 0; 1293 1294 // Return true if the iOS application linked against a version of libsystem where P2P 1295 // interfaces were included by default when using kDNSServiceInterfaceIndexAny. 1296 // Using 160.0.0 == 0xa00000 as the version threshold. 1297 static int includeP2PWithIndexAny() 1298 { 1299 if (libSystemVersion == 0) 1300 libSystemVersion = NSVersionOfLinkTimeLibrary("System"); 1301 1302 if (libSystemVersion < 0xa00000) 1303 return 1; 1304 else 1305 return 0; 1306 } 1307 1308 #else // TARGET_OS_EMBEDDED 1309 1310 // always return false for non iOS platforms 1311 static int includeP2PWithIndexAny() 1312 { 1313 return 0; 1314 } 1315 1316 #endif // TARGET_OS_EMBEDDED 1317 1318 DNSServiceErrorType DNSSD_API DNSServiceResolve 1319 ( 1320 DNSServiceRef *sdRef, 1321 DNSServiceFlags flags, 1322 uint32_t interfaceIndex, 1323 const char *name, 1324 const char *regtype, 1325 const char *domain, 1326 DNSServiceResolveReply callBack, 1327 void *context 1328 ) 1329 { 1330 char *ptr; 1331 size_t len; 1332 ipc_msg_hdr *hdr; 1333 DNSServiceErrorType err; 1334 1335 if (!sdRef || !name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam; 1336 1337 // Need a real InterfaceID for WakeOnResolve 1338 if ((flags & kDNSServiceFlagsWakeOnResolve) != 0 && 1339 ((interfaceIndex == kDNSServiceInterfaceIndexAny) || 1340 (interfaceIndex == kDNSServiceInterfaceIndexLocalOnly) || 1341 (interfaceIndex == kDNSServiceInterfaceIndexUnicast) || 1342 (interfaceIndex == kDNSServiceInterfaceIndexP2P) || 1343 (interfaceIndex == kDNSServiceInterfaceIndexBLE))) 1344 { 1345 return kDNSServiceErr_BadParam; 1346 } 1347 1348 if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny()) 1349 flags |= kDNSServiceFlagsIncludeP2P; 1350 1351 err = ConnectToServer(sdRef, flags, resolve_request, handle_resolve_response, (void *)callBack, context); 1352 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 1353 1354 // Calculate total message length 1355 len = sizeof(flags); 1356 len += sizeof(interfaceIndex); 1357 len += strlen(name) + 1; 1358 len += strlen(regtype) + 1; 1359 len += strlen(domain) + 1; 1360 1361 hdr = create_hdr(resolve_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); 1362 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 1363 1364 put_flags(flags, &ptr); 1365 put_uint32(interfaceIndex, &ptr); 1366 put_string(name, &ptr); 1367 put_string(regtype, &ptr); 1368 put_string(domain, &ptr); 1369 1370 err = deliver_request(hdr, *sdRef); // Will free hdr for us 1371 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 1372 return err; 1373 } 1374 1375 static void handle_query_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) 1376 { 1377 uint32_t ttl; 1378 char name[kDNSServiceMaxDomainName]; 1379 uint16_t rrtype, rrclass, rdlen; 1380 const char *rdata; 1381 1382 get_string(&data, end, name, kDNSServiceMaxDomainName); 1383 rrtype = get_uint16(&data, end); 1384 rrclass = get_uint16(&data, end); 1385 rdlen = get_uint16(&data, end); 1386 rdata = get_rdata(&data, end, rdlen); 1387 ttl = get_uint32(&data, end); 1388 1389 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_query_response: error reading result from daemon"); 1390 else ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, name, rrtype, rrclass, rdlen, rdata, ttl, sdr->AppContext); 1391 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 1392 } 1393 1394 DNSServiceErrorType DNSSD_API DNSServiceQueryRecord 1395 ( 1396 DNSServiceRef *sdRef, 1397 DNSServiceFlags flags, 1398 uint32_t interfaceIndex, 1399 const char *name, 1400 uint16_t rrtype, 1401 uint16_t rrclass, 1402 DNSServiceQueryRecordReply callBack, 1403 void *context 1404 ) 1405 { 1406 char *ptr; 1407 size_t len; 1408 ipc_msg_hdr *hdr; 1409 DNSServiceErrorType err; 1410 1411 // NULL name handled below. 1412 if (!sdRef || !callBack) return kDNSServiceErr_BadParam; 1413 1414 if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny()) 1415 flags |= kDNSServiceFlagsIncludeP2P; 1416 1417 err = ConnectToServer(sdRef, flags, query_request, handle_query_response, (void *)callBack, context); 1418 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 1419 1420 if (!name) name = "\0"; 1421 1422 // Calculate total message length 1423 len = sizeof(flags); 1424 len += sizeof(uint32_t); // interfaceIndex 1425 len += strlen(name) + 1; 1426 len += 2 * sizeof(uint16_t); // rrtype, rrclass 1427 1428 hdr = create_hdr(query_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); 1429 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 1430 1431 put_flags(flags, &ptr); 1432 put_uint32(interfaceIndex, &ptr); 1433 put_string(name, &ptr); 1434 put_uint16(rrtype, &ptr); 1435 put_uint16(rrclass, &ptr); 1436 1437 err = deliver_request(hdr, *sdRef); // Will free hdr for us 1438 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 1439 return err; 1440 } 1441 1442 static void handle_addrinfo_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) 1443 { 1444 char hostname[kDNSServiceMaxDomainName]; 1445 uint16_t rrtype, rrclass, rdlen; 1446 const char *rdata; 1447 uint32_t ttl; 1448 1449 get_string(&data, end, hostname, kDNSServiceMaxDomainName); 1450 rrtype = get_uint16(&data, end); 1451 rrclass = get_uint16(&data, end); 1452 rdlen = get_uint16(&data, end); 1453 rdata = get_rdata (&data, end, rdlen); 1454 ttl = get_uint32(&data, end); 1455 (void)rrclass; // Unused 1456 1457 // We only generate client callbacks for A and AAAA results (including NXDOMAIN results for 1458 // those types, if the client has requested those with the kDNSServiceFlagsReturnIntermediates). 1459 // Other result types, specifically CNAME referrals, are not communicated to the client, because 1460 // the DNSServiceGetAddrInfoReply interface doesn't have any meaningful way to communiate CNAME referrals. 1461 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_addrinfo_response: error reading result from daemon"); 1462 else if (rrtype == kDNSServiceType_A || rrtype == kDNSServiceType_AAAA) 1463 { 1464 struct sockaddr_in sa4; 1465 struct sockaddr_in6 sa6; 1466 const struct sockaddr *const sa = (rrtype == kDNSServiceType_A) ? (struct sockaddr*)&sa4 : (struct sockaddr*)&sa6; 1467 if (rrtype == kDNSServiceType_A) 1468 { 1469 memset(&sa4, 0, sizeof(sa4)); 1470 #ifndef NOT_HAVE_SA_LEN 1471 sa4.sin_len = sizeof(struct sockaddr_in); 1472 #endif 1473 sa4.sin_family = AF_INET; 1474 // sin_port = 0; 1475 if (!cbh->cb_err) memcpy(&sa4.sin_addr, rdata, rdlen); 1476 } 1477 else 1478 { 1479 memset(&sa6, 0, sizeof(sa6)); 1480 #ifndef NOT_HAVE_SA_LEN 1481 sa6.sin6_len = sizeof(struct sockaddr_in6); 1482 #endif 1483 sa6.sin6_family = AF_INET6; 1484 // sin6_port = 0; 1485 // sin6_flowinfo = 0; 1486 // sin6_scope_id = 0; 1487 if (!cbh->cb_err) 1488 { 1489 memcpy(&sa6.sin6_addr, rdata, rdlen); 1490 if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr)) sa6.sin6_scope_id = cbh->cb_interface; 1491 } 1492 } 1493 // Validation results are always delivered separately from the actual results of the 1494 // DNSServiceGetAddrInfo. Set the "addr" to NULL as per the documentation. 1495 // 1496 // Note: If we deliver validation results along with the "addr" in the future, we need 1497 // a way to differentiate the negative response from validation-only response as both 1498 // has zero address. 1499 if (!(cbh->cb_flags & kDNSServiceFlagsValidate)) 1500 ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, sa, ttl, sdr->AppContext); 1501 else 1502 ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, NULL, 0, sdr->AppContext); 1503 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 1504 } 1505 } 1506 1507 DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo 1508 ( 1509 DNSServiceRef *sdRef, 1510 DNSServiceFlags flags, 1511 uint32_t interfaceIndex, 1512 uint32_t protocol, 1513 const char *hostname, 1514 DNSServiceGetAddrInfoReply callBack, 1515 void *context /* may be NULL */ 1516 ) 1517 { 1518 char *ptr; 1519 size_t len; 1520 ipc_msg_hdr *hdr; 1521 DNSServiceErrorType err; 1522 1523 if (!sdRef || !hostname || !callBack) return kDNSServiceErr_BadParam; 1524 1525 err = ConnectToServer(sdRef, flags, addrinfo_request, handle_addrinfo_response, (void *)callBack, context); 1526 if (err) 1527 { 1528 return err; // On error ConnectToServer leaves *sdRef set to NULL 1529 } 1530 1531 // Calculate total message length 1532 len = sizeof(flags); 1533 len += sizeof(uint32_t); // interfaceIndex 1534 len += sizeof(uint32_t); // protocol 1535 len += strlen(hostname) + 1; 1536 1537 hdr = create_hdr(addrinfo_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); 1538 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 1539 1540 put_flags(flags, &ptr); 1541 put_uint32(interfaceIndex, &ptr); 1542 put_uint32(protocol, &ptr); 1543 put_string(hostname, &ptr); 1544 1545 err = deliver_request(hdr, *sdRef); // Will free hdr for us 1546 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 1547 return err; 1548 } 1549 1550 static void handle_browse_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) 1551 { 1552 char replyName[256], replyType[kDNSServiceMaxDomainName], replyDomain[kDNSServiceMaxDomainName]; 1553 get_string(&data, end, replyName, 256); 1554 get_string(&data, end, replyType, kDNSServiceMaxDomainName); 1555 get_string(&data, end, replyDomain, kDNSServiceMaxDomainName); 1556 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_browse_response: error reading result from daemon"); 1557 else ((DNSServiceBrowseReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, replyName, replyType, replyDomain, sdr->AppContext); 1558 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 1559 } 1560 1561 DNSServiceErrorType DNSSD_API DNSServiceBrowse 1562 ( 1563 DNSServiceRef *sdRef, 1564 DNSServiceFlags flags, 1565 uint32_t interfaceIndex, 1566 const char *regtype, 1567 const char *domain, 1568 DNSServiceBrowseReply callBack, 1569 void *context 1570 ) 1571 { 1572 char *ptr; 1573 size_t len; 1574 ipc_msg_hdr *hdr; 1575 DNSServiceErrorType err; 1576 1577 // NULL domain handled below 1578 if (!sdRef || !regtype || !callBack) return kDNSServiceErr_BadParam; 1579 1580 if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny()) 1581 flags |= kDNSServiceFlagsIncludeP2P; 1582 1583 err = ConnectToServer(sdRef, flags, browse_request, handle_browse_response, (void *)callBack, context); 1584 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 1585 1586 if (!domain) domain = ""; 1587 len = sizeof(flags); 1588 len += sizeof(interfaceIndex); 1589 len += strlen(regtype) + 1; 1590 len += strlen(domain) + 1; 1591 1592 hdr = create_hdr(browse_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); 1593 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 1594 1595 put_flags(flags, &ptr); 1596 put_uint32(interfaceIndex, &ptr); 1597 put_string(regtype, &ptr); 1598 put_string(domain, &ptr); 1599 1600 err = deliver_request(hdr, *sdRef); // Will free hdr for us 1601 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 1602 return err; 1603 } 1604 1605 DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain) 1606 { 1607 DNSServiceErrorType err; 1608 DNSServiceOp *tmp; 1609 char *ptr; 1610 size_t len; 1611 ipc_msg_hdr *hdr; 1612 1613 if (!domain) return kDNSServiceErr_BadParam; 1614 len = sizeof(flags) + strlen(domain) + 1; 1615 1616 err = ConnectToServer(&tmp, 0, setdomain_request, NULL, NULL, NULL); 1617 if (err) return err; 1618 1619 hdr = create_hdr(setdomain_request, &len, &ptr, 0, tmp); 1620 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; } 1621 1622 put_flags(flags, &ptr); 1623 put_string(domain, &ptr); 1624 err = deliver_request(hdr, tmp); // Will free hdr for us 1625 DNSServiceRefDeallocate(tmp); 1626 return err; 1627 } 1628 1629 static void handle_regservice_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) 1630 { 1631 char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName]; 1632 get_string(&data, end, name, 256); 1633 get_string(&data, end, regtype, kDNSServiceMaxDomainName); 1634 get_string(&data, end, domain, kDNSServiceMaxDomainName); 1635 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_regservice_response: error reading result from daemon"); 1636 else ((DNSServiceRegisterReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_err, name, regtype, domain, sdr->AppContext); 1637 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 1638 } 1639 1640 DNSServiceErrorType DNSSD_API DNSServiceRegister 1641 ( 1642 DNSServiceRef *sdRef, 1643 DNSServiceFlags flags, 1644 uint32_t interfaceIndex, 1645 const char *name, 1646 const char *regtype, 1647 const char *domain, 1648 const char *host, 1649 uint16_t PortInNetworkByteOrder, 1650 uint16_t txtLen, 1651 const void *txtRecord, 1652 DNSServiceRegisterReply callBack, 1653 void *context 1654 ) 1655 { 1656 char *ptr; 1657 size_t len; 1658 ipc_msg_hdr *hdr; 1659 DNSServiceErrorType err; 1660 union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder }; 1661 1662 if (!sdRef || !regtype) return kDNSServiceErr_BadParam; 1663 if (!name) name = ""; 1664 if (!domain) domain = ""; 1665 if (!host) host = ""; 1666 if (!txtRecord) txtRecord = (void*)""; 1667 1668 // No callback must have auto-rename 1669 if (!callBack && (flags & kDNSServiceFlagsNoAutoRename)) return kDNSServiceErr_BadParam; 1670 1671 if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny()) 1672 flags |= kDNSServiceFlagsIncludeP2P; 1673 1674 err = ConnectToServer(sdRef, flags, reg_service_request, callBack ? handle_regservice_response : NULL, (void *)callBack, context); 1675 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 1676 1677 len = sizeof(DNSServiceFlags); 1678 len += sizeof(uint32_t); // interfaceIndex 1679 len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4; 1680 len += 2 * sizeof(uint16_t); // port, txtLen 1681 len += txtLen; 1682 1683 hdr = create_hdr(reg_service_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); 1684 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 1685 if (!callBack) hdr->ipc_flags |= IPC_FLAGS_NOREPLY; 1686 1687 put_flags(flags, &ptr); 1688 put_uint32(interfaceIndex, &ptr); 1689 put_string(name, &ptr); 1690 put_string(regtype, &ptr); 1691 put_string(domain, &ptr); 1692 put_string(host, &ptr); 1693 *ptr++ = port.b[0]; 1694 *ptr++ = port.b[1]; 1695 put_uint16(txtLen, &ptr); 1696 put_rdata(txtLen, txtRecord, &ptr); 1697 1698 err = deliver_request(hdr, *sdRef); // Will free hdr for us 1699 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 1700 return err; 1701 } 1702 1703 static void handle_enumeration_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) 1704 { 1705 char domain[kDNSServiceMaxDomainName]; 1706 get_string(&data, end, domain, kDNSServiceMaxDomainName); 1707 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_enumeration_response: error reading result from daemon"); 1708 else ((DNSServiceDomainEnumReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, domain, sdr->AppContext); 1709 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 1710 } 1711 1712 DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains 1713 ( 1714 DNSServiceRef *sdRef, 1715 DNSServiceFlags flags, 1716 uint32_t interfaceIndex, 1717 DNSServiceDomainEnumReply callBack, 1718 void *context 1719 ) 1720 { 1721 char *ptr; 1722 size_t len; 1723 ipc_msg_hdr *hdr; 1724 DNSServiceErrorType err; 1725 int f1; 1726 int f2; 1727 1728 if (!sdRef || !callBack) return kDNSServiceErr_BadParam; 1729 1730 f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0; 1731 f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0; 1732 if (f1 + f2 != 1) return kDNSServiceErr_BadParam; 1733 1734 err = ConnectToServer(sdRef, flags, enumeration_request, handle_enumeration_response, (void *)callBack, context); 1735 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 1736 1737 len = sizeof(DNSServiceFlags); 1738 len += sizeof(uint32_t); 1739 1740 hdr = create_hdr(enumeration_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); 1741 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 1742 1743 put_flags(flags, &ptr); 1744 put_uint32(interfaceIndex, &ptr); 1745 1746 err = deliver_request(hdr, *sdRef); // Will free hdr for us 1747 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 1748 return err; 1749 } 1750 1751 static void ConnectionResponse(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *const data, const char *const end) 1752 { 1753 (void)data; // Unused 1754 1755 //printf("ConnectionResponse got %d\n", cbh->ipc_hdr.op); 1756 if (cbh->ipc_hdr.op != reg_record_reply_op) 1757 { 1758 // When using kDNSServiceFlagsShareConnection, need to search the list of associated DNSServiceOps 1759 // to find the one this response is intended for, and then call through to its ProcessReply handler. 1760 // We start with our first subordinate DNSServiceRef -- don't want to accidentally match the parent DNSServiceRef. 1761 DNSServiceOp *op = sdr->next; 1762 while (op && (op->uid.u32[0] != cbh->ipc_hdr.client_context.u32[0] || op->uid.u32[1] != cbh->ipc_hdr.client_context.u32[1])) 1763 op = op->next; 1764 // Note: We may sometimes not find a matching DNSServiceOp, in the case where the client has 1765 // cancelled the subordinate DNSServiceOp, but there are still messages in the pipeline from the daemon 1766 if (op && op->ProcessReply) op->ProcessReply(op, cbh, data, end); 1767 // WARNING: Don't touch op or sdr after this -- client may have called DNSServiceRefDeallocate 1768 return; 1769 } 1770 else 1771 { 1772 DNSRecordRef rec; 1773 for (rec = sdr->rec; rec; rec = rec->recnext) 1774 { 1775 if (rec->uid.u32[0] == cbh->ipc_hdr.client_context.u32[0] && rec->uid.u32[1] == cbh->ipc_hdr.client_context.u32[1]) 1776 break; 1777 } 1778 // The record might have been freed already and hence not an 1779 // error if the record is not found. 1780 if (!rec) 1781 { 1782 syslog(LOG_INFO, "ConnectionResponse: Record not found"); 1783 return; 1784 } 1785 if (rec->sdr != sdr) 1786 { 1787 syslog(LOG_WARNING, "ConnectionResponse: Record sdr mismatch: rec %p sdr %p", rec->sdr, sdr); 1788 return; 1789 } 1790 1791 if (sdr->op == connection_request || sdr->op == connection_delegate_request) 1792 { 1793 rec->AppCallback(rec->sdr, rec, cbh->cb_flags, cbh->cb_err, rec->AppContext); 1794 } 1795 else 1796 { 1797 syslog(LOG_WARNING, "dnssd_clientstub ConnectionResponse: sdr->op != connection_request"); 1798 rec->AppCallback(rec->sdr, rec, 0, kDNSServiceErr_Unknown, rec->AppContext); 1799 } 1800 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 1801 } 1802 } 1803 1804 DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef) 1805 { 1806 DNSServiceErrorType err; 1807 char *ptr; 1808 size_t len = 0; 1809 ipc_msg_hdr *hdr; 1810 1811 if (!sdRef) return kDNSServiceErr_BadParam; 1812 err = ConnectToServer(sdRef, 0, connection_request, ConnectionResponse, NULL, NULL); 1813 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 1814 1815 hdr = create_hdr(connection_request, &len, &ptr, 0, *sdRef); 1816 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 1817 1818 err = deliver_request(hdr, *sdRef); // Will free hdr for us 1819 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 1820 return err; 1821 } 1822 1823 #if APPLE_OSX_mDNSResponder && !TARGET_IPHONE_SIMULATOR 1824 DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid) 1825 { 1826 char *ptr; 1827 size_t len = 0; 1828 ipc_msg_hdr *hdr; 1829 1830 if (!sdRef) return kDNSServiceErr_BadParam; 1831 DNSServiceErrorType err = ConnectToServer(sdRef, 0, connection_delegate_request, ConnectionResponse, NULL, NULL); 1832 if (err) 1833 { 1834 return err; // On error ConnectToServer leaves *sdRef set to NULL 1835 } 1836 1837 // Only one of the two options can be set. If pid is zero, uuid is used. 1838 // If both are specified only pid will be used. We send across the pid 1839 // so that the daemon knows what to read from the socket. 1840 1841 len += sizeof(int32_t); 1842 1843 hdr = create_hdr(connection_delegate_request, &len, &ptr, 0, *sdRef); 1844 if (!hdr) 1845 { 1846 DNSServiceRefDeallocate(*sdRef); 1847 *sdRef = NULL; 1848 return kDNSServiceErr_NoMemory; 1849 } 1850 1851 if (pid && setsockopt((*sdRef)->sockfd, SOL_SOCKET, SO_DELEGATED, &pid, sizeof(pid)) == -1) 1852 { 1853 syslog(LOG_WARNING, "dnssdclientstub: Could not setsockopt() for PID[%d], no entitlements or process(pid) invalid errno:%d (%s)", pid, errno, strerror(errno)); 1854 // Free the hdr in case we return before calling deliver_request() 1855 if (hdr) 1856 free(hdr); 1857 DNSServiceRefDeallocate(*sdRef); 1858 *sdRef = NULL; 1859 return kDNSServiceErr_NoAuth; 1860 } 1861 1862 if (!pid && setsockopt((*sdRef)->sockfd, SOL_SOCKET, SO_DELEGATED_UUID, uuid, sizeof(uuid_t)) == -1) 1863 { 1864 syslog(LOG_WARNING, "dnssdclientstub: Could not setsockopt() for UUID, no entitlements or process(uuid) invalid errno:%d (%s) ", errno, strerror(errno)); 1865 // Free the hdr in case we return before calling deliver_request() 1866 if (hdr) 1867 free(hdr); 1868 DNSServiceRefDeallocate(*sdRef); 1869 *sdRef = NULL; 1870 return kDNSServiceErr_NoAuth; 1871 } 1872 1873 put_uint32(pid, &ptr); 1874 1875 err = deliver_request(hdr, *sdRef); // Will free hdr for us 1876 if (err) 1877 { 1878 DNSServiceRefDeallocate(*sdRef); 1879 *sdRef = NULL; 1880 } 1881 return err; 1882 } 1883 #elif TARGET_IPHONE_SIMULATOR // This hack is for Simulator platform only 1884 DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid) 1885 { 1886 (void) pid; 1887 (void) uuid; 1888 return DNSServiceCreateConnection(sdRef); 1889 } 1890 #endif 1891 1892 DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord 1893 ( 1894 DNSServiceRef sdRef, 1895 DNSRecordRef *RecordRef, 1896 DNSServiceFlags flags, 1897 uint32_t interfaceIndex, 1898 const char *fullname, 1899 uint16_t rrtype, 1900 uint16_t rrclass, 1901 uint16_t rdlen, 1902 const void *rdata, 1903 uint32_t ttl, 1904 DNSServiceRegisterRecordReply callBack, 1905 void *context 1906 ) 1907 { 1908 char *ptr; 1909 size_t len; 1910 ipc_msg_hdr *hdr = NULL; 1911 DNSRecordRef rref = NULL; 1912 DNSRecord **p; 1913 int f1 = (flags & kDNSServiceFlagsShared) != 0; 1914 int f2 = (flags & kDNSServiceFlagsUnique) != 0; 1915 if (f1 + f2 != 1) return kDNSServiceErr_BadParam; 1916 1917 if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny()) 1918 flags |= kDNSServiceFlagsIncludeP2P; 1919 1920 if (!sdRef || !RecordRef || !fullname || (!rdata && rdlen) || !callBack) 1921 { 1922 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with NULL parameter"); 1923 return kDNSServiceErr_BadParam; 1924 } 1925 1926 if (!DNSServiceRefValid(sdRef)) 1927 { 1928 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator); 1929 return kDNSServiceErr_BadReference; 1930 } 1931 1932 if (sdRef->op != connection_request && sdRef->op != connection_delegate_request) 1933 { 1934 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with non-DNSServiceCreateConnection DNSServiceRef %p %d", sdRef, sdRef->op); 1935 return kDNSServiceErr_BadReference; 1936 } 1937 1938 *RecordRef = NULL; 1939 1940 len = sizeof(DNSServiceFlags); 1941 len += 2 * sizeof(uint32_t); // interfaceIndex, ttl 1942 len += 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen 1943 len += strlen(fullname) + 1; 1944 len += rdlen; 1945 1946 // Bump up the uid. Normally for shared operations (kDNSServiceFlagsShareConnection), this 1947 // is done in ConnectToServer. For DNSServiceRegisterRecord, ConnectToServer has already 1948 // been called. As multiple DNSServiceRegisterRecords can be multiplexed over a single 1949 // connection, we need a way to demultiplex the response so that the callback corresponding 1950 // to the right DNSServiceRegisterRecord instance can be called. Use the same mechanism that 1951 // is used by kDNSServiceFlagsShareConnection. create_hdr copies the uid value to ipc 1952 // hdr->client_context which will be returned in the ipc response. 1953 if (++sdRef->uid.u32[0] == 0) 1954 ++sdRef->uid.u32[1]; 1955 hdr = create_hdr(reg_record_request, &len, &ptr, 1, sdRef); 1956 if (!hdr) return kDNSServiceErr_NoMemory; 1957 1958 put_flags(flags, &ptr); 1959 put_uint32(interfaceIndex, &ptr); 1960 put_string(fullname, &ptr); 1961 put_uint16(rrtype, &ptr); 1962 put_uint16(rrclass, &ptr); 1963 put_uint16(rdlen, &ptr); 1964 put_rdata(rdlen, rdata, &ptr); 1965 put_uint32(ttl, &ptr); 1966 1967 rref = malloc(sizeof(DNSRecord)); 1968 if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; } 1969 rref->AppContext = context; 1970 rref->AppCallback = callBack; 1971 rref->record_index = sdRef->max_index++; 1972 rref->sdr = sdRef; 1973 rref->recnext = NULL; 1974 *RecordRef = rref; 1975 // Remember the uid that we are sending across so that we can match 1976 // when the response comes back. 1977 rref->uid = sdRef->uid; 1978 hdr->reg_index = rref->record_index; 1979 1980 p = &(sdRef)->rec; 1981 while (*p) p = &(*p)->recnext; 1982 *p = rref; 1983 1984 return deliver_request(hdr, sdRef); // Will free hdr for us 1985 } 1986 1987 // sdRef returned by DNSServiceRegister() 1988 DNSServiceErrorType DNSSD_API DNSServiceAddRecord 1989 ( 1990 DNSServiceRef sdRef, 1991 DNSRecordRef *RecordRef, 1992 DNSServiceFlags flags, 1993 uint16_t rrtype, 1994 uint16_t rdlen, 1995 const void *rdata, 1996 uint32_t ttl 1997 ) 1998 { 1999 ipc_msg_hdr *hdr; 2000 size_t len = 0; 2001 char *ptr; 2002 DNSRecordRef rref; 2003 DNSRecord **p; 2004 2005 if (!sdRef || !RecordRef || (!rdata && rdlen)) 2006 { 2007 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL parameter"); 2008 return kDNSServiceErr_BadParam; 2009 } 2010 if (sdRef->op != reg_service_request) 2011 { 2012 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with non-DNSServiceRegister DNSServiceRef %p %d", sdRef, sdRef->op); 2013 return kDNSServiceErr_BadReference; 2014 } 2015 2016 if (!DNSServiceRefValid(sdRef)) 2017 { 2018 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator); 2019 return kDNSServiceErr_BadReference; 2020 } 2021 2022 *RecordRef = NULL; 2023 2024 len += 2 * sizeof(uint16_t); // rrtype, rdlen 2025 len += rdlen; 2026 len += sizeof(uint32_t); 2027 len += sizeof(DNSServiceFlags); 2028 2029 hdr = create_hdr(add_record_request, &len, &ptr, 1, sdRef); 2030 if (!hdr) return kDNSServiceErr_NoMemory; 2031 put_flags(flags, &ptr); 2032 put_uint16(rrtype, &ptr); 2033 put_uint16(rdlen, &ptr); 2034 put_rdata(rdlen, rdata, &ptr); 2035 put_uint32(ttl, &ptr); 2036 2037 rref = malloc(sizeof(DNSRecord)); 2038 if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; } 2039 rref->AppContext = NULL; 2040 rref->AppCallback = NULL; 2041 rref->record_index = sdRef->max_index++; 2042 rref->sdr = sdRef; 2043 rref->recnext = NULL; 2044 *RecordRef = rref; 2045 hdr->reg_index = rref->record_index; 2046 2047 p = &(sdRef)->rec; 2048 while (*p) p = &(*p)->recnext; 2049 *p = rref; 2050 2051 return deliver_request(hdr, sdRef); // Will free hdr for us 2052 } 2053 2054 // DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord 2055 DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord 2056 ( 2057 DNSServiceRef sdRef, 2058 DNSRecordRef RecordRef, 2059 DNSServiceFlags flags, 2060 uint16_t rdlen, 2061 const void *rdata, 2062 uint32_t ttl 2063 ) 2064 { 2065 ipc_msg_hdr *hdr; 2066 size_t len = 0; 2067 char *ptr; 2068 2069 if (!sdRef || (!rdata && rdlen)) 2070 { 2071 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with NULL parameter"); 2072 return kDNSServiceErr_BadParam; 2073 } 2074 2075 if (!DNSServiceRefValid(sdRef)) 2076 { 2077 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator); 2078 return kDNSServiceErr_BadReference; 2079 } 2080 2081 // Note: RecordRef is allowed to be NULL 2082 2083 len += sizeof(uint16_t); 2084 len += rdlen; 2085 len += sizeof(uint32_t); 2086 len += sizeof(DNSServiceFlags); 2087 2088 hdr = create_hdr(update_record_request, &len, &ptr, 1, sdRef); 2089 if (!hdr) return kDNSServiceErr_NoMemory; 2090 hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX; 2091 put_flags(flags, &ptr); 2092 put_uint16(rdlen, &ptr); 2093 put_rdata(rdlen, rdata, &ptr); 2094 put_uint32(ttl, &ptr); 2095 return deliver_request(hdr, sdRef); // Will free hdr for us 2096 } 2097 2098 DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord 2099 ( 2100 DNSServiceRef sdRef, 2101 DNSRecordRef RecordRef, 2102 DNSServiceFlags flags 2103 ) 2104 { 2105 ipc_msg_hdr *hdr; 2106 size_t len = 0; 2107 char *ptr; 2108 DNSServiceErrorType err; 2109 2110 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; } 2111 if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSRecordRef"); return kDNSServiceErr_BadParam; } 2112 if (!sdRef->max_index) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with bad DNSServiceRef"); return kDNSServiceErr_BadReference; } 2113 2114 if (!DNSServiceRefValid(sdRef)) 2115 { 2116 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator); 2117 return kDNSServiceErr_BadReference; 2118 } 2119 2120 len += sizeof(flags); 2121 hdr = create_hdr(remove_record_request, &len, &ptr, 1, sdRef); 2122 if (!hdr) return kDNSServiceErr_NoMemory; 2123 hdr->reg_index = RecordRef->record_index; 2124 put_flags(flags, &ptr); 2125 err = deliver_request(hdr, sdRef); // Will free hdr for us 2126 if (!err) 2127 { 2128 // This RecordRef could have been allocated in DNSServiceRegisterRecord or DNSServiceAddRecord. 2129 // If so, delink from the list before freeing 2130 DNSRecord **p = &sdRef->rec; 2131 while (*p && *p != RecordRef) p = &(*p)->recnext; 2132 if (*p) *p = RecordRef->recnext; 2133 free(RecordRef); 2134 } 2135 return err; 2136 } 2137 2138 DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord 2139 ( 2140 DNSServiceFlags flags, 2141 uint32_t interfaceIndex, 2142 const char *fullname, 2143 uint16_t rrtype, 2144 uint16_t rrclass, 2145 uint16_t rdlen, 2146 const void *rdata 2147 ) 2148 { 2149 DNSServiceErrorType err; 2150 char *ptr; 2151 size_t len; 2152 ipc_msg_hdr *hdr; 2153 DNSServiceOp *tmp = NULL; 2154 2155 if (!fullname || (!rdata && rdlen)) return kDNSServiceErr_BadParam; 2156 2157 err = ConnectToServer(&tmp, flags, reconfirm_record_request, NULL, NULL, NULL); 2158 if (err) return err; 2159 2160 len = sizeof(DNSServiceFlags); 2161 len += sizeof(uint32_t); 2162 len += strlen(fullname) + 1; 2163 len += 3 * sizeof(uint16_t); 2164 len += rdlen; 2165 hdr = create_hdr(reconfirm_record_request, &len, &ptr, 0, tmp); 2166 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; } 2167 2168 put_flags(flags, &ptr); 2169 put_uint32(interfaceIndex, &ptr); 2170 put_string(fullname, &ptr); 2171 put_uint16(rrtype, &ptr); 2172 put_uint16(rrclass, &ptr); 2173 put_uint16(rdlen, &ptr); 2174 put_rdata(rdlen, rdata, &ptr); 2175 2176 err = deliver_request(hdr, tmp); // Will free hdr for us 2177 DNSServiceRefDeallocate(tmp); 2178 return err; 2179 } 2180 2181 2182 static void handle_port_mapping_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) 2183 { 2184 union { uint32_t l; u_char b[4]; } addr; 2185 uint8_t protocol; 2186 union { uint16_t s; u_char b[2]; } internalPort; 2187 union { uint16_t s; u_char b[2]; } externalPort; 2188 uint32_t ttl; 2189 2190 if (!data || data + 13 > end) goto fail; 2191 2192 addr.b[0] = *data++; 2193 addr.b[1] = *data++; 2194 addr.b[2] = *data++; 2195 addr.b[3] = *data++; 2196 protocol = *data++; 2197 internalPort.b[0] = *data++; 2198 internalPort.b[1] = *data++; 2199 externalPort.b[0] = *data++; 2200 externalPort.b[1] = *data++; 2201 ttl = get_uint32(&data, end); 2202 if (!data) goto fail; 2203 2204 ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, addr.l, protocol, internalPort.s, externalPort.s, ttl, sdr->AppContext); 2205 return; 2206 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 2207 2208 fail : 2209 syslog(LOG_WARNING, "dnssd_clientstub handle_port_mapping_response: error reading result from daemon"); 2210 } 2211 2212 DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate 2213 ( 2214 DNSServiceRef *sdRef, 2215 DNSServiceFlags flags, 2216 uint32_t interfaceIndex, 2217 uint32_t protocol, /* TCP and/or UDP */ 2218 uint16_t internalPortInNetworkByteOrder, 2219 uint16_t externalPortInNetworkByteOrder, 2220 uint32_t ttl, /* time to live in seconds */ 2221 DNSServiceNATPortMappingReply callBack, 2222 void *context /* may be NULL */ 2223 ) 2224 { 2225 char *ptr; 2226 size_t len; 2227 ipc_msg_hdr *hdr; 2228 union { uint16_t s; u_char b[2]; } internalPort = { internalPortInNetworkByteOrder }; 2229 union { uint16_t s; u_char b[2]; } externalPort = { externalPortInNetworkByteOrder }; 2230 2231 DNSServiceErrorType err = ConnectToServer(sdRef, flags, port_mapping_request, handle_port_mapping_response, (void *)callBack, context); 2232 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 2233 2234 len = sizeof(flags); 2235 len += sizeof(interfaceIndex); 2236 len += sizeof(protocol); 2237 len += sizeof(internalPort); 2238 len += sizeof(externalPort); 2239 len += sizeof(ttl); 2240 2241 hdr = create_hdr(port_mapping_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); 2242 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 2243 2244 put_flags(flags, &ptr); 2245 put_uint32(interfaceIndex, &ptr); 2246 put_uint32(protocol, &ptr); 2247 *ptr++ = internalPort.b[0]; 2248 *ptr++ = internalPort.b[1]; 2249 *ptr++ = externalPort.b[0]; 2250 *ptr++ = externalPort.b[1]; 2251 put_uint32(ttl, &ptr); 2252 2253 err = deliver_request(hdr, *sdRef); // Will free hdr for us 2254 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 2255 return err; 2256 } 2257 2258 #if _DNS_SD_LIBDISPATCH 2259 DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue 2260 ( 2261 DNSServiceRef service, 2262 dispatch_queue_t queue 2263 ) 2264 { 2265 int dnssd_fd = DNSServiceRefSockFD(service); 2266 if (dnssd_fd == dnssd_InvalidSocket) return kDNSServiceErr_BadParam; 2267 if (!queue) 2268 { 2269 syslog(LOG_WARNING, "dnssd_clientstub: DNSServiceSetDispatchQueue dispatch queue NULL"); 2270 return kDNSServiceErr_BadParam; 2271 } 2272 if (service->disp_queue) 2273 { 2274 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch queue set already"); 2275 return kDNSServiceErr_BadParam; 2276 } 2277 if (service->disp_source) 2278 { 2279 syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch source set already"); 2280 return kDNSServiceErr_BadParam; 2281 } 2282 service->disp_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, dnssd_fd, 0, queue); 2283 if (!service->disp_source) 2284 { 2285 syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch_source_create failed"); 2286 return kDNSServiceErr_NoMemory; 2287 } 2288 service->disp_queue = queue; 2289 dispatch_source_set_event_handler(service->disp_source, ^{DNSServiceProcessResult(service);}); 2290 dispatch_source_set_cancel_handler(service->disp_source, ^{dnssd_close(dnssd_fd);}); 2291 dispatch_resume(service->disp_source); 2292 return kDNSServiceErr_NoError; 2293 } 2294 #endif // _DNS_SD_LIBDISPATCH 2295 2296 #if !defined(_WIN32) 2297 2298 static void DNSSD_API SleepKeepaliveCallback(DNSServiceRef sdRef, DNSRecordRef rec, const DNSServiceFlags flags, 2299 DNSServiceErrorType errorCode, void *context) 2300 { 2301 SleepKAContext *ka = (SleepKAContext *)context; 2302 (void)rec; // Unused 2303 (void)flags; // Unused 2304 2305 if (sdRef->kacontext != context) 2306 syslog(LOG_WARNING, "SleepKeepaliveCallback context mismatch"); 2307 2308 if (ka->AppCallback) 2309 ((DNSServiceSleepKeepaliveReply)ka->AppCallback)(sdRef, errorCode, ka->AppContext); 2310 } 2311 2312 DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive 2313 ( 2314 DNSServiceRef *sdRef, 2315 DNSServiceFlags flags, 2316 int fd, 2317 unsigned int timeout, 2318 DNSServiceSleepKeepaliveReply callBack, 2319 void *context 2320 ) 2321 { 2322 char source_str[INET6_ADDRSTRLEN]; 2323 char target_str[INET6_ADDRSTRLEN]; 2324 struct sockaddr_storage lss; 2325 struct sockaddr_storage rss; 2326 socklen_t len1, len2; 2327 unsigned int len, proxyreclen; 2328 char buf[256]; 2329 DNSServiceErrorType err; 2330 DNSRecordRef record = NULL; 2331 char name[10]; 2332 char recname[128]; 2333 SleepKAContext *ka; 2334 unsigned int i, unique; 2335 2336 2337 (void) flags; //unused 2338 if (!timeout) return kDNSServiceErr_BadParam; 2339 2340 2341 len1 = sizeof(lss); 2342 if (getsockname(fd, (struct sockaddr *)&lss, &len1) < 0) 2343 { 2344 syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getsockname %d\n", errno); 2345 return kDNSServiceErr_BadParam; 2346 } 2347 2348 len2 = sizeof(rss); 2349 if (getpeername(fd, (struct sockaddr *)&rss, &len2) < 0) 2350 { 2351 syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getpeername %d\n", errno); 2352 return kDNSServiceErr_BadParam; 2353 } 2354 2355 if (len1 != len2) 2356 { 2357 syslog(LOG_WARNING, "DNSServiceSleepKeepalive local/remote info not same"); 2358 return kDNSServiceErr_Unknown; 2359 } 2360 2361 unique = 0; 2362 if (lss.ss_family == AF_INET) 2363 { 2364 struct sockaddr_in *sl = (struct sockaddr_in *)&lss; 2365 struct sockaddr_in *sr = (struct sockaddr_in *)&rss; 2366 unsigned char *ptr = (unsigned char *)&sl->sin_addr; 2367 2368 if (!inet_ntop(AF_INET, (const void *)&sr->sin_addr, target_str, sizeof (target_str))) 2369 { 2370 syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote info failed %d", errno); 2371 return kDNSServiceErr_Unknown; 2372 } 2373 if (!inet_ntop(AF_INET, (const void *)&sl->sin_addr, source_str, sizeof (source_str))) 2374 { 2375 syslog(LOG_WARNING, "DNSServiceSleepKeepalive local info failed %d", errno); 2376 return kDNSServiceErr_Unknown; 2377 } 2378 // Sum of all bytes in the local address and port should result in a unique 2379 // number in the local network 2380 for (i = 0; i < sizeof(struct in_addr); i++) 2381 unique += ptr[i]; 2382 unique += sl->sin_port; 2383 len = snprintf(buf+1, sizeof(buf) - 1, "t=%u h=%s d=%s l=%u r=%u", timeout, source_str, target_str, ntohs(sl->sin_port), ntohs(sr->sin_port)); 2384 } 2385 else 2386 { 2387 struct sockaddr_in6 *sl6 = (struct sockaddr_in6 *)&lss; 2388 struct sockaddr_in6 *sr6 = (struct sockaddr_in6 *)&rss; 2389 unsigned char *ptr = (unsigned char *)&sl6->sin6_addr; 2390 2391 if (!inet_ntop(AF_INET6, (const void *)&sr6->sin6_addr, target_str, sizeof (target_str))) 2392 { 2393 syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote6 info failed %d", errno); 2394 return kDNSServiceErr_Unknown; 2395 } 2396 if (!inet_ntop(AF_INET6, (const void *)&sl6->sin6_addr, source_str, sizeof (source_str))) 2397 { 2398 syslog(LOG_WARNING, "DNSServiceSleepKeepalive local6 info failed %d", errno); 2399 return kDNSServiceErr_Unknown; 2400 } 2401 for (i = 0; i < sizeof(struct in6_addr); i++) 2402 unique += ptr[i]; 2403 unique += sl6->sin6_port; 2404 len = snprintf(buf+1, sizeof(buf) - 1, "t=%u H=%s D=%s l=%u r=%u", timeout, source_str, target_str, ntohs(sl6->sin6_port), ntohs(sr6->sin6_port)); 2405 } 2406 2407 if (len >= (sizeof(buf) - 1)) 2408 { 2409 syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit local/remote info"); 2410 return kDNSServiceErr_Unknown; 2411 } 2412 // Include the NULL byte also in the first byte. The total length of the record includes the 2413 // first byte also. 2414 buf[0] = len + 1; 2415 proxyreclen = len + 2; 2416 2417 len = snprintf(name, sizeof(name), "%u", unique); 2418 if (len >= sizeof(name)) 2419 { 2420 syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit unique"); 2421 return kDNSServiceErr_Unknown; 2422 } 2423 2424 len = snprintf(recname, sizeof(recname), "%s.%s", name, "_keepalive._dns-sd._udp.local"); 2425 if (len >= sizeof(recname)) 2426 { 2427 syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit name"); 2428 return kDNSServiceErr_Unknown; 2429 } 2430 2431 ka = malloc(sizeof(SleepKAContext)); 2432 if (!ka) return kDNSServiceErr_NoMemory; 2433 ka->AppCallback = (void *)callBack; 2434 ka->AppContext = context; 2435 2436 err = DNSServiceCreateConnection(sdRef); 2437 if (err) 2438 { 2439 syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection"); 2440 free(ka); 2441 return err; 2442 } 2443 2444 // we don't care about the "record". When sdRef gets deallocated later, it will be freed too 2445 err = DNSServiceRegisterRecord(*sdRef, &record, kDNSServiceFlagsUnique, 0, recname, 2446 kDNSServiceType_NULL, kDNSServiceClass_IN, proxyreclen, buf, kDNSServiceInterfaceIndexAny, SleepKeepaliveCallback, ka); 2447 if (err) 2448 { 2449 syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection"); 2450 free(ka); 2451 return err; 2452 } 2453 (*sdRef)->kacontext = ka; 2454 return kDNSServiceErr_NoError; 2455 } 2456 #endif 2457