dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libdns_sd / common / dnssd_clientstub.c
blobb0fd9f99833f602fc142dd55c9e388d8cbc272e0
1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2003-2015 Apple Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
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.
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <fcntl.h>
33 #include "dnssd_ipc.h"
35 #if APPLE_OSX_mDNSResponder
36 #include <mach-o/dyld.h>
37 #include <uuid/uuid.h>
38 #include <TargetConditionals.h>
39 #include "dns_sd_private.h"
40 #endif
42 #if defined(_WIN32)
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>
53 #define sockaddr_mdns sockaddr_in
54 #define AF_MDNS AF_INET
56 // Disable warning: "'type cast' : from data pointer 'void *' to function pointer"
57 #pragma warning(disable:4055)
59 // Disable warning: "nonstandard extension, function/data pointer conversion in expression"
60 #pragma warning(disable:4152)
62 extern BOOL IsSystemServiceDisabled();
64 #define sleep(X) Sleep((X) * 1000)
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, ...)
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 ) { vsnprintf( buffer, len, message, args ); OutputDebugString( buffer ); free( buffer ); }
80 WSASetLastError( err );
82 #else
84 #include <sys/fcntl.h> // For O_RDWR etc.
85 #include <sys/time.h>
86 #include <sys/socket.h>
87 #include <syslog.h>
89 #define sockaddr_mdns sockaddr_un
90 #define AF_MDNS AF_LOCAL
92 #endif
94 // <rdar://problem/4096913> Specifies how many times we'll try and connect to the server.
96 #define DNSSD_CLIENT_MAXTRIES 4
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
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
107 #ifndef CTL_PATH_PREFIX
108 #define CTL_PATH_PREFIX "/var/tmp/dnssd_result_socket."
109 #endif
111 typedef struct
113 ipc_msg_hdr ipc_hdr;
114 DNSServiceFlags cb_flags;
115 uint32_t cb_interface;
116 DNSServiceErrorType cb_err;
117 } CallbackHeader;
119 typedef struct _DNSServiceRef_t DNSServiceOp;
120 typedef struct _DNSRecordRef_t DNSRecord;
122 #if !defined(_WIN32)
123 typedef struct
125 void *AppCallback; // Client callback function and context
126 void *AppContext;
127 } SleepKAContext;
128 #endif
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);
133 #define ValidatorBits 0x12345678
134 #define DNSServiceRefValid(X) (dnssd_SocketValid((X)->sockfd) && (((X)->sockfd ^ (X)->validator) == ValidatorBits))
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
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
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;
165 struct _DNSRecordRef_t
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;
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)
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)
183 ssize_t num_written = send(sd, buf, (long)len, 0);
184 if (num_written < 0 || (size_t)num_written > len)
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;
208 buf += num_written;
209 len -= num_written;
211 return 0;
214 enum { read_all_success = 0, read_all_fail = -1, read_all_wouldblock = -2 };
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)
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;
222 while (len)
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))
229 syslog(LOG_INFO, "dnssd_clientstub read_all: EINTR continue");
230 continue;
232 if ((num_read == 0) || (num_read < 0) || (num_read > len))
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)
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));
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;
262 buf += num_read;
263 len -= num_read;
265 return read_all_success;
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)
271 struct timeval tv = { 0, 0 };
272 fd_set readfds;
273 fd_set *fs;
274 int ret;
276 if (sd < FD_SETSIZE)
278 fs = &readfds;
279 FD_ZERO(fs);
281 else
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, (size_t)sizeof(int));
290 if (fs == NULL)
292 syslog(LOG_WARNING, "dnssd_clientstub more_bytes: malloc failed");
293 return 0;
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);
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)
311 int gDaemonErr = kDNSServiceErr_NoError;
313 // To prevent stack corruption since select does not work with timeout if fds > FD_SETSIZE(1024)
314 if (!gDaemonErr && sock < FD_SETSIZE)
316 struct timeval tv;
317 fd_set set;
319 FD_ZERO(&set);
320 FD_SET(sock, &set);
321 tv.tv_sec = timeout;
322 tv.tv_usec = 0;
323 if (!select((int)(sock + 1), &set, NULL, NULL, &tv))
325 // Ideally one should never hit this case: See comments before set_waitlimit()
326 syslog(LOG_WARNING, "dnssd_clientstub set_waitlimit:_daemon timed out (%d secs) without any response: Socket %d", timeout, sock);
327 gDaemonErr = kDNSServiceErr_Timeout;
330 return gDaemonErr;
333 /* create_hdr
335 * allocate and initialize an ipc message header. Value of len should initially be the
336 * length of the data, and is set to the value of the data plus the header. data_start
337 * is set to point to the beginning of the data section. SeparateReturnSocket should be
338 * non-zero for calls that can't receive an immediate error return value on their primary
339 * socket, and therefore require a separate return path for the error code result.
340 * if zero, the path to a control socket is appended at the beginning of the message buffer.
341 * data_start is set past this string.
343 static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int SeparateReturnSocket, DNSServiceOp *ref)
345 char *msg = NULL;
346 ipc_msg_hdr *hdr;
347 int datalen;
348 #if !defined(USE_TCP_LOOPBACK)
349 char ctrl_path[64] = ""; // "/var/tmp/dnssd_result_socket.xxxxxxxxxx-xxx-xxxxxx"
350 #endif
352 if (SeparateReturnSocket)
354 #if defined(USE_TCP_LOOPBACK)
355 *len += 2; // Allocate space for two-byte port number
356 #elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
357 struct timeval tv;
358 if (gettimeofday(&tv, NULL) < 0)
359 { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: gettimeofday failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); return NULL; }
360 snprintf(ctrl_path, sizeof(ctrl_path), "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(),
361 (unsigned long)(tv.tv_sec & 0xFFF), (unsigned long)(tv.tv_usec));
362 *len += strlen(ctrl_path) + 1;
363 #else
364 *len += 1; // Allocate space for single zero byte (empty C string)
365 #endif
368 datalen = (int) *len;
369 *len += sizeof(ipc_msg_hdr);
371 // Write message to buffer
372 msg = malloc(*len);
373 if (!msg) { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: malloc failed"); return NULL; }
375 memset(msg, 0, *len);
376 hdr = (ipc_msg_hdr *)msg;
377 hdr->version = VERSION;
378 hdr->datalen = datalen;
379 hdr->ipc_flags = 0;
380 hdr->op = op;
381 hdr->client_context = ref->uid;
382 hdr->reg_index = 0;
383 *data_start = msg + sizeof(ipc_msg_hdr);
384 #if defined(USE_TCP_LOOPBACK)
385 // Put dummy data in for the port, since we don't know what it is yet.
386 // The data will get filled in before we send the message. This happens in deliver_request().
387 if (SeparateReturnSocket) put_uint16(0, data_start);
388 #else
389 if (SeparateReturnSocket) put_string(ctrl_path, data_start);
390 #endif
391 return hdr;
394 static void FreeDNSRecords(DNSServiceOp *sdRef)
396 DNSRecord *rec = sdRef->rec;
397 while (rec)
399 DNSRecord *next = rec->recnext;
400 free(rec);
401 rec = next;
405 static void FreeDNSServiceOp(DNSServiceOp *x)
407 // We don't use our DNSServiceRefValid macro here because if we're cleaning up after a socket() call failed
408 // then sockfd could legitimately contain a failing value (e.g. dnssd_InvalidSocket)
409 if ((x->sockfd ^ x->validator) != ValidatorBits)
411 static DNSServiceOp *op_were_not_going_to_free_but_we_need_to_fool_the_analyzer;
412 syslog(LOG_WARNING, "dnssd_clientstub attempt to dispose invalid DNSServiceRef %p %08X %08X", x, x->sockfd, x->validator);
413 op_were_not_going_to_free_but_we_need_to_fool_the_analyzer = x;
415 else
417 x->next = NULL;
418 x->primary = NULL;
419 x->sockfd = dnssd_InvalidSocket;
420 x->validator = 0xDDDDDDDD;
421 x->op = request_op_none;
422 x->max_index = 0;
423 x->logcounter = 0;
424 x->moreptr = NULL;
425 x->ProcessReply = NULL;
426 x->AppCallback = NULL;
427 x->AppContext = NULL;
428 #if _DNS_SD_LIBDISPATCH
429 if (x->disp_source) dispatch_release(x->disp_source);
430 x->disp_source = NULL;
431 x->disp_queue = NULL;
432 #endif
433 // DNSRecords may have been added to subordinate sdRef e.g., DNSServiceRegister/DNSServiceAddRecord
434 // or on the main sdRef e.g., DNSServiceCreateConnection/DNSServiveRegisterRecord. DNSRecords may have
435 // been freed if the application called DNSRemoveRecord
436 FreeDNSRecords(x);
437 if (x->kacontext)
439 free(x->kacontext);
440 x->kacontext = NULL;
442 free(x);
446 // Return a connected service ref (deallocate with DNSServiceRefDeallocate)
447 static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags flags, uint32_t op, ProcessReplyFn ProcessReply, void *AppCallback, void *AppContext)
449 int NumTries = 0;
451 dnssd_sockaddr_t saddr;
452 DNSServiceOp *sdr;
454 if (!ref)
456 syslog(LOG_WARNING, "dnssd_clientstub DNSService operation with NULL DNSServiceRef");
457 return kDNSServiceErr_BadParam;
460 if (flags & kDNSServiceFlagsShareConnection)
462 if (!*ref)
464 syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with NULL DNSServiceRef");
465 return kDNSServiceErr_BadParam;
467 if (!DNSServiceRefValid(*ref) || ((*ref)->op != connection_request && (*ref)->op != connection_delegate_request) || (*ref)->primary)
469 syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with invalid DNSServiceRef %p %08X %08X op %d",
470 (*ref), (*ref)->sockfd, (*ref)->validator, (*ref)->op);
471 *ref = NULL;
472 return kDNSServiceErr_BadReference;
476 #if defined(_WIN32)
477 if (!g_initWinsock)
479 WSADATA wsaData;
480 g_initWinsock = 1;
481 if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { *ref = NULL; return kDNSServiceErr_ServiceNotRunning; }
483 // <rdar://problem/4096913> If the system service is disabled, we only want to try to connect once
484 if (IsSystemServiceDisabled())
485 NumTries = DNSSD_CLIENT_MAXTRIES;
486 #endif
488 sdr = malloc(sizeof(DNSServiceOp));
489 if (!sdr)
491 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: malloc failed");
492 *ref = NULL;
493 return kDNSServiceErr_NoMemory;
495 sdr->next = NULL;
496 sdr->primary = NULL;
497 sdr->sockfd = dnssd_InvalidSocket;
498 sdr->validator = sdr->sockfd ^ ValidatorBits;
499 sdr->op = op;
500 sdr->max_index = 0;
501 sdr->logcounter = 0;
502 sdr->moreptr = NULL;
503 sdr->uid.u32[0] = 0;
504 sdr->uid.u32[1] = 0;
505 sdr->ProcessReply = ProcessReply;
506 sdr->AppCallback = AppCallback;
507 sdr->AppContext = AppContext;
508 sdr->rec = NULL;
509 #if _DNS_SD_LIBDISPATCH
510 sdr->disp_source = NULL;
511 sdr->disp_queue = NULL;
512 #endif
513 sdr->kacontext = NULL;
515 if (flags & kDNSServiceFlagsShareConnection)
517 DNSServiceOp **p = &(*ref)->next; // Append ourselves to end of primary's list
518 while (*p)
519 p = &(*p)->next;
520 *p = sdr;
521 // Preincrement counter before we use it -- it helps with debugging if we know the all-zeroes ID should never appear
522 if (++(*ref)->uid.u32[0] == 0)
523 ++(*ref)->uid.u32[1]; // In parent DNSServiceOp increment UID counter
524 sdr->primary = *ref; // Set our primary pointer
525 sdr->sockfd = (*ref)->sockfd; // Inherit primary's socket
526 sdr->validator = (*ref)->validator;
527 sdr->uid = (*ref)->uid;
528 //printf("ConnectToServer sharing socket %d\n", sdr->sockfd);
530 else
532 #ifdef SO_NOSIGPIPE
533 const unsigned long optval = 1;
534 #endif
535 #ifndef USE_TCP_LOOPBACK
536 char* uds_serverpath = getenv(MDNS_UDS_SERVERPATH_ENVVAR);
537 if (uds_serverpath == NULL)
538 uds_serverpath = MDNS_UDS_SERVERPATH;
539 else if (strlen(uds_serverpath) >= MAX_CTLPATH)
541 uds_serverpath = MDNS_UDS_SERVERPATH;
542 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: using default path since env len is invalid");
544 #endif
545 *ref = NULL;
546 sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0);
547 sdr->validator = sdr->sockfd ^ ValidatorBits;
548 if (!dnssd_SocketValid(sdr->sockfd))
550 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: socket failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
551 FreeDNSServiceOp(sdr);
552 return kDNSServiceErr_NoMemory;
554 #ifdef SO_NOSIGPIPE
555 // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
556 if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
557 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_NOSIGPIPE failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
558 #endif
559 #if defined(USE_TCP_LOOPBACK)
560 saddr.sin_family = AF_INET;
561 saddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
562 saddr.sin_port = htons(MDNS_TCP_SERVERPORT);
563 #else
564 saddr.sun_family = AF_LOCAL;
565 strcpy(saddr.sun_path, uds_serverpath);
566 #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
568 int defunct = 1;
569 if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
570 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
572 #endif
573 #endif
575 while (1)
577 int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
578 if (!err)
579 break; // If we succeeded, return sdr
580 // If we failed, then it may be because the daemon is still launching.
581 // This can happen for processes that launch early in the boot process, while the
582 // daemon is still coming up. Rather than fail here, we wait 1 sec and try again.
583 // If, after DNSSD_CLIENT_MAXTRIES, we still can't connect to the daemon,
584 // then we give up and return a failure code.
585 if (++NumTries < DNSSD_CLIENT_MAXTRIES)
587 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect()-> No of tries: %d", NumTries);
588 sleep(1); // Sleep a bit, then try again
590 else
592 #if !defined(USE_TCP_LOOPBACK)
593 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect() failed path:%s Socket:%d Err:%d Errno:%d %s",
594 uds_serverpath, sdr->sockfd, err, dnssd_errno, dnssd_strerror(dnssd_errno));
595 #endif
596 dnssd_close(sdr->sockfd);
597 FreeDNSServiceOp(sdr);
598 return kDNSServiceErr_ServiceNotRunning;
601 //printf("ConnectToServer opened socket %d\n", sdr->sockfd);
604 *ref = sdr;
605 return kDNSServiceErr_NoError;
608 #define deliver_request_bailout(MSG) \
609 syslog(LOG_WARNING, "dnssd_clientstub deliver_request: %s failed %d (%s)", (MSG), dnssd_errno, dnssd_strerror(dnssd_errno)); goto cleanup
611 static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
613 if (!hdr)
615 syslog(LOG_WARNING, "dnssd_clientstub deliver_request: !hdr");
616 return kDNSServiceErr_Unknown;
619 uint32_t datalen = hdr->datalen; // We take a copy here because we're going to convert hdr->datalen to network byte order
620 #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
621 char *const data = (char *)hdr + sizeof(ipc_msg_hdr);
622 #endif
623 dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
624 DNSServiceErrorType err = kDNSServiceErr_Unknown; // Default for the "goto cleanup" cases
626 // Note: need to check hdr->op, not sdr->op.
627 // hdr->op contains the code for the specific operation we're currently doing, whereas sdr->op
628 // contains the original parent DNSServiceOp (e.g. for an add_record_request, hdr->op will be
629 // add_record_request but the parent sdr->op will be connection_request or reg_service_request)
630 const int MakeSeparateReturnSocket = (sdr->primary ||
631 hdr->op == reg_record_request || hdr->op == add_record_request || hdr->op == update_record_request || hdr->op == remove_record_request);
633 if (!DNSServiceRefValid(sdr))
635 if (hdr)
636 free(hdr);
637 syslog(LOG_WARNING, "dnssd_clientstub deliver_request: invalid DNSServiceRef %p %08X %08X", sdr, sdr->sockfd, sdr->validator);
638 return kDNSServiceErr_BadReference;
641 if (MakeSeparateReturnSocket)
643 #if defined(USE_TCP_LOOPBACK)
645 union { uint16_t s; u_char b[2]; } port;
646 dnssd_sockaddr_t caddr;
647 dnssd_socklen_t len = (dnssd_socklen_t) sizeof(caddr);
648 listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
649 if (!dnssd_SocketValid(listenfd)) {
650 deliver_request_bailout("TCP socket");
653 caddr.sin_family = AF_INET;
654 caddr.sin_port = 0;
655 caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
656 if (bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr)) < 0) {
657 deliver_request_bailout("TCP bind");
659 if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) {
660 deliver_request_bailout("TCP getsockname");
662 if (listen(listenfd, 1) < 0) {
663 deliver_request_bailout("TCP listen");
665 port.s = caddr.sin_port;
666 data[0] = port.b[0]; // don't switch the byte order, as the
667 data[1] = port.b[1]; // daemon expects it in network byte order
669 #elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
671 mode_t mask;
672 int bindresult;
673 dnssd_sockaddr_t caddr;
674 listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
675 if (!dnssd_SocketValid(listenfd)) {
676 deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET socket");
679 caddr.sun_family = AF_LOCAL;
680 // According to Stevens (section 3.2), there is no portable way to
681 // determine whether sa_len is defined on a particular platform.
682 #ifndef NOT_HAVE_SA_LEN
683 caddr.sun_len = sizeof(struct sockaddr_un);
684 #endif
685 strcpy(caddr.sun_path, data);
686 mask = umask(0);
687 bindresult = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr));
688 umask(mask);
689 if (bindresult < 0) {
690 deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET bind");
692 if (listen(listenfd, 1) < 0) {
693 deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET listen");
696 #else
698 dnssd_sock_t sp[2];
699 if (socketpair(AF_DNSSD, SOCK_STREAM, 0, sp) < 0) {
700 deliver_request_bailout("socketpair");
702 else
704 errsd = sp[0]; // We'll read our four-byte error code from sp[0]
705 listenfd = sp[1]; // We'll send sp[1] to the daemon
706 #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
708 int defunct = 1;
709 if (setsockopt(errsd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
710 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
712 #endif
715 #endif
718 #if !defined(USE_TCP_LOOPBACK) && !defined(USE_NAMED_ERROR_RETURN_SOCKET)
719 // If we're going to make a separate error return socket, and pass it to the daemon
720 // using sendmsg, then we'll hold back one data byte to go with it.
721 // On some versions of Unix (including Leopard) sending a control message without
722 // any associated data does not work reliably -- e.g. one particular issue we ran
723 // into is that if the receiving program is in a kqueue loop waiting to be notified
724 // of the received message, it doesn't get woken up when the control message arrives.
725 if (MakeSeparateReturnSocket || sdr->op == send_bpf)
726 datalen--; // Okay to use sdr->op when checking for op == send_bpf
727 #endif
729 // At this point, our listening socket is set up and waiting, if necessary, for the daemon to connect back to
730 ConvertHeaderBytes(hdr);
731 //syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %lu bytes", (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
732 //if (MakeSeparateReturnSocket) syslog(LOG_WARNING, "dnssd_clientstub deliver_request name is %s", data);
733 #if TEST_SENDING_ONE_BYTE_AT_A_TIME
734 unsigned int i;
735 for (i=0; i<datalen + sizeof(ipc_msg_hdr); i++)
737 syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %d", i);
738 if (write_all(sdr->sockfd, ((char *)hdr)+i, 1) < 0)
739 { syslog(LOG_WARNING, "write_all (byte %u) failed", i); goto cleanup; }
740 usleep(10000);
742 #else
743 if (write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr)) < 0)
745 // write_all already prints an error message if there is an error writing to
746 // the socket except for DEFUNCT. Logging here is unnecessary and also wrong
747 // in the case of DEFUNCT sockets
748 syslog(LOG_INFO, "dnssd_clientstub deliver_request ERROR: write_all(%d, %lu bytes) failed",
749 sdr->sockfd, (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
750 goto cleanup;
752 #endif
754 if (!MakeSeparateReturnSocket)
755 errsd = sdr->sockfd;
756 if (MakeSeparateReturnSocket || sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
758 #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
759 // At this point we may wait in accept for a few milliseconds waiting for the daemon to connect back to us,
760 // but that's okay -- the daemon should not take more than a few milliseconds to respond.
761 // set_waitlimit() ensures we do not block indefinitely just in case something is wrong
762 dnssd_sockaddr_t daddr;
763 dnssd_socklen_t len = sizeof(daddr);
764 if ((err = set_waitlimit(listenfd, DNSSD_CLIENT_TIMEOUT)) != kDNSServiceErr_NoError)
765 goto cleanup;
766 errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
767 if (!dnssd_SocketValid(errsd)) {
768 deliver_request_bailout("accept");
770 #else
772 struct iovec vec = { ((char *)hdr) + sizeof(ipc_msg_hdr) + datalen, 1 }; // Send the last byte along with the SCM_RIGHTS
773 struct msghdr msg;
774 struct cmsghdr *cmsg;
775 char cbuf[CMSG_SPACE(4 * sizeof(dnssd_sock_t))];
777 msg.msg_name = 0;
778 msg.msg_namelen = 0;
779 msg.msg_iov = &vec;
780 msg.msg_iovlen = 1;
781 msg.msg_flags = 0;
782 if (MakeSeparateReturnSocket || sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
784 if (sdr->op == send_bpf)
786 int i;
787 char p[12]; // Room for "/dev/bpf999" with terminating null
788 for (i=0; i<100; i++)
790 snprintf(p, sizeof(p), "/dev/bpf%d", i);
791 listenfd = open(p, O_RDWR, 0);
792 //if (dnssd_SocketValid(listenfd)) syslog(LOG_WARNING, "Sending fd %d for %s", listenfd, p);
793 if (!dnssd_SocketValid(listenfd) && dnssd_errno != EBUSY)
794 syslog(LOG_WARNING, "Error opening %s %d (%s)", p, dnssd_errno, dnssd_strerror(dnssd_errno));
795 if (dnssd_SocketValid(listenfd) || dnssd_errno != EBUSY) break;
798 msg.msg_control = cbuf;
799 msg.msg_controllen = CMSG_LEN(sizeof(dnssd_sock_t));
801 cmsg = CMSG_FIRSTHDR(&msg);
802 cmsg->cmsg_len = CMSG_LEN(sizeof(dnssd_sock_t));
803 cmsg->cmsg_level = SOL_SOCKET;
804 cmsg->cmsg_type = SCM_RIGHTS;
805 *((dnssd_sock_t *)CMSG_DATA(cmsg)) = listenfd;
808 #if TEST_KQUEUE_CONTROL_MESSAGE_BUG
809 sleep(1);
810 #endif
812 #if DEBUG_64BIT_SCM_RIGHTS
813 syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d %ld %ld %ld/%ld/%ld/%ld",
814 errsd, listenfd, sizeof(dnssd_sock_t), sizeof(void*),
815 sizeof(struct cmsghdr) + sizeof(dnssd_sock_t),
816 CMSG_LEN(sizeof(dnssd_sock_t)), (long)CMSG_SPACE(sizeof(dnssd_sock_t)),
817 (long)((char*)CMSG_DATA(cmsg) + 4 - cbuf));
818 #endif // DEBUG_64BIT_SCM_RIGHTS
820 if (sendmsg(sdr->sockfd, &msg, 0) < 0)
822 syslog(LOG_WARNING, "dnssd_clientstub deliver_request ERROR: sendmsg failed read sd=%d write sd=%d errno %d (%s)",
823 errsd, listenfd, dnssd_errno, dnssd_strerror(dnssd_errno));
824 err = kDNSServiceErr_Incompatible;
825 goto cleanup;
828 #if DEBUG_64BIT_SCM_RIGHTS
829 syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d okay", errsd, listenfd);
830 #endif // DEBUG_64BIT_SCM_RIGHTS
832 #endif
833 // Close our end of the socketpair *before* calling read_all() to get the four-byte error code.
834 // Otherwise, if the daemon closes our socket (or crashes), we will have to wait for a timeout
835 // in read_all() because the socket is not closed (we still have an open reference to it)
836 // Note: listenfd is overwritten in the case of send_bpf above and that will be closed here
837 // for send_bpf operation.
838 dnssd_close(listenfd);
839 listenfd = dnssd_InvalidSocket; // Make sure we don't close it a second time in the cleanup handling below
842 // At this point we may wait in read_all for a few milliseconds waiting for the daemon to send us the error code,
843 // but that's okay -- the daemon should not take more than a few milliseconds to respond.
844 // set_waitlimit() ensures we do not block indefinitely just in case something is wrong
845 if (sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
846 err = kDNSServiceErr_NoError;
847 else if ((err = set_waitlimit(errsd, DNSSD_CLIENT_TIMEOUT)) == kDNSServiceErr_NoError)
849 if (read_all(errsd, (char*)&err, (int)sizeof(err)) < 0)
850 err = kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us
851 else
852 err = ntohl(err);
854 //syslog(LOG_WARNING, "dnssd_clientstub deliver_request: retrieved error code %d", err);
856 cleanup:
857 if (MakeSeparateReturnSocket)
859 if (dnssd_SocketValid(listenfd)) dnssd_close(listenfd);
860 if (dnssd_SocketValid(errsd)) dnssd_close(errsd);
861 #if defined(USE_NAMED_ERROR_RETURN_SOCKET)
862 // syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removing UDS: %s", data);
863 if (unlink(data) != 0)
864 syslog(LOG_WARNING, "dnssd_clientstub WARNING: unlink(\"%s\") failed errno %d (%s)", data, dnssd_errno, dnssd_strerror(dnssd_errno));
865 // else syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removed UDS: %s", data);
866 #endif
869 free(hdr);
870 return err;
873 int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef)
875 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with NULL DNSServiceRef"); return dnssd_InvalidSocket; }
877 if (!DNSServiceRefValid(sdRef))
879 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with invalid DNSServiceRef %p %08X %08X",
880 sdRef, sdRef->sockfd, sdRef->validator);
881 return dnssd_InvalidSocket;
884 if (sdRef->primary)
886 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
887 return dnssd_InvalidSocket;
890 return (int) sdRef->sockfd;
893 #if _DNS_SD_LIBDISPATCH
894 static void CallbackWithError(DNSServiceRef sdRef, DNSServiceErrorType error)
896 DNSServiceOp *sdr = sdRef;
897 DNSServiceOp *sdrNext;
898 DNSRecord *rec;
899 DNSRecord *recnext;
900 int morebytes;
902 while (sdr)
904 // We can't touch the sdr after the callback as it can be deallocated in the callback
905 sdrNext = sdr->next;
906 morebytes = 1;
907 sdr->moreptr = &morebytes;
908 switch (sdr->op)
910 case resolve_request:
911 if (sdr->AppCallback) ((DNSServiceResolveReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, sdr->AppContext);
912 break;
913 case query_request:
914 if (sdr->AppCallback) ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, 0, sdr->AppContext);
915 break;
916 case addrinfo_request:
917 if (sdr->AppCallback) ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, NULL, 0, sdr->AppContext);
918 break;
919 case browse_request:
920 if (sdr->AppCallback) ((DNSServiceBrowseReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, NULL, sdr->AppContext);
921 break;
922 case reg_service_request:
923 if (sdr->AppCallback) ((DNSServiceRegisterReply) sdr->AppCallback)(sdr, 0, error, NULL, 0, NULL, sdr->AppContext);
924 break;
925 case enumeration_request:
926 if (sdr->AppCallback) ((DNSServiceDomainEnumReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, sdr->AppContext);
927 break;
928 case connection_request:
929 case connection_delegate_request:
930 // This means Register Record, walk the list of DNSRecords to do the callback
931 rec = sdr->rec;
932 while (rec)
934 recnext = rec->recnext;
935 if (rec->AppCallback) ((DNSServiceRegisterRecordReply)rec->AppCallback)(sdr, 0, 0, error, rec->AppContext);
936 // The Callback can call DNSServiceRefDeallocate which in turn frees sdr and all the records.
937 // Detect that and return early
938 if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:Record: CallbackwithError morebytes zero"); return;}
939 rec = recnext;
941 break;
942 case port_mapping_request:
943 if (sdr->AppCallback) ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, 0, 0, error, 0, 0, 0, 0, 0, sdr->AppContext);
944 break;
945 default:
946 syslog(LOG_WARNING, "dnssd_clientstub CallbackWithError called with bad op %d", sdr->op);
948 // If DNSServiceRefDeallocate was called in the callback, morebytes will be zero. As the sdRef
949 // (and its subordinates) have been freed, we should not proceed further. Note that when we
950 // call the callback with a subordinate sdRef the application can call DNSServiceRefDeallocate
951 // on the main sdRef and DNSServiceRefDeallocate handles this case by walking all the sdRefs and
952 // clears the moreptr so that we can terminate here.
954 // If DNSServiceRefDeallocate was not called in the callback, then set moreptr to NULL so that
955 // we don't access the stack variable after we return from this function.
956 if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:sdRef: CallbackwithError morebytes zero sdr %p", sdr); return;}
957 else {sdr->moreptr = NULL;}
958 sdr = sdrNext;
961 #endif // _DNS_SD_LIBDISPATCH
963 // Handle reply from server, calling application client callback. If there is no reply
964 // from the daemon on the socket contained in sdRef, the call will block.
965 DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
967 int morebytes = 0;
969 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
971 if (!DNSServiceRefValid(sdRef))
973 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
974 return kDNSServiceErr_BadReference;
977 if (sdRef->primary)
979 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
980 return kDNSServiceErr_BadReference;
983 if (!sdRef->ProcessReply)
985 static int num_logs = 0;
986 if (num_logs < 10) syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function");
987 if (num_logs < 1000) num_logs++;else sleep(1);
988 return kDNSServiceErr_BadReference;
993 CallbackHeader cbh;
994 char *data;
996 // return NoError on EWOULDBLOCK. This will handle the case
997 // where a non-blocking socket is told there is data, but it was a false positive.
998 // On error, read_all will write a message to syslog for us, so don't need to duplicate that here
999 // Note: If we want to properly support using non-blocking sockets in the future
1000 int result = read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr));
1001 if (result == read_all_fail)
1003 // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
1004 // in the callback.
1005 sdRef->ProcessReply = NULL;
1006 #if _DNS_SD_LIBDISPATCH
1007 // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
1008 // is not called by the application and hence need to communicate the error. Cancel the
1009 // source so that we don't get any more events
1010 // Note: read_all fails if we could not read from the daemon which can happen if the
1011 // daemon dies or the file descriptor is disconnected (defunct).
1012 if (sdRef->disp_source)
1014 dispatch_source_cancel(sdRef->disp_source);
1015 dispatch_release(sdRef->disp_source);
1016 sdRef->disp_source = NULL;
1017 CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
1019 #endif
1020 // Don't touch sdRef anymore as it might have been deallocated
1021 return kDNSServiceErr_ServiceNotRunning;
1023 else if (result == read_all_wouldblock)
1025 if (morebytes && sdRef->logcounter < 100)
1027 sdRef->logcounter++;
1028 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult error: select indicated data was waiting but read_all returned EWOULDBLOCK");
1030 return kDNSServiceErr_NoError;
1033 ConvertHeaderBytes(&cbh.ipc_hdr);
1034 if (cbh.ipc_hdr.version != VERSION)
1036 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult daemon version %d does not match client version %d", cbh.ipc_hdr.version, VERSION);
1037 sdRef->ProcessReply = NULL;
1038 return kDNSServiceErr_Incompatible;
1041 data = malloc(cbh.ipc_hdr.datalen);
1042 if (!data) return kDNSServiceErr_NoMemory;
1043 if (read_all(sdRef->sockfd, data, cbh.ipc_hdr.datalen) < 0) // On error, read_all will write a message to syslog for us
1045 // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
1046 // in the callback.
1047 sdRef->ProcessReply = NULL;
1048 #if _DNS_SD_LIBDISPATCH
1049 // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
1050 // is not called by the application and hence need to communicate the error. Cancel the
1051 // source so that we don't get any more events
1052 if (sdRef->disp_source)
1054 dispatch_source_cancel(sdRef->disp_source);
1055 dispatch_release(sdRef->disp_source);
1056 sdRef->disp_source = NULL;
1057 CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
1059 #endif
1060 // Don't touch sdRef anymore as it might have been deallocated
1061 free(data);
1062 return kDNSServiceErr_ServiceNotRunning;
1064 else
1066 const char *ptr = data;
1067 cbh.cb_flags = get_flags (&ptr, data + cbh.ipc_hdr.datalen);
1068 cbh.cb_interface = get_uint32 (&ptr, data + cbh.ipc_hdr.datalen);
1069 cbh.cb_err = get_error_code(&ptr, data + cbh.ipc_hdr.datalen);
1071 // CAUTION: We have to handle the case where the client calls DNSServiceRefDeallocate from within the callback function.
1072 // To do this we set moreptr to point to morebytes. If the client does call DNSServiceRefDeallocate(),
1073 // then that routine will clear morebytes for us, and cause us to exit our loop.
1074 morebytes = more_bytes(sdRef->sockfd);
1075 if (morebytes)
1077 cbh.cb_flags |= kDNSServiceFlagsMoreComing;
1078 sdRef->moreptr = &morebytes;
1080 if (ptr) sdRef->ProcessReply(sdRef, &cbh, ptr, data + cbh.ipc_hdr.datalen);
1081 // Careful code here:
1082 // If morebytes is non-zero, that means we set sdRef->moreptr above, and the operation was not
1083 // cancelled out from under us, so now we need to clear sdRef->moreptr so we don't leave a stray
1084 // dangling pointer pointing to a long-gone stack variable.
1085 // If morebytes is zero, then one of two thing happened:
1086 // (a) morebytes was 0 above, so we didn't set sdRef->moreptr, so we don't need to clear it
1087 // (b) morebytes was 1 above, and we set sdRef->moreptr, but the operation was cancelled (with DNSServiceRefDeallocate()),
1088 // so we MUST NOT try to dereference our stale sdRef pointer.
1089 if (morebytes) sdRef->moreptr = NULL;
1091 free(data);
1092 } while (morebytes);
1094 return kDNSServiceErr_NoError;
1097 void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef)
1099 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with NULL DNSServiceRef"); return; }
1101 if (!DNSServiceRefValid(sdRef)) // Also verifies dnssd_SocketValid(sdRef->sockfd) for us too
1103 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
1104 return;
1107 // 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
1108 if (sdRef->moreptr) *(sdRef->moreptr) = 0;
1110 if (sdRef->primary) // If this is a subordinate DNSServiceOp, just send a 'stop' command
1112 DNSServiceOp **p = &sdRef->primary->next;
1113 while (*p && *p != sdRef) p = &(*p)->next;
1114 if (*p)
1116 char *ptr;
1117 size_t len = 0;
1118 ipc_msg_hdr *hdr = create_hdr(cancel_request, &len, &ptr, 0, sdRef);
1119 if (hdr)
1121 ConvertHeaderBytes(hdr);
1122 write_all(sdRef->sockfd, (char *)hdr, len);
1123 free(hdr);
1125 *p = sdRef->next;
1126 FreeDNSServiceOp(sdRef);
1129 else // else, make sure to terminate all subordinates as well
1131 #if _DNS_SD_LIBDISPATCH
1132 // The cancel handler will close the fd if a dispatch source has been set
1133 if (sdRef->disp_source)
1135 // By setting the ProcessReply to NULL, we make sure that we never call
1136 // the application callbacks ever, after returning from this function. We
1137 // assume that DNSServiceRefDeallocate is called from the serial queue
1138 // that was passed to DNSServiceSetDispatchQueue. Hence, dispatch_source_cancel
1139 // should cancel all the blocks on the queue and hence there should be no more
1140 // callbacks when we return from this function. Setting ProcessReply to NULL
1141 // provides extra protection.
1142 sdRef->ProcessReply = NULL;
1143 shutdown(sdRef->sockfd, SHUT_WR);
1144 dispatch_source_cancel(sdRef->disp_source);
1145 dispatch_release(sdRef->disp_source);
1146 sdRef->disp_source = NULL;
1148 // if disp_queue is set, it means it used the DNSServiceSetDispatchQueue API. In that case,
1149 // when the source was cancelled, the fd was closed in the handler. Currently the source
1150 // is cancelled only when the mDNSResponder daemon dies
1151 else if (!sdRef->disp_queue) dnssd_close(sdRef->sockfd);
1152 #else
1153 dnssd_close(sdRef->sockfd);
1154 #endif
1155 // Free DNSRecords added in DNSRegisterRecord if they have not
1156 // been freed in DNSRemoveRecord
1157 while (sdRef)
1159 DNSServiceOp *p = sdRef;
1160 sdRef = sdRef->next;
1161 // When there is an error reading from the daemon e.g., bad fd, CallbackWithError
1162 // is called which sets moreptr. It might set the moreptr on a subordinate sdRef
1163 // but the application might call DNSServiceRefDeallocate with the main sdRef from
1164 // the callback. Hence, when we loop through the subordinate sdRefs, we need
1165 // to clear the moreptr so that CallbackWithError can terminate itself instead of
1166 // walking through the freed sdRefs.
1167 if (p->moreptr) *(p->moreptr) = 0;
1168 FreeDNSServiceOp(p);
1173 DNSServiceErrorType DNSSD_API DNSServiceGetProperty(const char *property, void *result, uint32_t *size)
1175 char *ptr;
1176 size_t len = strlen(property) + 1;
1177 ipc_msg_hdr *hdr;
1178 DNSServiceOp *tmp;
1179 uint32_t actualsize;
1181 DNSServiceErrorType err = ConnectToServer(&tmp, 0, getproperty_request, NULL, NULL, NULL);
1182 if (err) return err;
1184 hdr = create_hdr(getproperty_request, &len, &ptr, 0, tmp);
1185 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
1187 put_string(property, &ptr);
1188 err = deliver_request(hdr, tmp); // Will free hdr for us
1189 if (err) { DNSServiceRefDeallocate(tmp); return err; }
1191 if (read_all(tmp->sockfd, (char*)&actualsize, (int)sizeof(actualsize)) < 0)
1192 { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
1194 actualsize = ntohl(actualsize);
1195 if (read_all(tmp->sockfd, (char*)result, actualsize < *size ? actualsize : *size) < 0)
1196 { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
1197 DNSServiceRefDeallocate(tmp);
1199 // Swap version result back to local process byte order
1200 if (!strcmp(property, kDNSServiceProperty_DaemonVersion) && *size >= 4)
1201 *(uint32_t*)result = ntohl(*(uint32_t*)result);
1203 *size = actualsize;
1204 return kDNSServiceErr_NoError;
1207 DNSServiceErrorType DNSSD_API DNSServiceGetPID(const uint16_t srcport, int32_t *pid)
1209 char *ptr;
1210 ipc_msg_hdr *hdr;
1211 DNSServiceOp *tmp;
1212 size_t len = sizeof(int32_t);
1214 DNSServiceErrorType err = ConnectToServer(&tmp, 0, getpid_request, NULL, NULL, NULL);
1215 if (err) return err;
1217 hdr = create_hdr(getpid_request, &len, &ptr, 0, tmp);
1218 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
1220 put_uint16(srcport, &ptr);
1221 err = deliver_request(hdr, tmp); // Will free hdr for us
1222 if (err) { DNSServiceRefDeallocate(tmp); return err; }
1224 if (read_all(tmp->sockfd, (char*)pid, sizeof(int32_t)) < 0)
1225 { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
1227 DNSServiceRefDeallocate(tmp);
1228 return kDNSServiceErr_NoError;
1231 static void handle_resolve_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *end)
1233 char fullname[kDNSServiceMaxDomainName];
1234 char target[kDNSServiceMaxDomainName];
1235 uint16_t txtlen;
1236 union { uint16_t s; u_char b[2]; } port;
1237 unsigned char *txtrecord;
1239 get_string(&data, end, fullname, kDNSServiceMaxDomainName);
1240 get_string(&data, end, target, kDNSServiceMaxDomainName);
1241 if (!data || data + 2 > end) goto fail;
1243 port.b[0] = *data++;
1244 port.b[1] = *data++;
1245 txtlen = get_uint16(&data, end);
1246 txtrecord = (unsigned char *)get_rdata(&data, end, txtlen);
1248 if (!data) goto fail;
1249 ((DNSServiceResolveReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, fullname, target, port.s, txtlen, txtrecord, sdr->AppContext);
1250 return;
1251 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1252 fail:
1253 syslog(LOG_WARNING, "dnssd_clientstub handle_resolve_response: error reading result from daemon");
1256 #if TARGET_OS_EMBEDDED
1258 static int32_t libSystemVersion = 0;
1260 // Return true if the iOS application linked against a version of libsystem where P2P
1261 // interfaces were included by default when using kDNSServiceInterfaceIndexAny.
1262 // Using 160.0.0 == 0xa00000 as the version threshold.
1263 static int includeP2PWithIndexAny()
1265 if (libSystemVersion == 0)
1266 libSystemVersion = NSVersionOfLinkTimeLibrary("System");
1268 if (libSystemVersion < 0xa00000)
1269 return 1;
1270 else
1271 return 0;
1274 #else // TARGET_OS_EMBEDDED
1276 // always return false for non iOS platforms
1277 static int includeP2PWithIndexAny()
1279 return 0;
1282 #endif // TARGET_OS_EMBEDDED
1284 DNSServiceErrorType DNSSD_API DNSServiceResolve
1286 DNSServiceRef *sdRef,
1287 DNSServiceFlags flags,
1288 uint32_t interfaceIndex,
1289 const char *name,
1290 const char *regtype,
1291 const char *domain,
1292 DNSServiceResolveReply callBack,
1293 void *context
1296 char *ptr;
1297 size_t len;
1298 ipc_msg_hdr *hdr;
1299 DNSServiceErrorType err;
1301 if (!name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam;
1303 // Need a real InterfaceID for WakeOnResolve
1304 if ((flags & kDNSServiceFlagsWakeOnResolve) != 0 &&
1305 ((interfaceIndex == kDNSServiceInterfaceIndexAny) ||
1306 (interfaceIndex == kDNSServiceInterfaceIndexLocalOnly) ||
1307 (interfaceIndex == kDNSServiceInterfaceIndexUnicast) ||
1308 (interfaceIndex == kDNSServiceInterfaceIndexP2P)))
1310 return kDNSServiceErr_BadParam;
1313 if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
1314 flags |= kDNSServiceFlagsIncludeP2P;
1316 err = ConnectToServer(sdRef, flags, resolve_request, handle_resolve_response, (void *)callBack, context);
1317 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1319 // Calculate total message length
1320 len = sizeof(flags);
1321 len += sizeof(interfaceIndex);
1322 len += strlen(name) + 1;
1323 len += strlen(regtype) + 1;
1324 len += strlen(domain) + 1;
1326 hdr = create_hdr(resolve_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1327 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1329 put_flags(flags, &ptr);
1330 put_uint32(interfaceIndex, &ptr);
1331 put_string(name, &ptr);
1332 put_string(regtype, &ptr);
1333 put_string(domain, &ptr);
1335 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1336 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1337 return err;
1340 static void handle_query_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
1342 uint32_t ttl;
1343 char name[kDNSServiceMaxDomainName];
1344 uint16_t rrtype, rrclass, rdlen;
1345 const char *rdata;
1347 get_string(&data, end, name, kDNSServiceMaxDomainName);
1348 rrtype = get_uint16(&data, end);
1349 rrclass = get_uint16(&data, end);
1350 rdlen = get_uint16(&data, end);
1351 rdata = get_rdata(&data, end, rdlen);
1352 ttl = get_uint32(&data, end);
1354 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_query_response: error reading result from daemon");
1355 else ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, name, rrtype, rrclass, rdlen, rdata, ttl, sdr->AppContext);
1356 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1359 DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
1361 DNSServiceRef *sdRef,
1362 DNSServiceFlags flags,
1363 uint32_t interfaceIndex,
1364 const char *name,
1365 uint16_t rrtype,
1366 uint16_t rrclass,
1367 DNSServiceQueryRecordReply callBack,
1368 void *context
1371 char *ptr;
1372 size_t len;
1373 ipc_msg_hdr *hdr;
1374 DNSServiceErrorType err;
1376 if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
1377 flags |= kDNSServiceFlagsIncludeP2P;
1379 err = ConnectToServer(sdRef, flags, query_request, handle_query_response, (void *)callBack, context);
1380 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1382 if (!name) name = "\0";
1384 // Calculate total message length
1385 len = sizeof(flags);
1386 len += sizeof(uint32_t); // interfaceIndex
1387 len += strlen(name) + 1;
1388 len += 2 * sizeof(uint16_t); // rrtype, rrclass
1390 hdr = create_hdr(query_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1391 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1393 put_flags(flags, &ptr);
1394 put_uint32(interfaceIndex, &ptr);
1395 put_string(name, &ptr);
1396 put_uint16(rrtype, &ptr);
1397 put_uint16(rrclass, &ptr);
1399 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1400 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1401 return err;
1404 static void handle_addrinfo_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
1406 char hostname[kDNSServiceMaxDomainName];
1407 uint16_t rrtype, rrclass, rdlen;
1408 const char *rdata;
1409 uint32_t ttl;
1411 get_string(&data, end, hostname, kDNSServiceMaxDomainName);
1412 rrtype = get_uint16(&data, end);
1413 rrclass = get_uint16(&data, end);
1414 rdlen = get_uint16(&data, end);
1415 rdata = get_rdata (&data, end, rdlen);
1416 ttl = get_uint32(&data, end);
1417 (void)rrclass; // Unused
1419 // We only generate client callbacks for A and AAAA results (including NXDOMAIN results for
1420 // those types, if the client has requested those with the kDNSServiceFlagsReturnIntermediates).
1421 // Other result types, specifically CNAME referrals, are not communicated to the client, because
1422 // the DNSServiceGetAddrInfoReply interface doesn't have any meaningful way to communiate CNAME referrals.
1423 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_addrinfo_response: error reading result from daemon");
1424 else if (rrtype == kDNSServiceType_A || rrtype == kDNSServiceType_AAAA)
1426 struct sockaddr_in sa4;
1427 struct sockaddr_in6 sa6;
1428 const struct sockaddr *const sa = (rrtype == kDNSServiceType_A) ? (struct sockaddr*)&sa4 : (struct sockaddr*)&sa6;
1429 if (rrtype == kDNSServiceType_A)
1431 memset(&sa4, 0, sizeof(sa4));
1432 #ifndef NOT_HAVE_SA_LEN
1433 sa4.sin_len = sizeof(struct sockaddr_in);
1434 #endif
1435 sa4.sin_family = AF_INET;
1436 // sin_port = 0;
1437 if (!cbh->cb_err) memcpy(&sa4.sin_addr, rdata, rdlen);
1439 else
1441 memset(&sa6, 0, sizeof(sa6));
1442 #ifndef NOT_HAVE_SA_LEN
1443 sa6.sin6_len = sizeof(struct sockaddr_in6);
1444 #endif
1445 sa6.sin6_family = AF_INET6;
1446 // sin6_port = 0;
1447 // sin6_flowinfo = 0;
1448 // sin6_scope_id = 0;
1449 if (!cbh->cb_err)
1451 memcpy(&sa6.sin6_addr, rdata, rdlen);
1452 if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr)) sa6.sin6_scope_id = cbh->cb_interface;
1455 // Validation results are always delivered separately from the actual results of the
1456 // DNSServiceGetAddrInfo. Set the "addr" to NULL as per the documentation.
1458 // Note: If we deliver validation results along with the "addr" in the future, we need
1459 // a way to differentiate the negative response from validation-only response as both
1460 // has zero address.
1461 if (!(cbh->cb_flags & kDNSServiceFlagsValidate))
1462 ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, sa, ttl, sdr->AppContext);
1463 else
1464 ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, NULL, 0, sdr->AppContext);
1465 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1469 DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
1471 DNSServiceRef *sdRef,
1472 DNSServiceFlags flags,
1473 uint32_t interfaceIndex,
1474 uint32_t protocol,
1475 const char *hostname,
1476 DNSServiceGetAddrInfoReply callBack,
1477 void *context /* may be NULL */
1480 char *ptr;
1481 size_t len;
1482 ipc_msg_hdr *hdr;
1483 DNSServiceErrorType err;
1485 if (!hostname) return kDNSServiceErr_BadParam;
1487 err = ConnectToServer(sdRef, flags, addrinfo_request, handle_addrinfo_response, (void *)callBack, context);
1488 if (err)
1490 return err; // On error ConnectToServer leaves *sdRef set to NULL
1493 // Calculate total message length
1494 len = sizeof(flags);
1495 len += sizeof(uint32_t); // interfaceIndex
1496 len += sizeof(uint32_t); // protocol
1497 len += strlen(hostname) + 1;
1499 hdr = create_hdr(addrinfo_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1500 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1502 put_flags(flags, &ptr);
1503 put_uint32(interfaceIndex, &ptr);
1504 put_uint32(protocol, &ptr);
1505 put_string(hostname, &ptr);
1507 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1508 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1509 return err;
1512 static void handle_browse_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
1514 char replyName[256], replyType[kDNSServiceMaxDomainName], replyDomain[kDNSServiceMaxDomainName];
1515 get_string(&data, end, replyName, 256);
1516 get_string(&data, end, replyType, kDNSServiceMaxDomainName);
1517 get_string(&data, end, replyDomain, kDNSServiceMaxDomainName);
1518 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_browse_response: error reading result from daemon");
1519 else ((DNSServiceBrowseReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, replyName, replyType, replyDomain, sdr->AppContext);
1520 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1523 DNSServiceErrorType DNSSD_API DNSServiceBrowse
1525 DNSServiceRef *sdRef,
1526 DNSServiceFlags flags,
1527 uint32_t interfaceIndex,
1528 const char *regtype,
1529 const char *domain,
1530 DNSServiceBrowseReply callBack,
1531 void *context
1534 char *ptr;
1535 size_t len;
1536 ipc_msg_hdr *hdr;
1537 DNSServiceErrorType err;
1539 if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
1540 flags |= kDNSServiceFlagsIncludeP2P;
1542 err = ConnectToServer(sdRef, flags, browse_request, handle_browse_response, (void *)callBack, context);
1543 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1545 if (!domain) domain = "";
1546 len = sizeof(flags);
1547 len += sizeof(interfaceIndex);
1548 len += strlen(regtype) + 1;
1549 len += strlen(domain) + 1;
1551 hdr = create_hdr(browse_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1552 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1554 put_flags(flags, &ptr);
1555 put_uint32(interfaceIndex, &ptr);
1556 put_string(regtype, &ptr);
1557 put_string(domain, &ptr);
1559 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1560 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1561 return err;
1564 DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain);
1565 DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain)
1567 DNSServiceOp *tmp;
1568 char *ptr;
1569 size_t len = sizeof(flags) + strlen(domain) + 1;
1570 ipc_msg_hdr *hdr;
1571 DNSServiceErrorType err = ConnectToServer(&tmp, 0, setdomain_request, NULL, NULL, NULL);
1572 if (err) return err;
1574 hdr = create_hdr(setdomain_request, &len, &ptr, 0, tmp);
1575 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
1577 put_flags(flags, &ptr);
1578 put_string(domain, &ptr);
1579 err = deliver_request(hdr, tmp); // Will free hdr for us
1580 DNSServiceRefDeallocate(tmp);
1581 return err;
1584 static void handle_regservice_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
1586 char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
1587 get_string(&data, end, name, 256);
1588 get_string(&data, end, regtype, kDNSServiceMaxDomainName);
1589 get_string(&data, end, domain, kDNSServiceMaxDomainName);
1590 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_regservice_response: error reading result from daemon");
1591 else ((DNSServiceRegisterReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_err, name, regtype, domain, sdr->AppContext);
1592 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1595 DNSServiceErrorType DNSSD_API DNSServiceRegister
1597 DNSServiceRef *sdRef,
1598 DNSServiceFlags flags,
1599 uint32_t interfaceIndex,
1600 const char *name,
1601 const char *regtype,
1602 const char *domain,
1603 const char *host,
1604 uint16_t PortInNetworkByteOrder,
1605 uint16_t txtLen,
1606 const void *txtRecord,
1607 DNSServiceRegisterReply callBack,
1608 void *context
1611 char *ptr;
1612 size_t len;
1613 ipc_msg_hdr *hdr;
1614 DNSServiceErrorType err;
1615 union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder };
1617 if (!name) name = "";
1618 if (!regtype) return kDNSServiceErr_BadParam;
1619 if (!domain) domain = "";
1620 if (!host) host = "";
1621 if (!txtRecord) txtRecord = (void*)"";
1623 // No callback must have auto-rename
1624 if (!callBack && (flags & kDNSServiceFlagsNoAutoRename)) return kDNSServiceErr_BadParam;
1626 if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
1627 flags |= kDNSServiceFlagsIncludeP2P;
1629 err = ConnectToServer(sdRef, flags, reg_service_request, callBack ? handle_regservice_response : NULL, (void *)callBack, context);
1630 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1632 len = sizeof(DNSServiceFlags);
1633 len += sizeof(uint32_t); // interfaceIndex
1634 len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4;
1635 len += 2 * sizeof(uint16_t); // port, txtLen
1636 len += txtLen;
1638 hdr = create_hdr(reg_service_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1639 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1640 if (!callBack) hdr->ipc_flags |= IPC_FLAGS_NOREPLY;
1642 put_flags(flags, &ptr);
1643 put_uint32(interfaceIndex, &ptr);
1644 put_string(name, &ptr);
1645 put_string(regtype, &ptr);
1646 put_string(domain, &ptr);
1647 put_string(host, &ptr);
1648 *ptr++ = port.b[0];
1649 *ptr++ = port.b[1];
1650 put_uint16(txtLen, &ptr);
1651 put_rdata(txtLen, txtRecord, &ptr);
1653 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1654 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1655 return err;
1658 static void handle_enumeration_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
1660 char domain[kDNSServiceMaxDomainName];
1661 get_string(&data, end, domain, kDNSServiceMaxDomainName);
1662 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_enumeration_response: error reading result from daemon");
1663 else ((DNSServiceDomainEnumReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, domain, sdr->AppContext);
1664 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1667 DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
1669 DNSServiceRef *sdRef,
1670 DNSServiceFlags flags,
1671 uint32_t interfaceIndex,
1672 DNSServiceDomainEnumReply callBack,
1673 void *context
1676 char *ptr;
1677 size_t len;
1678 ipc_msg_hdr *hdr;
1679 DNSServiceErrorType err;
1681 int f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0;
1682 int f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0;
1683 if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
1685 err = ConnectToServer(sdRef, flags, enumeration_request, handle_enumeration_response, (void *)callBack, context);
1686 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1688 len = sizeof(DNSServiceFlags);
1689 len += sizeof(uint32_t);
1691 hdr = create_hdr(enumeration_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1692 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1694 put_flags(flags, &ptr);
1695 put_uint32(interfaceIndex, &ptr);
1697 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1698 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1699 return err;
1702 static void ConnectionResponse(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *const data, const char *const end)
1704 (void)data; // Unused
1706 //printf("ConnectionResponse got %d\n", cbh->ipc_hdr.op);
1707 if (cbh->ipc_hdr.op != reg_record_reply_op)
1709 // When using kDNSServiceFlagsShareConnection, need to search the list of associated DNSServiceOps
1710 // to find the one this response is intended for, and then call through to its ProcessReply handler.
1711 // We start with our first subordinate DNSServiceRef -- don't want to accidentally match the parent DNSServiceRef.
1712 DNSServiceOp *op = sdr->next;
1713 while (op && (op->uid.u32[0] != cbh->ipc_hdr.client_context.u32[0] || op->uid.u32[1] != cbh->ipc_hdr.client_context.u32[1]))
1714 op = op->next;
1715 // Note: We may sometimes not find a matching DNSServiceOp, in the case where the client has
1716 // cancelled the subordinate DNSServiceOp, but there are still messages in the pipeline from the daemon
1717 if (op && op->ProcessReply) op->ProcessReply(op, cbh, data, end);
1718 // WARNING: Don't touch op or sdr after this -- client may have called DNSServiceRefDeallocate
1719 return;
1721 else
1723 DNSRecordRef rec;
1724 for (rec = sdr->rec; rec; rec = rec->recnext)
1726 if (rec->uid.u32[0] == cbh->ipc_hdr.client_context.u32[0] && rec->uid.u32[1] == cbh->ipc_hdr.client_context.u32[1])
1727 break;
1729 // The record might have been freed already and hence not an
1730 // error if the record is not found.
1731 if (!rec)
1733 syslog(LOG_INFO, "ConnectionResponse: Record not found");
1734 return;
1736 if (rec->sdr != sdr)
1738 syslog(LOG_WARNING, "ConnectionResponse: Record sdr mismatch: rec %p sdr %p", rec->sdr, sdr);
1739 return;
1742 if (sdr->op == connection_request || sdr->op == connection_delegate_request)
1744 rec->AppCallback(rec->sdr, rec, cbh->cb_flags, cbh->cb_err, rec->AppContext);
1746 else
1748 syslog(LOG_WARNING, "dnssd_clientstub ConnectionResponse: sdr->op != connection_request");
1749 rec->AppCallback(rec->sdr, rec, 0, kDNSServiceErr_Unknown, rec->AppContext);
1751 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1755 DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef)
1757 char *ptr;
1758 size_t len = 0;
1759 ipc_msg_hdr *hdr;
1760 DNSServiceErrorType err = ConnectToServer(sdRef, 0, connection_request, ConnectionResponse, NULL, NULL);
1761 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1763 hdr = create_hdr(connection_request, &len, &ptr, 0, *sdRef);
1764 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1766 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1767 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1768 return err;
1771 #if APPLE_OSX_mDNSResponder && !TARGET_IPHONE_SIMULATOR
1772 DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid)
1774 char *ptr;
1775 size_t len = 0;
1776 ipc_msg_hdr *hdr;
1778 DNSServiceErrorType err = ConnectToServer(sdRef, 0, connection_delegate_request, ConnectionResponse, NULL, NULL);
1779 if (err)
1781 return err; // On error ConnectToServer leaves *sdRef set to NULL
1784 // Only one of the two options can be set. If pid is zero, uuid is used.
1785 // If both are specified only pid will be used. We send across the pid
1786 // so that the daemon knows what to read from the socket.
1788 len += sizeof(int32_t);
1790 hdr = create_hdr(connection_delegate_request, &len, &ptr, 0, *sdRef);
1791 if (!hdr)
1793 DNSServiceRefDeallocate(*sdRef);
1794 *sdRef = NULL;
1795 return kDNSServiceErr_NoMemory;
1798 if (pid && setsockopt((*sdRef)->sockfd, SOL_SOCKET, SO_DELEGATED, &pid, sizeof(pid)) == -1)
1800 syslog(LOG_WARNING, "dnssdclientstub: Could not setsockopt() for PID[%d], no entitlements or process(pid) invalid errno:%d (%s)", pid, errno, strerror(errno));
1801 // Free the hdr in case we return before calling deliver_request()
1802 if (hdr)
1803 free(hdr);
1804 DNSServiceRefDeallocate(*sdRef);
1805 *sdRef = NULL;
1806 return kDNSServiceErr_NoAuth;
1809 if (!pid && setsockopt((*sdRef)->sockfd, SOL_SOCKET, SO_DELEGATED_UUID, uuid, sizeof(uuid_t)) == -1)
1811 syslog(LOG_WARNING, "dnssdclientstub: Could not setsockopt() for UUID, no entitlements or process(uuid) invalid errno:%d (%s) ", errno, strerror(errno));
1812 // Free the hdr in case we return before calling deliver_request()
1813 if (hdr)
1814 free(hdr);
1815 DNSServiceRefDeallocate(*sdRef);
1816 *sdRef = NULL;
1817 return kDNSServiceErr_NoAuth;
1820 put_uint32(pid, &ptr);
1822 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1823 if (err)
1825 DNSServiceRefDeallocate(*sdRef);
1826 *sdRef = NULL;
1828 return err;
1830 #elif TARGET_IPHONE_SIMULATOR // This hack is for Simulator platform only
1831 DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid)
1833 (void) pid;
1834 (void) uuid;
1835 return DNSServiceCreateConnection(sdRef);
1837 #endif
1839 DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
1841 DNSServiceRef sdRef,
1842 DNSRecordRef *RecordRef,
1843 DNSServiceFlags flags,
1844 uint32_t interfaceIndex,
1845 const char *fullname,
1846 uint16_t rrtype,
1847 uint16_t rrclass,
1848 uint16_t rdlen,
1849 const void *rdata,
1850 uint32_t ttl,
1851 DNSServiceRegisterRecordReply callBack,
1852 void *context
1855 char *ptr;
1856 size_t len;
1857 ipc_msg_hdr *hdr = NULL;
1858 DNSRecordRef rref = NULL;
1859 DNSRecord **p;
1860 int f1 = (flags & kDNSServiceFlagsShared) != 0;
1861 int f2 = (flags & kDNSServiceFlagsUnique) != 0;
1862 if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
1864 if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
1865 flags |= kDNSServiceFlagsIncludeP2P;
1867 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
1869 if (!DNSServiceRefValid(sdRef))
1871 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
1872 return kDNSServiceErr_BadReference;
1875 if (sdRef->op != connection_request && sdRef->op != connection_delegate_request)
1877 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with non-DNSServiceCreateConnection DNSServiceRef %p %d", sdRef, sdRef->op);
1878 return kDNSServiceErr_BadReference;
1881 *RecordRef = NULL;
1883 len = sizeof(DNSServiceFlags);
1884 len += 2 * sizeof(uint32_t); // interfaceIndex, ttl
1885 len += 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen
1886 len += strlen(fullname) + 1;
1887 len += rdlen;
1889 // Bump up the uid. Normally for shared operations (kDNSServiceFlagsShareConnection), this
1890 // is done in ConnectToServer. For DNSServiceRegisterRecord, ConnectToServer has already
1891 // been called. As multiple DNSServiceRegisterRecords can be multiplexed over a single
1892 // connection, we need a way to demultiplex the response so that the callback corresponding
1893 // to the right DNSServiceRegisterRecord instance can be called. Use the same mechanism that
1894 // is used by kDNSServiceFlagsShareConnection. create_hdr copies the uid value to ipc
1895 // hdr->client_context which will be returned in the ipc response.
1896 if (++sdRef->uid.u32[0] == 0)
1897 ++sdRef->uid.u32[1];
1898 hdr = create_hdr(reg_record_request, &len, &ptr, 1, sdRef);
1899 if (!hdr) return kDNSServiceErr_NoMemory;
1901 put_flags(flags, &ptr);
1902 put_uint32(interfaceIndex, &ptr);
1903 put_string(fullname, &ptr);
1904 put_uint16(rrtype, &ptr);
1905 put_uint16(rrclass, &ptr);
1906 put_uint16(rdlen, &ptr);
1907 put_rdata(rdlen, rdata, &ptr);
1908 put_uint32(ttl, &ptr);
1910 rref = malloc(sizeof(DNSRecord));
1911 if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; }
1912 rref->AppContext = context;
1913 rref->AppCallback = callBack;
1914 rref->record_index = sdRef->max_index++;
1915 rref->sdr = sdRef;
1916 rref->recnext = NULL;
1917 *RecordRef = rref;
1918 // Remember the uid that we are sending across so that we can match
1919 // when the response comes back.
1920 rref->uid = sdRef->uid;
1921 hdr->reg_index = rref->record_index;
1923 p = &(sdRef)->rec;
1924 while (*p) p = &(*p)->recnext;
1925 *p = rref;
1927 return deliver_request(hdr, sdRef); // Will free hdr for us
1930 // sdRef returned by DNSServiceRegister()
1931 DNSServiceErrorType DNSSD_API DNSServiceAddRecord
1933 DNSServiceRef sdRef,
1934 DNSRecordRef *RecordRef,
1935 DNSServiceFlags flags,
1936 uint16_t rrtype,
1937 uint16_t rdlen,
1938 const void *rdata,
1939 uint32_t ttl
1942 ipc_msg_hdr *hdr;
1943 size_t len = 0;
1944 char *ptr;
1945 DNSRecordRef rref;
1946 DNSRecord **p;
1948 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
1949 if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSRecordRef pointer"); return kDNSServiceErr_BadParam; }
1950 if (sdRef->op != reg_service_request)
1952 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with non-DNSServiceRegister DNSServiceRef %p %d", sdRef, sdRef->op);
1953 return kDNSServiceErr_BadReference;
1956 if (!DNSServiceRefValid(sdRef))
1958 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
1959 return kDNSServiceErr_BadReference;
1962 *RecordRef = NULL;
1964 len += 2 * sizeof(uint16_t); // rrtype, rdlen
1965 len += rdlen;
1966 len += sizeof(uint32_t);
1967 len += sizeof(DNSServiceFlags);
1969 hdr = create_hdr(add_record_request, &len, &ptr, 1, sdRef);
1970 if (!hdr) return kDNSServiceErr_NoMemory;
1971 put_flags(flags, &ptr);
1972 put_uint16(rrtype, &ptr);
1973 put_uint16(rdlen, &ptr);
1974 put_rdata(rdlen, rdata, &ptr);
1975 put_uint32(ttl, &ptr);
1977 rref = malloc(sizeof(DNSRecord));
1978 if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; }
1979 rref->AppContext = NULL;
1980 rref->AppCallback = NULL;
1981 rref->record_index = sdRef->max_index++;
1982 rref->sdr = sdRef;
1983 rref->recnext = NULL;
1984 *RecordRef = rref;
1985 hdr->reg_index = rref->record_index;
1987 p = &(sdRef)->rec;
1988 while (*p) p = &(*p)->recnext;
1989 *p = rref;
1991 return deliver_request(hdr, sdRef); // Will free hdr for us
1994 // DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
1995 DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
1997 DNSServiceRef sdRef,
1998 DNSRecordRef RecordRef,
1999 DNSServiceFlags flags,
2000 uint16_t rdlen,
2001 const void *rdata,
2002 uint32_t ttl
2005 ipc_msg_hdr *hdr;
2006 size_t len = 0;
2007 char *ptr;
2009 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
2011 if (!DNSServiceRefValid(sdRef))
2013 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
2014 return kDNSServiceErr_BadReference;
2017 // Note: RecordRef is allowed to be NULL
2019 len += sizeof(uint16_t);
2020 len += rdlen;
2021 len += sizeof(uint32_t);
2022 len += sizeof(DNSServiceFlags);
2024 hdr = create_hdr(update_record_request, &len, &ptr, 1, sdRef);
2025 if (!hdr) return kDNSServiceErr_NoMemory;
2026 hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX;
2027 put_flags(flags, &ptr);
2028 put_uint16(rdlen, &ptr);
2029 put_rdata(rdlen, rdata, &ptr);
2030 put_uint32(ttl, &ptr);
2031 return deliver_request(hdr, sdRef); // Will free hdr for us
2034 DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
2036 DNSServiceRef sdRef,
2037 DNSRecordRef RecordRef,
2038 DNSServiceFlags flags
2041 ipc_msg_hdr *hdr;
2042 size_t len = 0;
2043 char *ptr;
2044 DNSServiceErrorType err;
2046 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
2047 if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSRecordRef"); return kDNSServiceErr_BadParam; }
2048 if (!sdRef->max_index) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with bad DNSServiceRef"); return kDNSServiceErr_BadReference; }
2050 if (!DNSServiceRefValid(sdRef))
2052 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
2053 return kDNSServiceErr_BadReference;
2056 len += sizeof(flags);
2057 hdr = create_hdr(remove_record_request, &len, &ptr, 1, sdRef);
2058 if (!hdr) return kDNSServiceErr_NoMemory;
2059 hdr->reg_index = RecordRef->record_index;
2060 put_flags(flags, &ptr);
2061 err = deliver_request(hdr, sdRef); // Will free hdr for us
2062 if (!err)
2064 // This RecordRef could have been allocated in DNSServiceRegisterRecord or DNSServiceAddRecord.
2065 // If so, delink from the list before freeing
2066 DNSRecord **p = &sdRef->rec;
2067 while (*p && *p != RecordRef) p = &(*p)->recnext;
2068 if (*p) *p = RecordRef->recnext;
2069 free(RecordRef);
2071 return err;
2074 DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
2076 DNSServiceFlags flags,
2077 uint32_t interfaceIndex,
2078 const char *fullname,
2079 uint16_t rrtype,
2080 uint16_t rrclass,
2081 uint16_t rdlen,
2082 const void *rdata
2085 char *ptr;
2086 size_t len;
2087 ipc_msg_hdr *hdr;
2088 DNSServiceOp *tmp;
2090 DNSServiceErrorType err = ConnectToServer(&tmp, flags, reconfirm_record_request, NULL, NULL, NULL);
2091 if (err) return err;
2093 len = sizeof(DNSServiceFlags);
2094 len += sizeof(uint32_t);
2095 len += strlen(fullname) + 1;
2096 len += 3 * sizeof(uint16_t);
2097 len += rdlen;
2098 hdr = create_hdr(reconfirm_record_request, &len, &ptr, 0, tmp);
2099 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
2101 put_flags(flags, &ptr);
2102 put_uint32(interfaceIndex, &ptr);
2103 put_string(fullname, &ptr);
2104 put_uint16(rrtype, &ptr);
2105 put_uint16(rrclass, &ptr);
2106 put_uint16(rdlen, &ptr);
2107 put_rdata(rdlen, rdata, &ptr);
2109 err = deliver_request(hdr, tmp); // Will free hdr for us
2110 DNSServiceRefDeallocate(tmp);
2111 return err;
2115 static void handle_port_mapping_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
2117 union { uint32_t l; u_char b[4]; } addr;
2118 uint8_t protocol;
2119 union { uint16_t s; u_char b[2]; } internalPort;
2120 union { uint16_t s; u_char b[2]; } externalPort;
2121 uint32_t ttl;
2123 if (!data || data + 13 > end) goto fail;
2125 addr.b[0] = *data++;
2126 addr.b[1] = *data++;
2127 addr.b[2] = *data++;
2128 addr.b[3] = *data++;
2129 protocol = *data++;
2130 internalPort.b[0] = *data++;
2131 internalPort.b[1] = *data++;
2132 externalPort.b[0] = *data++;
2133 externalPort.b[1] = *data++;
2134 ttl = get_uint32(&data, end);
2135 if (!data) goto fail;
2137 ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, addr.l, protocol, internalPort.s, externalPort.s, ttl, sdr->AppContext);
2138 return;
2139 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
2141 fail :
2142 syslog(LOG_WARNING, "dnssd_clientstub handle_port_mapping_response: error reading result from daemon");
2145 DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
2147 DNSServiceRef *sdRef,
2148 DNSServiceFlags flags,
2149 uint32_t interfaceIndex,
2150 uint32_t protocol, /* TCP and/or UDP */
2151 uint16_t internalPortInNetworkByteOrder,
2152 uint16_t externalPortInNetworkByteOrder,
2153 uint32_t ttl, /* time to live in seconds */
2154 DNSServiceNATPortMappingReply callBack,
2155 void *context /* may be NULL */
2158 char *ptr;
2159 size_t len;
2160 ipc_msg_hdr *hdr;
2161 union { uint16_t s; u_char b[2]; } internalPort = { internalPortInNetworkByteOrder };
2162 union { uint16_t s; u_char b[2]; } externalPort = { externalPortInNetworkByteOrder };
2164 DNSServiceErrorType err = ConnectToServer(sdRef, flags, port_mapping_request, handle_port_mapping_response, (void *)callBack, context);
2165 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
2167 len = sizeof(flags);
2168 len += sizeof(interfaceIndex);
2169 len += sizeof(protocol);
2170 len += sizeof(internalPort);
2171 len += sizeof(externalPort);
2172 len += sizeof(ttl);
2174 hdr = create_hdr(port_mapping_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
2175 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
2177 put_flags(flags, &ptr);
2178 put_uint32(interfaceIndex, &ptr);
2179 put_uint32(protocol, &ptr);
2180 *ptr++ = internalPort.b[0];
2181 *ptr++ = internalPort.b[1];
2182 *ptr++ = externalPort.b[0];
2183 *ptr++ = externalPort.b[1];
2184 put_uint32(ttl, &ptr);
2186 err = deliver_request(hdr, *sdRef); // Will free hdr for us
2187 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
2188 return err;
2191 #if _DNS_SD_LIBDISPATCH
2192 DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue
2194 DNSServiceRef service,
2195 dispatch_queue_t queue
2198 int dnssd_fd = DNSServiceRefSockFD(service);
2199 if (dnssd_fd == dnssd_InvalidSocket) return kDNSServiceErr_BadParam;
2200 if (!queue)
2202 syslog(LOG_WARNING, "dnssd_clientstub: DNSServiceSetDispatchQueue dispatch queue NULL");
2203 return kDNSServiceErr_BadParam;
2205 if (service->disp_queue)
2207 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch queue set already");
2208 return kDNSServiceErr_BadParam;
2210 if (service->disp_source)
2212 syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch source set already");
2213 return kDNSServiceErr_BadParam;
2215 service->disp_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, dnssd_fd, 0, queue);
2216 if (!service->disp_source)
2218 syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch_source_create failed");
2219 return kDNSServiceErr_NoMemory;
2221 service->disp_queue = queue;
2222 dispatch_source_set_event_handler(service->disp_source, ^{DNSServiceProcessResult(service);});
2223 dispatch_source_set_cancel_handler(service->disp_source, ^{dnssd_close(dnssd_fd);});
2224 dispatch_resume(service->disp_source);
2225 return kDNSServiceErr_NoError;
2227 #endif // _DNS_SD_LIBDISPATCH
2229 #if !defined(_WIN32)
2231 static void DNSSD_API SleepKeepaliveCallback(DNSServiceRef sdRef, DNSRecordRef rec, const DNSServiceFlags flags,
2232 DNSServiceErrorType errorCode, void *context)
2234 SleepKAContext *ka = (SleepKAContext *)context;
2235 (void)rec; // Unused
2236 (void)flags; // Unused
2238 if (sdRef->kacontext != context)
2239 syslog(LOG_WARNING, "SleepKeepaliveCallback context mismatch");
2241 if (ka->AppCallback)
2242 ((DNSServiceSleepKeepaliveReply)ka->AppCallback)(sdRef, errorCode, ka->AppContext);
2245 DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
2247 DNSServiceRef *sdRef,
2248 DNSServiceFlags flags,
2249 int fd,
2250 unsigned int timeout,
2251 DNSServiceSleepKeepaliveReply callBack,
2252 void *context
2255 char source_str[INET6_ADDRSTRLEN];
2256 char target_str[INET6_ADDRSTRLEN];
2257 struct sockaddr_storage lss;
2258 struct sockaddr_storage rss;
2259 socklen_t len1, len2;
2260 unsigned int len, proxyreclen;
2261 char buf[256];
2262 DNSServiceErrorType err;
2263 DNSRecordRef record = NULL;
2264 char name[10];
2265 char recname[128];
2266 SleepKAContext *ka;
2267 unsigned int i, unique;
2270 (void) flags; //unused
2271 if (!timeout) return kDNSServiceErr_BadParam;
2274 len1 = sizeof(lss);
2275 if (getsockname(fd, (struct sockaddr *)&lss, &len1) < 0)
2277 syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getsockname %d\n", errno);
2278 return kDNSServiceErr_BadParam;
2281 len2 = sizeof(rss);
2282 if (getpeername(fd, (struct sockaddr *)&rss, &len2) < 0)
2284 syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getpeername %d\n", errno);
2285 return kDNSServiceErr_BadParam;
2288 if (len1 != len2)
2290 syslog(LOG_WARNING, "DNSServiceSleepKeepalive local/remote info not same");
2291 return kDNSServiceErr_Unknown;
2294 unique = 0;
2295 if (lss.ss_family == AF_INET)
2297 struct sockaddr_in *sl = (struct sockaddr_in *)&lss;
2298 struct sockaddr_in *sr = (struct sockaddr_in *)&rss;
2299 unsigned char *ptr = (unsigned char *)&sl->sin_addr;
2301 if (!inet_ntop(AF_INET, (const void *)&sr->sin_addr, target_str, sizeof (target_str)))
2303 syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote info failed %d", errno);
2304 return kDNSServiceErr_Unknown;
2306 if (!inet_ntop(AF_INET, (const void *)&sl->sin_addr, source_str, sizeof (source_str)))
2308 syslog(LOG_WARNING, "DNSServiceSleepKeepalive local info failed %d", errno);
2309 return kDNSServiceErr_Unknown;
2311 // Sum of all bytes in the local address and port should result in a unique
2312 // number in the local network
2313 for (i = 0; i < sizeof(struct in_addr); i++)
2314 unique += ptr[i];
2315 unique += sl->sin_port;
2316 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));
2318 else
2320 struct sockaddr_in6 *sl6 = (struct sockaddr_in6 *)&lss;
2321 struct sockaddr_in6 *sr6 = (struct sockaddr_in6 *)&rss;
2322 unsigned char *ptr = (unsigned char *)&sl6->sin6_addr;
2324 if (!inet_ntop(AF_INET6, (const void *)&sr6->sin6_addr, target_str, sizeof (target_str)))
2326 syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote6 info failed %d", errno);
2327 return kDNSServiceErr_Unknown;
2329 if (!inet_ntop(AF_INET6, (const void *)&sl6->sin6_addr, source_str, sizeof (source_str)))
2331 syslog(LOG_WARNING, "DNSServiceSleepKeepalive local6 info failed %d", errno);
2332 return kDNSServiceErr_Unknown;
2334 for (i = 0; i < sizeof(struct in6_addr); i++)
2335 unique += ptr[i];
2336 unique += sl6->sin6_port;
2337 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));
2340 if (len >= (sizeof(buf) - 1))
2342 syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit local/remote info");
2343 return kDNSServiceErr_Unknown;
2345 // Include the NULL byte also in the first byte. The total length of the record includes the
2346 // first byte also.
2347 buf[0] = len + 1;
2348 proxyreclen = len + 2;
2350 len = snprintf(name, sizeof(name), "%u", unique);
2351 if (len >= sizeof(name))
2353 syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit unique");
2354 return kDNSServiceErr_Unknown;
2357 len = snprintf(recname, sizeof(recname), "%s.%s", name, "_keepalive._dns-sd._udp.local");
2358 if (len >= sizeof(recname))
2360 syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit name");
2361 return kDNSServiceErr_Unknown;
2364 ka = malloc(sizeof(SleepKAContext));
2365 if (!ka) return kDNSServiceErr_NoMemory;
2366 ka->AppCallback = (void *)callBack;
2367 ka->AppContext = context;
2369 err = DNSServiceCreateConnection(sdRef);
2370 if (err)
2372 syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection");
2373 free(ka);
2374 return err;
2377 // we don't care about the "record". When sdRef gets deallocated later, it will be freed too
2378 err = DNSServiceRegisterRecord(*sdRef, &record, kDNSServiceFlagsUnique, 0, recname,
2379 kDNSServiceType_NULL, kDNSServiceClass_IN, proxyreclen, buf, kDNSServiceInterfaceIndexAny, SleepKeepaliveCallback, ka);
2380 if (err)
2382 syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection");
2383 free(ka);
2384 return err;
2386 (*sdRef)->kacontext = ka;
2387 return kDNSServiceErr_NoError;
2389 #endif