14b22b933Srs /* -*- Mode: C; tab-width: 4 -*- 24b22b933Srs * 3cda73f64SToomas Soome * Copyright (c) 2003-2015 Apple Inc. All rights reserved. 44b22b933Srs * 55ffb0c9bSToomas Soome * Redistribution and use in source and binary forms, with or without 64b22b933Srs * modification, are permitted provided that the following conditions are met: 74b22b933Srs * 85ffb0c9bSToomas Soome * 1. Redistributions of source code must retain the above copyright notice, 95ffb0c9bSToomas Soome * this list of conditions and the following disclaimer. 105ffb0c9bSToomas Soome * 2. Redistributions in binary form must reproduce the above copyright notice, 115ffb0c9bSToomas Soome * this list of conditions and the following disclaimer in the documentation 125ffb0c9bSToomas Soome * and/or other materials provided with the distribution. 13cda73f64SToomas Soome * 3. Neither the name of Apple Inc. ("Apple") nor the names of its 145ffb0c9bSToomas Soome * contributors may be used to endorse or promote products derived from this 155ffb0c9bSToomas Soome * software without specific prior written permission. 164b22b933Srs * 175ffb0c9bSToomas Soome * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 185ffb0c9bSToomas Soome * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 195ffb0c9bSToomas Soome * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 205ffb0c9bSToomas Soome * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 215ffb0c9bSToomas Soome * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 225ffb0c9bSToomas Soome * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 235ffb0c9bSToomas Soome * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 245ffb0c9bSToomas Soome * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 255ffb0c9bSToomas Soome * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 264b22b933Srs * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 274b22b933Srs */ 284b22b933Srs 294b22b933Srs #include <errno.h> 304b22b933Srs #include <stdlib.h> 31*3b436d06SToomas Soome #include <fcntl.h> 325ffb0c9bSToomas Soome 33cda73f64SToomas Soome #include "dnssd_ipc.h" 34cda73f64SToomas Soome 355ffb0c9bSToomas Soome #if APPLE_OSX_mDNSResponder 365ffb0c9bSToomas Soome #include <mach-o/dyld.h> 375ffb0c9bSToomas Soome #include <uuid/uuid.h> 385ffb0c9bSToomas Soome #include <TargetConditionals.h> 39c65ebfc7SToomas Soome #include "dns_sd_internal.h" 405ffb0c9bSToomas Soome #endif 414b22b933Srs 424b22b933Srs #if defined(_WIN32) 434b22b933Srs 445ffb0c9bSToomas Soome #define _SSIZE_T 455ffb0c9bSToomas Soome #include <CommonServices.h> 465ffb0c9bSToomas Soome #include <DebugServices.h> 475ffb0c9bSToomas Soome #include <winsock2.h> 485ffb0c9bSToomas Soome #include <ws2tcpip.h> 495ffb0c9bSToomas Soome #include <windows.h> 505ffb0c9bSToomas Soome #include <stdarg.h> 515ffb0c9bSToomas Soome #include <stdio.h> 524b22b933Srs 535ffb0c9bSToomas Soome #define sockaddr_mdns sockaddr_in 545ffb0c9bSToomas Soome #define AF_MDNS AF_INET 554b22b933Srs 565ffb0c9bSToomas Soome // Disable warning: "'type cast' : from data pointer 'void *' to function pointer" 575ffb0c9bSToomas Soome #pragma warning(disable:4055) 584b22b933Srs 595ffb0c9bSToomas Soome // Disable warning: "nonstandard extension, function/data pointer conversion in expression" 605ffb0c9bSToomas Soome #pragma warning(disable:4152) 614b22b933Srs 624b22b933Srs extern BOOL IsSystemServiceDisabled(); 634b22b933Srs 645ffb0c9bSToomas Soome #define sleep(X) Sleep((X) * 1000) 654b22b933Srs 664b22b933Srs static int g_initWinsock = 0; 675ffb0c9bSToomas Soome #define LOG_WARNING kDebugLevelWarning 685ffb0c9bSToomas Soome #define LOG_INFO kDebugLevelInfo 695ffb0c9bSToomas Soome static void syslog( int priority, const char * message, ...) 705ffb0c9bSToomas Soome { 715ffb0c9bSToomas Soome va_list args; 725ffb0c9bSToomas Soome int len; 735ffb0c9bSToomas Soome char * buffer; 745ffb0c9bSToomas Soome DWORD err = WSAGetLastError(); 755ffb0c9bSToomas Soome (void) priority; 765ffb0c9bSToomas Soome va_start( args, message ); 775ffb0c9bSToomas Soome len = _vscprintf( message, args ) + 1; 785ffb0c9bSToomas Soome buffer = malloc( len * sizeof(char) ); 79cda73f64SToomas Soome if ( buffer ) { vsnprintf( buffer, len, message, args ); OutputDebugString( buffer ); free( buffer ); } 805ffb0c9bSToomas Soome WSASetLastError( err ); 815ffb0c9bSToomas Soome } 824b22b933Srs #else 834b22b933Srs 84*3b436d06SToomas Soome #include <sys/fcntl.h> // For O_RDWR etc. 855ffb0c9bSToomas Soome #include <sys/time.h> 865ffb0c9bSToomas Soome #include <sys/socket.h> 875ffb0c9bSToomas Soome #include <syslog.h> 884b22b933Srs 895ffb0c9bSToomas Soome #define sockaddr_mdns sockaddr_un 905ffb0c9bSToomas Soome #define AF_MDNS AF_LOCAL 914b22b933Srs 924b22b933Srs #endif 934b22b933Srs 945ffb0c9bSToomas Soome // <rdar://problem/4096913> Specifies how many times we'll try and connect to the server. 954b22b933Srs 964b22b933Srs #define DNSSD_CLIENT_MAXTRIES 4 974b22b933Srs 985ffb0c9bSToomas Soome // Uncomment the line below to use the old error return mechanism of creating a temporary named socket (e.g. in /var/tmp) 995ffb0c9bSToomas Soome //#define USE_NAMED_ERROR_RETURN_SOCKET 1 1004b22b933Srs 1015ffb0c9bSToomas Soome // If the UDS client has not received a response from the daemon in 60 secs, it is unlikely to get one 1025ffb0c9bSToomas Soome // Note: Timeout of 3 secs should be sufficient in normal scenarios, but 60 secs is chosen as a safeguard since 1035ffb0c9bSToomas Soome // some clients may come up before mDNSResponder itself after a BOOT and on rare ocassions IOPM/Keychain/D2D calls 1045ffb0c9bSToomas Soome // in mDNSResponder's INIT may take a much longer time to return 1055ffb0c9bSToomas Soome #define DNSSD_CLIENT_TIMEOUT 60 1065ffb0c9bSToomas Soome 1075ffb0c9bSToomas Soome #ifndef CTL_PATH_PREFIX 1085ffb0c9bSToomas Soome #define CTL_PATH_PREFIX "/var/tmp/dnssd_result_socket." 1095ffb0c9bSToomas Soome #endif 1105ffb0c9bSToomas Soome 1115ffb0c9bSToomas Soome typedef struct 1125ffb0c9bSToomas Soome { 1135ffb0c9bSToomas Soome ipc_msg_hdr ipc_hdr; 1145ffb0c9bSToomas Soome DNSServiceFlags cb_flags; 1155ffb0c9bSToomas Soome uint32_t cb_interface; 1165ffb0c9bSToomas Soome DNSServiceErrorType cb_err; 1175ffb0c9bSToomas Soome } CallbackHeader; 1185ffb0c9bSToomas Soome 1195ffb0c9bSToomas Soome typedef struct _DNSServiceRef_t DNSServiceOp; 1205ffb0c9bSToomas Soome typedef struct _DNSRecordRef_t DNSRecord; 1215ffb0c9bSToomas Soome 1225ffb0c9bSToomas Soome #if !defined(_WIN32) 1235ffb0c9bSToomas Soome typedef struct 1245ffb0c9bSToomas Soome { 1255ffb0c9bSToomas Soome void *AppCallback; // Client callback function and context 1265ffb0c9bSToomas Soome void *AppContext; 1275ffb0c9bSToomas Soome } SleepKAContext; 1285ffb0c9bSToomas Soome #endif 1295ffb0c9bSToomas Soome 1305ffb0c9bSToomas Soome // client stub callback to process message from server and deliver results to client application 1315ffb0c9bSToomas Soome typedef void (*ProcessReplyFn)(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *msg, const char *const end); 1325ffb0c9bSToomas Soome 1335ffb0c9bSToomas Soome #define ValidatorBits 0x12345678 1345ffb0c9bSToomas Soome #define DNSServiceRefValid(X) (dnssd_SocketValid((X)->sockfd) && (((X)->sockfd ^ (X)->validator) == ValidatorBits)) 1355ffb0c9bSToomas Soome 1365ffb0c9bSToomas Soome // When using kDNSServiceFlagsShareConnection, there is one primary _DNSServiceOp_t, and zero or more subordinates 1375ffb0c9bSToomas Soome // For the primary, the 'next' field points to the first subordinate, and its 'next' field points to the next, and so on. 1385ffb0c9bSToomas Soome // For the primary, the 'primary' field is NULL; for subordinates the 'primary' field points back to the associated primary 1395ffb0c9bSToomas Soome // 1405ffb0c9bSToomas Soome // _DNS_SD_LIBDISPATCH is defined where libdispatch/GCD is available. This does not mean that the application will use the 1415ffb0c9bSToomas Soome // DNSServiceSetDispatchQueue API. Hence any new code guarded with _DNS_SD_LIBDISPATCH should still be backwards compatible. 1425ffb0c9bSToomas Soome struct _DNSServiceRef_t 1435ffb0c9bSToomas Soome { 1445ffb0c9bSToomas Soome DNSServiceOp *next; // For shared connection 1455ffb0c9bSToomas Soome DNSServiceOp *primary; // For shared connection 1465ffb0c9bSToomas Soome dnssd_sock_t sockfd; // Connected socket between client and daemon 1475ffb0c9bSToomas Soome dnssd_sock_t validator; // Used to detect memory corruption, double disposals, etc. 1485ffb0c9bSToomas Soome client_context_t uid; // For shared connection requests, each subordinate DNSServiceRef has its own ID, 1495ffb0c9bSToomas Soome // unique within the scope of the same shared parent DNSServiceRef 1505ffb0c9bSToomas Soome uint32_t op; // request_op_t or reply_op_t 1515ffb0c9bSToomas Soome uint32_t max_index; // Largest assigned record index - 0 if no additional records registered 1525ffb0c9bSToomas Soome uint32_t logcounter; // Counter used to control number of syslog messages we write 1535ffb0c9bSToomas Soome int *moreptr; // Set while DNSServiceProcessResult working on this particular DNSServiceRef 1545ffb0c9bSToomas Soome ProcessReplyFn ProcessReply; // Function pointer to the code to handle received messages 1555ffb0c9bSToomas Soome void *AppCallback; // Client callback function and context 1565ffb0c9bSToomas Soome void *AppContext; 1575ffb0c9bSToomas Soome DNSRecord *rec; 1585ffb0c9bSToomas Soome #if _DNS_SD_LIBDISPATCH 1595ffb0c9bSToomas Soome dispatch_source_t disp_source; 1605ffb0c9bSToomas Soome dispatch_queue_t disp_queue; 1615ffb0c9bSToomas Soome #endif 1625ffb0c9bSToomas Soome void *kacontext; 1635ffb0c9bSToomas Soome }; 1645ffb0c9bSToomas Soome 1655ffb0c9bSToomas Soome struct _DNSRecordRef_t 1665ffb0c9bSToomas Soome { 1675ffb0c9bSToomas Soome DNSRecord *recnext; 1685ffb0c9bSToomas Soome void *AppContext; 1695ffb0c9bSToomas Soome DNSServiceRegisterRecordReply AppCallback; 1704b22b933Srs DNSRecordRef recref; 1714b22b933Srs uint32_t record_index; // index is unique to the ServiceDiscoveryRef 1725ffb0c9bSToomas Soome client_context_t uid; // For demultiplexing multiple DNSServiceRegisterRecord calls 1735ffb0c9bSToomas Soome DNSServiceOp *sdr; 1745ffb0c9bSToomas Soome }; 1754b22b933Srs 176c65ebfc7SToomas Soome #if !defined(USE_TCP_LOOPBACK) 177c65ebfc7SToomas Soome static void SetUDSPath(struct sockaddr_un *saddr, const char *path) 178c65ebfc7SToomas Soome { 179c65ebfc7SToomas Soome size_t pathLen; 180c65ebfc7SToomas Soome 181c65ebfc7SToomas Soome pathLen = strlen(path); 182c65ebfc7SToomas Soome if (pathLen < sizeof(saddr->sun_path)) 183c65ebfc7SToomas Soome memcpy(saddr->sun_path, path, pathLen + 1); 184c65ebfc7SToomas Soome else 185c65ebfc7SToomas Soome saddr->sun_path[0] = '\0'; 186c65ebfc7SToomas Soome } 187c65ebfc7SToomas Soome #endif 188c65ebfc7SToomas Soome 1895ffb0c9bSToomas Soome // Write len bytes. Return 0 on success, -1 on error 1905ffb0c9bSToomas Soome static int write_all(dnssd_sock_t sd, char *buf, size_t len) 1915ffb0c9bSToomas Soome { 1924b22b933Srs // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead. 1935ffb0c9bSToomas Soome //if (send(sd, buf, len, MSG_WAITALL) != len) return -1; 1944b22b933Srs while (len) 1955ffb0c9bSToomas Soome { 1965ffb0c9bSToomas Soome ssize_t num_written = send(sd, buf, (long)len, 0); 1975ffb0c9bSToomas Soome if (num_written < 0 || (size_t)num_written > len) 1985ffb0c9bSToomas Soome { 199c65ebfc7SToomas Soome // Check whether socket has gone defunct, 200c65ebfc7SToomas Soome // otherwise, an error here indicates some OS bug 2015ffb0c9bSToomas Soome // or that the mDNSResponder daemon crashed (which should never happen). 202c65ebfc7SToomas Soome #if !defined(__ppc__) && defined(SO_ISDEFUNCT) 203c65ebfc7SToomas Soome int defunct = 0; 2045ffb0c9bSToomas Soome socklen_t dlen = sizeof (defunct); 2055ffb0c9bSToomas Soome if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0) 2065ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub write_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); 2075ffb0c9bSToomas Soome if (!defunct) 2085ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd, 2095ffb0c9bSToomas Soome (long)num_written, (long)len, 2105ffb0c9bSToomas Soome (num_written < 0) ? dnssd_errno : 0, 2115ffb0c9bSToomas Soome (num_written < 0) ? dnssd_strerror(dnssd_errno) : ""); 2125ffb0c9bSToomas Soome else 2135ffb0c9bSToomas Soome syslog(LOG_INFO, "dnssd_clientstub write_all(%d) DEFUNCT", sd); 214c65ebfc7SToomas Soome #else 2155ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd, 2165ffb0c9bSToomas Soome (long)num_written, (long)len, 2175ffb0c9bSToomas Soome (num_written < 0) ? dnssd_errno : 0, 2185ffb0c9bSToomas Soome (num_written < 0) ? dnssd_strerror(dnssd_errno) : ""); 219c65ebfc7SToomas Soome #endif 2205ffb0c9bSToomas Soome return -1; 2215ffb0c9bSToomas Soome } 2225ffb0c9bSToomas Soome buf += num_written; 2235ffb0c9bSToomas Soome len -= num_written; 2244b22b933Srs } 2255ffb0c9bSToomas Soome return 0; 2265ffb0c9bSToomas Soome } 2275ffb0c9bSToomas Soome 2285ffb0c9bSToomas Soome enum { read_all_success = 0, read_all_fail = -1, read_all_wouldblock = -2 }; 2294b22b933Srs 2305ffb0c9bSToomas Soome // Read len bytes. Return 0 on success, read_all_fail on error, or read_all_wouldblock for 2314b22b933Srs static int read_all(dnssd_sock_t sd, char *buf, int len) 2325ffb0c9bSToomas Soome { 2334b22b933Srs // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead. 2345ffb0c9bSToomas Soome //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1; 2355ffb0c9bSToomas Soome 2364b22b933Srs while (len) 2375ffb0c9bSToomas Soome { 2385ffb0c9bSToomas Soome ssize_t num_read = recv(sd, buf, len, 0); 2395ffb0c9bSToomas Soome // It is valid to get an interrupted system call error e.g., somebody attaching 2405ffb0c9bSToomas Soome // in a debugger, retry without failing 241c65ebfc7SToomas Soome if ((num_read < 0) && (errno == EINTR)) 242c65ebfc7SToomas Soome { 243c65ebfc7SToomas Soome syslog(LOG_INFO, "dnssd_clientstub read_all: EINTR continue"); 244c65ebfc7SToomas Soome continue; 2455ffb0c9bSToomas Soome } 2465ffb0c9bSToomas Soome if ((num_read == 0) || (num_read < 0) || (num_read > len)) 2475ffb0c9bSToomas Soome { 2485ffb0c9bSToomas Soome int printWarn = 0; 2495ffb0c9bSToomas Soome int defunct = 0; 250c65ebfc7SToomas Soome 251c65ebfc7SToomas Soome // Check whether socket has gone defunct, 252c65ebfc7SToomas Soome // otherwise, an error here indicates some OS bug 2535ffb0c9bSToomas Soome // or that the mDNSResponder daemon crashed (which should never happen). 2545ffb0c9bSToomas Soome #if defined(WIN32) 2555ffb0c9bSToomas Soome // <rdar://problem/7481776> Suppress logs for "A non-blocking socket operation 2565ffb0c9bSToomas Soome // could not be completed immediately" 2575ffb0c9bSToomas Soome if (WSAGetLastError() != WSAEWOULDBLOCK) 2585ffb0c9bSToomas Soome printWarn = 1; 2595ffb0c9bSToomas Soome #endif 2605ffb0c9bSToomas Soome #if !defined(__ppc__) && defined(SO_ISDEFUNCT) 2615ffb0c9bSToomas Soome { 2625ffb0c9bSToomas Soome socklen_t dlen = sizeof (defunct); 2635ffb0c9bSToomas Soome if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0) 2645ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub read_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); 2655ffb0c9bSToomas Soome } 2665ffb0c9bSToomas Soome if (!defunct) 2675ffb0c9bSToomas Soome printWarn = 1; 2685ffb0c9bSToomas Soome #endif 2695ffb0c9bSToomas Soome if (printWarn) 2705ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub read_all(%d) failed %ld/%ld %d %s", sd, 2715ffb0c9bSToomas Soome (long)num_read, (long)len, 2725ffb0c9bSToomas Soome (num_read < 0) ? dnssd_errno : 0, 2735ffb0c9bSToomas Soome (num_read < 0) ? dnssd_strerror(dnssd_errno) : ""); 2745ffb0c9bSToomas Soome else if (defunct) 2755ffb0c9bSToomas Soome syslog(LOG_INFO, "dnssd_clientstub read_all(%d) DEFUNCT", sd); 2765ffb0c9bSToomas Soome return (num_read < 0 && dnssd_errno == dnssd_EWOULDBLOCK) ? read_all_wouldblock : read_all_fail; 2775ffb0c9bSToomas Soome } 2785ffb0c9bSToomas Soome buf += num_read; 2795ffb0c9bSToomas Soome len -= num_read; 2804b22b933Srs } 2815ffb0c9bSToomas Soome return read_all_success; 2825ffb0c9bSToomas Soome } 2835ffb0c9bSToomas Soome 2845ffb0c9bSToomas Soome // Returns 1 if more bytes remain to be read on socket descriptor sd, 0 otherwise 2855ffb0c9bSToomas Soome static int more_bytes(dnssd_sock_t sd) 2865ffb0c9bSToomas Soome { 2875ffb0c9bSToomas Soome struct timeval tv = { 0, 0 }; 2885ffb0c9bSToomas Soome fd_set readfds; 2895ffb0c9bSToomas Soome fd_set *fs; 2905ffb0c9bSToomas Soome int ret; 2915ffb0c9bSToomas Soome 292c65ebfc7SToomas Soome #if defined(_WIN32) 293c65ebfc7SToomas Soome fs = &readfds; 294c65ebfc7SToomas Soome FD_ZERO(fs); 295c65ebfc7SToomas Soome FD_SET(sd, fs); 296c65ebfc7SToomas Soome ret = select((int)sd+1, fs, (fd_set*)NULL, (fd_set*)NULL, &tv); 297c65ebfc7SToomas Soome #else 2985ffb0c9bSToomas Soome if (sd < FD_SETSIZE) 2995ffb0c9bSToomas Soome { 3005ffb0c9bSToomas Soome fs = &readfds; 3015ffb0c9bSToomas Soome FD_ZERO(fs); 3025ffb0c9bSToomas Soome } 3035ffb0c9bSToomas Soome else 3045ffb0c9bSToomas Soome { 3055ffb0c9bSToomas Soome // Compute the number of integers needed for storing "sd". Internally fd_set is stored 3065ffb0c9bSToomas Soome // as an array of ints with one bit for each fd and hence we need to compute 3075ffb0c9bSToomas Soome // the number of ints needed rather than the number of bytes. If "sd" is 32, we need 3085ffb0c9bSToomas Soome // two ints and not just one. 3095ffb0c9bSToomas Soome int nfdbits = sizeof (int) * 8; 3105ffb0c9bSToomas Soome int nints = (sd/nfdbits) + 1; 311cda73f64SToomas Soome fs = (fd_set *)calloc(nints, (size_t)sizeof(int)); 312c65ebfc7SToomas Soome if (fs == NULL) 313c65ebfc7SToomas Soome { 314c65ebfc7SToomas Soome syslog(LOG_WARNING, "dnssd_clientstub more_bytes: malloc failed"); 315c65ebfc7SToomas Soome return 0; 3165ffb0c9bSToomas Soome } 3175ffb0c9bSToomas Soome } 3185ffb0c9bSToomas Soome FD_SET(sd, fs); 3195ffb0c9bSToomas Soome ret = select((int)sd+1, fs, (fd_set*)NULL, (fd_set*)NULL, &tv); 320c65ebfc7SToomas Soome if (fs != &readfds) 3215ffb0c9bSToomas Soome free(fs); 322c65ebfc7SToomas Soome #endif 3235ffb0c9bSToomas Soome return (ret > 0); 3245ffb0c9bSToomas Soome } 3255ffb0c9bSToomas Soome 3265ffb0c9bSToomas Soome // set_waitlimit() implements a timeout using select. It is called from deliver_request() before recv() OR accept() 3275ffb0c9bSToomas Soome // to ensure the UDS clients are not blocked in these system calls indefinitely. 3285ffb0c9bSToomas Soome // Note: Ideally one should never be blocked here, because it indicates either mDNSResponder daemon is not yet up/hung/ 329c65ebfc7SToomas Soome // superbusy/crashed or some other OS bug. For eg: On Windows which suffers from 3rd party software 330c65ebfc7SToomas Soome // (primarily 3rd party firewall software) interfering with proper functioning of the TCP protocol stack it is possible 3315ffb0c9bSToomas Soome // the next operation on this socket(recv/accept) is blocked since we depend on TCP to communicate with the system service. 3325ffb0c9bSToomas Soome static int set_waitlimit(dnssd_sock_t sock, int timeout) 3335ffb0c9bSToomas Soome { 3345ffb0c9bSToomas Soome int gDaemonErr = kDNSServiceErr_NoError; 3355ffb0c9bSToomas Soome 3365ffb0c9bSToomas Soome // To prevent stack corruption since select does not work with timeout if fds > FD_SETSIZE(1024) 3375ffb0c9bSToomas Soome if (!gDaemonErr && sock < FD_SETSIZE) 3385ffb0c9bSToomas Soome { 3395ffb0c9bSToomas Soome struct timeval tv; 3405ffb0c9bSToomas Soome fd_set set; 3415ffb0c9bSToomas Soome 3425ffb0c9bSToomas Soome FD_ZERO(&set); 3435ffb0c9bSToomas Soome FD_SET(sock, &set); 3445ffb0c9bSToomas Soome tv.tv_sec = timeout; 3455ffb0c9bSToomas Soome tv.tv_usec = 0; 3465ffb0c9bSToomas Soome if (!select((int)(sock + 1), &set, NULL, NULL, &tv)) 3475ffb0c9bSToomas Soome { 3485ffb0c9bSToomas Soome // Ideally one should never hit this case: See comments before set_waitlimit() 3495ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub set_waitlimit:_daemon timed out (%d secs) without any response: Socket %d", timeout, sock); 3505ffb0c9bSToomas Soome gDaemonErr = kDNSServiceErr_Timeout; 3515ffb0c9bSToomas Soome } 3525ffb0c9bSToomas Soome } 3535ffb0c9bSToomas Soome return gDaemonErr; 3545ffb0c9bSToomas Soome } 3554b22b933Srs 3564b22b933Srs /* create_hdr 3574b22b933Srs * 3585ffb0c9bSToomas Soome * allocate and initialize an ipc message header. Value of len should initially be the 3595ffb0c9bSToomas Soome * length of the data, and is set to the value of the data plus the header. data_start 3605ffb0c9bSToomas Soome * is set to point to the beginning of the data section. SeparateReturnSocket should be 3615ffb0c9bSToomas Soome * non-zero for calls that can't receive an immediate error return value on their primary 3625ffb0c9bSToomas Soome * socket, and therefore require a separate return path for the error code result. 3634b22b933Srs * if zero, the path to a control socket is appended at the beginning of the message buffer. 3644b22b933Srs * data_start is set past this string. 3654b22b933Srs */ 3665ffb0c9bSToomas Soome static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int SeparateReturnSocket, DNSServiceOp *ref) 3675ffb0c9bSToomas Soome { 3684b22b933Srs char *msg = NULL; 3694b22b933Srs ipc_msg_hdr *hdr; 3704b22b933Srs int datalen; 3714b22b933Srs #if !defined(USE_TCP_LOOPBACK) 3725ffb0c9bSToomas Soome char ctrl_path[64] = ""; // "/var/tmp/dnssd_result_socket.xxxxxxxxxx-xxx-xxxxxx" 3734b22b933Srs #endif 3744b22b933Srs 3755ffb0c9bSToomas Soome if (SeparateReturnSocket) 3765ffb0c9bSToomas Soome { 3774b22b933Srs #if defined(USE_TCP_LOOPBACK) 3785ffb0c9bSToomas Soome *len += 2; // Allocate space for two-byte port number 3795ffb0c9bSToomas Soome #elif defined(USE_NAMED_ERROR_RETURN_SOCKET) 3805ffb0c9bSToomas Soome struct timeval tv; 3815ffb0c9bSToomas Soome if (gettimeofday(&tv, NULL) < 0) 3825ffb0c9bSToomas Soome { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: gettimeofday failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); return NULL; } 383cda73f64SToomas Soome snprintf(ctrl_path, sizeof(ctrl_path), "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(), 3845ffb0c9bSToomas Soome (unsigned long)(tv.tv_sec & 0xFFF), (unsigned long)(tv.tv_usec)); 3854b22b933Srs *len += strlen(ctrl_path) + 1; 3865ffb0c9bSToomas Soome #else 3875ffb0c9bSToomas Soome *len += 1; // Allocate space for single zero byte (empty C string) 3884b22b933Srs #endif 3895ffb0c9bSToomas Soome } 3904b22b933Srs 3914b22b933Srs datalen = (int) *len; 3924b22b933Srs *len += sizeof(ipc_msg_hdr); 3934b22b933Srs 3945ffb0c9bSToomas Soome // Write message to buffer 3954b22b933Srs msg = malloc(*len); 3965ffb0c9bSToomas Soome if (!msg) { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: malloc failed"); return NULL; } 3975ffb0c9bSToomas Soome 3985ffb0c9bSToomas Soome memset(msg, 0, *len); 3995ffb0c9bSToomas Soome hdr = (ipc_msg_hdr *)msg; 4005ffb0c9bSToomas Soome hdr->version = VERSION; 4015ffb0c9bSToomas Soome hdr->datalen = datalen; 4025ffb0c9bSToomas Soome hdr->ipc_flags = 0; 4035ffb0c9bSToomas Soome hdr->op = op; 4045ffb0c9bSToomas Soome hdr->client_context = ref->uid; 4055ffb0c9bSToomas Soome hdr->reg_index = 0; 4064b22b933Srs *data_start = msg + sizeof(ipc_msg_hdr); 4074b22b933Srs #if defined(USE_TCP_LOOPBACK) 4085ffb0c9bSToomas Soome // Put dummy data in for the port, since we don't know what it is yet. 4095ffb0c9bSToomas Soome // The data will get filled in before we send the message. This happens in deliver_request(). 4105ffb0c9bSToomas Soome if (SeparateReturnSocket) put_uint16(0, data_start); 4114b22b933Srs #else 4125ffb0c9bSToomas Soome if (SeparateReturnSocket) put_string(ctrl_path, data_start); 4134b22b933Srs #endif 4144b22b933Srs return hdr; 4155ffb0c9bSToomas Soome } 4164b22b933Srs 4175ffb0c9bSToomas Soome static void FreeDNSRecords(DNSServiceOp *sdRef) 4185ffb0c9bSToomas Soome { 4195ffb0c9bSToomas Soome DNSRecord *rec = sdRef->rec; 4205ffb0c9bSToomas Soome while (rec) 4214b22b933Srs { 4225ffb0c9bSToomas Soome DNSRecord *next = rec->recnext; 4235ffb0c9bSToomas Soome free(rec); 4245ffb0c9bSToomas Soome rec = next; 4255ffb0c9bSToomas Soome } 4265ffb0c9bSToomas Soome } 4274b22b933Srs 4285ffb0c9bSToomas Soome static void FreeDNSServiceOp(DNSServiceOp *x) 4295ffb0c9bSToomas Soome { 4305ffb0c9bSToomas Soome // We don't use our DNSServiceRefValid macro here because if we're cleaning up after a socket() call failed 4315ffb0c9bSToomas Soome // then sockfd could legitimately contain a failing value (e.g. dnssd_InvalidSocket) 4325ffb0c9bSToomas Soome if ((x->sockfd ^ x->validator) != ValidatorBits) 433cda73f64SToomas Soome { 434cda73f64SToomas Soome static DNSServiceOp *op_were_not_going_to_free_but_we_need_to_fool_the_analyzer; 4355ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub attempt to dispose invalid DNSServiceRef %p %08X %08X", x, x->sockfd, x->validator); 436cda73f64SToomas Soome op_were_not_going_to_free_but_we_need_to_fool_the_analyzer = x; 437cda73f64SToomas Soome } 4385ffb0c9bSToomas Soome else 4395ffb0c9bSToomas Soome { 4405ffb0c9bSToomas Soome x->next = NULL; 4415ffb0c9bSToomas Soome x->primary = NULL; 4425ffb0c9bSToomas Soome x->sockfd = dnssd_InvalidSocket; 4435ffb0c9bSToomas Soome x->validator = 0xDDDDDDDD; 4445ffb0c9bSToomas Soome x->op = request_op_none; 4455ffb0c9bSToomas Soome x->max_index = 0; 4465ffb0c9bSToomas Soome x->logcounter = 0; 4475ffb0c9bSToomas Soome x->moreptr = NULL; 4485ffb0c9bSToomas Soome x->ProcessReply = NULL; 4495ffb0c9bSToomas Soome x->AppCallback = NULL; 4505ffb0c9bSToomas Soome x->AppContext = NULL; 4515ffb0c9bSToomas Soome #if _DNS_SD_LIBDISPATCH 4525ffb0c9bSToomas Soome if (x->disp_source) dispatch_release(x->disp_source); 4535ffb0c9bSToomas Soome x->disp_source = NULL; 4545ffb0c9bSToomas Soome x->disp_queue = NULL; 4555ffb0c9bSToomas Soome #endif 4565ffb0c9bSToomas Soome // DNSRecords may have been added to subordinate sdRef e.g., DNSServiceRegister/DNSServiceAddRecord 457c65ebfc7SToomas Soome // or on the main sdRef e.g., DNSServiceCreateConnection/DNSServiceRegisterRecord. 458c65ebfc7SToomas Soome // DNSRecords may have been freed if the application called DNSRemoveRecord. 4595ffb0c9bSToomas Soome FreeDNSRecords(x); 4605ffb0c9bSToomas Soome if (x->kacontext) 4615ffb0c9bSToomas Soome { 4625ffb0c9bSToomas Soome free(x->kacontext); 4635ffb0c9bSToomas Soome x->kacontext = NULL; 4645ffb0c9bSToomas Soome } 4655ffb0c9bSToomas Soome free(x); 4665ffb0c9bSToomas Soome } 4675ffb0c9bSToomas Soome } 4684b22b933Srs 4695ffb0c9bSToomas Soome // Return a connected service ref (deallocate with DNSServiceRefDeallocate) 4705ffb0c9bSToomas Soome static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags flags, uint32_t op, ProcessReplyFn ProcessReply, void *AppCallback, void *AppContext) 4715ffb0c9bSToomas Soome { 4725ffb0c9bSToomas Soome int NumTries = 0; 4734b22b933Srs 4745ffb0c9bSToomas Soome dnssd_sockaddr_t saddr; 4755ffb0c9bSToomas Soome DNSServiceOp *sdr; 4764b22b933Srs 477c65ebfc7SToomas Soome if (!ref) 478c65ebfc7SToomas Soome { 479c65ebfc7SToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSService operation with NULL DNSServiceRef"); 480c65ebfc7SToomas Soome return kDNSServiceErr_BadParam; 4815ffb0c9bSToomas Soome } 4824b22b933Srs 4835ffb0c9bSToomas Soome if (flags & kDNSServiceFlagsShareConnection) 4845ffb0c9bSToomas Soome { 4855ffb0c9bSToomas Soome if (!*ref) 4865ffb0c9bSToomas Soome { 4875ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with NULL DNSServiceRef"); 4885ffb0c9bSToomas Soome return kDNSServiceErr_BadParam; 4895ffb0c9bSToomas Soome } 4905ffb0c9bSToomas Soome if (!DNSServiceRefValid(*ref) || ((*ref)->op != connection_request && (*ref)->op != connection_delegate_request) || (*ref)->primary) 4915ffb0c9bSToomas Soome { 4925ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with invalid DNSServiceRef %p %08X %08X op %d", 4935ffb0c9bSToomas Soome (*ref), (*ref)->sockfd, (*ref)->validator, (*ref)->op); 4945ffb0c9bSToomas Soome *ref = NULL; 4955ffb0c9bSToomas Soome return kDNSServiceErr_BadReference; 4965ffb0c9bSToomas Soome } 4975ffb0c9bSToomas Soome } 4984b22b933Srs 4995ffb0c9bSToomas Soome #if defined(_WIN32) 5005ffb0c9bSToomas Soome if (!g_initWinsock) 5015ffb0c9bSToomas Soome { 5025ffb0c9bSToomas Soome WSADATA wsaData; 5035ffb0c9bSToomas Soome g_initWinsock = 1; 5045ffb0c9bSToomas Soome if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { *ref = NULL; return kDNSServiceErr_ServiceNotRunning; } 5055ffb0c9bSToomas Soome } 5065ffb0c9bSToomas Soome // <rdar://problem/4096913> If the system service is disabled, we only want to try to connect once 507c65ebfc7SToomas Soome if (IsSystemServiceDisabled()) 5085ffb0c9bSToomas Soome NumTries = DNSSD_CLIENT_MAXTRIES; 5095ffb0c9bSToomas Soome #endif 5105ffb0c9bSToomas Soome 5115ffb0c9bSToomas Soome sdr = malloc(sizeof(DNSServiceOp)); 512c65ebfc7SToomas Soome if (!sdr) 513c65ebfc7SToomas Soome { 514c65ebfc7SToomas Soome syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: malloc failed"); 515c65ebfc7SToomas Soome *ref = NULL; 516c65ebfc7SToomas Soome return kDNSServiceErr_NoMemory; 5175ffb0c9bSToomas Soome } 5185ffb0c9bSToomas Soome sdr->next = NULL; 5195ffb0c9bSToomas Soome sdr->primary = NULL; 5205ffb0c9bSToomas Soome sdr->sockfd = dnssd_InvalidSocket; 5215ffb0c9bSToomas Soome sdr->validator = sdr->sockfd ^ ValidatorBits; 5225ffb0c9bSToomas Soome sdr->op = op; 5235ffb0c9bSToomas Soome sdr->max_index = 0; 5245ffb0c9bSToomas Soome sdr->logcounter = 0; 5255ffb0c9bSToomas Soome sdr->moreptr = NULL; 5265ffb0c9bSToomas Soome sdr->uid.u32[0] = 0; 5275ffb0c9bSToomas Soome sdr->uid.u32[1] = 0; 5285ffb0c9bSToomas Soome sdr->ProcessReply = ProcessReply; 5295ffb0c9bSToomas Soome sdr->AppCallback = AppCallback; 5305ffb0c9bSToomas Soome sdr->AppContext = AppContext; 5315ffb0c9bSToomas Soome sdr->rec = NULL; 5325ffb0c9bSToomas Soome #if _DNS_SD_LIBDISPATCH 5335ffb0c9bSToomas Soome sdr->disp_source = NULL; 5345ffb0c9bSToomas Soome sdr->disp_queue = NULL; 5354b22b933Srs #endif 5365ffb0c9bSToomas Soome sdr->kacontext = NULL; 5374b22b933Srs 5385ffb0c9bSToomas Soome if (flags & kDNSServiceFlagsShareConnection) 5394b22b933Srs { 5405ffb0c9bSToomas Soome DNSServiceOp **p = &(*ref)->next; // Append ourselves to end of primary's list 541c65ebfc7SToomas Soome while (*p) 5425ffb0c9bSToomas Soome p = &(*p)->next; 5435ffb0c9bSToomas Soome *p = sdr; 5445ffb0c9bSToomas Soome // Preincrement counter before we use it -- it helps with debugging if we know the all-zeroes ID should never appear 545c65ebfc7SToomas Soome if (++(*ref)->uid.u32[0] == 0) 5465ffb0c9bSToomas Soome ++(*ref)->uid.u32[1]; // In parent DNSServiceOp increment UID counter 5475ffb0c9bSToomas Soome sdr->primary = *ref; // Set our primary pointer 5485ffb0c9bSToomas Soome sdr->sockfd = (*ref)->sockfd; // Inherit primary's socket 5495ffb0c9bSToomas Soome sdr->validator = (*ref)->validator; 5505ffb0c9bSToomas Soome sdr->uid = (*ref)->uid; 5515ffb0c9bSToomas Soome //printf("ConnectToServer sharing socket %d\n", sdr->sockfd); 5525ffb0c9bSToomas Soome } 5535ffb0c9bSToomas Soome else 5545ffb0c9bSToomas Soome { 5555ffb0c9bSToomas Soome #ifdef SO_NOSIGPIPE 5565ffb0c9bSToomas Soome const unsigned long optval = 1; 5575ffb0c9bSToomas Soome #endif 5585ffb0c9bSToomas Soome #ifndef USE_TCP_LOOPBACK 5595ffb0c9bSToomas Soome char* uds_serverpath = getenv(MDNS_UDS_SERVERPATH_ENVVAR); 5605ffb0c9bSToomas Soome if (uds_serverpath == NULL) 5615ffb0c9bSToomas Soome uds_serverpath = MDNS_UDS_SERVERPATH; 562cda73f64SToomas Soome else if (strlen(uds_serverpath) >= MAX_CTLPATH) 563cda73f64SToomas Soome { 564cda73f64SToomas Soome uds_serverpath = MDNS_UDS_SERVERPATH; 565cda73f64SToomas Soome syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: using default path since env len is invalid"); 566cda73f64SToomas Soome } 5675ffb0c9bSToomas Soome #endif 5685ffb0c9bSToomas Soome *ref = NULL; 5695ffb0c9bSToomas Soome sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0); 5705ffb0c9bSToomas Soome sdr->validator = sdr->sockfd ^ ValidatorBits; 5715ffb0c9bSToomas Soome if (!dnssd_SocketValid(sdr->sockfd)) 5725ffb0c9bSToomas Soome { 5735ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: socket failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); 5745ffb0c9bSToomas Soome FreeDNSServiceOp(sdr); 5755ffb0c9bSToomas Soome return kDNSServiceErr_NoMemory; 5765ffb0c9bSToomas Soome } 5775ffb0c9bSToomas Soome #ifdef SO_NOSIGPIPE 5785ffb0c9bSToomas Soome // Some environments (e.g. OS X) support turning off SIGPIPE for a socket 5795ffb0c9bSToomas Soome if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0) 5805ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_NOSIGPIPE failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); 5815ffb0c9bSToomas Soome #endif 5825ffb0c9bSToomas Soome #if defined(USE_TCP_LOOPBACK) 5835ffb0c9bSToomas Soome saddr.sin_family = AF_INET; 5845ffb0c9bSToomas Soome saddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR); 5855ffb0c9bSToomas Soome saddr.sin_port = htons(MDNS_TCP_SERVERPORT); 5865ffb0c9bSToomas Soome #else 5875ffb0c9bSToomas Soome saddr.sun_family = AF_LOCAL; 588c65ebfc7SToomas Soome SetUDSPath(&saddr, uds_serverpath); 5895ffb0c9bSToomas Soome #if !defined(__ppc__) && defined(SO_DEFUNCTOK) 5905ffb0c9bSToomas Soome { 5915ffb0c9bSToomas Soome int defunct = 1; 5925ffb0c9bSToomas Soome if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0) 5935ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); 5945ffb0c9bSToomas Soome } 5955ffb0c9bSToomas Soome #endif 5965ffb0c9bSToomas Soome #endif 597c65ebfc7SToomas Soome 5985ffb0c9bSToomas Soome while (1) 5995ffb0c9bSToomas Soome { 6005ffb0c9bSToomas Soome int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr)); 6015ffb0c9bSToomas Soome if (!err) 6025ffb0c9bSToomas Soome break; // If we succeeded, return sdr 6035ffb0c9bSToomas Soome // If we failed, then it may be because the daemon is still launching. 6045ffb0c9bSToomas Soome // This can happen for processes that launch early in the boot process, while the 6055ffb0c9bSToomas Soome // daemon is still coming up. Rather than fail here, we wait 1 sec and try again. 6065ffb0c9bSToomas Soome // If, after DNSSD_CLIENT_MAXTRIES, we still can't connect to the daemon, 6075ffb0c9bSToomas Soome // then we give up and return a failure code. 6085ffb0c9bSToomas Soome if (++NumTries < DNSSD_CLIENT_MAXTRIES) 6095ffb0c9bSToomas Soome { 610c65ebfc7SToomas Soome syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect()-> No of tries: %d", NumTries); 6115ffb0c9bSToomas Soome sleep(1); // Sleep a bit, then try again 6125ffb0c9bSToomas Soome } 613c65ebfc7SToomas Soome else 6145ffb0c9bSToomas Soome { 615cda73f64SToomas Soome #if !defined(USE_TCP_LOOPBACK) 616c65ebfc7SToomas Soome syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect() failed path:%s Socket:%d Err:%d Errno:%d %s", 6175ffb0c9bSToomas Soome uds_serverpath, sdr->sockfd, err, dnssd_errno, dnssd_strerror(dnssd_errno)); 618cda73f64SToomas Soome #endif 619c65ebfc7SToomas Soome dnssd_close(sdr->sockfd); 620c65ebfc7SToomas Soome FreeDNSServiceOp(sdr); 621c65ebfc7SToomas Soome return kDNSServiceErr_ServiceNotRunning; 6225ffb0c9bSToomas Soome } 6235ffb0c9bSToomas Soome } 6245ffb0c9bSToomas Soome //printf("ConnectToServer opened socket %d\n", sdr->sockfd); 6255ffb0c9bSToomas Soome } 6265ffb0c9bSToomas Soome 6275ffb0c9bSToomas Soome *ref = sdr; 6285ffb0c9bSToomas Soome return kDNSServiceErr_NoError; 6295ffb0c9bSToomas Soome } 6305ffb0c9bSToomas Soome 6315ffb0c9bSToomas Soome #define deliver_request_bailout(MSG) \ 632*3b436d06SToomas Soome syslog(LOG_WARNING, "dnssd_clientstub deliver_request: %s failed %d (%s)", (MSG), dnssd_errno, dnssd_strerror(dnssd_errno)); goto cleanup 6335ffb0c9bSToomas Soome 6345ffb0c9bSToomas Soome static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) 6355ffb0c9bSToomas Soome { 636c65ebfc7SToomas Soome uint32_t datalen; 637c65ebfc7SToomas Soome dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket; 638c65ebfc7SToomas Soome DNSServiceErrorType err = kDNSServiceErr_Unknown; // Default for the "goto cleanup" cases 639c65ebfc7SToomas Soome int MakeSeparateReturnSocket; 640c65ebfc7SToomas Soome #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET) 641c65ebfc7SToomas Soome char *data; 642c65ebfc7SToomas Soome #endif 643c65ebfc7SToomas Soome 644cda73f64SToomas Soome if (!hdr) 645cda73f64SToomas Soome { 646cda73f64SToomas Soome syslog(LOG_WARNING, "dnssd_clientstub deliver_request: !hdr"); 647cda73f64SToomas Soome return kDNSServiceErr_Unknown; 648cda73f64SToomas Soome } 649cda73f64SToomas Soome 650c65ebfc7SToomas Soome datalen = hdr->datalen; // We take a copy here because we're going to convert hdr->datalen to network byte order 6515ffb0c9bSToomas Soome #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET) 652c65ebfc7SToomas Soome data = (char *)hdr + sizeof(ipc_msg_hdr); 6535ffb0c9bSToomas Soome #endif 6545ffb0c9bSToomas Soome 6555ffb0c9bSToomas Soome // Note: need to check hdr->op, not sdr->op. 6565ffb0c9bSToomas Soome // hdr->op contains the code for the specific operation we're currently doing, whereas sdr->op 6575ffb0c9bSToomas Soome // contains the original parent DNSServiceOp (e.g. for an add_record_request, hdr->op will be 6585ffb0c9bSToomas Soome // add_record_request but the parent sdr->op will be connection_request or reg_service_request) 659c65ebfc7SToomas Soome MakeSeparateReturnSocket = (sdr->primary || 660cda73f64SToomas Soome hdr->op == reg_record_request || hdr->op == add_record_request || hdr->op == update_record_request || hdr->op == remove_record_request); 6615ffb0c9bSToomas Soome 6625ffb0c9bSToomas Soome if (!DNSServiceRefValid(sdr)) 6635ffb0c9bSToomas Soome { 6645ffb0c9bSToomas Soome if (hdr) 6655ffb0c9bSToomas Soome free(hdr); 6665ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub deliver_request: invalid DNSServiceRef %p %08X %08X", sdr, sdr->sockfd, sdr->validator); 6675ffb0c9bSToomas Soome return kDNSServiceErr_BadReference; 6685ffb0c9bSToomas Soome } 6694b22b933Srs 6705ffb0c9bSToomas Soome if (MakeSeparateReturnSocket) 6715ffb0c9bSToomas Soome { 6725ffb0c9bSToomas Soome #if defined(USE_TCP_LOOPBACK) 6735ffb0c9bSToomas Soome { 6745ffb0c9bSToomas Soome union { uint16_t s; u_char b[2]; } port; 6755ffb0c9bSToomas Soome dnssd_sockaddr_t caddr; 6765ffb0c9bSToomas Soome dnssd_socklen_t len = (dnssd_socklen_t) sizeof(caddr); 6775ffb0c9bSToomas Soome listenfd = socket(AF_DNSSD, SOCK_STREAM, 0); 678*3b436d06SToomas Soome if (!dnssd_SocketValid(listenfd)) { 679*3b436d06SToomas Soome deliver_request_bailout("TCP socket"); 680*3b436d06SToomas Soome } 6815ffb0c9bSToomas Soome 6825ffb0c9bSToomas Soome caddr.sin_family = AF_INET; 6835ffb0c9bSToomas Soome caddr.sin_port = 0; 6845ffb0c9bSToomas Soome caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR); 685*3b436d06SToomas Soome if (bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr)) < 0) { 686*3b436d06SToomas Soome deliver_request_bailout("TCP bind"); 687*3b436d06SToomas Soome } 688*3b436d06SToomas Soome if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) { 689*3b436d06SToomas Soome deliver_request_bailout("TCP getsockname"); 690*3b436d06SToomas Soome } 691*3b436d06SToomas Soome if (listen(listenfd, 1) < 0) { 692*3b436d06SToomas Soome deliver_request_bailout("TCP listen"); 693*3b436d06SToomas Soome } 6945ffb0c9bSToomas Soome port.s = caddr.sin_port; 6955ffb0c9bSToomas Soome data[0] = port.b[0]; // don't switch the byte order, as the 6965ffb0c9bSToomas Soome data[1] = port.b[1]; // daemon expects it in network byte order 6975ffb0c9bSToomas Soome } 6985ffb0c9bSToomas Soome #elif defined(USE_NAMED_ERROR_RETURN_SOCKET) 6995ffb0c9bSToomas Soome { 7005ffb0c9bSToomas Soome mode_t mask; 7015ffb0c9bSToomas Soome int bindresult; 7025ffb0c9bSToomas Soome dnssd_sockaddr_t caddr; 7035ffb0c9bSToomas Soome listenfd = socket(AF_DNSSD, SOCK_STREAM, 0); 704*3b436d06SToomas Soome if (!dnssd_SocketValid(listenfd)) { 705*3b436d06SToomas Soome deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET socket"); 706*3b436d06SToomas Soome } 7075ffb0c9bSToomas Soome 7085ffb0c9bSToomas Soome caddr.sun_family = AF_LOCAL; 7095ffb0c9bSToomas Soome // According to Stevens (section 3.2), there is no portable way to 7105ffb0c9bSToomas Soome // determine whether sa_len is defined on a particular platform. 7115ffb0c9bSToomas Soome #ifndef NOT_HAVE_SA_LEN 7125ffb0c9bSToomas Soome caddr.sun_len = sizeof(struct sockaddr_un); 7135ffb0c9bSToomas Soome #endif 714c65ebfc7SToomas Soome SetUDSPath(&caddr, data); 7155ffb0c9bSToomas Soome mask = umask(0); 7165ffb0c9bSToomas Soome bindresult = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr)); 7175ffb0c9bSToomas Soome umask(mask); 718*3b436d06SToomas Soome if (bindresult < 0) { 719*3b436d06SToomas Soome deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET bind"); 720*3b436d06SToomas Soome } 721*3b436d06SToomas Soome if (listen(listenfd, 1) < 0) { 722*3b436d06SToomas Soome deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET listen"); 723*3b436d06SToomas Soome } 7245ffb0c9bSToomas Soome } 7255ffb0c9bSToomas Soome #else 7265ffb0c9bSToomas Soome { 7275ffb0c9bSToomas Soome dnssd_sock_t sp[2]; 728*3b436d06SToomas Soome if (socketpair(AF_DNSSD, SOCK_STREAM, 0, sp) < 0) { 729*3b436d06SToomas Soome deliver_request_bailout("socketpair"); 730*3b436d06SToomas Soome } 7315ffb0c9bSToomas Soome else 7325ffb0c9bSToomas Soome { 7335ffb0c9bSToomas Soome errsd = sp[0]; // We'll read our four-byte error code from sp[0] 7345ffb0c9bSToomas Soome listenfd = sp[1]; // We'll send sp[1] to the daemon 7355ffb0c9bSToomas Soome #if !defined(__ppc__) && defined(SO_DEFUNCTOK) 7365ffb0c9bSToomas Soome { 7375ffb0c9bSToomas Soome int defunct = 1; 7385ffb0c9bSToomas Soome if (setsockopt(errsd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0) 7395ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); 7405ffb0c9bSToomas Soome } 7415ffb0c9bSToomas Soome #endif 7425ffb0c9bSToomas Soome } 7435ffb0c9bSToomas Soome } 7445ffb0c9bSToomas Soome #endif 7455ffb0c9bSToomas Soome } 7464b22b933Srs 7475ffb0c9bSToomas Soome #if !defined(USE_TCP_LOOPBACK) && !defined(USE_NAMED_ERROR_RETURN_SOCKET) 7485ffb0c9bSToomas Soome // If we're going to make a separate error return socket, and pass it to the daemon 7495ffb0c9bSToomas Soome // using sendmsg, then we'll hold back one data byte to go with it. 7505ffb0c9bSToomas Soome // On some versions of Unix (including Leopard) sending a control message without 7515ffb0c9bSToomas Soome // any associated data does not work reliably -- e.g. one particular issue we ran 7525ffb0c9bSToomas Soome // into is that if the receiving program is in a kqueue loop waiting to be notified 7535ffb0c9bSToomas Soome // of the received message, it doesn't get woken up when the control message arrives. 754c65ebfc7SToomas Soome if (MakeSeparateReturnSocket || sdr->op == send_bpf) 7555ffb0c9bSToomas Soome datalen--; // Okay to use sdr->op when checking for op == send_bpf 7565ffb0c9bSToomas Soome #endif 7575ffb0c9bSToomas Soome 7585ffb0c9bSToomas Soome // At this point, our listening socket is set up and waiting, if necessary, for the daemon to connect back to 7595ffb0c9bSToomas Soome ConvertHeaderBytes(hdr); 7605ffb0c9bSToomas Soome //syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %lu bytes", (unsigned long)(datalen + sizeof(ipc_msg_hdr))); 7615ffb0c9bSToomas Soome //if (MakeSeparateReturnSocket) syslog(LOG_WARNING, "dnssd_clientstub deliver_request name is %s", data); 7625ffb0c9bSToomas Soome #if TEST_SENDING_ONE_BYTE_AT_A_TIME 7635ffb0c9bSToomas Soome unsigned int i; 7645ffb0c9bSToomas Soome for (i=0; i<datalen + sizeof(ipc_msg_hdr); i++) 7655ffb0c9bSToomas Soome { 7665ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %d", i); 7675ffb0c9bSToomas Soome if (write_all(sdr->sockfd, ((char *)hdr)+i, 1) < 0) 7685ffb0c9bSToomas Soome { syslog(LOG_WARNING, "write_all (byte %u) failed", i); goto cleanup; } 7695ffb0c9bSToomas Soome usleep(10000); 7705ffb0c9bSToomas Soome } 7714b22b933Srs #else 7725ffb0c9bSToomas Soome if (write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr)) < 0) 7735ffb0c9bSToomas Soome { 7745ffb0c9bSToomas Soome // write_all already prints an error message if there is an error writing to 7755ffb0c9bSToomas Soome // the socket except for DEFUNCT. Logging here is unnecessary and also wrong 7765ffb0c9bSToomas Soome // in the case of DEFUNCT sockets 7775ffb0c9bSToomas Soome syslog(LOG_INFO, "dnssd_clientstub deliver_request ERROR: write_all(%d, %lu bytes) failed", 7785ffb0c9bSToomas Soome sdr->sockfd, (unsigned long)(datalen + sizeof(ipc_msg_hdr))); 7795ffb0c9bSToomas Soome goto cleanup; 7805ffb0c9bSToomas Soome } 7814b22b933Srs #endif 7825ffb0c9bSToomas Soome 783c65ebfc7SToomas Soome if (!MakeSeparateReturnSocket) 7845ffb0c9bSToomas Soome errsd = sdr->sockfd; 7855ffb0c9bSToomas Soome if (MakeSeparateReturnSocket || sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf 7865ffb0c9bSToomas Soome { 7875ffb0c9bSToomas Soome #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET) 7885ffb0c9bSToomas Soome // At this point we may wait in accept for a few milliseconds waiting for the daemon to connect back to us, 7895ffb0c9bSToomas Soome // but that's okay -- the daemon should not take more than a few milliseconds to respond. 7905ffb0c9bSToomas Soome // set_waitlimit() ensures we do not block indefinitely just in case something is wrong 7915ffb0c9bSToomas Soome dnssd_sockaddr_t daddr; 7925ffb0c9bSToomas Soome dnssd_socklen_t len = sizeof(daddr); 793c65ebfc7SToomas Soome if ((err = set_waitlimit(listenfd, DNSSD_CLIENT_TIMEOUT)) != kDNSServiceErr_NoError) 7945ffb0c9bSToomas Soome goto cleanup; 7955ffb0c9bSToomas Soome errsd = accept(listenfd, (struct sockaddr *)&daddr, &len); 796*3b436d06SToomas Soome if (!dnssd_SocketValid(errsd)) { 7975ffb0c9bSToomas Soome deliver_request_bailout("accept"); 798*3b436d06SToomas Soome } 7995ffb0c9bSToomas Soome #else 8005ffb0c9bSToomas Soome 8015ffb0c9bSToomas Soome struct iovec vec = { ((char *)hdr) + sizeof(ipc_msg_hdr) + datalen, 1 }; // Send the last byte along with the SCM_RIGHTS 8025ffb0c9bSToomas Soome struct msghdr msg; 8035ffb0c9bSToomas Soome struct cmsghdr *cmsg; 8045ffb0c9bSToomas Soome char cbuf[CMSG_SPACE(4 * sizeof(dnssd_sock_t))]; 8055ffb0c9bSToomas Soome 8065ffb0c9bSToomas Soome msg.msg_name = 0; 8075ffb0c9bSToomas Soome msg.msg_namelen = 0; 8085ffb0c9bSToomas Soome msg.msg_iov = &vec; 8095ffb0c9bSToomas Soome msg.msg_iovlen = 1; 8105ffb0c9bSToomas Soome msg.msg_flags = 0; 8115ffb0c9bSToomas Soome if (MakeSeparateReturnSocket || sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf 8125ffb0c9bSToomas Soome { 8135ffb0c9bSToomas Soome if (sdr->op == send_bpf) 8145ffb0c9bSToomas Soome { 8155ffb0c9bSToomas Soome int i; 8165ffb0c9bSToomas Soome char p[12]; // Room for "/dev/bpf999" with terminating null 8175ffb0c9bSToomas Soome for (i=0; i<100; i++) 8185ffb0c9bSToomas Soome { 8195ffb0c9bSToomas Soome snprintf(p, sizeof(p), "/dev/bpf%d", i); 8205ffb0c9bSToomas Soome listenfd = open(p, O_RDWR, 0); 8215ffb0c9bSToomas Soome //if (dnssd_SocketValid(listenfd)) syslog(LOG_WARNING, "Sending fd %d for %s", listenfd, p); 8225ffb0c9bSToomas Soome if (!dnssd_SocketValid(listenfd) && dnssd_errno != EBUSY) 8235ffb0c9bSToomas Soome syslog(LOG_WARNING, "Error opening %s %d (%s)", p, dnssd_errno, dnssd_strerror(dnssd_errno)); 8245ffb0c9bSToomas Soome if (dnssd_SocketValid(listenfd) || dnssd_errno != EBUSY) break; 8255ffb0c9bSToomas Soome } 8265ffb0c9bSToomas Soome } 8275ffb0c9bSToomas Soome msg.msg_control = cbuf; 8285ffb0c9bSToomas Soome msg.msg_controllen = CMSG_LEN(sizeof(dnssd_sock_t)); 8295ffb0c9bSToomas Soome 8305ffb0c9bSToomas Soome cmsg = CMSG_FIRSTHDR(&msg); 8315ffb0c9bSToomas Soome cmsg->cmsg_len = CMSG_LEN(sizeof(dnssd_sock_t)); 8325ffb0c9bSToomas Soome cmsg->cmsg_level = SOL_SOCKET; 8335ffb0c9bSToomas Soome cmsg->cmsg_type = SCM_RIGHTS; 8345ffb0c9bSToomas Soome *((dnssd_sock_t *)CMSG_DATA(cmsg)) = listenfd; 8355ffb0c9bSToomas Soome } 8365ffb0c9bSToomas Soome 8375ffb0c9bSToomas Soome #if TEST_KQUEUE_CONTROL_MESSAGE_BUG 8385ffb0c9bSToomas Soome sleep(1); 8394b22b933Srs #endif 8404b22b933Srs 8415ffb0c9bSToomas Soome #if DEBUG_64BIT_SCM_RIGHTS 8425ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d %ld %ld %ld/%ld/%ld/%ld", 8435ffb0c9bSToomas Soome errsd, listenfd, sizeof(dnssd_sock_t), sizeof(void*), 8445ffb0c9bSToomas Soome sizeof(struct cmsghdr) + sizeof(dnssd_sock_t), 8455ffb0c9bSToomas Soome CMSG_LEN(sizeof(dnssd_sock_t)), (long)CMSG_SPACE(sizeof(dnssd_sock_t)), 8465ffb0c9bSToomas Soome (long)((char*)CMSG_DATA(cmsg) + 4 - cbuf)); 8475ffb0c9bSToomas Soome #endif // DEBUG_64BIT_SCM_RIGHTS 8484b22b933Srs 8495ffb0c9bSToomas Soome if (sendmsg(sdr->sockfd, &msg, 0) < 0) 8504b22b933Srs { 8515ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub deliver_request ERROR: sendmsg failed read sd=%d write sd=%d errno %d (%s)", 8525ffb0c9bSToomas Soome errsd, listenfd, dnssd_errno, dnssd_strerror(dnssd_errno)); 8535ffb0c9bSToomas Soome err = kDNSServiceErr_Incompatible; 8545ffb0c9bSToomas Soome goto cleanup; 8554b22b933Srs } 8564b22b933Srs 8575ffb0c9bSToomas Soome #if DEBUG_64BIT_SCM_RIGHTS 8585ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d okay", errsd, listenfd); 8595ffb0c9bSToomas Soome #endif // DEBUG_64BIT_SCM_RIGHTS 8604b22b933Srs 8615ffb0c9bSToomas Soome #endif 8625ffb0c9bSToomas Soome // Close our end of the socketpair *before* calling read_all() to get the four-byte error code. 8635ffb0c9bSToomas Soome // Otherwise, if the daemon closes our socket (or crashes), we will have to wait for a timeout 8645ffb0c9bSToomas Soome // in read_all() because the socket is not closed (we still have an open reference to it) 8655ffb0c9bSToomas Soome // Note: listenfd is overwritten in the case of send_bpf above and that will be closed here 8665ffb0c9bSToomas Soome // for send_bpf operation. 8675ffb0c9bSToomas Soome dnssd_close(listenfd); 8685ffb0c9bSToomas Soome listenfd = dnssd_InvalidSocket; // Make sure we don't close it a second time in the cleanup handling below 8695ffb0c9bSToomas Soome } 8705ffb0c9bSToomas Soome 8715ffb0c9bSToomas Soome // At this point we may wait in read_all for a few milliseconds waiting for the daemon to send us the error code, 8725ffb0c9bSToomas Soome // but that's okay -- the daemon should not take more than a few milliseconds to respond. 8735ffb0c9bSToomas Soome // set_waitlimit() ensures we do not block indefinitely just in case something is wrong 8745ffb0c9bSToomas Soome if (sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf 8755ffb0c9bSToomas Soome err = kDNSServiceErr_NoError; 8765ffb0c9bSToomas Soome else if ((err = set_waitlimit(errsd, DNSSD_CLIENT_TIMEOUT)) == kDNSServiceErr_NoError) 8775ffb0c9bSToomas Soome { 8785ffb0c9bSToomas Soome if (read_all(errsd, (char*)&err, (int)sizeof(err)) < 0) 8795ffb0c9bSToomas Soome err = kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us 8805ffb0c9bSToomas Soome else 8815ffb0c9bSToomas Soome err = ntohl(err); 8825ffb0c9bSToomas Soome } 8835ffb0c9bSToomas Soome //syslog(LOG_WARNING, "dnssd_clientstub deliver_request: retrieved error code %d", err); 8844b22b933Srs 8854b22b933Srs cleanup: 8865ffb0c9bSToomas Soome if (MakeSeparateReturnSocket) 8875ffb0c9bSToomas Soome { 8885ffb0c9bSToomas Soome if (dnssd_SocketValid(listenfd)) dnssd_close(listenfd); 8895ffb0c9bSToomas Soome if (dnssd_SocketValid(errsd)) dnssd_close(errsd); 8905ffb0c9bSToomas Soome #if defined(USE_NAMED_ERROR_RETURN_SOCKET) 8915ffb0c9bSToomas Soome // syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removing UDS: %s", data); 8925ffb0c9bSToomas Soome if (unlink(data) != 0) 8935ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub WARNING: unlink(\"%s\") failed errno %d (%s)", data, dnssd_errno, dnssd_strerror(dnssd_errno)); 8945ffb0c9bSToomas Soome // else syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removed UDS: %s", data); 8954b22b933Srs #endif 8964b22b933Srs } 8974b22b933Srs 8985ffb0c9bSToomas Soome free(hdr); 8995ffb0c9bSToomas Soome return err; 9005ffb0c9bSToomas Soome } 9015ffb0c9bSToomas Soome 902c65ebfc7SToomas Soome dnssd_sock_t DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef) 9035ffb0c9bSToomas Soome { 9045ffb0c9bSToomas Soome if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with NULL DNSServiceRef"); return dnssd_InvalidSocket; } 9055ffb0c9bSToomas Soome 9065ffb0c9bSToomas Soome if (!DNSServiceRefValid(sdRef)) 9074b22b933Srs { 9085ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with invalid DNSServiceRef %p %08X %08X", 9095ffb0c9bSToomas Soome sdRef, sdRef->sockfd, sdRef->validator); 9105ffb0c9bSToomas Soome return dnssd_InvalidSocket; 9115ffb0c9bSToomas Soome } 9125ffb0c9bSToomas Soome 9135ffb0c9bSToomas Soome if (sdRef->primary) 9145ffb0c9bSToomas Soome { 9155ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef); 9165ffb0c9bSToomas Soome return dnssd_InvalidSocket; 9175ffb0c9bSToomas Soome } 9185ffb0c9bSToomas Soome 919c65ebfc7SToomas Soome return sdRef->sockfd; 9205ffb0c9bSToomas Soome } 9215ffb0c9bSToomas Soome 9225ffb0c9bSToomas Soome #if _DNS_SD_LIBDISPATCH 9235ffb0c9bSToomas Soome static void CallbackWithError(DNSServiceRef sdRef, DNSServiceErrorType error) 9245ffb0c9bSToomas Soome { 9255ffb0c9bSToomas Soome DNSServiceOp *sdr = sdRef; 9265ffb0c9bSToomas Soome DNSServiceOp *sdrNext; 9275ffb0c9bSToomas Soome DNSRecord *rec; 9285ffb0c9bSToomas Soome DNSRecord *recnext; 9295ffb0c9bSToomas Soome int morebytes; 9305ffb0c9bSToomas Soome 9315ffb0c9bSToomas Soome while (sdr) 9325ffb0c9bSToomas Soome { 9335ffb0c9bSToomas Soome // We can't touch the sdr after the callback as it can be deallocated in the callback 9345ffb0c9bSToomas Soome sdrNext = sdr->next; 9355ffb0c9bSToomas Soome morebytes = 1; 9365ffb0c9bSToomas Soome sdr->moreptr = &morebytes; 9375ffb0c9bSToomas Soome switch (sdr->op) 9385ffb0c9bSToomas Soome { 9395ffb0c9bSToomas Soome case resolve_request: 9405ffb0c9bSToomas Soome if (sdr->AppCallback) ((DNSServiceResolveReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, sdr->AppContext); 9415ffb0c9bSToomas Soome break; 9425ffb0c9bSToomas Soome case query_request: 9435ffb0c9bSToomas Soome if (sdr->AppCallback) ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, 0, sdr->AppContext); 9445ffb0c9bSToomas Soome break; 9455ffb0c9bSToomas Soome case addrinfo_request: 9465ffb0c9bSToomas Soome if (sdr->AppCallback) ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, NULL, 0, sdr->AppContext); 9475ffb0c9bSToomas Soome break; 9485ffb0c9bSToomas Soome case browse_request: 9495ffb0c9bSToomas Soome if (sdr->AppCallback) ((DNSServiceBrowseReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, NULL, sdr->AppContext); 9505ffb0c9bSToomas Soome break; 9515ffb0c9bSToomas Soome case reg_service_request: 9525ffb0c9bSToomas Soome if (sdr->AppCallback) ((DNSServiceRegisterReply) sdr->AppCallback)(sdr, 0, error, NULL, 0, NULL, sdr->AppContext); 9535ffb0c9bSToomas Soome break; 9545ffb0c9bSToomas Soome case enumeration_request: 9555ffb0c9bSToomas Soome if (sdr->AppCallback) ((DNSServiceDomainEnumReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, sdr->AppContext); 9565ffb0c9bSToomas Soome break; 9575ffb0c9bSToomas Soome case connection_request: 9585ffb0c9bSToomas Soome case connection_delegate_request: 9595ffb0c9bSToomas Soome // This means Register Record, walk the list of DNSRecords to do the callback 9605ffb0c9bSToomas Soome rec = sdr->rec; 9615ffb0c9bSToomas Soome while (rec) 9625ffb0c9bSToomas Soome { 9635ffb0c9bSToomas Soome recnext = rec->recnext; 9645ffb0c9bSToomas Soome if (rec->AppCallback) ((DNSServiceRegisterRecordReply)rec->AppCallback)(sdr, 0, 0, error, rec->AppContext); 9655ffb0c9bSToomas Soome // The Callback can call DNSServiceRefDeallocate which in turn frees sdr and all the records. 9665ffb0c9bSToomas Soome // Detect that and return early 9675ffb0c9bSToomas Soome if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:Record: CallbackwithError morebytes zero"); return;} 9685ffb0c9bSToomas Soome rec = recnext; 9695ffb0c9bSToomas Soome } 9705ffb0c9bSToomas Soome break; 9715ffb0c9bSToomas Soome case port_mapping_request: 9725ffb0c9bSToomas Soome if (sdr->AppCallback) ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, 0, 0, error, 0, 0, 0, 0, 0, sdr->AppContext); 9735ffb0c9bSToomas Soome break; 9745ffb0c9bSToomas Soome default: 9755ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub CallbackWithError called with bad op %d", sdr->op); 9765ffb0c9bSToomas Soome } 9775ffb0c9bSToomas Soome // If DNSServiceRefDeallocate was called in the callback, morebytes will be zero. As the sdRef 9785ffb0c9bSToomas Soome // (and its subordinates) have been freed, we should not proceed further. Note that when we 9795ffb0c9bSToomas Soome // call the callback with a subordinate sdRef the application can call DNSServiceRefDeallocate 9805ffb0c9bSToomas Soome // on the main sdRef and DNSServiceRefDeallocate handles this case by walking all the sdRefs and 9815ffb0c9bSToomas Soome // clears the moreptr so that we can terminate here. 9825ffb0c9bSToomas Soome // 9835ffb0c9bSToomas Soome // If DNSServiceRefDeallocate was not called in the callback, then set moreptr to NULL so that 9845ffb0c9bSToomas Soome // we don't access the stack variable after we return from this function. 9855ffb0c9bSToomas Soome if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:sdRef: CallbackwithError morebytes zero sdr %p", sdr); return;} 9865ffb0c9bSToomas Soome else {sdr->moreptr = NULL;} 9875ffb0c9bSToomas Soome sdr = sdrNext; 9884b22b933Srs } 9895ffb0c9bSToomas Soome } 9905ffb0c9bSToomas Soome #endif // _DNS_SD_LIBDISPATCH 9914b22b933Srs 9925ffb0c9bSToomas Soome // Handle reply from server, calling application client callback. If there is no reply 9934b22b933Srs // from the daemon on the socket contained in sdRef, the call will block. 9944b22b933Srs DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef) 9955ffb0c9bSToomas Soome { 9965ffb0c9bSToomas Soome int morebytes = 0; 9975ffb0c9bSToomas Soome 9985ffb0c9bSToomas Soome if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; } 9995ffb0c9bSToomas Soome 10005ffb0c9bSToomas Soome if (!DNSServiceRefValid(sdRef)) 10014b22b933Srs { 10025ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator); 10035ffb0c9bSToomas Soome return kDNSServiceErr_BadReference; 10045ffb0c9bSToomas Soome } 10054b22b933Srs 10065ffb0c9bSToomas Soome if (sdRef->primary) 10075ffb0c9bSToomas Soome { 10085ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef); 10094b22b933Srs return kDNSServiceErr_BadReference; 10105ffb0c9bSToomas Soome } 10114b22b933Srs 10125ffb0c9bSToomas Soome if (!sdRef->ProcessReply) 10135ffb0c9bSToomas Soome { 10145ffb0c9bSToomas Soome static int num_logs = 0; 10155ffb0c9bSToomas Soome if (num_logs < 10) syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function"); 10165ffb0c9bSToomas Soome if (num_logs < 1000) num_logs++;else sleep(1); 10175ffb0c9bSToomas Soome return kDNSServiceErr_BadReference; 10184b22b933Srs } 10194b22b933Srs 10205ffb0c9bSToomas Soome do 10215ffb0c9bSToomas Soome { 10225ffb0c9bSToomas Soome CallbackHeader cbh; 10235ffb0c9bSToomas Soome char *data; 10245ffb0c9bSToomas Soome 10255ffb0c9bSToomas Soome // return NoError on EWOULDBLOCK. This will handle the case 10265ffb0c9bSToomas Soome // where a non-blocking socket is told there is data, but it was a false positive. 10275ffb0c9bSToomas Soome // On error, read_all will write a message to syslog for us, so don't need to duplicate that here 10285ffb0c9bSToomas Soome // Note: If we want to properly support using non-blocking sockets in the future 10295ffb0c9bSToomas Soome int result = read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr)); 10305ffb0c9bSToomas Soome if (result == read_all_fail) 10315ffb0c9bSToomas Soome { 10325ffb0c9bSToomas Soome // Set the ProcessReply to NULL before callback as the sdRef can get deallocated 10335ffb0c9bSToomas Soome // in the callback. 10345ffb0c9bSToomas Soome sdRef->ProcessReply = NULL; 10355ffb0c9bSToomas Soome #if _DNS_SD_LIBDISPATCH 10365ffb0c9bSToomas Soome // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult 10375ffb0c9bSToomas Soome // is not called by the application and hence need to communicate the error. Cancel the 10385ffb0c9bSToomas Soome // source so that we don't get any more events 10395ffb0c9bSToomas Soome // Note: read_all fails if we could not read from the daemon which can happen if the 10405ffb0c9bSToomas Soome // daemon dies or the file descriptor is disconnected (defunct). 10415ffb0c9bSToomas Soome if (sdRef->disp_source) 10425ffb0c9bSToomas Soome { 10435ffb0c9bSToomas Soome dispatch_source_cancel(sdRef->disp_source); 10445ffb0c9bSToomas Soome dispatch_release(sdRef->disp_source); 10455ffb0c9bSToomas Soome sdRef->disp_source = NULL; 10465ffb0c9bSToomas Soome CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning); 10475ffb0c9bSToomas Soome } 10485ffb0c9bSToomas Soome #endif 10495ffb0c9bSToomas Soome // Don't touch sdRef anymore as it might have been deallocated 10505ffb0c9bSToomas Soome return kDNSServiceErr_ServiceNotRunning; 10515ffb0c9bSToomas Soome } 10525ffb0c9bSToomas Soome else if (result == read_all_wouldblock) 10535ffb0c9bSToomas Soome { 10545ffb0c9bSToomas Soome if (morebytes && sdRef->logcounter < 100) 10555ffb0c9bSToomas Soome { 10565ffb0c9bSToomas Soome sdRef->logcounter++; 10575ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult error: select indicated data was waiting but read_all returned EWOULDBLOCK"); 10585ffb0c9bSToomas Soome } 10595ffb0c9bSToomas Soome return kDNSServiceErr_NoError; 10605ffb0c9bSToomas Soome } 10615ffb0c9bSToomas Soome 10625ffb0c9bSToomas Soome ConvertHeaderBytes(&cbh.ipc_hdr); 10635ffb0c9bSToomas Soome if (cbh.ipc_hdr.version != VERSION) 10645ffb0c9bSToomas Soome { 10655ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult daemon version %d does not match client version %d", cbh.ipc_hdr.version, VERSION); 10665ffb0c9bSToomas Soome sdRef->ProcessReply = NULL; 10675ffb0c9bSToomas Soome return kDNSServiceErr_Incompatible; 10685ffb0c9bSToomas Soome } 10695ffb0c9bSToomas Soome 10705ffb0c9bSToomas Soome data = malloc(cbh.ipc_hdr.datalen); 10715ffb0c9bSToomas Soome if (!data) return kDNSServiceErr_NoMemory; 10725ffb0c9bSToomas Soome if (read_all(sdRef->sockfd, data, cbh.ipc_hdr.datalen) < 0) // On error, read_all will write a message to syslog for us 10735ffb0c9bSToomas Soome { 10745ffb0c9bSToomas Soome // Set the ProcessReply to NULL before callback as the sdRef can get deallocated 10755ffb0c9bSToomas Soome // in the callback. 10765ffb0c9bSToomas Soome sdRef->ProcessReply = NULL; 10775ffb0c9bSToomas Soome #if _DNS_SD_LIBDISPATCH 10785ffb0c9bSToomas Soome // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult 10795ffb0c9bSToomas Soome // is not called by the application and hence need to communicate the error. Cancel the 10805ffb0c9bSToomas Soome // source so that we don't get any more events 10815ffb0c9bSToomas Soome if (sdRef->disp_source) 10825ffb0c9bSToomas Soome { 10835ffb0c9bSToomas Soome dispatch_source_cancel(sdRef->disp_source); 10845ffb0c9bSToomas Soome dispatch_release(sdRef->disp_source); 10855ffb0c9bSToomas Soome sdRef->disp_source = NULL; 10865ffb0c9bSToomas Soome CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning); 10875ffb0c9bSToomas Soome } 10885ffb0c9bSToomas Soome #endif 10895ffb0c9bSToomas Soome // Don't touch sdRef anymore as it might have been deallocated 10905ffb0c9bSToomas Soome free(data); 10915ffb0c9bSToomas Soome return kDNSServiceErr_ServiceNotRunning; 10925ffb0c9bSToomas Soome } 10935ffb0c9bSToomas Soome else 10945ffb0c9bSToomas Soome { 10955ffb0c9bSToomas Soome const char *ptr = data; 10965ffb0c9bSToomas Soome cbh.cb_flags = get_flags (&ptr, data + cbh.ipc_hdr.datalen); 10975ffb0c9bSToomas Soome cbh.cb_interface = get_uint32 (&ptr, data + cbh.ipc_hdr.datalen); 10985ffb0c9bSToomas Soome cbh.cb_err = get_error_code(&ptr, data + cbh.ipc_hdr.datalen); 10995ffb0c9bSToomas Soome 11005ffb0c9bSToomas Soome // CAUTION: We have to handle the case where the client calls DNSServiceRefDeallocate from within the callback function. 11015ffb0c9bSToomas Soome // To do this we set moreptr to point to morebytes. If the client does call DNSServiceRefDeallocate(), 11025ffb0c9bSToomas Soome // then that routine will clear morebytes for us, and cause us to exit our loop. 11035ffb0c9bSToomas Soome morebytes = more_bytes(sdRef->sockfd); 11045ffb0c9bSToomas Soome if (morebytes) 11055ffb0c9bSToomas Soome { 11065ffb0c9bSToomas Soome cbh.cb_flags |= kDNSServiceFlagsMoreComing; 11075ffb0c9bSToomas Soome sdRef->moreptr = &morebytes; 11085ffb0c9bSToomas Soome } 11095ffb0c9bSToomas Soome if (ptr) sdRef->ProcessReply(sdRef, &cbh, ptr, data + cbh.ipc_hdr.datalen); 11105ffb0c9bSToomas Soome // Careful code here: 11115ffb0c9bSToomas Soome // If morebytes is non-zero, that means we set sdRef->moreptr above, and the operation was not 11125ffb0c9bSToomas Soome // cancelled out from under us, so now we need to clear sdRef->moreptr so we don't leave a stray 11135ffb0c9bSToomas Soome // dangling pointer pointing to a long-gone stack variable. 11145ffb0c9bSToomas Soome // If morebytes is zero, then one of two thing happened: 11155ffb0c9bSToomas Soome // (a) morebytes was 0 above, so we didn't set sdRef->moreptr, so we don't need to clear it 11165ffb0c9bSToomas Soome // (b) morebytes was 1 above, and we set sdRef->moreptr, but the operation was cancelled (with DNSServiceRefDeallocate()), 11175ffb0c9bSToomas Soome // so we MUST NOT try to dereference our stale sdRef pointer. 11185ffb0c9bSToomas Soome if (morebytes) sdRef->moreptr = NULL; 11195ffb0c9bSToomas Soome } 11205ffb0c9bSToomas Soome free(data); 11215ffb0c9bSToomas Soome } while (morebytes); 11225ffb0c9bSToomas Soome 11235ffb0c9bSToomas Soome return kDNSServiceErr_NoError; 11245ffb0c9bSToomas Soome } 11255ffb0c9bSToomas Soome 11264b22b933Srs void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef) 11275ffb0c9bSToomas Soome { 11285ffb0c9bSToomas Soome if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with NULL DNSServiceRef"); return; } 11295ffb0c9bSToomas Soome 11305ffb0c9bSToomas Soome if (!DNSServiceRefValid(sdRef)) // Also verifies dnssd_SocketValid(sdRef->sockfd) for us too 11315ffb0c9bSToomas Soome { 11325ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator); 11335ffb0c9bSToomas Soome return; 11345ffb0c9bSToomas Soome } 11355ffb0c9bSToomas Soome 11365ffb0c9bSToomas Soome // 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 11375ffb0c9bSToomas Soome if (sdRef->moreptr) *(sdRef->moreptr) = 0; 11385ffb0c9bSToomas Soome 11395ffb0c9bSToomas Soome if (sdRef->primary) // If this is a subordinate DNSServiceOp, just send a 'stop' command 11405ffb0c9bSToomas Soome { 11415ffb0c9bSToomas Soome DNSServiceOp **p = &sdRef->primary->next; 11425ffb0c9bSToomas Soome while (*p && *p != sdRef) p = &(*p)->next; 11435ffb0c9bSToomas Soome if (*p) 11445ffb0c9bSToomas Soome { 11455ffb0c9bSToomas Soome char *ptr; 11465ffb0c9bSToomas Soome size_t len = 0; 11475ffb0c9bSToomas Soome ipc_msg_hdr *hdr = create_hdr(cancel_request, &len, &ptr, 0, sdRef); 11485ffb0c9bSToomas Soome if (hdr) 11495ffb0c9bSToomas Soome { 11505ffb0c9bSToomas Soome ConvertHeaderBytes(hdr); 11515ffb0c9bSToomas Soome write_all(sdRef->sockfd, (char *)hdr, len); 11525ffb0c9bSToomas Soome free(hdr); 11535ffb0c9bSToomas Soome } 11545ffb0c9bSToomas Soome *p = sdRef->next; 11555ffb0c9bSToomas Soome FreeDNSServiceOp(sdRef); 11565ffb0c9bSToomas Soome } 11575ffb0c9bSToomas Soome } 11585ffb0c9bSToomas Soome else // else, make sure to terminate all subordinates as well 11595ffb0c9bSToomas Soome { 11605ffb0c9bSToomas Soome #if _DNS_SD_LIBDISPATCH 11615ffb0c9bSToomas Soome // The cancel handler will close the fd if a dispatch source has been set 11625ffb0c9bSToomas Soome if (sdRef->disp_source) 11635ffb0c9bSToomas Soome { 11645ffb0c9bSToomas Soome // By setting the ProcessReply to NULL, we make sure that we never call 11655ffb0c9bSToomas Soome // the application callbacks ever, after returning from this function. We 11665ffb0c9bSToomas Soome // assume that DNSServiceRefDeallocate is called from the serial queue 11675ffb0c9bSToomas Soome // that was passed to DNSServiceSetDispatchQueue. Hence, dispatch_source_cancel 11685ffb0c9bSToomas Soome // should cancel all the blocks on the queue and hence there should be no more 11695ffb0c9bSToomas Soome // callbacks when we return from this function. Setting ProcessReply to NULL 11705ffb0c9bSToomas Soome // provides extra protection. 11715ffb0c9bSToomas Soome sdRef->ProcessReply = NULL; 11725ffb0c9bSToomas Soome shutdown(sdRef->sockfd, SHUT_WR); 11735ffb0c9bSToomas Soome dispatch_source_cancel(sdRef->disp_source); 11745ffb0c9bSToomas Soome dispatch_release(sdRef->disp_source); 11755ffb0c9bSToomas Soome sdRef->disp_source = NULL; 11765ffb0c9bSToomas Soome } 11775ffb0c9bSToomas Soome // if disp_queue is set, it means it used the DNSServiceSetDispatchQueue API. In that case, 11785ffb0c9bSToomas Soome // when the source was cancelled, the fd was closed in the handler. Currently the source 11795ffb0c9bSToomas Soome // is cancelled only when the mDNSResponder daemon dies 11805ffb0c9bSToomas Soome else if (!sdRef->disp_queue) dnssd_close(sdRef->sockfd); 11815ffb0c9bSToomas Soome #else 11825ffb0c9bSToomas Soome dnssd_close(sdRef->sockfd); 11835ffb0c9bSToomas Soome #endif 11845ffb0c9bSToomas Soome // Free DNSRecords added in DNSRegisterRecord if they have not 11855ffb0c9bSToomas Soome // been freed in DNSRemoveRecord 11865ffb0c9bSToomas Soome while (sdRef) 11875ffb0c9bSToomas Soome { 11885ffb0c9bSToomas Soome DNSServiceOp *p = sdRef; 11895ffb0c9bSToomas Soome sdRef = sdRef->next; 11905ffb0c9bSToomas Soome // When there is an error reading from the daemon e.g., bad fd, CallbackWithError 11915ffb0c9bSToomas Soome // is called which sets moreptr. It might set the moreptr on a subordinate sdRef 11925ffb0c9bSToomas Soome // but the application might call DNSServiceRefDeallocate with the main sdRef from 11935ffb0c9bSToomas Soome // the callback. Hence, when we loop through the subordinate sdRefs, we need 11945ffb0c9bSToomas Soome // to clear the moreptr so that CallbackWithError can terminate itself instead of 11955ffb0c9bSToomas Soome // walking through the freed sdRefs. 11965ffb0c9bSToomas Soome if (p->moreptr) *(p->moreptr) = 0; 11975ffb0c9bSToomas Soome FreeDNSServiceOp(p); 11985ffb0c9bSToomas Soome } 11995ffb0c9bSToomas Soome } 12005ffb0c9bSToomas Soome } 12015ffb0c9bSToomas Soome 12025ffb0c9bSToomas Soome DNSServiceErrorType DNSSD_API DNSServiceGetProperty(const char *property, void *result, uint32_t *size) 12035ffb0c9bSToomas Soome { 1204c65ebfc7SToomas Soome DNSServiceErrorType err; 12055ffb0c9bSToomas Soome char *ptr; 1206c65ebfc7SToomas Soome size_t len; 12075ffb0c9bSToomas Soome ipc_msg_hdr *hdr; 12085ffb0c9bSToomas Soome DNSServiceOp *tmp; 12095ffb0c9bSToomas Soome uint32_t actualsize; 12105ffb0c9bSToomas Soome 1211c65ebfc7SToomas Soome if (!property || !result || !size) 1212c65ebfc7SToomas Soome return kDNSServiceErr_BadParam; 1213c65ebfc7SToomas Soome 1214c65ebfc7SToomas Soome len = strlen(property) + 1; 1215c65ebfc7SToomas Soome err = ConnectToServer(&tmp, 0, getproperty_request, NULL, NULL, NULL); 12165ffb0c9bSToomas Soome if (err) return err; 12175ffb0c9bSToomas Soome 12185ffb0c9bSToomas Soome hdr = create_hdr(getproperty_request, &len, &ptr, 0, tmp); 12195ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; } 12205ffb0c9bSToomas Soome 12215ffb0c9bSToomas Soome put_string(property, &ptr); 12225ffb0c9bSToomas Soome err = deliver_request(hdr, tmp); // Will free hdr for us 1223cda73f64SToomas Soome if (err) { DNSServiceRefDeallocate(tmp); return err; } 1224cda73f64SToomas Soome 12255ffb0c9bSToomas Soome if (read_all(tmp->sockfd, (char*)&actualsize, (int)sizeof(actualsize)) < 0) 12265ffb0c9bSToomas Soome { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; } 12275ffb0c9bSToomas Soome 12285ffb0c9bSToomas Soome actualsize = ntohl(actualsize); 12295ffb0c9bSToomas Soome if (read_all(tmp->sockfd, (char*)result, actualsize < *size ? actualsize : *size) < 0) 12305ffb0c9bSToomas Soome { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; } 12315ffb0c9bSToomas Soome DNSServiceRefDeallocate(tmp); 12325ffb0c9bSToomas Soome 12335ffb0c9bSToomas Soome // Swap version result back to local process byte order 12345ffb0c9bSToomas Soome if (!strcmp(property, kDNSServiceProperty_DaemonVersion) && *size >= 4) 12355ffb0c9bSToomas Soome *(uint32_t*)result = ntohl(*(uint32_t*)result); 12365ffb0c9bSToomas Soome 12375ffb0c9bSToomas Soome *size = actualsize; 12385ffb0c9bSToomas Soome return kDNSServiceErr_NoError; 12395ffb0c9bSToomas Soome } 12405ffb0c9bSToomas Soome 12415ffb0c9bSToomas Soome DNSServiceErrorType DNSSD_API DNSServiceGetPID(const uint16_t srcport, int32_t *pid) 12425ffb0c9bSToomas Soome { 12435ffb0c9bSToomas Soome char *ptr; 12445ffb0c9bSToomas Soome ipc_msg_hdr *hdr; 1245c65ebfc7SToomas Soome DNSServiceOp *tmp = NULL; 12465ffb0c9bSToomas Soome size_t len = sizeof(int32_t); 12475ffb0c9bSToomas Soome 12485ffb0c9bSToomas Soome DNSServiceErrorType err = ConnectToServer(&tmp, 0, getpid_request, NULL, NULL, NULL); 1249cda73f64SToomas Soome if (err) return err; 12505ffb0c9bSToomas Soome 12515ffb0c9bSToomas Soome hdr = create_hdr(getpid_request, &len, &ptr, 0, tmp); 1252cda73f64SToomas Soome if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; } 12534b22b933Srs 12545ffb0c9bSToomas Soome put_uint16(srcport, &ptr); 12555ffb0c9bSToomas Soome err = deliver_request(hdr, tmp); // Will free hdr for us 1256cda73f64SToomas Soome if (err) { DNSServiceRefDeallocate(tmp); return err; } 12575ffb0c9bSToomas Soome 12585ffb0c9bSToomas Soome if (read_all(tmp->sockfd, (char*)pid, sizeof(int32_t)) < 0) 1259cda73f64SToomas Soome { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; } 12605ffb0c9bSToomas Soome 12615ffb0c9bSToomas Soome DNSServiceRefDeallocate(tmp); 12625ffb0c9bSToomas Soome return kDNSServiceErr_NoError; 12635ffb0c9bSToomas Soome } 12645ffb0c9bSToomas Soome 12655ffb0c9bSToomas Soome static void handle_resolve_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *end) 12665ffb0c9bSToomas Soome { 12674b22b933Srs char fullname[kDNSServiceMaxDomainName]; 12684b22b933Srs char target[kDNSServiceMaxDomainName]; 12694b22b933Srs uint16_t txtlen; 12704b22b933Srs union { uint16_t s; u_char b[2]; } port; 12714b22b933Srs unsigned char *txtrecord; 12725ffb0c9bSToomas Soome 12735ffb0c9bSToomas Soome get_string(&data, end, fullname, kDNSServiceMaxDomainName); 12745ffb0c9bSToomas Soome get_string(&data, end, target, kDNSServiceMaxDomainName); 12755ffb0c9bSToomas Soome if (!data || data + 2 > end) goto fail; 12765ffb0c9bSToomas Soome 12774b22b933Srs port.b[0] = *data++; 12784b22b933Srs port.b[1] = *data++; 12795ffb0c9bSToomas Soome txtlen = get_uint16(&data, end); 12805ffb0c9bSToomas Soome txtrecord = (unsigned char *)get_rdata(&data, end, txtlen); 12814b22b933Srs 12825ffb0c9bSToomas Soome if (!data) goto fail; 12835ffb0c9bSToomas Soome ((DNSServiceResolveReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, fullname, target, port.s, txtlen, txtrecord, sdr->AppContext); 12845ffb0c9bSToomas Soome return; 12855ffb0c9bSToomas Soome // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 12865ffb0c9bSToomas Soome fail: 12875ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub handle_resolve_response: error reading result from daemon"); 12885ffb0c9bSToomas Soome } 12895ffb0c9bSToomas Soome 12905ffb0c9bSToomas Soome #if TARGET_OS_EMBEDDED 12915ffb0c9bSToomas Soome 12925ffb0c9bSToomas Soome static int32_t libSystemVersion = 0; 12935ffb0c9bSToomas Soome 12945ffb0c9bSToomas Soome // Return true if the iOS application linked against a version of libsystem where P2P 12955ffb0c9bSToomas Soome // interfaces were included by default when using kDNSServiceInterfaceIndexAny. 12965ffb0c9bSToomas Soome // Using 160.0.0 == 0xa00000 as the version threshold. 12975ffb0c9bSToomas Soome static int includeP2PWithIndexAny() 12985ffb0c9bSToomas Soome { 12995ffb0c9bSToomas Soome if (libSystemVersion == 0) 13005ffb0c9bSToomas Soome libSystemVersion = NSVersionOfLinkTimeLibrary("System"); 13015ffb0c9bSToomas Soome 13025ffb0c9bSToomas Soome if (libSystemVersion < 0xa00000) 13035ffb0c9bSToomas Soome return 1; 13045ffb0c9bSToomas Soome else 13055ffb0c9bSToomas Soome return 0; 13065ffb0c9bSToomas Soome } 13075ffb0c9bSToomas Soome 13085ffb0c9bSToomas Soome #else // TARGET_OS_EMBEDDED 13095ffb0c9bSToomas Soome 13105ffb0c9bSToomas Soome // always return false for non iOS platforms 13115ffb0c9bSToomas Soome static int includeP2PWithIndexAny() 13125ffb0c9bSToomas Soome { 13135ffb0c9bSToomas Soome return 0; 13145ffb0c9bSToomas Soome } 13155ffb0c9bSToomas Soome 13165ffb0c9bSToomas Soome #endif // TARGET_OS_EMBEDDED 13174b22b933Srs 13184b22b933Srs DNSServiceErrorType DNSSD_API DNSServiceResolve 13195ffb0c9bSToomas Soome ( 13205ffb0c9bSToomas Soome DNSServiceRef *sdRef, 13215ffb0c9bSToomas Soome DNSServiceFlags flags, 13225ffb0c9bSToomas Soome uint32_t interfaceIndex, 13235ffb0c9bSToomas Soome const char *name, 13245ffb0c9bSToomas Soome const char *regtype, 13255ffb0c9bSToomas Soome const char *domain, 13265ffb0c9bSToomas Soome DNSServiceResolveReply callBack, 13275ffb0c9bSToomas Soome void *context 13285ffb0c9bSToomas Soome ) 13295ffb0c9bSToomas Soome { 13305ffb0c9bSToomas Soome char *ptr; 13314b22b933Srs size_t len; 13324b22b933Srs ipc_msg_hdr *hdr; 13334b22b933Srs DNSServiceErrorType err; 13344b22b933Srs 1335c65ebfc7SToomas Soome if (!sdRef || !name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam; 13365ffb0c9bSToomas Soome 13375ffb0c9bSToomas Soome // Need a real InterfaceID for WakeOnResolve 13385ffb0c9bSToomas Soome if ((flags & kDNSServiceFlagsWakeOnResolve) != 0 && 13395ffb0c9bSToomas Soome ((interfaceIndex == kDNSServiceInterfaceIndexAny) || 13405ffb0c9bSToomas Soome (interfaceIndex == kDNSServiceInterfaceIndexLocalOnly) || 13415ffb0c9bSToomas Soome (interfaceIndex == kDNSServiceInterfaceIndexUnicast) || 1342c65ebfc7SToomas Soome (interfaceIndex == kDNSServiceInterfaceIndexP2P) || 1343c65ebfc7SToomas Soome (interfaceIndex == kDNSServiceInterfaceIndexBLE))) 13445ffb0c9bSToomas Soome { 13455ffb0c9bSToomas Soome return kDNSServiceErr_BadParam; 13465ffb0c9bSToomas Soome } 13475ffb0c9bSToomas Soome 13485ffb0c9bSToomas Soome if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny()) 13495ffb0c9bSToomas Soome flags |= kDNSServiceFlagsIncludeP2P; 13504b22b933Srs 1351*3b436d06SToomas Soome err = ConnectToServer(sdRef, flags, resolve_request, handle_resolve_response, (void *)callBack, context); 13525ffb0c9bSToomas Soome if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 13534b22b933Srs 13545ffb0c9bSToomas Soome // Calculate total message length 13554b22b933Srs len = sizeof(flags); 13564b22b933Srs len += sizeof(interfaceIndex); 13574b22b933Srs len += strlen(name) + 1; 13584b22b933Srs len += strlen(regtype) + 1; 13594b22b933Srs len += strlen(domain) + 1; 13604b22b933Srs 13615ffb0c9bSToomas Soome hdr = create_hdr(resolve_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); 13625ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 13634b22b933Srs 13644b22b933Srs put_flags(flags, &ptr); 13655ffb0c9bSToomas Soome put_uint32(interfaceIndex, &ptr); 13664b22b933Srs put_string(name, &ptr); 13674b22b933Srs put_string(regtype, &ptr); 13684b22b933Srs put_string(domain, &ptr); 13694b22b933Srs 13705ffb0c9bSToomas Soome err = deliver_request(hdr, *sdRef); // Will free hdr for us 13715ffb0c9bSToomas Soome if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 13724b22b933Srs return err; 13735ffb0c9bSToomas Soome } 13744b22b933Srs 13755ffb0c9bSToomas Soome static void handle_query_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) 13765ffb0c9bSToomas Soome { 13775ffb0c9bSToomas Soome uint32_t ttl; 13784b22b933Srs char name[kDNSServiceMaxDomainName]; 13794b22b933Srs uint16_t rrtype, rrclass, rdlen; 13805ffb0c9bSToomas Soome const char *rdata; 13815ffb0c9bSToomas Soome 13825ffb0c9bSToomas Soome get_string(&data, end, name, kDNSServiceMaxDomainName); 13835ffb0c9bSToomas Soome rrtype = get_uint16(&data, end); 13845ffb0c9bSToomas Soome rrclass = get_uint16(&data, end); 13855ffb0c9bSToomas Soome rdlen = get_uint16(&data, end); 13865ffb0c9bSToomas Soome rdata = get_rdata(&data, end, rdlen); 13875ffb0c9bSToomas Soome ttl = get_uint32(&data, end); 13885ffb0c9bSToomas Soome 13895ffb0c9bSToomas Soome if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_query_response: error reading result from daemon"); 13905ffb0c9bSToomas Soome else ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, name, rrtype, rrclass, rdlen, rdata, ttl, sdr->AppContext); 13915ffb0c9bSToomas Soome // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 13925ffb0c9bSToomas Soome } 13934b22b933Srs 13944b22b933Srs DNSServiceErrorType DNSSD_API DNSServiceQueryRecord 13955ffb0c9bSToomas Soome ( 13964b22b933Srs DNSServiceRef *sdRef, 13975ffb0c9bSToomas Soome DNSServiceFlags flags, 13985ffb0c9bSToomas Soome uint32_t interfaceIndex, 13994b22b933Srs const char *name, 14005ffb0c9bSToomas Soome uint16_t rrtype, 14015ffb0c9bSToomas Soome uint16_t rrclass, 14025ffb0c9bSToomas Soome DNSServiceQueryRecordReply callBack, 14034b22b933Srs void *context 14045ffb0c9bSToomas Soome ) 14055ffb0c9bSToomas Soome { 14065ffb0c9bSToomas Soome char *ptr; 14074b22b933Srs size_t len; 14084b22b933Srs ipc_msg_hdr *hdr; 14094b22b933Srs DNSServiceErrorType err; 14104b22b933Srs 1411c65ebfc7SToomas Soome // NULL name handled below. 1412c65ebfc7SToomas Soome if (!sdRef || !callBack) return kDNSServiceErr_BadParam; 1413c65ebfc7SToomas Soome 14145ffb0c9bSToomas Soome if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny()) 14155ffb0c9bSToomas Soome flags |= kDNSServiceFlagsIncludeP2P; 14165ffb0c9bSToomas Soome 1417*3b436d06SToomas Soome err = ConnectToServer(sdRef, flags, query_request, handle_query_response, (void *)callBack, context); 14185ffb0c9bSToomas Soome if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 14194b22b933Srs 14204b22b933Srs if (!name) name = "\0"; 14214b22b933Srs 14225ffb0c9bSToomas Soome // Calculate total message length 14234b22b933Srs len = sizeof(flags); 14245ffb0c9bSToomas Soome len += sizeof(uint32_t); // interfaceIndex 14254b22b933Srs len += strlen(name) + 1; 14264b22b933Srs len += 2 * sizeof(uint16_t); // rrtype, rrclass 14274b22b933Srs 14285ffb0c9bSToomas Soome hdr = create_hdr(query_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); 14295ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 14304b22b933Srs 14314b22b933Srs put_flags(flags, &ptr); 14325ffb0c9bSToomas Soome put_uint32(interfaceIndex, &ptr); 14334b22b933Srs put_string(name, &ptr); 14345ffb0c9bSToomas Soome put_uint16(rrtype, &ptr); 14355ffb0c9bSToomas Soome put_uint16(rrclass, &ptr); 14364b22b933Srs 14375ffb0c9bSToomas Soome err = deliver_request(hdr, *sdRef); // Will free hdr for us 14385ffb0c9bSToomas Soome if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 14395ffb0c9bSToomas Soome return err; 14405ffb0c9bSToomas Soome } 14415ffb0c9bSToomas Soome 14425ffb0c9bSToomas Soome static void handle_addrinfo_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) 14435ffb0c9bSToomas Soome { 14445ffb0c9bSToomas Soome char hostname[kDNSServiceMaxDomainName]; 1445cda73f64SToomas Soome uint16_t rrtype, rrclass, rdlen; 14465ffb0c9bSToomas Soome const char *rdata; 14475ffb0c9bSToomas Soome uint32_t ttl; 14485ffb0c9bSToomas Soome 14495ffb0c9bSToomas Soome get_string(&data, end, hostname, kDNSServiceMaxDomainName); 14505ffb0c9bSToomas Soome rrtype = get_uint16(&data, end); 1451cda73f64SToomas Soome rrclass = get_uint16(&data, end); 14525ffb0c9bSToomas Soome rdlen = get_uint16(&data, end); 14535ffb0c9bSToomas Soome rdata = get_rdata (&data, end, rdlen); 14545ffb0c9bSToomas Soome ttl = get_uint32(&data, end); 1455cda73f64SToomas Soome (void)rrclass; // Unused 14565ffb0c9bSToomas Soome 14575ffb0c9bSToomas Soome // We only generate client callbacks for A and AAAA results (including NXDOMAIN results for 14585ffb0c9bSToomas Soome // those types, if the client has requested those with the kDNSServiceFlagsReturnIntermediates). 14595ffb0c9bSToomas Soome // Other result types, specifically CNAME referrals, are not communicated to the client, because 14605ffb0c9bSToomas Soome // the DNSServiceGetAddrInfoReply interface doesn't have any meaningful way to communiate CNAME referrals. 14615ffb0c9bSToomas Soome if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_addrinfo_response: error reading result from daemon"); 14625ffb0c9bSToomas Soome else if (rrtype == kDNSServiceType_A || rrtype == kDNSServiceType_AAAA) 14635ffb0c9bSToomas Soome { 14645ffb0c9bSToomas Soome struct sockaddr_in sa4; 14655ffb0c9bSToomas Soome struct sockaddr_in6 sa6; 14665ffb0c9bSToomas Soome const struct sockaddr *const sa = (rrtype == kDNSServiceType_A) ? (struct sockaddr*)&sa4 : (struct sockaddr*)&sa6; 14675ffb0c9bSToomas Soome if (rrtype == kDNSServiceType_A) 14684b22b933Srs { 14695ffb0c9bSToomas Soome memset(&sa4, 0, sizeof(sa4)); 14705ffb0c9bSToomas Soome #ifndef NOT_HAVE_SA_LEN 14715ffb0c9bSToomas Soome sa4.sin_len = sizeof(struct sockaddr_in); 14725ffb0c9bSToomas Soome #endif 14735ffb0c9bSToomas Soome sa4.sin_family = AF_INET; 14745ffb0c9bSToomas Soome // sin_port = 0; 14755ffb0c9bSToomas Soome if (!cbh->cb_err) memcpy(&sa4.sin_addr, rdata, rdlen); 14765ffb0c9bSToomas Soome } 14775ffb0c9bSToomas Soome else 14785ffb0c9bSToomas Soome { 14795ffb0c9bSToomas Soome memset(&sa6, 0, sizeof(sa6)); 14805ffb0c9bSToomas Soome #ifndef NOT_HAVE_SA_LEN 14815ffb0c9bSToomas Soome sa6.sin6_len = sizeof(struct sockaddr_in6); 14825ffb0c9bSToomas Soome #endif 14835ffb0c9bSToomas Soome sa6.sin6_family = AF_INET6; 14845ffb0c9bSToomas Soome // sin6_port = 0; 14855ffb0c9bSToomas Soome // sin6_flowinfo = 0; 14865ffb0c9bSToomas Soome // sin6_scope_id = 0; 14875ffb0c9bSToomas Soome if (!cbh->cb_err) 14885ffb0c9bSToomas Soome { 14895ffb0c9bSToomas Soome memcpy(&sa6.sin6_addr, rdata, rdlen); 14905ffb0c9bSToomas Soome if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr)) sa6.sin6_scope_id = cbh->cb_interface; 14915ffb0c9bSToomas Soome } 14924b22b933Srs } 14935ffb0c9bSToomas Soome // Validation results are always delivered separately from the actual results of the 14945ffb0c9bSToomas Soome // DNSServiceGetAddrInfo. Set the "addr" to NULL as per the documentation. 14955ffb0c9bSToomas Soome // 14965ffb0c9bSToomas Soome // Note: If we deliver validation results along with the "addr" in the future, we need 14975ffb0c9bSToomas Soome // a way to differentiate the negative response from validation-only response as both 14985ffb0c9bSToomas Soome // has zero address. 14995ffb0c9bSToomas Soome if (!(cbh->cb_flags & kDNSServiceFlagsValidate)) 15005ffb0c9bSToomas Soome ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, sa, ttl, sdr->AppContext); 15015ffb0c9bSToomas Soome else 15025ffb0c9bSToomas Soome ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, NULL, 0, sdr->AppContext); 15035ffb0c9bSToomas Soome // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 15045ffb0c9bSToomas Soome } 15055ffb0c9bSToomas Soome } 15064b22b933Srs 15075ffb0c9bSToomas Soome DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo 15085ffb0c9bSToomas Soome ( 15095ffb0c9bSToomas Soome DNSServiceRef *sdRef, 15105ffb0c9bSToomas Soome DNSServiceFlags flags, 15115ffb0c9bSToomas Soome uint32_t interfaceIndex, 15125ffb0c9bSToomas Soome uint32_t protocol, 15135ffb0c9bSToomas Soome const char *hostname, 15145ffb0c9bSToomas Soome DNSServiceGetAddrInfoReply callBack, 15155ffb0c9bSToomas Soome void *context /* may be NULL */ 15165ffb0c9bSToomas Soome ) 15175ffb0c9bSToomas Soome { 15185ffb0c9bSToomas Soome char *ptr; 15195ffb0c9bSToomas Soome size_t len; 15205ffb0c9bSToomas Soome ipc_msg_hdr *hdr; 15215ffb0c9bSToomas Soome DNSServiceErrorType err; 15224b22b933Srs 1523c65ebfc7SToomas Soome if (!sdRef || !hostname || !callBack) return kDNSServiceErr_BadParam; 15244b22b933Srs 1525*3b436d06SToomas Soome err = ConnectToServer(sdRef, flags, addrinfo_request, handle_addrinfo_response, (void *)callBack, context); 15265ffb0c9bSToomas Soome if (err) 15274b22b933Srs { 15285ffb0c9bSToomas Soome return err; // On error ConnectToServer leaves *sdRef set to NULL 15294b22b933Srs } 15304b22b933Srs 15315ffb0c9bSToomas Soome // Calculate total message length 15325ffb0c9bSToomas Soome len = sizeof(flags); 15335ffb0c9bSToomas Soome len += sizeof(uint32_t); // interfaceIndex 15345ffb0c9bSToomas Soome len += sizeof(uint32_t); // protocol 15355ffb0c9bSToomas Soome len += strlen(hostname) + 1; 15365ffb0c9bSToomas Soome 15375ffb0c9bSToomas Soome hdr = create_hdr(addrinfo_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); 15385ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 15395ffb0c9bSToomas Soome 15405ffb0c9bSToomas Soome put_flags(flags, &ptr); 15415ffb0c9bSToomas Soome put_uint32(interfaceIndex, &ptr); 15425ffb0c9bSToomas Soome put_uint32(protocol, &ptr); 15435ffb0c9bSToomas Soome put_string(hostname, &ptr); 15445ffb0c9bSToomas Soome 15455ffb0c9bSToomas Soome err = deliver_request(hdr, *sdRef); // Will free hdr for us 15465ffb0c9bSToomas Soome if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 15475ffb0c9bSToomas Soome return err; 15485ffb0c9bSToomas Soome } 15495ffb0c9bSToomas Soome 15505ffb0c9bSToomas Soome static void handle_browse_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) 15515ffb0c9bSToomas Soome { 15525ffb0c9bSToomas Soome char replyName[256], replyType[kDNSServiceMaxDomainName], replyDomain[kDNSServiceMaxDomainName]; 15535ffb0c9bSToomas Soome get_string(&data, end, replyName, 256); 15545ffb0c9bSToomas Soome get_string(&data, end, replyType, kDNSServiceMaxDomainName); 15555ffb0c9bSToomas Soome get_string(&data, end, replyDomain, kDNSServiceMaxDomainName); 15565ffb0c9bSToomas Soome if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_browse_response: error reading result from daemon"); 15575ffb0c9bSToomas Soome else ((DNSServiceBrowseReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, replyName, replyType, replyDomain, sdr->AppContext); 15585ffb0c9bSToomas Soome // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 15595ffb0c9bSToomas Soome } 15605ffb0c9bSToomas Soome 15614b22b933Srs DNSServiceErrorType DNSSD_API DNSServiceBrowse 15625ffb0c9bSToomas Soome ( 15635ffb0c9bSToomas Soome DNSServiceRef *sdRef, 15645ffb0c9bSToomas Soome DNSServiceFlags flags, 15655ffb0c9bSToomas Soome uint32_t interfaceIndex, 15665ffb0c9bSToomas Soome const char *regtype, 15675ffb0c9bSToomas Soome const char *domain, 15685ffb0c9bSToomas Soome DNSServiceBrowseReply callBack, 15695ffb0c9bSToomas Soome void *context 15705ffb0c9bSToomas Soome ) 15715ffb0c9bSToomas Soome { 15725ffb0c9bSToomas Soome char *ptr; 15734b22b933Srs size_t len; 15744b22b933Srs ipc_msg_hdr *hdr; 15754b22b933Srs DNSServiceErrorType err; 15764b22b933Srs 1577c65ebfc7SToomas Soome // NULL domain handled below 1578c65ebfc7SToomas Soome if (!sdRef || !regtype || !callBack) return kDNSServiceErr_BadParam; 1579c65ebfc7SToomas Soome 15805ffb0c9bSToomas Soome if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny()) 15815ffb0c9bSToomas Soome flags |= kDNSServiceFlagsIncludeP2P; 15824b22b933Srs 1583*3b436d06SToomas Soome err = ConnectToServer(sdRef, flags, browse_request, handle_browse_response, (void *)callBack, context); 15845ffb0c9bSToomas Soome if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 15854b22b933Srs 15865ffb0c9bSToomas Soome if (!domain) domain = ""; 15874b22b933Srs len = sizeof(flags); 15884b22b933Srs len += sizeof(interfaceIndex); 15894b22b933Srs len += strlen(regtype) + 1; 15904b22b933Srs len += strlen(domain) + 1; 15914b22b933Srs 15925ffb0c9bSToomas Soome hdr = create_hdr(browse_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); 15935ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 15945ffb0c9bSToomas Soome 15954b22b933Srs put_flags(flags, &ptr); 15965ffb0c9bSToomas Soome put_uint32(interfaceIndex, &ptr); 15974b22b933Srs put_string(regtype, &ptr); 15984b22b933Srs put_string(domain, &ptr); 15994b22b933Srs 16005ffb0c9bSToomas Soome err = deliver_request(hdr, *sdRef); // Will free hdr for us 16015ffb0c9bSToomas Soome if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 16024b22b933Srs return err; 16035ffb0c9bSToomas Soome } 16044b22b933Srs 16055ffb0c9bSToomas Soome DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain) 16065ffb0c9bSToomas Soome { 1607c65ebfc7SToomas Soome DNSServiceErrorType err; 16085ffb0c9bSToomas Soome DNSServiceOp *tmp; 16095ffb0c9bSToomas Soome char *ptr; 1610c65ebfc7SToomas Soome size_t len; 16115ffb0c9bSToomas Soome ipc_msg_hdr *hdr; 1612c65ebfc7SToomas Soome 1613c65ebfc7SToomas Soome if (!domain) return kDNSServiceErr_BadParam; 1614c65ebfc7SToomas Soome len = sizeof(flags) + strlen(domain) + 1; 1615c65ebfc7SToomas Soome 1616c65ebfc7SToomas Soome err = ConnectToServer(&tmp, 0, setdomain_request, NULL, NULL, NULL); 16175ffb0c9bSToomas Soome if (err) return err; 16185ffb0c9bSToomas Soome 16195ffb0c9bSToomas Soome hdr = create_hdr(setdomain_request, &len, &ptr, 0, tmp); 16205ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; } 16214b22b933Srs 16224b22b933Srs put_flags(flags, &ptr); 16234b22b933Srs put_string(domain, &ptr); 16245ffb0c9bSToomas Soome err = deliver_request(hdr, tmp); // Will free hdr for us 16255ffb0c9bSToomas Soome DNSServiceRefDeallocate(tmp); 16265ffb0c9bSToomas Soome return err; 16275ffb0c9bSToomas Soome } 16284b22b933Srs 16295ffb0c9bSToomas Soome static void handle_regservice_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) 16305ffb0c9bSToomas Soome { 16314b22b933Srs char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName]; 16325ffb0c9bSToomas Soome get_string(&data, end, name, 256); 16335ffb0c9bSToomas Soome get_string(&data, end, regtype, kDNSServiceMaxDomainName); 16345ffb0c9bSToomas Soome get_string(&data, end, domain, kDNSServiceMaxDomainName); 16355ffb0c9bSToomas Soome if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_regservice_response: error reading result from daemon"); 16365ffb0c9bSToomas Soome else ((DNSServiceRegisterReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_err, name, regtype, domain, sdr->AppContext); 16375ffb0c9bSToomas Soome // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 16385ffb0c9bSToomas Soome } 16394b22b933Srs 16404b22b933Srs DNSServiceErrorType DNSSD_API DNSServiceRegister 16415ffb0c9bSToomas Soome ( 16424b22b933Srs DNSServiceRef *sdRef, 16435ffb0c9bSToomas Soome DNSServiceFlags flags, 16445ffb0c9bSToomas Soome uint32_t interfaceIndex, 16454b22b933Srs const char *name, 16464b22b933Srs const char *regtype, 16474b22b933Srs const char *domain, 16484b22b933Srs const char *host, 16495ffb0c9bSToomas Soome uint16_t PortInNetworkByteOrder, 16505ffb0c9bSToomas Soome uint16_t txtLen, 16514b22b933Srs const void *txtRecord, 16525ffb0c9bSToomas Soome DNSServiceRegisterReply callBack, 16534b22b933Srs void *context 16545ffb0c9bSToomas Soome ) 16555ffb0c9bSToomas Soome { 16565ffb0c9bSToomas Soome char *ptr; 16574b22b933Srs size_t len; 16584b22b933Srs ipc_msg_hdr *hdr; 16594b22b933Srs DNSServiceErrorType err; 16604b22b933Srs union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder }; 16614b22b933Srs 1662c65ebfc7SToomas Soome if (!sdRef || !regtype) return kDNSServiceErr_BadParam; 16634b22b933Srs if (!name) name = ""; 16644b22b933Srs if (!domain) domain = ""; 16654b22b933Srs if (!host) host = ""; 16664b22b933Srs if (!txtRecord) txtRecord = (void*)""; 16674b22b933Srs 16685ffb0c9bSToomas Soome // No callback must have auto-rename 16694b22b933Srs if (!callBack && (flags & kDNSServiceFlagsNoAutoRename)) return kDNSServiceErr_BadParam; 16704b22b933Srs 16715ffb0c9bSToomas Soome if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny()) 16725ffb0c9bSToomas Soome flags |= kDNSServiceFlagsIncludeP2P; 16735ffb0c9bSToomas Soome 1674*3b436d06SToomas Soome err = ConnectToServer(sdRef, flags, reg_service_request, callBack ? handle_regservice_response : NULL, (void *)callBack, context); 16755ffb0c9bSToomas Soome if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 16765ffb0c9bSToomas Soome 16774b22b933Srs len = sizeof(DNSServiceFlags); 16784b22b933Srs len += sizeof(uint32_t); // interfaceIndex 16794b22b933Srs len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4; 16804b22b933Srs len += 2 * sizeof(uint16_t); // port, txtLen 16814b22b933Srs len += txtLen; 16824b22b933Srs 16835ffb0c9bSToomas Soome hdr = create_hdr(reg_service_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); 16845ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 1685cda73f64SToomas Soome if (!callBack) hdr->ipc_flags |= IPC_FLAGS_NOREPLY; 16865ffb0c9bSToomas Soome 16874b22b933Srs put_flags(flags, &ptr); 16885ffb0c9bSToomas Soome put_uint32(interfaceIndex, &ptr); 16894b22b933Srs put_string(name, &ptr); 16904b22b933Srs put_string(regtype, &ptr); 16914b22b933Srs put_string(domain, &ptr); 16924b22b933Srs put_string(host, &ptr); 16934b22b933Srs *ptr++ = port.b[0]; 16944b22b933Srs *ptr++ = port.b[1]; 16955ffb0c9bSToomas Soome put_uint16(txtLen, &ptr); 16964b22b933Srs put_rdata(txtLen, txtRecord, &ptr); 16974b22b933Srs 16985ffb0c9bSToomas Soome err = deliver_request(hdr, *sdRef); // Will free hdr for us 16995ffb0c9bSToomas Soome if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 17004b22b933Srs return err; 17015ffb0c9bSToomas Soome } 17024b22b933Srs 17035ffb0c9bSToomas Soome static void handle_enumeration_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) 17045ffb0c9bSToomas Soome { 17054b22b933Srs char domain[kDNSServiceMaxDomainName]; 17065ffb0c9bSToomas Soome get_string(&data, end, domain, kDNSServiceMaxDomainName); 17075ffb0c9bSToomas Soome if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_enumeration_response: error reading result from daemon"); 17085ffb0c9bSToomas Soome else ((DNSServiceDomainEnumReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, domain, sdr->AppContext); 17095ffb0c9bSToomas Soome // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 17105ffb0c9bSToomas Soome } 17114b22b933Srs 17124b22b933Srs DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains 17135ffb0c9bSToomas Soome ( 17145ffb0c9bSToomas Soome DNSServiceRef *sdRef, 17155ffb0c9bSToomas Soome DNSServiceFlags flags, 17165ffb0c9bSToomas Soome uint32_t interfaceIndex, 17175ffb0c9bSToomas Soome DNSServiceDomainEnumReply callBack, 17185ffb0c9bSToomas Soome void *context 17195ffb0c9bSToomas Soome ) 17205ffb0c9bSToomas Soome { 17215ffb0c9bSToomas Soome char *ptr; 17224b22b933Srs size_t len; 17234b22b933Srs ipc_msg_hdr *hdr; 17244b22b933Srs DNSServiceErrorType err; 1725c65ebfc7SToomas Soome int f1; 1726c65ebfc7SToomas Soome int f2; 17275ffb0c9bSToomas Soome 1728c65ebfc7SToomas Soome if (!sdRef || !callBack) return kDNSServiceErr_BadParam; 1729c65ebfc7SToomas Soome 1730c65ebfc7SToomas Soome f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0; 1731c65ebfc7SToomas Soome f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0; 17324b22b933Srs if (f1 + f2 != 1) return kDNSServiceErr_BadParam; 17334b22b933Srs 1734*3b436d06SToomas Soome err = ConnectToServer(sdRef, flags, enumeration_request, handle_enumeration_response, (void *)callBack, context); 17355ffb0c9bSToomas Soome if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 17364b22b933Srs 17375ffb0c9bSToomas Soome len = sizeof(DNSServiceFlags); 17384b22b933Srs len += sizeof(uint32_t); 17394b22b933Srs 17405ffb0c9bSToomas Soome hdr = create_hdr(enumeration_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); 17415ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 17424b22b933Srs 17434b22b933Srs put_flags(flags, &ptr); 17445ffb0c9bSToomas Soome put_uint32(interfaceIndex, &ptr); 17454b22b933Srs 17465ffb0c9bSToomas Soome err = deliver_request(hdr, *sdRef); // Will free hdr for us 17475ffb0c9bSToomas Soome if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 17485ffb0c9bSToomas Soome return err; 17495ffb0c9bSToomas Soome } 17505ffb0c9bSToomas Soome 17515ffb0c9bSToomas Soome static void ConnectionResponse(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *const data, const char *const end) 17525ffb0c9bSToomas Soome { 17535ffb0c9bSToomas Soome (void)data; // Unused 17545ffb0c9bSToomas Soome 17555ffb0c9bSToomas Soome //printf("ConnectionResponse got %d\n", cbh->ipc_hdr.op); 17565ffb0c9bSToomas Soome if (cbh->ipc_hdr.op != reg_record_reply_op) 17575ffb0c9bSToomas Soome { 17585ffb0c9bSToomas Soome // When using kDNSServiceFlagsShareConnection, need to search the list of associated DNSServiceOps 17595ffb0c9bSToomas Soome // to find the one this response is intended for, and then call through to its ProcessReply handler. 17605ffb0c9bSToomas Soome // We start with our first subordinate DNSServiceRef -- don't want to accidentally match the parent DNSServiceRef. 17615ffb0c9bSToomas Soome DNSServiceOp *op = sdr->next; 17625ffb0c9bSToomas Soome while (op && (op->uid.u32[0] != cbh->ipc_hdr.client_context.u32[0] || op->uid.u32[1] != cbh->ipc_hdr.client_context.u32[1])) 17635ffb0c9bSToomas Soome op = op->next; 17645ffb0c9bSToomas Soome // Note: We may sometimes not find a matching DNSServiceOp, in the case where the client has 17655ffb0c9bSToomas Soome // cancelled the subordinate DNSServiceOp, but there are still messages in the pipeline from the daemon 17665ffb0c9bSToomas Soome if (op && op->ProcessReply) op->ProcessReply(op, cbh, data, end); 17675ffb0c9bSToomas Soome // WARNING: Don't touch op or sdr after this -- client may have called DNSServiceRefDeallocate 17685ffb0c9bSToomas Soome return; 17695ffb0c9bSToomas Soome } 17705ffb0c9bSToomas Soome else 17715ffb0c9bSToomas Soome { 17725ffb0c9bSToomas Soome DNSRecordRef rec; 17735ffb0c9bSToomas Soome for (rec = sdr->rec; rec; rec = rec->recnext) 17744b22b933Srs { 17755ffb0c9bSToomas Soome if (rec->uid.u32[0] == cbh->ipc_hdr.client_context.u32[0] && rec->uid.u32[1] == cbh->ipc_hdr.client_context.u32[1]) 17765ffb0c9bSToomas Soome break; 17775ffb0c9bSToomas Soome } 17785ffb0c9bSToomas Soome // The record might have been freed already and hence not an 17795ffb0c9bSToomas Soome // error if the record is not found. 17805ffb0c9bSToomas Soome if (!rec) 17815ffb0c9bSToomas Soome { 17825ffb0c9bSToomas Soome syslog(LOG_INFO, "ConnectionResponse: Record not found"); 17835ffb0c9bSToomas Soome return; 17845ffb0c9bSToomas Soome } 17855ffb0c9bSToomas Soome if (rec->sdr != sdr) 17865ffb0c9bSToomas Soome { 17875ffb0c9bSToomas Soome syslog(LOG_WARNING, "ConnectionResponse: Record sdr mismatch: rec %p sdr %p", rec->sdr, sdr); 17885ffb0c9bSToomas Soome return; 17894b22b933Srs } 17904b22b933Srs 17915ffb0c9bSToomas Soome if (sdr->op == connection_request || sdr->op == connection_delegate_request) 17925ffb0c9bSToomas Soome { 17935ffb0c9bSToomas Soome rec->AppCallback(rec->sdr, rec, cbh->cb_flags, cbh->cb_err, rec->AppContext); 17945ffb0c9bSToomas Soome } 17955ffb0c9bSToomas Soome else 17965ffb0c9bSToomas Soome { 17975ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub ConnectionResponse: sdr->op != connection_request"); 17985ffb0c9bSToomas Soome rec->AppCallback(rec->sdr, rec, 0, kDNSServiceErr_Unknown, rec->AppContext); 17995ffb0c9bSToomas Soome } 18005ffb0c9bSToomas Soome // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 18015ffb0c9bSToomas Soome } 18025ffb0c9bSToomas Soome } 18035ffb0c9bSToomas Soome 18045ffb0c9bSToomas Soome DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef) 18055ffb0c9bSToomas Soome { 1806c65ebfc7SToomas Soome DNSServiceErrorType err; 18075ffb0c9bSToomas Soome char *ptr; 18085ffb0c9bSToomas Soome size_t len = 0; 18095ffb0c9bSToomas Soome ipc_msg_hdr *hdr; 1810c65ebfc7SToomas Soome 1811c65ebfc7SToomas Soome if (!sdRef) return kDNSServiceErr_BadParam; 1812c65ebfc7SToomas Soome err = ConnectToServer(sdRef, 0, connection_request, ConnectionResponse, NULL, NULL); 18135ffb0c9bSToomas Soome if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 18145ffb0c9bSToomas Soome 18155ffb0c9bSToomas Soome hdr = create_hdr(connection_request, &len, &ptr, 0, *sdRef); 18165ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 18175ffb0c9bSToomas Soome 18185ffb0c9bSToomas Soome err = deliver_request(hdr, *sdRef); // Will free hdr for us 18195ffb0c9bSToomas Soome if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 18204b22b933Srs return err; 18215ffb0c9bSToomas Soome } 18225ffb0c9bSToomas Soome 18235ffb0c9bSToomas Soome #if APPLE_OSX_mDNSResponder && !TARGET_IPHONE_SIMULATOR 18245ffb0c9bSToomas Soome DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid) 18255ffb0c9bSToomas Soome { 18265ffb0c9bSToomas Soome char *ptr; 18275ffb0c9bSToomas Soome size_t len = 0; 18285ffb0c9bSToomas Soome ipc_msg_hdr *hdr; 18294b22b933Srs 1830c65ebfc7SToomas Soome if (!sdRef) return kDNSServiceErr_BadParam; 18315ffb0c9bSToomas Soome DNSServiceErrorType err = ConnectToServer(sdRef, 0, connection_delegate_request, ConnectionResponse, NULL, NULL); 18325ffb0c9bSToomas Soome if (err) 18335ffb0c9bSToomas Soome { 18345ffb0c9bSToomas Soome return err; // On error ConnectToServer leaves *sdRef set to NULL 18354b22b933Srs } 18364b22b933Srs 1837c65ebfc7SToomas Soome // Only one of the two options can be set. If pid is zero, uuid is used. 18385ffb0c9bSToomas Soome // If both are specified only pid will be used. We send across the pid 18395ffb0c9bSToomas Soome // so that the daemon knows what to read from the socket. 18405ffb0c9bSToomas Soome 18415ffb0c9bSToomas Soome len += sizeof(int32_t); 18425ffb0c9bSToomas Soome 18435ffb0c9bSToomas Soome hdr = create_hdr(connection_delegate_request, &len, &ptr, 0, *sdRef); 18445ffb0c9bSToomas Soome if (!hdr) 18454b22b933Srs { 18465ffb0c9bSToomas Soome DNSServiceRefDeallocate(*sdRef); 18475ffb0c9bSToomas Soome *sdRef = NULL; 18485ffb0c9bSToomas Soome return kDNSServiceErr_NoMemory; 18495ffb0c9bSToomas Soome } 18504b22b933Srs 18515ffb0c9bSToomas Soome if (pid && setsockopt((*sdRef)->sockfd, SOL_SOCKET, SO_DELEGATED, &pid, sizeof(pid)) == -1) 1852c65ebfc7SToomas Soome { 1853c65ebfc7SToomas Soome syslog(LOG_WARNING, "dnssdclientstub: Could not setsockopt() for PID[%d], no entitlements or process(pid) invalid errno:%d (%s)", pid, errno, strerror(errno)); 1854c65ebfc7SToomas Soome // Free the hdr in case we return before calling deliver_request() 18555ffb0c9bSToomas Soome if (hdr) 18565ffb0c9bSToomas Soome free(hdr); 18575ffb0c9bSToomas Soome DNSServiceRefDeallocate(*sdRef); 18585ffb0c9bSToomas Soome *sdRef = NULL; 18595ffb0c9bSToomas Soome return kDNSServiceErr_NoAuth; 18605ffb0c9bSToomas Soome } 18614b22b933Srs 18625ffb0c9bSToomas Soome if (!pid && setsockopt((*sdRef)->sockfd, SOL_SOCKET, SO_DELEGATED_UUID, uuid, sizeof(uuid_t)) == -1) 18635ffb0c9bSToomas Soome { 18645ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssdclientstub: Could not setsockopt() for UUID, no entitlements or process(uuid) invalid errno:%d (%s) ", errno, strerror(errno)); 18655ffb0c9bSToomas Soome // Free the hdr in case we return before calling deliver_request() 18665ffb0c9bSToomas Soome if (hdr) 18675ffb0c9bSToomas Soome free(hdr); 18685ffb0c9bSToomas Soome DNSServiceRefDeallocate(*sdRef); 18695ffb0c9bSToomas Soome *sdRef = NULL; 18705ffb0c9bSToomas Soome return kDNSServiceErr_NoAuth; 18714b22b933Srs } 18724b22b933Srs 18735ffb0c9bSToomas Soome put_uint32(pid, &ptr); 18745ffb0c9bSToomas Soome 18755ffb0c9bSToomas Soome err = deliver_request(hdr, *sdRef); // Will free hdr for us 18765ffb0c9bSToomas Soome if (err) 18774b22b933Srs { 18785ffb0c9bSToomas Soome DNSServiceRefDeallocate(*sdRef); 18795ffb0c9bSToomas Soome *sdRef = NULL; 18804b22b933Srs } 18815ffb0c9bSToomas Soome return err; 18825ffb0c9bSToomas Soome } 18835ffb0c9bSToomas Soome #elif TARGET_IPHONE_SIMULATOR // This hack is for Simulator platform only 18845ffb0c9bSToomas Soome DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid) 18855ffb0c9bSToomas Soome { 18865ffb0c9bSToomas Soome (void) pid; 18875ffb0c9bSToomas Soome (void) uuid; 18885ffb0c9bSToomas Soome return DNSServiceCreateConnection(sdRef); 18895ffb0c9bSToomas Soome } 18905ffb0c9bSToomas Soome #endif 18914b22b933Srs 18924b22b933Srs DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord 18935ffb0c9bSToomas Soome ( 18945ffb0c9bSToomas Soome DNSServiceRef sdRef, 18954b22b933Srs DNSRecordRef *RecordRef, 18965ffb0c9bSToomas Soome DNSServiceFlags flags, 18975ffb0c9bSToomas Soome uint32_t interfaceIndex, 18984b22b933Srs const char *fullname, 18995ffb0c9bSToomas Soome uint16_t rrtype, 19005ffb0c9bSToomas Soome uint16_t rrclass, 19015ffb0c9bSToomas Soome uint16_t rdlen, 19024b22b933Srs const void *rdata, 19035ffb0c9bSToomas Soome uint32_t ttl, 19045ffb0c9bSToomas Soome DNSServiceRegisterRecordReply callBack, 19054b22b933Srs void *context 19065ffb0c9bSToomas Soome ) 19075ffb0c9bSToomas Soome { 19085ffb0c9bSToomas Soome char *ptr; 19094b22b933Srs size_t len; 19104b22b933Srs ipc_msg_hdr *hdr = NULL; 19114b22b933Srs DNSRecordRef rref = NULL; 19125ffb0c9bSToomas Soome DNSRecord **p; 19134b22b933Srs int f1 = (flags & kDNSServiceFlagsShared) != 0; 19144b22b933Srs int f2 = (flags & kDNSServiceFlagsUnique) != 0; 19154b22b933Srs if (f1 + f2 != 1) return kDNSServiceErr_BadParam; 19164b22b933Srs 19175ffb0c9bSToomas Soome if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny()) 19185ffb0c9bSToomas Soome flags |= kDNSServiceFlagsIncludeP2P; 19195ffb0c9bSToomas Soome 1920c65ebfc7SToomas Soome if (!sdRef || !RecordRef || !fullname || (!rdata && rdlen) || !callBack) 1921c65ebfc7SToomas Soome { 1922c65ebfc7SToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with NULL parameter"); 1923c65ebfc7SToomas Soome return kDNSServiceErr_BadParam; 1924c65ebfc7SToomas Soome } 19255ffb0c9bSToomas Soome 19265ffb0c9bSToomas Soome if (!DNSServiceRefValid(sdRef)) 19275ffb0c9bSToomas Soome { 19285ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator); 19295ffb0c9bSToomas Soome return kDNSServiceErr_BadReference; 19305ffb0c9bSToomas Soome } 19315ffb0c9bSToomas Soome 19325ffb0c9bSToomas Soome if (sdRef->op != connection_request && sdRef->op != connection_delegate_request) 19335ffb0c9bSToomas Soome { 19345ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with non-DNSServiceCreateConnection DNSServiceRef %p %d", sdRef, sdRef->op); 19354b22b933Srs return kDNSServiceErr_BadReference; 19365ffb0c9bSToomas Soome } 19375ffb0c9bSToomas Soome 19384b22b933Srs *RecordRef = NULL; 19394b22b933Srs 19405ffb0c9bSToomas Soome len = sizeof(DNSServiceFlags); 19414b22b933Srs len += 2 * sizeof(uint32_t); // interfaceIndex, ttl 19424b22b933Srs len += 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen 19434b22b933Srs len += strlen(fullname) + 1; 19444b22b933Srs len += rdlen; 19454b22b933Srs 19465ffb0c9bSToomas Soome // Bump up the uid. Normally for shared operations (kDNSServiceFlagsShareConnection), this 19475ffb0c9bSToomas Soome // is done in ConnectToServer. For DNSServiceRegisterRecord, ConnectToServer has already 19485ffb0c9bSToomas Soome // been called. As multiple DNSServiceRegisterRecords can be multiplexed over a single 19495ffb0c9bSToomas Soome // connection, we need a way to demultiplex the response so that the callback corresponding 19505ffb0c9bSToomas Soome // to the right DNSServiceRegisterRecord instance can be called. Use the same mechanism that 19515ffb0c9bSToomas Soome // is used by kDNSServiceFlagsShareConnection. create_hdr copies the uid value to ipc 19525ffb0c9bSToomas Soome // hdr->client_context which will be returned in the ipc response. 19535ffb0c9bSToomas Soome if (++sdRef->uid.u32[0] == 0) 19545ffb0c9bSToomas Soome ++sdRef->uid.u32[1]; 19555ffb0c9bSToomas Soome hdr = create_hdr(reg_record_request, &len, &ptr, 1, sdRef); 19565ffb0c9bSToomas Soome if (!hdr) return kDNSServiceErr_NoMemory; 19575ffb0c9bSToomas Soome 19584b22b933Srs put_flags(flags, &ptr); 19595ffb0c9bSToomas Soome put_uint32(interfaceIndex, &ptr); 19604b22b933Srs put_string(fullname, &ptr); 19615ffb0c9bSToomas Soome put_uint16(rrtype, &ptr); 19625ffb0c9bSToomas Soome put_uint16(rrclass, &ptr); 19635ffb0c9bSToomas Soome put_uint16(rdlen, &ptr); 19644b22b933Srs put_rdata(rdlen, rdata, &ptr); 19655ffb0c9bSToomas Soome put_uint32(ttl, &ptr); 19664b22b933Srs 19675ffb0c9bSToomas Soome rref = malloc(sizeof(DNSRecord)); 19685ffb0c9bSToomas Soome if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; } 19695ffb0c9bSToomas Soome rref->AppContext = context; 19705ffb0c9bSToomas Soome rref->AppCallback = callBack; 19714b22b933Srs rref->record_index = sdRef->max_index++; 19724b22b933Srs rref->sdr = sdRef; 19735ffb0c9bSToomas Soome rref->recnext = NULL; 19744b22b933Srs *RecordRef = rref; 19755ffb0c9bSToomas Soome // Remember the uid that we are sending across so that we can match 19765ffb0c9bSToomas Soome // when the response comes back. 19775ffb0c9bSToomas Soome rref->uid = sdRef->uid; 19784b22b933Srs hdr->reg_index = rref->record_index; 19794b22b933Srs 19805ffb0c9bSToomas Soome p = &(sdRef)->rec; 19815ffb0c9bSToomas Soome while (*p) p = &(*p)->recnext; 19825ffb0c9bSToomas Soome *p = rref; 19834b22b933Srs 19845ffb0c9bSToomas Soome return deliver_request(hdr, sdRef); // Will free hdr for us 19855ffb0c9bSToomas Soome } 19864b22b933Srs 19875ffb0c9bSToomas Soome // sdRef returned by DNSServiceRegister() 19884b22b933Srs DNSServiceErrorType DNSSD_API DNSServiceAddRecord 19895ffb0c9bSToomas Soome ( 19905ffb0c9bSToomas Soome DNSServiceRef sdRef, 19914b22b933Srs DNSRecordRef *RecordRef, 19925ffb0c9bSToomas Soome DNSServiceFlags flags, 19935ffb0c9bSToomas Soome uint16_t rrtype, 19945ffb0c9bSToomas Soome uint16_t rdlen, 19954b22b933Srs const void *rdata, 19965ffb0c9bSToomas Soome uint32_t ttl 19975ffb0c9bSToomas Soome ) 19985ffb0c9bSToomas Soome { 19994b22b933Srs ipc_msg_hdr *hdr; 20004b22b933Srs size_t len = 0; 20014b22b933Srs char *ptr; 20024b22b933Srs DNSRecordRef rref; 20035ffb0c9bSToomas Soome DNSRecord **p; 20045ffb0c9bSToomas Soome 2005c65ebfc7SToomas Soome if (!sdRef || !RecordRef || (!rdata && rdlen)) 2006c65ebfc7SToomas Soome { 2007c65ebfc7SToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL parameter"); 2008c65ebfc7SToomas Soome return kDNSServiceErr_BadParam; 2009c65ebfc7SToomas Soome } 20105ffb0c9bSToomas Soome if (sdRef->op != reg_service_request) 20115ffb0c9bSToomas Soome { 20125ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with non-DNSServiceRegister DNSServiceRef %p %d", sdRef, sdRef->op); 20135ffb0c9bSToomas Soome return kDNSServiceErr_BadReference; 20145ffb0c9bSToomas Soome } 20154b22b933Srs 20165ffb0c9bSToomas Soome if (!DNSServiceRefValid(sdRef)) 20175ffb0c9bSToomas Soome { 20185ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator); 20194b22b933Srs return kDNSServiceErr_BadReference; 20205ffb0c9bSToomas Soome } 20215ffb0c9bSToomas Soome 20224b22b933Srs *RecordRef = NULL; 20234b22b933Srs 20245ffb0c9bSToomas Soome len += 2 * sizeof(uint16_t); // rrtype, rdlen 20254b22b933Srs len += rdlen; 20264b22b933Srs len += sizeof(uint32_t); 20274b22b933Srs len += sizeof(DNSServiceFlags); 20284b22b933Srs 20295ffb0c9bSToomas Soome hdr = create_hdr(add_record_request, &len, &ptr, 1, sdRef); 20305ffb0c9bSToomas Soome if (!hdr) return kDNSServiceErr_NoMemory; 20314b22b933Srs put_flags(flags, &ptr); 20325ffb0c9bSToomas Soome put_uint16(rrtype, &ptr); 20335ffb0c9bSToomas Soome put_uint16(rdlen, &ptr); 20344b22b933Srs put_rdata(rdlen, rdata, &ptr); 20355ffb0c9bSToomas Soome put_uint32(ttl, &ptr); 20364b22b933Srs 20375ffb0c9bSToomas Soome rref = malloc(sizeof(DNSRecord)); 20385ffb0c9bSToomas Soome if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; } 20395ffb0c9bSToomas Soome rref->AppContext = NULL; 20405ffb0c9bSToomas Soome rref->AppCallback = NULL; 20414b22b933Srs rref->record_index = sdRef->max_index++; 20424b22b933Srs rref->sdr = sdRef; 20435ffb0c9bSToomas Soome rref->recnext = NULL; 20444b22b933Srs *RecordRef = rref; 20454b22b933Srs hdr->reg_index = rref->record_index; 20464b22b933Srs 20475ffb0c9bSToomas Soome p = &(sdRef)->rec; 20485ffb0c9bSToomas Soome while (*p) p = &(*p)->recnext; 20495ffb0c9bSToomas Soome *p = rref; 20505ffb0c9bSToomas Soome 20515ffb0c9bSToomas Soome return deliver_request(hdr, sdRef); // Will free hdr for us 20524b22b933Srs } 20534b22b933Srs 20545ffb0c9bSToomas Soome // DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord 20554b22b933Srs DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord 20565ffb0c9bSToomas Soome ( 20575ffb0c9bSToomas Soome DNSServiceRef sdRef, 20585ffb0c9bSToomas Soome DNSRecordRef RecordRef, 20595ffb0c9bSToomas Soome DNSServiceFlags flags, 20605ffb0c9bSToomas Soome uint16_t rdlen, 20614b22b933Srs const void *rdata, 20625ffb0c9bSToomas Soome uint32_t ttl 20635ffb0c9bSToomas Soome ) 20645ffb0c9bSToomas Soome { 20654b22b933Srs ipc_msg_hdr *hdr; 20664b22b933Srs size_t len = 0; 20674b22b933Srs char *ptr; 20684b22b933Srs 2069c65ebfc7SToomas Soome if (!sdRef || (!rdata && rdlen)) 2070c65ebfc7SToomas Soome { 2071c65ebfc7SToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with NULL parameter"); 2072c65ebfc7SToomas Soome return kDNSServiceErr_BadParam; 2073c65ebfc7SToomas Soome } 20745ffb0c9bSToomas Soome 20755ffb0c9bSToomas Soome if (!DNSServiceRefValid(sdRef)) 20765ffb0c9bSToomas Soome { 20775ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator); 20785ffb0c9bSToomas Soome return kDNSServiceErr_BadReference; 20795ffb0c9bSToomas Soome } 20805ffb0c9bSToomas Soome 20815ffb0c9bSToomas Soome // Note: RecordRef is allowed to be NULL 20824b22b933Srs 20834b22b933Srs len += sizeof(uint16_t); 20844b22b933Srs len += rdlen; 20854b22b933Srs len += sizeof(uint32_t); 20864b22b933Srs len += sizeof(DNSServiceFlags); 20874b22b933Srs 20885ffb0c9bSToomas Soome hdr = create_hdr(update_record_request, &len, &ptr, 1, sdRef); 20895ffb0c9bSToomas Soome if (!hdr) return kDNSServiceErr_NoMemory; 20904b22b933Srs hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX; 20914b22b933Srs put_flags(flags, &ptr); 20925ffb0c9bSToomas Soome put_uint16(rdlen, &ptr); 20934b22b933Srs put_rdata(rdlen, rdata, &ptr); 20945ffb0c9bSToomas Soome put_uint32(ttl, &ptr); 20955ffb0c9bSToomas Soome return deliver_request(hdr, sdRef); // Will free hdr for us 20965ffb0c9bSToomas Soome } 20974b22b933Srs 20984b22b933Srs DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord 20995ffb0c9bSToomas Soome ( 21005ffb0c9bSToomas Soome DNSServiceRef sdRef, 21015ffb0c9bSToomas Soome DNSRecordRef RecordRef, 21025ffb0c9bSToomas Soome DNSServiceFlags flags 21035ffb0c9bSToomas Soome ) 21045ffb0c9bSToomas Soome { 21054b22b933Srs ipc_msg_hdr *hdr; 21064b22b933Srs size_t len = 0; 21074b22b933Srs char *ptr; 21084b22b933Srs DNSServiceErrorType err; 21094b22b933Srs 21105ffb0c9bSToomas Soome if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; } 21115ffb0c9bSToomas Soome if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSRecordRef"); return kDNSServiceErr_BadParam; } 21125ffb0c9bSToomas Soome if (!sdRef->max_index) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with bad DNSServiceRef"); return kDNSServiceErr_BadReference; } 21135ffb0c9bSToomas Soome 21145ffb0c9bSToomas Soome if (!DNSServiceRefValid(sdRef)) 21155ffb0c9bSToomas Soome { 21165ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator); 21174b22b933Srs return kDNSServiceErr_BadReference; 21185ffb0c9bSToomas Soome } 21194b22b933Srs 21204b22b933Srs len += sizeof(flags); 21215ffb0c9bSToomas Soome hdr = create_hdr(remove_record_request, &len, &ptr, 1, sdRef); 21225ffb0c9bSToomas Soome if (!hdr) return kDNSServiceErr_NoMemory; 21234b22b933Srs hdr->reg_index = RecordRef->record_index; 21244b22b933Srs put_flags(flags, &ptr); 21255ffb0c9bSToomas Soome err = deliver_request(hdr, sdRef); // Will free hdr for us 21265ffb0c9bSToomas Soome if (!err) 21275ffb0c9bSToomas Soome { 21285ffb0c9bSToomas Soome // This RecordRef could have been allocated in DNSServiceRegisterRecord or DNSServiceAddRecord. 21295ffb0c9bSToomas Soome // If so, delink from the list before freeing 21305ffb0c9bSToomas Soome DNSRecord **p = &sdRef->rec; 21315ffb0c9bSToomas Soome while (*p && *p != RecordRef) p = &(*p)->recnext; 21325ffb0c9bSToomas Soome if (*p) *p = RecordRef->recnext; 21335ffb0c9bSToomas Soome free(RecordRef); 21344b22b933Srs } 21355ffb0c9bSToomas Soome return err; 21365ffb0c9bSToomas Soome } 21374b22b933Srs 21384b22b933Srs DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord 21395ffb0c9bSToomas Soome ( 21405ffb0c9bSToomas Soome DNSServiceFlags flags, 21415ffb0c9bSToomas Soome uint32_t interfaceIndex, 21425ffb0c9bSToomas Soome const char *fullname, 21435ffb0c9bSToomas Soome uint16_t rrtype, 21445ffb0c9bSToomas Soome uint16_t rrclass, 21455ffb0c9bSToomas Soome uint16_t rdlen, 21465ffb0c9bSToomas Soome const void *rdata 21475ffb0c9bSToomas Soome ) 21485ffb0c9bSToomas Soome { 2149c65ebfc7SToomas Soome DNSServiceErrorType err; 21504b22b933Srs char *ptr; 21514b22b933Srs size_t len; 21524b22b933Srs ipc_msg_hdr *hdr; 2153c65ebfc7SToomas Soome DNSServiceOp *tmp = NULL; 2154c65ebfc7SToomas Soome 2155c65ebfc7SToomas Soome if (!fullname || (!rdata && rdlen)) return kDNSServiceErr_BadParam; 21565ffb0c9bSToomas Soome 2157c65ebfc7SToomas Soome err = ConnectToServer(&tmp, flags, reconfirm_record_request, NULL, NULL, NULL); 21585ffb0c9bSToomas Soome if (err) return err; 21594b22b933Srs 21604b22b933Srs len = sizeof(DNSServiceFlags); 21614b22b933Srs len += sizeof(uint32_t); 21624b22b933Srs len += strlen(fullname) + 1; 21634b22b933Srs len += 3 * sizeof(uint16_t); 21644b22b933Srs len += rdlen; 21655ffb0c9bSToomas Soome hdr = create_hdr(reconfirm_record_request, &len, &ptr, 0, tmp); 21665ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; } 21674b22b933Srs 21684b22b933Srs put_flags(flags, &ptr); 21695ffb0c9bSToomas Soome put_uint32(interfaceIndex, &ptr); 21704b22b933Srs put_string(fullname, &ptr); 21715ffb0c9bSToomas Soome put_uint16(rrtype, &ptr); 21725ffb0c9bSToomas Soome put_uint16(rrclass, &ptr); 21735ffb0c9bSToomas Soome put_uint16(rdlen, &ptr); 21744b22b933Srs put_rdata(rdlen, rdata, &ptr); 21755ffb0c9bSToomas Soome 21765ffb0c9bSToomas Soome err = deliver_request(hdr, tmp); // Will free hdr for us 21774b22b933Srs DNSServiceRefDeallocate(tmp); 21785ffb0c9bSToomas Soome return err; 21795ffb0c9bSToomas Soome } 21805ffb0c9bSToomas Soome 21815ffb0c9bSToomas Soome 21825ffb0c9bSToomas Soome static void handle_port_mapping_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) 21835ffb0c9bSToomas Soome { 21845ffb0c9bSToomas Soome union { uint32_t l; u_char b[4]; } addr; 21855ffb0c9bSToomas Soome uint8_t protocol; 21865ffb0c9bSToomas Soome union { uint16_t s; u_char b[2]; } internalPort; 21875ffb0c9bSToomas Soome union { uint16_t s; u_char b[2]; } externalPort; 21885ffb0c9bSToomas Soome uint32_t ttl; 21895ffb0c9bSToomas Soome 21905ffb0c9bSToomas Soome if (!data || data + 13 > end) goto fail; 21915ffb0c9bSToomas Soome 21925ffb0c9bSToomas Soome addr.b[0] = *data++; 21935ffb0c9bSToomas Soome addr.b[1] = *data++; 21945ffb0c9bSToomas Soome addr.b[2] = *data++; 21955ffb0c9bSToomas Soome addr.b[3] = *data++; 21965ffb0c9bSToomas Soome protocol = *data++; 21975ffb0c9bSToomas Soome internalPort.b[0] = *data++; 21985ffb0c9bSToomas Soome internalPort.b[1] = *data++; 21995ffb0c9bSToomas Soome externalPort.b[0] = *data++; 22005ffb0c9bSToomas Soome externalPort.b[1] = *data++; 22015ffb0c9bSToomas Soome ttl = get_uint32(&data, end); 22025ffb0c9bSToomas Soome if (!data) goto fail; 22035ffb0c9bSToomas Soome 22045ffb0c9bSToomas Soome ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, addr.l, protocol, internalPort.s, externalPort.s, ttl, sdr->AppContext); 22055ffb0c9bSToomas Soome return; 22065ffb0c9bSToomas Soome // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function 22075ffb0c9bSToomas Soome 22085ffb0c9bSToomas Soome fail : 22095ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub handle_port_mapping_response: error reading result from daemon"); 22105ffb0c9bSToomas Soome } 22115ffb0c9bSToomas Soome 22125ffb0c9bSToomas Soome DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate 22135ffb0c9bSToomas Soome ( 22145ffb0c9bSToomas Soome DNSServiceRef *sdRef, 22155ffb0c9bSToomas Soome DNSServiceFlags flags, 22165ffb0c9bSToomas Soome uint32_t interfaceIndex, 22175ffb0c9bSToomas Soome uint32_t protocol, /* TCP and/or UDP */ 22185ffb0c9bSToomas Soome uint16_t internalPortInNetworkByteOrder, 22195ffb0c9bSToomas Soome uint16_t externalPortInNetworkByteOrder, 22205ffb0c9bSToomas Soome uint32_t ttl, /* time to live in seconds */ 22215ffb0c9bSToomas Soome DNSServiceNATPortMappingReply callBack, 22225ffb0c9bSToomas Soome void *context /* may be NULL */ 22235ffb0c9bSToomas Soome ) 22245ffb0c9bSToomas Soome { 22255ffb0c9bSToomas Soome char *ptr; 22265ffb0c9bSToomas Soome size_t len; 22275ffb0c9bSToomas Soome ipc_msg_hdr *hdr; 22285ffb0c9bSToomas Soome union { uint16_t s; u_char b[2]; } internalPort = { internalPortInNetworkByteOrder }; 22295ffb0c9bSToomas Soome union { uint16_t s; u_char b[2]; } externalPort = { externalPortInNetworkByteOrder }; 22305ffb0c9bSToomas Soome 2231*3b436d06SToomas Soome DNSServiceErrorType err = ConnectToServer(sdRef, flags, port_mapping_request, handle_port_mapping_response, (void *)callBack, context); 22325ffb0c9bSToomas Soome if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL 22335ffb0c9bSToomas Soome 22345ffb0c9bSToomas Soome len = sizeof(flags); 22355ffb0c9bSToomas Soome len += sizeof(interfaceIndex); 22365ffb0c9bSToomas Soome len += sizeof(protocol); 22375ffb0c9bSToomas Soome len += sizeof(internalPort); 22385ffb0c9bSToomas Soome len += sizeof(externalPort); 22395ffb0c9bSToomas Soome len += sizeof(ttl); 22405ffb0c9bSToomas Soome 22415ffb0c9bSToomas Soome hdr = create_hdr(port_mapping_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); 22425ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; } 22435ffb0c9bSToomas Soome 22445ffb0c9bSToomas Soome put_flags(flags, &ptr); 22455ffb0c9bSToomas Soome put_uint32(interfaceIndex, &ptr); 22465ffb0c9bSToomas Soome put_uint32(protocol, &ptr); 22475ffb0c9bSToomas Soome *ptr++ = internalPort.b[0]; 22485ffb0c9bSToomas Soome *ptr++ = internalPort.b[1]; 22495ffb0c9bSToomas Soome *ptr++ = externalPort.b[0]; 22505ffb0c9bSToomas Soome *ptr++ = externalPort.b[1]; 22515ffb0c9bSToomas Soome put_uint32(ttl, &ptr); 22525ffb0c9bSToomas Soome 22535ffb0c9bSToomas Soome err = deliver_request(hdr, *sdRef); // Will free hdr for us 22545ffb0c9bSToomas Soome if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; } 22555ffb0c9bSToomas Soome return err; 22565ffb0c9bSToomas Soome } 22575ffb0c9bSToomas Soome 22585ffb0c9bSToomas Soome #if _DNS_SD_LIBDISPATCH 22595ffb0c9bSToomas Soome DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue 22605ffb0c9bSToomas Soome ( 22615ffb0c9bSToomas Soome DNSServiceRef service, 22625ffb0c9bSToomas Soome dispatch_queue_t queue 22635ffb0c9bSToomas Soome ) 22645ffb0c9bSToomas Soome { 22655ffb0c9bSToomas Soome int dnssd_fd = DNSServiceRefSockFD(service); 22665ffb0c9bSToomas Soome if (dnssd_fd == dnssd_InvalidSocket) return kDNSServiceErr_BadParam; 22675ffb0c9bSToomas Soome if (!queue) 22685ffb0c9bSToomas Soome { 22695ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub: DNSServiceSetDispatchQueue dispatch queue NULL"); 22705ffb0c9bSToomas Soome return kDNSServiceErr_BadParam; 22715ffb0c9bSToomas Soome } 22725ffb0c9bSToomas Soome if (service->disp_queue) 22735ffb0c9bSToomas Soome { 22745ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch queue set already"); 22755ffb0c9bSToomas Soome return kDNSServiceErr_BadParam; 22765ffb0c9bSToomas Soome } 22775ffb0c9bSToomas Soome if (service->disp_source) 22785ffb0c9bSToomas Soome { 22795ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch source set already"); 22805ffb0c9bSToomas Soome return kDNSServiceErr_BadParam; 22815ffb0c9bSToomas Soome } 22825ffb0c9bSToomas Soome service->disp_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, dnssd_fd, 0, queue); 22835ffb0c9bSToomas Soome if (!service->disp_source) 22845ffb0c9bSToomas Soome { 22855ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch_source_create failed"); 22865ffb0c9bSToomas Soome return kDNSServiceErr_NoMemory; 22875ffb0c9bSToomas Soome } 22885ffb0c9bSToomas Soome service->disp_queue = queue; 22895ffb0c9bSToomas Soome dispatch_source_set_event_handler(service->disp_source, ^{DNSServiceProcessResult(service);}); 22905ffb0c9bSToomas Soome dispatch_source_set_cancel_handler(service->disp_source, ^{dnssd_close(dnssd_fd);}); 22915ffb0c9bSToomas Soome dispatch_resume(service->disp_source); 22925ffb0c9bSToomas Soome return kDNSServiceErr_NoError; 22935ffb0c9bSToomas Soome } 22945ffb0c9bSToomas Soome #endif // _DNS_SD_LIBDISPATCH 22955ffb0c9bSToomas Soome 22965ffb0c9bSToomas Soome #if !defined(_WIN32) 22975ffb0c9bSToomas Soome 22985ffb0c9bSToomas Soome static void DNSSD_API SleepKeepaliveCallback(DNSServiceRef sdRef, DNSRecordRef rec, const DNSServiceFlags flags, 22995ffb0c9bSToomas Soome DNSServiceErrorType errorCode, void *context) 23005ffb0c9bSToomas Soome { 23015ffb0c9bSToomas Soome SleepKAContext *ka = (SleepKAContext *)context; 23025ffb0c9bSToomas Soome (void)rec; // Unused 23035ffb0c9bSToomas Soome (void)flags; // Unused 23045ffb0c9bSToomas Soome 23055ffb0c9bSToomas Soome if (sdRef->kacontext != context) 23065ffb0c9bSToomas Soome syslog(LOG_WARNING, "SleepKeepaliveCallback context mismatch"); 23075ffb0c9bSToomas Soome 23085ffb0c9bSToomas Soome if (ka->AppCallback) 23095ffb0c9bSToomas Soome ((DNSServiceSleepKeepaliveReply)ka->AppCallback)(sdRef, errorCode, ka->AppContext); 23105ffb0c9bSToomas Soome } 23115ffb0c9bSToomas Soome 23125ffb0c9bSToomas Soome DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive 23135ffb0c9bSToomas Soome ( 23145ffb0c9bSToomas Soome DNSServiceRef *sdRef, 23155ffb0c9bSToomas Soome DNSServiceFlags flags, 23165ffb0c9bSToomas Soome int fd, 23175ffb0c9bSToomas Soome unsigned int timeout, 23185ffb0c9bSToomas Soome DNSServiceSleepKeepaliveReply callBack, 23195ffb0c9bSToomas Soome void *context 23205ffb0c9bSToomas Soome ) 23215ffb0c9bSToomas Soome { 23225ffb0c9bSToomas Soome char source_str[INET6_ADDRSTRLEN]; 23235ffb0c9bSToomas Soome char target_str[INET6_ADDRSTRLEN]; 23245ffb0c9bSToomas Soome struct sockaddr_storage lss; 23255ffb0c9bSToomas Soome struct sockaddr_storage rss; 23265ffb0c9bSToomas Soome socklen_t len1, len2; 23275ffb0c9bSToomas Soome unsigned int len, proxyreclen; 23285ffb0c9bSToomas Soome char buf[256]; 23295ffb0c9bSToomas Soome DNSServiceErrorType err; 23305ffb0c9bSToomas Soome DNSRecordRef record = NULL; 23315ffb0c9bSToomas Soome char name[10]; 23325ffb0c9bSToomas Soome char recname[128]; 23335ffb0c9bSToomas Soome SleepKAContext *ka; 23345ffb0c9bSToomas Soome unsigned int i, unique; 23355ffb0c9bSToomas Soome 23365ffb0c9bSToomas Soome 23375ffb0c9bSToomas Soome (void) flags; //unused 23385ffb0c9bSToomas Soome if (!timeout) return kDNSServiceErr_BadParam; 23395ffb0c9bSToomas Soome 23405ffb0c9bSToomas Soome 23415ffb0c9bSToomas Soome len1 = sizeof(lss); 23425ffb0c9bSToomas Soome if (getsockname(fd, (struct sockaddr *)&lss, &len1) < 0) 23435ffb0c9bSToomas Soome { 23445ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getsockname %d\n", errno); 23455ffb0c9bSToomas Soome return kDNSServiceErr_BadParam; 23465ffb0c9bSToomas Soome } 23475ffb0c9bSToomas Soome 23485ffb0c9bSToomas Soome len2 = sizeof(rss); 23495ffb0c9bSToomas Soome if (getpeername(fd, (struct sockaddr *)&rss, &len2) < 0) 23505ffb0c9bSToomas Soome { 23515ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getpeername %d\n", errno); 23525ffb0c9bSToomas Soome return kDNSServiceErr_BadParam; 23535ffb0c9bSToomas Soome } 23545ffb0c9bSToomas Soome 23555ffb0c9bSToomas Soome if (len1 != len2) 23565ffb0c9bSToomas Soome { 23575ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive local/remote info not same"); 23585ffb0c9bSToomas Soome return kDNSServiceErr_Unknown; 23595ffb0c9bSToomas Soome } 23605ffb0c9bSToomas Soome 23615ffb0c9bSToomas Soome unique = 0; 23625ffb0c9bSToomas Soome if (lss.ss_family == AF_INET) 23635ffb0c9bSToomas Soome { 23645ffb0c9bSToomas Soome struct sockaddr_in *sl = (struct sockaddr_in *)&lss; 23655ffb0c9bSToomas Soome struct sockaddr_in *sr = (struct sockaddr_in *)&rss; 23665ffb0c9bSToomas Soome unsigned char *ptr = (unsigned char *)&sl->sin_addr; 23675ffb0c9bSToomas Soome 23685ffb0c9bSToomas Soome if (!inet_ntop(AF_INET, (const void *)&sr->sin_addr, target_str, sizeof (target_str))) 23695ffb0c9bSToomas Soome { 23705ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote info failed %d", errno); 23715ffb0c9bSToomas Soome return kDNSServiceErr_Unknown; 23725ffb0c9bSToomas Soome } 23735ffb0c9bSToomas Soome if (!inet_ntop(AF_INET, (const void *)&sl->sin_addr, source_str, sizeof (source_str))) 23745ffb0c9bSToomas Soome { 23755ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive local info failed %d", errno); 23765ffb0c9bSToomas Soome return kDNSServiceErr_Unknown; 23775ffb0c9bSToomas Soome } 23785ffb0c9bSToomas Soome // Sum of all bytes in the local address and port should result in a unique 23795ffb0c9bSToomas Soome // number in the local network 23805ffb0c9bSToomas Soome for (i = 0; i < sizeof(struct in_addr); i++) 23815ffb0c9bSToomas Soome unique += ptr[i]; 23825ffb0c9bSToomas Soome unique += sl->sin_port; 23835ffb0c9bSToomas Soome 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)); 23845ffb0c9bSToomas Soome } 23855ffb0c9bSToomas Soome else 23865ffb0c9bSToomas Soome { 23875ffb0c9bSToomas Soome struct sockaddr_in6 *sl6 = (struct sockaddr_in6 *)&lss; 23885ffb0c9bSToomas Soome struct sockaddr_in6 *sr6 = (struct sockaddr_in6 *)&rss; 23895ffb0c9bSToomas Soome unsigned char *ptr = (unsigned char *)&sl6->sin6_addr; 23905ffb0c9bSToomas Soome 23915ffb0c9bSToomas Soome if (!inet_ntop(AF_INET6, (const void *)&sr6->sin6_addr, target_str, sizeof (target_str))) 23925ffb0c9bSToomas Soome { 23935ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote6 info failed %d", errno); 23945ffb0c9bSToomas Soome return kDNSServiceErr_Unknown; 23955ffb0c9bSToomas Soome } 23965ffb0c9bSToomas Soome if (!inet_ntop(AF_INET6, (const void *)&sl6->sin6_addr, source_str, sizeof (source_str))) 23975ffb0c9bSToomas Soome { 23985ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive local6 info failed %d", errno); 23995ffb0c9bSToomas Soome return kDNSServiceErr_Unknown; 24005ffb0c9bSToomas Soome } 24015ffb0c9bSToomas Soome for (i = 0; i < sizeof(struct in6_addr); i++) 24025ffb0c9bSToomas Soome unique += ptr[i]; 24035ffb0c9bSToomas Soome unique += sl6->sin6_port; 24045ffb0c9bSToomas Soome 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)); 24055ffb0c9bSToomas Soome } 24065ffb0c9bSToomas Soome 24075ffb0c9bSToomas Soome if (len >= (sizeof(buf) - 1)) 24085ffb0c9bSToomas Soome { 24095ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit local/remote info"); 24105ffb0c9bSToomas Soome return kDNSServiceErr_Unknown; 24115ffb0c9bSToomas Soome } 24125ffb0c9bSToomas Soome // Include the NULL byte also in the first byte. The total length of the record includes the 24135ffb0c9bSToomas Soome // first byte also. 24145ffb0c9bSToomas Soome buf[0] = len + 1; 24155ffb0c9bSToomas Soome proxyreclen = len + 2; 24165ffb0c9bSToomas Soome 24175ffb0c9bSToomas Soome len = snprintf(name, sizeof(name), "%u", unique); 24185ffb0c9bSToomas Soome if (len >= sizeof(name)) 24195ffb0c9bSToomas Soome { 24205ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit unique"); 24215ffb0c9bSToomas Soome return kDNSServiceErr_Unknown; 24225ffb0c9bSToomas Soome } 24235ffb0c9bSToomas Soome 24245ffb0c9bSToomas Soome len = snprintf(recname, sizeof(recname), "%s.%s", name, "_keepalive._dns-sd._udp.local"); 24255ffb0c9bSToomas Soome if (len >= sizeof(recname)) 24265ffb0c9bSToomas Soome { 24275ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit name"); 24285ffb0c9bSToomas Soome return kDNSServiceErr_Unknown; 24295ffb0c9bSToomas Soome } 24305ffb0c9bSToomas Soome 24315ffb0c9bSToomas Soome ka = malloc(sizeof(SleepKAContext)); 24325ffb0c9bSToomas Soome if (!ka) return kDNSServiceErr_NoMemory; 2433*3b436d06SToomas Soome ka->AppCallback = (void *)callBack; 24345ffb0c9bSToomas Soome ka->AppContext = context; 24355ffb0c9bSToomas Soome 24365ffb0c9bSToomas Soome err = DNSServiceCreateConnection(sdRef); 24375ffb0c9bSToomas Soome if (err) 24385ffb0c9bSToomas Soome { 24395ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection"); 24405ffb0c9bSToomas Soome free(ka); 24415ffb0c9bSToomas Soome return err; 24424b22b933Srs } 24434b22b933Srs 24445ffb0c9bSToomas Soome // we don't care about the "record". When sdRef gets deallocated later, it will be freed too 24455ffb0c9bSToomas Soome err = DNSServiceRegisterRecord(*sdRef, &record, kDNSServiceFlagsUnique, 0, recname, 24465ffb0c9bSToomas Soome kDNSServiceType_NULL, kDNSServiceClass_IN, proxyreclen, buf, kDNSServiceInterfaceIndexAny, SleepKeepaliveCallback, ka); 24475ffb0c9bSToomas Soome if (err) 24485ffb0c9bSToomas Soome { 24495ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection"); 24505ffb0c9bSToomas Soome free(ka); 24515ffb0c9bSToomas Soome return err; 24525ffb0c9bSToomas Soome } 24535ffb0c9bSToomas Soome (*sdRef)->kacontext = ka; 24545ffb0c9bSToomas Soome return kDNSServiceErr_NoError; 24555ffb0c9bSToomas Soome } 24565ffb0c9bSToomas Soome #endif 2457