14b22b933Srs200217 /* -*- Mode: C; tab-width: 4 -*-
24b22b933Srs200217 *
34b22b933Srs200217 * Copyright (c) 2003-2004, Apple Computer, Inc. All rights reserved.
44b22b933Srs200217 *
54b22b933Srs200217 * Redistribution and use in source and binary forms, with or without
64b22b933Srs200217 * modification, are permitted provided that the following conditions are met:
74b22b933Srs200217 *
84b22b933Srs200217 * 1. Redistributions of source code must retain the above copyright notice,
94b22b933Srs200217 * this list of conditions and the following disclaimer.
104b22b933Srs200217 * 2. Redistributions in binary form must reproduce the above copyright notice,
114b22b933Srs200217 * this list of conditions and the following disclaimer in the documentation
124b22b933Srs200217 * and/or other materials provided with the distribution.
134b22b933Srs200217 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
144b22b933Srs200217 * contributors may be used to endorse or promote products derived from this
154b22b933Srs200217 * software without specific prior written permission.
164b22b933Srs200217 *
174b22b933Srs200217 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
184b22b933Srs200217 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
194b22b933Srs200217 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
204b22b933Srs200217 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
214b22b933Srs200217 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
224b22b933Srs200217 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
234b22b933Srs200217 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
244b22b933Srs200217 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
254b22b933Srs200217 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
264b22b933Srs200217 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
274b22b933Srs200217 */
284b22b933Srs200217
294b22b933Srs200217 #include <errno.h>
304b22b933Srs200217 #include <stdlib.h>
31*5ffb0c9bSToomas Soome #include <fcntl.h>
32*5ffb0c9bSToomas Soome
33*5ffb0c9bSToomas Soome #if APPLE_OSX_mDNSResponder
34*5ffb0c9bSToomas Soome #include <mach-o/dyld.h>
35*5ffb0c9bSToomas Soome #include <uuid/uuid.h>
36*5ffb0c9bSToomas Soome #include <TargetConditionals.h>
37*5ffb0c9bSToomas Soome #endif
384b22b933Srs200217
394b22b933Srs200217 #include "dnssd_ipc.h"
404b22b933Srs200217
414b22b933Srs200217 #if defined(_WIN32)
424b22b933Srs200217
43*5ffb0c9bSToomas Soome #define _SSIZE_T
44*5ffb0c9bSToomas Soome #include <CommonServices.h>
45*5ffb0c9bSToomas Soome #include <DebugServices.h>
464b22b933Srs200217 #include <winsock2.h>
47*5ffb0c9bSToomas Soome #include <ws2tcpip.h>
484b22b933Srs200217 #include <windows.h>
49*5ffb0c9bSToomas Soome #include <stdarg.h>
50*5ffb0c9bSToomas Soome #include <stdio.h>
514b22b933Srs200217
524b22b933Srs200217 #define sockaddr_mdns sockaddr_in
534b22b933Srs200217 #define AF_MDNS AF_INET
544b22b933Srs200217
55*5ffb0c9bSToomas Soome // Disable warning: "'type cast' : from data pointer 'void *' to function pointer"
564b22b933Srs200217 #pragma warning(disable:4055)
574b22b933Srs200217
58*5ffb0c9bSToomas Soome // Disable warning: "nonstandard extension, function/data pointer conversion in expression"
594b22b933Srs200217 #pragma warning(disable:4152)
604b22b933Srs200217
614b22b933Srs200217 extern BOOL IsSystemServiceDisabled();
624b22b933Srs200217
634b22b933Srs200217 #define sleep(X) Sleep((X) * 1000)
644b22b933Srs200217
654b22b933Srs200217 static int g_initWinsock = 0;
66*5ffb0c9bSToomas Soome #define LOG_WARNING kDebugLevelWarning
67*5ffb0c9bSToomas Soome #define LOG_INFO kDebugLevelInfo
syslog(int priority,const char * message,...)68*5ffb0c9bSToomas Soome static void syslog( int priority, const char * message, ...)
69*5ffb0c9bSToomas Soome {
70*5ffb0c9bSToomas Soome va_list args;
71*5ffb0c9bSToomas Soome int len;
72*5ffb0c9bSToomas Soome char * buffer;
73*5ffb0c9bSToomas Soome DWORD err = WSAGetLastError();
74*5ffb0c9bSToomas Soome (void) priority;
75*5ffb0c9bSToomas Soome va_start( args, message );
76*5ffb0c9bSToomas Soome len = _vscprintf( message, args ) + 1;
77*5ffb0c9bSToomas Soome buffer = malloc( len * sizeof(char) );
78*5ffb0c9bSToomas Soome if ( buffer ) { vsprintf( buffer, message, args ); OutputDebugString( buffer ); free( buffer ); }
79*5ffb0c9bSToomas Soome WSASetLastError( err );
80*5ffb0c9bSToomas Soome }
814b22b933Srs200217 #else
824b22b933Srs200217
83*5ffb0c9bSToomas Soome #include <sys/fcntl.h> // For O_RDWR etc.
844b22b933Srs200217 #include <sys/time.h>
854b22b933Srs200217 #include <sys/socket.h>
864b22b933Srs200217 #include <syslog.h>
874b22b933Srs200217
884b22b933Srs200217 #define sockaddr_mdns sockaddr_un
894b22b933Srs200217 #define AF_MDNS AF_LOCAL
904b22b933Srs200217
914b22b933Srs200217 #endif
924b22b933Srs200217
93*5ffb0c9bSToomas Soome // <rdar://problem/4096913> Specifies how many times we'll try and connect to the server.
944b22b933Srs200217
954b22b933Srs200217 #define DNSSD_CLIENT_MAXTRIES 4
964b22b933Srs200217
97*5ffb0c9bSToomas Soome // Uncomment the line below to use the old error return mechanism of creating a temporary named socket (e.g. in /var/tmp)
98*5ffb0c9bSToomas Soome //#define USE_NAMED_ERROR_RETURN_SOCKET 1
994b22b933Srs200217
100*5ffb0c9bSToomas Soome // If the UDS client has not received a response from the daemon in 60 secs, it is unlikely to get one
101*5ffb0c9bSToomas Soome // Note: Timeout of 3 secs should be sufficient in normal scenarios, but 60 secs is chosen as a safeguard since
102*5ffb0c9bSToomas Soome // some clients may come up before mDNSResponder itself after a BOOT and on rare ocassions IOPM/Keychain/D2D calls
103*5ffb0c9bSToomas Soome // in mDNSResponder's INIT may take a much longer time to return
104*5ffb0c9bSToomas Soome #define DNSSD_CLIENT_TIMEOUT 60
105*5ffb0c9bSToomas Soome
106*5ffb0c9bSToomas Soome #ifndef CTL_PATH_PREFIX
107*5ffb0c9bSToomas Soome #define CTL_PATH_PREFIX "/var/tmp/dnssd_result_socket."
108*5ffb0c9bSToomas Soome #endif
109*5ffb0c9bSToomas Soome
110*5ffb0c9bSToomas Soome typedef struct
1114b22b933Srs200217 {
112*5ffb0c9bSToomas Soome ipc_msg_hdr ipc_hdr;
113*5ffb0c9bSToomas Soome DNSServiceFlags cb_flags;
114*5ffb0c9bSToomas Soome uint32_t cb_interface;
115*5ffb0c9bSToomas Soome DNSServiceErrorType cb_err;
116*5ffb0c9bSToomas Soome } CallbackHeader;
117*5ffb0c9bSToomas Soome
118*5ffb0c9bSToomas Soome typedef struct _DNSServiceRef_t DNSServiceOp;
119*5ffb0c9bSToomas Soome typedef struct _DNSRecordRef_t DNSRecord;
120*5ffb0c9bSToomas Soome
121*5ffb0c9bSToomas Soome #if !defined(_WIN32)
122*5ffb0c9bSToomas Soome typedef struct
123*5ffb0c9bSToomas Soome {
124*5ffb0c9bSToomas Soome void *AppCallback; // Client callback function and context
125*5ffb0c9bSToomas Soome void *AppContext;
126*5ffb0c9bSToomas Soome } SleepKAContext;
127*5ffb0c9bSToomas Soome #endif
128*5ffb0c9bSToomas Soome
129*5ffb0c9bSToomas Soome // client stub callback to process message from server and deliver results to client application
130*5ffb0c9bSToomas Soome typedef void (*ProcessReplyFn)(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *msg, const char *const end);
131*5ffb0c9bSToomas Soome
132*5ffb0c9bSToomas Soome #define ValidatorBits 0x12345678
133*5ffb0c9bSToomas Soome #define DNSServiceRefValid(X) (dnssd_SocketValid((X)->sockfd) && (((X)->sockfd ^ (X)->validator) == ValidatorBits))
134*5ffb0c9bSToomas Soome
135*5ffb0c9bSToomas Soome // When using kDNSServiceFlagsShareConnection, there is one primary _DNSServiceOp_t, and zero or more subordinates
136*5ffb0c9bSToomas Soome // For the primary, the 'next' field points to the first subordinate, and its 'next' field points to the next, and so on.
137*5ffb0c9bSToomas Soome // For the primary, the 'primary' field is NULL; for subordinates the 'primary' field points back to the associated primary
138*5ffb0c9bSToomas Soome //
139*5ffb0c9bSToomas Soome // _DNS_SD_LIBDISPATCH is defined where libdispatch/GCD is available. This does not mean that the application will use the
140*5ffb0c9bSToomas Soome // DNSServiceSetDispatchQueue API. Hence any new code guarded with _DNS_SD_LIBDISPATCH should still be backwards compatible.
141*5ffb0c9bSToomas Soome struct _DNSServiceRef_t
142*5ffb0c9bSToomas Soome {
143*5ffb0c9bSToomas Soome DNSServiceOp *next; // For shared connection
144*5ffb0c9bSToomas Soome DNSServiceOp *primary; // For shared connection
145*5ffb0c9bSToomas Soome dnssd_sock_t sockfd; // Connected socket between client and daemon
146*5ffb0c9bSToomas Soome dnssd_sock_t validator; // Used to detect memory corruption, double disposals, etc.
147*5ffb0c9bSToomas Soome client_context_t uid; // For shared connection requests, each subordinate DNSServiceRef has its own ID,
148*5ffb0c9bSToomas Soome // unique within the scope of the same shared parent DNSServiceRef
1494b22b933Srs200217 uint32_t op; // request_op_t or reply_op_t
150*5ffb0c9bSToomas Soome uint32_t max_index; // Largest assigned record index - 0 if no additional records registered
151*5ffb0c9bSToomas Soome uint32_t logcounter; // Counter used to control number of syslog messages we write
152*5ffb0c9bSToomas Soome int *moreptr; // Set while DNSServiceProcessResult working on this particular DNSServiceRef
153*5ffb0c9bSToomas Soome ProcessReplyFn ProcessReply; // Function pointer to the code to handle received messages
154*5ffb0c9bSToomas Soome void *AppCallback; // Client callback function and context
155*5ffb0c9bSToomas Soome void *AppContext;
156*5ffb0c9bSToomas Soome DNSRecord *rec;
157*5ffb0c9bSToomas Soome #if _DNS_SD_LIBDISPATCH
158*5ffb0c9bSToomas Soome dispatch_source_t disp_source;
159*5ffb0c9bSToomas Soome dispatch_queue_t disp_queue;
160*5ffb0c9bSToomas Soome #endif
161*5ffb0c9bSToomas Soome void *kacontext;
162*5ffb0c9bSToomas Soome };
1634b22b933Srs200217
164*5ffb0c9bSToomas Soome struct _DNSRecordRef_t
1654b22b933Srs200217 {
166*5ffb0c9bSToomas Soome DNSRecord *recnext;
167*5ffb0c9bSToomas Soome void *AppContext;
168*5ffb0c9bSToomas Soome DNSServiceRegisterRecordReply AppCallback;
1694b22b933Srs200217 DNSRecordRef recref;
1704b22b933Srs200217 uint32_t record_index; // index is unique to the ServiceDiscoveryRef
171*5ffb0c9bSToomas Soome client_context_t uid; // For demultiplexing multiple DNSServiceRegisterRecord calls
172*5ffb0c9bSToomas Soome DNSServiceOp *sdr;
173*5ffb0c9bSToomas Soome };
1744b22b933Srs200217
175*5ffb0c9bSToomas Soome // Write len bytes. Return 0 on success, -1 on error
write_all(dnssd_sock_t sd,char * buf,size_t len)176*5ffb0c9bSToomas Soome static int write_all(dnssd_sock_t sd, char *buf, size_t len)
1774b22b933Srs200217 {
1784b22b933Srs200217 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
1794b22b933Srs200217 //if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
1804b22b933Srs200217 while (len)
1814b22b933Srs200217 {
182*5ffb0c9bSToomas Soome ssize_t num_written = send(sd, buf, (long)len, 0);
183*5ffb0c9bSToomas Soome if (num_written < 0 || (size_t)num_written > len)
184*5ffb0c9bSToomas Soome {
185*5ffb0c9bSToomas Soome // Should never happen. If it does, it indicates some OS bug,
186*5ffb0c9bSToomas Soome // or that the mDNSResponder daemon crashed (which should never happen).
187*5ffb0c9bSToomas Soome #if !defined(__ppc__) && defined(SO_ISDEFUNCT)
188*5ffb0c9bSToomas Soome int defunct;
189*5ffb0c9bSToomas Soome socklen_t dlen = sizeof (defunct);
190*5ffb0c9bSToomas Soome if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0)
191*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub write_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
192*5ffb0c9bSToomas Soome if (!defunct)
193*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
194*5ffb0c9bSToomas Soome (long)num_written, (long)len,
195*5ffb0c9bSToomas Soome (num_written < 0) ? dnssd_errno : 0,
196*5ffb0c9bSToomas Soome (num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
197*5ffb0c9bSToomas Soome else
198*5ffb0c9bSToomas Soome syslog(LOG_INFO, "dnssd_clientstub write_all(%d) DEFUNCT", sd);
199*5ffb0c9bSToomas Soome #else
200*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
201*5ffb0c9bSToomas Soome (long)num_written, (long)len,
202*5ffb0c9bSToomas Soome (num_written < 0) ? dnssd_errno : 0,
203*5ffb0c9bSToomas Soome (num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
204*5ffb0c9bSToomas Soome #endif
205*5ffb0c9bSToomas Soome return -1;
206*5ffb0c9bSToomas Soome }
2074b22b933Srs200217 buf += num_written;
2084b22b933Srs200217 len -= num_written;
2094b22b933Srs200217 }
2104b22b933Srs200217 return 0;
2114b22b933Srs200217 }
2124b22b933Srs200217
213*5ffb0c9bSToomas Soome enum { read_all_success = 0, read_all_fail = -1, read_all_wouldblock = -2 };
214*5ffb0c9bSToomas Soome
215*5ffb0c9bSToomas Soome // Read len bytes. Return 0 on success, read_all_fail on error, or read_all_wouldblock for
read_all(dnssd_sock_t sd,char * buf,int len)2164b22b933Srs200217 static int read_all(dnssd_sock_t sd, char *buf, int len)
2174b22b933Srs200217 {
2184b22b933Srs200217 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
2194b22b933Srs200217 //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1;
220*5ffb0c9bSToomas Soome
2214b22b933Srs200217 while (len)
2224b22b933Srs200217 {
2234b22b933Srs200217 ssize_t num_read = recv(sd, buf, len, 0);
224*5ffb0c9bSToomas Soome // It is valid to get an interrupted system call error e.g., somebody attaching
225*5ffb0c9bSToomas Soome // in a debugger, retry without failing
226*5ffb0c9bSToomas Soome if ((num_read < 0) && (errno == EINTR))
227*5ffb0c9bSToomas Soome {
228*5ffb0c9bSToomas Soome syslog(LOG_INFO, "dnssd_clientstub read_all: EINTR continue");
2294b22b933Srs200217 continue;
230*5ffb0c9bSToomas Soome }
231*5ffb0c9bSToomas Soome if ((num_read == 0) || (num_read < 0) || (num_read > len))
232*5ffb0c9bSToomas Soome {
233*5ffb0c9bSToomas Soome int printWarn = 0;
234*5ffb0c9bSToomas Soome int defunct = 0;
235*5ffb0c9bSToomas Soome // Should never happen. If it does, it indicates some OS bug,
236*5ffb0c9bSToomas Soome // or that the mDNSResponder daemon crashed (which should never happen).
237*5ffb0c9bSToomas Soome #if defined(WIN32)
238*5ffb0c9bSToomas Soome // <rdar://problem/7481776> Suppress logs for "A non-blocking socket operation
239*5ffb0c9bSToomas Soome // could not be completed immediately"
240*5ffb0c9bSToomas Soome if (WSAGetLastError() != WSAEWOULDBLOCK)
241*5ffb0c9bSToomas Soome printWarn = 1;
242*5ffb0c9bSToomas Soome #endif
243*5ffb0c9bSToomas Soome #if !defined(__ppc__) && defined(SO_ISDEFUNCT)
244*5ffb0c9bSToomas Soome {
245*5ffb0c9bSToomas Soome socklen_t dlen = sizeof (defunct);
246*5ffb0c9bSToomas Soome if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0)
247*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub read_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
248*5ffb0c9bSToomas Soome }
249*5ffb0c9bSToomas Soome if (!defunct)
250*5ffb0c9bSToomas Soome printWarn = 1;
251*5ffb0c9bSToomas Soome #endif
252*5ffb0c9bSToomas Soome if (printWarn)
253*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub read_all(%d) failed %ld/%ld %d %s", sd,
254*5ffb0c9bSToomas Soome (long)num_read, (long)len,
255*5ffb0c9bSToomas Soome (num_read < 0) ? dnssd_errno : 0,
256*5ffb0c9bSToomas Soome (num_read < 0) ? dnssd_strerror(dnssd_errno) : "");
257*5ffb0c9bSToomas Soome else if (defunct)
258*5ffb0c9bSToomas Soome syslog(LOG_INFO, "dnssd_clientstub read_all(%d) DEFUNCT", sd);
259*5ffb0c9bSToomas Soome return (num_read < 0 && dnssd_errno == dnssd_EWOULDBLOCK) ? read_all_wouldblock : read_all_fail;
260*5ffb0c9bSToomas Soome }
2614b22b933Srs200217 buf += num_read;
2624b22b933Srs200217 len -= num_read;
2634b22b933Srs200217 }
264*5ffb0c9bSToomas Soome return read_all_success;
265*5ffb0c9bSToomas Soome }
266*5ffb0c9bSToomas Soome
267*5ffb0c9bSToomas Soome // Returns 1 if more bytes remain to be read on socket descriptor sd, 0 otherwise
more_bytes(dnssd_sock_t sd)268*5ffb0c9bSToomas Soome static int more_bytes(dnssd_sock_t sd)
269*5ffb0c9bSToomas Soome {
270*5ffb0c9bSToomas Soome struct timeval tv = { 0, 0 };
271*5ffb0c9bSToomas Soome fd_set readfds;
272*5ffb0c9bSToomas Soome fd_set *fs;
273*5ffb0c9bSToomas Soome int ret;
274*5ffb0c9bSToomas Soome
275*5ffb0c9bSToomas Soome if (sd < FD_SETSIZE)
276*5ffb0c9bSToomas Soome {
277*5ffb0c9bSToomas Soome fs = &readfds;
278*5ffb0c9bSToomas Soome FD_ZERO(fs);
279*5ffb0c9bSToomas Soome }
280*5ffb0c9bSToomas Soome else
281*5ffb0c9bSToomas Soome {
282*5ffb0c9bSToomas Soome // Compute the number of integers needed for storing "sd". Internally fd_set is stored
283*5ffb0c9bSToomas Soome // as an array of ints with one bit for each fd and hence we need to compute
284*5ffb0c9bSToomas Soome // the number of ints needed rather than the number of bytes. If "sd" is 32, we need
285*5ffb0c9bSToomas Soome // two ints and not just one.
286*5ffb0c9bSToomas Soome int nfdbits = sizeof (int) * 8;
287*5ffb0c9bSToomas Soome int nints = (sd/nfdbits) + 1;
288*5ffb0c9bSToomas Soome fs = (fd_set *)calloc(nints, sizeof(int));
289*5ffb0c9bSToomas Soome if (fs == NULL)
290*5ffb0c9bSToomas Soome {
291*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub more_bytes: malloc failed");
2924b22b933Srs200217 return 0;
2934b22b933Srs200217 }
294*5ffb0c9bSToomas Soome }
295*5ffb0c9bSToomas Soome FD_SET(sd, fs);
296*5ffb0c9bSToomas Soome ret = select((int)sd+1, fs, (fd_set*)NULL, (fd_set*)NULL, &tv);
297*5ffb0c9bSToomas Soome if (fs != &readfds)
298*5ffb0c9bSToomas Soome free(fs);
299*5ffb0c9bSToomas Soome return (ret > 0);
300*5ffb0c9bSToomas Soome }
301*5ffb0c9bSToomas Soome
302*5ffb0c9bSToomas Soome // set_waitlimit() implements a timeout using select. It is called from deliver_request() before recv() OR accept()
303*5ffb0c9bSToomas Soome // to ensure the UDS clients are not blocked in these system calls indefinitely.
304*5ffb0c9bSToomas Soome // Note: Ideally one should never be blocked here, because it indicates either mDNSResponder daemon is not yet up/hung/
305*5ffb0c9bSToomas Soome // superbusy/crashed or some other OS bug. For eg: On Windows which suffers from 3rd party software
306*5ffb0c9bSToomas Soome // (primarily 3rd party firewall software) interfering with proper functioning of the TCP protocol stack it is possible
307*5ffb0c9bSToomas Soome // the next operation on this socket(recv/accept) is blocked since we depend on TCP to communicate with the system service.
set_waitlimit(dnssd_sock_t sock,int timeout)308*5ffb0c9bSToomas Soome static int set_waitlimit(dnssd_sock_t sock, int timeout)
309*5ffb0c9bSToomas Soome {
310*5ffb0c9bSToomas Soome int gDaemonErr = kDNSServiceErr_NoError;
311*5ffb0c9bSToomas Soome
312*5ffb0c9bSToomas Soome // To prevent stack corruption since select does not work with timeout if fds > FD_SETSIZE(1024)
313*5ffb0c9bSToomas Soome if (!gDaemonErr && sock < FD_SETSIZE)
314*5ffb0c9bSToomas Soome {
315*5ffb0c9bSToomas Soome struct timeval tv;
316*5ffb0c9bSToomas Soome fd_set set;
317*5ffb0c9bSToomas Soome
318*5ffb0c9bSToomas Soome FD_ZERO(&set);
319*5ffb0c9bSToomas Soome FD_SET(sock, &set);
320*5ffb0c9bSToomas Soome tv.tv_sec = timeout;
321*5ffb0c9bSToomas Soome tv.tv_usec = 0;
322*5ffb0c9bSToomas Soome if (!select((int)(sock + 1), &set, NULL, NULL, &tv))
323*5ffb0c9bSToomas Soome {
324*5ffb0c9bSToomas Soome // Ideally one should never hit this case: See comments before set_waitlimit()
325*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub set_waitlimit:_daemon timed out (%d secs) without any response: Socket %d", timeout, sock);
326*5ffb0c9bSToomas Soome gDaemonErr = kDNSServiceErr_Timeout;
327*5ffb0c9bSToomas Soome }
328*5ffb0c9bSToomas Soome }
329*5ffb0c9bSToomas Soome return gDaemonErr;
330*5ffb0c9bSToomas Soome }
3314b22b933Srs200217
3324b22b933Srs200217 /* create_hdr
3334b22b933Srs200217 *
334*5ffb0c9bSToomas Soome * allocate and initialize an ipc message header. Value of len should initially be the
3354b22b933Srs200217 * length of the data, and is set to the value of the data plus the header. data_start
336*5ffb0c9bSToomas Soome * is set to point to the beginning of the data section. SeparateReturnSocket should be
337*5ffb0c9bSToomas Soome * non-zero for calls that can't receive an immediate error return value on their primary
338*5ffb0c9bSToomas Soome * socket, and therefore require a separate return path for the error code result.
3394b22b933Srs200217 * if zero, the path to a control socket is appended at the beginning of the message buffer.
3404b22b933Srs200217 * data_start is set past this string.
3414b22b933Srs200217 */
create_hdr(uint32_t op,size_t * len,char ** data_start,int SeparateReturnSocket,DNSServiceOp * ref)342*5ffb0c9bSToomas Soome static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int SeparateReturnSocket, DNSServiceOp *ref)
3434b22b933Srs200217 {
3444b22b933Srs200217 char *msg = NULL;
3454b22b933Srs200217 ipc_msg_hdr *hdr;
3464b22b933Srs200217 int datalen;
3474b22b933Srs200217 #if !defined(USE_TCP_LOOPBACK)
348*5ffb0c9bSToomas Soome char ctrl_path[64] = ""; // "/var/tmp/dnssd_result_socket.xxxxxxxxxx-xxx-xxxxxx"
3494b22b933Srs200217 #endif
3504b22b933Srs200217
351*5ffb0c9bSToomas Soome if (SeparateReturnSocket)
3524b22b933Srs200217 {
3534b22b933Srs200217 #if defined(USE_TCP_LOOPBACK)
3544b22b933Srs200217 *len += 2; // Allocate space for two-byte port number
355*5ffb0c9bSToomas Soome #elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
356*5ffb0c9bSToomas Soome struct timeval tv;
357*5ffb0c9bSToomas Soome if (gettimeofday(&tv, NULL) < 0)
358*5ffb0c9bSToomas Soome { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: gettimeofday failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); return NULL; }
3594b22b933Srs200217 sprintf(ctrl_path, "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(),
360*5ffb0c9bSToomas Soome (unsigned long)(tv.tv_sec & 0xFFF), (unsigned long)(tv.tv_usec));
3614b22b933Srs200217 *len += strlen(ctrl_path) + 1;
362*5ffb0c9bSToomas Soome #else
363*5ffb0c9bSToomas Soome *len += 1; // Allocate space for single zero byte (empty C string)
3644b22b933Srs200217 #endif
3654b22b933Srs200217 }
3664b22b933Srs200217
3674b22b933Srs200217 datalen = (int) *len;
3684b22b933Srs200217 *len += sizeof(ipc_msg_hdr);
3694b22b933Srs200217
370*5ffb0c9bSToomas Soome // Write message to buffer
3714b22b933Srs200217 msg = malloc(*len);
372*5ffb0c9bSToomas Soome if (!msg) { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: malloc failed"); return NULL; }
3734b22b933Srs200217
374*5ffb0c9bSToomas Soome memset(msg, 0, *len);
375*5ffb0c9bSToomas Soome hdr = (ipc_msg_hdr *)msg;
3764b22b933Srs200217 hdr->version = VERSION;
377*5ffb0c9bSToomas Soome hdr->datalen = datalen;
378*5ffb0c9bSToomas Soome hdr->ipc_flags = 0;
3794b22b933Srs200217 hdr->op = op;
380*5ffb0c9bSToomas Soome hdr->client_context = ref->uid;
381*5ffb0c9bSToomas Soome hdr->reg_index = 0;
3824b22b933Srs200217 *data_start = msg + sizeof(ipc_msg_hdr);
3834b22b933Srs200217 #if defined(USE_TCP_LOOPBACK)
384*5ffb0c9bSToomas Soome // Put dummy data in for the port, since we don't know what it is yet.
385*5ffb0c9bSToomas Soome // The data will get filled in before we send the message. This happens in deliver_request().
386*5ffb0c9bSToomas Soome if (SeparateReturnSocket) put_uint16(0, data_start);
3874b22b933Srs200217 #else
388*5ffb0c9bSToomas Soome if (SeparateReturnSocket) put_string(ctrl_path, data_start);
3894b22b933Srs200217 #endif
3904b22b933Srs200217 return hdr;
3914b22b933Srs200217 }
3924b22b933Srs200217
FreeDNSRecords(DNSServiceOp * sdRef)393*5ffb0c9bSToomas Soome static void FreeDNSRecords(DNSServiceOp *sdRef)
3944b22b933Srs200217 {
395*5ffb0c9bSToomas Soome DNSRecord *rec = sdRef->rec;
396*5ffb0c9bSToomas Soome while (rec)
397*5ffb0c9bSToomas Soome {
398*5ffb0c9bSToomas Soome DNSRecord *next = rec->recnext;
399*5ffb0c9bSToomas Soome free(rec);
400*5ffb0c9bSToomas Soome rec = next;
401*5ffb0c9bSToomas Soome }
402*5ffb0c9bSToomas Soome }
403*5ffb0c9bSToomas Soome
FreeDNSServiceOp(DNSServiceOp * x)404*5ffb0c9bSToomas Soome static void FreeDNSServiceOp(DNSServiceOp *x)
405*5ffb0c9bSToomas Soome {
406*5ffb0c9bSToomas Soome // We don't use our DNSServiceRefValid macro here because if we're cleaning up after a socket() call failed
407*5ffb0c9bSToomas Soome // then sockfd could legitimately contain a failing value (e.g. dnssd_InvalidSocket)
408*5ffb0c9bSToomas Soome if ((x->sockfd ^ x->validator) != ValidatorBits)
409*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub attempt to dispose invalid DNSServiceRef %p %08X %08X", x, x->sockfd, x->validator);
410*5ffb0c9bSToomas Soome else
411*5ffb0c9bSToomas Soome {
412*5ffb0c9bSToomas Soome x->next = NULL;
413*5ffb0c9bSToomas Soome x->primary = NULL;
414*5ffb0c9bSToomas Soome x->sockfd = dnssd_InvalidSocket;
415*5ffb0c9bSToomas Soome x->validator = 0xDDDDDDDD;
416*5ffb0c9bSToomas Soome x->op = request_op_none;
417*5ffb0c9bSToomas Soome x->max_index = 0;
418*5ffb0c9bSToomas Soome x->logcounter = 0;
419*5ffb0c9bSToomas Soome x->moreptr = NULL;
420*5ffb0c9bSToomas Soome x->ProcessReply = NULL;
421*5ffb0c9bSToomas Soome x->AppCallback = NULL;
422*5ffb0c9bSToomas Soome x->AppContext = NULL;
423*5ffb0c9bSToomas Soome #if _DNS_SD_LIBDISPATCH
424*5ffb0c9bSToomas Soome if (x->disp_source) dispatch_release(x->disp_source);
425*5ffb0c9bSToomas Soome x->disp_source = NULL;
426*5ffb0c9bSToomas Soome x->disp_queue = NULL;
427*5ffb0c9bSToomas Soome #endif
428*5ffb0c9bSToomas Soome // DNSRecords may have been added to subordinate sdRef e.g., DNSServiceRegister/DNSServiceAddRecord
429*5ffb0c9bSToomas Soome // or on the main sdRef e.g., DNSServiceCreateConnection/DNSServiveRegisterRecord. DNSRecords may have
430*5ffb0c9bSToomas Soome // been freed if the application called DNSRemoveRecord
431*5ffb0c9bSToomas Soome FreeDNSRecords(x);
432*5ffb0c9bSToomas Soome if (x->kacontext)
433*5ffb0c9bSToomas Soome {
434*5ffb0c9bSToomas Soome free(x->kacontext);
435*5ffb0c9bSToomas Soome x->kacontext = NULL;
436*5ffb0c9bSToomas Soome }
437*5ffb0c9bSToomas Soome free(x);
438*5ffb0c9bSToomas Soome }
439*5ffb0c9bSToomas Soome }
440*5ffb0c9bSToomas Soome
441*5ffb0c9bSToomas Soome // Return a connected service ref (deallocate with DNSServiceRefDeallocate)
ConnectToServer(DNSServiceRef * ref,DNSServiceFlags flags,uint32_t op,ProcessReplyFn ProcessReply,void * AppCallback,void * AppContext)442*5ffb0c9bSToomas Soome static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags flags, uint32_t op, ProcessReplyFn ProcessReply, void *AppCallback, void *AppContext)
443*5ffb0c9bSToomas Soome {
4444b22b933Srs200217 int NumTries = 0;
4454b22b933Srs200217
446*5ffb0c9bSToomas Soome dnssd_sockaddr_t saddr;
447*5ffb0c9bSToomas Soome DNSServiceOp *sdr;
448*5ffb0c9bSToomas Soome
449*5ffb0c9bSToomas Soome if (!ref)
450*5ffb0c9bSToomas Soome {
451*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSService operation with NULL DNSServiceRef");
452*5ffb0c9bSToomas Soome return kDNSServiceErr_BadParam;
453*5ffb0c9bSToomas Soome }
454*5ffb0c9bSToomas Soome
455*5ffb0c9bSToomas Soome if (flags & kDNSServiceFlagsShareConnection)
456*5ffb0c9bSToomas Soome {
457*5ffb0c9bSToomas Soome if (!*ref)
458*5ffb0c9bSToomas Soome {
459*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with NULL DNSServiceRef");
460*5ffb0c9bSToomas Soome return kDNSServiceErr_BadParam;
461*5ffb0c9bSToomas Soome }
462*5ffb0c9bSToomas Soome if (!DNSServiceRefValid(*ref) || ((*ref)->op != connection_request && (*ref)->op != connection_delegate_request) || (*ref)->primary)
463*5ffb0c9bSToomas Soome {
464*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with invalid DNSServiceRef %p %08X %08X op %d",
465*5ffb0c9bSToomas Soome (*ref), (*ref)->sockfd, (*ref)->validator, (*ref)->op);
466*5ffb0c9bSToomas Soome *ref = NULL;
467*5ffb0c9bSToomas Soome return kDNSServiceErr_BadReference;
468*5ffb0c9bSToomas Soome }
469*5ffb0c9bSToomas Soome }
470*5ffb0c9bSToomas Soome
4714b22b933Srs200217 #if defined(_WIN32)
4724b22b933Srs200217 if (!g_initWinsock)
4734b22b933Srs200217 {
4744b22b933Srs200217 WSADATA wsaData;
4754b22b933Srs200217 g_initWinsock = 1;
476*5ffb0c9bSToomas Soome if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { *ref = NULL; return kDNSServiceErr_ServiceNotRunning; }
4774b22b933Srs200217 }
478*5ffb0c9bSToomas Soome // <rdar://problem/4096913> If the system service is disabled, we only want to try to connect once
4794b22b933Srs200217 if (IsSystemServiceDisabled())
4804b22b933Srs200217 NumTries = DNSSD_CLIENT_MAXTRIES;
4814b22b933Srs200217 #endif
4824b22b933Srs200217
483*5ffb0c9bSToomas Soome sdr = malloc(sizeof(DNSServiceOp));
484*5ffb0c9bSToomas Soome if (!sdr)
485*5ffb0c9bSToomas Soome {
486*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: malloc failed");
487*5ffb0c9bSToomas Soome *ref = NULL;
488*5ffb0c9bSToomas Soome return kDNSServiceErr_NoMemory;
489*5ffb0c9bSToomas Soome }
490*5ffb0c9bSToomas Soome sdr->next = NULL;
491*5ffb0c9bSToomas Soome sdr->primary = NULL;
492*5ffb0c9bSToomas Soome sdr->sockfd = dnssd_InvalidSocket;
493*5ffb0c9bSToomas Soome sdr->validator = sdr->sockfd ^ ValidatorBits;
494*5ffb0c9bSToomas Soome sdr->op = op;
495*5ffb0c9bSToomas Soome sdr->max_index = 0;
496*5ffb0c9bSToomas Soome sdr->logcounter = 0;
497*5ffb0c9bSToomas Soome sdr->moreptr = NULL;
498*5ffb0c9bSToomas Soome sdr->uid.u32[0] = 0;
499*5ffb0c9bSToomas Soome sdr->uid.u32[1] = 0;
500*5ffb0c9bSToomas Soome sdr->ProcessReply = ProcessReply;
501*5ffb0c9bSToomas Soome sdr->AppCallback = AppCallback;
502*5ffb0c9bSToomas Soome sdr->AppContext = AppContext;
503*5ffb0c9bSToomas Soome sdr->rec = NULL;
504*5ffb0c9bSToomas Soome #if _DNS_SD_LIBDISPATCH
505*5ffb0c9bSToomas Soome sdr->disp_source = NULL;
506*5ffb0c9bSToomas Soome sdr->disp_queue = NULL;
507*5ffb0c9bSToomas Soome #endif
508*5ffb0c9bSToomas Soome sdr->kacontext = NULL;
509*5ffb0c9bSToomas Soome
510*5ffb0c9bSToomas Soome if (flags & kDNSServiceFlagsShareConnection)
511*5ffb0c9bSToomas Soome {
512*5ffb0c9bSToomas Soome DNSServiceOp **p = &(*ref)->next; // Append ourselves to end of primary's list
513*5ffb0c9bSToomas Soome while (*p)
514*5ffb0c9bSToomas Soome p = &(*p)->next;
515*5ffb0c9bSToomas Soome *p = sdr;
516*5ffb0c9bSToomas Soome // Preincrement counter before we use it -- it helps with debugging if we know the all-zeroes ID should never appear
517*5ffb0c9bSToomas Soome if (++(*ref)->uid.u32[0] == 0)
518*5ffb0c9bSToomas Soome ++(*ref)->uid.u32[1]; // In parent DNSServiceOp increment UID counter
519*5ffb0c9bSToomas Soome sdr->primary = *ref; // Set our primary pointer
520*5ffb0c9bSToomas Soome sdr->sockfd = (*ref)->sockfd; // Inherit primary's socket
521*5ffb0c9bSToomas Soome sdr->validator = (*ref)->validator;
522*5ffb0c9bSToomas Soome sdr->uid = (*ref)->uid;
523*5ffb0c9bSToomas Soome //printf("ConnectToServer sharing socket %d\n", sdr->sockfd);
524*5ffb0c9bSToomas Soome }
525*5ffb0c9bSToomas Soome else
526*5ffb0c9bSToomas Soome {
527*5ffb0c9bSToomas Soome #ifdef SO_NOSIGPIPE
528*5ffb0c9bSToomas Soome const unsigned long optval = 1;
529*5ffb0c9bSToomas Soome #endif
530*5ffb0c9bSToomas Soome #ifndef USE_TCP_LOOPBACK
531*5ffb0c9bSToomas Soome char* uds_serverpath = getenv(MDNS_UDS_SERVERPATH_ENVVAR);
532*5ffb0c9bSToomas Soome if (uds_serverpath == NULL)
533*5ffb0c9bSToomas Soome uds_serverpath = MDNS_UDS_SERVERPATH;
534*5ffb0c9bSToomas Soome #endif
535*5ffb0c9bSToomas Soome *ref = NULL;
5364b22b933Srs200217 sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0);
537*5ffb0c9bSToomas Soome sdr->validator = sdr->sockfd ^ ValidatorBits;
538*5ffb0c9bSToomas Soome if (!dnssd_SocketValid(sdr->sockfd))
539*5ffb0c9bSToomas Soome {
540*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: socket failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
541*5ffb0c9bSToomas Soome FreeDNSServiceOp(sdr);
542*5ffb0c9bSToomas Soome return kDNSServiceErr_NoMemory;
543*5ffb0c9bSToomas Soome }
544*5ffb0c9bSToomas Soome #ifdef SO_NOSIGPIPE
545*5ffb0c9bSToomas Soome // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
546*5ffb0c9bSToomas Soome if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
547*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_NOSIGPIPE failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
548*5ffb0c9bSToomas Soome #endif
5494b22b933Srs200217 #if defined(USE_TCP_LOOPBACK)
5504b22b933Srs200217 saddr.sin_family = AF_INET;
5514b22b933Srs200217 saddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
5524b22b933Srs200217 saddr.sin_port = htons(MDNS_TCP_SERVERPORT);
5534b22b933Srs200217 #else
5544b22b933Srs200217 saddr.sun_family = AF_LOCAL;
555*5ffb0c9bSToomas Soome strcpy(saddr.sun_path, uds_serverpath);
556*5ffb0c9bSToomas Soome #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
557*5ffb0c9bSToomas Soome {
558*5ffb0c9bSToomas Soome int defunct = 1;
559*5ffb0c9bSToomas Soome if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
560*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
561*5ffb0c9bSToomas Soome }
5624b22b933Srs200217 #endif
563*5ffb0c9bSToomas Soome #endif
564*5ffb0c9bSToomas Soome
5654b22b933Srs200217 while (1)
5664b22b933Srs200217 {
5674b22b933Srs200217 int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
568*5ffb0c9bSToomas Soome if (!err)
569*5ffb0c9bSToomas Soome break; // If we succeeded, return sdr
5704b22b933Srs200217 // If we failed, then it may be because the daemon is still launching.
5714b22b933Srs200217 // This can happen for processes that launch early in the boot process, while the
572*5ffb0c9bSToomas Soome // daemon is still coming up. Rather than fail here, we wait 1 sec and try again.
573*5ffb0c9bSToomas Soome // If, after DNSSD_CLIENT_MAXTRIES, we still can't connect to the daemon,
5744b22b933Srs200217 // then we give up and return a failure code.
5754b22b933Srs200217 if (++NumTries < DNSSD_CLIENT_MAXTRIES)
576*5ffb0c9bSToomas Soome {
577*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect()-> No of tries: %d", NumTries);
5784b22b933Srs200217 sleep(1); // Sleep a bit, then try again
579*5ffb0c9bSToomas Soome }
5804b22b933Srs200217 else
5814b22b933Srs200217 {
582*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect() failed path:%s Socket:%d Err:%d Errno:%d %s",
583*5ffb0c9bSToomas Soome uds_serverpath, sdr->sockfd, err, dnssd_errno, dnssd_strerror(dnssd_errno));
5844b22b933Srs200217 dnssd_close(sdr->sockfd);
585*5ffb0c9bSToomas Soome FreeDNSServiceOp(sdr);
586*5ffb0c9bSToomas Soome return kDNSServiceErr_ServiceNotRunning;
5874b22b933Srs200217 }
5884b22b933Srs200217 }
589*5ffb0c9bSToomas Soome //printf("ConnectToServer opened socket %d\n", sdr->sockfd);
5904b22b933Srs200217 }
5914b22b933Srs200217
592*5ffb0c9bSToomas Soome *ref = sdr;
593*5ffb0c9bSToomas Soome return kDNSServiceErr_NoError;
594*5ffb0c9bSToomas Soome }
595*5ffb0c9bSToomas Soome
596*5ffb0c9bSToomas Soome #define deliver_request_bailout(MSG) \
597*5ffb0c9bSToomas Soome do { syslog(LOG_WARNING, "dnssd_clientstub deliver_request: %s failed %d (%s)", (MSG), dnssd_errno, dnssd_strerror(dnssd_errno)); goto cleanup; } while(0)
598*5ffb0c9bSToomas Soome
deliver_request(ipc_msg_hdr * hdr,DNSServiceOp * sdr)599*5ffb0c9bSToomas Soome static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
6004b22b933Srs200217 {
601*5ffb0c9bSToomas Soome uint32_t datalen = hdr->datalen; // We take a copy here because we're going to convert hdr->datalen to network byte order
602*5ffb0c9bSToomas Soome #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
603*5ffb0c9bSToomas Soome char *const data = (char *)hdr + sizeof(ipc_msg_hdr);
604*5ffb0c9bSToomas Soome #endif
6054b22b933Srs200217 dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
606*5ffb0c9bSToomas Soome DNSServiceErrorType err = kDNSServiceErr_Unknown; // Default for the "goto cleanup" cases
607*5ffb0c9bSToomas Soome int MakeSeparateReturnSocket = 0;
6084b22b933Srs200217
609*5ffb0c9bSToomas Soome // Note: need to check hdr->op, not sdr->op.
610*5ffb0c9bSToomas Soome // hdr->op contains the code for the specific operation we're currently doing, whereas sdr->op
611*5ffb0c9bSToomas Soome // contains the original parent DNSServiceOp (e.g. for an add_record_request, hdr->op will be
612*5ffb0c9bSToomas Soome // add_record_request but the parent sdr->op will be connection_request or reg_service_request)
613*5ffb0c9bSToomas Soome if (sdr->primary ||
614*5ffb0c9bSToomas Soome hdr->op == reg_record_request || hdr->op == add_record_request || hdr->op == update_record_request || hdr->op == remove_record_request)
615*5ffb0c9bSToomas Soome MakeSeparateReturnSocket = 1;
6164b22b933Srs200217
617*5ffb0c9bSToomas Soome if (!DNSServiceRefValid(sdr))
6184b22b933Srs200217 {
619*5ffb0c9bSToomas Soome if (hdr)
620*5ffb0c9bSToomas Soome free(hdr);
621*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub deliver_request: invalid DNSServiceRef %p %08X %08X", sdr, sdr->sockfd, sdr->validator);
622*5ffb0c9bSToomas Soome return kDNSServiceErr_BadReference;
623*5ffb0c9bSToomas Soome }
6244b22b933Srs200217
625*5ffb0c9bSToomas Soome if (!hdr)
626*5ffb0c9bSToomas Soome {
627*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub deliver_request: !hdr");
628*5ffb0c9bSToomas Soome return kDNSServiceErr_Unknown;
629*5ffb0c9bSToomas Soome }
630*5ffb0c9bSToomas Soome
631*5ffb0c9bSToomas Soome if (MakeSeparateReturnSocket)
632*5ffb0c9bSToomas Soome {
6334b22b933Srs200217 #if defined(USE_TCP_LOOPBACK)
6344b22b933Srs200217 {
6354b22b933Srs200217 union { uint16_t s; u_char b[2]; } port;
636*5ffb0c9bSToomas Soome dnssd_sockaddr_t caddr;
637*5ffb0c9bSToomas Soome dnssd_socklen_t len = (dnssd_socklen_t) sizeof(caddr);
638*5ffb0c9bSToomas Soome listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
639*5ffb0c9bSToomas Soome if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("TCP socket");
640*5ffb0c9bSToomas Soome
6414b22b933Srs200217 caddr.sin_family = AF_INET;
6424b22b933Srs200217 caddr.sin_port = 0;
6434b22b933Srs200217 caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
644*5ffb0c9bSToomas Soome if (bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr)) < 0) deliver_request_bailout("TCP bind");
645*5ffb0c9bSToomas Soome if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) deliver_request_bailout("TCP getsockname");
646*5ffb0c9bSToomas Soome if (listen(listenfd, 1) < 0) deliver_request_bailout("TCP listen");
6474b22b933Srs200217 port.s = caddr.sin_port;
6484b22b933Srs200217 data[0] = port.b[0]; // don't switch the byte order, as the
6494b22b933Srs200217 data[1] = port.b[1]; // daemon expects it in network byte order
6504b22b933Srs200217 }
651*5ffb0c9bSToomas Soome #elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
6524b22b933Srs200217 {
653*5ffb0c9bSToomas Soome mode_t mask;
654*5ffb0c9bSToomas Soome int bindresult;
655*5ffb0c9bSToomas Soome dnssd_sockaddr_t caddr;
656*5ffb0c9bSToomas Soome listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
657*5ffb0c9bSToomas Soome if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET socket");
658*5ffb0c9bSToomas Soome
6594b22b933Srs200217 caddr.sun_family = AF_LOCAL;
6604b22b933Srs200217 // According to Stevens (section 3.2), there is no portable way to
6614b22b933Srs200217 // determine whether sa_len is defined on a particular platform.
6624b22b933Srs200217 #ifndef NOT_HAVE_SA_LEN
6634b22b933Srs200217 caddr.sun_len = sizeof(struct sockaddr_un);
6644b22b933Srs200217 #endif
6654b22b933Srs200217 strcpy(caddr.sun_path, data);
666*5ffb0c9bSToomas Soome mask = umask(0);
667*5ffb0c9bSToomas Soome bindresult = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr));
6684b22b933Srs200217 umask(mask);
669*5ffb0c9bSToomas Soome if (bindresult < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET bind");
670*5ffb0c9bSToomas Soome if (listen(listenfd, 1) < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET listen");
671*5ffb0c9bSToomas Soome }
672*5ffb0c9bSToomas Soome #else
673*5ffb0c9bSToomas Soome {
674*5ffb0c9bSToomas Soome dnssd_sock_t sp[2];
675*5ffb0c9bSToomas Soome if (socketpair(AF_DNSSD, SOCK_STREAM, 0, sp) < 0) deliver_request_bailout("socketpair");
676*5ffb0c9bSToomas Soome else
677*5ffb0c9bSToomas Soome {
678*5ffb0c9bSToomas Soome errsd = sp[0]; // We'll read our four-byte error code from sp[0]
679*5ffb0c9bSToomas Soome listenfd = sp[1]; // We'll send sp[1] to the daemon
680*5ffb0c9bSToomas Soome #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
681*5ffb0c9bSToomas Soome {
682*5ffb0c9bSToomas Soome int defunct = 1;
683*5ffb0c9bSToomas Soome if (setsockopt(errsd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
684*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
685*5ffb0c9bSToomas Soome }
686*5ffb0c9bSToomas Soome #endif
687*5ffb0c9bSToomas Soome }
6884b22b933Srs200217 }
6894b22b933Srs200217 #endif
6904b22b933Srs200217 }
6914b22b933Srs200217
692*5ffb0c9bSToomas Soome #if !defined(USE_TCP_LOOPBACK) && !defined(USE_NAMED_ERROR_RETURN_SOCKET)
693*5ffb0c9bSToomas Soome // If we're going to make a separate error return socket, and pass it to the daemon
694*5ffb0c9bSToomas Soome // using sendmsg, then we'll hold back one data byte to go with it.
695*5ffb0c9bSToomas Soome // On some versions of Unix (including Leopard) sending a control message without
696*5ffb0c9bSToomas Soome // any associated data does not work reliably -- e.g. one particular issue we ran
697*5ffb0c9bSToomas Soome // into is that if the receiving program is in a kqueue loop waiting to be notified
698*5ffb0c9bSToomas Soome // of the received message, it doesn't get woken up when the control message arrives.
699*5ffb0c9bSToomas Soome if (MakeSeparateReturnSocket || sdr->op == send_bpf)
700*5ffb0c9bSToomas Soome datalen--; // Okay to use sdr->op when checking for op == send_bpf
701*5ffb0c9bSToomas Soome #endif
7024b22b933Srs200217
703*5ffb0c9bSToomas Soome // At this point, our listening socket is set up and waiting, if necessary, for the daemon to connect back to
704*5ffb0c9bSToomas Soome ConvertHeaderBytes(hdr);
705*5ffb0c9bSToomas Soome //syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %lu bytes", (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
706*5ffb0c9bSToomas Soome //if (MakeSeparateReturnSocket) syslog(LOG_WARNING, "dnssd_clientstub deliver_request name is %s", data);
707*5ffb0c9bSToomas Soome #if TEST_SENDING_ONE_BYTE_AT_A_TIME
708*5ffb0c9bSToomas Soome unsigned int i;
709*5ffb0c9bSToomas Soome for (i=0; i<datalen + sizeof(ipc_msg_hdr); i++)
7104b22b933Srs200217 {
711*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %d", i);
712*5ffb0c9bSToomas Soome if (write_all(sdr->sockfd, ((char *)hdr)+i, 1) < 0)
713*5ffb0c9bSToomas Soome { syslog(LOG_WARNING, "write_all (byte %u) failed", i); goto cleanup; }
714*5ffb0c9bSToomas Soome usleep(10000);
715*5ffb0c9bSToomas Soome }
716*5ffb0c9bSToomas Soome #else
717*5ffb0c9bSToomas Soome if (write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr)) < 0)
718*5ffb0c9bSToomas Soome {
719*5ffb0c9bSToomas Soome // write_all already prints an error message if there is an error writing to
720*5ffb0c9bSToomas Soome // the socket except for DEFUNCT. Logging here is unnecessary and also wrong
721*5ffb0c9bSToomas Soome // in the case of DEFUNCT sockets
722*5ffb0c9bSToomas Soome syslog(LOG_INFO, "dnssd_clientstub deliver_request ERROR: write_all(%d, %lu bytes) failed",
723*5ffb0c9bSToomas Soome sdr->sockfd, (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
724*5ffb0c9bSToomas Soome goto cleanup;
725*5ffb0c9bSToomas Soome }
726*5ffb0c9bSToomas Soome #endif
727*5ffb0c9bSToomas Soome
728*5ffb0c9bSToomas Soome if (!MakeSeparateReturnSocket)
729*5ffb0c9bSToomas Soome errsd = sdr->sockfd;
730*5ffb0c9bSToomas Soome if (MakeSeparateReturnSocket || sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
731*5ffb0c9bSToomas Soome {
732*5ffb0c9bSToomas Soome #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
733*5ffb0c9bSToomas Soome // At this point we may wait in accept for a few milliseconds waiting for the daemon to connect back to us,
734*5ffb0c9bSToomas Soome // but that's okay -- the daemon should not take more than a few milliseconds to respond.
735*5ffb0c9bSToomas Soome // set_waitlimit() ensures we do not block indefinitely just in case something is wrong
736*5ffb0c9bSToomas Soome dnssd_sockaddr_t daddr;
737*5ffb0c9bSToomas Soome dnssd_socklen_t len = sizeof(daddr);
738*5ffb0c9bSToomas Soome if ((err = set_waitlimit(listenfd, DNSSD_CLIENT_TIMEOUT)) != kDNSServiceErr_NoError)
739*5ffb0c9bSToomas Soome goto cleanup;
7404b22b933Srs200217 errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
741*5ffb0c9bSToomas Soome if (!dnssd_SocketValid(errsd))
742*5ffb0c9bSToomas Soome deliver_request_bailout("accept");
743*5ffb0c9bSToomas Soome #else
744*5ffb0c9bSToomas Soome
745*5ffb0c9bSToomas Soome struct iovec vec = { ((char *)hdr) + sizeof(ipc_msg_hdr) + datalen, 1 }; // Send the last byte along with the SCM_RIGHTS
746*5ffb0c9bSToomas Soome struct msghdr msg;
747*5ffb0c9bSToomas Soome struct cmsghdr *cmsg;
748*5ffb0c9bSToomas Soome char cbuf[CMSG_SPACE(4 * sizeof(dnssd_sock_t))];
749*5ffb0c9bSToomas Soome
750*5ffb0c9bSToomas Soome msg.msg_name = 0;
751*5ffb0c9bSToomas Soome msg.msg_namelen = 0;
752*5ffb0c9bSToomas Soome msg.msg_iov = &vec;
753*5ffb0c9bSToomas Soome msg.msg_iovlen = 1;
754*5ffb0c9bSToomas Soome msg.msg_flags = 0;
755*5ffb0c9bSToomas Soome if (MakeSeparateReturnSocket || sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
756*5ffb0c9bSToomas Soome {
757*5ffb0c9bSToomas Soome if (sdr->op == send_bpf)
758*5ffb0c9bSToomas Soome {
759*5ffb0c9bSToomas Soome int i;
760*5ffb0c9bSToomas Soome char p[12]; // Room for "/dev/bpf999" with terminating null
761*5ffb0c9bSToomas Soome for (i=0; i<100; i++)
762*5ffb0c9bSToomas Soome {
763*5ffb0c9bSToomas Soome snprintf(p, sizeof(p), "/dev/bpf%d", i);
764*5ffb0c9bSToomas Soome listenfd = open(p, O_RDWR, 0);
765*5ffb0c9bSToomas Soome //if (dnssd_SocketValid(listenfd)) syslog(LOG_WARNING, "Sending fd %d for %s", listenfd, p);
766*5ffb0c9bSToomas Soome if (!dnssd_SocketValid(listenfd) && dnssd_errno != EBUSY)
767*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "Error opening %s %d (%s)", p, dnssd_errno, dnssd_strerror(dnssd_errno));
768*5ffb0c9bSToomas Soome if (dnssd_SocketValid(listenfd) || dnssd_errno != EBUSY) break;
769*5ffb0c9bSToomas Soome }
770*5ffb0c9bSToomas Soome }
771*5ffb0c9bSToomas Soome msg.msg_control = cbuf;
772*5ffb0c9bSToomas Soome msg.msg_controllen = CMSG_LEN(sizeof(dnssd_sock_t));
773*5ffb0c9bSToomas Soome
774*5ffb0c9bSToomas Soome cmsg = CMSG_FIRSTHDR(&msg);
775*5ffb0c9bSToomas Soome cmsg->cmsg_len = CMSG_LEN(sizeof(dnssd_sock_t));
776*5ffb0c9bSToomas Soome cmsg->cmsg_level = SOL_SOCKET;
777*5ffb0c9bSToomas Soome cmsg->cmsg_type = SCM_RIGHTS;
778*5ffb0c9bSToomas Soome *((dnssd_sock_t *)CMSG_DATA(cmsg)) = listenfd;
7794b22b933Srs200217 }
7804b22b933Srs200217
781*5ffb0c9bSToomas Soome #if TEST_KQUEUE_CONTROL_MESSAGE_BUG
782*5ffb0c9bSToomas Soome sleep(1);
783*5ffb0c9bSToomas Soome #endif
784*5ffb0c9bSToomas Soome
785*5ffb0c9bSToomas Soome #if DEBUG_64BIT_SCM_RIGHTS
786*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d %ld %ld %ld/%ld/%ld/%ld",
787*5ffb0c9bSToomas Soome errsd, listenfd, sizeof(dnssd_sock_t), sizeof(void*),
788*5ffb0c9bSToomas Soome sizeof(struct cmsghdr) + sizeof(dnssd_sock_t),
789*5ffb0c9bSToomas Soome CMSG_LEN(sizeof(dnssd_sock_t)), (long)CMSG_SPACE(sizeof(dnssd_sock_t)),
790*5ffb0c9bSToomas Soome (long)((char*)CMSG_DATA(cmsg) + 4 - cbuf));
791*5ffb0c9bSToomas Soome #endif // DEBUG_64BIT_SCM_RIGHTS
792*5ffb0c9bSToomas Soome
793*5ffb0c9bSToomas Soome if (sendmsg(sdr->sockfd, &msg, 0) < 0)
794*5ffb0c9bSToomas Soome {
795*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub deliver_request ERROR: sendmsg failed read sd=%d write sd=%d errno %d (%s)",
796*5ffb0c9bSToomas Soome errsd, listenfd, dnssd_errno, dnssd_strerror(dnssd_errno));
797*5ffb0c9bSToomas Soome err = kDNSServiceErr_Incompatible;
798*5ffb0c9bSToomas Soome goto cleanup;
799*5ffb0c9bSToomas Soome }
800*5ffb0c9bSToomas Soome
801*5ffb0c9bSToomas Soome #if DEBUG_64BIT_SCM_RIGHTS
802*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d okay", errsd, listenfd);
803*5ffb0c9bSToomas Soome #endif // DEBUG_64BIT_SCM_RIGHTS
804*5ffb0c9bSToomas Soome
805*5ffb0c9bSToomas Soome #endif
806*5ffb0c9bSToomas Soome // Close our end of the socketpair *before* calling read_all() to get the four-byte error code.
807*5ffb0c9bSToomas Soome // Otherwise, if the daemon closes our socket (or crashes), we will have to wait for a timeout
808*5ffb0c9bSToomas Soome // in read_all() because the socket is not closed (we still have an open reference to it)
809*5ffb0c9bSToomas Soome // Note: listenfd is overwritten in the case of send_bpf above and that will be closed here
810*5ffb0c9bSToomas Soome // for send_bpf operation.
811*5ffb0c9bSToomas Soome dnssd_close(listenfd);
812*5ffb0c9bSToomas Soome listenfd = dnssd_InvalidSocket; // Make sure we don't close it a second time in the cleanup handling below
813*5ffb0c9bSToomas Soome }
814*5ffb0c9bSToomas Soome
815*5ffb0c9bSToomas Soome // At this point we may wait in read_all for a few milliseconds waiting for the daemon to send us the error code,
816*5ffb0c9bSToomas Soome // but that's okay -- the daemon should not take more than a few milliseconds to respond.
817*5ffb0c9bSToomas Soome // set_waitlimit() ensures we do not block indefinitely just in case something is wrong
818*5ffb0c9bSToomas Soome if (sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
819*5ffb0c9bSToomas Soome err = kDNSServiceErr_NoError;
820*5ffb0c9bSToomas Soome else if ((err = set_waitlimit(errsd, DNSSD_CLIENT_TIMEOUT)) == kDNSServiceErr_NoError)
821*5ffb0c9bSToomas Soome {
8224b22b933Srs200217 if (read_all(errsd, (char*)&err, (int)sizeof(err)) < 0)
823*5ffb0c9bSToomas Soome err = kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us
8244b22b933Srs200217 else
8254b22b933Srs200217 err = ntohl(err);
826*5ffb0c9bSToomas Soome }
827*5ffb0c9bSToomas Soome //syslog(LOG_WARNING, "dnssd_clientstub deliver_request: retrieved error code %d", err);
8284b22b933Srs200217
8294b22b933Srs200217 cleanup:
830*5ffb0c9bSToomas Soome if (MakeSeparateReturnSocket)
8314b22b933Srs200217 {
832*5ffb0c9bSToomas Soome if (dnssd_SocketValid(listenfd)) dnssd_close(listenfd);
833*5ffb0c9bSToomas Soome if (dnssd_SocketValid(errsd)) dnssd_close(errsd);
834*5ffb0c9bSToomas Soome #if defined(USE_NAMED_ERROR_RETURN_SOCKET)
835*5ffb0c9bSToomas Soome // syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removing UDS: %s", data);
8364b22b933Srs200217 if (unlink(data) != 0)
837*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub WARNING: unlink(\"%s\") failed errno %d (%s)", data, dnssd_errno, dnssd_strerror(dnssd_errno));
838*5ffb0c9bSToomas Soome // else syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removed UDS: %s", data);
8394b22b933Srs200217 #endif
8404b22b933Srs200217 }
841*5ffb0c9bSToomas Soome
842*5ffb0c9bSToomas Soome free(hdr);
8434b22b933Srs200217 return err;
8444b22b933Srs200217 }
8454b22b933Srs200217
DNSServiceRefSockFD(DNSServiceRef sdRef)8464b22b933Srs200217 int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef)
8474b22b933Srs200217 {
848*5ffb0c9bSToomas Soome if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with NULL DNSServiceRef"); return dnssd_InvalidSocket; }
849*5ffb0c9bSToomas Soome
850*5ffb0c9bSToomas Soome if (!DNSServiceRefValid(sdRef))
851*5ffb0c9bSToomas Soome {
852*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with invalid DNSServiceRef %p %08X %08X",
853*5ffb0c9bSToomas Soome sdRef, sdRef->sockfd, sdRef->validator);
854*5ffb0c9bSToomas Soome return dnssd_InvalidSocket;
855*5ffb0c9bSToomas Soome }
856*5ffb0c9bSToomas Soome
857*5ffb0c9bSToomas Soome if (sdRef->primary)
858*5ffb0c9bSToomas Soome {
859*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
860*5ffb0c9bSToomas Soome return dnssd_InvalidSocket;
861*5ffb0c9bSToomas Soome }
862*5ffb0c9bSToomas Soome
8634b22b933Srs200217 return (int) sdRef->sockfd;
8644b22b933Srs200217 }
8654b22b933Srs200217
866*5ffb0c9bSToomas Soome #if _DNS_SD_LIBDISPATCH
CallbackWithError(DNSServiceRef sdRef,DNSServiceErrorType error)867*5ffb0c9bSToomas Soome static void CallbackWithError(DNSServiceRef sdRef, DNSServiceErrorType error)
868*5ffb0c9bSToomas Soome {
869*5ffb0c9bSToomas Soome DNSServiceOp *sdr = sdRef;
870*5ffb0c9bSToomas Soome DNSServiceOp *sdrNext;
871*5ffb0c9bSToomas Soome DNSRecord *rec;
872*5ffb0c9bSToomas Soome DNSRecord *recnext;
873*5ffb0c9bSToomas Soome int morebytes;
874*5ffb0c9bSToomas Soome
875*5ffb0c9bSToomas Soome while (sdr)
876*5ffb0c9bSToomas Soome {
877*5ffb0c9bSToomas Soome // We can't touch the sdr after the callback as it can be deallocated in the callback
878*5ffb0c9bSToomas Soome sdrNext = sdr->next;
879*5ffb0c9bSToomas Soome morebytes = 1;
880*5ffb0c9bSToomas Soome sdr->moreptr = &morebytes;
881*5ffb0c9bSToomas Soome switch (sdr->op)
882*5ffb0c9bSToomas Soome {
883*5ffb0c9bSToomas Soome case resolve_request:
884*5ffb0c9bSToomas Soome if (sdr->AppCallback) ((DNSServiceResolveReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, sdr->AppContext);
885*5ffb0c9bSToomas Soome break;
886*5ffb0c9bSToomas Soome case query_request:
887*5ffb0c9bSToomas Soome if (sdr->AppCallback) ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, 0, sdr->AppContext);
888*5ffb0c9bSToomas Soome break;
889*5ffb0c9bSToomas Soome case addrinfo_request:
890*5ffb0c9bSToomas Soome if (sdr->AppCallback) ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, NULL, 0, sdr->AppContext);
891*5ffb0c9bSToomas Soome break;
892*5ffb0c9bSToomas Soome case browse_request:
893*5ffb0c9bSToomas Soome if (sdr->AppCallback) ((DNSServiceBrowseReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, NULL, sdr->AppContext);
894*5ffb0c9bSToomas Soome break;
895*5ffb0c9bSToomas Soome case reg_service_request:
896*5ffb0c9bSToomas Soome if (sdr->AppCallback) ((DNSServiceRegisterReply) sdr->AppCallback)(sdr, 0, error, NULL, 0, NULL, sdr->AppContext);
897*5ffb0c9bSToomas Soome break;
898*5ffb0c9bSToomas Soome case enumeration_request:
899*5ffb0c9bSToomas Soome if (sdr->AppCallback) ((DNSServiceDomainEnumReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, sdr->AppContext);
900*5ffb0c9bSToomas Soome break;
901*5ffb0c9bSToomas Soome case connection_request:
902*5ffb0c9bSToomas Soome case connection_delegate_request:
903*5ffb0c9bSToomas Soome // This means Register Record, walk the list of DNSRecords to do the callback
904*5ffb0c9bSToomas Soome rec = sdr->rec;
905*5ffb0c9bSToomas Soome while (rec)
906*5ffb0c9bSToomas Soome {
907*5ffb0c9bSToomas Soome recnext = rec->recnext;
908*5ffb0c9bSToomas Soome if (rec->AppCallback) ((DNSServiceRegisterRecordReply)rec->AppCallback)(sdr, 0, 0, error, rec->AppContext);
909*5ffb0c9bSToomas Soome // The Callback can call DNSServiceRefDeallocate which in turn frees sdr and all the records.
910*5ffb0c9bSToomas Soome // Detect that and return early
911*5ffb0c9bSToomas Soome if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:Record: CallbackwithError morebytes zero"); return;}
912*5ffb0c9bSToomas Soome rec = recnext;
913*5ffb0c9bSToomas Soome }
914*5ffb0c9bSToomas Soome break;
915*5ffb0c9bSToomas Soome case port_mapping_request:
916*5ffb0c9bSToomas Soome if (sdr->AppCallback) ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, 0, 0, error, 0, 0, 0, 0, 0, sdr->AppContext);
917*5ffb0c9bSToomas Soome break;
918*5ffb0c9bSToomas Soome default:
919*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub CallbackWithError called with bad op %d", sdr->op);
920*5ffb0c9bSToomas Soome }
921*5ffb0c9bSToomas Soome // If DNSServiceRefDeallocate was called in the callback, morebytes will be zero. As the sdRef
922*5ffb0c9bSToomas Soome // (and its subordinates) have been freed, we should not proceed further. Note that when we
923*5ffb0c9bSToomas Soome // call the callback with a subordinate sdRef the application can call DNSServiceRefDeallocate
924*5ffb0c9bSToomas Soome // on the main sdRef and DNSServiceRefDeallocate handles this case by walking all the sdRefs and
925*5ffb0c9bSToomas Soome // clears the moreptr so that we can terminate here.
926*5ffb0c9bSToomas Soome //
927*5ffb0c9bSToomas Soome // If DNSServiceRefDeallocate was not called in the callback, then set moreptr to NULL so that
928*5ffb0c9bSToomas Soome // we don't access the stack variable after we return from this function.
929*5ffb0c9bSToomas Soome if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:sdRef: CallbackwithError morebytes zero sdr %p", sdr); return;}
930*5ffb0c9bSToomas Soome else {sdr->moreptr = NULL;}
931*5ffb0c9bSToomas Soome sdr = sdrNext;
932*5ffb0c9bSToomas Soome }
933*5ffb0c9bSToomas Soome }
934*5ffb0c9bSToomas Soome #endif // _DNS_SD_LIBDISPATCH
935*5ffb0c9bSToomas Soome
936*5ffb0c9bSToomas Soome // Handle reply from server, calling application client callback. If there is no reply
9374b22b933Srs200217 // from the daemon on the socket contained in sdRef, the call will block.
DNSServiceProcessResult(DNSServiceRef sdRef)9384b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
9394b22b933Srs200217 {
940*5ffb0c9bSToomas Soome int morebytes = 0;
9414b22b933Srs200217
942*5ffb0c9bSToomas Soome if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
943*5ffb0c9bSToomas Soome
944*5ffb0c9bSToomas Soome if (!DNSServiceRefValid(sdRef))
945*5ffb0c9bSToomas Soome {
946*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
9474b22b933Srs200217 return kDNSServiceErr_BadReference;
9484b22b933Srs200217 }
949*5ffb0c9bSToomas Soome
950*5ffb0c9bSToomas Soome if (sdRef->primary)
951*5ffb0c9bSToomas Soome {
952*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
953*5ffb0c9bSToomas Soome return kDNSServiceErr_BadReference;
954*5ffb0c9bSToomas Soome }
955*5ffb0c9bSToomas Soome
956*5ffb0c9bSToomas Soome if (!sdRef->ProcessReply)
957*5ffb0c9bSToomas Soome {
958*5ffb0c9bSToomas Soome static int num_logs = 0;
959*5ffb0c9bSToomas Soome if (num_logs < 10) syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function");
960*5ffb0c9bSToomas Soome if (num_logs < 1000) num_logs++;else sleep(1);
961*5ffb0c9bSToomas Soome return kDNSServiceErr_BadReference;
962*5ffb0c9bSToomas Soome }
963*5ffb0c9bSToomas Soome
964*5ffb0c9bSToomas Soome do
965*5ffb0c9bSToomas Soome {
966*5ffb0c9bSToomas Soome CallbackHeader cbh;
967*5ffb0c9bSToomas Soome char *data;
968*5ffb0c9bSToomas Soome
969*5ffb0c9bSToomas Soome // return NoError on EWOULDBLOCK. This will handle the case
970*5ffb0c9bSToomas Soome // where a non-blocking socket is told there is data, but it was a false positive.
971*5ffb0c9bSToomas Soome // On error, read_all will write a message to syslog for us, so don't need to duplicate that here
972*5ffb0c9bSToomas Soome // Note: If we want to properly support using non-blocking sockets in the future
973*5ffb0c9bSToomas Soome int result = read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr));
974*5ffb0c9bSToomas Soome if (result == read_all_fail)
975*5ffb0c9bSToomas Soome {
976*5ffb0c9bSToomas Soome // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
977*5ffb0c9bSToomas Soome // in the callback.
978*5ffb0c9bSToomas Soome sdRef->ProcessReply = NULL;
979*5ffb0c9bSToomas Soome #if _DNS_SD_LIBDISPATCH
980*5ffb0c9bSToomas Soome // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
981*5ffb0c9bSToomas Soome // is not called by the application and hence need to communicate the error. Cancel the
982*5ffb0c9bSToomas Soome // source so that we don't get any more events
983*5ffb0c9bSToomas Soome // Note: read_all fails if we could not read from the daemon which can happen if the
984*5ffb0c9bSToomas Soome // daemon dies or the file descriptor is disconnected (defunct).
985*5ffb0c9bSToomas Soome if (sdRef->disp_source)
986*5ffb0c9bSToomas Soome {
987*5ffb0c9bSToomas Soome dispatch_source_cancel(sdRef->disp_source);
988*5ffb0c9bSToomas Soome dispatch_release(sdRef->disp_source);
989*5ffb0c9bSToomas Soome sdRef->disp_source = NULL;
990*5ffb0c9bSToomas Soome CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
991*5ffb0c9bSToomas Soome }
992*5ffb0c9bSToomas Soome #endif
993*5ffb0c9bSToomas Soome // Don't touch sdRef anymore as it might have been deallocated
994*5ffb0c9bSToomas Soome return kDNSServiceErr_ServiceNotRunning;
995*5ffb0c9bSToomas Soome }
996*5ffb0c9bSToomas Soome else if (result == read_all_wouldblock)
997*5ffb0c9bSToomas Soome {
998*5ffb0c9bSToomas Soome if (morebytes && sdRef->logcounter < 100)
999*5ffb0c9bSToomas Soome {
1000*5ffb0c9bSToomas Soome sdRef->logcounter++;
1001*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult error: select indicated data was waiting but read_all returned EWOULDBLOCK");
1002*5ffb0c9bSToomas Soome }
1003*5ffb0c9bSToomas Soome return kDNSServiceErr_NoError;
1004*5ffb0c9bSToomas Soome }
1005*5ffb0c9bSToomas Soome
1006*5ffb0c9bSToomas Soome ConvertHeaderBytes(&cbh.ipc_hdr);
1007*5ffb0c9bSToomas Soome if (cbh.ipc_hdr.version != VERSION)
1008*5ffb0c9bSToomas Soome {
1009*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult daemon version %d does not match client version %d", cbh.ipc_hdr.version, VERSION);
1010*5ffb0c9bSToomas Soome sdRef->ProcessReply = NULL;
10114b22b933Srs200217 return kDNSServiceErr_Incompatible;
1012*5ffb0c9bSToomas Soome }
1013*5ffb0c9bSToomas Soome
1014*5ffb0c9bSToomas Soome data = malloc(cbh.ipc_hdr.datalen);
10154b22b933Srs200217 if (!data) return kDNSServiceErr_NoMemory;
1016*5ffb0c9bSToomas Soome if (read_all(sdRef->sockfd, data, cbh.ipc_hdr.datalen) < 0) // On error, read_all will write a message to syslog for us
1017*5ffb0c9bSToomas Soome {
1018*5ffb0c9bSToomas Soome // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
1019*5ffb0c9bSToomas Soome // in the callback.
1020*5ffb0c9bSToomas Soome sdRef->ProcessReply = NULL;
1021*5ffb0c9bSToomas Soome #if _DNS_SD_LIBDISPATCH
1022*5ffb0c9bSToomas Soome // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
1023*5ffb0c9bSToomas Soome // is not called by the application and hence need to communicate the error. Cancel the
1024*5ffb0c9bSToomas Soome // source so that we don't get any more events
1025*5ffb0c9bSToomas Soome if (sdRef->disp_source)
1026*5ffb0c9bSToomas Soome {
1027*5ffb0c9bSToomas Soome dispatch_source_cancel(sdRef->disp_source);
1028*5ffb0c9bSToomas Soome dispatch_release(sdRef->disp_source);
1029*5ffb0c9bSToomas Soome sdRef->disp_source = NULL;
1030*5ffb0c9bSToomas Soome CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
1031*5ffb0c9bSToomas Soome }
1032*5ffb0c9bSToomas Soome #endif
1033*5ffb0c9bSToomas Soome // Don't touch sdRef anymore as it might have been deallocated
10344b22b933Srs200217 free(data);
1035*5ffb0c9bSToomas Soome return kDNSServiceErr_ServiceNotRunning;
1036*5ffb0c9bSToomas Soome }
1037*5ffb0c9bSToomas Soome else
1038*5ffb0c9bSToomas Soome {
1039*5ffb0c9bSToomas Soome const char *ptr = data;
1040*5ffb0c9bSToomas Soome cbh.cb_flags = get_flags (&ptr, data + cbh.ipc_hdr.datalen);
1041*5ffb0c9bSToomas Soome cbh.cb_interface = get_uint32 (&ptr, data + cbh.ipc_hdr.datalen);
1042*5ffb0c9bSToomas Soome cbh.cb_err = get_error_code(&ptr, data + cbh.ipc_hdr.datalen);
1043*5ffb0c9bSToomas Soome
1044*5ffb0c9bSToomas Soome // CAUTION: We have to handle the case where the client calls DNSServiceRefDeallocate from within the callback function.
1045*5ffb0c9bSToomas Soome // To do this we set moreptr to point to morebytes. If the client does call DNSServiceRefDeallocate(),
1046*5ffb0c9bSToomas Soome // then that routine will clear morebytes for us, and cause us to exit our loop.
1047*5ffb0c9bSToomas Soome morebytes = more_bytes(sdRef->sockfd);
1048*5ffb0c9bSToomas Soome if (morebytes)
1049*5ffb0c9bSToomas Soome {
1050*5ffb0c9bSToomas Soome cbh.cb_flags |= kDNSServiceFlagsMoreComing;
1051*5ffb0c9bSToomas Soome sdRef->moreptr = &morebytes;
1052*5ffb0c9bSToomas Soome }
1053*5ffb0c9bSToomas Soome if (ptr) sdRef->ProcessReply(sdRef, &cbh, ptr, data + cbh.ipc_hdr.datalen);
1054*5ffb0c9bSToomas Soome // Careful code here:
1055*5ffb0c9bSToomas Soome // If morebytes is non-zero, that means we set sdRef->moreptr above, and the operation was not
1056*5ffb0c9bSToomas Soome // cancelled out from under us, so now we need to clear sdRef->moreptr so we don't leave a stray
1057*5ffb0c9bSToomas Soome // dangling pointer pointing to a long-gone stack variable.
1058*5ffb0c9bSToomas Soome // If morebytes is zero, then one of two thing happened:
1059*5ffb0c9bSToomas Soome // (a) morebytes was 0 above, so we didn't set sdRef->moreptr, so we don't need to clear it
1060*5ffb0c9bSToomas Soome // (b) morebytes was 1 above, and we set sdRef->moreptr, but the operation was cancelled (with DNSServiceRefDeallocate()),
1061*5ffb0c9bSToomas Soome // so we MUST NOT try to dereference our stale sdRef pointer.
1062*5ffb0c9bSToomas Soome if (morebytes) sdRef->moreptr = NULL;
1063*5ffb0c9bSToomas Soome }
1064*5ffb0c9bSToomas Soome free(data);
1065*5ffb0c9bSToomas Soome } while (morebytes);
1066*5ffb0c9bSToomas Soome
10674b22b933Srs200217 return kDNSServiceErr_NoError;
10684b22b933Srs200217 }
10694b22b933Srs200217
DNSServiceRefDeallocate(DNSServiceRef sdRef)10704b22b933Srs200217 void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef)
10714b22b933Srs200217 {
1072*5ffb0c9bSToomas Soome if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with NULL DNSServiceRef"); return; }
1073*5ffb0c9bSToomas Soome
1074*5ffb0c9bSToomas Soome if (!DNSServiceRefValid(sdRef)) // Also verifies dnssd_SocketValid(sdRef->sockfd) for us too
1075*5ffb0c9bSToomas Soome {
1076*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
1077*5ffb0c9bSToomas Soome return;
10784b22b933Srs200217 }
10794b22b933Srs200217
1080*5ffb0c9bSToomas 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
1081*5ffb0c9bSToomas Soome if (sdRef->moreptr) *(sdRef->moreptr) = 0;
1082*5ffb0c9bSToomas Soome
1083*5ffb0c9bSToomas Soome if (sdRef->primary) // If this is a subordinate DNSServiceOp, just send a 'stop' command
10844b22b933Srs200217 {
1085*5ffb0c9bSToomas Soome DNSServiceOp **p = &sdRef->primary->next;
1086*5ffb0c9bSToomas Soome while (*p && *p != sdRef) p = &(*p)->next;
1087*5ffb0c9bSToomas Soome if (*p)
1088*5ffb0c9bSToomas Soome {
1089*5ffb0c9bSToomas Soome char *ptr;
1090*5ffb0c9bSToomas Soome size_t len = 0;
1091*5ffb0c9bSToomas Soome ipc_msg_hdr *hdr = create_hdr(cancel_request, &len, &ptr, 0, sdRef);
1092*5ffb0c9bSToomas Soome if (hdr)
1093*5ffb0c9bSToomas Soome {
1094*5ffb0c9bSToomas Soome ConvertHeaderBytes(hdr);
1095*5ffb0c9bSToomas Soome write_all(sdRef->sockfd, (char *)hdr, len);
1096*5ffb0c9bSToomas Soome free(hdr);
1097*5ffb0c9bSToomas Soome }
1098*5ffb0c9bSToomas Soome *p = sdRef->next;
1099*5ffb0c9bSToomas Soome FreeDNSServiceOp(sdRef);
1100*5ffb0c9bSToomas Soome }
1101*5ffb0c9bSToomas Soome }
1102*5ffb0c9bSToomas Soome else // else, make sure to terminate all subordinates as well
1103*5ffb0c9bSToomas Soome {
1104*5ffb0c9bSToomas Soome #if _DNS_SD_LIBDISPATCH
1105*5ffb0c9bSToomas Soome // The cancel handler will close the fd if a dispatch source has been set
1106*5ffb0c9bSToomas Soome if (sdRef->disp_source)
1107*5ffb0c9bSToomas Soome {
1108*5ffb0c9bSToomas Soome // By setting the ProcessReply to NULL, we make sure that we never call
1109*5ffb0c9bSToomas Soome // the application callbacks ever, after returning from this function. We
1110*5ffb0c9bSToomas Soome // assume that DNSServiceRefDeallocate is called from the serial queue
1111*5ffb0c9bSToomas Soome // that was passed to DNSServiceSetDispatchQueue. Hence, dispatch_source_cancel
1112*5ffb0c9bSToomas Soome // should cancel all the blocks on the queue and hence there should be no more
1113*5ffb0c9bSToomas Soome // callbacks when we return from this function. Setting ProcessReply to NULL
1114*5ffb0c9bSToomas Soome // provides extra protection.
1115*5ffb0c9bSToomas Soome sdRef->ProcessReply = NULL;
1116*5ffb0c9bSToomas Soome shutdown(sdRef->sockfd, SHUT_WR);
1117*5ffb0c9bSToomas Soome dispatch_source_cancel(sdRef->disp_source);
1118*5ffb0c9bSToomas Soome dispatch_release(sdRef->disp_source);
1119*5ffb0c9bSToomas Soome sdRef->disp_source = NULL;
1120*5ffb0c9bSToomas Soome }
1121*5ffb0c9bSToomas Soome // if disp_queue is set, it means it used the DNSServiceSetDispatchQueue API. In that case,
1122*5ffb0c9bSToomas Soome // when the source was cancelled, the fd was closed in the handler. Currently the source
1123*5ffb0c9bSToomas Soome // is cancelled only when the mDNSResponder daemon dies
1124*5ffb0c9bSToomas Soome else if (!sdRef->disp_queue) dnssd_close(sdRef->sockfd);
1125*5ffb0c9bSToomas Soome #else
1126*5ffb0c9bSToomas Soome dnssd_close(sdRef->sockfd);
1127*5ffb0c9bSToomas Soome #endif
1128*5ffb0c9bSToomas Soome // Free DNSRecords added in DNSRegisterRecord if they have not
1129*5ffb0c9bSToomas Soome // been freed in DNSRemoveRecord
1130*5ffb0c9bSToomas Soome while (sdRef)
1131*5ffb0c9bSToomas Soome {
1132*5ffb0c9bSToomas Soome DNSServiceOp *p = sdRef;
1133*5ffb0c9bSToomas Soome sdRef = sdRef->next;
1134*5ffb0c9bSToomas Soome // When there is an error reading from the daemon e.g., bad fd, CallbackWithError
1135*5ffb0c9bSToomas Soome // is called which sets moreptr. It might set the moreptr on a subordinate sdRef
1136*5ffb0c9bSToomas Soome // but the application might call DNSServiceRefDeallocate with the main sdRef from
1137*5ffb0c9bSToomas Soome // the callback. Hence, when we loop through the subordinate sdRefs, we need
1138*5ffb0c9bSToomas Soome // to clear the moreptr so that CallbackWithError can terminate itself instead of
1139*5ffb0c9bSToomas Soome // walking through the freed sdRefs.
1140*5ffb0c9bSToomas Soome if (p->moreptr) *(p->moreptr) = 0;
1141*5ffb0c9bSToomas Soome FreeDNSServiceOp(p);
1142*5ffb0c9bSToomas Soome }
1143*5ffb0c9bSToomas Soome }
1144*5ffb0c9bSToomas Soome }
1145*5ffb0c9bSToomas Soome
DNSServiceGetProperty(const char * property,void * result,uint32_t * size)1146*5ffb0c9bSToomas Soome DNSServiceErrorType DNSSD_API DNSServiceGetProperty(const char *property, void *result, uint32_t *size)
1147*5ffb0c9bSToomas Soome {
1148*5ffb0c9bSToomas Soome char *ptr;
1149*5ffb0c9bSToomas Soome size_t len = strlen(property) + 1;
1150*5ffb0c9bSToomas Soome ipc_msg_hdr *hdr;
1151*5ffb0c9bSToomas Soome DNSServiceOp *tmp;
1152*5ffb0c9bSToomas Soome uint32_t actualsize;
1153*5ffb0c9bSToomas Soome
1154*5ffb0c9bSToomas Soome DNSServiceErrorType err = ConnectToServer(&tmp, 0, getproperty_request, NULL, NULL, NULL);
1155*5ffb0c9bSToomas Soome if (err) return err;
1156*5ffb0c9bSToomas Soome
1157*5ffb0c9bSToomas Soome hdr = create_hdr(getproperty_request, &len, &ptr, 0, tmp);
1158*5ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
1159*5ffb0c9bSToomas Soome
1160*5ffb0c9bSToomas Soome put_string(property, &ptr);
1161*5ffb0c9bSToomas Soome err = deliver_request(hdr, tmp); // Will free hdr for us
1162*5ffb0c9bSToomas Soome if (read_all(tmp->sockfd, (char*)&actualsize, (int)sizeof(actualsize)) < 0)
1163*5ffb0c9bSToomas Soome { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
1164*5ffb0c9bSToomas Soome
1165*5ffb0c9bSToomas Soome actualsize = ntohl(actualsize);
1166*5ffb0c9bSToomas Soome if (read_all(tmp->sockfd, (char*)result, actualsize < *size ? actualsize : *size) < 0)
1167*5ffb0c9bSToomas Soome { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
1168*5ffb0c9bSToomas Soome DNSServiceRefDeallocate(tmp);
1169*5ffb0c9bSToomas Soome
1170*5ffb0c9bSToomas Soome // Swap version result back to local process byte order
1171*5ffb0c9bSToomas Soome if (!strcmp(property, kDNSServiceProperty_DaemonVersion) && *size >= 4)
1172*5ffb0c9bSToomas Soome *(uint32_t*)result = ntohl(*(uint32_t*)result);
1173*5ffb0c9bSToomas Soome
1174*5ffb0c9bSToomas Soome *size = actualsize;
1175*5ffb0c9bSToomas Soome return kDNSServiceErr_NoError;
1176*5ffb0c9bSToomas Soome }
1177*5ffb0c9bSToomas Soome
DNSServiceGetPID(const uint16_t srcport,int32_t * pid)1178*5ffb0c9bSToomas Soome DNSServiceErrorType DNSSD_API DNSServiceGetPID(const uint16_t srcport, int32_t *pid)
1179*5ffb0c9bSToomas Soome {
1180*5ffb0c9bSToomas Soome char *ptr;
1181*5ffb0c9bSToomas Soome ipc_msg_hdr *hdr;
1182*5ffb0c9bSToomas Soome DNSServiceOp *tmp;
1183*5ffb0c9bSToomas Soome size_t len = sizeof(int32_t);
1184*5ffb0c9bSToomas Soome
1185*5ffb0c9bSToomas Soome DNSServiceErrorType err = ConnectToServer(&tmp, 0, getpid_request, NULL, NULL, NULL);
1186*5ffb0c9bSToomas Soome if (err)
1187*5ffb0c9bSToomas Soome return err;
1188*5ffb0c9bSToomas Soome
1189*5ffb0c9bSToomas Soome hdr = create_hdr(getpid_request, &len, &ptr, 0, tmp);
1190*5ffb0c9bSToomas Soome if (!hdr)
1191*5ffb0c9bSToomas Soome {
1192*5ffb0c9bSToomas Soome DNSServiceRefDeallocate(tmp);
1193*5ffb0c9bSToomas Soome return kDNSServiceErr_NoMemory;
1194*5ffb0c9bSToomas Soome }
1195*5ffb0c9bSToomas Soome
1196*5ffb0c9bSToomas Soome put_uint16(srcport, &ptr);
1197*5ffb0c9bSToomas Soome err = deliver_request(hdr, tmp); // Will free hdr for us
1198*5ffb0c9bSToomas Soome
1199*5ffb0c9bSToomas Soome if (read_all(tmp->sockfd, (char*)pid, sizeof(int32_t)) < 0)
1200*5ffb0c9bSToomas Soome {
1201*5ffb0c9bSToomas Soome DNSServiceRefDeallocate(tmp);
1202*5ffb0c9bSToomas Soome return kDNSServiceErr_ServiceNotRunning;
1203*5ffb0c9bSToomas Soome }
1204*5ffb0c9bSToomas Soome
1205*5ffb0c9bSToomas Soome DNSServiceRefDeallocate(tmp);
1206*5ffb0c9bSToomas Soome return kDNSServiceErr_NoError;
1207*5ffb0c9bSToomas Soome }
1208*5ffb0c9bSToomas Soome
handle_resolve_response(DNSServiceOp * const sdr,const CallbackHeader * const cbh,const char * data,const char * end)1209*5ffb0c9bSToomas Soome static void handle_resolve_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *end)
1210*5ffb0c9bSToomas Soome {
12114b22b933Srs200217 char fullname[kDNSServiceMaxDomainName];
12124b22b933Srs200217 char target[kDNSServiceMaxDomainName];
12134b22b933Srs200217 uint16_t txtlen;
12144b22b933Srs200217 union { uint16_t s; u_char b[2]; } port;
12154b22b933Srs200217 unsigned char *txtrecord;
12164b22b933Srs200217
1217*5ffb0c9bSToomas Soome get_string(&data, end, fullname, kDNSServiceMaxDomainName);
1218*5ffb0c9bSToomas Soome get_string(&data, end, target, kDNSServiceMaxDomainName);
1219*5ffb0c9bSToomas Soome if (!data || data + 2 > end) goto fail;
1220*5ffb0c9bSToomas Soome
12214b22b933Srs200217 port.b[0] = *data++;
12224b22b933Srs200217 port.b[1] = *data++;
1223*5ffb0c9bSToomas Soome txtlen = get_uint16(&data, end);
1224*5ffb0c9bSToomas Soome txtrecord = (unsigned char *)get_rdata(&data, end, txtlen);
12254b22b933Srs200217
1226*5ffb0c9bSToomas Soome if (!data) goto fail;
1227*5ffb0c9bSToomas Soome ((DNSServiceResolveReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, fullname, target, port.s, txtlen, txtrecord, sdr->AppContext);
1228*5ffb0c9bSToomas Soome return;
1229*5ffb0c9bSToomas Soome // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1230*5ffb0c9bSToomas Soome fail:
1231*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub handle_resolve_response: error reading result from daemon");
12324b22b933Srs200217 }
12334b22b933Srs200217
1234*5ffb0c9bSToomas Soome #if TARGET_OS_EMBEDDED
1235*5ffb0c9bSToomas Soome
1236*5ffb0c9bSToomas Soome static int32_t libSystemVersion = 0;
1237*5ffb0c9bSToomas Soome
1238*5ffb0c9bSToomas Soome // Return true if the iOS application linked against a version of libsystem where P2P
1239*5ffb0c9bSToomas Soome // interfaces were included by default when using kDNSServiceInterfaceIndexAny.
1240*5ffb0c9bSToomas Soome // Using 160.0.0 == 0xa00000 as the version threshold.
includeP2PWithIndexAny()1241*5ffb0c9bSToomas Soome static int includeP2PWithIndexAny()
1242*5ffb0c9bSToomas Soome {
1243*5ffb0c9bSToomas Soome if (libSystemVersion == 0)
1244*5ffb0c9bSToomas Soome libSystemVersion = NSVersionOfLinkTimeLibrary("System");
1245*5ffb0c9bSToomas Soome
1246*5ffb0c9bSToomas Soome if (libSystemVersion < 0xa00000)
1247*5ffb0c9bSToomas Soome return 1;
1248*5ffb0c9bSToomas Soome else
1249*5ffb0c9bSToomas Soome return 0;
1250*5ffb0c9bSToomas Soome }
1251*5ffb0c9bSToomas Soome
1252*5ffb0c9bSToomas Soome #else // TARGET_OS_EMBEDDED
1253*5ffb0c9bSToomas Soome
1254*5ffb0c9bSToomas Soome // always return false for non iOS platforms
includeP2PWithIndexAny()1255*5ffb0c9bSToomas Soome static int includeP2PWithIndexAny()
1256*5ffb0c9bSToomas Soome {
1257*5ffb0c9bSToomas Soome return 0;
1258*5ffb0c9bSToomas Soome }
1259*5ffb0c9bSToomas Soome
1260*5ffb0c9bSToomas Soome #endif // TARGET_OS_EMBEDDED
1261*5ffb0c9bSToomas Soome
DNSServiceResolve(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * name,const char * regtype,const char * domain,DNSServiceResolveReply callBack,void * context)12624b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceResolve
12634b22b933Srs200217 (
12644b22b933Srs200217 DNSServiceRef *sdRef,
12654b22b933Srs200217 DNSServiceFlags flags,
12664b22b933Srs200217 uint32_t interfaceIndex,
12674b22b933Srs200217 const char *name,
12684b22b933Srs200217 const char *regtype,
12694b22b933Srs200217 const char *domain,
12704b22b933Srs200217 DNSServiceResolveReply callBack,
12714b22b933Srs200217 void *context
12724b22b933Srs200217 )
12734b22b933Srs200217 {
1274*5ffb0c9bSToomas Soome char *ptr;
12754b22b933Srs200217 size_t len;
12764b22b933Srs200217 ipc_msg_hdr *hdr;
12774b22b933Srs200217 DNSServiceErrorType err;
12784b22b933Srs200217
12794b22b933Srs200217 if (!name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam;
12804b22b933Srs200217
1281*5ffb0c9bSToomas Soome // Need a real InterfaceID for WakeOnResolve
1282*5ffb0c9bSToomas Soome if ((flags & kDNSServiceFlagsWakeOnResolve) != 0 &&
1283*5ffb0c9bSToomas Soome ((interfaceIndex == kDNSServiceInterfaceIndexAny) ||
1284*5ffb0c9bSToomas Soome (interfaceIndex == kDNSServiceInterfaceIndexLocalOnly) ||
1285*5ffb0c9bSToomas Soome (interfaceIndex == kDNSServiceInterfaceIndexUnicast) ||
1286*5ffb0c9bSToomas Soome (interfaceIndex == kDNSServiceInterfaceIndexP2P)))
1287*5ffb0c9bSToomas Soome {
1288*5ffb0c9bSToomas Soome return kDNSServiceErr_BadParam;
1289*5ffb0c9bSToomas Soome }
1290*5ffb0c9bSToomas Soome
1291*5ffb0c9bSToomas Soome if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
1292*5ffb0c9bSToomas Soome flags |= kDNSServiceFlagsIncludeP2P;
1293*5ffb0c9bSToomas Soome
1294*5ffb0c9bSToomas Soome err = ConnectToServer(sdRef, flags, resolve_request, handle_resolve_response, (void *)callBack, context);
1295*5ffb0c9bSToomas Soome if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1296*5ffb0c9bSToomas Soome
1297*5ffb0c9bSToomas Soome // Calculate total message length
12984b22b933Srs200217 len = sizeof(flags);
12994b22b933Srs200217 len += sizeof(interfaceIndex);
13004b22b933Srs200217 len += strlen(name) + 1;
13014b22b933Srs200217 len += strlen(regtype) + 1;
13024b22b933Srs200217 len += strlen(domain) + 1;
13034b22b933Srs200217
1304*5ffb0c9bSToomas Soome hdr = create_hdr(resolve_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1305*5ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
13064b22b933Srs200217
13074b22b933Srs200217 put_flags(flags, &ptr);
1308*5ffb0c9bSToomas Soome put_uint32(interfaceIndex, &ptr);
13094b22b933Srs200217 put_string(name, &ptr);
13104b22b933Srs200217 put_string(regtype, &ptr);
13114b22b933Srs200217 put_string(domain, &ptr);
13124b22b933Srs200217
1313*5ffb0c9bSToomas Soome err = deliver_request(hdr, *sdRef); // Will free hdr for us
1314*5ffb0c9bSToomas Soome if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
13154b22b933Srs200217 return err;
13164b22b933Srs200217 }
13174b22b933Srs200217
handle_query_response(DNSServiceOp * const sdr,const CallbackHeader * const cbh,const char * data,const char * const end)1318*5ffb0c9bSToomas Soome static void handle_query_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
13194b22b933Srs200217 {
1320*5ffb0c9bSToomas Soome uint32_t ttl;
13214b22b933Srs200217 char name[kDNSServiceMaxDomainName];
13224b22b933Srs200217 uint16_t rrtype, rrclass, rdlen;
1323*5ffb0c9bSToomas Soome const char *rdata;
13244b22b933Srs200217
1325*5ffb0c9bSToomas Soome get_string(&data, end, name, kDNSServiceMaxDomainName);
1326*5ffb0c9bSToomas Soome rrtype = get_uint16(&data, end);
1327*5ffb0c9bSToomas Soome rrclass = get_uint16(&data, end);
1328*5ffb0c9bSToomas Soome rdlen = get_uint16(&data, end);
1329*5ffb0c9bSToomas Soome rdata = get_rdata(&data, end, rdlen);
1330*5ffb0c9bSToomas Soome ttl = get_uint32(&data, end);
13314b22b933Srs200217
1332*5ffb0c9bSToomas Soome if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_query_response: error reading result from daemon");
1333*5ffb0c9bSToomas Soome else ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, name, rrtype, rrclass, rdlen, rdata, ttl, sdr->AppContext);
1334*5ffb0c9bSToomas Soome // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
13354b22b933Srs200217 }
13364b22b933Srs200217
DNSServiceQueryRecord(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * name,uint16_t rrtype,uint16_t rrclass,DNSServiceQueryRecordReply callBack,void * context)13374b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
13384b22b933Srs200217 (
13394b22b933Srs200217 DNSServiceRef *sdRef,
13404b22b933Srs200217 DNSServiceFlags flags,
13414b22b933Srs200217 uint32_t interfaceIndex,
13424b22b933Srs200217 const char *name,
13434b22b933Srs200217 uint16_t rrtype,
13444b22b933Srs200217 uint16_t rrclass,
13454b22b933Srs200217 DNSServiceQueryRecordReply callBack,
13464b22b933Srs200217 void *context
13474b22b933Srs200217 )
13484b22b933Srs200217 {
1349*5ffb0c9bSToomas Soome char *ptr;
13504b22b933Srs200217 size_t len;
13514b22b933Srs200217 ipc_msg_hdr *hdr;
13524b22b933Srs200217 DNSServiceErrorType err;
13534b22b933Srs200217
1354*5ffb0c9bSToomas Soome if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
1355*5ffb0c9bSToomas Soome flags |= kDNSServiceFlagsIncludeP2P;
1356*5ffb0c9bSToomas Soome
1357*5ffb0c9bSToomas Soome err = ConnectToServer(sdRef, flags, query_request, handle_query_response, (void *)callBack, context);
1358*5ffb0c9bSToomas Soome if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
13594b22b933Srs200217
13604b22b933Srs200217 if (!name) name = "\0";
13614b22b933Srs200217
1362*5ffb0c9bSToomas Soome // Calculate total message length
13634b22b933Srs200217 len = sizeof(flags);
13644b22b933Srs200217 len += sizeof(uint32_t); // interfaceIndex
13654b22b933Srs200217 len += strlen(name) + 1;
13664b22b933Srs200217 len += 2 * sizeof(uint16_t); // rrtype, rrclass
13674b22b933Srs200217
1368*5ffb0c9bSToomas Soome hdr = create_hdr(query_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1369*5ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
13704b22b933Srs200217
13714b22b933Srs200217 put_flags(flags, &ptr);
1372*5ffb0c9bSToomas Soome put_uint32(interfaceIndex, &ptr);
13734b22b933Srs200217 put_string(name, &ptr);
1374*5ffb0c9bSToomas Soome put_uint16(rrtype, &ptr);
1375*5ffb0c9bSToomas Soome put_uint16(rrclass, &ptr);
13764b22b933Srs200217
1377*5ffb0c9bSToomas Soome err = deliver_request(hdr, *sdRef); // Will free hdr for us
1378*5ffb0c9bSToomas Soome if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1379*5ffb0c9bSToomas Soome return err;
1380*5ffb0c9bSToomas Soome }
1381*5ffb0c9bSToomas Soome
handle_addrinfo_response(DNSServiceOp * const sdr,const CallbackHeader * const cbh,const char * data,const char * const end)1382*5ffb0c9bSToomas Soome static void handle_addrinfo_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
1383*5ffb0c9bSToomas Soome {
1384*5ffb0c9bSToomas Soome char hostname[kDNSServiceMaxDomainName];
1385*5ffb0c9bSToomas Soome uint16_t rrtype, rdlen;
1386*5ffb0c9bSToomas Soome const char *rdata;
1387*5ffb0c9bSToomas Soome uint32_t ttl;
1388*5ffb0c9bSToomas Soome
1389*5ffb0c9bSToomas Soome get_string(&data, end, hostname, kDNSServiceMaxDomainName);
1390*5ffb0c9bSToomas Soome rrtype = get_uint16(&data, end);
1391*5ffb0c9bSToomas Soome (void) get_uint16(&data, end); /* class is not used */
1392*5ffb0c9bSToomas Soome rdlen = get_uint16(&data, end);
1393*5ffb0c9bSToomas Soome rdata = get_rdata (&data, end, rdlen);
1394*5ffb0c9bSToomas Soome ttl = get_uint32(&data, end);
1395*5ffb0c9bSToomas Soome
1396*5ffb0c9bSToomas Soome // We only generate client callbacks for A and AAAA results (including NXDOMAIN results for
1397*5ffb0c9bSToomas Soome // those types, if the client has requested those with the kDNSServiceFlagsReturnIntermediates).
1398*5ffb0c9bSToomas Soome // Other result types, specifically CNAME referrals, are not communicated to the client, because
1399*5ffb0c9bSToomas Soome // the DNSServiceGetAddrInfoReply interface doesn't have any meaningful way to communiate CNAME referrals.
1400*5ffb0c9bSToomas Soome if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_addrinfo_response: error reading result from daemon");
1401*5ffb0c9bSToomas Soome else if (rrtype == kDNSServiceType_A || rrtype == kDNSServiceType_AAAA)
1402*5ffb0c9bSToomas Soome {
1403*5ffb0c9bSToomas Soome struct sockaddr_in sa4;
1404*5ffb0c9bSToomas Soome struct sockaddr_in6 sa6;
1405*5ffb0c9bSToomas Soome const struct sockaddr *const sa = (rrtype == kDNSServiceType_A) ? (struct sockaddr*)&sa4 : (struct sockaddr*)&sa6;
1406*5ffb0c9bSToomas Soome if (rrtype == kDNSServiceType_A)
1407*5ffb0c9bSToomas Soome {
1408*5ffb0c9bSToomas Soome memset(&sa4, 0, sizeof(sa4));
1409*5ffb0c9bSToomas Soome #ifndef NOT_HAVE_SA_LEN
1410*5ffb0c9bSToomas Soome sa4.sin_len = sizeof(struct sockaddr_in);
1411*5ffb0c9bSToomas Soome #endif
1412*5ffb0c9bSToomas Soome sa4.sin_family = AF_INET;
1413*5ffb0c9bSToomas Soome // sin_port = 0;
1414*5ffb0c9bSToomas Soome if (!cbh->cb_err) memcpy(&sa4.sin_addr, rdata, rdlen);
1415*5ffb0c9bSToomas Soome }
1416*5ffb0c9bSToomas Soome else
1417*5ffb0c9bSToomas Soome {
1418*5ffb0c9bSToomas Soome memset(&sa6, 0, sizeof(sa6));
1419*5ffb0c9bSToomas Soome #ifndef NOT_HAVE_SA_LEN
1420*5ffb0c9bSToomas Soome sa6.sin6_len = sizeof(struct sockaddr_in6);
1421*5ffb0c9bSToomas Soome #endif
1422*5ffb0c9bSToomas Soome sa6.sin6_family = AF_INET6;
1423*5ffb0c9bSToomas Soome // sin6_port = 0;
1424*5ffb0c9bSToomas Soome // sin6_flowinfo = 0;
1425*5ffb0c9bSToomas Soome // sin6_scope_id = 0;
1426*5ffb0c9bSToomas Soome if (!cbh->cb_err)
1427*5ffb0c9bSToomas Soome {
1428*5ffb0c9bSToomas Soome memcpy(&sa6.sin6_addr, rdata, rdlen);
1429*5ffb0c9bSToomas Soome if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr)) sa6.sin6_scope_id = cbh->cb_interface;
1430*5ffb0c9bSToomas Soome }
1431*5ffb0c9bSToomas Soome }
1432*5ffb0c9bSToomas Soome // Validation results are always delivered separately from the actual results of the
1433*5ffb0c9bSToomas Soome // DNSServiceGetAddrInfo. Set the "addr" to NULL as per the documentation.
1434*5ffb0c9bSToomas Soome //
1435*5ffb0c9bSToomas Soome // Note: If we deliver validation results along with the "addr" in the future, we need
1436*5ffb0c9bSToomas Soome // a way to differentiate the negative response from validation-only response as both
1437*5ffb0c9bSToomas Soome // has zero address.
1438*5ffb0c9bSToomas Soome if (!(cbh->cb_flags & kDNSServiceFlagsValidate))
1439*5ffb0c9bSToomas Soome ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, sa, ttl, sdr->AppContext);
1440*5ffb0c9bSToomas Soome else
1441*5ffb0c9bSToomas Soome ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, NULL, 0, sdr->AppContext);
1442*5ffb0c9bSToomas Soome // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1443*5ffb0c9bSToomas Soome }
1444*5ffb0c9bSToomas Soome }
1445*5ffb0c9bSToomas Soome
DNSServiceGetAddrInfo(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,uint32_t protocol,const char * hostname,DNSServiceGetAddrInfoReply callBack,void * context)1446*5ffb0c9bSToomas Soome DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
1447*5ffb0c9bSToomas Soome (
1448*5ffb0c9bSToomas Soome DNSServiceRef *sdRef,
1449*5ffb0c9bSToomas Soome DNSServiceFlags flags,
1450*5ffb0c9bSToomas Soome uint32_t interfaceIndex,
1451*5ffb0c9bSToomas Soome uint32_t protocol,
1452*5ffb0c9bSToomas Soome const char *hostname,
1453*5ffb0c9bSToomas Soome DNSServiceGetAddrInfoReply callBack,
1454*5ffb0c9bSToomas Soome void *context /* may be NULL */
1455*5ffb0c9bSToomas Soome )
1456*5ffb0c9bSToomas Soome {
1457*5ffb0c9bSToomas Soome char *ptr;
1458*5ffb0c9bSToomas Soome size_t len;
1459*5ffb0c9bSToomas Soome ipc_msg_hdr *hdr;
1460*5ffb0c9bSToomas Soome DNSServiceErrorType err;
1461*5ffb0c9bSToomas Soome
1462*5ffb0c9bSToomas Soome if (!hostname) return kDNSServiceErr_BadParam;
1463*5ffb0c9bSToomas Soome
1464*5ffb0c9bSToomas Soome err = ConnectToServer(sdRef, flags, addrinfo_request, handle_addrinfo_response, (void *)callBack, context);
14654b22b933Srs200217 if (err)
14664b22b933Srs200217 {
1467*5ffb0c9bSToomas Soome return err; // On error ConnectToServer leaves *sdRef set to NULL
1468*5ffb0c9bSToomas Soome }
1469*5ffb0c9bSToomas Soome
1470*5ffb0c9bSToomas Soome // Calculate total message length
1471*5ffb0c9bSToomas Soome len = sizeof(flags);
1472*5ffb0c9bSToomas Soome len += sizeof(uint32_t); // interfaceIndex
1473*5ffb0c9bSToomas Soome len += sizeof(uint32_t); // protocol
1474*5ffb0c9bSToomas Soome len += strlen(hostname) + 1;
1475*5ffb0c9bSToomas Soome
1476*5ffb0c9bSToomas Soome hdr = create_hdr(addrinfo_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1477*5ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1478*5ffb0c9bSToomas Soome
1479*5ffb0c9bSToomas Soome put_flags(flags, &ptr);
1480*5ffb0c9bSToomas Soome put_uint32(interfaceIndex, &ptr);
1481*5ffb0c9bSToomas Soome put_uint32(protocol, &ptr);
1482*5ffb0c9bSToomas Soome put_string(hostname, &ptr);
1483*5ffb0c9bSToomas Soome
1484*5ffb0c9bSToomas Soome err = deliver_request(hdr, *sdRef); // Will free hdr for us
1485*5ffb0c9bSToomas Soome if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
14864b22b933Srs200217 return err;
14874b22b933Srs200217 }
14884b22b933Srs200217
handle_browse_response(DNSServiceOp * const sdr,const CallbackHeader * const cbh,const char * data,const char * const end)1489*5ffb0c9bSToomas Soome static void handle_browse_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
14904b22b933Srs200217 {
1491*5ffb0c9bSToomas Soome char replyName[256], replyType[kDNSServiceMaxDomainName], replyDomain[kDNSServiceMaxDomainName];
1492*5ffb0c9bSToomas Soome get_string(&data, end, replyName, 256);
1493*5ffb0c9bSToomas Soome get_string(&data, end, replyType, kDNSServiceMaxDomainName);
1494*5ffb0c9bSToomas Soome get_string(&data, end, replyDomain, kDNSServiceMaxDomainName);
1495*5ffb0c9bSToomas Soome if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_browse_response: error reading result from daemon");
1496*5ffb0c9bSToomas Soome else ((DNSServiceBrowseReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, replyName, replyType, replyDomain, sdr->AppContext);
1497*5ffb0c9bSToomas Soome // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
14984b22b933Srs200217 }
14994b22b933Srs200217
DNSServiceBrowse(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * regtype,const char * domain,DNSServiceBrowseReply callBack,void * context)15004b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceBrowse
15014b22b933Srs200217 (
15024b22b933Srs200217 DNSServiceRef *sdRef,
15034b22b933Srs200217 DNSServiceFlags flags,
15044b22b933Srs200217 uint32_t interfaceIndex,
15054b22b933Srs200217 const char *regtype,
15064b22b933Srs200217 const char *domain,
15074b22b933Srs200217 DNSServiceBrowseReply callBack,
15084b22b933Srs200217 void *context
15094b22b933Srs200217 )
15104b22b933Srs200217 {
1511*5ffb0c9bSToomas Soome char *ptr;
15124b22b933Srs200217 size_t len;
15134b22b933Srs200217 ipc_msg_hdr *hdr;
15144b22b933Srs200217 DNSServiceErrorType err;
15154b22b933Srs200217
1516*5ffb0c9bSToomas Soome if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
1517*5ffb0c9bSToomas Soome flags |= kDNSServiceFlagsIncludeP2P;
1518*5ffb0c9bSToomas Soome
1519*5ffb0c9bSToomas Soome err = ConnectToServer(sdRef, flags, browse_request, handle_browse_response, (void *)callBack, context);
1520*5ffb0c9bSToomas Soome if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
15214b22b933Srs200217
15224b22b933Srs200217 if (!domain) domain = "";
15234b22b933Srs200217 len = sizeof(flags);
15244b22b933Srs200217 len += sizeof(interfaceIndex);
15254b22b933Srs200217 len += strlen(regtype) + 1;
15264b22b933Srs200217 len += strlen(domain) + 1;
15274b22b933Srs200217
1528*5ffb0c9bSToomas Soome hdr = create_hdr(browse_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1529*5ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1530*5ffb0c9bSToomas Soome
15314b22b933Srs200217 put_flags(flags, &ptr);
1532*5ffb0c9bSToomas Soome put_uint32(interfaceIndex, &ptr);
15334b22b933Srs200217 put_string(regtype, &ptr);
15344b22b933Srs200217 put_string(domain, &ptr);
15354b22b933Srs200217
1536*5ffb0c9bSToomas Soome err = deliver_request(hdr, *sdRef); // Will free hdr for us
1537*5ffb0c9bSToomas Soome if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
15384b22b933Srs200217 return err;
15394b22b933Srs200217 }
15404b22b933Srs200217
1541*5ffb0c9bSToomas Soome DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain);
DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags,const char * domain)1542*5ffb0c9bSToomas Soome DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain)
15434b22b933Srs200217 {
1544*5ffb0c9bSToomas Soome DNSServiceOp *tmp;
1545*5ffb0c9bSToomas Soome char *ptr;
15464b22b933Srs200217 size_t len = sizeof(flags) + strlen(domain) + 1;
1547*5ffb0c9bSToomas Soome ipc_msg_hdr *hdr;
1548*5ffb0c9bSToomas Soome DNSServiceErrorType err = ConnectToServer(&tmp, 0, setdomain_request, NULL, NULL, NULL);
1549*5ffb0c9bSToomas Soome if (err) return err;
15504b22b933Srs200217
1551*5ffb0c9bSToomas Soome hdr = create_hdr(setdomain_request, &len, &ptr, 0, tmp);
1552*5ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
1553*5ffb0c9bSToomas Soome
15544b22b933Srs200217 put_flags(flags, &ptr);
15554b22b933Srs200217 put_string(domain, &ptr);
1556*5ffb0c9bSToomas Soome err = deliver_request(hdr, tmp); // Will free hdr for us
1557*5ffb0c9bSToomas Soome DNSServiceRefDeallocate(tmp);
15584b22b933Srs200217 return err;
15594b22b933Srs200217 }
15604b22b933Srs200217
handle_regservice_response(DNSServiceOp * const sdr,const CallbackHeader * const cbh,const char * data,const char * const end)1561*5ffb0c9bSToomas Soome static void handle_regservice_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
15624b22b933Srs200217 {
15634b22b933Srs200217 char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
1564*5ffb0c9bSToomas Soome get_string(&data, end, name, 256);
1565*5ffb0c9bSToomas Soome get_string(&data, end, regtype, kDNSServiceMaxDomainName);
1566*5ffb0c9bSToomas Soome get_string(&data, end, domain, kDNSServiceMaxDomainName);
1567*5ffb0c9bSToomas Soome if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_regservice_response: error reading result from daemon");
1568*5ffb0c9bSToomas Soome else ((DNSServiceRegisterReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_err, name, regtype, domain, sdr->AppContext);
1569*5ffb0c9bSToomas Soome // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
15704b22b933Srs200217 }
15714b22b933Srs200217
DNSServiceRegister(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * name,const char * regtype,const char * domain,const char * host,uint16_t PortInNetworkByteOrder,uint16_t txtLen,const void * txtRecord,DNSServiceRegisterReply callBack,void * context)15724b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceRegister
15734b22b933Srs200217 (
15744b22b933Srs200217 DNSServiceRef *sdRef,
15754b22b933Srs200217 DNSServiceFlags flags,
15764b22b933Srs200217 uint32_t interfaceIndex,
15774b22b933Srs200217 const char *name,
15784b22b933Srs200217 const char *regtype,
15794b22b933Srs200217 const char *domain,
15804b22b933Srs200217 const char *host,
15814b22b933Srs200217 uint16_t PortInNetworkByteOrder,
15824b22b933Srs200217 uint16_t txtLen,
15834b22b933Srs200217 const void *txtRecord,
15844b22b933Srs200217 DNSServiceRegisterReply callBack,
15854b22b933Srs200217 void *context
15864b22b933Srs200217 )
15874b22b933Srs200217 {
1588*5ffb0c9bSToomas Soome char *ptr;
15894b22b933Srs200217 size_t len;
15904b22b933Srs200217 ipc_msg_hdr *hdr;
15914b22b933Srs200217 DNSServiceErrorType err;
15924b22b933Srs200217 union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder };
15934b22b933Srs200217
15944b22b933Srs200217 if (!name) name = "";
15954b22b933Srs200217 if (!regtype) return kDNSServiceErr_BadParam;
15964b22b933Srs200217 if (!domain) domain = "";
15974b22b933Srs200217 if (!host) host = "";
15984b22b933Srs200217 if (!txtRecord) txtRecord = (void*)"";
15994b22b933Srs200217
1600*5ffb0c9bSToomas Soome // No callback must have auto-rename
16014b22b933Srs200217 if (!callBack && (flags & kDNSServiceFlagsNoAutoRename)) return kDNSServiceErr_BadParam;
16024b22b933Srs200217
1603*5ffb0c9bSToomas Soome if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
1604*5ffb0c9bSToomas Soome flags |= kDNSServiceFlagsIncludeP2P;
1605*5ffb0c9bSToomas Soome
1606*5ffb0c9bSToomas Soome err = ConnectToServer(sdRef, flags, reg_service_request, callBack ? handle_regservice_response : NULL, (void *)callBack, context);
1607*5ffb0c9bSToomas Soome if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1608*5ffb0c9bSToomas Soome
16094b22b933Srs200217 len = sizeof(DNSServiceFlags);
16104b22b933Srs200217 len += sizeof(uint32_t); // interfaceIndex
16114b22b933Srs200217 len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4;
16124b22b933Srs200217 len += 2 * sizeof(uint16_t); // port, txtLen
16134b22b933Srs200217 len += txtLen;
16144b22b933Srs200217
1615*5ffb0c9bSToomas Soome hdr = create_hdr(reg_service_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1616*5ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1617*5ffb0c9bSToomas Soome
1618*5ffb0c9bSToomas Soome // If it is going over a shared connection, then don't set the IPC_FLAGS_NOREPLY
1619*5ffb0c9bSToomas Soome // as it affects all the operations over the shared connection. This is not
1620*5ffb0c9bSToomas Soome // a normal case and hence receiving the response back from the daemon and
1621*5ffb0c9bSToomas Soome // discarding it in ConnectionResponse is okay.
1622*5ffb0c9bSToomas Soome
1623*5ffb0c9bSToomas Soome if (!(flags & kDNSServiceFlagsShareConnection) && !callBack) hdr->ipc_flags |= IPC_FLAGS_NOREPLY;
1624*5ffb0c9bSToomas Soome
16254b22b933Srs200217 put_flags(flags, &ptr);
1626*5ffb0c9bSToomas Soome put_uint32(interfaceIndex, &ptr);
16274b22b933Srs200217 put_string(name, &ptr);
16284b22b933Srs200217 put_string(regtype, &ptr);
16294b22b933Srs200217 put_string(domain, &ptr);
16304b22b933Srs200217 put_string(host, &ptr);
16314b22b933Srs200217 *ptr++ = port.b[0];
16324b22b933Srs200217 *ptr++ = port.b[1];
1633*5ffb0c9bSToomas Soome put_uint16(txtLen, &ptr);
16344b22b933Srs200217 put_rdata(txtLen, txtRecord, &ptr);
16354b22b933Srs200217
1636*5ffb0c9bSToomas Soome err = deliver_request(hdr, *sdRef); // Will free hdr for us
1637*5ffb0c9bSToomas Soome if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
16384b22b933Srs200217 return err;
16394b22b933Srs200217 }
16404b22b933Srs200217
handle_enumeration_response(DNSServiceOp * const sdr,const CallbackHeader * const cbh,const char * data,const char * const end)1641*5ffb0c9bSToomas Soome static void handle_enumeration_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
16424b22b933Srs200217 {
16434b22b933Srs200217 char domain[kDNSServiceMaxDomainName];
1644*5ffb0c9bSToomas Soome get_string(&data, end, domain, kDNSServiceMaxDomainName);
1645*5ffb0c9bSToomas Soome if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_enumeration_response: error reading result from daemon");
1646*5ffb0c9bSToomas Soome else ((DNSServiceDomainEnumReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, domain, sdr->AppContext);
1647*5ffb0c9bSToomas Soome // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
16484b22b933Srs200217 }
16494b22b933Srs200217
DNSServiceEnumerateDomains(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,DNSServiceDomainEnumReply callBack,void * context)16504b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
16514b22b933Srs200217 (
16524b22b933Srs200217 DNSServiceRef *sdRef,
16534b22b933Srs200217 DNSServiceFlags flags,
16544b22b933Srs200217 uint32_t interfaceIndex,
16554b22b933Srs200217 DNSServiceDomainEnumReply callBack,
16564b22b933Srs200217 void *context
16574b22b933Srs200217 )
16584b22b933Srs200217 {
1659*5ffb0c9bSToomas Soome char *ptr;
16604b22b933Srs200217 size_t len;
16614b22b933Srs200217 ipc_msg_hdr *hdr;
16624b22b933Srs200217 DNSServiceErrorType err;
1663*5ffb0c9bSToomas Soome
16644b22b933Srs200217 int f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0;
16654b22b933Srs200217 int f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0;
16664b22b933Srs200217 if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
16674b22b933Srs200217
1668*5ffb0c9bSToomas Soome err = ConnectToServer(sdRef, flags, enumeration_request, handle_enumeration_response, (void *)callBack, context);
1669*5ffb0c9bSToomas Soome if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
16704b22b933Srs200217
16714b22b933Srs200217 len = sizeof(DNSServiceFlags);
16724b22b933Srs200217 len += sizeof(uint32_t);
16734b22b933Srs200217
1674*5ffb0c9bSToomas Soome hdr = create_hdr(enumeration_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1675*5ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
16764b22b933Srs200217
16774b22b933Srs200217 put_flags(flags, &ptr);
1678*5ffb0c9bSToomas Soome put_uint32(interfaceIndex, &ptr);
16794b22b933Srs200217
1680*5ffb0c9bSToomas Soome err = deliver_request(hdr, *sdRef); // Will free hdr for us
1681*5ffb0c9bSToomas Soome if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
16824b22b933Srs200217 return err;
16834b22b933Srs200217 }
16844b22b933Srs200217
ConnectionResponse(DNSServiceOp * const sdr,const CallbackHeader * const cbh,const char * const data,const char * const end)1685*5ffb0c9bSToomas Soome static void ConnectionResponse(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *const data, const char *const end)
16864b22b933Srs200217 {
1687*5ffb0c9bSToomas Soome (void)data; // Unused
16884b22b933Srs200217
1689*5ffb0c9bSToomas Soome //printf("ConnectionResponse got %d\n", cbh->ipc_hdr.op);
1690*5ffb0c9bSToomas Soome if (cbh->ipc_hdr.op != reg_record_reply_op)
16914b22b933Srs200217 {
1692*5ffb0c9bSToomas Soome // When using kDNSServiceFlagsShareConnection, need to search the list of associated DNSServiceOps
1693*5ffb0c9bSToomas Soome // to find the one this response is intended for, and then call through to its ProcessReply handler.
1694*5ffb0c9bSToomas Soome // We start with our first subordinate DNSServiceRef -- don't want to accidentally match the parent DNSServiceRef.
1695*5ffb0c9bSToomas Soome DNSServiceOp *op = sdr->next;
1696*5ffb0c9bSToomas 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]))
1697*5ffb0c9bSToomas Soome op = op->next;
1698*5ffb0c9bSToomas Soome // Note: We may sometimes not find a matching DNSServiceOp, in the case where the client has
1699*5ffb0c9bSToomas Soome // cancelled the subordinate DNSServiceOp, but there are still messages in the pipeline from the daemon
1700*5ffb0c9bSToomas Soome if (op && op->ProcessReply) op->ProcessReply(op, cbh, data, end);
1701*5ffb0c9bSToomas Soome // WARNING: Don't touch op or sdr after this -- client may have called DNSServiceRefDeallocate
17024b22b933Srs200217 return;
17034b22b933Srs200217 }
1704*5ffb0c9bSToomas Soome else
1705*5ffb0c9bSToomas Soome {
1706*5ffb0c9bSToomas Soome DNSRecordRef rec;
1707*5ffb0c9bSToomas Soome for (rec = sdr->rec; rec; rec = rec->recnext)
1708*5ffb0c9bSToomas Soome {
1709*5ffb0c9bSToomas Soome if (rec->uid.u32[0] == cbh->ipc_hdr.client_context.u32[0] && rec->uid.u32[1] == cbh->ipc_hdr.client_context.u32[1])
1710*5ffb0c9bSToomas Soome break;
1711*5ffb0c9bSToomas Soome }
1712*5ffb0c9bSToomas Soome // The record might have been freed already and hence not an
1713*5ffb0c9bSToomas Soome // error if the record is not found.
1714*5ffb0c9bSToomas Soome if (!rec)
1715*5ffb0c9bSToomas Soome {
1716*5ffb0c9bSToomas Soome syslog(LOG_INFO, "ConnectionResponse: Record not found");
1717*5ffb0c9bSToomas Soome return;
1718*5ffb0c9bSToomas Soome }
1719*5ffb0c9bSToomas Soome if (rec->sdr != sdr)
1720*5ffb0c9bSToomas Soome {
1721*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "ConnectionResponse: Record sdr mismatch: rec %p sdr %p", rec->sdr, sdr);
1722*5ffb0c9bSToomas Soome return;
1723*5ffb0c9bSToomas Soome }
17244b22b933Srs200217
1725*5ffb0c9bSToomas Soome if (sdr->op == connection_request || sdr->op == connection_delegate_request)
1726*5ffb0c9bSToomas Soome {
1727*5ffb0c9bSToomas Soome rec->AppCallback(rec->sdr, rec, cbh->cb_flags, cbh->cb_err, rec->AppContext);
1728*5ffb0c9bSToomas Soome }
1729*5ffb0c9bSToomas Soome else
1730*5ffb0c9bSToomas Soome {
1731*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub ConnectionResponse: sdr->op != connection_request");
1732*5ffb0c9bSToomas Soome rec->AppCallback(rec->sdr, rec, 0, kDNSServiceErr_Unknown, rec->AppContext);
1733*5ffb0c9bSToomas Soome }
1734*5ffb0c9bSToomas Soome // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1735*5ffb0c9bSToomas Soome }
17364b22b933Srs200217 }
17374b22b933Srs200217
DNSServiceCreateConnection(DNSServiceRef * sdRef)17384b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef)
17394b22b933Srs200217 {
1740*5ffb0c9bSToomas Soome char *ptr;
1741*5ffb0c9bSToomas Soome size_t len = 0;
1742*5ffb0c9bSToomas Soome ipc_msg_hdr *hdr;
1743*5ffb0c9bSToomas Soome DNSServiceErrorType err = ConnectToServer(sdRef, 0, connection_request, ConnectionResponse, NULL, NULL);
1744*5ffb0c9bSToomas Soome if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1745*5ffb0c9bSToomas Soome
1746*5ffb0c9bSToomas Soome hdr = create_hdr(connection_request, &len, &ptr, 0, *sdRef);
1747*5ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1748*5ffb0c9bSToomas Soome
1749*5ffb0c9bSToomas Soome err = deliver_request(hdr, *sdRef); // Will free hdr for us
1750*5ffb0c9bSToomas Soome if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1751*5ffb0c9bSToomas Soome return err;
17524b22b933Srs200217 }
17534b22b933Srs200217
1754*5ffb0c9bSToomas Soome #if APPLE_OSX_mDNSResponder && !TARGET_IPHONE_SIMULATOR
DNSServiceCreateDelegateConnection(DNSServiceRef * sdRef,int32_t pid,uuid_t uuid)1755*5ffb0c9bSToomas Soome DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid)
1756*5ffb0c9bSToomas Soome {
1757*5ffb0c9bSToomas Soome char *ptr;
1758*5ffb0c9bSToomas Soome size_t len = 0;
1759*5ffb0c9bSToomas Soome ipc_msg_hdr *hdr;
1760*5ffb0c9bSToomas Soome
1761*5ffb0c9bSToomas Soome DNSServiceErrorType err = ConnectToServer(sdRef, 0, connection_delegate_request, ConnectionResponse, NULL, NULL);
1762*5ffb0c9bSToomas Soome if (err)
1763*5ffb0c9bSToomas Soome {
1764*5ffb0c9bSToomas Soome return err; // On error ConnectToServer leaves *sdRef set to NULL
1765*5ffb0c9bSToomas Soome }
1766*5ffb0c9bSToomas Soome
1767*5ffb0c9bSToomas Soome // Only one of the two options can be set. If pid is zero, uuid is used.
1768*5ffb0c9bSToomas Soome // If both are specified only pid will be used. We send across the pid
1769*5ffb0c9bSToomas Soome // so that the daemon knows what to read from the socket.
1770*5ffb0c9bSToomas Soome
1771*5ffb0c9bSToomas Soome len += sizeof(int32_t);
1772*5ffb0c9bSToomas Soome
1773*5ffb0c9bSToomas Soome hdr = create_hdr(connection_delegate_request, &len, &ptr, 0, *sdRef);
1774*5ffb0c9bSToomas Soome if (!hdr)
1775*5ffb0c9bSToomas Soome {
1776*5ffb0c9bSToomas Soome DNSServiceRefDeallocate(*sdRef);
1777*5ffb0c9bSToomas Soome *sdRef = NULL;
1778*5ffb0c9bSToomas Soome return kDNSServiceErr_NoMemory;
1779*5ffb0c9bSToomas Soome }
1780*5ffb0c9bSToomas Soome
1781*5ffb0c9bSToomas Soome if (pid && setsockopt((*sdRef)->sockfd, SOL_SOCKET, SO_DELEGATED, &pid, sizeof(pid)) == -1)
1782*5ffb0c9bSToomas Soome {
1783*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssdclientstub: Could not setsockopt() for PID[%d], no entitlements or process(pid) invalid errno:%d (%s)", pid, errno, strerror(errno));
1784*5ffb0c9bSToomas Soome // Free the hdr in case we return before calling deliver_request()
1785*5ffb0c9bSToomas Soome if (hdr)
1786*5ffb0c9bSToomas Soome free(hdr);
1787*5ffb0c9bSToomas Soome DNSServiceRefDeallocate(*sdRef);
1788*5ffb0c9bSToomas Soome *sdRef = NULL;
1789*5ffb0c9bSToomas Soome return kDNSServiceErr_NoAuth;
1790*5ffb0c9bSToomas Soome }
1791*5ffb0c9bSToomas Soome
1792*5ffb0c9bSToomas Soome if (!pid && setsockopt((*sdRef)->sockfd, SOL_SOCKET, SO_DELEGATED_UUID, uuid, sizeof(uuid_t)) == -1)
1793*5ffb0c9bSToomas Soome {
1794*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssdclientstub: Could not setsockopt() for UUID, no entitlements or process(uuid) invalid errno:%d (%s) ", errno, strerror(errno));
1795*5ffb0c9bSToomas Soome // Free the hdr in case we return before calling deliver_request()
1796*5ffb0c9bSToomas Soome if (hdr)
1797*5ffb0c9bSToomas Soome free(hdr);
1798*5ffb0c9bSToomas Soome DNSServiceRefDeallocate(*sdRef);
1799*5ffb0c9bSToomas Soome *sdRef = NULL;
1800*5ffb0c9bSToomas Soome return kDNSServiceErr_NoAuth;
1801*5ffb0c9bSToomas Soome }
1802*5ffb0c9bSToomas Soome
1803*5ffb0c9bSToomas Soome put_uint32(pid, &ptr);
1804*5ffb0c9bSToomas Soome
1805*5ffb0c9bSToomas Soome err = deliver_request(hdr, *sdRef); // Will free hdr for us
1806*5ffb0c9bSToomas Soome if (err)
1807*5ffb0c9bSToomas Soome {
1808*5ffb0c9bSToomas Soome DNSServiceRefDeallocate(*sdRef);
1809*5ffb0c9bSToomas Soome *sdRef = NULL;
1810*5ffb0c9bSToomas Soome }
1811*5ffb0c9bSToomas Soome return err;
1812*5ffb0c9bSToomas Soome }
1813*5ffb0c9bSToomas Soome #elif TARGET_IPHONE_SIMULATOR // This hack is for Simulator platform only
DNSServiceCreateDelegateConnection(DNSServiceRef * sdRef,int32_t pid,uuid_t uuid)1814*5ffb0c9bSToomas Soome DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid)
1815*5ffb0c9bSToomas Soome {
1816*5ffb0c9bSToomas Soome (void) pid;
1817*5ffb0c9bSToomas Soome (void) uuid;
1818*5ffb0c9bSToomas Soome return DNSServiceCreateConnection(sdRef);
1819*5ffb0c9bSToomas Soome }
1820*5ffb0c9bSToomas Soome #endif
1821*5ffb0c9bSToomas Soome
DNSServiceRegisterRecord(DNSServiceRef sdRef,DNSRecordRef * RecordRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * fullname,uint16_t rrtype,uint16_t rrclass,uint16_t rdlen,const void * rdata,uint32_t ttl,DNSServiceRegisterRecordReply callBack,void * context)18224b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
18234b22b933Srs200217 (
18244b22b933Srs200217 DNSServiceRef sdRef,
18254b22b933Srs200217 DNSRecordRef *RecordRef,
18264b22b933Srs200217 DNSServiceFlags flags,
18274b22b933Srs200217 uint32_t interfaceIndex,
18284b22b933Srs200217 const char *fullname,
18294b22b933Srs200217 uint16_t rrtype,
18304b22b933Srs200217 uint16_t rrclass,
18314b22b933Srs200217 uint16_t rdlen,
18324b22b933Srs200217 const void *rdata,
18334b22b933Srs200217 uint32_t ttl,
18344b22b933Srs200217 DNSServiceRegisterRecordReply callBack,
18354b22b933Srs200217 void *context
18364b22b933Srs200217 )
18374b22b933Srs200217 {
1838*5ffb0c9bSToomas Soome char *ptr;
18394b22b933Srs200217 size_t len;
18404b22b933Srs200217 ipc_msg_hdr *hdr = NULL;
18414b22b933Srs200217 DNSRecordRef rref = NULL;
1842*5ffb0c9bSToomas Soome DNSRecord **p;
18434b22b933Srs200217 int f1 = (flags & kDNSServiceFlagsShared) != 0;
18444b22b933Srs200217 int f2 = (flags & kDNSServiceFlagsUnique) != 0;
18454b22b933Srs200217 if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
18464b22b933Srs200217
1847*5ffb0c9bSToomas Soome if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
1848*5ffb0c9bSToomas Soome flags |= kDNSServiceFlagsIncludeP2P;
1849*5ffb0c9bSToomas Soome
1850*5ffb0c9bSToomas Soome if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
1851*5ffb0c9bSToomas Soome
1852*5ffb0c9bSToomas Soome if (!DNSServiceRefValid(sdRef))
1853*5ffb0c9bSToomas Soome {
1854*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
18554b22b933Srs200217 return kDNSServiceErr_BadReference;
1856*5ffb0c9bSToomas Soome }
1857*5ffb0c9bSToomas Soome
1858*5ffb0c9bSToomas Soome if (sdRef->op != connection_request && sdRef->op != connection_delegate_request)
1859*5ffb0c9bSToomas Soome {
1860*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with non-DNSServiceCreateConnection DNSServiceRef %p %d", sdRef, sdRef->op);
1861*5ffb0c9bSToomas Soome return kDNSServiceErr_BadReference;
1862*5ffb0c9bSToomas Soome }
1863*5ffb0c9bSToomas Soome
18644b22b933Srs200217 *RecordRef = NULL;
18654b22b933Srs200217
18664b22b933Srs200217 len = sizeof(DNSServiceFlags);
18674b22b933Srs200217 len += 2 * sizeof(uint32_t); // interfaceIndex, ttl
18684b22b933Srs200217 len += 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen
18694b22b933Srs200217 len += strlen(fullname) + 1;
18704b22b933Srs200217 len += rdlen;
18714b22b933Srs200217
1872*5ffb0c9bSToomas Soome // Bump up the uid. Normally for shared operations (kDNSServiceFlagsShareConnection), this
1873*5ffb0c9bSToomas Soome // is done in ConnectToServer. For DNSServiceRegisterRecord, ConnectToServer has already
1874*5ffb0c9bSToomas Soome // been called. As multiple DNSServiceRegisterRecords can be multiplexed over a single
1875*5ffb0c9bSToomas Soome // connection, we need a way to demultiplex the response so that the callback corresponding
1876*5ffb0c9bSToomas Soome // to the right DNSServiceRegisterRecord instance can be called. Use the same mechanism that
1877*5ffb0c9bSToomas Soome // is used by kDNSServiceFlagsShareConnection. create_hdr copies the uid value to ipc
1878*5ffb0c9bSToomas Soome // hdr->client_context which will be returned in the ipc response.
1879*5ffb0c9bSToomas Soome if (++sdRef->uid.u32[0] == 0)
1880*5ffb0c9bSToomas Soome ++sdRef->uid.u32[1];
1881*5ffb0c9bSToomas Soome hdr = create_hdr(reg_record_request, &len, &ptr, 1, sdRef);
1882*5ffb0c9bSToomas Soome if (!hdr) return kDNSServiceErr_NoMemory;
18834b22b933Srs200217
1884*5ffb0c9bSToomas Soome put_flags(flags, &ptr);
1885*5ffb0c9bSToomas Soome put_uint32(interfaceIndex, &ptr);
1886*5ffb0c9bSToomas Soome put_string(fullname, &ptr);
1887*5ffb0c9bSToomas Soome put_uint16(rrtype, &ptr);
1888*5ffb0c9bSToomas Soome put_uint16(rrclass, &ptr);
1889*5ffb0c9bSToomas Soome put_uint16(rdlen, &ptr);
1890*5ffb0c9bSToomas Soome put_rdata(rdlen, rdata, &ptr);
1891*5ffb0c9bSToomas Soome put_uint32(ttl, &ptr);
1892*5ffb0c9bSToomas Soome
1893*5ffb0c9bSToomas Soome rref = malloc(sizeof(DNSRecord));
1894*5ffb0c9bSToomas Soome if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; }
1895*5ffb0c9bSToomas Soome rref->AppContext = context;
1896*5ffb0c9bSToomas Soome rref->AppCallback = callBack;
18974b22b933Srs200217 rref->record_index = sdRef->max_index++;
18984b22b933Srs200217 rref->sdr = sdRef;
1899*5ffb0c9bSToomas Soome rref->recnext = NULL;
19004b22b933Srs200217 *RecordRef = rref;
1901*5ffb0c9bSToomas Soome // Remember the uid that we are sending across so that we can match
1902*5ffb0c9bSToomas Soome // when the response comes back.
1903*5ffb0c9bSToomas Soome rref->uid = sdRef->uid;
19044b22b933Srs200217 hdr->reg_index = rref->record_index;
19054b22b933Srs200217
1906*5ffb0c9bSToomas Soome p = &(sdRef)->rec;
1907*5ffb0c9bSToomas Soome while (*p) p = &(*p)->recnext;
1908*5ffb0c9bSToomas Soome *p = rref;
19094b22b933Srs200217
1910*5ffb0c9bSToomas Soome return deliver_request(hdr, sdRef); // Will free hdr for us
19114b22b933Srs200217 }
19124b22b933Srs200217
19134b22b933Srs200217 // sdRef returned by DNSServiceRegister()
DNSServiceAddRecord(DNSServiceRef sdRef,DNSRecordRef * RecordRef,DNSServiceFlags flags,uint16_t rrtype,uint16_t rdlen,const void * rdata,uint32_t ttl)19144b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceAddRecord
19154b22b933Srs200217 (
19164b22b933Srs200217 DNSServiceRef sdRef,
19174b22b933Srs200217 DNSRecordRef *RecordRef,
19184b22b933Srs200217 DNSServiceFlags flags,
19194b22b933Srs200217 uint16_t rrtype,
19204b22b933Srs200217 uint16_t rdlen,
19214b22b933Srs200217 const void *rdata,
19224b22b933Srs200217 uint32_t ttl
19234b22b933Srs200217 )
19244b22b933Srs200217 {
19254b22b933Srs200217 ipc_msg_hdr *hdr;
19264b22b933Srs200217 size_t len = 0;
19274b22b933Srs200217 char *ptr;
19284b22b933Srs200217 DNSRecordRef rref;
1929*5ffb0c9bSToomas Soome DNSRecord **p;
19304b22b933Srs200217
1931*5ffb0c9bSToomas Soome if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
1932*5ffb0c9bSToomas Soome if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSRecordRef pointer"); return kDNSServiceErr_BadParam; }
1933*5ffb0c9bSToomas Soome if (sdRef->op != reg_service_request)
1934*5ffb0c9bSToomas Soome {
1935*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with non-DNSServiceRegister DNSServiceRef %p %d", sdRef, sdRef->op);
19364b22b933Srs200217 return kDNSServiceErr_BadReference;
1937*5ffb0c9bSToomas Soome }
1938*5ffb0c9bSToomas Soome
1939*5ffb0c9bSToomas Soome if (!DNSServiceRefValid(sdRef))
1940*5ffb0c9bSToomas Soome {
1941*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
1942*5ffb0c9bSToomas Soome return kDNSServiceErr_BadReference;
1943*5ffb0c9bSToomas Soome }
1944*5ffb0c9bSToomas Soome
19454b22b933Srs200217 *RecordRef = NULL;
19464b22b933Srs200217
19474b22b933Srs200217 len += 2 * sizeof(uint16_t); // rrtype, rdlen
19484b22b933Srs200217 len += rdlen;
19494b22b933Srs200217 len += sizeof(uint32_t);
19504b22b933Srs200217 len += sizeof(DNSServiceFlags);
19514b22b933Srs200217
1952*5ffb0c9bSToomas Soome hdr = create_hdr(add_record_request, &len, &ptr, 1, sdRef);
1953*5ffb0c9bSToomas Soome if (!hdr) return kDNSServiceErr_NoMemory;
19544b22b933Srs200217 put_flags(flags, &ptr);
1955*5ffb0c9bSToomas Soome put_uint16(rrtype, &ptr);
1956*5ffb0c9bSToomas Soome put_uint16(rdlen, &ptr);
19574b22b933Srs200217 put_rdata(rdlen, rdata, &ptr);
1958*5ffb0c9bSToomas Soome put_uint32(ttl, &ptr);
19594b22b933Srs200217
1960*5ffb0c9bSToomas Soome rref = malloc(sizeof(DNSRecord));
1961*5ffb0c9bSToomas Soome if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; }
1962*5ffb0c9bSToomas Soome rref->AppContext = NULL;
1963*5ffb0c9bSToomas Soome rref->AppCallback = NULL;
19644b22b933Srs200217 rref->record_index = sdRef->max_index++;
19654b22b933Srs200217 rref->sdr = sdRef;
1966*5ffb0c9bSToomas Soome rref->recnext = NULL;
19674b22b933Srs200217 *RecordRef = rref;
19684b22b933Srs200217 hdr->reg_index = rref->record_index;
19694b22b933Srs200217
1970*5ffb0c9bSToomas Soome p = &(sdRef)->rec;
1971*5ffb0c9bSToomas Soome while (*p) p = &(*p)->recnext;
1972*5ffb0c9bSToomas Soome *p = rref;
1973*5ffb0c9bSToomas Soome
1974*5ffb0c9bSToomas Soome return deliver_request(hdr, sdRef); // Will free hdr for us
19754b22b933Srs200217 }
19764b22b933Srs200217
19774b22b933Srs200217 // DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
DNSServiceUpdateRecord(DNSServiceRef sdRef,DNSRecordRef RecordRef,DNSServiceFlags flags,uint16_t rdlen,const void * rdata,uint32_t ttl)19784b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
19794b22b933Srs200217 (
19804b22b933Srs200217 DNSServiceRef sdRef,
19814b22b933Srs200217 DNSRecordRef RecordRef,
19824b22b933Srs200217 DNSServiceFlags flags,
19834b22b933Srs200217 uint16_t rdlen,
19844b22b933Srs200217 const void *rdata,
19854b22b933Srs200217 uint32_t ttl
19864b22b933Srs200217 )
19874b22b933Srs200217 {
19884b22b933Srs200217 ipc_msg_hdr *hdr;
19894b22b933Srs200217 size_t len = 0;
19904b22b933Srs200217 char *ptr;
19914b22b933Srs200217
1992*5ffb0c9bSToomas Soome if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
1993*5ffb0c9bSToomas Soome
1994*5ffb0c9bSToomas Soome if (!DNSServiceRefValid(sdRef))
1995*5ffb0c9bSToomas Soome {
1996*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
1997*5ffb0c9bSToomas Soome return kDNSServiceErr_BadReference;
1998*5ffb0c9bSToomas Soome }
1999*5ffb0c9bSToomas Soome
2000*5ffb0c9bSToomas Soome // Note: RecordRef is allowed to be NULL
20014b22b933Srs200217
20024b22b933Srs200217 len += sizeof(uint16_t);
20034b22b933Srs200217 len += rdlen;
20044b22b933Srs200217 len += sizeof(uint32_t);
20054b22b933Srs200217 len += sizeof(DNSServiceFlags);
20064b22b933Srs200217
2007*5ffb0c9bSToomas Soome hdr = create_hdr(update_record_request, &len, &ptr, 1, sdRef);
2008*5ffb0c9bSToomas Soome if (!hdr) return kDNSServiceErr_NoMemory;
20094b22b933Srs200217 hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX;
20104b22b933Srs200217 put_flags(flags, &ptr);
2011*5ffb0c9bSToomas Soome put_uint16(rdlen, &ptr);
20124b22b933Srs200217 put_rdata(rdlen, rdata, &ptr);
2013*5ffb0c9bSToomas Soome put_uint32(ttl, &ptr);
2014*5ffb0c9bSToomas Soome return deliver_request(hdr, sdRef); // Will free hdr for us
20154b22b933Srs200217 }
20164b22b933Srs200217
DNSServiceRemoveRecord(DNSServiceRef sdRef,DNSRecordRef RecordRef,DNSServiceFlags flags)20174b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
20184b22b933Srs200217 (
20194b22b933Srs200217 DNSServiceRef sdRef,
20204b22b933Srs200217 DNSRecordRef RecordRef,
20214b22b933Srs200217 DNSServiceFlags flags
20224b22b933Srs200217 )
20234b22b933Srs200217 {
20244b22b933Srs200217 ipc_msg_hdr *hdr;
20254b22b933Srs200217 size_t len = 0;
20264b22b933Srs200217 char *ptr;
20274b22b933Srs200217 DNSServiceErrorType err;
20284b22b933Srs200217
2029*5ffb0c9bSToomas Soome if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
2030*5ffb0c9bSToomas Soome if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSRecordRef"); return kDNSServiceErr_BadParam; }
2031*5ffb0c9bSToomas Soome if (!sdRef->max_index) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with bad DNSServiceRef"); return kDNSServiceErr_BadReference; }
2032*5ffb0c9bSToomas Soome
2033*5ffb0c9bSToomas Soome if (!DNSServiceRefValid(sdRef))
2034*5ffb0c9bSToomas Soome {
2035*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
20364b22b933Srs200217 return kDNSServiceErr_BadReference;
2037*5ffb0c9bSToomas Soome }
20384b22b933Srs200217
20394b22b933Srs200217 len += sizeof(flags);
2040*5ffb0c9bSToomas Soome hdr = create_hdr(remove_record_request, &len, &ptr, 1, sdRef);
2041*5ffb0c9bSToomas Soome if (!hdr) return kDNSServiceErr_NoMemory;
20424b22b933Srs200217 hdr->reg_index = RecordRef->record_index;
20434b22b933Srs200217 put_flags(flags, &ptr);
2044*5ffb0c9bSToomas Soome err = deliver_request(hdr, sdRef); // Will free hdr for us
2045*5ffb0c9bSToomas Soome if (!err)
2046*5ffb0c9bSToomas Soome {
2047*5ffb0c9bSToomas Soome // This RecordRef could have been allocated in DNSServiceRegisterRecord or DNSServiceAddRecord.
2048*5ffb0c9bSToomas Soome // If so, delink from the list before freeing
2049*5ffb0c9bSToomas Soome DNSRecord **p = &sdRef->rec;
2050*5ffb0c9bSToomas Soome while (*p && *p != RecordRef) p = &(*p)->recnext;
2051*5ffb0c9bSToomas Soome if (*p) *p = RecordRef->recnext;
2052*5ffb0c9bSToomas Soome free(RecordRef);
2053*5ffb0c9bSToomas Soome }
20544b22b933Srs200217 return err;
20554b22b933Srs200217 }
20564b22b933Srs200217
DNSServiceReconfirmRecord(DNSServiceFlags flags,uint32_t interfaceIndex,const char * fullname,uint16_t rrtype,uint16_t rrclass,uint16_t rdlen,const void * rdata)20574b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
20584b22b933Srs200217 (
20594b22b933Srs200217 DNSServiceFlags flags,
20604b22b933Srs200217 uint32_t interfaceIndex,
20614b22b933Srs200217 const char *fullname,
20624b22b933Srs200217 uint16_t rrtype,
20634b22b933Srs200217 uint16_t rrclass,
20644b22b933Srs200217 uint16_t rdlen,
20654b22b933Srs200217 const void *rdata
20664b22b933Srs200217 )
20674b22b933Srs200217 {
20684b22b933Srs200217 char *ptr;
20694b22b933Srs200217 size_t len;
20704b22b933Srs200217 ipc_msg_hdr *hdr;
2071*5ffb0c9bSToomas Soome DNSServiceOp *tmp;
2072*5ffb0c9bSToomas Soome
2073*5ffb0c9bSToomas Soome DNSServiceErrorType err = ConnectToServer(&tmp, flags, reconfirm_record_request, NULL, NULL, NULL);
2074*5ffb0c9bSToomas Soome if (err) return err;
20754b22b933Srs200217
20764b22b933Srs200217 len = sizeof(DNSServiceFlags);
20774b22b933Srs200217 len += sizeof(uint32_t);
20784b22b933Srs200217 len += strlen(fullname) + 1;
20794b22b933Srs200217 len += 3 * sizeof(uint16_t);
20804b22b933Srs200217 len += rdlen;
2081*5ffb0c9bSToomas Soome hdr = create_hdr(reconfirm_record_request, &len, &ptr, 0, tmp);
2082*5ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
20834b22b933Srs200217
20844b22b933Srs200217 put_flags(flags, &ptr);
2085*5ffb0c9bSToomas Soome put_uint32(interfaceIndex, &ptr);
20864b22b933Srs200217 put_string(fullname, &ptr);
2087*5ffb0c9bSToomas Soome put_uint16(rrtype, &ptr);
2088*5ffb0c9bSToomas Soome put_uint16(rrclass, &ptr);
2089*5ffb0c9bSToomas Soome put_uint16(rdlen, &ptr);
20904b22b933Srs200217 put_rdata(rdlen, rdata, &ptr);
2091*5ffb0c9bSToomas Soome
2092*5ffb0c9bSToomas Soome err = deliver_request(hdr, tmp); // Will free hdr for us
20934b22b933Srs200217 DNSServiceRefDeallocate(tmp);
2094*5ffb0c9bSToomas Soome return err;
20954b22b933Srs200217 }
20964b22b933Srs200217
2097*5ffb0c9bSToomas Soome
handle_port_mapping_response(DNSServiceOp * const sdr,const CallbackHeader * const cbh,const char * data,const char * const end)2098*5ffb0c9bSToomas Soome static void handle_port_mapping_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
2099*5ffb0c9bSToomas Soome {
2100*5ffb0c9bSToomas Soome union { uint32_t l; u_char b[4]; } addr;
2101*5ffb0c9bSToomas Soome uint8_t protocol;
2102*5ffb0c9bSToomas Soome union { uint16_t s; u_char b[2]; } internalPort;
2103*5ffb0c9bSToomas Soome union { uint16_t s; u_char b[2]; } externalPort;
2104*5ffb0c9bSToomas Soome uint32_t ttl;
2105*5ffb0c9bSToomas Soome
2106*5ffb0c9bSToomas Soome if (!data || data + 13 > end) goto fail;
2107*5ffb0c9bSToomas Soome
2108*5ffb0c9bSToomas Soome addr.b[0] = *data++;
2109*5ffb0c9bSToomas Soome addr.b[1] = *data++;
2110*5ffb0c9bSToomas Soome addr.b[2] = *data++;
2111*5ffb0c9bSToomas Soome addr.b[3] = *data++;
2112*5ffb0c9bSToomas Soome protocol = *data++;
2113*5ffb0c9bSToomas Soome internalPort.b[0] = *data++;
2114*5ffb0c9bSToomas Soome internalPort.b[1] = *data++;
2115*5ffb0c9bSToomas Soome externalPort.b[0] = *data++;
2116*5ffb0c9bSToomas Soome externalPort.b[1] = *data++;
2117*5ffb0c9bSToomas Soome ttl = get_uint32(&data, end);
2118*5ffb0c9bSToomas Soome if (!data) goto fail;
2119*5ffb0c9bSToomas Soome
2120*5ffb0c9bSToomas Soome ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, addr.l, protocol, internalPort.s, externalPort.s, ttl, sdr->AppContext);
2121*5ffb0c9bSToomas Soome return;
2122*5ffb0c9bSToomas Soome // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
2123*5ffb0c9bSToomas Soome
2124*5ffb0c9bSToomas Soome fail :
2125*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub handle_port_mapping_response: error reading result from daemon");
2126*5ffb0c9bSToomas Soome }
2127*5ffb0c9bSToomas Soome
DNSServiceNATPortMappingCreate(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,uint32_t protocol,uint16_t internalPortInNetworkByteOrder,uint16_t externalPortInNetworkByteOrder,uint32_t ttl,DNSServiceNATPortMappingReply callBack,void * context)2128*5ffb0c9bSToomas Soome DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
2129*5ffb0c9bSToomas Soome (
2130*5ffb0c9bSToomas Soome DNSServiceRef *sdRef,
2131*5ffb0c9bSToomas Soome DNSServiceFlags flags,
2132*5ffb0c9bSToomas Soome uint32_t interfaceIndex,
2133*5ffb0c9bSToomas Soome uint32_t protocol, /* TCP and/or UDP */
2134*5ffb0c9bSToomas Soome uint16_t internalPortInNetworkByteOrder,
2135*5ffb0c9bSToomas Soome uint16_t externalPortInNetworkByteOrder,
2136*5ffb0c9bSToomas Soome uint32_t ttl, /* time to live in seconds */
2137*5ffb0c9bSToomas Soome DNSServiceNATPortMappingReply callBack,
2138*5ffb0c9bSToomas Soome void *context /* may be NULL */
2139*5ffb0c9bSToomas Soome )
2140*5ffb0c9bSToomas Soome {
2141*5ffb0c9bSToomas Soome char *ptr;
2142*5ffb0c9bSToomas Soome size_t len;
2143*5ffb0c9bSToomas Soome ipc_msg_hdr *hdr;
2144*5ffb0c9bSToomas Soome union { uint16_t s; u_char b[2]; } internalPort = { internalPortInNetworkByteOrder };
2145*5ffb0c9bSToomas Soome union { uint16_t s; u_char b[2]; } externalPort = { externalPortInNetworkByteOrder };
2146*5ffb0c9bSToomas Soome
2147*5ffb0c9bSToomas Soome DNSServiceErrorType err = ConnectToServer(sdRef, flags, port_mapping_request, handle_port_mapping_response, (void *)callBack, context);
2148*5ffb0c9bSToomas Soome if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
2149*5ffb0c9bSToomas Soome
2150*5ffb0c9bSToomas Soome len = sizeof(flags);
2151*5ffb0c9bSToomas Soome len += sizeof(interfaceIndex);
2152*5ffb0c9bSToomas Soome len += sizeof(protocol);
2153*5ffb0c9bSToomas Soome len += sizeof(internalPort);
2154*5ffb0c9bSToomas Soome len += sizeof(externalPort);
2155*5ffb0c9bSToomas Soome len += sizeof(ttl);
2156*5ffb0c9bSToomas Soome
2157*5ffb0c9bSToomas Soome hdr = create_hdr(port_mapping_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
2158*5ffb0c9bSToomas Soome if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
2159*5ffb0c9bSToomas Soome
2160*5ffb0c9bSToomas Soome put_flags(flags, &ptr);
2161*5ffb0c9bSToomas Soome put_uint32(interfaceIndex, &ptr);
2162*5ffb0c9bSToomas Soome put_uint32(protocol, &ptr);
2163*5ffb0c9bSToomas Soome *ptr++ = internalPort.b[0];
2164*5ffb0c9bSToomas Soome *ptr++ = internalPort.b[1];
2165*5ffb0c9bSToomas Soome *ptr++ = externalPort.b[0];
2166*5ffb0c9bSToomas Soome *ptr++ = externalPort.b[1];
2167*5ffb0c9bSToomas Soome put_uint32(ttl, &ptr);
2168*5ffb0c9bSToomas Soome
2169*5ffb0c9bSToomas Soome err = deliver_request(hdr, *sdRef); // Will free hdr for us
2170*5ffb0c9bSToomas Soome if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
2171*5ffb0c9bSToomas Soome return err;
2172*5ffb0c9bSToomas Soome }
2173*5ffb0c9bSToomas Soome
2174*5ffb0c9bSToomas Soome #if _DNS_SD_LIBDISPATCH
DNSServiceSetDispatchQueue(DNSServiceRef service,dispatch_queue_t queue)2175*5ffb0c9bSToomas Soome DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue
2176*5ffb0c9bSToomas Soome (
2177*5ffb0c9bSToomas Soome DNSServiceRef service,
2178*5ffb0c9bSToomas Soome dispatch_queue_t queue
2179*5ffb0c9bSToomas Soome )
2180*5ffb0c9bSToomas Soome {
2181*5ffb0c9bSToomas Soome int dnssd_fd = DNSServiceRefSockFD(service);
2182*5ffb0c9bSToomas Soome if (dnssd_fd == dnssd_InvalidSocket) return kDNSServiceErr_BadParam;
2183*5ffb0c9bSToomas Soome if (!queue)
2184*5ffb0c9bSToomas Soome {
2185*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub: DNSServiceSetDispatchQueue dispatch queue NULL");
2186*5ffb0c9bSToomas Soome return kDNSServiceErr_BadParam;
2187*5ffb0c9bSToomas Soome }
2188*5ffb0c9bSToomas Soome if (service->disp_queue)
2189*5ffb0c9bSToomas Soome {
2190*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch queue set already");
2191*5ffb0c9bSToomas Soome return kDNSServiceErr_BadParam;
2192*5ffb0c9bSToomas Soome }
2193*5ffb0c9bSToomas Soome if (service->disp_source)
2194*5ffb0c9bSToomas Soome {
2195*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch source set already");
2196*5ffb0c9bSToomas Soome return kDNSServiceErr_BadParam;
2197*5ffb0c9bSToomas Soome }
2198*5ffb0c9bSToomas Soome service->disp_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, dnssd_fd, 0, queue);
2199*5ffb0c9bSToomas Soome if (!service->disp_source)
2200*5ffb0c9bSToomas Soome {
2201*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch_source_create failed");
2202*5ffb0c9bSToomas Soome return kDNSServiceErr_NoMemory;
2203*5ffb0c9bSToomas Soome }
2204*5ffb0c9bSToomas Soome service->disp_queue = queue;
2205*5ffb0c9bSToomas Soome dispatch_source_set_event_handler(service->disp_source, ^{DNSServiceProcessResult(service);});
2206*5ffb0c9bSToomas Soome dispatch_source_set_cancel_handler(service->disp_source, ^{dnssd_close(dnssd_fd);});
2207*5ffb0c9bSToomas Soome dispatch_resume(service->disp_source);
2208*5ffb0c9bSToomas Soome return kDNSServiceErr_NoError;
2209*5ffb0c9bSToomas Soome }
2210*5ffb0c9bSToomas Soome #endif // _DNS_SD_LIBDISPATCH
2211*5ffb0c9bSToomas Soome
2212*5ffb0c9bSToomas Soome #if !defined(_WIN32)
2213*5ffb0c9bSToomas Soome
SleepKeepaliveCallback(DNSServiceRef sdRef,DNSRecordRef rec,const DNSServiceFlags flags,DNSServiceErrorType errorCode,void * context)2214*5ffb0c9bSToomas Soome static void DNSSD_API SleepKeepaliveCallback(DNSServiceRef sdRef, DNSRecordRef rec, const DNSServiceFlags flags,
2215*5ffb0c9bSToomas Soome DNSServiceErrorType errorCode, void *context)
2216*5ffb0c9bSToomas Soome {
2217*5ffb0c9bSToomas Soome SleepKAContext *ka = (SleepKAContext *)context;
2218*5ffb0c9bSToomas Soome (void)rec; // Unused
2219*5ffb0c9bSToomas Soome (void)flags; // Unused
2220*5ffb0c9bSToomas Soome
2221*5ffb0c9bSToomas Soome if (sdRef->kacontext != context)
2222*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "SleepKeepaliveCallback context mismatch");
2223*5ffb0c9bSToomas Soome
2224*5ffb0c9bSToomas Soome if (ka->AppCallback)
2225*5ffb0c9bSToomas Soome ((DNSServiceSleepKeepaliveReply)ka->AppCallback)(sdRef, errorCode, ka->AppContext);
2226*5ffb0c9bSToomas Soome }
2227*5ffb0c9bSToomas Soome
DNSServiceSleepKeepalive(DNSServiceRef * sdRef,DNSServiceFlags flags,int fd,unsigned int timeout,DNSServiceSleepKeepaliveReply callBack,void * context)2228*5ffb0c9bSToomas Soome DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
2229*5ffb0c9bSToomas Soome (
2230*5ffb0c9bSToomas Soome DNSServiceRef *sdRef,
2231*5ffb0c9bSToomas Soome DNSServiceFlags flags,
2232*5ffb0c9bSToomas Soome int fd,
2233*5ffb0c9bSToomas Soome unsigned int timeout,
2234*5ffb0c9bSToomas Soome DNSServiceSleepKeepaliveReply callBack,
2235*5ffb0c9bSToomas Soome void *context
2236*5ffb0c9bSToomas Soome )
2237*5ffb0c9bSToomas Soome {
2238*5ffb0c9bSToomas Soome char source_str[INET6_ADDRSTRLEN];
2239*5ffb0c9bSToomas Soome char target_str[INET6_ADDRSTRLEN];
2240*5ffb0c9bSToomas Soome struct sockaddr_storage lss;
2241*5ffb0c9bSToomas Soome struct sockaddr_storage rss;
2242*5ffb0c9bSToomas Soome socklen_t len1, len2;
2243*5ffb0c9bSToomas Soome unsigned int len, proxyreclen;
2244*5ffb0c9bSToomas Soome char buf[256];
2245*5ffb0c9bSToomas Soome DNSServiceErrorType err;
2246*5ffb0c9bSToomas Soome DNSRecordRef record = NULL;
2247*5ffb0c9bSToomas Soome char name[10];
2248*5ffb0c9bSToomas Soome char recname[128];
2249*5ffb0c9bSToomas Soome SleepKAContext *ka;
2250*5ffb0c9bSToomas Soome unsigned int i, unique;
2251*5ffb0c9bSToomas Soome
2252*5ffb0c9bSToomas Soome
2253*5ffb0c9bSToomas Soome (void) flags; //unused
2254*5ffb0c9bSToomas Soome if (!timeout) return kDNSServiceErr_BadParam;
2255*5ffb0c9bSToomas Soome
2256*5ffb0c9bSToomas Soome
2257*5ffb0c9bSToomas Soome len1 = sizeof(lss);
2258*5ffb0c9bSToomas Soome if (getsockname(fd, (struct sockaddr *)&lss, &len1) < 0)
2259*5ffb0c9bSToomas Soome {
2260*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getsockname %d\n", errno);
2261*5ffb0c9bSToomas Soome return kDNSServiceErr_BadParam;
2262*5ffb0c9bSToomas Soome }
2263*5ffb0c9bSToomas Soome
2264*5ffb0c9bSToomas Soome len2 = sizeof(rss);
2265*5ffb0c9bSToomas Soome if (getpeername(fd, (struct sockaddr *)&rss, &len2) < 0)
2266*5ffb0c9bSToomas Soome {
2267*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getpeername %d\n", errno);
2268*5ffb0c9bSToomas Soome return kDNSServiceErr_BadParam;
2269*5ffb0c9bSToomas Soome }
2270*5ffb0c9bSToomas Soome
2271*5ffb0c9bSToomas Soome if (len1 != len2)
2272*5ffb0c9bSToomas Soome {
2273*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive local/remote info not same");
2274*5ffb0c9bSToomas Soome return kDNSServiceErr_Unknown;
2275*5ffb0c9bSToomas Soome }
2276*5ffb0c9bSToomas Soome
2277*5ffb0c9bSToomas Soome unique = 0;
2278*5ffb0c9bSToomas Soome if (lss.ss_family == AF_INET)
2279*5ffb0c9bSToomas Soome {
2280*5ffb0c9bSToomas Soome struct sockaddr_in *sl = (struct sockaddr_in *)&lss;
2281*5ffb0c9bSToomas Soome struct sockaddr_in *sr = (struct sockaddr_in *)&rss;
2282*5ffb0c9bSToomas Soome unsigned char *ptr = (unsigned char *)&sl->sin_addr;
2283*5ffb0c9bSToomas Soome
2284*5ffb0c9bSToomas Soome if (!inet_ntop(AF_INET, (const void *)&sr->sin_addr, target_str, sizeof (target_str)))
2285*5ffb0c9bSToomas Soome {
2286*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote info failed %d", errno);
2287*5ffb0c9bSToomas Soome return kDNSServiceErr_Unknown;
2288*5ffb0c9bSToomas Soome }
2289*5ffb0c9bSToomas Soome if (!inet_ntop(AF_INET, (const void *)&sl->sin_addr, source_str, sizeof (source_str)))
2290*5ffb0c9bSToomas Soome {
2291*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive local info failed %d", errno);
2292*5ffb0c9bSToomas Soome return kDNSServiceErr_Unknown;
2293*5ffb0c9bSToomas Soome }
2294*5ffb0c9bSToomas Soome // Sum of all bytes in the local address and port should result in a unique
2295*5ffb0c9bSToomas Soome // number in the local network
2296*5ffb0c9bSToomas Soome for (i = 0; i < sizeof(struct in_addr); i++)
2297*5ffb0c9bSToomas Soome unique += ptr[i];
2298*5ffb0c9bSToomas Soome unique += sl->sin_port;
2299*5ffb0c9bSToomas 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));
2300*5ffb0c9bSToomas Soome }
2301*5ffb0c9bSToomas Soome else
2302*5ffb0c9bSToomas Soome {
2303*5ffb0c9bSToomas Soome struct sockaddr_in6 *sl6 = (struct sockaddr_in6 *)&lss;
2304*5ffb0c9bSToomas Soome struct sockaddr_in6 *sr6 = (struct sockaddr_in6 *)&rss;
2305*5ffb0c9bSToomas Soome unsigned char *ptr = (unsigned char *)&sl6->sin6_addr;
2306*5ffb0c9bSToomas Soome
2307*5ffb0c9bSToomas Soome if (!inet_ntop(AF_INET6, (const void *)&sr6->sin6_addr, target_str, sizeof (target_str)))
2308*5ffb0c9bSToomas Soome {
2309*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote6 info failed %d", errno);
2310*5ffb0c9bSToomas Soome return kDNSServiceErr_Unknown;
2311*5ffb0c9bSToomas Soome }
2312*5ffb0c9bSToomas Soome if (!inet_ntop(AF_INET6, (const void *)&sl6->sin6_addr, source_str, sizeof (source_str)))
2313*5ffb0c9bSToomas Soome {
2314*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive local6 info failed %d", errno);
2315*5ffb0c9bSToomas Soome return kDNSServiceErr_Unknown;
2316*5ffb0c9bSToomas Soome }
2317*5ffb0c9bSToomas Soome for (i = 0; i < sizeof(struct in6_addr); i++)
2318*5ffb0c9bSToomas Soome unique += ptr[i];
2319*5ffb0c9bSToomas Soome unique += sl6->sin6_port;
2320*5ffb0c9bSToomas 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));
2321*5ffb0c9bSToomas Soome }
2322*5ffb0c9bSToomas Soome
2323*5ffb0c9bSToomas Soome if (len >= (sizeof(buf) - 1))
2324*5ffb0c9bSToomas Soome {
2325*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit local/remote info");
2326*5ffb0c9bSToomas Soome return kDNSServiceErr_Unknown;
2327*5ffb0c9bSToomas Soome }
2328*5ffb0c9bSToomas Soome // Include the NULL byte also in the first byte. The total length of the record includes the
2329*5ffb0c9bSToomas Soome // first byte also.
2330*5ffb0c9bSToomas Soome buf[0] = len + 1;
2331*5ffb0c9bSToomas Soome proxyreclen = len + 2;
2332*5ffb0c9bSToomas Soome
2333*5ffb0c9bSToomas Soome len = snprintf(name, sizeof(name), "%u", unique);
2334*5ffb0c9bSToomas Soome if (len >= sizeof(name))
2335*5ffb0c9bSToomas Soome {
2336*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit unique");
2337*5ffb0c9bSToomas Soome return kDNSServiceErr_Unknown;
2338*5ffb0c9bSToomas Soome }
2339*5ffb0c9bSToomas Soome
2340*5ffb0c9bSToomas Soome len = snprintf(recname, sizeof(recname), "%s.%s", name, "_keepalive._dns-sd._udp.local");
2341*5ffb0c9bSToomas Soome if (len >= sizeof(recname))
2342*5ffb0c9bSToomas Soome {
2343*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit name");
2344*5ffb0c9bSToomas Soome return kDNSServiceErr_Unknown;
2345*5ffb0c9bSToomas Soome }
2346*5ffb0c9bSToomas Soome
2347*5ffb0c9bSToomas Soome ka = malloc(sizeof(SleepKAContext));
2348*5ffb0c9bSToomas Soome if (!ka) return kDNSServiceErr_NoMemory;
2349*5ffb0c9bSToomas Soome ka->AppCallback = (void *)callBack;
2350*5ffb0c9bSToomas Soome ka->AppContext = context;
2351*5ffb0c9bSToomas Soome
2352*5ffb0c9bSToomas Soome err = DNSServiceCreateConnection(sdRef);
2353*5ffb0c9bSToomas Soome if (err)
2354*5ffb0c9bSToomas Soome {
2355*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection");
2356*5ffb0c9bSToomas Soome free(ka);
2357*5ffb0c9bSToomas Soome return err;
2358*5ffb0c9bSToomas Soome }
2359*5ffb0c9bSToomas Soome
2360*5ffb0c9bSToomas Soome // we don't care about the "record". When sdRef gets deallocated later, it will be freed too
2361*5ffb0c9bSToomas Soome err = DNSServiceRegisterRecord(*sdRef, &record, kDNSServiceFlagsUnique, 0, recname,
2362*5ffb0c9bSToomas Soome kDNSServiceType_NULL, kDNSServiceClass_IN, proxyreclen, buf, kDNSServiceInterfaceIndexAny, SleepKeepaliveCallback, ka);
2363*5ffb0c9bSToomas Soome if (err)
2364*5ffb0c9bSToomas Soome {
2365*5ffb0c9bSToomas Soome syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection");
2366*5ffb0c9bSToomas Soome free(ka);
2367*5ffb0c9bSToomas Soome return err;
2368*5ffb0c9bSToomas Soome }
2369*5ffb0c9bSToomas Soome (*sdRef)->kacontext = ka;
2370*5ffb0c9bSToomas Soome return kDNSServiceErr_NoError;
2371*5ffb0c9bSToomas Soome }
2372*5ffb0c9bSToomas Soome #endif
2373