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