]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSShared/dnssd_clientstub.c
mDNSResponder-214.3.tar.gz
[apple/mdnsresponder.git] / mDNSShared / dnssd_clientstub.c
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 %ld/%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 %ld/%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 }