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