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.
32 #include "dnssd_ipc.h"
34 #if APPLE_OSX_mDNSResponder
35 #include <mach-o/dyld.h>
36 #include <uuid/uuid.h>
37 #include <TargetConditionals.h>
38 #include "dns_sd_internal.h"
44 #include <CommonServices.h>
45 #include <DebugServices.h>
52 #define sockaddr_mdns sockaddr_in
53 #define AF_MDNS AF_INET
55 // Disable warning: "'type cast' : from data pointer 'void *' to function pointer"
56 #pragma warning(disable:4055)
58 // Disable warning: "nonstandard extension, function/data pointer conversion in expression"
59 #pragma warning(disable:4152)
61 extern BOOL
IsSystemServiceDisabled();
63 #define sleep(X) Sleep((X) * 1000)
65 static int g_initWinsock
= 0;
66 #define LOG_WARNING kDebugLevelWarning
67 #define LOG_INFO kDebugLevelInfo
68 static void syslog( int priority
, const char * message
, ...)
73 DWORD err
= WSAGetLastError();
75 va_start( args
, message
);
76 len
= _vscprintf( message
, args
) + 1;
77 buffer
= malloc( len
* sizeof(char) );
78 if ( buffer
) { vsnprintf( buffer
, len
, message
, args
); OutputDebugString( buffer
); free( buffer
); }
79 WSASetLastError( err
);
83 #include <fcntl.h> // For O_RDWR etc.
85 #include <sys/socket.h>
88 #define sockaddr_mdns sockaddr_un
89 #define AF_MDNS AF_LOCAL
94 // <rdar://problem/4096913> Specifies how many times we'll try and connect to the server.
96 #define DNSSD_CLIENT_MAXTRIES 4
99 // Uncomment the line below to use the old error return mechanism of creating a temporary named socket (e.g. in /var/tmp)
100 //#define USE_NAMED_ERROR_RETURN_SOCKET 1
102 // If the UDS client has not received a response from the daemon in 60 secs, it is unlikely to get one
103 // Note: Timeout of 3 secs should be sufficient in normal scenarios, but 60 secs is chosen as a safeguard since
104 // some clients may come up before mDNSResponder itself after a BOOT and on rare ocassions IOPM/Keychain/D2D calls
105 // in mDNSResponder's INIT may take a much longer time to return
106 #define DNSSD_CLIENT_TIMEOUT 60
108 #ifndef CTL_PATH_PREFIX
109 #define CTL_PATH_PREFIX "/var/tmp/dnssd_result_socket."
115 DNSServiceFlags cb_flags
;
116 uint32_t cb_interface
;
117 DNSServiceErrorType cb_err
;
120 typedef struct _DNSServiceRef_t DNSServiceOp
;
121 typedef struct _DNSRecordRef_t DNSRecord
;
126 void *AppCallback
; // Client callback function and context
131 // client stub callback to process message from server and deliver results to client application
132 typedef void (*ProcessReplyFn
)(DNSServiceOp
*const sdr
, const CallbackHeader
*const cbh
, const char *msg
, const char *const end
);
134 #define ValidatorBits 0x12345678
135 #define DNSServiceRefValid(X) (dnssd_SocketValid((X)->sockfd) && (((X)->sockfd ^ (X)->validator) == ValidatorBits))
137 // When using kDNSServiceFlagsShareConnection, there is one primary _DNSServiceOp_t, and zero or more subordinates
138 // For the primary, the 'next' field points to the first subordinate, and its 'next' field points to the next, and so on.
139 // For the primary, the 'primary' field is NULL; for subordinates the 'primary' field points back to the associated primary
141 // _DNS_SD_LIBDISPATCH is defined where libdispatch/GCD is available. This does not mean that the application will use the
142 // DNSServiceSetDispatchQueue API. Hence any new code guarded with _DNS_SD_LIBDISPATCH should still be backwards compatible.
143 struct _DNSServiceRef_t
145 DNSServiceOp
*next
; // For shared connection
146 DNSServiceOp
*primary
; // For shared connection
147 dnssd_sock_t sockfd
; // Connected socket between client and daemon
148 dnssd_sock_t validator
; // Used to detect memory corruption, double disposals, etc.
149 client_context_t uid
; // For shared connection requests, each subordinate DNSServiceRef has its own ID,
150 // unique within the scope of the same shared parent DNSServiceRef
151 uint32_t op
; // request_op_t or reply_op_t
152 uint32_t max_index
; // Largest assigned record index - 0 if no additional records registered
153 uint32_t logcounter
; // Counter used to control number of syslog messages we write
154 int *moreptr
; // Set while DNSServiceProcessResult working on this particular DNSServiceRef
155 ProcessReplyFn ProcessReply
; // Function pointer to the code to handle received messages
156 void *AppCallback
; // Client callback function and context
159 #if _DNS_SD_LIBDISPATCH
160 dispatch_source_t disp_source
;
161 dispatch_queue_t disp_queue
;
166 struct _DNSRecordRef_t
170 DNSServiceRegisterRecordReply AppCallback
;
172 uint32_t record_index
; // index is unique to the ServiceDiscoveryRef
173 client_context_t uid
; // For demultiplexing multiple DNSServiceRegisterRecord calls
177 #if !defined(USE_TCP_LOOPBACK)
178 static void SetUDSPath(struct sockaddr_un
*saddr
, const char *path
)
182 pathLen
= strlen(path
);
183 if (pathLen
< sizeof(saddr
->sun_path
))
184 memcpy(saddr
->sun_path
, path
, pathLen
+ 1);
186 saddr
->sun_path
[0] = '\0';
190 enum { write_all_success
= 0, write_all_fail
= -1, write_all_defunct
= -2 };
192 // Write len bytes. Return 0 on success, -1 on error
193 static int write_all(dnssd_sock_t sd
, char *buf
, size_t len
)
195 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
196 //if (send(sd, buf, len, MSG_WAITALL) != len) return write_all_fail;
199 ssize_t num_written
= send(sd
, buf
, (long)len
, 0);
200 if (num_written
< 0 || (size_t)num_written
> len
)
202 // Check whether socket has gone defunct,
203 // otherwise, an error here indicates some OS bug
204 // or that the mDNSResponder daemon crashed (which should never happen).
205 #if !defined(__ppc__) && defined(SO_ISDEFUNCT)
207 socklen_t dlen
= sizeof (defunct
);
208 if (getsockopt(sd
, SOL_SOCKET
, SO_ISDEFUNCT
, &defunct
, &dlen
) < 0)
209 syslog(LOG_WARNING
, "dnssd_clientstub write_all: SO_ISDEFUNCT failed %d %s", dnssd_errno
, dnssd_strerror(dnssd_errno
));
211 syslog(LOG_WARNING
, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd
,
212 (long)num_written
, (long)len
,
213 (num_written
< 0) ? dnssd_errno
: 0,
214 (num_written
< 0) ? dnssd_strerror(dnssd_errno
) : "");
216 syslog(LOG_INFO
, "dnssd_clientstub write_all(%d) DEFUNCT", sd
);
217 return defunct
? write_all_defunct
: write_all_fail
;
219 syslog(LOG_WARNING
, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd
,
220 (long)num_written
, (long)len
,
221 (num_written
< 0) ? dnssd_errno
: 0,
222 (num_written
< 0) ? dnssd_strerror(dnssd_errno
) : "");
223 return write_all_fail
;
229 return write_all_success
;
232 enum { read_all_success
= 0, read_all_fail
= -1, read_all_wouldblock
= -2, read_all_defunct
= -3 };
234 // Read len bytes. Return 0 on success, read_all_fail on error, or read_all_wouldblock for
235 static int read_all(dnssd_sock_t sd
, char *buf
, int len
)
237 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
238 //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1;
242 ssize_t num_read
= recv(sd
, buf
, len
, 0);
243 // It is valid to get an interrupted system call error e.g., somebody attaching
244 // in a debugger, retry without failing
245 if ((num_read
< 0) && (errno
== EINTR
))
247 syslog(LOG_INFO
, "dnssd_clientstub read_all: EINTR continue");
250 if ((num_read
== 0) || (num_read
< 0) || (num_read
> len
))
255 // Check whether socket has gone defunct,
256 // otherwise, an error here indicates some OS bug
257 // or that the mDNSResponder daemon crashed (which should never happen).
259 // <rdar://problem/7481776> Suppress logs for "A non-blocking socket operation
260 // could not be completed immediately"
261 if (WSAGetLastError() != WSAEWOULDBLOCK
)
264 #if !defined(__ppc__) && defined(SO_ISDEFUNCT)
266 socklen_t dlen
= sizeof (defunct
);
267 if (getsockopt(sd
, SOL_SOCKET
, SO_ISDEFUNCT
, &defunct
, &dlen
) < 0)
268 syslog(LOG_WARNING
, "dnssd_clientstub read_all: SO_ISDEFUNCT failed %d %s", dnssd_errno
, dnssd_strerror(dnssd_errno
));
274 syslog(LOG_WARNING
, "dnssd_clientstub read_all(%d) failed %ld/%ld %d %s", sd
,
275 (long)num_read
, (long)len
,
276 (num_read
< 0) ? dnssd_errno
: 0,
277 (num_read
< 0) ? dnssd_strerror(dnssd_errno
) : "");
279 syslog(LOG_INFO
, "dnssd_clientstub read_all(%d) DEFUNCT", sd
);
280 return (num_read
< 0 && dnssd_errno
== dnssd_EWOULDBLOCK
) ? read_all_wouldblock
: (defunct
? read_all_defunct
: read_all_fail
);
285 return read_all_success
;
288 // Returns 1 if more bytes remain to be read on socket descriptor sd, 0 otherwise
289 static int more_bytes(dnssd_sock_t sd
)
291 struct timeval tv
= { 0, 0 };
300 ret
= select((int)sd
+1, fs
, (fd_set
*)NULL
, (fd_set
*)NULL
, &tv
);
302 // This whole thing would probably be better done using kevent() instead of select()
310 // Compute the number of integers needed for storing "sd". Internally fd_set is stored
311 // as an array of ints with one bit for each fd and hence we need to compute
312 // the number of ints needed rather than the number of bytes. If "sd" is 32, we need
313 // two ints and not just one.
314 int nfdbits
= sizeof (int) * 8;
315 int nints
= (sd
/nfdbits
) + 1;
316 fs
= (fd_set
*)calloc(nints
, (size_t)sizeof(int));
319 syslog(LOG_WARNING
, "dnssd_clientstub more_bytes: malloc failed");
324 ret
= select((int)sd
+1, fs
, (fd_set
*)NULL
, (fd_set
*)NULL
, &tv
);
331 // set_waitlimit() implements a timeout using select. It is called from deliver_request() before recv() OR accept()
332 // to ensure the UDS clients are not blocked in these system calls indefinitely.
333 // Note: Ideally one should never be blocked here, because it indicates either mDNSResponder daemon is not yet up/hung/
334 // superbusy/crashed or some other OS bug. For eg: On Windows which suffers from 3rd party software
335 // (primarily 3rd party firewall software) interfering with proper functioning of the TCP protocol stack it is possible
336 // the next operation on this socket(recv/accept) is blocked since we depend on TCP to communicate with the system service.
337 static int set_waitlimit(dnssd_sock_t sock
, int timeout
)
339 int gDaemonErr
= kDNSServiceErr_NoError
;
341 // The comment below is wrong. The select() routine does not cause stack corruption.
342 // The use of FD_SET out of range for the bitmap is what causes stack corruption.
343 // For how to do this correctly, see the example using calloc() in more_bytes() above.
344 // Even better, both should be changed to use kevent() instead of select().
345 // To prevent stack corruption since select does not work with timeout if fds > FD_SETSIZE(1024)
346 if (!gDaemonErr
&& sock
< FD_SETSIZE
)
355 if (!select((int)(sock
+ 1), &set
, NULL
, NULL
, &tv
))
357 // Ideally one should never hit this case: See comments before set_waitlimit()
358 syslog(LOG_WARNING
, "dnssd_clientstub set_waitlimit:_daemon timed out (%d secs) without any response: Socket %d", timeout
, sock
);
359 gDaemonErr
= kDNSServiceErr_Timeout
;
367 * allocate and initialize an ipc message header. Value of len should initially be the
368 * length of the data, and is set to the value of the data plus the header. data_start
369 * is set to point to the beginning of the data section. SeparateReturnSocket should be
370 * non-zero for calls that can't receive an immediate error return value on their primary
371 * socket, and therefore require a separate return path for the error code result.
372 * if zero, the path to a control socket is appended at the beginning of the message buffer.
373 * data_start is set past this string.
375 static ipc_msg_hdr
*create_hdr(uint32_t op
, size_t *len
, char **data_start
, int SeparateReturnSocket
, DNSServiceOp
*ref
)
380 #if !defined(USE_TCP_LOOPBACK)
381 char ctrl_path
[64] = ""; // "/var/tmp/dnssd_result_socket.xxxxxxxxxx-xxx-xxxxxx"
384 if (SeparateReturnSocket
)
386 #if defined(USE_TCP_LOOPBACK)
387 *len
+= 2; // Allocate space for two-byte port number
388 #elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
390 if (gettimeofday(&tv
, NULL
) < 0)
391 { syslog(LOG_WARNING
, "dnssd_clientstub create_hdr: gettimeofday failed %d %s", dnssd_errno
, dnssd_strerror(dnssd_errno
)); return NULL
; }
392 snprintf(ctrl_path
, sizeof(ctrl_path
), "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX
, (int)getpid(),
393 (unsigned long)(tv
.tv_sec
& 0xFFF), (unsigned long)(tv
.tv_usec
));
394 *len
+= strlen(ctrl_path
) + 1;
396 *len
+= 1; // Allocate space for single zero byte (empty C string)
400 datalen
= (int) *len
;
401 *len
+= sizeof(ipc_msg_hdr
);
403 // Write message to buffer
405 if (!msg
) { syslog(LOG_WARNING
, "dnssd_clientstub create_hdr: malloc failed"); return NULL
; }
407 memset(msg
, 0, *len
);
408 hdr
= (ipc_msg_hdr
*)msg
;
409 hdr
->version
= VERSION
;
410 hdr
->datalen
= datalen
;
413 hdr
->client_context
= ref
->uid
;
415 *data_start
= msg
+ sizeof(ipc_msg_hdr
);
416 #if defined(USE_TCP_LOOPBACK)
417 // Put dummy data in for the port, since we don't know what it is yet.
418 // The data will get filled in before we send the message. This happens in deliver_request().
419 if (SeparateReturnSocket
) put_uint16(0, data_start
);
421 if (SeparateReturnSocket
) put_string(ctrl_path
, data_start
);
426 static void FreeDNSRecords(DNSServiceOp
*sdRef
)
428 DNSRecord
*rec
= sdRef
->rec
;
431 DNSRecord
*next
= rec
->recnext
;
437 static void FreeDNSServiceOp(DNSServiceOp
*x
)
439 // We don't use our DNSServiceRefValid macro here because if we're cleaning up after a socket() call failed
440 // then sockfd could legitimately contain a failing value (e.g. dnssd_InvalidSocket)
441 if ((x
->sockfd
^ x
->validator
) != ValidatorBits
)
448 x
->sockfd
= dnssd_InvalidSocket
;
449 x
->validator
= 0xDDDDDDDD;
450 x
->op
= request_op_none
;
454 x
->ProcessReply
= NULL
;
455 x
->AppCallback
= NULL
;
456 x
->AppContext
= NULL
;
457 #if _DNS_SD_LIBDISPATCH
458 if (x
->disp_source
) dispatch_release(x
->disp_source
);
459 x
->disp_source
= NULL
;
460 x
->disp_queue
= NULL
;
462 // DNSRecords may have been added to subordinate sdRef e.g., DNSServiceRegister/DNSServiceAddRecord
463 // or on the main sdRef e.g., DNSServiceCreateConnection/DNSServiceRegisterRecord.
464 // DNSRecords may have been freed if the application called DNSRemoveRecord.
475 // Return a connected service ref (deallocate with DNSServiceRefDeallocate)
476 static DNSServiceErrorType
ConnectToServer(DNSServiceRef
*ref
, DNSServiceFlags flags
, uint32_t op
, ProcessReplyFn ProcessReply
, void *AppCallback
, void *AppContext
)
482 dnssd_sockaddr_t saddr
;
487 syslog(LOG_WARNING
, "dnssd_clientstub DNSService operation with NULL DNSServiceRef");
488 return kDNSServiceErr_BadParam
;
491 if (flags
& kDNSServiceFlagsShareConnection
)
495 syslog(LOG_WARNING
, "dnssd_clientstub kDNSServiceFlagsShareConnection used with NULL DNSServiceRef");
496 return kDNSServiceErr_BadParam
;
498 if (!DNSServiceRefValid(*ref
) || ((*ref
)->op
!= connection_request
&& (*ref
)->op
!= connection_delegate_request
) || (*ref
)->primary
)
500 syslog(LOG_WARNING
, "dnssd_clientstub kDNSServiceFlagsShareConnection used with invalid DNSServiceRef %p %08X %08X op %d",
501 (*ref
), (*ref
)->sockfd
, (*ref
)->validator
, (*ref
)->op
);
503 return kDNSServiceErr_BadReference
;
512 if (WSAStartup(MAKEWORD(2,2), &wsaData
) != 0) { *ref
= NULL
; return kDNSServiceErr_ServiceNotRunning
; }
514 // <rdar://problem/4096913> If the system service is disabled, we only want to try to connect once
515 if (IsSystemServiceDisabled())
516 NumTries
= DNSSD_CLIENT_MAXTRIES
;
519 sdr
= malloc(sizeof(DNSServiceOp
));
522 syslog(LOG_WARNING
, "dnssd_clientstub ConnectToServer: malloc failed");
524 return kDNSServiceErr_NoMemory
;
528 sdr
->sockfd
= dnssd_InvalidSocket
;
529 sdr
->validator
= sdr
->sockfd
^ ValidatorBits
;
536 sdr
->ProcessReply
= ProcessReply
;
537 sdr
->AppCallback
= AppCallback
;
538 sdr
->AppContext
= AppContext
;
540 #if _DNS_SD_LIBDISPATCH
541 sdr
->disp_source
= NULL
;
542 sdr
->disp_queue
= NULL
;
544 sdr
->kacontext
= NULL
;
546 if (flags
& kDNSServiceFlagsShareConnection
)
548 DNSServiceOp
**p
= &(*ref
)->next
; // Append ourselves to end of primary's list
552 // Preincrement counter before we use it -- it helps with debugging if we know the all-zeroes ID should never appear
553 if (++(*ref
)->uid
.u32
[0] == 0)
554 ++(*ref
)->uid
.u32
[1]; // In parent DNSServiceOp increment UID counter
555 sdr
->primary
= *ref
; // Set our primary pointer
556 sdr
->sockfd
= (*ref
)->sockfd
; // Inherit primary's socket
557 sdr
->validator
= (*ref
)->validator
;
558 sdr
->uid
= (*ref
)->uid
;
559 //printf("ConnectToServer sharing socket %d\n", sdr->sockfd);
564 const unsigned long optval
= 1;
566 #ifndef USE_TCP_LOOPBACK
567 char* uds_serverpath
= getenv(MDNS_UDS_SERVERPATH_ENVVAR
);
568 if (uds_serverpath
== NULL
)
569 uds_serverpath
= MDNS_UDS_SERVERPATH
;
570 else if (strlen(uds_serverpath
) >= MAX_CTLPATH
)
572 uds_serverpath
= MDNS_UDS_SERVERPATH
;
573 syslog(LOG_WARNING
, "dnssd_clientstub ConnectToServer: using default path since env len is invalid");
577 sdr
->sockfd
= socket(AF_DNSSD
, SOCK_STREAM
, 0);
578 sdr
->validator
= sdr
->sockfd
^ ValidatorBits
;
579 if (!dnssd_SocketValid(sdr
->sockfd
))
581 syslog(LOG_WARNING
, "dnssd_clientstub ConnectToServer: socket failed %d %s", dnssd_errno
, dnssd_strerror(dnssd_errno
));
582 FreeDNSServiceOp(sdr
);
583 return kDNSServiceErr_NoMemory
;
586 int fcntl_flags
= fcntl(sdr
->sockfd
, F_GETFD
);
587 if (fcntl_flags
!= -1)
589 fcntl_flags
|= FD_CLOEXEC
;
590 int ret
= fcntl(sdr
->sockfd
, F_SETFD
, fcntl_flags
);
592 syslog(LOG_WARNING
, "dnssd_clientstub ConnectToServer: Failed to set FD_CLOEXEC on socket %d %s",
593 dnssd_errno
, dnssd_strerror(dnssd_errno
));
597 syslog(LOG_WARNING
, "dnssd_clientstub ConnectToServer: Failed to get the file descriptor flags of socket %d %s",
598 dnssd_errno
, dnssd_strerror(dnssd_errno
));
600 #endif // !defined(_WIN32)
602 // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
603 if (setsockopt(sdr
->sockfd
, SOL_SOCKET
, SO_NOSIGPIPE
, &optval
, sizeof(optval
)) < 0)
604 syslog(LOG_WARNING
, "dnssd_clientstub ConnectToServer: SO_NOSIGPIPE failed %d %s", dnssd_errno
, dnssd_strerror(dnssd_errno
));
606 #if defined(USE_TCP_LOOPBACK)
607 saddr
.sin_family
= AF_INET
;
608 saddr
.sin_addr
.s_addr
= inet_addr(MDNS_TCP_SERVERADDR
);
609 saddr
.sin_port
= htons(MDNS_TCP_SERVERPORT
);
611 saddr
.sun_family
= AF_LOCAL
;
612 SetUDSPath(&saddr
, uds_serverpath
);
613 #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
616 if (setsockopt(sdr
->sockfd
, SOL_SOCKET
, SO_DEFUNCTOK
, &defunct
, sizeof(defunct
)) < 0)
617 syslog(LOG_WARNING
, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno
, dnssd_strerror(dnssd_errno
));
625 int err
= connect(sdr
->sockfd
, (struct sockaddr
*) &saddr
, sizeof(saddr
));
627 break; // If we succeeded, return sdr
629 // If we failed, then it may be because the daemon is still launching.
630 // This can happen for processes that launch early in the boot process, while the
631 // daemon is still coming up. Rather than fail here, we wait 1 sec and try again.
632 // If, after DNSSD_CLIENT_MAXTRIES, we still can't connect to the daemon,
633 // then we give up and return a failure code.
634 if (++NumTries
< DNSSD_CLIENT_MAXTRIES
)
636 syslog(LOG_WARNING
, "dnssd_clientstub ConnectToServer: connect()-> No of tries: %d", NumTries
);
637 sleep(1); // Sleep a bit, then try again
641 #if !defined(USE_TCP_LOOPBACK)
642 syslog(LOG_WARNING
, "dnssd_clientstub ConnectToServer: connect() failed path:%s Socket:%d Err:%d Errno:%d %s",
643 uds_serverpath
, sdr
->sockfd
, err
, dnssd_errno
, dnssd_strerror(dnssd_errno
));
645 dnssd_close(sdr
->sockfd
);
646 FreeDNSServiceOp(sdr
);
647 return kDNSServiceErr_ServiceNotRunning
;
651 int err
= connect(sdr
->sockfd
, (struct sockaddr
*) &saddr
, sizeof(saddr
));
654 #if !defined(USE_TCP_LOOPBACK)
655 syslog(LOG_WARNING
, "dnssd_clientstub ConnectToServer: connect() failed path:%s Socket:%d Err:%d Errno:%d %s",
656 uds_serverpath
, sdr
->sockfd
, err
, dnssd_errno
, dnssd_strerror(dnssd_errno
));
658 dnssd_close(sdr
->sockfd
);
659 FreeDNSServiceOp(sdr
);
660 return kDNSServiceErr_ServiceNotRunning
;
666 return kDNSServiceErr_NoError
;
669 #define deliver_request_bailout(MSG) \
670 do { syslog(LOG_WARNING, "dnssd_clientstub deliver_request: %s failed %d (%s)", (MSG), dnssd_errno, dnssd_strerror(dnssd_errno)); goto cleanup; } while(0)
672 static DNSServiceErrorType
deliver_request(ipc_msg_hdr
*hdr
, DNSServiceOp
*sdr
)
675 dnssd_sock_t listenfd
= dnssd_InvalidSocket
, errsd
= dnssd_InvalidSocket
;
676 DNSServiceErrorType err
= kDNSServiceErr_Unknown
; // Default for the "goto cleanup" cases
677 int MakeSeparateReturnSocket
;
679 #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
685 syslog(LOG_WARNING
, "dnssd_clientstub deliver_request: !hdr");
686 return kDNSServiceErr_Unknown
;
689 datalen
= hdr
->datalen
; // We take a copy here because we're going to convert hdr->datalen to network byte order
690 #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
691 data
= (char *)hdr
+ sizeof(ipc_msg_hdr
);
694 // Note: need to check hdr->op, not sdr->op.
695 // hdr->op contains the code for the specific operation we're currently doing, whereas sdr->op
696 // contains the original parent DNSServiceOp (e.g. for an add_record_request, hdr->op will be
697 // add_record_request but the parent sdr->op will be connection_request or reg_service_request)
698 MakeSeparateReturnSocket
= (sdr
->primary
||
699 hdr
->op
== reg_record_request
|| hdr
->op
== add_record_request
|| hdr
->op
== update_record_request
|| hdr
->op
== remove_record_request
);
701 if (!DNSServiceRefValid(sdr
))
705 syslog(LOG_WARNING
, "dnssd_clientstub deliver_request: invalid DNSServiceRef %p %08X %08X", sdr
, sdr
->sockfd
, sdr
->validator
);
706 return kDNSServiceErr_BadReference
;
709 if (MakeSeparateReturnSocket
)
711 #if defined(USE_TCP_LOOPBACK)
713 union { uint16_t s
; u_char b
[2]; } port
;
714 dnssd_sockaddr_t caddr
;
715 dnssd_socklen_t len
= (dnssd_socklen_t
) sizeof(caddr
);
716 listenfd
= socket(AF_DNSSD
, SOCK_STREAM
, 0);
717 if (!dnssd_SocketValid(listenfd
)) deliver_request_bailout("TCP socket");
719 caddr
.sin_family
= AF_INET
;
721 caddr
.sin_addr
.s_addr
= inet_addr(MDNS_TCP_SERVERADDR
);
722 if (bind(listenfd
, (struct sockaddr
*) &caddr
, sizeof(caddr
)) < 0) deliver_request_bailout("TCP bind");
723 if (getsockname(listenfd
, (struct sockaddr
*) &caddr
, &len
) < 0) deliver_request_bailout("TCP getsockname");
724 if (listen(listenfd
, 1) < 0) deliver_request_bailout("TCP listen");
725 port
.s
= caddr
.sin_port
;
726 data
[0] = port
.b
[0]; // don't switch the byte order, as the
727 data
[1] = port
.b
[1]; // daemon expects it in network byte order
729 #elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
733 dnssd_sockaddr_t caddr
;
734 listenfd
= socket(AF_DNSSD
, SOCK_STREAM
, 0);
735 if (!dnssd_SocketValid(listenfd
)) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET socket");
737 caddr
.sun_family
= AF_LOCAL
;
738 // According to Stevens (section 3.2), there is no portable way to
739 // determine whether sa_len is defined on a particular platform.
740 #ifndef NOT_HAVE_SA_LEN
741 caddr
.sun_len
= sizeof(struct sockaddr_un
);
743 SetUDSPath(&caddr
, data
);
745 bindresult
= bind(listenfd
, (struct sockaddr
*)&caddr
, sizeof(caddr
));
747 if (bindresult
< 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET bind");
748 if (listen(listenfd
, 1) < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET listen");
753 if (socketpair(AF_DNSSD
, SOCK_STREAM
, 0, sp
) < 0) deliver_request_bailout("socketpair");
756 errsd
= sp
[0]; // We'll read our four-byte error code from sp[0]
757 listenfd
= sp
[1]; // We'll send sp[1] to the daemon
758 #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
761 if (setsockopt(errsd
, SOL_SOCKET
, SO_DEFUNCTOK
, &defunct
, sizeof(defunct
)) < 0)
762 syslog(LOG_WARNING
, "dnssd_clientstub deliver_request: SO_DEFUNCTOK failed %d %s", dnssd_errno
, dnssd_strerror(dnssd_errno
));
770 #if !defined(USE_TCP_LOOPBACK) && !defined(USE_NAMED_ERROR_RETURN_SOCKET)
771 // If we're going to make a separate error return socket, and pass it to the daemon
772 // using sendmsg, then we'll hold back one data byte to go with it.
773 // On some versions of Unix (including Leopard) sending a control message without
774 // any associated data does not work reliably -- e.g. one particular issue we ran
775 // into is that if the receiving program is in a kqueue loop waiting to be notified
776 // of the received message, it doesn't get woken up when the control message arrives.
777 if (MakeSeparateReturnSocket
|| sdr
->op
== send_bpf
)
778 datalen
--; // Okay to use sdr->op when checking for op == send_bpf
781 // At this point, our listening socket is set up and waiting, if necessary, for the daemon to connect back to
782 ConvertHeaderBytes(hdr
);
783 //syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %lu bytes", (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
784 //if (MakeSeparateReturnSocket) syslog(LOG_WARNING, "dnssd_clientstub deliver_request name is %s", data);
785 #if TEST_SENDING_ONE_BYTE_AT_A_TIME
787 for (i
=0; i
<datalen
+ sizeof(ipc_msg_hdr
); i
++)
789 syslog(LOG_WARNING
, "dnssd_clientstub deliver_request writing %d", i
);
790 ioresult
= write_all(sdr
->sockfd
, ((char *)hdr
)+i
, 1);
791 if (ioresult
< write_all_success
)
793 syslog(LOG_WARNING
, "dnssd_clientstub deliver_request write_all (byte %u) failed", i
);
794 err
= (ioresult
== write_all_defunct
) ? kDNSServiceErr_DefunctConnection
: kDNSServiceErr_ServiceNotRunning
;
800 ioresult
= write_all(sdr
->sockfd
, (char *)hdr
, datalen
+ sizeof(ipc_msg_hdr
));
801 if (ioresult
< write_all_success
)
803 // write_all already prints an error message if there is an error writing to
804 // the socket except for DEFUNCT. Logging here is unnecessary and also wrong
805 // in the case of DEFUNCT sockets
806 syslog(LOG_INFO
, "dnssd_clientstub deliver_request ERROR: write_all(%d, %lu bytes) failed",
807 sdr
->sockfd
, (unsigned long)(datalen
+ sizeof(ipc_msg_hdr
)));
808 err
= (ioresult
== write_all_defunct
) ? kDNSServiceErr_DefunctConnection
: kDNSServiceErr_ServiceNotRunning
;
813 if (!MakeSeparateReturnSocket
)
815 if (MakeSeparateReturnSocket
|| sdr
->op
== send_bpf
) // Okay to use sdr->op when checking for op == send_bpf
817 #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
818 // At this point we may wait in accept for a few milliseconds waiting for the daemon to connect back to us,
819 // but that's okay -- the daemon should not take more than a few milliseconds to respond.
820 // set_waitlimit() ensures we do not block indefinitely just in case something is wrong
821 dnssd_sockaddr_t daddr
;
822 dnssd_socklen_t len
= sizeof(daddr
);
823 if ((err
= set_waitlimit(listenfd
, DNSSD_CLIENT_TIMEOUT
)) != kDNSServiceErr_NoError
)
825 errsd
= accept(listenfd
, (struct sockaddr
*)&daddr
, &len
);
826 if (!dnssd_SocketValid(errsd
))
827 deliver_request_bailout("accept");
830 struct iovec vec
= { ((char *)hdr
) + sizeof(ipc_msg_hdr
) + datalen
, 1 }; // Send the last byte along with the SCM_RIGHTS
832 struct cmsghdr
*cmsg
;
833 char cbuf
[CMSG_SPACE(4 * sizeof(dnssd_sock_t
))];
840 if (MakeSeparateReturnSocket
|| sdr
->op
== send_bpf
) // Okay to use sdr->op when checking for op == send_bpf
842 if (sdr
->op
== send_bpf
)
845 char p
[12]; // Room for "/dev/bpf999" with terminating null
846 for (i
=0; i
<100; i
++)
848 snprintf(p
, sizeof(p
), "/dev/bpf%d", i
);
849 listenfd
= open(p
, O_RDWR
, 0);
850 //if (dnssd_SocketValid(listenfd)) syslog(LOG_WARNING, "dnssd_clientstub deliver_request Sending fd %d for %s", listenfd, p);
851 if (!dnssd_SocketValid(listenfd
) && dnssd_errno
!= EBUSY
)
852 syslog(LOG_WARNING
, "dnssd_clientstub deliver_request Error opening %s %d (%s)", p
, dnssd_errno
, dnssd_strerror(dnssd_errno
));
853 if (dnssd_SocketValid(listenfd
) || dnssd_errno
!= EBUSY
) break;
856 msg
.msg_control
= cbuf
;
857 msg
.msg_controllen
= CMSG_LEN(sizeof(dnssd_sock_t
));
859 cmsg
= CMSG_FIRSTHDR(&msg
);
860 cmsg
->cmsg_len
= CMSG_LEN(sizeof(dnssd_sock_t
));
861 cmsg
->cmsg_level
= SOL_SOCKET
;
862 cmsg
->cmsg_type
= SCM_RIGHTS
;
863 *((dnssd_sock_t
*)CMSG_DATA(cmsg
)) = listenfd
;
866 #if TEST_KQUEUE_CONTROL_MESSAGE_BUG
870 #if DEBUG_64BIT_SCM_RIGHTS
871 syslog(LOG_WARNING
, "dnssd_clientstub deliver_request sendmsg read sd=%d write sd=%d %ld %ld %ld/%ld/%ld/%ld",
872 errsd
, listenfd
, sizeof(dnssd_sock_t
), sizeof(void*),
873 sizeof(struct cmsghdr
) + sizeof(dnssd_sock_t
),
874 CMSG_LEN(sizeof(dnssd_sock_t
)), (long)CMSG_SPACE(sizeof(dnssd_sock_t
)),
875 (long)((char*)CMSG_DATA(cmsg
) + 4 - cbuf
));
876 #endif // DEBUG_64BIT_SCM_RIGHTS
878 if (sendmsg(sdr
->sockfd
, &msg
, 0) < 0)
880 syslog(LOG_WARNING
, "dnssd_clientstub deliver_request ERROR: sendmsg failed read sd=%d write sd=%d errno %d (%s)",
881 errsd
, listenfd
, dnssd_errno
, dnssd_strerror(dnssd_errno
));
882 err
= kDNSServiceErr_Incompatible
;
886 #if DEBUG_64BIT_SCM_RIGHTS
887 syslog(LOG_WARNING
, "dnssd_clientstub deliver_request sendmsg read sd=%d write sd=%d okay", errsd
, listenfd
);
888 #endif // DEBUG_64BIT_SCM_RIGHTS
891 // Close our end of the socketpair *before* calling read_all() to get the four-byte error code.
892 // Otherwise, if the daemon closes our socket (or crashes), we will have to wait for a timeout
893 // in read_all() because the socket is not closed (we still have an open reference to it)
894 // Note: listenfd is overwritten in the case of send_bpf above and that will be closed here
895 // for send_bpf operation.
896 dnssd_close(listenfd
);
897 listenfd
= dnssd_InvalidSocket
; // Make sure we don't close it a second time in the cleanup handling below
900 // At this point we may wait in read_all for a few milliseconds waiting for the daemon to send us the error code,
901 // but that's okay -- the daemon should not take more than a few milliseconds to respond.
902 // set_waitlimit() ensures we do not block indefinitely just in case something is wrong
903 if (sdr
->op
== send_bpf
) // Okay to use sdr->op when checking for op == send_bpf
904 err
= kDNSServiceErr_NoError
;
905 else if ((err
= set_waitlimit(errsd
, DNSSD_CLIENT_TIMEOUT
)) == kDNSServiceErr_NoError
)
907 ioresult
= read_all(errsd
, (char*)&err
, (int)sizeof(err
));
908 if (ioresult
< read_all_success
)
909 err
= (ioresult
== read_all_defunct
) ? kDNSServiceErr_DefunctConnection
: kDNSServiceErr_ServiceNotRunning
; // On failure read_all will have written a message to syslog for us
913 //syslog(LOG_WARNING, "dnssd_clientstub deliver_request: retrieved error code %d", err);
916 if (MakeSeparateReturnSocket
)
918 if (dnssd_SocketValid(listenfd
)) dnssd_close(listenfd
);
919 if (dnssd_SocketValid(errsd
)) dnssd_close(errsd
);
920 #if defined(USE_NAMED_ERROR_RETURN_SOCKET)
921 // syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removing UDS: %s", data);
922 if (unlink(data
) != 0)
923 syslog(LOG_WARNING
, "dnssd_clientstub WARNING: unlink(\"%s\") failed errno %d (%s)", data
, dnssd_errno
, dnssd_strerror(dnssd_errno
));
924 // else syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removed UDS: %s", data);
932 dnssd_sock_t DNSSD_API
DNSServiceRefSockFD(DNSServiceRef sdRef
)
934 if (!sdRef
) { syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceRefSockFD called with NULL DNSServiceRef"); return dnssd_InvalidSocket
; }
936 if (!DNSServiceRefValid(sdRef
))
938 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceRefSockFD called with invalid DNSServiceRef %p %08X %08X",
939 sdRef
, sdRef
->sockfd
, sdRef
->validator
);
940 return dnssd_InvalidSocket
;
945 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceRefSockFD undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef
);
946 return dnssd_InvalidSocket
;
949 return sdRef
->sockfd
;
952 #if _DNS_SD_LIBDISPATCH
953 static void CallbackWithError(DNSServiceRef sdRef
, DNSServiceErrorType error
)
955 DNSServiceOp
*sdr
= sdRef
;
956 DNSServiceOp
*sdrNext
;
963 // We can't touch the sdr after the callback as it can be deallocated in the callback
966 sdr
->moreptr
= &morebytes
;
969 case resolve_request
:
970 if (sdr
->AppCallback
) ((DNSServiceResolveReply
) sdr
->AppCallback
)(sdr
, 0, 0, error
, NULL
, 0, 0, 0, NULL
, sdr
->AppContext
);
973 if (sdr
->AppCallback
) ((DNSServiceQueryRecordReply
)sdr
->AppCallback
)(sdr
, 0, 0, error
, NULL
, 0, 0, 0, NULL
, 0, sdr
->AppContext
);
975 case addrinfo_request
:
976 if (sdr
->AppCallback
) ((DNSServiceGetAddrInfoReply
)sdr
->AppCallback
)(sdr
, 0, 0, error
, NULL
, NULL
, 0, sdr
->AppContext
);
979 if (sdr
->AppCallback
) ((DNSServiceBrowseReply
) sdr
->AppCallback
)(sdr
, 0, 0, error
, NULL
, 0, NULL
, sdr
->AppContext
);
981 case reg_service_request
:
982 if (sdr
->AppCallback
) ((DNSServiceRegisterReply
) sdr
->AppCallback
)(sdr
, 0, error
, NULL
, 0, NULL
, sdr
->AppContext
);
984 case enumeration_request
:
985 if (sdr
->AppCallback
) ((DNSServiceDomainEnumReply
) sdr
->AppCallback
)(sdr
, 0, 0, error
, NULL
, sdr
->AppContext
);
987 case connection_request
:
988 case connection_delegate_request
:
989 // This means Register Record, walk the list of DNSRecords to do the callback
993 recnext
= rec
->recnext
;
994 if (rec
->AppCallback
) ((DNSServiceRegisterRecordReply
)rec
->AppCallback
)(sdr
, 0, 0, error
, rec
->AppContext
);
995 // The Callback can call DNSServiceRefDeallocate which in turn frees sdr and all the records.
996 // Detect that and return early
997 if (!morebytes
) { syslog(LOG_WARNING
, "dnssd_clientstub:Record: CallbackwithError morebytes zero"); return; }
1001 case port_mapping_request
:
1002 if (sdr
->AppCallback
) ((DNSServiceNATPortMappingReply
)sdr
->AppCallback
)(sdr
, 0, 0, error
, 0, 0, 0, 0, 0, sdr
->AppContext
);
1005 syslog(LOG_WARNING
, "dnssd_clientstub CallbackWithError called with bad op %d", sdr
->op
);
1007 // If DNSServiceRefDeallocate was called in the callback, morebytes will be zero. As the sdRef
1008 // (and its subordinates) have been freed, we should not proceed further. Note that when we
1009 // call the callback with a subordinate sdRef the application can call DNSServiceRefDeallocate
1010 // on the main sdRef and DNSServiceRefDeallocate handles this case by walking all the sdRefs and
1011 // clears the moreptr so that we can terminate here.
1013 // If DNSServiceRefDeallocate was not called in the callback, then set moreptr to NULL so that
1014 // we don't access the stack variable after we return from this function.
1015 if (!morebytes
) { syslog(LOG_WARNING
, "dnssd_clientstub:sdRef: CallbackwithError morebytes zero sdr %p", sdr
); return; }
1016 else {sdr
->moreptr
= NULL
;}
1020 #endif // _DNS_SD_LIBDISPATCH
1022 // Handle reply from server, calling application client callback. If there is no reply
1023 // from the daemon on the socket contained in sdRef, the call will block.
1024 DNSServiceErrorType DNSSD_API
DNSServiceProcessResult(DNSServiceRef sdRef
)
1028 DNSServiceErrorType error
;
1030 if (!sdRef
) { syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceProcessResult called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam
; }
1032 if (!DNSServiceRefValid(sdRef
))
1034 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceProcessResult called with invalid DNSServiceRef %p %08X %08X", sdRef
, sdRef
->sockfd
, sdRef
->validator
);
1035 return kDNSServiceErr_BadReference
;
1040 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceProcessResult undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef
);
1041 return kDNSServiceErr_BadReference
;
1044 if (!sdRef
->ProcessReply
)
1046 static int num_logs
= 0;
1047 if (num_logs
< 10) syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function");
1048 if (num_logs
< 1000) num_logs
++;else sleep(1);
1049 return kDNSServiceErr_BadReference
;
1057 // return NoError on EWOULDBLOCK. This will handle the case
1058 // where a non-blocking socket is told there is data, but it was a false positive.
1059 // On error, read_all will write a message to syslog for us, so don't need to duplicate that here
1060 // Note: If we want to properly support using non-blocking sockets in the future
1061 ioresult
= read_all(sdRef
->sockfd
, (void *)&cbh
.ipc_hdr
, sizeof(cbh
.ipc_hdr
));
1062 if (ioresult
== read_all_fail
|| ioresult
== read_all_defunct
)
1064 error
= (ioresult
== read_all_defunct
) ? kDNSServiceErr_DefunctConnection
: kDNSServiceErr_ServiceNotRunning
;
1066 // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
1068 sdRef
->ProcessReply
= NULL
;
1069 #if _DNS_SD_LIBDISPATCH
1070 // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
1071 // is not called by the application and hence need to communicate the error. Cancel the
1072 // source so that we don't get any more events
1073 // Note: read_all fails if we could not read from the daemon which can happen if the
1074 // daemon dies or the file descriptor is disconnected (defunct).
1075 if (sdRef
->disp_source
)
1077 dispatch_source_cancel(sdRef
->disp_source
);
1078 dispatch_release(sdRef
->disp_source
);
1079 sdRef
->disp_source
= NULL
;
1080 CallbackWithError(sdRef
, error
);
1083 // Don't touch sdRef anymore as it might have been deallocated
1086 else if (ioresult
== read_all_wouldblock
)
1088 if (morebytes
&& sdRef
->logcounter
< 100)
1090 sdRef
->logcounter
++;
1091 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceProcessResult error: select indicated data was waiting but read_all returned EWOULDBLOCK");
1093 return kDNSServiceErr_NoError
;
1096 ConvertHeaderBytes(&cbh
.ipc_hdr
);
1097 if (cbh
.ipc_hdr
.version
!= VERSION
)
1099 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceProcessResult daemon version %d does not match client version %d", cbh
.ipc_hdr
.version
, VERSION
);
1100 sdRef
->ProcessReply
= NULL
;
1101 return kDNSServiceErr_Incompatible
;
1104 data
= malloc(cbh
.ipc_hdr
.datalen
);
1105 if (!data
) return kDNSServiceErr_NoMemory
;
1106 ioresult
= read_all(sdRef
->sockfd
, data
, cbh
.ipc_hdr
.datalen
);
1107 if (ioresult
< read_all_success
) // On error, read_all will write a message to syslog for us
1109 error
= (ioresult
== read_all_defunct
) ? kDNSServiceErr_DefunctConnection
: kDNSServiceErr_ServiceNotRunning
;
1111 // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
1113 sdRef
->ProcessReply
= NULL
;
1114 #if _DNS_SD_LIBDISPATCH
1115 // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
1116 // is not called by the application and hence need to communicate the error. Cancel the
1117 // source so that we don't get any more events
1118 if (sdRef
->disp_source
)
1120 dispatch_source_cancel(sdRef
->disp_source
);
1121 dispatch_release(sdRef
->disp_source
);
1122 sdRef
->disp_source
= NULL
;
1123 CallbackWithError(sdRef
, error
);
1126 // Don't touch sdRef anymore as it might have been deallocated
1132 const char *ptr
= data
;
1133 cbh
.cb_flags
= get_flags (&ptr
, data
+ cbh
.ipc_hdr
.datalen
);
1134 cbh
.cb_interface
= get_uint32 (&ptr
, data
+ cbh
.ipc_hdr
.datalen
);
1135 cbh
.cb_err
= get_error_code(&ptr
, data
+ cbh
.ipc_hdr
.datalen
);
1137 // CAUTION: We have to handle the case where the client calls DNSServiceRefDeallocate from within the callback function.
1138 // To do this we set moreptr to point to morebytes. If the client does call DNSServiceRefDeallocate(),
1139 // then that routine will clear morebytes for us, and cause us to exit our loop.
1140 morebytes
= more_bytes(sdRef
->sockfd
);
1143 cbh
.cb_flags
|= kDNSServiceFlagsMoreComing
;
1144 sdRef
->moreptr
= &morebytes
;
1146 if (ptr
) sdRef
->ProcessReply(sdRef
, &cbh
, ptr
, data
+ cbh
.ipc_hdr
.datalen
);
1147 // Careful code here:
1148 // If morebytes is non-zero, that means we set sdRef->moreptr above, and the operation was not
1149 // cancelled out from under us, so now we need to clear sdRef->moreptr so we don't leave a stray
1150 // dangling pointer pointing to a long-gone stack variable.
1151 // If morebytes is zero, then one of two thing happened:
1152 // (a) morebytes was 0 above, so we didn't set sdRef->moreptr, so we don't need to clear it
1153 // (b) morebytes was 1 above, and we set sdRef->moreptr, but the operation was cancelled (with DNSServiceRefDeallocate()),
1154 // so we MUST NOT try to dereference our stale sdRef pointer.
1155 if (morebytes
) sdRef
->moreptr
= NULL
;
1158 } while (morebytes
);
1160 return kDNSServiceErr_NoError
;
1163 void DNSSD_API
DNSServiceRefDeallocate(DNSServiceRef sdRef
)
1165 if (!sdRef
) { syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceRefDeallocate called with NULL DNSServiceRef"); return; }
1167 if (!DNSServiceRefValid(sdRef
)) // Also verifies dnssd_SocketValid(sdRef->sockfd) for us too
1169 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceRefDeallocate called with invalid DNSServiceRef %p %08X %08X", sdRef
, sdRef
->sockfd
, sdRef
->validator
);
1173 // 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
1174 if (sdRef
->moreptr
) *(sdRef
->moreptr
) = 0;
1176 if (sdRef
->primary
) // If this is a subordinate DNSServiceOp, just send a 'stop' command
1178 DNSServiceOp
**p
= &sdRef
->primary
->next
;
1179 while (*p
&& *p
!= sdRef
) p
= &(*p
)->next
;
1184 ipc_msg_hdr
*hdr
= create_hdr(cancel_request
, &len
, &ptr
, 0, sdRef
);
1187 ConvertHeaderBytes(hdr
);
1188 write_all(sdRef
->sockfd
, (char *)hdr
, len
);
1192 FreeDNSServiceOp(sdRef
);
1195 else // else, make sure to terminate all subordinates as well
1197 #if _DNS_SD_LIBDISPATCH
1198 // The cancel handler will close the fd if a dispatch source has been set
1199 if (sdRef
->disp_source
)
1201 // By setting the ProcessReply to NULL, we make sure that we never call
1202 // the application callbacks ever, after returning from this function. We
1203 // assume that DNSServiceRefDeallocate is called from the serial queue
1204 // that was passed to DNSServiceSetDispatchQueue. Hence, dispatch_source_cancel
1205 // should cancel all the blocks on the queue and hence there should be no more
1206 // callbacks when we return from this function. Setting ProcessReply to NULL
1207 // provides extra protection.
1208 sdRef
->ProcessReply
= NULL
;
1209 shutdown(sdRef
->sockfd
, SHUT_WR
);
1210 dispatch_source_cancel(sdRef
->disp_source
);
1211 dispatch_release(sdRef
->disp_source
);
1212 sdRef
->disp_source
= NULL
;
1214 // if disp_queue is set, it means it used the DNSServiceSetDispatchQueue API. In that case,
1215 // when the source was cancelled, the fd was closed in the handler. Currently the source
1216 // is cancelled only when the mDNSResponder daemon dies
1217 else if (!sdRef
->disp_queue
) dnssd_close(sdRef
->sockfd
);
1219 dnssd_close(sdRef
->sockfd
);
1221 // Free DNSRecords added in DNSRegisterRecord if they have not
1222 // been freed in DNSRemoveRecord
1225 DNSServiceOp
*p
= sdRef
;
1226 sdRef
= sdRef
->next
;
1227 // When there is an error reading from the daemon e.g., bad fd, CallbackWithError
1228 // is called which sets moreptr. It might set the moreptr on a subordinate sdRef
1229 // but the application might call DNSServiceRefDeallocate with the main sdRef from
1230 // the callback. Hence, when we loop through the subordinate sdRefs, we need
1231 // to clear the moreptr so that CallbackWithError can terminate itself instead of
1232 // walking through the freed sdRefs.
1233 if (p
->moreptr
) *(p
->moreptr
) = 0;
1234 FreeDNSServiceOp(p
);
1239 DNSServiceErrorType DNSSD_API
DNSServiceGetProperty(const char *property
, void *result
, uint32_t *size
)
1241 DNSServiceErrorType err
;
1246 uint32_t actualsize
;
1249 if (!property
|| !result
|| !size
)
1250 return kDNSServiceErr_BadParam
;
1252 len
= strlen(property
) + 1;
1253 err
= ConnectToServer(&tmp
, 0, getproperty_request
, NULL
, NULL
, NULL
);
1254 if (err
) return err
;
1256 hdr
= create_hdr(getproperty_request
, &len
, &ptr
, 0, tmp
);
1257 if (!hdr
) { DNSServiceRefDeallocate(tmp
); return kDNSServiceErr_NoMemory
; }
1259 put_string(property
, &ptr
);
1260 err
= deliver_request(hdr
, tmp
); // Will free hdr for us
1261 if (err
) { DNSServiceRefDeallocate(tmp
); return err
; }
1263 ioresult
= read_all(tmp
->sockfd
, (char*)&actualsize
, (int)sizeof(actualsize
));
1264 if (ioresult
< read_all_success
)
1265 { DNSServiceRefDeallocate(tmp
); return (ioresult
== read_all_defunct
) ? kDNSServiceErr_DefunctConnection
: kDNSServiceErr_ServiceNotRunning
; }
1267 actualsize
= ntohl(actualsize
);
1268 ioresult
= read_all(tmp
->sockfd
, (char*)result
, actualsize
< *size
? actualsize
: *size
);
1269 if (ioresult
< read_all_success
)
1270 { DNSServiceRefDeallocate(tmp
); return (ioresult
== read_all_defunct
) ? kDNSServiceErr_DefunctConnection
: kDNSServiceErr_ServiceNotRunning
; }
1271 DNSServiceRefDeallocate(tmp
);
1273 // Swap version result back to local process byte order
1274 if (!strcmp(property
, kDNSServiceProperty_DaemonVersion
) && *size
>= 4)
1275 *(uint32_t*)result
= ntohl(*(uint32_t*)result
);
1278 return kDNSServiceErr_NoError
;
1281 DNSServiceErrorType DNSSD_API
DNSServiceGetPID(const uint16_t srcport
, int32_t *pid
)
1285 DNSServiceOp
*tmp
= NULL
;
1286 size_t len
= sizeof(int32_t);
1289 DNSServiceErrorType err
= ConnectToServer(&tmp
, 0, getpid_request
, NULL
, NULL
, NULL
);
1290 if (err
) return err
;
1292 hdr
= create_hdr(getpid_request
, &len
, &ptr
, 0, tmp
);
1293 if (!hdr
) { DNSServiceRefDeallocate(tmp
); return kDNSServiceErr_NoMemory
; }
1295 put_uint16(srcport
, &ptr
);
1296 err
= deliver_request(hdr
, tmp
); // Will free hdr for us
1297 if (err
) { DNSServiceRefDeallocate(tmp
); return err
; }
1299 ioresult
= read_all(tmp
->sockfd
, (char*)pid
, sizeof(int32_t));
1300 if (ioresult
< read_all_success
)
1301 { DNSServiceRefDeallocate(tmp
); return (ioresult
== read_all_defunct
) ? kDNSServiceErr_DefunctConnection
: kDNSServiceErr_ServiceNotRunning
; }
1303 DNSServiceRefDeallocate(tmp
);
1304 return kDNSServiceErr_NoError
;
1307 static void handle_resolve_response(DNSServiceOp
*const sdr
, const CallbackHeader
*const cbh
, const char *data
, const char *end
)
1309 char fullname
[kDNSServiceMaxDomainName
];
1310 char target
[kDNSServiceMaxDomainName
];
1312 union { uint16_t s
; u_char b
[2]; } port
;
1313 unsigned char *txtrecord
;
1315 get_string(&data
, end
, fullname
, kDNSServiceMaxDomainName
);
1316 get_string(&data
, end
, target
, kDNSServiceMaxDomainName
);
1317 if (!data
|| data
+ 2 > end
) goto fail
;
1319 port
.b
[0] = *data
++;
1320 port
.b
[1] = *data
++;
1321 txtlen
= get_uint16(&data
, end
);
1322 txtrecord
= (unsigned char *)get_rdata(&data
, end
, txtlen
);
1324 if (!data
) goto fail
;
1325 ((DNSServiceResolveReply
)sdr
->AppCallback
)(sdr
, cbh
->cb_flags
, cbh
->cb_interface
, cbh
->cb_err
, fullname
, target
, port
.s
, txtlen
, txtrecord
, sdr
->AppContext
);
1327 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1329 syslog(LOG_WARNING
, "dnssd_clientstub handle_resolve_response: error reading result from daemon");
1332 #if TARGET_OS_IPHONE
1334 static int32_t libSystemVersion
= 0;
1336 // Return true if the iOS application linked against a version of libsystem where P2P
1337 // interfaces were included by default when using kDNSServiceInterfaceIndexAny.
1338 // Using 160.0.0 == 0xa00000 as the version threshold.
1339 static int includeP2PWithIndexAny()
1341 if (libSystemVersion
== 0)
1342 libSystemVersion
= NSVersionOfLinkTimeLibrary("System");
1344 if (libSystemVersion
< 0xa00000)
1350 #else // TARGET_OS_IPHONE
1352 // always return false for non iOS platforms
1353 static int includeP2PWithIndexAny()
1358 #endif // TARGET_OS_IPHONE
1360 DNSServiceErrorType DNSSD_API DNSServiceResolve
1362 DNSServiceRef
*sdRef
,
1363 DNSServiceFlags flags
,
1364 uint32_t interfaceIndex
,
1366 const char *regtype
,
1368 DNSServiceResolveReply callBack
,
1375 DNSServiceErrorType err
;
1377 if (!sdRef
|| !name
|| !regtype
|| !domain
|| !callBack
) return kDNSServiceErr_BadParam
;
1379 // Need a real InterfaceID for WakeOnResolve
1380 if ((flags
& kDNSServiceFlagsWakeOnResolve
) != 0 &&
1381 ((interfaceIndex
== kDNSServiceInterfaceIndexAny
) ||
1382 (interfaceIndex
== kDNSServiceInterfaceIndexLocalOnly
) ||
1383 (interfaceIndex
== kDNSServiceInterfaceIndexUnicast
) ||
1384 (interfaceIndex
== kDNSServiceInterfaceIndexP2P
) ||
1385 (interfaceIndex
== kDNSServiceInterfaceIndexBLE
)))
1387 return kDNSServiceErr_BadParam
;
1390 if ((interfaceIndex
== kDNSServiceInterfaceIndexAny
) && includeP2PWithIndexAny())
1391 flags
|= kDNSServiceFlagsIncludeP2P
;
1393 err
= ConnectToServer(sdRef
, flags
, resolve_request
, handle_resolve_response
, callBack
, context
);
1394 if (err
) return err
; // On error ConnectToServer leaves *sdRef set to NULL
1396 // Calculate total message length
1397 len
= sizeof(flags
);
1398 len
+= sizeof(interfaceIndex
);
1399 len
+= strlen(name
) + 1;
1400 len
+= strlen(regtype
) + 1;
1401 len
+= strlen(domain
) + 1;
1403 hdr
= create_hdr(resolve_request
, &len
, &ptr
, (*sdRef
)->primary
? 1 : 0, *sdRef
);
1404 if (!hdr
) { DNSServiceRefDeallocate(*sdRef
); *sdRef
= NULL
; return kDNSServiceErr_NoMemory
; }
1406 put_flags(flags
, &ptr
);
1407 put_uint32(interfaceIndex
, &ptr
);
1408 put_string(name
, &ptr
);
1409 put_string(regtype
, &ptr
);
1410 put_string(domain
, &ptr
);
1412 err
= deliver_request(hdr
, *sdRef
); // Will free hdr for us
1413 if (err
) { DNSServiceRefDeallocate(*sdRef
); *sdRef
= NULL
; }
1417 static void handle_query_response(DNSServiceOp
*const sdr
, const CallbackHeader
*const cbh
, const char *data
, const char *const end
)
1420 char name
[kDNSServiceMaxDomainName
];
1421 uint16_t rrtype
, rrclass
, rdlen
;
1424 get_string(&data
, end
, name
, kDNSServiceMaxDomainName
);
1425 rrtype
= get_uint16(&data
, end
);
1426 rrclass
= get_uint16(&data
, end
);
1427 rdlen
= get_uint16(&data
, end
);
1428 rdata
= get_rdata(&data
, end
, rdlen
);
1429 ttl
= get_uint32(&data
, end
);
1431 if (!data
) syslog(LOG_WARNING
, "dnssd_clientstub handle_query_response: error reading result from daemon");
1432 else ((DNSServiceQueryRecordReply
)sdr
->AppCallback
)(sdr
, cbh
->cb_flags
, cbh
->cb_interface
, cbh
->cb_err
, name
, rrtype
, rrclass
, rdlen
, rdata
, ttl
, sdr
->AppContext
);
1433 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1436 DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
1438 DNSServiceRef
*sdRef
,
1439 DNSServiceFlags flags
,
1440 uint32_t interfaceIndex
,
1444 DNSServiceQueryRecordReply callBack
,
1451 DNSServiceErrorType err
;
1453 // NULL name handled below.
1454 if (!sdRef
|| !callBack
) return kDNSServiceErr_BadParam
;
1456 if ((interfaceIndex
== kDNSServiceInterfaceIndexAny
) && includeP2PWithIndexAny())
1457 flags
|= kDNSServiceFlagsIncludeP2P
;
1459 err
= ConnectToServer(sdRef
, flags
, query_request
, handle_query_response
, callBack
, context
);
1460 if (err
) return err
; // On error ConnectToServer leaves *sdRef set to NULL
1462 if (!name
) name
= "\0";
1464 // Calculate total message length
1465 len
= sizeof(flags
);
1466 len
+= sizeof(uint32_t); // interfaceIndex
1467 len
+= strlen(name
) + 1;
1468 len
+= 2 * sizeof(uint16_t); // rrtype, rrclass
1470 hdr
= create_hdr(query_request
, &len
, &ptr
, (*sdRef
)->primary
? 1 : 0, *sdRef
);
1471 if (!hdr
) { DNSServiceRefDeallocate(*sdRef
); *sdRef
= NULL
; return kDNSServiceErr_NoMemory
; }
1473 put_flags(flags
, &ptr
);
1474 put_uint32(interfaceIndex
, &ptr
);
1475 put_string(name
, &ptr
);
1476 put_uint16(rrtype
, &ptr
);
1477 put_uint16(rrclass
, &ptr
);
1479 err
= deliver_request(hdr
, *sdRef
); // Will free hdr for us
1480 if (err
) { DNSServiceRefDeallocate(*sdRef
); *sdRef
= NULL
; }
1484 static void handle_addrinfo_response(DNSServiceOp
*const sdr
, const CallbackHeader
*const cbh
, const char *data
, const char *const end
)
1486 char hostname
[kDNSServiceMaxDomainName
];
1487 uint16_t rrtype
, rrclass
, rdlen
;
1491 get_string(&data
, end
, hostname
, kDNSServiceMaxDomainName
);
1492 rrtype
= get_uint16(&data
, end
);
1493 rrclass
= get_uint16(&data
, end
);
1494 rdlen
= get_uint16(&data
, end
);
1495 rdata
= get_rdata (&data
, end
, rdlen
);
1496 ttl
= get_uint32(&data
, end
);
1497 (void)rrclass
; // Unused
1499 // We only generate client callbacks for A and AAAA results (including NXDOMAIN results for
1500 // those types, if the client has requested those with the kDNSServiceFlagsReturnIntermediates).
1501 // Other result types, specifically CNAME referrals, are not communicated to the client, because
1502 // the DNSServiceGetAddrInfoReply interface doesn't have any meaningful way to communiate CNAME referrals.
1503 if (!data
) syslog(LOG_WARNING
, "dnssd_clientstub handle_addrinfo_response: error reading result from daemon");
1504 else if (rrtype
== kDNSServiceType_A
|| rrtype
== kDNSServiceType_AAAA
)
1506 struct sockaddr_in sa4
;
1507 struct sockaddr_in6 sa6
;
1508 const struct sockaddr
*const sa
= (rrtype
== kDNSServiceType_A
) ? (struct sockaddr
*)&sa4
: (struct sockaddr
*)&sa6
;
1509 if (rrtype
== kDNSServiceType_A
)
1511 memset(&sa4
, 0, sizeof(sa4
));
1512 #ifndef NOT_HAVE_SA_LEN
1513 sa4
.sin_len
= sizeof(struct sockaddr_in
);
1515 sa4
.sin_family
= AF_INET
;
1517 if (!cbh
->cb_err
) memcpy(&sa4
.sin_addr
, rdata
, rdlen
);
1521 memset(&sa6
, 0, sizeof(sa6
));
1522 #ifndef NOT_HAVE_SA_LEN
1523 sa6
.sin6_len
= sizeof(struct sockaddr_in6
);
1525 sa6
.sin6_family
= AF_INET6
;
1527 // sin6_flowinfo = 0;
1528 // sin6_scope_id = 0;
1531 memcpy(&sa6
.sin6_addr
, rdata
, rdlen
);
1532 if (IN6_IS_ADDR_LINKLOCAL(&sa6
.sin6_addr
)) sa6
.sin6_scope_id
= cbh
->cb_interface
;
1535 // Validation results are always delivered separately from the actual results of the
1536 // DNSServiceGetAddrInfo. Set the "addr" to NULL as per the documentation.
1538 // Note: If we deliver validation results along with the "addr" in the future, we need
1539 // a way to differentiate the negative response from validation-only response as both
1540 // has zero address.
1541 if (!(cbh
->cb_flags
& kDNSServiceFlagsValidate
))
1542 ((DNSServiceGetAddrInfoReply
)sdr
->AppCallback
)(sdr
, cbh
->cb_flags
, cbh
->cb_interface
, cbh
->cb_err
, hostname
, sa
, ttl
, sdr
->AppContext
);
1544 ((DNSServiceGetAddrInfoReply
)sdr
->AppCallback
)(sdr
, cbh
->cb_flags
, cbh
->cb_interface
, cbh
->cb_err
, hostname
, NULL
, 0, sdr
->AppContext
);
1545 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1549 DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
1551 DNSServiceRef
*sdRef
,
1552 DNSServiceFlags flags
,
1553 uint32_t interfaceIndex
,
1555 const char *hostname
,
1556 DNSServiceGetAddrInfoReply callBack
,
1557 void *context
/* may be NULL */
1563 DNSServiceErrorType err
;
1565 if (!sdRef
|| !hostname
|| !callBack
) return kDNSServiceErr_BadParam
;
1567 err
= ConnectToServer(sdRef
, flags
, addrinfo_request
, handle_addrinfo_response
, callBack
, context
);
1570 return err
; // On error ConnectToServer leaves *sdRef set to NULL
1573 // Calculate total message length
1574 len
= sizeof(flags
);
1575 len
+= sizeof(uint32_t); // interfaceIndex
1576 len
+= sizeof(uint32_t); // protocol
1577 len
+= strlen(hostname
) + 1;
1579 hdr
= create_hdr(addrinfo_request
, &len
, &ptr
, (*sdRef
)->primary
? 1 : 0, *sdRef
);
1580 if (!hdr
) { DNSServiceRefDeallocate(*sdRef
); *sdRef
= NULL
; return kDNSServiceErr_NoMemory
; }
1582 put_flags(flags
, &ptr
);
1583 put_uint32(interfaceIndex
, &ptr
);
1584 put_uint32(protocol
, &ptr
);
1585 put_string(hostname
, &ptr
);
1587 err
= deliver_request(hdr
, *sdRef
); // Will free hdr for us
1588 if (err
) { DNSServiceRefDeallocate(*sdRef
); *sdRef
= NULL
; }
1592 static void handle_browse_response(DNSServiceOp
*const sdr
, const CallbackHeader
*const cbh
, const char *data
, const char *const end
)
1594 char replyName
[256], replyType
[kDNSServiceMaxDomainName
], replyDomain
[kDNSServiceMaxDomainName
];
1595 get_string(&data
, end
, replyName
, 256);
1596 get_string(&data
, end
, replyType
, kDNSServiceMaxDomainName
);
1597 get_string(&data
, end
, replyDomain
, kDNSServiceMaxDomainName
);
1598 if (!data
) syslog(LOG_WARNING
, "dnssd_clientstub handle_browse_response: error reading result from daemon");
1599 else ((DNSServiceBrowseReply
)sdr
->AppCallback
)(sdr
, cbh
->cb_flags
, cbh
->cb_interface
, cbh
->cb_err
, replyName
, replyType
, replyDomain
, sdr
->AppContext
);
1600 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1603 DNSServiceErrorType DNSSD_API DNSServiceBrowse
1605 DNSServiceRef
*sdRef
,
1606 DNSServiceFlags flags
,
1607 uint32_t interfaceIndex
,
1608 const char *regtype
,
1610 DNSServiceBrowseReply callBack
,
1617 DNSServiceErrorType err
;
1619 // NULL domain handled below
1620 if (!sdRef
|| !regtype
|| !callBack
) return kDNSServiceErr_BadParam
;
1622 if ((interfaceIndex
== kDNSServiceInterfaceIndexAny
) && includeP2PWithIndexAny())
1623 flags
|= kDNSServiceFlagsIncludeP2P
;
1625 err
= ConnectToServer(sdRef
, flags
, browse_request
, handle_browse_response
, callBack
, context
);
1626 if (err
) return err
; // On error ConnectToServer leaves *sdRef set to NULL
1628 if (!domain
) domain
= "";
1629 len
= sizeof(flags
);
1630 len
+= sizeof(interfaceIndex
);
1631 len
+= strlen(regtype
) + 1;
1632 len
+= strlen(domain
) + 1;
1634 hdr
= create_hdr(browse_request
, &len
, &ptr
, (*sdRef
)->primary
? 1 : 0, *sdRef
);
1635 if (!hdr
) { DNSServiceRefDeallocate(*sdRef
); *sdRef
= NULL
; return kDNSServiceErr_NoMemory
; }
1637 put_flags(flags
, &ptr
);
1638 put_uint32(interfaceIndex
, &ptr
);
1639 put_string(regtype
, &ptr
);
1640 put_string(domain
, &ptr
);
1642 err
= deliver_request(hdr
, *sdRef
); // Will free hdr for us
1643 if (err
) { DNSServiceRefDeallocate(*sdRef
); *sdRef
= NULL
; }
1647 DNSServiceErrorType DNSSD_API
DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags
, const char *domain
)
1649 DNSServiceErrorType err
;
1655 if (!domain
) return kDNSServiceErr_BadParam
;
1656 len
= sizeof(flags
) + strlen(domain
) + 1;
1658 err
= ConnectToServer(&tmp
, 0, setdomain_request
, NULL
, NULL
, NULL
);
1659 if (err
) return err
;
1661 hdr
= create_hdr(setdomain_request
, &len
, &ptr
, 0, tmp
);
1662 if (!hdr
) { DNSServiceRefDeallocate(tmp
); return kDNSServiceErr_NoMemory
; }
1664 put_flags(flags
, &ptr
);
1665 put_string(domain
, &ptr
);
1666 err
= deliver_request(hdr
, tmp
); // Will free hdr for us
1667 DNSServiceRefDeallocate(tmp
);
1671 static void handle_regservice_response(DNSServiceOp
*const sdr
, const CallbackHeader
*const cbh
, const char *data
, const char *const end
)
1673 char name
[256], regtype
[kDNSServiceMaxDomainName
], domain
[kDNSServiceMaxDomainName
];
1674 get_string(&data
, end
, name
, 256);
1675 get_string(&data
, end
, regtype
, kDNSServiceMaxDomainName
);
1676 get_string(&data
, end
, domain
, kDNSServiceMaxDomainName
);
1677 if (!data
) syslog(LOG_WARNING
, "dnssd_clientstub handle_regservice_response: error reading result from daemon");
1678 else ((DNSServiceRegisterReply
)sdr
->AppCallback
)(sdr
, cbh
->cb_flags
, cbh
->cb_err
, name
, regtype
, domain
, sdr
->AppContext
);
1679 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1682 DNSServiceErrorType DNSSD_API DNSServiceRegister
1684 DNSServiceRef
*sdRef
,
1685 DNSServiceFlags flags
,
1686 uint32_t interfaceIndex
,
1688 const char *regtype
,
1691 uint16_t PortInNetworkByteOrder
,
1693 const void *txtRecord
,
1694 DNSServiceRegisterReply callBack
,
1701 DNSServiceErrorType err
;
1702 union { uint16_t s
; u_char b
[2]; } port
= { PortInNetworkByteOrder
};
1704 if (!sdRef
|| !regtype
) return kDNSServiceErr_BadParam
;
1705 if (!name
) name
= "";
1706 if (!domain
) domain
= "";
1707 if (!host
) host
= "";
1708 if (!txtRecord
) txtRecord
= (void*)"";
1710 // No callback must have auto-rename
1711 if (!callBack
&& (flags
& kDNSServiceFlagsNoAutoRename
)) return kDNSServiceErr_BadParam
;
1713 if ((interfaceIndex
== kDNSServiceInterfaceIndexAny
) && includeP2PWithIndexAny())
1714 flags
|= kDNSServiceFlagsIncludeP2P
;
1716 err
= ConnectToServer(sdRef
, flags
, reg_service_request
, callBack
? handle_regservice_response
: NULL
, callBack
, context
);
1717 if (err
) return err
; // On error ConnectToServer leaves *sdRef set to NULL
1719 len
= sizeof(DNSServiceFlags
);
1720 len
+= sizeof(uint32_t); // interfaceIndex
1721 len
+= strlen(name
) + strlen(regtype
) + strlen(domain
) + strlen(host
) + 4;
1722 len
+= 2 * sizeof(uint16_t); // port, txtLen
1725 hdr
= create_hdr(reg_service_request
, &len
, &ptr
, (*sdRef
)->primary
? 1 : 0, *sdRef
);
1726 if (!hdr
) { DNSServiceRefDeallocate(*sdRef
); *sdRef
= NULL
; return kDNSServiceErr_NoMemory
; }
1727 if (!callBack
) hdr
->ipc_flags
|= IPC_FLAGS_NOREPLY
;
1729 put_flags(flags
, &ptr
);
1730 put_uint32(interfaceIndex
, &ptr
);
1731 put_string(name
, &ptr
);
1732 put_string(regtype
, &ptr
);
1733 put_string(domain
, &ptr
);
1734 put_string(host
, &ptr
);
1737 put_uint16(txtLen
, &ptr
);
1738 put_rdata(txtLen
, txtRecord
, &ptr
);
1740 err
= deliver_request(hdr
, *sdRef
); // Will free hdr for us
1741 if (err
) { DNSServiceRefDeallocate(*sdRef
); *sdRef
= NULL
; }
1745 static void handle_enumeration_response(DNSServiceOp
*const sdr
, const CallbackHeader
*const cbh
, const char *data
, const char *const end
)
1747 char domain
[kDNSServiceMaxDomainName
];
1748 get_string(&data
, end
, domain
, kDNSServiceMaxDomainName
);
1749 if (!data
) syslog(LOG_WARNING
, "dnssd_clientstub handle_enumeration_response: error reading result from daemon");
1750 else ((DNSServiceDomainEnumReply
)sdr
->AppCallback
)(sdr
, cbh
->cb_flags
, cbh
->cb_interface
, cbh
->cb_err
, domain
, sdr
->AppContext
);
1751 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1754 DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
1756 DNSServiceRef
*sdRef
,
1757 DNSServiceFlags flags
,
1758 uint32_t interfaceIndex
,
1759 DNSServiceDomainEnumReply callBack
,
1766 DNSServiceErrorType err
;
1770 if (!sdRef
|| !callBack
) return kDNSServiceErr_BadParam
;
1772 f1
= (flags
& kDNSServiceFlagsBrowseDomains
) != 0;
1773 f2
= (flags
& kDNSServiceFlagsRegistrationDomains
) != 0;
1774 if (f1
+ f2
!= 1) return kDNSServiceErr_BadParam
;
1776 err
= ConnectToServer(sdRef
, flags
, enumeration_request
, handle_enumeration_response
, callBack
, context
);
1777 if (err
) return err
; // On error ConnectToServer leaves *sdRef set to NULL
1779 len
= sizeof(DNSServiceFlags
);
1780 len
+= sizeof(uint32_t);
1782 hdr
= create_hdr(enumeration_request
, &len
, &ptr
, (*sdRef
)->primary
? 1 : 0, *sdRef
);
1783 if (!hdr
) { DNSServiceRefDeallocate(*sdRef
); *sdRef
= NULL
; return kDNSServiceErr_NoMemory
; }
1785 put_flags(flags
, &ptr
);
1786 put_uint32(interfaceIndex
, &ptr
);
1788 err
= deliver_request(hdr
, *sdRef
); // Will free hdr for us
1789 if (err
) { DNSServiceRefDeallocate(*sdRef
); *sdRef
= NULL
; }
1793 static void ConnectionResponse(DNSServiceOp
*const sdr
, const CallbackHeader
*const cbh
, const char *const data
, const char *const end
)
1795 (void)data
; // Unused
1797 //printf("ConnectionResponse got %d\n", cbh->ipc_hdr.op);
1798 if (cbh
->ipc_hdr
.op
!= reg_record_reply_op
)
1800 // When using kDNSServiceFlagsShareConnection, need to search the list of associated DNSServiceOps
1801 // to find the one this response is intended for, and then call through to its ProcessReply handler.
1802 // We start with our first subordinate DNSServiceRef -- don't want to accidentally match the parent DNSServiceRef.
1803 DNSServiceOp
*op
= sdr
->next
;
1804 while (op
&& (op
->uid
.u32
[0] != cbh
->ipc_hdr
.client_context
.u32
[0] || op
->uid
.u32
[1] != cbh
->ipc_hdr
.client_context
.u32
[1]))
1806 // Note: We may sometimes not find a matching DNSServiceOp, in the case where the client has
1807 // cancelled the subordinate DNSServiceOp, but there are still messages in the pipeline from the daemon
1808 if (op
&& op
->ProcessReply
) op
->ProcessReply(op
, cbh
, data
, end
);
1809 // WARNING: Don't touch op or sdr after this -- client may have called DNSServiceRefDeallocate
1815 for (rec
= sdr
->rec
; rec
; rec
= rec
->recnext
)
1817 if (rec
->uid
.u32
[0] == cbh
->ipc_hdr
.client_context
.u32
[0] && rec
->uid
.u32
[1] == cbh
->ipc_hdr
.client_context
.u32
[1])
1820 // The record might have been freed already and hence not an
1821 // error if the record is not found.
1824 syslog(LOG_INFO
, "dnssd_clientstub ConnectionResponse: Record not found");
1827 if (rec
->sdr
!= sdr
)
1829 syslog(LOG_WARNING
, "dnssd_clientstub ConnectionResponse: Record sdr mismatch: rec %p sdr %p", rec
->sdr
, sdr
);
1833 if (sdr
->op
== connection_request
|| sdr
->op
== connection_delegate_request
)
1835 rec
->AppCallback(rec
->sdr
, rec
, cbh
->cb_flags
, cbh
->cb_err
, rec
->AppContext
);
1839 syslog(LOG_WARNING
, "dnssd_clientstub ConnectionResponse: sdr->op != connection_request");
1840 rec
->AppCallback(rec
->sdr
, rec
, 0, kDNSServiceErr_Unknown
, rec
->AppContext
);
1842 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1846 DNSServiceErrorType DNSSD_API
DNSServiceCreateConnection(DNSServiceRef
*sdRef
)
1848 DNSServiceErrorType err
;
1853 if (!sdRef
) return kDNSServiceErr_BadParam
;
1854 err
= ConnectToServer(sdRef
, 0, connection_request
, ConnectionResponse
, NULL
, NULL
);
1855 if (err
) return err
; // On error ConnectToServer leaves *sdRef set to NULL
1857 hdr
= create_hdr(connection_request
, &len
, &ptr
, 0, *sdRef
);
1858 if (!hdr
) { DNSServiceRefDeallocate(*sdRef
); *sdRef
= NULL
; return kDNSServiceErr_NoMemory
; }
1860 err
= deliver_request(hdr
, *sdRef
); // Will free hdr for us
1861 if (err
) { DNSServiceRefDeallocate(*sdRef
); *sdRef
= NULL
; }
1865 #if APPLE_OSX_mDNSResponder && !TARGET_OS_SIMULATOR
1866 DNSServiceErrorType DNSSD_API
DNSServiceCreateDelegateConnection(DNSServiceRef
*sdRef
, int32_t pid
, uuid_t uuid
)
1872 if (!sdRef
) return kDNSServiceErr_BadParam
;
1873 DNSServiceErrorType err
= ConnectToServer(sdRef
, 0, connection_delegate_request
, ConnectionResponse
, NULL
, NULL
);
1876 return err
; // On error ConnectToServer leaves *sdRef set to NULL
1879 // Only one of the two options can be set. If pid is zero, uuid is used.
1880 // If both are specified only pid will be used. We send across the pid
1881 // so that the daemon knows what to read from the socket.
1883 len
+= sizeof(int32_t);
1885 hdr
= create_hdr(connection_delegate_request
, &len
, &ptr
, 0, *sdRef
);
1888 DNSServiceRefDeallocate(*sdRef
);
1890 return kDNSServiceErr_NoMemory
;
1893 if (pid
&& setsockopt((*sdRef
)->sockfd
, SOL_SOCKET
, SO_DELEGATED
, &pid
, sizeof(pid
)) == -1)
1895 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceCreateDelegateConnection: Could not setsockopt() for PID[%d], no entitlements or process(pid) invalid errno:%d (%s)", pid
, errno
, strerror(errno
));
1896 // Free the hdr in case we return before calling deliver_request()
1899 DNSServiceRefDeallocate(*sdRef
);
1901 return kDNSServiceErr_NoAuth
;
1904 if (!pid
&& setsockopt((*sdRef
)->sockfd
, SOL_SOCKET
, SO_DELEGATED_UUID
, uuid
, sizeof(uuid_t
)) == -1)
1906 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceCreateDelegateConnection: Could not setsockopt() for UUID, no entitlements or process(uuid) invalid errno:%d (%s) ", errno
, strerror(errno
));
1907 // Free the hdr in case we return before calling deliver_request()
1910 DNSServiceRefDeallocate(*sdRef
);
1912 return kDNSServiceErr_NoAuth
;
1915 put_uint32(pid
, &ptr
);
1917 err
= deliver_request(hdr
, *sdRef
); // Will free hdr for us
1920 DNSServiceRefDeallocate(*sdRef
);
1925 #elif TARGET_OS_SIMULATOR // This hack is for Simulator platform only
1926 DNSServiceErrorType DNSSD_API
DNSServiceCreateDelegateConnection(DNSServiceRef
*sdRef
, int32_t pid
, uuid_t uuid
)
1930 return DNSServiceCreateConnection(sdRef
);
1934 DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
1936 DNSServiceRef sdRef
,
1937 DNSRecordRef
*RecordRef
,
1938 DNSServiceFlags flags
,
1939 uint32_t interfaceIndex
,
1940 const char *fullname
,
1946 DNSServiceRegisterRecordReply callBack
,
1952 ipc_msg_hdr
*hdr
= NULL
;
1953 DNSRecordRef rref
= NULL
;
1955 // Verify that only one of the following flags is set.
1956 int f1
= (flags
& kDNSServiceFlagsShared
) != 0;
1957 int f2
= (flags
& kDNSServiceFlagsUnique
) != 0;
1958 int f3
= (flags
& kDNSServiceFlagsKnownUnique
) != 0;
1959 if (f1
+ f2
+ f3
!= 1) return kDNSServiceErr_BadParam
;
1961 if ((interfaceIndex
== kDNSServiceInterfaceIndexAny
) && includeP2PWithIndexAny())
1962 flags
|= kDNSServiceFlagsIncludeP2P
;
1964 if (!sdRef
|| !RecordRef
|| !fullname
|| (!rdata
&& rdlen
) || !callBack
)
1966 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceRegisterRecord called with NULL parameter");
1967 return kDNSServiceErr_BadParam
;
1970 if (!DNSServiceRefValid(sdRef
))
1972 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceRegisterRecord called with invalid DNSServiceRef %p %08X %08X", sdRef
, sdRef
->sockfd
, sdRef
->validator
);
1973 return kDNSServiceErr_BadReference
;
1976 if (sdRef
->op
!= connection_request
&& sdRef
->op
!= connection_delegate_request
)
1978 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceRegisterRecord called with non-DNSServiceCreateConnection DNSServiceRef %p %d", sdRef
, sdRef
->op
);
1979 return kDNSServiceErr_BadReference
;
1984 len
= sizeof(DNSServiceFlags
);
1985 len
+= 2 * sizeof(uint32_t); // interfaceIndex, ttl
1986 len
+= 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen
1987 len
+= strlen(fullname
) + 1;
1990 // Bump up the uid. Normally for shared operations (kDNSServiceFlagsShareConnection), this
1991 // is done in ConnectToServer. For DNSServiceRegisterRecord, ConnectToServer has already
1992 // been called. As multiple DNSServiceRegisterRecords can be multiplexed over a single
1993 // connection, we need a way to demultiplex the response so that the callback corresponding
1994 // to the right DNSServiceRegisterRecord instance can be called. Use the same mechanism that
1995 // is used by kDNSServiceFlagsShareConnection. create_hdr copies the uid value to ipc
1996 // hdr->client_context which will be returned in the ipc response.
1997 if (++sdRef
->uid
.u32
[0] == 0)
1998 ++sdRef
->uid
.u32
[1];
1999 hdr
= create_hdr(reg_record_request
, &len
, &ptr
, 1, sdRef
);
2000 if (!hdr
) return kDNSServiceErr_NoMemory
;
2002 put_flags(flags
, &ptr
);
2003 put_uint32(interfaceIndex
, &ptr
);
2004 put_string(fullname
, &ptr
);
2005 put_uint16(rrtype
, &ptr
);
2006 put_uint16(rrclass
, &ptr
);
2007 put_uint16(rdlen
, &ptr
);
2008 put_rdata(rdlen
, rdata
, &ptr
);
2009 put_uint32(ttl
, &ptr
);
2011 rref
= malloc(sizeof(DNSRecord
));
2012 if (!rref
) { free(hdr
); return kDNSServiceErr_NoMemory
; }
2013 rref
->AppContext
= context
;
2014 rref
->AppCallback
= callBack
;
2015 rref
->record_index
= sdRef
->max_index
++;
2017 rref
->recnext
= NULL
;
2019 // Remember the uid that we are sending across so that we can match
2020 // when the response comes back.
2021 rref
->uid
= sdRef
->uid
;
2022 hdr
->reg_index
= rref
->record_index
;
2025 while (*p
) p
= &(*p
)->recnext
;
2028 return deliver_request(hdr
, sdRef
); // Will free hdr for us
2031 // sdRef returned by DNSServiceRegister()
2032 DNSServiceErrorType DNSSD_API DNSServiceAddRecord
2034 DNSServiceRef sdRef
,
2035 DNSRecordRef
*RecordRef
,
2036 DNSServiceFlags flags
,
2049 if (!sdRef
|| !RecordRef
|| (!rdata
&& rdlen
))
2051 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceAddRecord called with NULL parameter");
2052 return kDNSServiceErr_BadParam
;
2054 if (sdRef
->op
!= reg_service_request
)
2056 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceAddRecord called with non-DNSServiceRegister DNSServiceRef %p %d", sdRef
, sdRef
->op
);
2057 return kDNSServiceErr_BadReference
;
2060 if (!DNSServiceRefValid(sdRef
))
2062 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceAddRecord called with invalid DNSServiceRef %p %08X %08X", sdRef
, sdRef
->sockfd
, sdRef
->validator
);
2063 return kDNSServiceErr_BadReference
;
2068 len
+= 2 * sizeof(uint16_t); // rrtype, rdlen
2070 len
+= sizeof(uint32_t);
2071 len
+= sizeof(DNSServiceFlags
);
2073 hdr
= create_hdr(add_record_request
, &len
, &ptr
, 1, sdRef
);
2074 if (!hdr
) return kDNSServiceErr_NoMemory
;
2075 put_flags(flags
, &ptr
);
2076 put_uint16(rrtype
, &ptr
);
2077 put_uint16(rdlen
, &ptr
);
2078 put_rdata(rdlen
, rdata
, &ptr
);
2079 put_uint32(ttl
, &ptr
);
2081 rref
= malloc(sizeof(DNSRecord
));
2082 if (!rref
) { free(hdr
); return kDNSServiceErr_NoMemory
; }
2083 rref
->AppContext
= NULL
;
2084 rref
->AppCallback
= NULL
;
2085 rref
->record_index
= sdRef
->max_index
++;
2087 rref
->recnext
= NULL
;
2089 hdr
->reg_index
= rref
->record_index
;
2092 while (*p
) p
= &(*p
)->recnext
;
2095 return deliver_request(hdr
, sdRef
); // Will free hdr for us
2098 // DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
2099 DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
2101 DNSServiceRef sdRef
,
2102 DNSRecordRef RecordRef
,
2103 DNSServiceFlags flags
,
2113 if (!sdRef
|| (!rdata
&& rdlen
))
2115 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceUpdateRecord called with NULL parameter");
2116 return kDNSServiceErr_BadParam
;
2119 if (!DNSServiceRefValid(sdRef
))
2121 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceUpdateRecord called with invalid DNSServiceRef %p %08X %08X", sdRef
, sdRef
->sockfd
, sdRef
->validator
);
2122 return kDNSServiceErr_BadReference
;
2125 // Note: RecordRef is allowed to be NULL
2127 len
+= sizeof(uint16_t);
2129 len
+= sizeof(uint32_t);
2130 len
+= sizeof(DNSServiceFlags
);
2132 hdr
= create_hdr(update_record_request
, &len
, &ptr
, 1, sdRef
);
2133 if (!hdr
) return kDNSServiceErr_NoMemory
;
2134 hdr
->reg_index
= RecordRef
? RecordRef
->record_index
: TXT_RECORD_INDEX
;
2135 put_flags(flags
, &ptr
);
2136 put_uint16(rdlen
, &ptr
);
2137 put_rdata(rdlen
, rdata
, &ptr
);
2138 put_uint32(ttl
, &ptr
);
2139 return deliver_request(hdr
, sdRef
); // Will free hdr for us
2142 DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
2144 DNSServiceRef sdRef
,
2145 DNSRecordRef RecordRef
,
2146 DNSServiceFlags flags
2152 DNSServiceErrorType err
;
2154 if (!sdRef
) { syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam
; }
2155 if (!RecordRef
) { syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSRecordRef"); return kDNSServiceErr_BadParam
; }
2156 if (!sdRef
->max_index
) { syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceRemoveRecord called with bad DNSServiceRef"); return kDNSServiceErr_BadReference
; }
2158 if (!DNSServiceRefValid(sdRef
))
2160 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceRemoveRecord called with invalid DNSServiceRef %p %08X %08X", sdRef
, sdRef
->sockfd
, sdRef
->validator
);
2161 return kDNSServiceErr_BadReference
;
2164 len
+= sizeof(flags
);
2165 hdr
= create_hdr(remove_record_request
, &len
, &ptr
, 1, sdRef
);
2166 if (!hdr
) return kDNSServiceErr_NoMemory
;
2167 hdr
->reg_index
= RecordRef
->record_index
;
2168 put_flags(flags
, &ptr
);
2169 err
= deliver_request(hdr
, sdRef
); // Will free hdr for us
2172 // This RecordRef could have been allocated in DNSServiceRegisterRecord or DNSServiceAddRecord.
2173 // If so, delink from the list before freeing
2174 DNSRecord
**p
= &sdRef
->rec
;
2175 while (*p
&& *p
!= RecordRef
) p
= &(*p
)->recnext
;
2176 if (*p
) *p
= RecordRef
->recnext
;
2182 DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
2184 DNSServiceFlags flags
,
2185 uint32_t interfaceIndex
,
2186 const char *fullname
,
2193 DNSServiceErrorType err
;
2197 DNSServiceOp
*tmp
= NULL
;
2199 if (!fullname
|| (!rdata
&& rdlen
)) return kDNSServiceErr_BadParam
;
2201 err
= ConnectToServer(&tmp
, flags
, reconfirm_record_request
, NULL
, NULL
, NULL
);
2202 if (err
) return err
;
2204 len
= sizeof(DNSServiceFlags
);
2205 len
+= sizeof(uint32_t);
2206 len
+= strlen(fullname
) + 1;
2207 len
+= 3 * sizeof(uint16_t);
2209 hdr
= create_hdr(reconfirm_record_request
, &len
, &ptr
, 0, tmp
);
2210 if (!hdr
) { DNSServiceRefDeallocate(tmp
); return kDNSServiceErr_NoMemory
; }
2212 put_flags(flags
, &ptr
);
2213 put_uint32(interfaceIndex
, &ptr
);
2214 put_string(fullname
, &ptr
);
2215 put_uint16(rrtype
, &ptr
);
2216 put_uint16(rrclass
, &ptr
);
2217 put_uint16(rdlen
, &ptr
);
2218 put_rdata(rdlen
, rdata
, &ptr
);
2220 err
= deliver_request(hdr
, tmp
); // Will free hdr for us
2221 DNSServiceRefDeallocate(tmp
);
2226 static void handle_port_mapping_response(DNSServiceOp
*const sdr
, const CallbackHeader
*const cbh
, const char *data
, const char *const end
)
2228 union { uint32_t l
; u_char b
[4]; } addr
;
2230 union { uint16_t s
; u_char b
[2]; } internalPort
;
2231 union { uint16_t s
; u_char b
[2]; } externalPort
;
2234 if (!data
|| data
+ 13 > end
) goto fail
;
2236 addr
.b
[0] = *data
++;
2237 addr
.b
[1] = *data
++;
2238 addr
.b
[2] = *data
++;
2239 addr
.b
[3] = *data
++;
2241 internalPort
.b
[0] = *data
++;
2242 internalPort
.b
[1] = *data
++;
2243 externalPort
.b
[0] = *data
++;
2244 externalPort
.b
[1] = *data
++;
2245 ttl
= get_uint32(&data
, end
);
2246 if (!data
) goto fail
;
2248 ((DNSServiceNATPortMappingReply
)sdr
->AppCallback
)(sdr
, cbh
->cb_flags
, cbh
->cb_interface
, cbh
->cb_err
, addr
.l
, protocol
, internalPort
.s
, externalPort
.s
, ttl
, sdr
->AppContext
);
2250 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
2253 syslog(LOG_WARNING
, "dnssd_clientstub handle_port_mapping_response: error reading result from daemon");
2256 DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
2258 DNSServiceRef
*sdRef
,
2259 DNSServiceFlags flags
,
2260 uint32_t interfaceIndex
,
2261 uint32_t protocol
, /* TCP and/or UDP */
2262 uint16_t internalPortInNetworkByteOrder
,
2263 uint16_t externalPortInNetworkByteOrder
,
2264 uint32_t ttl
, /* time to live in seconds */
2265 DNSServiceNATPortMappingReply callBack
,
2266 void *context
/* may be NULL */
2272 union { uint16_t s
; u_char b
[2]; } internalPort
= { internalPortInNetworkByteOrder
};
2273 union { uint16_t s
; u_char b
[2]; } externalPort
= { externalPortInNetworkByteOrder
};
2275 DNSServiceErrorType err
= ConnectToServer(sdRef
, flags
, port_mapping_request
, handle_port_mapping_response
, callBack
, context
);
2276 if (err
) return err
; // On error ConnectToServer leaves *sdRef set to NULL
2278 len
= sizeof(flags
);
2279 len
+= sizeof(interfaceIndex
);
2280 len
+= sizeof(protocol
);
2281 len
+= sizeof(internalPort
);
2282 len
+= sizeof(externalPort
);
2285 hdr
= create_hdr(port_mapping_request
, &len
, &ptr
, (*sdRef
)->primary
? 1 : 0, *sdRef
);
2286 if (!hdr
) { DNSServiceRefDeallocate(*sdRef
); *sdRef
= NULL
; return kDNSServiceErr_NoMemory
; }
2288 put_flags(flags
, &ptr
);
2289 put_uint32(interfaceIndex
, &ptr
);
2290 put_uint32(protocol
, &ptr
);
2291 *ptr
++ = internalPort
.b
[0];
2292 *ptr
++ = internalPort
.b
[1];
2293 *ptr
++ = externalPort
.b
[0];
2294 *ptr
++ = externalPort
.b
[1];
2295 put_uint32(ttl
, &ptr
);
2297 err
= deliver_request(hdr
, *sdRef
); // Will free hdr for us
2298 if (err
) { DNSServiceRefDeallocate(*sdRef
); *sdRef
= NULL
; }
2302 #if _DNS_SD_LIBDISPATCH
2303 DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue
2305 DNSServiceRef service
,
2306 dispatch_queue_t queue
2309 int dnssd_fd
= DNSServiceRefSockFD(service
);
2310 if (dnssd_fd
== dnssd_InvalidSocket
) return kDNSServiceErr_BadParam
;
2313 syslog(LOG_WARNING
, "dnssd_clientstub: DNSServiceSetDispatchQueue dispatch queue NULL");
2314 return kDNSServiceErr_BadParam
;
2316 if (service
->disp_queue
)
2318 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch queue set already");
2319 return kDNSServiceErr_BadParam
;
2321 if (service
->disp_source
)
2323 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch source set already");
2324 return kDNSServiceErr_BadParam
;
2326 service
->disp_source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, dnssd_fd
, 0, queue
);
2327 if (!service
->disp_source
)
2329 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch_source_create failed");
2330 return kDNSServiceErr_NoMemory
;
2332 service
->disp_queue
= queue
;
2333 dispatch_source_set_event_handler(service
->disp_source
, ^{DNSServiceProcessResult(service
);});
2334 dispatch_source_set_cancel_handler(service
->disp_source
, ^{dnssd_close(dnssd_fd
);});
2335 dispatch_resume(service
->disp_source
);
2336 return kDNSServiceErr_NoError
;
2338 #endif // _DNS_SD_LIBDISPATCH
2340 #if !defined(_WIN32)
2342 static void DNSSD_API
SleepKeepaliveCallback(DNSServiceRef sdRef
, DNSRecordRef rec
, const DNSServiceFlags flags
,
2343 DNSServiceErrorType errorCode
, void *context
)
2345 SleepKAContext
*ka
= (SleepKAContext
*)context
;
2346 (void)rec
; // Unused
2347 (void)flags
; // Unused
2349 if (sdRef
->kacontext
!= context
)
2350 syslog(LOG_WARNING
, "dnssd_clientstub SleepKeepaliveCallback context mismatch");
2352 if (ka
->AppCallback
)
2353 ((DNSServiceSleepKeepaliveReply
)ka
->AppCallback
)(sdRef
, errorCode
, ka
->AppContext
);
2356 DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
2358 DNSServiceRef
*sdRef
,
2359 DNSServiceFlags flags
,
2361 unsigned int timeout
,
2362 DNSServiceSleepKeepaliveReply callBack
,
2366 char source_str
[INET6_ADDRSTRLEN
];
2367 char target_str
[INET6_ADDRSTRLEN
];
2368 struct sockaddr_storage lss
;
2369 struct sockaddr_storage rss
;
2370 socklen_t len1
, len2
;
2371 unsigned int len
, proxyreclen
;
2373 DNSServiceErrorType err
;
2374 DNSRecordRef record
= NULL
;
2378 unsigned int i
, unique
;
2381 (void) flags
; //unused
2382 if (!timeout
) return kDNSServiceErr_BadParam
;
2386 if (getsockname(fd
, (struct sockaddr
*)&lss
, &len1
) < 0)
2388 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceSleepKeepalive: getsockname %d\n", errno
);
2389 return kDNSServiceErr_BadParam
;
2393 if (getpeername(fd
, (struct sockaddr
*)&rss
, &len2
) < 0)
2395 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceSleepKeepalive: getpeername %d\n", errno
);
2396 return kDNSServiceErr_BadParam
;
2401 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceSleepKeepalive local/remote info not same");
2402 return kDNSServiceErr_Unknown
;
2406 if (lss
.ss_family
== AF_INET
)
2408 struct sockaddr_in
*sl
= (struct sockaddr_in
*)&lss
;
2409 struct sockaddr_in
*sr
= (struct sockaddr_in
*)&rss
;
2410 unsigned char *ptr
= (unsigned char *)&sl
->sin_addr
;
2412 if (!inet_ntop(AF_INET
, (const void *)&sr
->sin_addr
, target_str
, sizeof (target_str
)))
2414 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceSleepKeepalive remote info failed %d", errno
);
2415 return kDNSServiceErr_Unknown
;
2417 if (!inet_ntop(AF_INET
, (const void *)&sl
->sin_addr
, source_str
, sizeof (source_str
)))
2419 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceSleepKeepalive local info failed %d", errno
);
2420 return kDNSServiceErr_Unknown
;
2422 // Sum of all bytes in the local address and port should result in a unique
2423 // number in the local network
2424 for (i
= 0; i
< sizeof(struct in_addr
); i
++)
2426 unique
+= sl
->sin_port
;
2427 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
));
2431 struct sockaddr_in6
*sl6
= (struct sockaddr_in6
*)&lss
;
2432 struct sockaddr_in6
*sr6
= (struct sockaddr_in6
*)&rss
;
2433 unsigned char *ptr
= (unsigned char *)&sl6
->sin6_addr
;
2435 if (!inet_ntop(AF_INET6
, (const void *)&sr6
->sin6_addr
, target_str
, sizeof (target_str
)))
2437 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceSleepKeepalive remote6 info failed %d", errno
);
2438 return kDNSServiceErr_Unknown
;
2440 if (!inet_ntop(AF_INET6
, (const void *)&sl6
->sin6_addr
, source_str
, sizeof (source_str
)))
2442 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceSleepKeepalive local6 info failed %d", errno
);
2443 return kDNSServiceErr_Unknown
;
2445 for (i
= 0; i
< sizeof(struct in6_addr
); i
++)
2447 unique
+= sl6
->sin6_port
;
2448 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
));
2451 if (len
>= (sizeof(buf
) - 1))
2453 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceSleepKeepalive could not fit local/remote info");
2454 return kDNSServiceErr_Unknown
;
2456 // Include the NULL byte also in the first byte. The total length of the record includes the
2459 proxyreclen
= len
+ 2;
2461 len
= snprintf(name
, sizeof(name
), "%u", unique
);
2462 if (len
>= sizeof(name
))
2464 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceSleepKeepalive could not fit unique");
2465 return kDNSServiceErr_Unknown
;
2468 len
= snprintf(recname
, sizeof(recname
), "%s.%s", name
, "_keepalive._dns-sd._udp.local");
2469 if (len
>= sizeof(recname
))
2471 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceSleepKeepalive could not fit name");
2472 return kDNSServiceErr_Unknown
;
2475 ka
= malloc(sizeof(SleepKAContext
));
2476 if (!ka
) return kDNSServiceErr_NoMemory
;
2477 ka
->AppCallback
= callBack
;
2478 ka
->AppContext
= context
;
2480 err
= DNSServiceCreateConnection(sdRef
);
2483 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceSleepKeepalive cannot create connection");
2488 // we don't care about the "record". When sdRef gets deallocated later, it will be freed too
2489 err
= DNSServiceRegisterRecord(*sdRef
, &record
, kDNSServiceFlagsUnique
, 0, recname
,
2490 kDNSServiceType_NULL
, kDNSServiceClass_IN
, proxyreclen
, buf
, kDNSServiceInterfaceIndexAny
, SleepKeepaliveCallback
, ka
);
2493 syslog(LOG_WARNING
, "dnssd_clientstub DNSServiceSleepKeepalive cannot create connection");
2497 (*sdRef
)->kacontext
= ka
;
2498 return kDNSServiceErr_NoError
;