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