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