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