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