]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSShared/dnssd_clientstub.c
mDNSResponder-1310.40.42.tar.gz
[apple/mdnsresponder.git] / mDNSShared / dnssd_clientstub.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2003-2020 Apple 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 Inc. ("Apple") nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <errno.h>
30 #include <stdlib.h>
31
32 #include "dnssd_ipc.h"
33
34 #if APPLE_OSX_mDNSResponder
35 #include <mach-o/dyld.h>
36 #include <uuid/uuid.h>
37 #include <TargetConditionals.h>
38 #include "dns_sd_private.h"
39 #include "dnssd_clientstub_apple.h"
40 #include <CoreUtils/CommonServices.h>
41 #if !defined(__i386__)
42 #define CHECK_BUNDLE_VERSION 1
43 #else
44 #define CHECK_BUNDLE_VERSION 0
45 #endif
46 #endif
47
48 #if defined(_WIN32)
49
50 #define _SSIZE_T
51 #include <CommonServices.h>
52 #include <DebugServices.h>
53 #include <winsock2.h>
54 #include <ws2tcpip.h>
55 #include <windows.h>
56 #include <stdarg.h>
57 #include <stdio.h>
58
59 #define sockaddr_mdns sockaddr_in
60 #define AF_MDNS AF_INET
61
62 // Disable warning: "'type cast' : from data pointer 'void *' to function pointer"
63 #pragma warning(disable:4055)
64
65 // Disable warning: "nonstandard extension, function/data pointer conversion in expression"
66 #pragma warning(disable:4152)
67
68 extern BOOL IsSystemServiceDisabled();
69
70 #define sleep(X) Sleep((X) * 1000)
71
72 static int g_initWinsock = 0;
73 #define LOG_WARNING kDebugLevelWarning
74 #define LOG_INFO kDebugLevelInfo
75 static void syslog( int priority, const char * message, ...)
76 {
77 va_list args;
78 int len;
79 char * buffer;
80 DWORD err = WSAGetLastError();
81 (void) priority;
82 va_start( args, message );
83 len = _vscprintf( message, args ) + 1;
84 buffer = malloc( len * sizeof(char) );
85 if ( buffer ) { vsnprintf( buffer, len, message, args ); OutputDebugString( buffer ); free( buffer ); }
86 WSASetLastError( err );
87 }
88 #else
89
90 #include <fcntl.h> // For O_RDWR etc.
91 #include <sys/time.h>
92 #include <sys/socket.h>
93 #include <syslog.h>
94
95 #define sockaddr_mdns sockaddr_un
96 #define AF_MDNS AF_LOCAL
97
98 #endif
99
100 #if CHECK_BUNDLE_VERSION
101 #include "bundle_utilities.h"
102 #include <os/feature_private.h>
103 #endif
104
105 #if defined(_WIN32)
106 // <rdar://problem/4096913> Specifies how many times we'll try and connect to the server.
107
108 #define DNSSD_CLIENT_MAXTRIES 4
109 #endif // _WIN32
110
111 // Uncomment the line below to use the old error return mechanism of creating a temporary named socket (e.g. in /var/tmp)
112 //#define USE_NAMED_ERROR_RETURN_SOCKET 1
113
114 // If the UDS client has not received a response from the daemon in 60 secs, it is unlikely to get one
115 // Note: Timeout of 3 secs should be sufficient in normal scenarios, but 60 secs is chosen as a safeguard since
116 // some clients may come up before mDNSResponder itself after a BOOT and on rare ocassions IOPM/Keychain/D2D calls
117 // in mDNSResponder's INIT may take a much longer time to return
118 #define DNSSD_CLIENT_TIMEOUT 60
119
120 #ifndef CTL_PATH_PREFIX
121 #define CTL_PATH_PREFIX "/var/tmp/dnssd_result_socket."
122 #endif
123
124 typedef struct
125 {
126 ipc_msg_hdr ipc_hdr;
127 DNSServiceFlags cb_flags;
128 uint32_t cb_interface;
129 DNSServiceErrorType cb_err;
130 } CallbackHeader;
131
132 typedef struct _DNSServiceRef_t DNSServiceOp;
133 typedef struct _DNSRecordRef_t DNSRecord;
134
135 #if !defined(_WIN32)
136 typedef struct
137 {
138 void *AppCallback; // Client callback function and context
139 void *AppContext;
140 } SleepKAContext;
141 #endif
142
143 // client stub callback to process message from server and deliver results to client application
144 typedef void (*ProcessReplyFn)(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *msg, const char *const end);
145
146 #define ValidatorBits 0x12345678
147 #define DNSServiceRefValid(X) (dnssd_SocketValid((X)->sockfd) && (((X)->sockfd ^ (X)->validator) == ValidatorBits))
148
149 // When using kDNSServiceFlagsShareConnection, there is one primary _DNSServiceOp_t, and zero or more subordinates
150 // For the primary, the 'next' field points to the first subordinate, and its 'next' field points to the next, and so on.
151 // For the primary, the 'primary' field is NULL; for subordinates the 'primary' field points back to the associated primary
152 //
153 // _DNS_SD_LIBDISPATCH is defined where libdispatch/GCD is available. This does not mean that the application will use the
154 // DNSServiceSetDispatchQueue API. Hence any new code guarded with _DNS_SD_LIBDISPATCH should still be backwards compatible.
155 struct _DNSServiceRef_t
156 {
157 DNSServiceOp *next; // For shared connection
158 DNSServiceOp *primary; // For shared connection
159 dnssd_sock_t sockfd; // Connected socket between client and daemon
160 dnssd_sock_t validator; // Used to detect memory corruption, double disposals, etc.
161 client_context_t uid; // For shared connection requests, each subordinate DNSServiceRef has its own ID,
162 // unique within the scope of the same shared parent DNSServiceRef
163 uint32_t op; // request_op_t or reply_op_t
164 uint32_t max_index; // Largest assigned record index - 0 if no additional records registered
165 uint32_t logcounter; // Counter used to control number of syslog messages we write
166 int *moreptr; // Set while DNSServiceProcessResult working on this particular DNSServiceRef
167 ProcessReplyFn ProcessReply; // Function pointer to the code to handle received messages
168 void *AppCallback; // Client callback function and context
169 void *AppContext;
170 DNSRecord *rec;
171 #if _DNS_SD_LIBDISPATCH
172 dispatch_source_t disp_source;
173 dispatch_queue_t disp_queue;
174 #endif
175 void *kacontext;
176 };
177
178 struct _DNSRecordRef_t
179 {
180 DNSRecord *recnext;
181 void *AppContext;
182 DNSServiceRegisterRecordReply AppCallback;
183 DNSRecordRef recref;
184 uint32_t record_index; // index is unique to the ServiceDiscoveryRef
185 client_context_t uid; // For demultiplexing multiple DNSServiceRegisterRecord calls
186 DNSServiceOp *sdr;
187 };
188
189 #if CHECK_BUNDLE_VERSION
190 static bool _should_return_noauth_error(void)
191 {
192 static dispatch_once_t s_once = 0;
193 static bool s_should = false;
194 dispatch_once(&s_once,
195 ^{
196 s_should = bundle_sdk_is_ios14_or_later();
197 });
198 return s_should;
199 }
200 #endif
201
202 #if !defined(USE_TCP_LOOPBACK)
203 static void SetUDSPath(struct sockaddr_un *saddr, const char *path)
204 {
205 size_t pathLen;
206
207 pathLen = strlen(path);
208 if (pathLen < sizeof(saddr->sun_path))
209 memcpy(saddr->sun_path, path, pathLen + 1);
210 else
211 saddr->sun_path[0] = '\0';
212 }
213 #endif
214
215 enum { write_all_success = 0, write_all_fail = -1, write_all_defunct = -2 };
216
217 // Write len bytes. Return 0 on success, -1 on error
218 static int write_all(dnssd_sock_t sd, char *buf, size_t len)
219 {
220 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
221 //if (send(sd, buf, len, MSG_WAITALL) != len) return write_all_fail;
222 while (len)
223 {
224 ssize_t num_written = send(sd, buf, (long)len, 0);
225 if (num_written < 0 || (size_t)num_written > len)
226 {
227 // Check whether socket has gone defunct,
228 // otherwise, an error here indicates some OS bug
229 // or that the mDNSResponder daemon crashed (which should never happen).
230 #if !defined(__ppc__) && defined(SO_ISDEFUNCT)
231 int defunct = 0;
232 socklen_t dlen = sizeof (defunct);
233 if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0)
234 syslog(LOG_WARNING, "dnssd_clientstub write_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
235 if (!defunct)
236 syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
237 (long)num_written, (long)len,
238 (num_written < 0) ? dnssd_errno : 0,
239 (num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
240 else
241 syslog(LOG_INFO, "dnssd_clientstub write_all(%d) DEFUNCT", sd);
242 return defunct ? write_all_defunct : write_all_fail;
243 #else
244 syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
245 (long)num_written, (long)len,
246 (num_written < 0) ? dnssd_errno : 0,
247 (num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
248 return write_all_fail;
249 #endif
250 }
251 buf += num_written;
252 len -= num_written;
253 }
254 return write_all_success;
255 }
256
257 enum { read_all_success = 0, read_all_fail = -1, read_all_wouldblock = -2, read_all_defunct = -3 };
258
259 // Read len bytes. Return 0 on success, read_all_fail on error, or read_all_wouldblock for
260 static int read_all(dnssd_sock_t sd, char *buf, int len)
261 {
262 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
263 //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1;
264
265 while (len)
266 {
267 ssize_t num_read = recv(sd, buf, len, 0);
268 // It is valid to get an interrupted system call error e.g., somebody attaching
269 // in a debugger, retry without failing
270 if ((num_read < 0) && (errno == EINTR))
271 {
272 syslog(LOG_INFO, "dnssd_clientstub read_all: EINTR continue");
273 continue;
274 }
275 if ((num_read == 0) || (num_read < 0) || (num_read > len))
276 {
277 int printWarn = 0;
278 int defunct = 0;
279
280 // Check whether socket has gone defunct,
281 // otherwise, an error here indicates some OS bug
282 // or that the mDNSResponder daemon crashed (which should never happen).
283 #if defined(WIN32)
284 // <rdar://problem/7481776> Suppress logs for "A non-blocking socket operation
285 // could not be completed immediately"
286 if (WSAGetLastError() != WSAEWOULDBLOCK)
287 printWarn = 1;
288 #endif
289 #if !defined(__ppc__) && defined(SO_ISDEFUNCT)
290 {
291 socklen_t dlen = sizeof (defunct);
292 if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0)
293 syslog(LOG_WARNING, "dnssd_clientstub read_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
294 }
295 if (!defunct)
296 printWarn = 1;
297 #endif
298 if (printWarn)
299 syslog(LOG_WARNING, "dnssd_clientstub read_all(%d) failed %ld/%ld %d %s", sd,
300 (long)num_read, (long)len,
301 (num_read < 0) ? dnssd_errno : 0,
302 (num_read < 0) ? dnssd_strerror(dnssd_errno) : "");
303 else if (defunct)
304 syslog(LOG_INFO, "dnssd_clientstub read_all(%d) DEFUNCT", sd);
305 return (num_read < 0 && dnssd_errno == dnssd_EWOULDBLOCK) ? read_all_wouldblock : (defunct ? read_all_defunct : read_all_fail);
306 }
307 buf += num_read;
308 len -= num_read;
309 }
310 return read_all_success;
311 }
312
313 // Returns 1 if more bytes remain to be read on socket descriptor sd, 0 otherwise
314 static int more_bytes(dnssd_sock_t sd)
315 {
316 struct timeval tv = { 0, 0 };
317 fd_set readfds;
318 fd_set *fs;
319 int ret;
320
321 #if defined(_WIN32)
322 fs = &readfds;
323 FD_ZERO(fs);
324 FD_SET(sd, fs);
325 ret = select((int)sd+1, fs, (fd_set*)NULL, (fd_set*)NULL, &tv);
326 #else
327 // This whole thing would probably be better done using kevent() instead of select()
328 if (sd < FD_SETSIZE)
329 {
330 fs = &readfds;
331 FD_ZERO(fs);
332 }
333 else
334 {
335 // Compute the number of integers needed for storing "sd". Internally fd_set is stored
336 // as an array of ints with one bit for each fd and hence we need to compute
337 // the number of ints needed rather than the number of bytes. If "sd" is 32, we need
338 // two ints and not just one.
339 int nfdbits = sizeof (int) * 8;
340 int nints = (sd/nfdbits) + 1;
341 fs = (fd_set *)calloc(nints, (size_t)sizeof(int));
342 if (fs == NULL)
343 {
344 syslog(LOG_WARNING, "dnssd_clientstub more_bytes: malloc failed");
345 return 0;
346 }
347 }
348 FD_SET(sd, fs);
349 ret = select((int)sd+1, fs, (fd_set*)NULL, (fd_set*)NULL, &tv);
350 if (fs != &readfds)
351 free(fs);
352 #endif
353 return (ret > 0);
354 }
355
356 // set_waitlimit() implements a timeout using select. It is called from deliver_request() before recv() OR accept()
357 // to ensure the UDS clients are not blocked in these system calls indefinitely.
358 // Note: Ideally one should never be blocked here, because it indicates either mDNSResponder daemon is not yet up/hung/
359 // superbusy/crashed or some other OS bug. For eg: On Windows which suffers from 3rd party software
360 // (primarily 3rd party firewall software) interfering with proper functioning of the TCP protocol stack it is possible
361 // the next operation on this socket(recv/accept) is blocked since we depend on TCP to communicate with the system service.
362 static int set_waitlimit(dnssd_sock_t sock, int timeout)
363 {
364 int gDaemonErr = kDNSServiceErr_NoError;
365
366 // The comment below is wrong. The select() routine does not cause stack corruption.
367 // The use of FD_SET out of range for the bitmap is what causes stack corruption.
368 // For how to do this correctly, see the example using calloc() in more_bytes() above.
369 // Even better, both should be changed to use kevent() instead of select().
370 // To prevent stack corruption since select does not work with timeout if fds > FD_SETSIZE(1024)
371 if (!gDaemonErr && sock < FD_SETSIZE)
372 {
373 struct timeval tv;
374 fd_set set;
375
376 FD_ZERO(&set);
377 FD_SET(sock, &set);
378 tv.tv_sec = timeout;
379 tv.tv_usec = 0;
380 if (!select((int)(sock + 1), &set, NULL, NULL, &tv))
381 {
382 // Ideally one should never hit this case: See comments before set_waitlimit()
383 syslog(LOG_WARNING, "dnssd_clientstub set_waitlimit:_daemon timed out (%d secs) without any response: Socket %d", timeout, sock);
384 gDaemonErr = kDNSServiceErr_Timeout;
385 }
386 }
387 return gDaemonErr;
388 }
389
390 /* create_hdr
391 *
392 * allocate and initialize an ipc message header. Value of len should initially be the
393 * length of the data, and is set to the value of the data plus the header. data_start
394 * is set to point to the beginning of the data section. SeparateReturnSocket should be
395 * non-zero for calls that can't receive an immediate error return value on their primary
396 * socket, and therefore require a separate return path for the error code result.
397 * if zero, the path to a control socket is appended at the beginning of the message buffer.
398 * data_start is set past this string.
399 */
400 static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int SeparateReturnSocket, DNSServiceOp *ref)
401 {
402 char *msg = NULL;
403 ipc_msg_hdr *hdr;
404 int datalen;
405 #if !defined(USE_TCP_LOOPBACK)
406 char ctrl_path[64] = ""; // "/var/tmp/dnssd_result_socket.xxxxxxxxxx-xxx-xxxxxx"
407 #endif
408
409 if (SeparateReturnSocket)
410 {
411 #if defined(USE_TCP_LOOPBACK)
412 *len += 2; // Allocate space for two-byte port number
413 #elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
414 struct timeval tv;
415 if (gettimeofday(&tv, NULL) < 0)
416 { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: gettimeofday failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); return NULL; }
417 snprintf(ctrl_path, sizeof(ctrl_path), "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(),
418 (unsigned long)(tv.tv_sec & 0xFFF), (unsigned long)(tv.tv_usec));
419 *len += strlen(ctrl_path) + 1;
420 #else
421 *len += 1; // Allocate space for single zero byte (empty C string)
422 #endif
423 }
424
425 datalen = (int) *len;
426 *len += sizeof(ipc_msg_hdr);
427
428 // Write message to buffer
429 msg = malloc(*len);
430 if (!msg) { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: malloc failed"); return NULL; }
431
432 memset(msg, 0, *len);
433 hdr = (ipc_msg_hdr *)msg;
434 hdr->version = VERSION;
435 hdr->datalen = datalen;
436 hdr->ipc_flags = 0;
437 hdr->op = op;
438 hdr->client_context = ref->uid;
439 hdr->reg_index = 0;
440 *data_start = msg + sizeof(ipc_msg_hdr);
441 #if defined(USE_TCP_LOOPBACK)
442 // Put dummy data in for the port, since we don't know what it is yet.
443 // The data will get filled in before we send the message. This happens in deliver_request().
444 if (SeparateReturnSocket) put_uint16(0, data_start);
445 #else
446 if (SeparateReturnSocket) put_string(ctrl_path, data_start);
447 #endif
448 return hdr;
449 }
450
451 static void FreeDNSRecords(DNSServiceOp *sdRef)
452 {
453 DNSRecord *rec = sdRef->rec;
454 while (rec)
455 {
456 DNSRecord *next = rec->recnext;
457 free(rec);
458 rec = next;
459 }
460 }
461
462 static void FreeDNSServiceOp(DNSServiceOp *x)
463 {
464 // We don't use our DNSServiceRefValid macro here because if we're cleaning up after a socket() call failed
465 // then sockfd could legitimately contain a failing value (e.g. dnssd_InvalidSocket)
466 if ((x->sockfd ^ x->validator) != ValidatorBits)
467 {
468 }
469 else
470 {
471 x->next = NULL;
472 x->primary = NULL;
473 x->sockfd = dnssd_InvalidSocket;
474 x->validator = 0xDDDDDDDD;
475 x->op = request_op_none;
476 x->max_index = 0;
477 x->logcounter = 0;
478 x->moreptr = NULL;
479 x->ProcessReply = NULL;
480 x->AppCallback = NULL;
481 x->AppContext = NULL;
482 #if _DNS_SD_LIBDISPATCH
483 if (x->disp_source) dispatch_release(x->disp_source);
484 x->disp_source = NULL;
485 x->disp_queue = NULL;
486 #endif
487 // DNSRecords may have been added to subordinate sdRef e.g., DNSServiceRegister/DNSServiceAddRecord
488 // or on the main sdRef e.g., DNSServiceCreateConnection/DNSServiceRegisterRecord.
489 // DNSRecords may have been freed if the application called DNSRemoveRecord.
490 FreeDNSRecords(x);
491 if (x->kacontext)
492 {
493 free(x->kacontext);
494 x->kacontext = NULL;
495 }
496 free(x);
497 }
498 }
499
500 // Return a connected service ref (deallocate with DNSServiceRefDeallocate)
501 static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags flags, uint32_t op, ProcessReplyFn ProcessReply, void *AppCallback, void *AppContext)
502 {
503 #if defined(_WIN32)
504 int NumTries = 0;
505 #endif // _WIN32
506
507 dnssd_sockaddr_t saddr;
508 DNSServiceOp *sdr;
509
510 if (!ref)
511 {
512 syslog(LOG_WARNING, "dnssd_clientstub DNSService operation with NULL DNSServiceRef");
513 return kDNSServiceErr_BadParam;
514 }
515
516 if (flags & kDNSServiceFlagsShareConnection)
517 {
518 if (!*ref)
519 {
520 syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with NULL DNSServiceRef");
521 return kDNSServiceErr_BadParam;
522 }
523 if (!DNSServiceRefValid(*ref) || ((*ref)->op != connection_request && (*ref)->op != connection_delegate_request) || (*ref)->primary)
524 {
525 syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with invalid DNSServiceRef %p %08X %08X op %d",
526 (*ref), (*ref)->sockfd, (*ref)->validator, (*ref)->op);
527 *ref = NULL;
528 return kDNSServiceErr_BadReference;
529 }
530 }
531
532 #if defined(_WIN32)
533 if (!g_initWinsock)
534 {
535 WSADATA wsaData;
536 g_initWinsock = 1;
537 if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { *ref = NULL; return kDNSServiceErr_ServiceNotRunning; }
538 }
539 // <rdar://problem/4096913> If the system service is disabled, we only want to try to connect once
540 if (IsSystemServiceDisabled())
541 NumTries = DNSSD_CLIENT_MAXTRIES;
542 #endif
543
544 sdr = malloc(sizeof(DNSServiceOp));
545 if (!sdr)
546 {
547 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: malloc failed");
548 *ref = NULL;
549 return kDNSServiceErr_NoMemory;
550 }
551 sdr->next = NULL;
552 sdr->primary = NULL;
553 sdr->sockfd = dnssd_InvalidSocket;
554 sdr->validator = sdr->sockfd ^ ValidatorBits;
555 sdr->op = op;
556 sdr->max_index = 0;
557 sdr->logcounter = 0;
558 sdr->moreptr = NULL;
559 sdr->uid.u32[0] = 0;
560 sdr->uid.u32[1] = 0;
561 sdr->ProcessReply = ProcessReply;
562 sdr->AppCallback = AppCallback;
563 sdr->AppContext = AppContext;
564 sdr->rec = NULL;
565 #if _DNS_SD_LIBDISPATCH
566 sdr->disp_source = NULL;
567 sdr->disp_queue = NULL;
568 #endif
569 sdr->kacontext = NULL;
570
571 if (flags & kDNSServiceFlagsShareConnection)
572 {
573 DNSServiceOp **p = &(*ref)->next; // Append ourselves to end of primary's list
574 while (*p)
575 p = &(*p)->next;
576 *p = sdr;
577 // Preincrement counter before we use it -- it helps with debugging if we know the all-zeroes ID should never appear
578 if (++(*ref)->uid.u32[0] == 0)
579 ++(*ref)->uid.u32[1]; // In parent DNSServiceOp increment UID counter
580 sdr->primary = *ref; // Set our primary pointer
581 sdr->sockfd = (*ref)->sockfd; // Inherit primary's socket
582 sdr->validator = (*ref)->validator;
583 sdr->uid = (*ref)->uid;
584 //printf("ConnectToServer sharing socket %d\n", sdr->sockfd);
585 }
586 else
587 {
588 #ifdef SO_NOSIGPIPE
589 const unsigned long optval = 1;
590 #endif
591 #ifndef USE_TCP_LOOPBACK
592 char* uds_serverpath = getenv(MDNS_UDS_SERVERPATH_ENVVAR);
593 if (uds_serverpath == NULL)
594 uds_serverpath = MDNS_UDS_SERVERPATH;
595 else if (strlen(uds_serverpath) >= MAX_CTLPATH)
596 {
597 uds_serverpath = MDNS_UDS_SERVERPATH;
598 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: using default path since env len is invalid");
599 }
600 #endif
601 *ref = NULL;
602 sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0);
603 sdr->validator = sdr->sockfd ^ ValidatorBits;
604 if (!dnssd_SocketValid(sdr->sockfd))
605 {
606 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: socket failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
607 FreeDNSServiceOp(sdr);
608 return kDNSServiceErr_NoMemory;
609 }
610 #if !defined(_WIN32)
611 int fcntl_flags = fcntl(sdr->sockfd, F_GETFD);
612 if (fcntl_flags != -1)
613 {
614 fcntl_flags |= FD_CLOEXEC;
615 int ret = fcntl(sdr->sockfd, F_SETFD, fcntl_flags);
616 if (ret == -1)
617 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: Failed to set FD_CLOEXEC on socket %d %s",
618 dnssd_errno, dnssd_strerror(dnssd_errno));
619 }
620 else
621 {
622 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: Failed to get the file descriptor flags of socket %d %s",
623 dnssd_errno, dnssd_strerror(dnssd_errno));
624 }
625 #endif // !defined(_WIN32)
626 #ifdef SO_NOSIGPIPE
627 // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
628 if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
629 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_NOSIGPIPE failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
630 #endif
631 #if defined(USE_TCP_LOOPBACK)
632 saddr.sin_family = AF_INET;
633 saddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
634 saddr.sin_port = htons(MDNS_TCP_SERVERPORT);
635 #else
636 saddr.sun_family = AF_LOCAL;
637 SetUDSPath(&saddr, uds_serverpath);
638 #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
639 {
640 int defunct = 1;
641 if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
642 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
643 }
644 #endif
645 #endif
646
647 #if defined(_WIN32)
648 while (1)
649 {
650 int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
651 if (!err)
652 break; // If we succeeded, return sdr
653
654 // If we failed, then it may be because the daemon is still launching.
655 // This can happen for processes that launch early in the boot process, while the
656 // daemon is still coming up. Rather than fail here, we wait 1 sec and try again.
657 // If, after DNSSD_CLIENT_MAXTRIES, we still can't connect to the daemon,
658 // then we give up and return a failure code.
659 if (++NumTries < DNSSD_CLIENT_MAXTRIES)
660 {
661 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect()-> No of tries: %d", NumTries);
662 sleep(1); // Sleep a bit, then try again
663 }
664 else
665 {
666 #if !defined(USE_TCP_LOOPBACK)
667 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect() failed path:%s Socket:%d Err:%d Errno:%d %s",
668 uds_serverpath, sdr->sockfd, err, dnssd_errno, dnssd_strerror(dnssd_errno));
669 #endif
670 dnssd_close(sdr->sockfd);
671 FreeDNSServiceOp(sdr);
672 return kDNSServiceErr_ServiceNotRunning;
673 }
674 }
675 #else
676 int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
677 if (err)
678 {
679 #if !defined(USE_TCP_LOOPBACK)
680 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect() failed path:%s Socket:%d Err:%d Errno:%d %s",
681 uds_serverpath, sdr->sockfd, err, dnssd_errno, dnssd_strerror(dnssd_errno));
682 #endif
683 dnssd_close(sdr->sockfd);
684 FreeDNSServiceOp(sdr);
685 return kDNSServiceErr_ServiceNotRunning;
686 }
687 #endif
688 }
689
690 *ref = sdr;
691 return kDNSServiceErr_NoError;
692 }
693
694 #define deliver_request_bailout(MSG) \
695 do { syslog(LOG_WARNING, "dnssd_clientstub deliver_request: %s failed %d (%s)", (MSG), dnssd_errno, dnssd_strerror(dnssd_errno)); goto cleanup; } while(0)
696
697 static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
698 {
699 uint32_t datalen;
700 dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
701 DNSServiceErrorType err = kDNSServiceErr_Unknown; // Default for the "goto cleanup" cases
702 int MakeSeparateReturnSocket;
703 int ioresult;
704 #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
705 char *data;
706 #endif
707
708 if (!hdr)
709 {
710 syslog(LOG_WARNING, "dnssd_clientstub deliver_request: !hdr");
711 return kDNSServiceErr_Unknown;
712 }
713
714 datalen = hdr->datalen; // We take a copy here because we're going to convert hdr->datalen to network byte order
715 #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
716 data = (char *)hdr + sizeof(ipc_msg_hdr);
717 #endif
718
719 // Note: need to check hdr->op, not sdr->op.
720 // hdr->op contains the code for the specific operation we're currently doing, whereas sdr->op
721 // contains the original parent DNSServiceOp (e.g. for an add_record_request, hdr->op will be
722 // add_record_request but the parent sdr->op will be connection_request or reg_service_request)
723 MakeSeparateReturnSocket = (sdr->primary ||
724 hdr->op == reg_record_request || hdr->op == add_record_request || hdr->op == update_record_request || hdr->op == remove_record_request);
725
726 if (!DNSServiceRefValid(sdr))
727 {
728 if (hdr)
729 free(hdr);
730 syslog(LOG_WARNING, "dnssd_clientstub deliver_request: invalid DNSServiceRef %p %08X %08X", sdr, sdr->sockfd, sdr->validator);
731 return kDNSServiceErr_BadReference;
732 }
733
734 if (MakeSeparateReturnSocket)
735 {
736 #if defined(USE_TCP_LOOPBACK)
737 {
738 union { uint16_t s; u_char b[2]; } port;
739 dnssd_sockaddr_t caddr;
740 dnssd_socklen_t len = (dnssd_socklen_t) sizeof(caddr);
741 listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
742 if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("TCP socket");
743
744 caddr.sin_family = AF_INET;
745 caddr.sin_port = 0;
746 caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
747 if (bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr)) < 0) deliver_request_bailout("TCP bind");
748 if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) deliver_request_bailout("TCP getsockname");
749 if (listen(listenfd, 1) < 0) deliver_request_bailout("TCP listen");
750 port.s = caddr.sin_port;
751 data[0] = port.b[0]; // don't switch the byte order, as the
752 data[1] = port.b[1]; // daemon expects it in network byte order
753 }
754 #elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
755 {
756 mode_t mask;
757 int bindresult;
758 dnssd_sockaddr_t caddr;
759 listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
760 if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET socket");
761
762 caddr.sun_family = AF_LOCAL;
763 // According to Stevens (section 3.2), there is no portable way to
764 // determine whether sa_len is defined on a particular platform.
765 #ifndef NOT_HAVE_SA_LEN
766 caddr.sun_len = sizeof(struct sockaddr_un);
767 #endif
768 SetUDSPath(&caddr, data);
769 mask = umask(0);
770 bindresult = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr));
771 umask(mask);
772 if (bindresult < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET bind");
773 if (listen(listenfd, 1) < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET listen");
774 }
775 #else
776 {
777 dnssd_sock_t sp[2];
778 if (socketpair(AF_DNSSD, SOCK_STREAM, 0, sp) < 0) deliver_request_bailout("socketpair");
779 else
780 {
781 errsd = sp[0]; // We'll read our four-byte error code from sp[0]
782 listenfd = sp[1]; // We'll send sp[1] to the daemon
783 #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
784 {
785 int defunct = 1;
786 if (setsockopt(errsd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
787 syslog(LOG_WARNING, "dnssd_clientstub deliver_request: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
788 }
789 #endif
790 }
791 }
792 #endif
793 }
794
795 #if !defined(USE_TCP_LOOPBACK) && !defined(USE_NAMED_ERROR_RETURN_SOCKET)
796 // If we're going to make a separate error return socket, and pass it to the daemon
797 // using sendmsg, then we'll hold back one data byte to go with it.
798 // On some versions of Unix (including Leopard) sending a control message without
799 // any associated data does not work reliably -- e.g. one particular issue we ran
800 // into is that if the receiving program is in a kqueue loop waiting to be notified
801 // of the received message, it doesn't get woken up when the control message arrives.
802 if (MakeSeparateReturnSocket || sdr->op == send_bpf)
803 datalen--; // Okay to use sdr->op when checking for op == send_bpf
804 #endif
805
806 // At this point, our listening socket is set up and waiting, if necessary, for the daemon to connect back to
807 ConvertHeaderBytes(hdr);
808 //syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %lu bytes", (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
809 //if (MakeSeparateReturnSocket) syslog(LOG_WARNING, "dnssd_clientstub deliver_request name is %s", data);
810 #if TEST_SENDING_ONE_BYTE_AT_A_TIME
811 unsigned int i;
812 for (i=0; i<datalen + sizeof(ipc_msg_hdr); i++)
813 {
814 syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %d", i);
815 ioresult = write_all(sdr->sockfd, ((char *)hdr)+i, 1);
816 if (ioresult < write_all_success)
817 {
818 syslog(LOG_WARNING, "dnssd_clientstub deliver_request write_all (byte %u) failed", i);
819 err = (ioresult == write_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning;
820 goto cleanup;
821 }
822 usleep(10000);
823 }
824 #else
825 ioresult = write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr));
826 if (ioresult < write_all_success)
827 {
828 // write_all already prints an error message if there is an error writing to
829 // the socket except for DEFUNCT. Logging here is unnecessary and also wrong
830 // in the case of DEFUNCT sockets
831 syslog(LOG_INFO, "dnssd_clientstub deliver_request ERROR: write_all(%d, %lu bytes) failed",
832 sdr->sockfd, (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
833 err = (ioresult == write_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning;
834 goto cleanup;
835 }
836 #endif
837
838 if (!MakeSeparateReturnSocket)
839 errsd = sdr->sockfd;
840 if (MakeSeparateReturnSocket || sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
841 {
842 #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
843 // At this point we may wait in accept for a few milliseconds waiting for the daemon to connect back to us,
844 // but that's okay -- the daemon should not take more than a few milliseconds to respond.
845 // set_waitlimit() ensures we do not block indefinitely just in case something is wrong
846 dnssd_sockaddr_t daddr;
847 dnssd_socklen_t len = sizeof(daddr);
848 if ((err = set_waitlimit(listenfd, DNSSD_CLIENT_TIMEOUT)) != kDNSServiceErr_NoError)
849 goto cleanup;
850 errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
851 if (!dnssd_SocketValid(errsd))
852 deliver_request_bailout("accept");
853 #else
854
855 struct iovec vec = { ((char *)hdr) + sizeof(ipc_msg_hdr) + datalen, 1 }; // Send the last byte along with the SCM_RIGHTS
856 struct msghdr msg;
857 struct cmsghdr *cmsg;
858 char cbuf[CMSG_SPACE(4 * sizeof(dnssd_sock_t))];
859
860 msg.msg_name = 0;
861 msg.msg_namelen = 0;
862 msg.msg_iov = &vec;
863 msg.msg_iovlen = 1;
864 msg.msg_flags = 0;
865 if (MakeSeparateReturnSocket || sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
866 {
867 if (sdr->op == send_bpf)
868 {
869 int i;
870 char p[12]; // Room for "/dev/bpf999" with terminating null
871 for (i=0; i<100; i++)
872 {
873 snprintf(p, sizeof(p), "/dev/bpf%d", i);
874 listenfd = open(p, O_RDWR, 0);
875 //if (dnssd_SocketValid(listenfd)) syslog(LOG_WARNING, "dnssd_clientstub deliver_request Sending fd %d for %s", listenfd, p);
876 if (!dnssd_SocketValid(listenfd) && dnssd_errno != EBUSY)
877 syslog(LOG_WARNING, "dnssd_clientstub deliver_request Error opening %s %d (%s)", p, dnssd_errno, dnssd_strerror(dnssd_errno));
878 if (dnssd_SocketValid(listenfd) || dnssd_errno != EBUSY) break;
879 }
880 }
881 msg.msg_control = cbuf;
882 msg.msg_controllen = CMSG_LEN(sizeof(dnssd_sock_t));
883
884 cmsg = CMSG_FIRSTHDR(&msg);
885 cmsg->cmsg_len = CMSG_LEN(sizeof(dnssd_sock_t));
886 cmsg->cmsg_level = SOL_SOCKET;
887 cmsg->cmsg_type = SCM_RIGHTS;
888 *((dnssd_sock_t *)CMSG_DATA(cmsg)) = listenfd;
889 }
890
891 #if TEST_KQUEUE_CONTROL_MESSAGE_BUG
892 sleep(1);
893 #endif
894
895 #if DEBUG_64BIT_SCM_RIGHTS
896 syslog(LOG_WARNING, "dnssd_clientstub deliver_request sendmsg read sd=%d write sd=%d %ld %ld %ld/%ld/%ld/%ld",
897 errsd, listenfd, sizeof(dnssd_sock_t), sizeof(void*),
898 sizeof(struct cmsghdr) + sizeof(dnssd_sock_t),
899 CMSG_LEN(sizeof(dnssd_sock_t)), (long)CMSG_SPACE(sizeof(dnssd_sock_t)),
900 (long)((char*)CMSG_DATA(cmsg) + 4 - cbuf));
901 #endif // DEBUG_64BIT_SCM_RIGHTS
902
903 if (sendmsg(sdr->sockfd, &msg, 0) < 0)
904 {
905 syslog(LOG_WARNING, "dnssd_clientstub deliver_request ERROR: sendmsg failed read sd=%d write sd=%d errno %d (%s)",
906 errsd, listenfd, dnssd_errno, dnssd_strerror(dnssd_errno));
907 err = kDNSServiceErr_Incompatible;
908 goto cleanup;
909 }
910
911 #if DEBUG_64BIT_SCM_RIGHTS
912 syslog(LOG_WARNING, "dnssd_clientstub deliver_request sendmsg read sd=%d write sd=%d okay", errsd, listenfd);
913 #endif // DEBUG_64BIT_SCM_RIGHTS
914
915 #endif
916 // Close our end of the socketpair *before* calling read_all() to get the four-byte error code.
917 // Otherwise, if the daemon closes our socket (or crashes), we will have to wait for a timeout
918 // in read_all() because the socket is not closed (we still have an open reference to it)
919 // Note: listenfd is overwritten in the case of send_bpf above and that will be closed here
920 // for send_bpf operation.
921 dnssd_close(listenfd);
922 listenfd = dnssd_InvalidSocket; // Make sure we don't close it a second time in the cleanup handling below
923 }
924
925 // At this point we may wait in read_all for a few milliseconds waiting for the daemon to send us the error code,
926 // but that's okay -- the daemon should not take more than a few milliseconds to respond.
927 // set_waitlimit() ensures we do not block indefinitely just in case something is wrong
928 if (sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
929 err = kDNSServiceErr_NoError;
930 else if ((err = set_waitlimit(errsd, DNSSD_CLIENT_TIMEOUT)) == kDNSServiceErr_NoError)
931 {
932 ioresult = read_all(errsd, (char*)&err, (int)sizeof(err));
933 if (ioresult < read_all_success)
934 err = (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us
935 else
936 err = ntohl(err);
937 }
938 //syslog(LOG_WARNING, "dnssd_clientstub deliver_request: retrieved error code %d", err);
939
940 cleanup:
941 if (MakeSeparateReturnSocket)
942 {
943 if (dnssd_SocketValid(listenfd)) dnssd_close(listenfd);
944 if (dnssd_SocketValid(errsd)) dnssd_close(errsd);
945 #if defined(USE_NAMED_ERROR_RETURN_SOCKET)
946 // syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removing UDS: %s", data);
947 if (unlink(data) != 0)
948 syslog(LOG_WARNING, "dnssd_clientstub WARNING: unlink(\"%s\") failed errno %d (%s)", data, dnssd_errno, dnssd_strerror(dnssd_errno));
949 // else syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removed UDS: %s", data);
950 #endif
951 }
952
953 free(hdr);
954 return err;
955 }
956
957 dnssd_sock_t DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef)
958 {
959 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with NULL DNSServiceRef"); return dnssd_InvalidSocket; }
960
961 if (!DNSServiceRefValid(sdRef))
962 {
963 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with invalid DNSServiceRef %p %08X %08X",
964 sdRef, sdRef->sockfd, sdRef->validator);
965 return dnssd_InvalidSocket;
966 }
967
968 if (sdRef->primary)
969 {
970 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
971 return dnssd_InvalidSocket;
972 }
973
974 return sdRef->sockfd;
975 }
976
977 #if _DNS_SD_LIBDISPATCH
978 static void CallbackWithError(DNSServiceRef sdRef, DNSServiceErrorType error)
979 {
980 DNSServiceOp *sdr = sdRef;
981 DNSServiceOp *sdrNext;
982 DNSRecord *rec;
983 DNSRecord *recnext;
984 int morebytes;
985
986 while (sdr)
987 {
988 // We can't touch the sdr after the callback as it can be deallocated in the callback
989 sdrNext = sdr->next;
990 morebytes = 1;
991 sdr->moreptr = &morebytes;
992 switch (sdr->op)
993 {
994 case resolve_request:
995 if (sdr->AppCallback) ((DNSServiceResolveReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, sdr->AppContext);
996 break;
997 case query_request:
998 if (sdr->AppCallback) ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, 0, sdr->AppContext);
999 break;
1000 case addrinfo_request:
1001 if (sdr->AppCallback) ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, NULL, 0, sdr->AppContext);
1002 break;
1003 case browse_request:
1004 if (sdr->AppCallback) ((DNSServiceBrowseReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, NULL, sdr->AppContext);
1005 break;
1006 case reg_service_request:
1007 if (sdr->AppCallback) ((DNSServiceRegisterReply) sdr->AppCallback)(sdr, 0, error, NULL, 0, NULL, sdr->AppContext);
1008 break;
1009 case enumeration_request:
1010 if (sdr->AppCallback) ((DNSServiceDomainEnumReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, sdr->AppContext);
1011 break;
1012 case connection_request:
1013 case connection_delegate_request:
1014 // This means Register Record, walk the list of DNSRecords to do the callback
1015 rec = sdr->rec;
1016 while (rec)
1017 {
1018 recnext = rec->recnext;
1019 if (rec->AppCallback) ((DNSServiceRegisterRecordReply)rec->AppCallback)(sdr, 0, 0, error, rec->AppContext);
1020 // The Callback can call DNSServiceRefDeallocate which in turn frees sdr and all the records.
1021 // Detect that and return early
1022 if (!morebytes) { syslog(LOG_WARNING, "dnssd_clientstub:Record: CallbackwithError morebytes zero"); return; }
1023 rec = recnext;
1024 }
1025 break;
1026 case port_mapping_request:
1027 if (sdr->AppCallback) ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, 0, 0, error, 0, 0, 0, 0, 0, sdr->AppContext);
1028 break;
1029 default:
1030 syslog(LOG_WARNING, "dnssd_clientstub CallbackWithError called with bad op %d", sdr->op);
1031 }
1032 // If DNSServiceRefDeallocate was called in the callback, morebytes will be zero. As the sdRef
1033 // (and its subordinates) have been freed, we should not proceed further. Note that when we
1034 // call the callback with a subordinate sdRef the application can call DNSServiceRefDeallocate
1035 // on the main sdRef and DNSServiceRefDeallocate handles this case by walking all the sdRefs and
1036 // clears the moreptr so that we can terminate here.
1037 //
1038 // If DNSServiceRefDeallocate was not called in the callback, then set moreptr to NULL so that
1039 // we don't access the stack variable after we return from this function.
1040 if (!morebytes) { syslog(LOG_WARNING, "dnssd_clientstub:sdRef: CallbackwithError morebytes zero sdr %p", sdr); return; }
1041 else {sdr->moreptr = NULL;}
1042 sdr = sdrNext;
1043 }
1044 }
1045 #endif // _DNS_SD_LIBDISPATCH
1046
1047 // Handle reply from server, calling application client callback. If there is no reply
1048 // from the daemon on the socket contained in sdRef, the call will block.
1049 DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
1050 {
1051 int morebytes = 0;
1052 int ioresult;
1053 DNSServiceErrorType error;
1054
1055 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
1056
1057 if (!DNSServiceRefValid(sdRef))
1058 {
1059 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
1060 return kDNSServiceErr_BadReference;
1061 }
1062
1063 if (sdRef->primary)
1064 {
1065 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
1066 return kDNSServiceErr_BadReference;
1067 }
1068
1069 if (!sdRef->ProcessReply)
1070 {
1071 static int num_logs = 0;
1072 if (num_logs < 10) syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function");
1073 if (num_logs < 1000) num_logs++;else sleep(1);
1074 return kDNSServiceErr_BadReference;
1075 }
1076
1077 do
1078 {
1079 CallbackHeader cbh;
1080 char *data;
1081
1082 // return NoError on EWOULDBLOCK. This will handle the case
1083 // where a non-blocking socket is told there is data, but it was a false positive.
1084 // On error, read_all will write a message to syslog for us, so don't need to duplicate that here
1085 // Note: If we want to properly support using non-blocking sockets in the future
1086 ioresult = read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr));
1087 if (ioresult == read_all_fail || ioresult == read_all_defunct)
1088 {
1089 error = (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning;
1090
1091 // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
1092 // in the callback.
1093 sdRef->ProcessReply = NULL;
1094 #if _DNS_SD_LIBDISPATCH
1095 // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
1096 // is not called by the application and hence need to communicate the error. Cancel the
1097 // source so that we don't get any more events
1098 // Note: read_all fails if we could not read from the daemon which can happen if the
1099 // daemon dies or the file descriptor is disconnected (defunct).
1100 if (sdRef->disp_source)
1101 {
1102 dispatch_source_cancel(sdRef->disp_source);
1103 dispatch_release(sdRef->disp_source);
1104 sdRef->disp_source = NULL;
1105 CallbackWithError(sdRef, error);
1106 }
1107 #endif
1108 // Don't touch sdRef anymore as it might have been deallocated
1109 return error;
1110 }
1111 else if (ioresult == read_all_wouldblock)
1112 {
1113 if (morebytes && sdRef->logcounter < 100)
1114 {
1115 sdRef->logcounter++;
1116 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult error: select indicated data was waiting but read_all returned EWOULDBLOCK");
1117 }
1118 return kDNSServiceErr_NoError;
1119 }
1120
1121 ConvertHeaderBytes(&cbh.ipc_hdr);
1122 if (cbh.ipc_hdr.version != VERSION)
1123 {
1124 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult daemon version %d does not match client version %d", cbh.ipc_hdr.version, VERSION);
1125 sdRef->ProcessReply = NULL;
1126 return kDNSServiceErr_Incompatible;
1127 }
1128
1129 data = malloc(cbh.ipc_hdr.datalen);
1130 if (!data) return kDNSServiceErr_NoMemory;
1131 ioresult = read_all(sdRef->sockfd, data, cbh.ipc_hdr.datalen);
1132 if (ioresult < read_all_success) // On error, read_all will write a message to syslog for us
1133 {
1134 error = (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning;
1135
1136 // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
1137 // in the callback.
1138 sdRef->ProcessReply = NULL;
1139 #if _DNS_SD_LIBDISPATCH
1140 // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
1141 // is not called by the application and hence need to communicate the error. Cancel the
1142 // source so that we don't get any more events
1143 if (sdRef->disp_source)
1144 {
1145 dispatch_source_cancel(sdRef->disp_source);
1146 dispatch_release(sdRef->disp_source);
1147 sdRef->disp_source = NULL;
1148 CallbackWithError(sdRef, error);
1149 }
1150 #endif
1151 // Don't touch sdRef anymore as it might have been deallocated
1152 free(data);
1153 return error;
1154 }
1155 else
1156 {
1157 const char *ptr = data;
1158 cbh.cb_flags = get_flags (&ptr, data + cbh.ipc_hdr.datalen);
1159 cbh.cb_interface = get_uint32 (&ptr, data + cbh.ipc_hdr.datalen);
1160 cbh.cb_err = get_error_code(&ptr, data + cbh.ipc_hdr.datalen);
1161
1162 // CAUTION: We have to handle the case where the client calls DNSServiceRefDeallocate from within the callback function.
1163 // To do this we set moreptr to point to morebytes. If the client does call DNSServiceRefDeallocate(),
1164 // then that routine will clear morebytes for us, and cause us to exit our loop.
1165 morebytes = more_bytes(sdRef->sockfd);
1166 if (morebytes)
1167 {
1168 cbh.cb_flags |= kDNSServiceFlagsMoreComing;
1169 sdRef->moreptr = &morebytes;
1170 }
1171 if (ptr) sdRef->ProcessReply(sdRef, &cbh, ptr, data + cbh.ipc_hdr.datalen);
1172 // Careful code here:
1173 // If morebytes is non-zero, that means we set sdRef->moreptr above, and the operation was not
1174 // cancelled out from under us, so now we need to clear sdRef->moreptr so we don't leave a stray
1175 // dangling pointer pointing to a long-gone stack variable.
1176 // If morebytes is zero, then one of two thing happened:
1177 // (a) morebytes was 0 above, so we didn't set sdRef->moreptr, so we don't need to clear it
1178 // (b) morebytes was 1 above, and we set sdRef->moreptr, but the operation was cancelled (with DNSServiceRefDeallocate()),
1179 // so we MUST NOT try to dereference our stale sdRef pointer.
1180 if (morebytes) sdRef->moreptr = NULL;
1181 }
1182 free(data);
1183 } while (morebytes);
1184
1185 return kDNSServiceErr_NoError;
1186 }
1187
1188 void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef)
1189 {
1190 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with NULL DNSServiceRef"); return; }
1191
1192 if (!DNSServiceRefValid(sdRef)) // Also verifies dnssd_SocketValid(sdRef->sockfd) for us too
1193 {
1194 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
1195 return;
1196 }
1197
1198 // 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
1199 if (sdRef->moreptr) *(sdRef->moreptr) = 0;
1200
1201 if (sdRef->primary) // If this is a subordinate DNSServiceOp, just send a 'stop' command
1202 {
1203 DNSServiceOp **p = &sdRef->primary->next;
1204 while (*p && *p != sdRef) p = &(*p)->next;
1205 if (*p)
1206 {
1207 char *ptr;
1208 size_t len = 0;
1209 ipc_msg_hdr *hdr = create_hdr(cancel_request, &len, &ptr, 0, sdRef);
1210 if (hdr)
1211 {
1212 ConvertHeaderBytes(hdr);
1213 write_all(sdRef->sockfd, (char *)hdr, len);
1214 free(hdr);
1215 }
1216 *p = sdRef->next;
1217 FreeDNSServiceOp(sdRef);
1218 }
1219 }
1220 else // else, make sure to terminate all subordinates as well
1221 {
1222 #if _DNS_SD_LIBDISPATCH
1223 // The cancel handler will close the fd if a dispatch source has been set
1224 if (sdRef->disp_source)
1225 {
1226 // By setting the ProcessReply to NULL, we make sure that we never call
1227 // the application callbacks ever, after returning from this function. We
1228 // assume that DNSServiceRefDeallocate is called from the serial queue
1229 // that was passed to DNSServiceSetDispatchQueue. Hence, dispatch_source_cancel
1230 // should cancel all the blocks on the queue and hence there should be no more
1231 // callbacks when we return from this function. Setting ProcessReply to NULL
1232 // provides extra protection.
1233 sdRef->ProcessReply = NULL;
1234 shutdown(sdRef->sockfd, SHUT_WR);
1235 dispatch_source_cancel(sdRef->disp_source);
1236 dispatch_release(sdRef->disp_source);
1237 sdRef->disp_source = NULL;
1238 }
1239 // if disp_queue is set, it means it used the DNSServiceSetDispatchQueue API. In that case,
1240 // when the source was cancelled, the fd was closed in the handler. Currently the source
1241 // is cancelled only when the mDNSResponder daemon dies
1242 else if (!sdRef->disp_queue) dnssd_close(sdRef->sockfd);
1243 #else
1244 dnssd_close(sdRef->sockfd);
1245 #endif
1246 // Free DNSRecords added in DNSRegisterRecord if they have not
1247 // been freed in DNSRemoveRecord
1248 while (sdRef)
1249 {
1250 DNSServiceOp *p = sdRef;
1251 sdRef = sdRef->next;
1252 // When there is an error reading from the daemon e.g., bad fd, CallbackWithError
1253 // is called which sets moreptr. It might set the moreptr on a subordinate sdRef
1254 // but the application might call DNSServiceRefDeallocate with the main sdRef from
1255 // the callback. Hence, when we loop through the subordinate sdRefs, we need
1256 // to clear the moreptr so that CallbackWithError can terminate itself instead of
1257 // walking through the freed sdRefs.
1258 if (p->moreptr) *(p->moreptr) = 0;
1259 FreeDNSServiceOp(p);
1260 }
1261 }
1262 }
1263
1264 DNSServiceErrorType DNSSD_API DNSServiceGetProperty(const char *property, void *result, uint32_t *size)
1265 {
1266 DNSServiceErrorType err;
1267 char *ptr;
1268 size_t len;
1269 ipc_msg_hdr *hdr;
1270 DNSServiceOp *tmp;
1271 uint32_t actualsize;
1272 int ioresult;
1273
1274 if (!property || !result || !size)
1275 return kDNSServiceErr_BadParam;
1276
1277 len = strlen(property) + 1;
1278 err = ConnectToServer(&tmp, 0, getproperty_request, NULL, NULL, NULL);
1279 if (err) return err;
1280
1281 hdr = create_hdr(getproperty_request, &len, &ptr, 0, tmp);
1282 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
1283
1284 put_string(property, &ptr);
1285 err = deliver_request(hdr, tmp); // Will free hdr for us
1286 if (err) { DNSServiceRefDeallocate(tmp); return err; }
1287
1288 ioresult = read_all(tmp->sockfd, (char*)&actualsize, (int)sizeof(actualsize));
1289 if (ioresult < read_all_success)
1290 { DNSServiceRefDeallocate(tmp); return (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning; }
1291
1292 actualsize = ntohl(actualsize);
1293 ioresult = read_all(tmp->sockfd, (char*)result, actualsize < *size ? actualsize : *size);
1294 if (ioresult < read_all_success)
1295 { DNSServiceRefDeallocate(tmp); return (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning; }
1296 DNSServiceRefDeallocate(tmp);
1297
1298 // Swap version result back to local process byte order
1299 if (!strcmp(property, kDNSServiceProperty_DaemonVersion) && *size >= 4)
1300 *(uint32_t*)result = ntohl(*(uint32_t*)result);
1301
1302 *size = actualsize;
1303 return kDNSServiceErr_NoError;
1304 }
1305
1306 DNSServiceErrorType DNSSD_API DNSServiceGetPID(const uint16_t srcport, int32_t *pid)
1307 {
1308 char *ptr;
1309 ipc_msg_hdr *hdr;
1310 DNSServiceOp *tmp = NULL;
1311 size_t len = sizeof(int32_t);
1312 int ioresult;
1313
1314 DNSServiceErrorType err = ConnectToServer(&tmp, 0, getpid_request, NULL, NULL, NULL);
1315 if (err) return err;
1316
1317 hdr = create_hdr(getpid_request, &len, &ptr, 0, tmp);
1318 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
1319
1320 put_uint16(srcport, &ptr);
1321 err = deliver_request(hdr, tmp); // Will free hdr for us
1322 if (err) { DNSServiceRefDeallocate(tmp); return err; }
1323
1324 ioresult = read_all(tmp->sockfd, (char*)pid, sizeof(int32_t));
1325 if (ioresult < read_all_success)
1326 { DNSServiceRefDeallocate(tmp); return (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning; }
1327
1328 DNSServiceRefDeallocate(tmp);
1329 return kDNSServiceErr_NoError;
1330 }
1331
1332 static void handle_resolve_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *end)
1333 {
1334 char fullname[kDNSServiceMaxDomainName];
1335 char target[kDNSServiceMaxDomainName];
1336 uint16_t txtlen;
1337 union { uint16_t s; u_char b[2]; } port;
1338 unsigned char *txtrecord;
1339
1340 get_string(&data, end, fullname, kDNSServiceMaxDomainName);
1341 get_string(&data, end, target, kDNSServiceMaxDomainName);
1342 if (!data || data + 2 > end) goto fail;
1343
1344 port.b[0] = *data++;
1345 port.b[1] = *data++;
1346 txtlen = get_uint16(&data, end);
1347 txtrecord = (unsigned char *)get_rdata(&data, end, txtlen);
1348
1349 if (!data) goto fail;
1350 ((DNSServiceResolveReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, fullname, target, port.s, txtlen, txtrecord, sdr->AppContext);
1351 return;
1352 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1353 fail:
1354 syslog(LOG_WARNING, "dnssd_clientstub handle_resolve_response: error reading result from daemon");
1355 }
1356
1357 #if TARGET_OS_IPHONE
1358
1359 static int32_t libSystemVersion = 0;
1360
1361 // Return true if the iOS application linked against a version of libsystem where P2P
1362 // interfaces were included by default when using kDNSServiceInterfaceIndexAny.
1363 // Using 160.0.0 == 0xa00000 as the version threshold.
1364 static int includeP2PWithIndexAny()
1365 {
1366 if (libSystemVersion == 0)
1367 libSystemVersion = NSVersionOfLinkTimeLibrary("System");
1368
1369 if (libSystemVersion < 0xa00000)
1370 return 1;
1371 else
1372 return 0;
1373 }
1374
1375 #else // TARGET_OS_IPHONE
1376
1377 // always return false for non iOS platforms
1378 static int includeP2PWithIndexAny()
1379 {
1380 return 0;
1381 }
1382
1383 #endif // TARGET_OS_IPHONE
1384
1385 DNSServiceErrorType DNSSD_API DNSServiceResolve
1386 (
1387 DNSServiceRef *sdRef,
1388 DNSServiceFlags flags,
1389 uint32_t interfaceIndex,
1390 const char *name,
1391 const char *regtype,
1392 const char *domain,
1393 DNSServiceResolveReply callBack,
1394 void *context
1395 )
1396 {
1397 char *ptr;
1398 size_t len;
1399 ipc_msg_hdr *hdr;
1400 DNSServiceErrorType err;
1401
1402 if (!sdRef || !name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam;
1403
1404 // Need a real InterfaceID for WakeOnResolve
1405 if ((flags & kDNSServiceFlagsWakeOnResolve) != 0 &&
1406 ((interfaceIndex == kDNSServiceInterfaceIndexAny) ||
1407 (interfaceIndex == kDNSServiceInterfaceIndexLocalOnly) ||
1408 (interfaceIndex == kDNSServiceInterfaceIndexUnicast) ||
1409 (interfaceIndex == kDNSServiceInterfaceIndexP2P) ||
1410 (interfaceIndex == kDNSServiceInterfaceIndexBLE)))
1411 {
1412 return kDNSServiceErr_BadParam;
1413 }
1414
1415 if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
1416 flags |= kDNSServiceFlagsIncludeP2P;
1417
1418 err = ConnectToServer(sdRef, flags, resolve_request, handle_resolve_response, callBack, context);
1419 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1420
1421 // Calculate total message length
1422 len = sizeof(flags);
1423 len += sizeof(interfaceIndex);
1424 len += strlen(name) + 1;
1425 len += strlen(regtype) + 1;
1426 len += strlen(domain) + 1;
1427
1428 hdr = create_hdr(resolve_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1429 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1430
1431 put_flags(flags, &ptr);
1432 put_uint32(interfaceIndex, &ptr);
1433 put_string(name, &ptr);
1434 put_string(regtype, &ptr);
1435 put_string(domain, &ptr);
1436
1437 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1438 #if CHECK_BUNDLE_VERSION
1439 if (err == kDNSServiceErr_NoAuth && !_should_return_noauth_error())
1440 {
1441 err = kDNSServiceErr_NoError;
1442 }
1443 #endif
1444 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1445 return err;
1446 }
1447
1448 static void handle_query_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
1449 {
1450 #if CHECK_BUNDLE_VERSION
1451 if (cbh->cb_err == kDNSServiceErr_PolicyDenied && !_should_return_noauth_error())
1452 {
1453 return;
1454 }
1455 #endif
1456 uint32_t ttl;
1457 char name[kDNSServiceMaxDomainName];
1458 uint16_t rrtype, rrclass, rdlen;
1459 const char *rdata;
1460
1461 get_string(&data, end, name, kDNSServiceMaxDomainName);
1462 rrtype = get_uint16(&data, end);
1463 rrclass = get_uint16(&data, end);
1464 rdlen = get_uint16(&data, end);
1465 rdata = get_rdata(&data, end, rdlen);
1466 ttl = get_uint32(&data, end);
1467
1468 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_query_response: error reading result from daemon");
1469 else ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, name, rrtype, rrclass, rdlen, rdata, ttl, sdr->AppContext);
1470 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1471 }
1472
1473 #if APPLE_OSX_mDNSResponder
1474 static size_t get_required_length_for_defaults(const xpc_object_t defaults)
1475 {
1476 size_t required_len = 0;
1477 size_t plist_data_len = 0;
1478 // Add length for IPC_TLV_TYPE_RESOLVER_CONFIG_PLIST_DATA.
1479 if (xpc_dictionary_get_data(defaults, kDNSServiceDefaultsKey_ResolverConfigPListData, &plist_data_len))
1480 {
1481 required_len += get_required_tlv16_length(plist_data_len);
1482 }
1483 // Add length for IPC_TLV_TYPE_REQUIRE_PRIVACY.
1484 required_len += get_required_tlv16_length(sizeof(uint8_t));
1485 return required_len;
1486 }
1487
1488 static void put_tlvs_for_defaults(const xpc_object_t defaults, ipc_msg_hdr *const hdr, char **ptr)
1489 {
1490 uint8_t require_privacy;
1491 size_t plist_data_len = 0;
1492 const uint8_t *const plist_data_ptr = xpc_dictionary_get_data(defaults,
1493 kDNSServiceDefaultsKey_ResolverConfigPListData, &plist_data_len);
1494 if (plist_data_ptr)
1495 {
1496 put_tlv16(IPC_TLV_TYPE_RESOLVER_CONFIG_PLIST_DATA, (uint16_t)plist_data_len, plist_data_ptr, ptr);
1497 }
1498 require_privacy = xpc_dictionary_get_bool(defaults, kDNSServiceDefaultsKey_RequirePrivacy) ? 1 : 0;
1499 put_tlv16(IPC_TLV_TYPE_REQUIRE_PRIVACY, sizeof(require_privacy), &require_privacy, ptr);
1500 hdr->ipc_flags |= IPC_FLAGS_TRAILING_TLVS;
1501 }
1502 #endif
1503
1504 DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
1505 (
1506 DNSServiceRef *sdRef,
1507 DNSServiceFlags flags,
1508 uint32_t interfaceIndex,
1509 const char *name,
1510 uint16_t rrtype,
1511 uint16_t rrclass,
1512 DNSServiceQueryRecordReply callBack,
1513 void *context
1514 )
1515 {
1516 char *ptr;
1517 size_t len;
1518 ipc_msg_hdr *hdr;
1519 DNSServiceErrorType err;
1520 #if APPLE_OSX_mDNSResponder
1521 xpc_object_t defaults;
1522 #endif
1523 // NULL name handled below.
1524 if (!sdRef || !callBack) return kDNSServiceErr_BadParam;
1525
1526 if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
1527 flags |= kDNSServiceFlagsIncludeP2P;
1528
1529 err = ConnectToServer(sdRef, flags, query_request, handle_query_response, callBack, context);
1530 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1531
1532 if (!name) name = "\0";
1533
1534 // Calculate total message length
1535 len = sizeof(flags);
1536 len += sizeof(uint32_t); // interfaceIndex
1537 len += strlen(name) + 1;
1538 len += 2 * sizeof(uint16_t); // rrtype, rrclass
1539 #if APPLE_OSX_mDNSResponder
1540 defaults = DNSServiceGetRetainedResolverDefaults();
1541 if (defaults)
1542 {
1543 len += get_required_length_for_defaults(defaults);
1544 }
1545 #endif
1546 hdr = create_hdr(query_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1547 if (!hdr)
1548 {
1549 DNSServiceRefDeallocate(*sdRef);
1550 *sdRef = NULL;
1551 #if APPLE_OSX_mDNSResponder
1552 xpc_forget(&defaults);
1553 #endif
1554 return kDNSServiceErr_NoMemory;
1555 }
1556 put_flags(flags, &ptr);
1557 put_uint32(interfaceIndex, &ptr);
1558 put_string(name, &ptr);
1559 put_uint16(rrtype, &ptr);
1560 put_uint16(rrclass, &ptr);
1561 #if APPLE_OSX_mDNSResponder
1562 if (defaults)
1563 {
1564 put_tlvs_for_defaults(defaults, hdr, &ptr);
1565 xpc_forget(&defaults);
1566 }
1567 #endif
1568 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1569 #if CHECK_BUNDLE_VERSION
1570 if (err == kDNSServiceErr_NoAuth && !_should_return_noauth_error())
1571 {
1572 err = kDNSServiceErr_NoError;
1573 }
1574 #endif
1575 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1576 return err;
1577 }
1578
1579 static void handle_addrinfo_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
1580 {
1581 #if CHECK_BUNDLE_VERSION
1582 if (cbh->cb_err == kDNSServiceErr_PolicyDenied && !_should_return_noauth_error())
1583 {
1584 return;
1585 }
1586 #endif
1587 char hostname[kDNSServiceMaxDomainName];
1588 uint16_t rrtype, rrclass, rdlen;
1589 const char *rdata;
1590 uint32_t ttl;
1591
1592 get_string(&data, end, hostname, kDNSServiceMaxDomainName);
1593 rrtype = get_uint16(&data, end);
1594 rrclass = get_uint16(&data, end);
1595 rdlen = get_uint16(&data, end);
1596 rdata = get_rdata (&data, end, rdlen);
1597 ttl = get_uint32(&data, end);
1598 (void)rrclass; // Unused
1599
1600 // We only generate client callbacks for A and AAAA results (including NXDOMAIN results for
1601 // those types, if the client has requested those with the kDNSServiceFlagsReturnIntermediates).
1602 // Other result types, specifically CNAME referrals, are not communicated to the client, because
1603 // the DNSServiceGetAddrInfoReply interface doesn't have any meaningful way to communiate CNAME referrals.
1604 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_addrinfo_response: error reading result from daemon");
1605 else if (rrtype == kDNSServiceType_A || rrtype == kDNSServiceType_AAAA)
1606 {
1607 struct sockaddr_in sa4;
1608 struct sockaddr_in6 sa6;
1609 const struct sockaddr *const sa = (rrtype == kDNSServiceType_A) ? (struct sockaddr*)&sa4 : (struct sockaddr*)&sa6;
1610 if (rrtype == kDNSServiceType_A)
1611 {
1612 memset(&sa4, 0, sizeof(sa4));
1613 #ifndef NOT_HAVE_SA_LEN
1614 sa4.sin_len = sizeof(struct sockaddr_in);
1615 #endif
1616 sa4.sin_family = AF_INET;
1617 // sin_port = 0;
1618 if (!cbh->cb_err) memcpy(&sa4.sin_addr, rdata, rdlen);
1619 }
1620 else
1621 {
1622 memset(&sa6, 0, sizeof(sa6));
1623 #ifndef NOT_HAVE_SA_LEN
1624 sa6.sin6_len = sizeof(struct sockaddr_in6);
1625 #endif
1626 sa6.sin6_family = AF_INET6;
1627 // sin6_port = 0;
1628 // sin6_flowinfo = 0;
1629 // sin6_scope_id = 0;
1630 if (!cbh->cb_err)
1631 {
1632 memcpy(&sa6.sin6_addr, rdata, rdlen);
1633 if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr)) sa6.sin6_scope_id = cbh->cb_interface;
1634 }
1635 }
1636
1637 ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, sa, ttl, sdr->AppContext);
1638 }
1639 else if (cbh->cb_err == kDNSServiceErr_PolicyDenied)
1640 {
1641 ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, NULL, ttl, sdr->AppContext);
1642 }
1643 }
1644
1645 DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
1646 (
1647 DNSServiceRef *sdRef,
1648 DNSServiceFlags flags,
1649 uint32_t interfaceIndex,
1650 uint32_t protocol,
1651 const char *hostname,
1652 DNSServiceGetAddrInfoReply callBack,
1653 void *context /* may be NULL */
1654 )
1655 {
1656 char *ptr;
1657 size_t len;
1658 ipc_msg_hdr *hdr;
1659 DNSServiceErrorType err;
1660 #if APPLE_OSX_mDNSResponder
1661 xpc_object_t defaults;
1662 #endif
1663
1664 if (!sdRef || !hostname || !callBack) return kDNSServiceErr_BadParam;
1665
1666 err = ConnectToServer(sdRef, flags, addrinfo_request, handle_addrinfo_response, callBack, context);
1667 if (err)
1668 {
1669 return err; // On error ConnectToServer leaves *sdRef set to NULL
1670 }
1671
1672 // Calculate total message length
1673 len = sizeof(flags);
1674 len += sizeof(uint32_t); // interfaceIndex
1675 len += sizeof(uint32_t); // protocol
1676 len += strlen(hostname) + 1;
1677 #if APPLE_OSX_mDNSResponder
1678 defaults = DNSServiceGetRetainedResolverDefaults();
1679 if (defaults)
1680 {
1681 len += get_required_length_for_defaults(defaults);
1682 }
1683 #endif
1684 hdr = create_hdr(addrinfo_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1685 if (!hdr)
1686 {
1687 DNSServiceRefDeallocate(*sdRef);
1688 *sdRef = NULL;
1689 #if APPLE_OSX_mDNSResponder
1690 xpc_forget(&defaults);
1691 #endif
1692 return kDNSServiceErr_NoMemory;
1693 }
1694 put_flags(flags, &ptr);
1695 put_uint32(interfaceIndex, &ptr);
1696 put_uint32(protocol, &ptr);
1697 put_string(hostname, &ptr);
1698 #if APPLE_OSX_mDNSResponder
1699 if (defaults)
1700 {
1701 put_tlvs_for_defaults(defaults, hdr, &ptr);
1702 xpc_forget(&defaults);
1703 }
1704 #endif
1705 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1706 #if CHECK_BUNDLE_VERSION
1707 if (err == kDNSServiceErr_NoAuth && !_should_return_noauth_error())
1708 {
1709 err = kDNSServiceErr_NoError;
1710 }
1711 #endif
1712 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1713 return err;
1714 }
1715
1716 static void handle_browse_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
1717 {
1718 #if CHECK_BUNDLE_VERSION
1719 if (cbh->cb_err == kDNSServiceErr_PolicyDenied && !_should_return_noauth_error())
1720 {
1721 return;
1722 }
1723 #endif
1724 char replyName[256], replyType[kDNSServiceMaxDomainName], replyDomain[kDNSServiceMaxDomainName];
1725 get_string(&data, end, replyName, 256);
1726 get_string(&data, end, replyType, kDNSServiceMaxDomainName);
1727 get_string(&data, end, replyDomain, kDNSServiceMaxDomainName);
1728 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_browse_response: error reading result from daemon");
1729 else ((DNSServiceBrowseReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, replyName, replyType, replyDomain, sdr->AppContext);
1730 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1731 }
1732
1733 DNSServiceErrorType DNSSD_API DNSServiceBrowse
1734 (
1735 DNSServiceRef *sdRef,
1736 DNSServiceFlags flags,
1737 uint32_t interfaceIndex,
1738 const char *regtype,
1739 const char *domain,
1740 DNSServiceBrowseReply callBack,
1741 void *context
1742 )
1743 {
1744 char *ptr;
1745 size_t len;
1746 ipc_msg_hdr *hdr;
1747 DNSServiceErrorType err;
1748
1749 // NULL domain handled below
1750 if (!sdRef || !regtype || !callBack) return kDNSServiceErr_BadParam;
1751
1752 if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
1753 flags |= kDNSServiceFlagsIncludeP2P;
1754
1755 err = ConnectToServer(sdRef, flags, browse_request, handle_browse_response, callBack, context);
1756 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1757
1758 if (!domain) domain = "";
1759 len = sizeof(flags);
1760 len += sizeof(interfaceIndex);
1761 len += strlen(regtype) + 1;
1762 len += strlen(domain) + 1;
1763
1764 hdr = create_hdr(browse_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1765 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1766
1767 put_flags(flags, &ptr);
1768 put_uint32(interfaceIndex, &ptr);
1769 put_string(regtype, &ptr);
1770 put_string(domain, &ptr);
1771
1772 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1773 #if CHECK_BUNDLE_VERSION
1774 if (err == kDNSServiceErr_NoAuth && !_should_return_noauth_error())
1775 {
1776 err = kDNSServiceErr_NoError;
1777 }
1778 #endif
1779 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1780 return err;
1781 }
1782
1783 DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain)
1784 {
1785 DNSServiceErrorType err;
1786 DNSServiceOp *tmp;
1787 char *ptr;
1788 size_t len;
1789 ipc_msg_hdr *hdr;
1790
1791 if (!domain) return kDNSServiceErr_BadParam;
1792 len = sizeof(flags) + strlen(domain) + 1;
1793
1794 err = ConnectToServer(&tmp, 0, setdomain_request, NULL, NULL, NULL);
1795 if (err) return err;
1796
1797 hdr = create_hdr(setdomain_request, &len, &ptr, 0, tmp);
1798 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
1799
1800 put_flags(flags, &ptr);
1801 put_string(domain, &ptr);
1802 err = deliver_request(hdr, tmp); // Will free hdr for us
1803 DNSServiceRefDeallocate(tmp);
1804 return err;
1805 }
1806
1807 static void handle_regservice_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
1808 {
1809 #if CHECK_BUNDLE_VERSION
1810 if (cbh->cb_err == kDNSServiceErr_PolicyDenied && !_should_return_noauth_error())
1811 {
1812 return;
1813 }
1814 #endif
1815 char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
1816 get_string(&data, end, name, 256);
1817 get_string(&data, end, regtype, kDNSServiceMaxDomainName);
1818 get_string(&data, end, domain, kDNSServiceMaxDomainName);
1819 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_regservice_response: error reading result from daemon");
1820 else ((DNSServiceRegisterReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_err, name, regtype, domain, sdr->AppContext);
1821 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1822 }
1823
1824 DNSServiceErrorType DNSSD_API DNSServiceRegister
1825 (
1826 DNSServiceRef *sdRef,
1827 DNSServiceFlags flags,
1828 uint32_t interfaceIndex,
1829 const char *name,
1830 const char *regtype,
1831 const char *domain,
1832 const char *host,
1833 uint16_t PortInNetworkByteOrder,
1834 uint16_t txtLen,
1835 const void *txtRecord,
1836 DNSServiceRegisterReply callBack,
1837 void *context
1838 )
1839 {
1840 char *ptr;
1841 size_t len;
1842 ipc_msg_hdr *hdr;
1843 DNSServiceErrorType err;
1844 union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder };
1845
1846 if (!sdRef || !regtype) return kDNSServiceErr_BadParam;
1847 if (!name) name = "";
1848 if (!domain) domain = "";
1849 if (!host) host = "";
1850 if (!txtRecord) txtRecord = (void*)"";
1851
1852 // No callback must have auto-rename
1853 if (!callBack && (flags & kDNSServiceFlagsNoAutoRename)) return kDNSServiceErr_BadParam;
1854
1855 if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
1856 flags |= kDNSServiceFlagsIncludeP2P;
1857
1858 err = ConnectToServer(sdRef, flags, reg_service_request, callBack ? handle_regservice_response : NULL, callBack, context);
1859 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1860
1861 len = sizeof(DNSServiceFlags);
1862 len += sizeof(uint32_t); // interfaceIndex
1863 len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4;
1864 len += 2 * sizeof(uint16_t); // port, txtLen
1865 len += txtLen;
1866
1867 hdr = create_hdr(reg_service_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1868 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1869 if (!callBack) hdr->ipc_flags |= IPC_FLAGS_NOREPLY;
1870
1871 put_flags(flags, &ptr);
1872 put_uint32(interfaceIndex, &ptr);
1873 put_string(name, &ptr);
1874 put_string(regtype, &ptr);
1875 put_string(domain, &ptr);
1876 put_string(host, &ptr);
1877 *ptr++ = port.b[0];
1878 *ptr++ = port.b[1];
1879 put_uint16(txtLen, &ptr);
1880 put_rdata(txtLen, txtRecord, &ptr);
1881
1882 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1883 #if CHECK_BUNDLE_VERSION
1884 if (err == kDNSServiceErr_NoAuth && !_should_return_noauth_error())
1885 {
1886 err = kDNSServiceErr_NoError;
1887 }
1888 #endif
1889 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1890 return err;
1891 }
1892
1893 static void handle_enumeration_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
1894 {
1895 char domain[kDNSServiceMaxDomainName];
1896 get_string(&data, end, domain, kDNSServiceMaxDomainName);
1897 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_enumeration_response: error reading result from daemon");
1898 else ((DNSServiceDomainEnumReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, domain, sdr->AppContext);
1899 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1900 }
1901
1902 DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
1903 (
1904 DNSServiceRef *sdRef,
1905 DNSServiceFlags flags,
1906 uint32_t interfaceIndex,
1907 DNSServiceDomainEnumReply callBack,
1908 void *context
1909 )
1910 {
1911 char *ptr;
1912 size_t len;
1913 ipc_msg_hdr *hdr;
1914 DNSServiceErrorType err;
1915 int f1;
1916 int f2;
1917
1918 if (!sdRef || !callBack) return kDNSServiceErr_BadParam;
1919
1920 f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0;
1921 f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0;
1922 if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
1923
1924 err = ConnectToServer(sdRef, flags, enumeration_request, handle_enumeration_response, callBack, context);
1925 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1926
1927 len = sizeof(DNSServiceFlags);
1928 len += sizeof(uint32_t);
1929
1930 hdr = create_hdr(enumeration_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1931 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1932
1933 put_flags(flags, &ptr);
1934 put_uint32(interfaceIndex, &ptr);
1935
1936 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1937 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1938 return err;
1939 }
1940
1941 static void ConnectionResponse(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *const data, const char *const end)
1942 {
1943 (void)data; // Unused
1944
1945 //printf("ConnectionResponse got %d\n", cbh->ipc_hdr.op);
1946 if (cbh->ipc_hdr.op != reg_record_reply_op)
1947 {
1948 // When using kDNSServiceFlagsShareConnection, need to search the list of associated DNSServiceOps
1949 // to find the one this response is intended for, and then call through to its ProcessReply handler.
1950 // We start with our first subordinate DNSServiceRef -- don't want to accidentally match the parent DNSServiceRef.
1951 DNSServiceOp *op = sdr->next;
1952 while (op && (op->uid.u32[0] != cbh->ipc_hdr.client_context.u32[0] || op->uid.u32[1] != cbh->ipc_hdr.client_context.u32[1]))
1953 op = op->next;
1954 // Note: We may sometimes not find a matching DNSServiceOp, in the case where the client has
1955 // cancelled the subordinate DNSServiceOp, but there are still messages in the pipeline from the daemon
1956 if (op && op->ProcessReply) op->ProcessReply(op, cbh, data, end);
1957 // WARNING: Don't touch op or sdr after this -- client may have called DNSServiceRefDeallocate
1958 return;
1959 }
1960 else
1961 {
1962 #if CHECK_BUNDLE_VERSION
1963 if (cbh->cb_err == kDNSServiceErr_PolicyDenied && !_should_return_noauth_error())
1964 {
1965 return;
1966 }
1967 #endif
1968 DNSRecordRef rec;
1969 for (rec = sdr->rec; rec; rec = rec->recnext)
1970 {
1971 if (rec->uid.u32[0] == cbh->ipc_hdr.client_context.u32[0] && rec->uid.u32[1] == cbh->ipc_hdr.client_context.u32[1])
1972 break;
1973 }
1974 // The record might have been freed already and hence not an
1975 // error if the record is not found.
1976 if (!rec)
1977 {
1978 syslog(LOG_INFO, "dnssd_clientstub ConnectionResponse: Record not found");
1979 return;
1980 }
1981 if (rec->sdr != sdr)
1982 {
1983 syslog(LOG_WARNING, "dnssd_clientstub ConnectionResponse: Record sdr mismatch: rec %p sdr %p", rec->sdr, sdr);
1984 return;
1985 }
1986
1987 if (sdr->op == connection_request || sdr->op == connection_delegate_request)
1988 {
1989 rec->AppCallback(rec->sdr, rec, cbh->cb_flags, cbh->cb_err, rec->AppContext);
1990 }
1991 else
1992 {
1993 syslog(LOG_WARNING, "dnssd_clientstub ConnectionResponse: sdr->op != connection_request");
1994 rec->AppCallback(rec->sdr, rec, 0, kDNSServiceErr_Unknown, rec->AppContext);
1995 }
1996 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1997 }
1998 }
1999
2000 DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef)
2001 {
2002 DNSServiceErrorType err;
2003 char *ptr;
2004 size_t len = 0;
2005 ipc_msg_hdr *hdr;
2006
2007 if (!sdRef) return kDNSServiceErr_BadParam;
2008 err = ConnectToServer(sdRef, 0, connection_request, ConnectionResponse, NULL, NULL);
2009 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
2010
2011 hdr = create_hdr(connection_request, &len, &ptr, 0, *sdRef);
2012 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
2013
2014 err = deliver_request(hdr, *sdRef); // Will free hdr for us
2015 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
2016 return err;
2017 }
2018
2019 #if APPLE_OSX_mDNSResponder && !TARGET_OS_SIMULATOR
2020 DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid)
2021 {
2022 char *ptr;
2023 size_t len = 0;
2024 ipc_msg_hdr *hdr;
2025
2026 if (!sdRef) return kDNSServiceErr_BadParam;
2027 DNSServiceErrorType err = ConnectToServer(sdRef, 0, connection_delegate_request, ConnectionResponse, NULL, NULL);
2028 if (err)
2029 {
2030 return err; // On error ConnectToServer leaves *sdRef set to NULL
2031 }
2032
2033 // Only one of the two options can be set. If pid is zero, uuid is used.
2034 // If both are specified only pid will be used. We send across the pid
2035 // so that the daemon knows what to read from the socket.
2036
2037 len += sizeof(int32_t);
2038
2039 hdr = create_hdr(connection_delegate_request, &len, &ptr, 0, *sdRef);
2040 if (!hdr)
2041 {
2042 DNSServiceRefDeallocate(*sdRef);
2043 *sdRef = NULL;
2044 return kDNSServiceErr_NoMemory;
2045 }
2046
2047 if (pid && setsockopt((*sdRef)->sockfd, SOL_SOCKET, SO_DELEGATED, &pid, sizeof(pid)) == -1)
2048 {
2049 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceCreateDelegateConnection: Could not setsockopt() for PID[%d], no entitlements or process(pid) invalid errno:%d (%s)", pid, errno, strerror(errno));
2050 // Free the hdr in case we return before calling deliver_request()
2051 if (hdr)
2052 free(hdr);
2053 DNSServiceRefDeallocate(*sdRef);
2054 *sdRef = NULL;
2055 return kDNSServiceErr_NoAuth;
2056 }
2057
2058 if (!pid && setsockopt((*sdRef)->sockfd, SOL_SOCKET, SO_DELEGATED_UUID, uuid, sizeof(uuid_t)) == -1)
2059 {
2060 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceCreateDelegateConnection: Could not setsockopt() for UUID, no entitlements or process(uuid) invalid errno:%d (%s) ", errno, strerror(errno));
2061 // Free the hdr in case we return before calling deliver_request()
2062 if (hdr)
2063 free(hdr);
2064 DNSServiceRefDeallocate(*sdRef);
2065 *sdRef = NULL;
2066 return kDNSServiceErr_NoAuth;
2067 }
2068
2069 put_uint32(pid, &ptr);
2070
2071 err = deliver_request(hdr, *sdRef); // Will free hdr for us
2072 if (err)
2073 {
2074 DNSServiceRefDeallocate(*sdRef);
2075 *sdRef = NULL;
2076 }
2077 return err;
2078 }
2079 #elif TARGET_OS_SIMULATOR // This hack is for Simulator platform only
2080 DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid)
2081 {
2082 (void) pid;
2083 (void) uuid;
2084 return DNSServiceCreateConnection(sdRef);
2085 }
2086 #endif
2087
2088 DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
2089 (
2090 DNSServiceRef sdRef,
2091 DNSRecordRef *RecordRef,
2092 DNSServiceFlags flags,
2093 uint32_t interfaceIndex,
2094 const char *fullname,
2095 uint16_t rrtype,
2096 uint16_t rrclass,
2097 uint16_t rdlen,
2098 const void *rdata,
2099 uint32_t ttl,
2100 DNSServiceRegisterRecordReply callBack,
2101 void *context
2102 )
2103 {
2104 DNSServiceErrorType err;
2105 char *ptr;
2106 size_t len;
2107 ipc_msg_hdr *hdr = NULL;
2108 DNSRecordRef rref = NULL;
2109 DNSRecord **p;
2110 // Verify that only one of the following flags is set.
2111 int f1 = (flags & kDNSServiceFlagsShared) != 0;
2112 int f2 = (flags & kDNSServiceFlagsUnique) != 0;
2113 int f3 = (flags & kDNSServiceFlagsKnownUnique) != 0;
2114 if (f1 + f2 + f3 != 1) return kDNSServiceErr_BadParam;
2115
2116 if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
2117 flags |= kDNSServiceFlagsIncludeP2P;
2118
2119 if (!sdRef || !RecordRef || !fullname || (!rdata && rdlen) || !callBack)
2120 {
2121 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with NULL parameter");
2122 return kDNSServiceErr_BadParam;
2123 }
2124
2125 if (!DNSServiceRefValid(sdRef))
2126 {
2127 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
2128 return kDNSServiceErr_BadReference;
2129 }
2130
2131 if (sdRef->op != connection_request && sdRef->op != connection_delegate_request)
2132 {
2133 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with non-DNSServiceCreateConnection DNSServiceRef %p %d", sdRef, sdRef->op);
2134 return kDNSServiceErr_BadReference;
2135 }
2136
2137 *RecordRef = NULL;
2138
2139 len = sizeof(DNSServiceFlags);
2140 len += 2 * sizeof(uint32_t); // interfaceIndex, ttl
2141 len += 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen
2142 len += strlen(fullname) + 1;
2143 len += rdlen;
2144
2145 // Bump up the uid. Normally for shared operations (kDNSServiceFlagsShareConnection), this
2146 // is done in ConnectToServer. For DNSServiceRegisterRecord, ConnectToServer has already
2147 // been called. As multiple DNSServiceRegisterRecords can be multiplexed over a single
2148 // connection, we need a way to demultiplex the response so that the callback corresponding
2149 // to the right DNSServiceRegisterRecord instance can be called. Use the same mechanism that
2150 // is used by kDNSServiceFlagsShareConnection. create_hdr copies the uid value to ipc
2151 // hdr->client_context which will be returned in the ipc response.
2152 if (++sdRef->uid.u32[0] == 0)
2153 ++sdRef->uid.u32[1];
2154 hdr = create_hdr(reg_record_request, &len, &ptr, 1, sdRef);
2155 if (!hdr) return kDNSServiceErr_NoMemory;
2156
2157 put_flags(flags, &ptr);
2158 put_uint32(interfaceIndex, &ptr);
2159 put_string(fullname, &ptr);
2160 put_uint16(rrtype, &ptr);
2161 put_uint16(rrclass, &ptr);
2162 put_uint16(rdlen, &ptr);
2163 put_rdata(rdlen, rdata, &ptr);
2164 put_uint32(ttl, &ptr);
2165
2166 rref = malloc(sizeof(DNSRecord));
2167 if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; }
2168 rref->AppContext = context;
2169 rref->AppCallback = callBack;
2170 rref->record_index = sdRef->max_index++;
2171 rref->sdr = sdRef;
2172 rref->recnext = NULL;
2173 *RecordRef = rref;
2174 // Remember the uid that we are sending across so that we can match
2175 // when the response comes back.
2176 rref->uid = sdRef->uid;
2177 hdr->reg_index = rref->record_index;
2178
2179 p = &(sdRef)->rec;
2180 while (*p) p = &(*p)->recnext;
2181 *p = rref;
2182
2183 err = deliver_request(hdr, sdRef); // Will free hdr for us
2184 #if CHECK_BUNDLE_VERSION
2185 if (err == kDNSServiceErr_NoAuth && !_should_return_noauth_error())
2186 {
2187 err = kDNSServiceErr_NoError;
2188 }
2189 #endif
2190 return err;
2191 }
2192
2193 // sdRef returned by DNSServiceRegister()
2194 DNSServiceErrorType DNSSD_API DNSServiceAddRecord
2195 (
2196 DNSServiceRef sdRef,
2197 DNSRecordRef *RecordRef,
2198 DNSServiceFlags flags,
2199 uint16_t rrtype,
2200 uint16_t rdlen,
2201 const void *rdata,
2202 uint32_t ttl
2203 )
2204 {
2205 ipc_msg_hdr *hdr;
2206 size_t len = 0;
2207 char *ptr;
2208 DNSRecordRef rref;
2209 DNSRecord **p;
2210
2211 if (!sdRef || !RecordRef || (!rdata && rdlen))
2212 {
2213 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL parameter");
2214 return kDNSServiceErr_BadParam;
2215 }
2216 if (sdRef->op != reg_service_request)
2217 {
2218 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with non-DNSServiceRegister DNSServiceRef %p %d", sdRef, sdRef->op);
2219 return kDNSServiceErr_BadReference;
2220 }
2221
2222 if (!DNSServiceRefValid(sdRef))
2223 {
2224 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
2225 return kDNSServiceErr_BadReference;
2226 }
2227
2228 *RecordRef = NULL;
2229
2230 len += 2 * sizeof(uint16_t); // rrtype, rdlen
2231 len += rdlen;
2232 len += sizeof(uint32_t);
2233 len += sizeof(DNSServiceFlags);
2234
2235 hdr = create_hdr(add_record_request, &len, &ptr, 1, sdRef);
2236 if (!hdr) return kDNSServiceErr_NoMemory;
2237 put_flags(flags, &ptr);
2238 put_uint16(rrtype, &ptr);
2239 put_uint16(rdlen, &ptr);
2240 put_rdata(rdlen, rdata, &ptr);
2241 put_uint32(ttl, &ptr);
2242
2243 rref = malloc(sizeof(DNSRecord));
2244 if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; }
2245 rref->AppContext = NULL;
2246 rref->AppCallback = NULL;
2247 rref->record_index = sdRef->max_index++;
2248 rref->sdr = sdRef;
2249 rref->recnext = NULL;
2250 *RecordRef = rref;
2251 hdr->reg_index = rref->record_index;
2252
2253 p = &(sdRef)->rec;
2254 while (*p) p = &(*p)->recnext;
2255 *p = rref;
2256
2257 return deliver_request(hdr, sdRef); // Will free hdr for us
2258 }
2259
2260 // DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
2261 DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
2262 (
2263 DNSServiceRef sdRef,
2264 DNSRecordRef RecordRef,
2265 DNSServiceFlags flags,
2266 uint16_t rdlen,
2267 const void *rdata,
2268 uint32_t ttl
2269 )
2270 {
2271 ipc_msg_hdr *hdr;
2272 size_t len = 0;
2273 char *ptr;
2274
2275 if (!sdRef || (!rdata && rdlen))
2276 {
2277 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with NULL parameter");
2278 return kDNSServiceErr_BadParam;
2279 }
2280
2281 if (!DNSServiceRefValid(sdRef))
2282 {
2283 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
2284 return kDNSServiceErr_BadReference;
2285 }
2286
2287 // Note: RecordRef is allowed to be NULL
2288
2289 len += sizeof(uint16_t);
2290 len += rdlen;
2291 len += sizeof(uint32_t);
2292 len += sizeof(DNSServiceFlags);
2293
2294 hdr = create_hdr(update_record_request, &len, &ptr, 1, sdRef);
2295 if (!hdr) return kDNSServiceErr_NoMemory;
2296 hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX;
2297 put_flags(flags, &ptr);
2298 put_uint16(rdlen, &ptr);
2299 put_rdata(rdlen, rdata, &ptr);
2300 put_uint32(ttl, &ptr);
2301 return deliver_request(hdr, sdRef); // Will free hdr for us
2302 }
2303
2304 DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
2305 (
2306 DNSServiceRef sdRef,
2307 DNSRecordRef RecordRef,
2308 DNSServiceFlags flags
2309 )
2310 {
2311 ipc_msg_hdr *hdr;
2312 size_t len = 0;
2313 char *ptr;
2314 DNSServiceErrorType err;
2315
2316 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
2317 if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSRecordRef"); return kDNSServiceErr_BadParam; }
2318 if (!sdRef->max_index) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with bad DNSServiceRef"); return kDNSServiceErr_BadReference; }
2319
2320 if (!DNSServiceRefValid(sdRef))
2321 {
2322 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
2323 return kDNSServiceErr_BadReference;
2324 }
2325
2326 len += sizeof(flags);
2327 hdr = create_hdr(remove_record_request, &len, &ptr, 1, sdRef);
2328 if (!hdr) return kDNSServiceErr_NoMemory;
2329 hdr->reg_index = RecordRef->record_index;
2330 put_flags(flags, &ptr);
2331 err = deliver_request(hdr, sdRef); // Will free hdr for us
2332 if (!err)
2333 {
2334 // This RecordRef could have been allocated in DNSServiceRegisterRecord or DNSServiceAddRecord.
2335 // If so, delink from the list before freeing
2336 DNSRecord **p = &sdRef->rec;
2337 while (*p && *p != RecordRef) p = &(*p)->recnext;
2338 if (*p) *p = RecordRef->recnext;
2339 free(RecordRef);
2340 }
2341 return err;
2342 }
2343
2344 DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
2345 (
2346 DNSServiceFlags flags,
2347 uint32_t interfaceIndex,
2348 const char *fullname,
2349 uint16_t rrtype,
2350 uint16_t rrclass,
2351 uint16_t rdlen,
2352 const void *rdata
2353 )
2354 {
2355 DNSServiceErrorType err;
2356 char *ptr;
2357 size_t len;
2358 ipc_msg_hdr *hdr;
2359 DNSServiceOp *tmp = NULL;
2360
2361 if (!fullname || (!rdata && rdlen)) return kDNSServiceErr_BadParam;
2362
2363 err = ConnectToServer(&tmp, flags, reconfirm_record_request, NULL, NULL, NULL);
2364 if (err) return err;
2365
2366 len = sizeof(DNSServiceFlags);
2367 len += sizeof(uint32_t);
2368 len += strlen(fullname) + 1;
2369 len += 3 * sizeof(uint16_t);
2370 len += rdlen;
2371 hdr = create_hdr(reconfirm_record_request, &len, &ptr, 0, tmp);
2372 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
2373
2374 put_flags(flags, &ptr);
2375 put_uint32(interfaceIndex, &ptr);
2376 put_string(fullname, &ptr);
2377 put_uint16(rrtype, &ptr);
2378 put_uint16(rrclass, &ptr);
2379 put_uint16(rdlen, &ptr);
2380 put_rdata(rdlen, rdata, &ptr);
2381
2382 err = deliver_request(hdr, tmp); // Will free hdr for us
2383 DNSServiceRefDeallocate(tmp);
2384 return err;
2385 }
2386
2387
2388 static void handle_port_mapping_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
2389 {
2390 union { uint32_t l; u_char b[4]; } addr;
2391 uint8_t protocol;
2392 union { uint16_t s; u_char b[2]; } internalPort;
2393 union { uint16_t s; u_char b[2]; } externalPort;
2394 uint32_t ttl;
2395
2396 if (!data || data + 13 > end) goto fail;
2397
2398 addr.b[0] = *data++;
2399 addr.b[1] = *data++;
2400 addr.b[2] = *data++;
2401 addr.b[3] = *data++;
2402 protocol = *data++;
2403 internalPort.b[0] = *data++;
2404 internalPort.b[1] = *data++;
2405 externalPort.b[0] = *data++;
2406 externalPort.b[1] = *data++;
2407 ttl = get_uint32(&data, end);
2408 if (!data) goto fail;
2409
2410 ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, addr.l, protocol, internalPort.s, externalPort.s, ttl, sdr->AppContext);
2411 return;
2412 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
2413
2414 fail :
2415 syslog(LOG_WARNING, "dnssd_clientstub handle_port_mapping_response: error reading result from daemon");
2416 }
2417
2418 DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
2419 (
2420 DNSServiceRef *sdRef,
2421 DNSServiceFlags flags,
2422 uint32_t interfaceIndex,
2423 uint32_t protocol, /* TCP and/or UDP */
2424 uint16_t internalPortInNetworkByteOrder,
2425 uint16_t externalPortInNetworkByteOrder,
2426 uint32_t ttl, /* time to live in seconds */
2427 DNSServiceNATPortMappingReply callBack,
2428 void *context /* may be NULL */
2429 )
2430 {
2431 char *ptr;
2432 size_t len;
2433 ipc_msg_hdr *hdr;
2434 union { uint16_t s; u_char b[2]; } internalPort = { internalPortInNetworkByteOrder };
2435 union { uint16_t s; u_char b[2]; } externalPort = { externalPortInNetworkByteOrder };
2436
2437 DNSServiceErrorType err = ConnectToServer(sdRef, flags, port_mapping_request, handle_port_mapping_response, callBack, context);
2438 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
2439
2440 len = sizeof(flags);
2441 len += sizeof(interfaceIndex);
2442 len += sizeof(protocol);
2443 len += sizeof(internalPort);
2444 len += sizeof(externalPort);
2445 len += sizeof(ttl);
2446
2447 hdr = create_hdr(port_mapping_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
2448 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
2449
2450 put_flags(flags, &ptr);
2451 put_uint32(interfaceIndex, &ptr);
2452 put_uint32(protocol, &ptr);
2453 *ptr++ = internalPort.b[0];
2454 *ptr++ = internalPort.b[1];
2455 *ptr++ = externalPort.b[0];
2456 *ptr++ = externalPort.b[1];
2457 put_uint32(ttl, &ptr);
2458
2459 err = deliver_request(hdr, *sdRef); // Will free hdr for us
2460 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
2461 return err;
2462 }
2463
2464 #if _DNS_SD_LIBDISPATCH
2465 DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue
2466 (
2467 DNSServiceRef service,
2468 dispatch_queue_t queue
2469 )
2470 {
2471 int dnssd_fd = DNSServiceRefSockFD(service);
2472 if (dnssd_fd == dnssd_InvalidSocket) return kDNSServiceErr_BadParam;
2473 if (!queue)
2474 {
2475 syslog(LOG_WARNING, "dnssd_clientstub: DNSServiceSetDispatchQueue dispatch queue NULL");
2476 return kDNSServiceErr_BadParam;
2477 }
2478 if (service->disp_queue)
2479 {
2480 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch queue set already");
2481 return kDNSServiceErr_BadParam;
2482 }
2483 if (service->disp_source)
2484 {
2485 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch source set already");
2486 return kDNSServiceErr_BadParam;
2487 }
2488 service->disp_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, dnssd_fd, 0, queue);
2489 if (!service->disp_source)
2490 {
2491 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch_source_create failed");
2492 return kDNSServiceErr_NoMemory;
2493 }
2494 service->disp_queue = queue;
2495 dispatch_source_set_event_handler(service->disp_source, ^{DNSServiceProcessResult(service);});
2496 dispatch_source_set_cancel_handler(service->disp_source, ^{dnssd_close(dnssd_fd);});
2497 dispatch_resume(service->disp_source);
2498 return kDNSServiceErr_NoError;
2499 }
2500 #endif // _DNS_SD_LIBDISPATCH
2501
2502 #if !defined(_WIN32)
2503
2504 static void DNSSD_API SleepKeepaliveCallback(DNSServiceRef sdRef, DNSRecordRef rec, const DNSServiceFlags flags,
2505 DNSServiceErrorType errorCode, void *context)
2506 {
2507 SleepKAContext *ka = (SleepKAContext *)context;
2508 (void)rec; // Unused
2509 (void)flags; // Unused
2510
2511 if (sdRef->kacontext != context)
2512 syslog(LOG_WARNING, "dnssd_clientstub SleepKeepaliveCallback context mismatch");
2513
2514 if (ka->AppCallback)
2515 ((DNSServiceSleepKeepaliveReply)ka->AppCallback)(sdRef, errorCode, ka->AppContext);
2516 }
2517
2518 static DNSServiceErrorType _DNSServiceSleepKeepalive_sockaddr
2519 (
2520 DNSServiceRef * sdRef,
2521 DNSServiceFlags flags,
2522 const struct sockaddr * localAddr,
2523 const struct sockaddr * remoteAddr,
2524 unsigned int timeout,
2525 DNSServiceSleepKeepaliveReply callBack,
2526 void * context
2527 );
2528
2529 DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
2530 (
2531 DNSServiceRef *sdRef,
2532 DNSServiceFlags flags,
2533 int fd,
2534 unsigned int timeout,
2535 DNSServiceSleepKeepaliveReply callBack,
2536 void *context
2537 )
2538 {
2539 struct sockaddr_storage lss;
2540 struct sockaddr_storage rss;
2541 socklen_t len1, len2;
2542
2543 len1 = sizeof(lss);
2544 if (getsockname(fd, (struct sockaddr *)&lss, &len1) < 0)
2545 {
2546 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive: getsockname %d\n", errno);
2547 return kDNSServiceErr_BadParam;
2548 }
2549
2550 len2 = sizeof(rss);
2551 if (getpeername(fd, (struct sockaddr *)&rss, &len2) < 0)
2552 {
2553 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive: getpeername %d\n", errno);
2554 return kDNSServiceErr_BadParam;
2555 }
2556
2557 if (len1 != len2)
2558 {
2559 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive local/remote info not same");
2560 return kDNSServiceErr_Unknown;
2561 }
2562 return _DNSServiceSleepKeepalive_sockaddr(sdRef, flags, (const struct sockaddr *)&lss, (const struct sockaddr *)&rss,
2563 timeout, callBack, context);
2564 }
2565
2566 DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive_sockaddr
2567 (
2568 DNSServiceRef * sdRef,
2569 DNSServiceFlags flags,
2570 const struct sockaddr * localAddr,
2571 const struct sockaddr * remoteAddr,
2572 unsigned int timeout,
2573 DNSServiceSleepKeepaliveReply callBack,
2574 void * context
2575 )
2576 {
2577 return _DNSServiceSleepKeepalive_sockaddr(sdRef, flags, localAddr, remoteAddr, timeout, callBack, context );
2578 }
2579
2580 static DNSServiceErrorType _DNSServiceSleepKeepalive_sockaddr
2581 (
2582 DNSServiceRef * sdRef,
2583 DNSServiceFlags flags,
2584 const struct sockaddr * localAddr,
2585 const struct sockaddr * remoteAddr,
2586 unsigned int timeout,
2587 DNSServiceSleepKeepaliveReply callBack,
2588 void * context
2589 )
2590 {
2591 char source_str[INET6_ADDRSTRLEN];
2592 char target_str[INET6_ADDRSTRLEN];
2593 unsigned int len, proxyreclen;
2594 char buf[256];
2595 DNSServiceErrorType err;
2596 DNSRecordRef record = NULL;
2597 char name[10];
2598 char recname[128];
2599 SleepKAContext *ka;
2600 unsigned int i, unique;
2601
2602 (void) flags; //unused
2603 if (!timeout) return kDNSServiceErr_BadParam;
2604
2605 unique = 0;
2606 if ((localAddr->sa_family == AF_INET) && (remoteAddr->sa_family == AF_INET))
2607 {
2608 const struct sockaddr_in *sl = (const struct sockaddr_in *)localAddr;
2609 const struct sockaddr_in *sr = (const struct sockaddr_in *)remoteAddr;
2610 unsigned char *ptr = (unsigned char *)&sl->sin_addr;
2611
2612 if (!inet_ntop(AF_INET, (const void *)&sr->sin_addr, target_str, sizeof (target_str)))
2613 {
2614 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive remote info failed %d", errno);
2615 return kDNSServiceErr_Unknown;
2616 }
2617 if (!inet_ntop(AF_INET, (const void *)&sl->sin_addr, source_str, sizeof (source_str)))
2618 {
2619 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive local info failed %d", errno);
2620 return kDNSServiceErr_Unknown;
2621 }
2622 // Sum of all bytes in the local address and port should result in a unique
2623 // number in the local network
2624 for (i = 0; i < sizeof(struct in_addr); i++)
2625 unique += ptr[i];
2626 unique += sl->sin_port;
2627 len = snprintf(buf+1, sizeof(buf) - 1, "t=%u h=%s d=%s l=%u r=%u", timeout, source_str, target_str, ntohs(sl->sin_port), ntohs(sr->sin_port));
2628 }
2629 else if ((localAddr->sa_family == AF_INET6) && (remoteAddr->sa_family == AF_INET6))
2630 {
2631 const struct sockaddr_in6 *sl6 = (const struct sockaddr_in6 *)localAddr;
2632 const struct sockaddr_in6 *sr6 = (const struct sockaddr_in6 *)remoteAddr;
2633 unsigned char *ptr = (unsigned char *)&sl6->sin6_addr;
2634
2635 if (!inet_ntop(AF_INET6, (const void *)&sr6->sin6_addr, target_str, sizeof (target_str)))
2636 {
2637 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive remote6 info failed %d", errno);
2638 return kDNSServiceErr_Unknown;
2639 }
2640 if (!inet_ntop(AF_INET6, (const void *)&sl6->sin6_addr, source_str, sizeof (source_str)))
2641 {
2642 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive local6 info failed %d", errno);
2643 return kDNSServiceErr_Unknown;
2644 }
2645 for (i = 0; i < sizeof(struct in6_addr); i++)
2646 unique += ptr[i];
2647 unique += sl6->sin6_port;
2648 len = snprintf(buf+1, sizeof(buf) - 1, "t=%u H=%s D=%s l=%u r=%u", timeout, source_str, target_str, ntohs(sl6->sin6_port), ntohs(sr6->sin6_port));
2649 }
2650 else
2651 {
2652 return kDNSServiceErr_BadParam;
2653 }
2654
2655 if (len >= (sizeof(buf) - 1))
2656 {
2657 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive could not fit local/remote info");
2658 return kDNSServiceErr_Unknown;
2659 }
2660 // Include the NULL byte also in the first byte. The total length of the record includes the
2661 // first byte also.
2662 buf[0] = len + 1;
2663 proxyreclen = len + 2;
2664
2665 len = snprintf(name, sizeof(name), "%u", unique);
2666 if (len >= sizeof(name))
2667 {
2668 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive could not fit unique");
2669 return kDNSServiceErr_Unknown;
2670 }
2671
2672 len = snprintf(recname, sizeof(recname), "%s.%s", name, "_keepalive._dns-sd._udp.local");
2673 if (len >= sizeof(recname))
2674 {
2675 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive could not fit name");
2676 return kDNSServiceErr_Unknown;
2677 }
2678
2679 ka = malloc(sizeof(SleepKAContext));
2680 if (!ka) return kDNSServiceErr_NoMemory;
2681 ka->AppCallback = callBack;
2682 ka->AppContext = context;
2683
2684 err = DNSServiceCreateConnection(sdRef);
2685 if (err)
2686 {
2687 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive cannot create connection");
2688 free(ka);
2689 return err;
2690 }
2691
2692 // we don't care about the "record". When sdRef gets deallocated later, it will be freed too
2693 err = DNSServiceRegisterRecord(*sdRef, &record, kDNSServiceFlagsUnique, 0, recname,
2694 kDNSServiceType_NULL, kDNSServiceClass_IN, proxyreclen, buf, kDNSServiceInterfaceIndexAny, SleepKeepaliveCallback, ka);
2695 if (err)
2696 {
2697 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive cannot create connection");
2698 free(ka);
2699 return err;
2700 }
2701 (*sdRef)->kacontext = ka;
2702 return kDNSServiceErr_NoError;
2703 }
2704 #endif