bump product version to 5.0.4.1
[LibreOffice.git] / sd / source / ui / remotecontrol / mDNSResponder / dnssd_clientstub.c
blobf8ac11663bb4f9a7ac60585f066a2528fe558e1a
1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2003-2004, Apple Computer, 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 Computer, Inc. ("Apple") nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
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 <sal/config.h>
31 #if defined _WIN32
32 #define _WINSOCK_DEPRECATED_NO_WARNINGS // warnings about inet_addr
33 #endif
35 #include <errno.h>
36 #include <stdlib.h>
38 #if APPLE_OSX_mDNSResponder
39 #include <mach-o/dyld.h>
40 #endif
42 #include "dnssd_ipc.h"
44 static int gDaemonErr = kDNSServiceErr_NoError;
46 #if defined(_WIN32)
48 #define _SSIZE_T
49 #include <CommonServices.h>
50 #include <DebugServices.h>
51 #include <winsock2.h>
52 #include <ws2tcpip.h>
53 #include <windows.h>
54 #include <stdarg.h>
55 #include <stdio.h>
57 #define sockaddr_mdns sockaddr_in
58 #define AF_MDNS AF_INET
60 // Disable warning: "'type cast' : from data pointer 'void *' to function pointer"
61 #pragma warning(disable:4055)
63 // Disable warning: "nonstandard extension, function/data pointer conversion in expression"
64 #pragma warning(disable:4152)
66 extern BOOL IsSystemServiceDisabled();
68 #define sleep(X) Sleep((X) * 1000)
70 static int g_initWinsock = 0;
71 #define LOG_WARNING kDebugLevelWarning
72 #define LOG_INFO kDebugLevelInfo
73 static void syslog( int priority, const char * message, ...)
75 va_list args;
76 int len;
77 char * buffer;
78 DWORD err = WSAGetLastError();
79 (void) priority;
80 va_start( args, message );
81 len = _vscprintf( message, args ) + 1;
82 buffer = malloc( len * sizeof(char) );
83 if ( buffer ) { vsprintf( buffer, message, args ); OutputDebugString( buffer ); free( buffer ); }
84 WSASetLastError( err );
85 va_end(args);
87 #else
89 #include <sys/fcntl.h>
90 #include <sys/time.h>
91 #include <sys/socket.h>
92 #include <syslog.h>
94 #define sockaddr_mdns sockaddr_un
95 #define AF_MDNS AF_LOCAL
97 #endif
99 // <rdar://problem/4096913> Specifies how many times we'll try and connect to the server.
101 #define DNSSD_CLIENT_MAXTRIES 4
103 // Uncomment the line below to use the old error return mechanism of creating a temporary named socket (e.g. in /var/tmp)
104 //#define USE_NAMED_ERROR_RETURN_SOCKET 1
106 #define DNSSD_CLIENT_TIMEOUT 10 // In seconds
108 #ifndef CTL_PATH_PREFIX
109 #define CTL_PATH_PREFIX "/var/tmp/dnssd_result_socket."
110 #endif
112 typedef struct
114 ipc_msg_hdr ipc_hdr;
115 DNSServiceFlags cb_flags;
116 uint32_t cb_interface;
117 DNSServiceErrorType cb_err;
118 } CallbackHeader;
120 typedef struct _DNSServiceRef_t DNSServiceOp;
121 typedef struct _DNSRecordRef_t DNSRecord;
123 #if !defined(_WIN32)
124 typedef struct
126 void *AppCallback; // Client callback function and context
127 void *AppContext;
128 } SleepKAContext;
129 #endif
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
157 void *AppContext;
158 DNSRecord *rec;
159 #if _DNS_SD_LIBDISPATCH
160 dispatch_source_t disp_source;
161 dispatch_queue_t disp_queue;
162 #endif
163 void *kacontext;
166 struct _DNSRecordRef_t
168 DNSRecord *recnext;
169 void *AppContext;
170 DNSServiceRegisterRecordReply AppCallback;
171 DNSRecordRef recref;
172 uint32_t record_index; // index is unique to the ServiceDiscoveryRef
173 client_context_t uid; // For demultiplexing multiple DNSServiceRegisterRecord calls
174 DNSServiceOp *sdr;
177 // Write len bytes. Return 0 on success, -1 on error
178 static int write_all(dnssd_sock_t sd, char *buf, size_t len)
180 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
181 //if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
182 while (len)
184 ssize_t num_written = send(sd, buf, (long)len, 0);
185 if (num_written < 0 || (size_t)num_written > len)
187 // Should never happen. If it does, it indicates some OS bug,
188 // or that the mDNSResponder daemon crashed (which should never happen).
189 #if !defined(__ppc__) && defined(SO_ISDEFUNCT)
190 int defunct;
191 socklen_t dlen = sizeof (defunct);
192 if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0)
193 syslog(LOG_WARNING, "dnssd_clientstub write_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
194 if (!defunct)
195 syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
196 (long)num_written, (long)len,
197 (num_written < 0) ? dnssd_errno : 0,
198 (num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
199 else
200 syslog(LOG_INFO, "dnssd_clientstub write_all(%d) DEFUNCT", sd);
201 #else
202 syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
203 (long)num_written, (long)len,
204 (num_written < 0) ? dnssd_errno : 0,
205 (num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
206 #endif
207 return -1;
209 buf += num_written;
210 len -= num_written;
212 return 0;
215 enum { read_all_success = 0, read_all_fail = -1, read_all_wouldblock = -2 };
217 // Read len bytes. Return 0 on success, read_all_fail on error, or read_all_wouldblock for
218 static int read_all(dnssd_sock_t sd, char *buf, int len)
220 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
221 //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1;
223 while (len)
225 ssize_t num_read = recv(sd, buf, len, 0);
226 // It is valid to get an interrupted system call error e.g., somebody attaching
227 // in a debugger, retry without failing
228 if ((num_read < 0) && (errno == EINTR)) { syslog(LOG_INFO, "dnssd_clientstub read_all: EINTR continue"); continue; }
229 if ((num_read == 0) || (num_read < 0) || (num_read > len))
231 int printWarn = 0;
232 int defunct = 0;
233 // Should never happen. If it does, it indicates some OS bug,
234 // or that the mDNSResponder daemon crashed (which should never happen).
235 #if defined(WIN32)
236 // <rdar://problem/7481776> Suppress logs for "A non-blocking socket operation
237 // could not be completed immediately"
238 if (WSAGetLastError() != WSAEWOULDBLOCK)
239 printWarn = 1;
240 #endif
241 #if !defined(__ppc__) && defined(SO_ISDEFUNCT)
243 socklen_t dlen = sizeof (defunct);
244 if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0)
245 syslog(LOG_WARNING, "dnssd_clientstub read_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
247 if (!defunct)
248 printWarn = 1;
249 #endif
250 if (printWarn)
251 syslog(LOG_WARNING, "dnssd_clientstub read_all(%d) failed %ld/%ld %d %s", sd,
252 (long)num_read, (long)len,
253 (num_read < 0) ? dnssd_errno : 0,
254 (num_read < 0) ? dnssd_strerror(dnssd_errno) : "");
255 else if (defunct)
256 syslog(LOG_INFO, "dnssd_clientstub read_all(%d) DEFUNCT", sd);
257 return (num_read < 0 && dnssd_errno == dnssd_EWOULDBLOCK) ? read_all_wouldblock : read_all_fail;
259 buf += num_read;
260 len -= num_read;
262 return read_all_success;
265 // Returns 1 if more bytes remain to be read on socket descriptor sd, 0 otherwise
266 static int more_bytes(dnssd_sock_t sd)
268 struct timeval tv = { 0, 0 };
269 fd_set readfds;
270 fd_set *fs;
271 int ret;
273 if (sd < FD_SETSIZE)
275 fs = &readfds;
276 FD_ZERO(fs);
278 else
280 // Compute the number of integers needed for storing "sd". Internally fd_set is stored
281 // as an array of ints with one bit for each fd and hence we need to compute
282 // the number of ints needed rather than the number of bytes. If "sd" is 32, we need
283 // two ints and not just one.
284 int nfdbits = sizeof (int) * 8;
285 int nints = (sd/nfdbits) + 1;
286 fs = (fd_set *)calloc(nints, sizeof(int));
287 if (fs == NULL) { syslog(LOG_WARNING, "dnssd_clientstub more_bytes: malloc failed"); return 0; }
289 FD_SET(sd, fs);
290 ret = select((int)sd+1, fs, (fd_set*)NULL, (fd_set*)NULL, &tv);
291 if (fs != &readfds) free(fs);
292 return (ret > 0);
295 // Wait for daemon to write to socket
296 static int wait_for_daemon(dnssd_sock_t sock, int timeout)
298 #ifndef WIN32
299 // At this point the next operation (accept() or read()) on this socket may block for a few milliseconds waiting
300 // for the daemon to respond, but that's okay -- the daemon is a trusted service and we know if won't take more
301 // than a few milliseconds to respond. So we'll forego checking for readability of the socket.
302 (void) sock;
303 (void) timeout;
304 #else
305 // Windows on the other hand suffers from 3rd party software (primarily 3rd party firewall software) that
306 // interferes with proper functioning of the TCP protocol stack. Because of this and because we depend on TCP
307 // to communicate with the system service, we want to make sure that the next operation on this socket (accept() or
308 // read()) doesn't block indefinitely.
309 if (!gDaemonErr)
311 struct timeval tv;
312 fd_set set;
314 FD_ZERO(&set);
315 FD_SET(sock, &set);
316 tv.tv_sec = timeout;
317 tv.tv_usec = 0;
318 if (!select((int)(sock + 1), &set, NULL, NULL, &tv))
320 syslog(LOG_WARNING, "dnssd_clientstub wait_for_daemon timed out");
321 gDaemonErr = kDNSServiceErr_Timeout;
324 #endif
325 return gDaemonErr;
328 /* create_hdr
330 * allocate and initialize an ipc message header. Value of len should initially be the
331 * length of the data, and is set to the value of the data plus the header. data_start
332 * is set to point to the beginning of the data section. SeparateReturnSocket should be
333 * non-zero for calls that can't receive an immediate error return value on their primary
334 * socket, and therefore require a separate return path for the error code result.
335 * if zero, the path to a control socket is appended at the beginning of the message buffer.
336 * data_start is set past this string.
338 static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int SeparateReturnSocket, DNSServiceOp *ref)
340 char *msg = NULL;
341 ipc_msg_hdr *hdr;
342 int datalen;
343 #if !defined(USE_TCP_LOOPBACK)
344 char ctrl_path[64] = ""; // "/var/tmp/dnssd_result_socket.xxxxxxxxxx-xxx-xxxxxx"
345 #endif
347 if (SeparateReturnSocket)
349 #if defined(USE_TCP_LOOPBACK)
350 *len += 2; // Allocate space for two-byte port number
351 #elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
352 struct timeval tv;
353 if (gettimeofday(&tv, NULL) < 0)
354 { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: gettimeofday failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); return NULL; }
355 sprintf(ctrl_path, "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(),
356 (unsigned long)(tv.tv_sec & 0xFFF), (unsigned long)(tv.tv_usec));
357 *len += strlen(ctrl_path) + 1;
358 #else
359 *len += 1; // Allocate space for single zero byte (empty C string)
360 #endif
363 datalen = (int) *len;
364 *len += sizeof(ipc_msg_hdr);
366 // Write message to buffer
367 msg = malloc(*len);
368 if (!msg) { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: malloc failed"); return NULL; }
370 memset(msg, 0, *len);
371 hdr = (ipc_msg_hdr *)msg;
372 hdr->version = VERSION;
373 hdr->datalen = datalen;
374 hdr->ipc_flags = 0;
375 hdr->op = op;
376 hdr->client_context = ref->uid;
377 hdr->reg_index = 0;
378 *data_start = msg + sizeof(ipc_msg_hdr);
379 #if defined(USE_TCP_LOOPBACK)
380 // Put dummy data in for the port, since we don't know what it is yet.
381 // The data will get filled in before we send the message. This happens in deliver_request().
382 if (SeparateReturnSocket) put_uint16(0, data_start);
383 #else
384 if (SeparateReturnSocket) put_string(ctrl_path, data_start);
385 #endif
386 return hdr;
389 static void FreeDNSRecords(DNSServiceOp *sdRef)
391 DNSRecord *rec = sdRef->rec;
392 while (rec)
394 DNSRecord *next = rec->recnext;
395 free(rec);
396 rec = next;
400 static void FreeDNSServiceOp(DNSServiceOp *x)
402 // We don't use our DNSServiceRefValid macro here because if we're cleaning up after a socket() call failed
403 // then sockfd could legitimately contain a failing value (e.g. dnssd_InvalidSocket)
404 if ((x->sockfd ^ x->validator) != ValidatorBits)
405 syslog(LOG_WARNING, "dnssd_clientstub attempt to dispose invalid DNSServiceRef %p %08X %08X", x, x->sockfd, x->validator);
406 else
408 x->next = NULL;
409 x->primary = NULL;
410 x->sockfd = dnssd_InvalidSocket;
411 x->validator = 0xDDDDDDDD;
412 x->op = request_op_none;
413 x->max_index = 0;
414 x->logcounter = 0;
415 x->moreptr = NULL;
416 x->ProcessReply = NULL;
417 x->AppCallback = NULL;
418 x->AppContext = NULL;
419 #if _DNS_SD_LIBDISPATCH
420 if (x->disp_source) dispatch_release(x->disp_source);
421 x->disp_source = NULL;
422 x->disp_queue = NULL;
423 #endif
424 // DNSRecords may have been added to subordinate sdRef e.g., DNSServiceRegister/DNSServiceAddRecord
425 // or on the main sdRef e.g., DNSServiceCreateConnection/DNSServiveRegisterRecord. DNSRecords may have
426 // been freed if the application called DNSRemoveRecord
427 FreeDNSRecords(x);
428 if (x->kacontext)
430 free(x->kacontext);
431 x->kacontext = NULL;
433 free(x);
437 // Return a connected service ref (deallocate with DNSServiceRefDeallocate)
438 static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags flags, uint32_t op, ProcessReplyFn ProcessReply, void *AppCallback, void *AppContext)
440 #if APPLE_OSX_mDNSResponder
441 int NumTries = DNSSD_CLIENT_MAXTRIES;
442 #else
443 int NumTries = 0;
444 #endif
446 dnssd_sockaddr_t saddr;
447 DNSServiceOp *sdr;
449 if (!ref) { syslog(LOG_WARNING, "dnssd_clientstub DNSService operation with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
451 if (flags & kDNSServiceFlagsShareConnection)
453 if (!*ref)
455 syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with NULL DNSServiceRef");
456 return kDNSServiceErr_BadParam;
458 if (!DNSServiceRefValid(*ref) || (*ref)->op != connection_request || (*ref)->primary)
460 syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with invalid DNSServiceRef %p %08X %08X",
461 (*ref), (*ref)->sockfd, (*ref)->validator);
462 *ref = NULL;
463 return kDNSServiceErr_BadReference;
467 #if defined(_WIN32)
468 if (!g_initWinsock)
470 WSADATA wsaData;
471 g_initWinsock = 1;
472 if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { *ref = NULL; return kDNSServiceErr_ServiceNotRunning; }
474 // <rdar://problem/4096913> If the system service is disabled, we only want to try to connect once
475 if (IsSystemServiceDisabled()) NumTries = DNSSD_CLIENT_MAXTRIES;
476 #endif
478 sdr = malloc(sizeof(DNSServiceOp));
479 if (!sdr) { syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: malloc failed"); *ref = NULL; return kDNSServiceErr_NoMemory; }
480 sdr->next = NULL;
481 sdr->primary = NULL;
482 sdr->sockfd = dnssd_InvalidSocket;
483 sdr->validator = sdr->sockfd ^ ValidatorBits;
484 sdr->op = op;
485 sdr->max_index = 0;
486 sdr->logcounter = 0;
487 sdr->moreptr = NULL;
488 sdr->uid.u32[0] = 0;
489 sdr->uid.u32[1] = 0;
490 sdr->ProcessReply = ProcessReply;
491 sdr->AppCallback = AppCallback;
492 sdr->AppContext = AppContext;
493 sdr->rec = NULL;
494 #if _DNS_SD_LIBDISPATCH
495 sdr->disp_source = NULL;
496 sdr->disp_queue = NULL;
497 #endif
498 sdr->kacontext = NULL;
500 if (flags & kDNSServiceFlagsShareConnection)
502 DNSServiceOp **p = &(*ref)->next; // Append ourselves to end of primary's list
503 while (*p) p = &(*p)->next;
504 *p = sdr;
505 // Preincrement counter before we use it -- it helps with debugging if we know the all-zeroes ID should never appear
506 if (++(*ref)->uid.u32[0] == 0) ++(*ref)->uid.u32[1]; // In parent DNSServiceOp increment UID counter
507 sdr->primary = *ref; // Set our primary pointer
508 sdr->sockfd = (*ref)->sockfd; // Inherit primary's socket
509 sdr->validator = (*ref)->validator;
510 sdr->uid = (*ref)->uid;
511 //printf("ConnectToServer sharing socket %d\n", sdr->sockfd);
513 else
515 #ifdef SO_NOSIGPIPE
516 const unsigned long optval = 1;
517 #endif
518 *ref = NULL;
519 sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0);
520 sdr->validator = sdr->sockfd ^ ValidatorBits;
521 if (!dnssd_SocketValid(sdr->sockfd))
523 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: socket failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
524 FreeDNSServiceOp(sdr);
525 return kDNSServiceErr_NoMemory;
527 #ifdef SO_NOSIGPIPE
528 // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
529 if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
530 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_NOSIGPIPE failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
531 #endif
532 #if defined(USE_TCP_LOOPBACK)
533 saddr.sin_family = AF_INET;
534 saddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
535 saddr.sin_port = htons(MDNS_TCP_SERVERPORT);
536 #else
537 saddr.sun_family = AF_LOCAL;
538 strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH);
539 #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
541 int defunct = 1;
542 if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
543 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
545 #endif
546 #endif
548 while (1)
550 int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
551 if (!err) break; // If we succeeded, return sdr
552 // If we failed, then it may be because the daemon is still launching.
553 // This can happen for processes that launch early in the boot process, while the
554 // daemon is still coming up. Rather than fail here, we'll wait a bit and try again.
555 // If, after four seconds, we still can't connect to the daemon,
556 // then we give up and return a failure code.
557 if (++NumTries < DNSSD_CLIENT_MAXTRIES) sleep(1); // Sleep a bit, then try again
558 else { dnssd_close(sdr->sockfd); FreeDNSServiceOp(sdr); return kDNSServiceErr_ServiceNotRunning; }
560 //printf("ConnectToServer opened socket %d\n", sdr->sockfd);
563 *ref = sdr;
564 return kDNSServiceErr_NoError;
567 #define deliver_request_bailout(MSG) \
568 do { syslog(LOG_WARNING, "dnssd_clientstub deliver_request: %s failed %d (%s)", (MSG), dnssd_errno, dnssd_strerror(dnssd_errno)); goto cleanup; } while(0)
570 static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
572 uint32_t datalen = hdr->datalen; // We take a copy here because we're going to convert hdr->datalen to network byte order
573 #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
574 char *const data = (char *)hdr + sizeof(ipc_msg_hdr);
575 #endif
576 dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
577 DNSServiceErrorType err = kDNSServiceErr_Unknown; // Default for the "goto cleanup" cases
578 int MakeSeparateReturnSocket = 0;
580 // Note: need to check hdr->op, not sdr->op.
581 // hdr->op contains the code for the specific operation we're currently doing, whereas sdr->op
582 // contains the original parent DNSServiceOp (e.g. for an add_record_request, hdr->op will be
583 // add_record_request but the parent sdr->op will be connection_request or reg_service_request)
584 if (sdr->primary ||
585 hdr->op == reg_record_request || hdr->op == add_record_request || hdr->op == update_record_request || hdr->op == remove_record_request)
586 MakeSeparateReturnSocket = 1;
588 if (!DNSServiceRefValid(sdr))
590 syslog(LOG_WARNING, "dnssd_clientstub deliver_request: invalid DNSServiceRef %p %08X %08X", sdr, sdr->sockfd, sdr->validator);
591 return kDNSServiceErr_BadReference;
594 if (!hdr) { syslog(LOG_WARNING, "dnssd_clientstub deliver_request: !hdr"); return kDNSServiceErr_Unknown; }
596 if (MakeSeparateReturnSocket)
598 #if defined(USE_TCP_LOOPBACK)
600 union { uint16_t s; u_char b[2]; } port;
601 dnssd_sockaddr_t caddr;
602 dnssd_socklen_t len = (dnssd_socklen_t) sizeof(caddr);
603 listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
604 if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("TCP socket");
606 caddr.sin_family = AF_INET;
607 caddr.sin_port = 0;
608 caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
609 if (bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr)) < 0) deliver_request_bailout("TCP bind");
610 if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) deliver_request_bailout("TCP getsockname");
611 if (listen(listenfd, 1) < 0) deliver_request_bailout("TCP listen");
612 port.s = caddr.sin_port;
613 data[0] = port.b[0]; // don't switch the byte order, as the
614 data[1] = port.b[1]; // daemon expects it in network byte order
616 #elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
618 mode_t mask;
619 int bindresult;
620 dnssd_sockaddr_t caddr;
621 listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
622 if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET socket");
624 caddr.sun_family = AF_LOCAL;
625 // According to Stevens (section 3.2), there is no portable way to
626 // determine whether sa_len is defined on a particular platform.
627 #ifndef NOT_HAVE_SA_LEN
628 caddr.sun_len = sizeof(struct sockaddr_un);
629 #endif
630 strcpy(caddr.sun_path, data);
631 #error "the below umask(3) calls are bad in a MT program (cf. fdo#60338):"
632 mask = umask(0);
633 bindresult = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr));
634 umask(mask);
635 if (bindresult < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET bind");
636 if (listen(listenfd, 1) < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET listen");
638 #else
640 dnssd_sock_t sp[2];
641 if (socketpair(AF_DNSSD, SOCK_STREAM, 0, sp) < 0) deliver_request_bailout("socketpair");
642 else
644 errsd = sp[0]; // We'll read our four-byte error code from sp[0]
645 listenfd = sp[1]; // We'll send sp[1] to the daemon
646 #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
648 int defunct = 1;
649 if (setsockopt(errsd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
650 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
652 #endif
655 #endif
658 #if !defined(USE_TCP_LOOPBACK) && !defined(USE_NAMED_ERROR_RETURN_SOCKET)
659 // If we're going to make a separate error return socket, and pass it to the daemon
660 // using sendmsg, then we'll hold back one data byte to go with it.
661 // On some versions of Unix (including Leopard) sending a control message without
662 // any associated data does not work reliably -- e.g. one particular issue we ran
663 // into is that if the receiving program is in a kqueue loop waiting to be notified
664 // of the received message, it doesn't get woken up when the control message arrives.
665 if (MakeSeparateReturnSocket || sdr->op == send_bpf) datalen--; // Okay to use sdr->op when checking for op == send_bpf
666 #endif
668 // At this point, our listening socket is set up and waiting, if necessary, for the daemon to connect back to
669 ConvertHeaderBytes(hdr);
670 //syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %lu bytes", (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
671 //if (MakeSeparateReturnSocket) syslog(LOG_WARNING, "dnssd_clientstub deliver_request name is %s", data);
672 #if TEST_SENDING_ONE_BYTE_AT_A_TIME
673 unsigned int i;
674 for (i=0; i<datalen + sizeof(ipc_msg_hdr); i++)
676 syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %d", i);
677 if (write_all(sdr->sockfd, ((char *)hdr)+i, 1) < 0)
678 { syslog(LOG_WARNING, "write_all (byte %u) failed", i); goto cleanup; }
679 usleep(10000);
681 #else
682 if (write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr)) < 0)
684 // write_all already prints an error message if there is an error writing to
685 // the socket except for DEFUNCT. Logging here is unnecessary and also wrong
686 // in the case of DEFUNCT sockets
687 syslog(LOG_INFO, "dnssd_clientstub deliver_request ERROR: write_all(%d, %lu bytes) failed",
688 sdr->sockfd, (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
689 goto cleanup;
691 #endif
693 if (!MakeSeparateReturnSocket) errsd = sdr->sockfd;
694 if (MakeSeparateReturnSocket || sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
696 #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
697 // At this point we may block in accept for a few milliseconds waiting for the daemon to connect back to us,
698 // but that's okay -- the daemon is a trusted service and we know if won't take more than a few milliseconds to respond.
699 dnssd_sockaddr_t daddr;
700 dnssd_socklen_t len = sizeof(daddr);
701 if ((err = wait_for_daemon(listenfd, DNSSD_CLIENT_TIMEOUT)) != kDNSServiceErr_NoError) goto cleanup;
702 errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
703 if (!dnssd_SocketValid(errsd)) deliver_request_bailout("accept");
704 #else
706 struct iovec vec = { ((char *)hdr) + sizeof(ipc_msg_hdr) + datalen, 1 }; // Send the last byte along with the SCM_RIGHTS
707 struct msghdr msg;
708 struct cmsghdr *cmsg;
709 char cbuf[CMSG_SPACE(sizeof(dnssd_sock_t))];
711 if (sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
713 int i;
714 char p[12]; // Room for "/dev/bpf999" with terminating null
715 for (i=0; i<100; i++)
717 snprintf(p, sizeof(p), "/dev/bpf%d", i);
718 listenfd = open(p, O_RDWR, 0);
719 //if (dnssd_SocketValid(listenfd)) syslog(LOG_WARNING, "Sending fd %d for %s", listenfd, p);
720 if (!dnssd_SocketValid(listenfd) && dnssd_errno != EBUSY)
721 syslog(LOG_WARNING, "Error opening %s %d (%s)", p, dnssd_errno, dnssd_strerror(dnssd_errno));
722 if (dnssd_SocketValid(listenfd) || dnssd_errno != EBUSY) break;
726 msg.msg_name = 0;
727 msg.msg_namelen = 0;
728 msg.msg_iov = &vec;
729 msg.msg_iovlen = 1;
730 msg.msg_control = cbuf;
731 msg.msg_controllen = CMSG_LEN(sizeof(dnssd_sock_t));
732 msg.msg_flags = 0;
733 cmsg = CMSG_FIRSTHDR(&msg);
734 cmsg->cmsg_len = CMSG_LEN(sizeof(dnssd_sock_t));
735 cmsg->cmsg_level = SOL_SOCKET;
736 cmsg->cmsg_type = SCM_RIGHTS;
737 *((dnssd_sock_t *)CMSG_DATA(cmsg)) = listenfd;
739 #if TEST_KQUEUE_CONTROL_MESSAGE_BUG
740 sleep(1);
741 #endif
743 #if DEBUG_64BIT_SCM_RIGHTS
744 syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d %ld %ld %ld/%ld/%ld/%ld",
745 errsd, listenfd, sizeof(dnssd_sock_t), sizeof(void*),
746 sizeof(struct cmsghdr) + sizeof(dnssd_sock_t),
747 CMSG_LEN(sizeof(dnssd_sock_t)), (long)CMSG_SPACE(sizeof(dnssd_sock_t)),
748 (long)((char*)CMSG_DATA(cmsg) + 4 - cbuf));
749 #endif // DEBUG_64BIT_SCM_RIGHTS
751 if (sendmsg(sdr->sockfd, &msg, 0) < 0)
753 syslog(LOG_WARNING, "dnssd_clientstub deliver_request ERROR: sendmsg failed read sd=%d write sd=%d errno %d (%s)",
754 errsd, listenfd, dnssd_errno, dnssd_strerror(dnssd_errno));
755 err = kDNSServiceErr_Incompatible;
756 goto cleanup;
759 #if DEBUG_64BIT_SCM_RIGHTS
760 syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d okay", errsd, listenfd);
761 #endif // DEBUG_64BIT_SCM_RIGHTS
763 #endif
764 // Close our end of the socketpair *before* blocking in read_all to get the four-byte error code.
765 // Otherwise, if the daemon closes our socket (or crashes), we block in read_all() forever
766 // because the socket is not closed (we still have an open reference to it ourselves).
767 dnssd_close(listenfd);
768 listenfd = dnssd_InvalidSocket; // Make sure we don't close it a second time in the cleanup handling below
771 // At this point we may block in read_all for a few milliseconds waiting for the daemon to send us the error code,
772 // but that's okay -- the daemon is a trusted service and we know if won't take more than a few milliseconds to respond.
773 if (sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
774 err = kDNSServiceErr_NoError;
775 else if ((err = wait_for_daemon(errsd, DNSSD_CLIENT_TIMEOUT)) == kDNSServiceErr_NoError)
777 if (read_all(errsd, (char*)&err, (int)sizeof(err)) < 0)
778 err = kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us
779 else
780 err = ntohl(err);
783 //syslog(LOG_WARNING, "dnssd_clientstub deliver_request: retrieved error code %d", err);
785 cleanup:
786 if (MakeSeparateReturnSocket)
788 if (dnssd_SocketValid(listenfd)) dnssd_close(listenfd);
789 if (dnssd_SocketValid(errsd)) dnssd_close(errsd);
790 #if defined(USE_NAMED_ERROR_RETURN_SOCKET)
791 // syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removing UDS: %s", data);
792 if (unlink(data) != 0)
793 syslog(LOG_WARNING, "dnssd_clientstub WARNING: unlink(\"%s\") failed errno %d (%s)", data, dnssd_errno, dnssd_strerror(dnssd_errno));
794 // else syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removed UDS: %s", data);
795 #endif
798 free(hdr);
799 return err;
802 int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef)
804 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with NULL DNSServiceRef"); return dnssd_InvalidSocket; }
806 if (!DNSServiceRefValid(sdRef))
808 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with invalid DNSServiceRef %p %08X %08X",
809 sdRef, sdRef->sockfd, sdRef->validator);
810 return dnssd_InvalidSocket;
813 if (sdRef->primary)
815 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
816 return dnssd_InvalidSocket;
819 return (int) sdRef->sockfd;
822 #if _DNS_SD_LIBDISPATCH
823 static void CallbackWithError(DNSServiceRef sdRef, DNSServiceErrorType error)
825 DNSServiceOp *sdr = sdRef;
826 DNSServiceOp *sdrNext;
827 DNSRecord *rec;
828 DNSRecord *recnext;
829 int morebytes;
831 while (sdr)
833 // We can't touch the sdr after the callback as it can be deallocated in the callback
834 sdrNext = sdr->next;
835 morebytes = 1;
836 sdr->moreptr = &morebytes;
837 switch (sdr->op)
839 case resolve_request:
840 if (sdr->AppCallback) ((DNSServiceResolveReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, sdr->AppContext);
841 break;
842 case query_request:
843 if (sdr->AppCallback) ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, 0, sdr->AppContext);
844 break;
845 case addrinfo_request:
846 if (sdr->AppCallback) ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, NULL, 0, sdr->AppContext);
847 break;
848 case browse_request:
849 if (sdr->AppCallback) ((DNSServiceBrowseReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, NULL, sdr->AppContext);
850 break;
851 case reg_service_request:
852 if (sdr->AppCallback) ((DNSServiceRegisterReply) sdr->AppCallback)(sdr, 0, error, NULL, 0, NULL, sdr->AppContext);
853 break;
854 case enumeration_request:
855 if (sdr->AppCallback) ((DNSServiceDomainEnumReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, sdr->AppContext);
856 break;
857 case connection_request:
858 // This means Register Record, walk the list of DNSRecords to do the callback
859 rec = sdr->rec;
860 while (rec)
862 recnext = rec->recnext;
863 if (rec->AppCallback) ((DNSServiceRegisterRecordReply)rec->AppCallback)(sdr, 0, 0, error, rec->AppContext);
864 // The Callback can call DNSServiceRefDeallocate which in turn frees sdr and all the records.
865 // Detect that and return early
866 if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:Record: CallbackwithError morebytes zero"); return;}
867 rec = recnext;
869 break;
870 case port_mapping_request:
871 if (sdr->AppCallback) ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, 0, 0, error, 0, 0, 0, 0, 0, sdr->AppContext);
872 break;
873 default:
874 syslog(LOG_WARNING, "dnssd_clientstub CallbackWithError called with bad op %d", sdr->op);
876 // If DNSServiceRefDeallocate was called in the callback, morebytes will be zero. As the sdRef
877 // (and its subordinates) have been freed, we should not proceed further. Note that when we
878 // call the callback with a subordinate sdRef the application can call DNSServiceRefDeallocate
879 // on the main sdRef and DNSServiceRefDeallocate handles this case by walking all the sdRefs and
880 // clears the moreptr so that we can terminate here.
882 // If DNSServiceRefDeallocate was not called in the callback, then set moreptr to NULL so that
883 // we don't access the stack variable after we return from this function.
884 if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:sdRef: CallbackwithError morebytes zero sdr %p", sdr); return;}
885 else {sdr->moreptr = NULL;}
886 sdr = sdrNext;
889 #endif // _DNS_SD_LIBDISPATCH
891 // Handle reply from server, calling application client callback. If there is no reply
892 // from the daemon on the socket contained in sdRef, the call will block.
893 DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
895 int morebytes = 0;
897 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
899 if (!DNSServiceRefValid(sdRef))
901 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
902 return kDNSServiceErr_BadReference;
905 if (sdRef->primary)
907 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
908 return kDNSServiceErr_BadReference;
911 if (!sdRef->ProcessReply)
913 static int num_logs = 0;
914 if (num_logs < 10) syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function");
915 if (num_logs < 1000) num_logs++;else sleep(1);
916 return kDNSServiceErr_BadReference;
921 CallbackHeader cbh;
922 char *data;
924 // return NoError on EWOULDBLOCK. This will handle the case
925 // where a non-blocking socket is told there is data, but it was a false positive.
926 // On error, read_all will write a message to syslog for us, so don't need to duplicate that here
927 // Note: If we want to properly support using non-blocking sockets in the future
928 int result = read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr));
929 if (result == read_all_fail)
931 // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
932 // in the callback.
933 sdRef->ProcessReply = NULL;
934 #if _DNS_SD_LIBDISPATCH
935 // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
936 // is not called by the application and hence need to communicate the error. Cancel the
937 // source so that we don't get any more events
938 // Note: read_all fails if we could not read from the daemon which can happen if the
939 // daemon dies or the file descriptor is disconnected (defunct).
940 if (sdRef->disp_source)
942 dispatch_source_cancel(sdRef->disp_source);
943 dispatch_release(sdRef->disp_source);
944 sdRef->disp_source = NULL;
945 CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
947 #endif
948 // Don't touch sdRef anymore as it might have been deallocated
949 return kDNSServiceErr_ServiceNotRunning;
951 else if (result == read_all_wouldblock)
953 if (morebytes && sdRef->logcounter < 100)
955 sdRef->logcounter++;
956 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult error: select indicated data was waiting but read_all returned EWOULDBLOCK");
958 return kDNSServiceErr_NoError;
961 ConvertHeaderBytes(&cbh.ipc_hdr);
962 if (cbh.ipc_hdr.version != VERSION)
964 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult daemon version %d does not match client version %d", cbh.ipc_hdr.version, VERSION);
965 sdRef->ProcessReply = NULL;
966 return kDNSServiceErr_Incompatible;
969 data = malloc(cbh.ipc_hdr.datalen);
970 if (!data) return kDNSServiceErr_NoMemory;
971 if (read_all(sdRef->sockfd, data, cbh.ipc_hdr.datalen) < 0) // On error, read_all will write a message to syslog for us
973 // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
974 // in the callback.
975 sdRef->ProcessReply = NULL;
976 #if _DNS_SD_LIBDISPATCH
977 // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
978 // is not called by the application and hence need to communicate the error. Cancel the
979 // source so that we don't get any more events
980 if (sdRef->disp_source)
982 dispatch_source_cancel(sdRef->disp_source);
983 dispatch_release(sdRef->disp_source);
984 sdRef->disp_source = NULL;
985 CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
987 #endif
988 // Don't touch sdRef anymore as it might have been deallocated
989 free(data);
990 return kDNSServiceErr_ServiceNotRunning;
992 else
994 const char *ptr = data;
995 cbh.cb_flags = get_flags (&ptr, data + cbh.ipc_hdr.datalen);
996 cbh.cb_interface = get_uint32 (&ptr, data + cbh.ipc_hdr.datalen);
997 cbh.cb_err = get_error_code(&ptr, data + cbh.ipc_hdr.datalen);
999 // CAUTION: We have to handle the case where the client calls DNSServiceRefDeallocate from within the callback function.
1000 // To do this we set moreptr to point to morebytes. If the client does call DNSServiceRefDeallocate(),
1001 // then that routine will clear morebytes for us, and cause us to exit our loop.
1002 morebytes = more_bytes(sdRef->sockfd);
1003 if (morebytes)
1005 cbh.cb_flags |= kDNSServiceFlagsMoreComing;
1006 sdRef->moreptr = &morebytes;
1008 if (ptr) sdRef->ProcessReply(sdRef, &cbh, ptr, data + cbh.ipc_hdr.datalen);
1009 // Careful code here:
1010 // If morebytes is non-zero, that means we set sdRef->moreptr above, and the operation was not
1011 // cancelled out from under us, so now we need to clear sdRef->moreptr so we don't leave a stray
1012 // dangling pointer pointing to a long-gone stack variable.
1013 // If morebytes is zero, then one of two thing happened:
1014 // (a) morebytes was 0 above, so we didn't set sdRef->moreptr, so we don't need to clear it
1015 // (b) morebytes was 1 above, and we set sdRef->moreptr, but the operation was cancelled (with DNSServiceRefDeallocate()),
1016 // so we MUST NOT try to dereference our stale sdRef pointer.
1017 if (morebytes) sdRef->moreptr = NULL;
1019 free(data);
1020 } while (morebytes);
1022 return kDNSServiceErr_NoError;
1025 void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef)
1027 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with NULL DNSServiceRef"); return; }
1029 if (!DNSServiceRefValid(sdRef)) // Also verifies dnssd_SocketValid(sdRef->sockfd) for us too
1031 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
1032 return;
1035 // 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
1036 if (sdRef->moreptr) *(sdRef->moreptr) = 0;
1038 if (sdRef->primary) // If this is a subordinate DNSServiceOp, just send a 'stop' command
1040 DNSServiceOp **p = &sdRef->primary->next;
1041 while (*p && *p != sdRef) p = &(*p)->next;
1042 if (*p)
1044 char *ptr;
1045 size_t len = 0;
1046 ipc_msg_hdr *hdr = create_hdr(cancel_request, &len, &ptr, 0, sdRef);
1047 if (hdr)
1049 ConvertHeaderBytes(hdr);
1050 write_all(sdRef->sockfd, (char *)hdr, len);
1051 free(hdr);
1053 *p = sdRef->next;
1054 FreeDNSServiceOp(sdRef);
1057 else // else, make sure to terminate all subordinates as well
1059 #if _DNS_SD_LIBDISPATCH
1060 // The cancel handler will close the fd if a dispatch source has been set
1061 if (sdRef->disp_source)
1063 // By setting the ProcessReply to NULL, we make sure that we never call
1064 // the application callbacks ever, after returning from this function. We
1065 // assume that DNSServiceRefDeallocate is called from the serial queue
1066 // that was passed to DNSServiceSetDispatchQueue. Hence, dispatch_source_cancel
1067 // should cancel all the blocks on the queue and hence there should be no more
1068 // callbacks when we return from this function. Setting ProcessReply to NULL
1069 // provides extra protection.
1070 sdRef->ProcessReply = NULL;
1071 dispatch_source_cancel(sdRef->disp_source);
1072 dispatch_release(sdRef->disp_source);
1073 sdRef->disp_source = NULL;
1075 // if disp_queue is set, it means it used the DNSServiceSetDispatchQueue API. In that case,
1076 // when the source was cancelled, the fd was closed in the handler. Currently the source
1077 // is cancelled only when the mDNSResponder daemon dies
1078 else if (!sdRef->disp_queue) dnssd_close(sdRef->sockfd);
1079 #else
1080 dnssd_close(sdRef->sockfd);
1081 #endif
1082 // Free DNSRecords added in DNSRegisterRecord if they have not
1083 // been freed in DNSRemoveRecord
1084 while (sdRef)
1086 DNSServiceOp *p = sdRef;
1087 sdRef = sdRef->next;
1088 // When there is an error reading from the daemon e.g., bad fd, CallbackWithError
1089 // is called which sets moreptr. It might set the moreptr on a subordinate sdRef
1090 // but the application might call DNSServiceRefDeallocate with the main sdRef from
1091 // the callback. Hence, when we loop through the subordinate sdRefs, we need
1092 // to clear the moreptr so that CallbackWithError can terminate itself instead of
1093 // walking through the freed sdRefs.
1094 if (p->moreptr) *(p->moreptr) = 0;
1095 FreeDNSServiceOp(p);
1100 DNSServiceErrorType DNSSD_API DNSServiceGetProperty(const char *property, void *result, uint32_t *size)
1102 char *ptr;
1103 size_t len = strlen(property) + 1;
1104 ipc_msg_hdr *hdr;
1105 DNSServiceOp *tmp;
1106 uint32_t actualsize;
1108 DNSServiceErrorType err = ConnectToServer(&tmp, 0, getproperty_request, NULL, NULL, NULL);
1109 if (err) return err;
1111 hdr = create_hdr(getproperty_request, &len, &ptr, 0, tmp);
1112 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
1114 put_string(property, &ptr);
1115 err = deliver_request(hdr, tmp); // Will free hdr for us
1116 if (read_all(tmp->sockfd, (char*)&actualsize, (int)sizeof(actualsize)) < 0)
1117 { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
1119 actualsize = ntohl(actualsize);
1120 if (read_all(tmp->sockfd, (char*)result, actualsize < *size ? actualsize : *size) < 0)
1121 { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
1122 DNSServiceRefDeallocate(tmp);
1124 // Swap version result back to local process byte order
1125 if (!strcmp(property, kDNSServiceProperty_DaemonVersion) && *size >= 4)
1126 *(uint32_t*)result = ntohl(*(uint32_t*)result);
1128 *size = actualsize;
1129 return kDNSServiceErr_NoError;
1132 static void handle_resolve_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *end)
1134 char fullname[kDNSServiceMaxDomainName];
1135 char target[kDNSServiceMaxDomainName];
1136 uint16_t txtlen;
1137 union { uint16_t s; u_char b[2]; } port;
1138 unsigned char *txtrecord;
1140 get_string(&data, end, fullname, kDNSServiceMaxDomainName);
1141 get_string(&data, end, target, kDNSServiceMaxDomainName);
1142 if (!data || data + 2 > end) goto fail;
1144 port.b[0] = *data++;
1145 port.b[1] = *data++;
1146 txtlen = get_uint16(&data, end);
1147 txtrecord = (unsigned char *)get_rdata(&data, end, txtlen);
1149 if (!data) goto fail;
1150 ((DNSServiceResolveReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, fullname, target, port.s, txtlen, txtrecord, sdr->AppContext);
1151 return;
1152 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1153 fail:
1154 syslog(LOG_WARNING, "dnssd_clientstub handle_resolve_response: error reading result from daemon");
1157 #if APPLE_OSX_mDNSResponder
1159 static int32_t libSystemVersion = 0;
1161 // Return true if the application linked against a version of libsystem where P2P
1162 // interfaces were included by default when using kDNSServiceInterfaceIndexAny.
1163 // Using 160.0.0 == 0xa00000 as the version threshold.
1164 static int includeP2PWithIndexAny()
1166 if (libSystemVersion == 0)
1167 libSystemVersion = NSVersionOfLinkTimeLibrary("System");
1169 if (libSystemVersion < 0xa00000)
1170 return 1;
1171 else
1172 return 0;
1175 #else // APPLE_OSX_mDNSResponder
1177 // always return false for non Apple platforms
1178 static int includeP2PWithIndexAny()
1180 return 0;
1183 #endif // APPLE_OSX_mDNSResponder
1185 DNSServiceErrorType DNSSD_API DNSServiceResolve
1187 DNSServiceRef *sdRef,
1188 DNSServiceFlags flags,
1189 uint32_t interfaceIndex,
1190 const char *name,
1191 const char *regtype,
1192 const char *domain,
1193 DNSServiceResolveReply callBack,
1194 void *context
1197 char *ptr;
1198 size_t len;
1199 ipc_msg_hdr *hdr;
1200 DNSServiceErrorType err;
1202 if (!name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam;
1204 // Need a real InterfaceID for WakeOnResolve
1205 if ((flags & kDNSServiceFlagsWakeOnResolve) != 0 &&
1206 ((interfaceIndex == kDNSServiceInterfaceIndexAny) ||
1207 (interfaceIndex == kDNSServiceInterfaceIndexLocalOnly) ||
1208 (interfaceIndex == kDNSServiceInterfaceIndexUnicast) ||
1209 (interfaceIndex == kDNSServiceInterfaceIndexP2P)))
1211 return kDNSServiceErr_BadParam;
1214 if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
1215 flags |= kDNSServiceFlagsIncludeP2P;
1217 err = ConnectToServer(sdRef, flags, resolve_request, handle_resolve_response, callBack, context);
1218 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1220 // Calculate total message length
1221 len = sizeof(flags);
1222 len += sizeof(interfaceIndex);
1223 len += strlen(name) + 1;
1224 len += strlen(regtype) + 1;
1225 len += strlen(domain) + 1;
1227 hdr = create_hdr(resolve_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1228 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1230 put_flags(flags, &ptr);
1231 put_uint32(interfaceIndex, &ptr);
1232 put_string(name, &ptr);
1233 put_string(regtype, &ptr);
1234 put_string(domain, &ptr);
1236 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1237 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1238 return err;
1241 static void handle_query_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
1243 uint32_t ttl;
1244 char name[kDNSServiceMaxDomainName];
1245 uint16_t rrtype, rrclass, rdlen;
1246 const char *rdata;
1248 get_string(&data, end, name, kDNSServiceMaxDomainName);
1249 rrtype = get_uint16(&data, end);
1250 rrclass = get_uint16(&data, end);
1251 rdlen = get_uint16(&data, end);
1252 rdata = get_rdata(&data, end, rdlen);
1253 ttl = get_uint32(&data, end);
1255 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_query_response: error reading result from daemon");
1256 else ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, name, rrtype, rrclass, rdlen, rdata, ttl, sdr->AppContext);
1257 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1260 DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
1262 DNSServiceRef *sdRef,
1263 DNSServiceFlags flags,
1264 uint32_t interfaceIndex,
1265 const char *name,
1266 uint16_t rrtype,
1267 uint16_t rrclass,
1268 DNSServiceQueryRecordReply callBack,
1269 void *context
1272 char *ptr;
1273 size_t len;
1274 ipc_msg_hdr *hdr;
1275 DNSServiceErrorType err;
1277 if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
1278 flags |= kDNSServiceFlagsIncludeP2P;
1280 err = ConnectToServer(sdRef, flags, query_request, handle_query_response, callBack, context);
1281 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1283 if (!name) name = "\0";
1285 // Calculate total message length
1286 len = sizeof(flags);
1287 len += sizeof(uint32_t); // interfaceIndex
1288 len += strlen(name) + 1;
1289 len += 2 * sizeof(uint16_t); // rrtype, rrclass
1291 hdr = create_hdr(query_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1292 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1294 put_flags(flags, &ptr);
1295 put_uint32(interfaceIndex, &ptr);
1296 put_string(name, &ptr);
1297 put_uint16(rrtype, &ptr);
1298 put_uint16(rrclass, &ptr);
1300 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1301 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1302 return err;
1305 static void handle_addrinfo_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
1307 char hostname[kDNSServiceMaxDomainName];
1308 uint16_t rrtype, rrclass, rdlen;
1309 const char *rdata;
1310 uint32_t ttl;
1312 get_string(&data, end, hostname, kDNSServiceMaxDomainName);
1313 rrtype = get_uint16(&data, end);
1314 rrclass = get_uint16(&data, end);
1315 rdlen = get_uint16(&data, end);
1316 rdata = get_rdata (&data, end, rdlen);
1317 ttl = get_uint32(&data, end);
1319 // We only generate client callbacks for A and AAAA results (including NXDOMAIN results for
1320 // those types, if the client has requested those with the kDNSServiceFlagsReturnIntermediates).
1321 // Other result types, specifically CNAME referrals, are not communicated to the client, because
1322 // the DNSServiceGetAddrInfoReply interface doesn't have any meaningful way to communiate CNAME referrals.
1323 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_addrinfo_response: error reading result from daemon");
1324 else if (rrtype == kDNSServiceType_A || rrtype == kDNSServiceType_AAAA)
1326 struct sockaddr_in sa4;
1327 struct sockaddr_in6 sa6;
1328 const struct sockaddr *const sa = (rrtype == kDNSServiceType_A) ? (struct sockaddr*)&sa4 : (struct sockaddr*)&sa6;
1329 if (rrtype == kDNSServiceType_A)
1331 memset(&sa4, 0, sizeof(sa4));
1332 #ifndef NOT_HAVE_SA_LEN
1333 sa4.sin_len = sizeof(struct sockaddr_in);
1334 #endif
1335 sa4.sin_family = AF_INET;
1336 // sin_port = 0;
1337 if (!cbh->cb_err) memcpy(&sa4.sin_addr, rdata, rdlen);
1339 else
1341 memset(&sa6, 0, sizeof(sa6));
1342 #ifndef NOT_HAVE_SA_LEN
1343 sa6.sin6_len = sizeof(struct sockaddr_in6);
1344 #endif
1345 sa6.sin6_family = AF_INET6;
1346 // sin6_port = 0;
1347 // sin6_flowinfo = 0;
1348 // sin6_scope_id = 0;
1349 if (!cbh->cb_err)
1351 memcpy(&sa6.sin6_addr, rdata, rdlen);
1352 if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr)) sa6.sin6_scope_id = cbh->cb_interface;
1355 ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, sa, ttl, sdr->AppContext);
1356 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1360 DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
1362 DNSServiceRef *sdRef,
1363 DNSServiceFlags flags,
1364 uint32_t interfaceIndex,
1365 uint32_t protocol,
1366 const char *hostname,
1367 DNSServiceGetAddrInfoReply callBack,
1368 void *context /* may be NULL */
1371 char *ptr;
1372 size_t len;
1373 ipc_msg_hdr *hdr;
1374 DNSServiceErrorType err;
1376 if (!hostname) return kDNSServiceErr_BadParam;
1378 err = ConnectToServer(sdRef, flags, addrinfo_request, handle_addrinfo_response, callBack, context);
1379 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1381 // Calculate total message length
1382 len = sizeof(flags);
1383 len += sizeof(uint32_t); // interfaceIndex
1384 len += sizeof(uint32_t); // protocol
1385 len += strlen(hostname) + 1;
1387 hdr = create_hdr(addrinfo_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1388 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1390 put_flags(flags, &ptr);
1391 put_uint32(interfaceIndex, &ptr);
1392 put_uint32(protocol, &ptr);
1393 put_string(hostname, &ptr);
1395 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1396 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1397 return err;
1400 static void handle_browse_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
1402 char replyName[256], replyType[kDNSServiceMaxDomainName], replyDomain[kDNSServiceMaxDomainName];
1403 get_string(&data, end, replyName, 256);
1404 get_string(&data, end, replyType, kDNSServiceMaxDomainName);
1405 get_string(&data, end, replyDomain, kDNSServiceMaxDomainName);
1406 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_browse_response: error reading result from daemon");
1407 else ((DNSServiceBrowseReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, replyName, replyType, replyDomain, sdr->AppContext);
1408 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1411 DNSServiceErrorType DNSSD_API DNSServiceBrowse
1413 DNSServiceRef *sdRef,
1414 DNSServiceFlags flags,
1415 uint32_t interfaceIndex,
1416 const char *regtype,
1417 const char *domain,
1418 DNSServiceBrowseReply callBack,
1419 void *context
1422 char *ptr;
1423 size_t len;
1424 ipc_msg_hdr *hdr;
1425 DNSServiceErrorType err;
1427 if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
1428 flags |= kDNSServiceFlagsIncludeP2P;
1430 err = ConnectToServer(sdRef, flags, browse_request, handle_browse_response, callBack, context);
1431 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1433 if (!domain) domain = "";
1434 len = sizeof(flags);
1435 len += sizeof(interfaceIndex);
1436 len += strlen(regtype) + 1;
1437 len += strlen(domain) + 1;
1439 hdr = create_hdr(browse_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1440 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1442 put_flags(flags, &ptr);
1443 put_uint32(interfaceIndex, &ptr);
1444 put_string(regtype, &ptr);
1445 put_string(domain, &ptr);
1447 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1448 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1449 return err;
1452 DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain);
1453 DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain)
1455 DNSServiceOp *tmp;
1456 char *ptr;
1457 size_t len = sizeof(flags) + strlen(domain) + 1;
1458 ipc_msg_hdr *hdr;
1459 DNSServiceErrorType err = ConnectToServer(&tmp, 0, setdomain_request, NULL, NULL, NULL);
1460 if (err) return err;
1462 hdr = create_hdr(setdomain_request, &len, &ptr, 0, tmp);
1463 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
1465 put_flags(flags, &ptr);
1466 put_string(domain, &ptr);
1467 err = deliver_request(hdr, tmp); // Will free hdr for us
1468 DNSServiceRefDeallocate(tmp);
1469 return err;
1472 static void handle_regservice_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
1474 char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
1475 get_string(&data, end, name, 256);
1476 get_string(&data, end, regtype, kDNSServiceMaxDomainName);
1477 get_string(&data, end, domain, kDNSServiceMaxDomainName);
1478 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_regservice_response: error reading result from daemon");
1479 else ((DNSServiceRegisterReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_err, name, regtype, domain, sdr->AppContext);
1480 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1483 DNSServiceErrorType DNSSD_API DNSServiceRegister
1485 DNSServiceRef *sdRef,
1486 DNSServiceFlags flags,
1487 uint32_t interfaceIndex,
1488 const char *name,
1489 const char *regtype,
1490 const char *domain,
1491 const char *host,
1492 uint16_t PortInNetworkByteOrder,
1493 uint16_t txtLen,
1494 const void *txtRecord,
1495 DNSServiceRegisterReply callBack,
1496 void *context
1499 char *ptr;
1500 size_t len;
1501 ipc_msg_hdr *hdr;
1502 DNSServiceErrorType err;
1503 union { uint16_t s; u_char b[2]; } port;
1505 port.s = PortInNetworkByteOrder;
1507 if (!name) name = "";
1508 if (!regtype) return kDNSServiceErr_BadParam;
1509 if (!domain) domain = "";
1510 if (!host) host = "";
1511 if (!txtRecord) txtRecord = (void*)"";
1513 // No callback must have auto-rename
1514 if (!callBack && (flags & kDNSServiceFlagsNoAutoRename)) return kDNSServiceErr_BadParam;
1516 if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
1517 flags |= kDNSServiceFlagsIncludeP2P;
1519 err = ConnectToServer(sdRef, flags, reg_service_request, callBack ? handle_regservice_response : NULL, callBack, context);
1520 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1522 len = sizeof(DNSServiceFlags);
1523 len += sizeof(uint32_t); // interfaceIndex
1524 len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4;
1525 len += 2 * sizeof(uint16_t); // port, txtLen
1526 len += txtLen;
1528 hdr = create_hdr(reg_service_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1529 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1531 // If it is going over a shared connection, then don't set the IPC_FLAGS_NOREPLY
1532 // as it affects all the operations over the shared connection. This is not
1533 // a normal case and hence receiving the response back from the daemon and
1534 // discarding it in ConnectionResponse is okay.
1536 if (!(flags & kDNSServiceFlagsShareConnection) && !callBack) hdr->ipc_flags |= IPC_FLAGS_NOREPLY;
1538 put_flags(flags, &ptr);
1539 put_uint32(interfaceIndex, &ptr);
1540 put_string(name, &ptr);
1541 put_string(regtype, &ptr);
1542 put_string(domain, &ptr);
1543 put_string(host, &ptr);
1544 *ptr++ = port.b[0];
1545 *ptr++ = port.b[1];
1546 put_uint16(txtLen, &ptr);
1547 put_rdata(txtLen, txtRecord, &ptr);
1549 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1550 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1551 return err;
1554 static void handle_enumeration_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
1556 char domain[kDNSServiceMaxDomainName];
1557 get_string(&data, end, domain, kDNSServiceMaxDomainName);
1558 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_enumeration_response: error reading result from daemon");
1559 else ((DNSServiceDomainEnumReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, domain, sdr->AppContext);
1560 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1563 DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
1565 DNSServiceRef *sdRef,
1566 DNSServiceFlags flags,
1567 uint32_t interfaceIndex,
1568 DNSServiceDomainEnumReply callBack,
1569 void *context
1572 char *ptr;
1573 size_t len;
1574 ipc_msg_hdr *hdr;
1575 DNSServiceErrorType err;
1577 int f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0;
1578 int f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0;
1579 if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
1581 err = ConnectToServer(sdRef, flags, enumeration_request, handle_enumeration_response, callBack, context);
1582 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1584 len = sizeof(DNSServiceFlags);
1585 len += sizeof(uint32_t);
1587 hdr = create_hdr(enumeration_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1588 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1590 put_flags(flags, &ptr);
1591 put_uint32(interfaceIndex, &ptr);
1593 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1594 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1595 return err;
1598 static void ConnectionResponse(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *const data, const char *const end)
1600 (void)data; // Unused
1602 //printf("ConnectionResponse got %d\n", cbh->ipc_hdr.op);
1603 if (cbh->ipc_hdr.op != reg_record_reply_op)
1605 // When using kDNSServiceFlagsShareConnection, need to search the list of associated DNSServiceOps
1606 // to find the one this response is intended for, and then call through to its ProcessReply handler.
1607 // We start with our first subordinate DNSServiceRef -- don't want to accidentally match the parent DNSServiceRef.
1608 DNSServiceOp *op = sdr->next;
1609 while (op && (op->uid.u32[0] != cbh->ipc_hdr.client_context.u32[0] || op->uid.u32[1] != cbh->ipc_hdr.client_context.u32[1]))
1610 op = op->next;
1611 // Note: We may sometimes not find a matching DNSServiceOp, in the case where the client has
1612 // cancelled the subordinate DNSServiceOp, but there are still messages in the pipeline from the daemon
1613 if (op && op->ProcessReply) op->ProcessReply(op, cbh, data, end);
1614 // WARNING: Don't touch op or sdr after this -- client may have called DNSServiceRefDeallocate
1615 return;
1617 else
1619 DNSRecordRef rec;
1620 for (rec = sdr->rec; rec; rec = rec->recnext)
1622 if (rec->uid.u32[0] == cbh->ipc_hdr.client_context.u32[0] && rec->uid.u32[1] == cbh->ipc_hdr.client_context.u32[1])
1623 break;
1625 // The record might have been freed already and hence not an
1626 // error if the record is not found.
1627 if (!rec)
1629 syslog(LOG_INFO, "ConnectionResponse: Record not found");
1630 return;
1632 if (rec->sdr != sdr)
1634 syslog(LOG_WARNING, "ConnectionResponse: Record sdr mismatch: rec %p sdr %p", rec->sdr, sdr);
1635 return;
1638 if (sdr->op == connection_request)
1640 rec->AppCallback(rec->sdr, rec, cbh->cb_flags, cbh->cb_err, rec->AppContext);
1642 else
1644 syslog(LOG_WARNING, "dnssd_clientstub ConnectionResponse: sdr->op != connection_request");
1645 rec->AppCallback(rec->sdr, rec, 0, kDNSServiceErr_Unknown, rec->AppContext);
1647 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1651 DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef)
1653 char *ptr;
1654 size_t len = 0;
1655 ipc_msg_hdr *hdr;
1656 DNSServiceErrorType err = ConnectToServer(sdRef, 0, connection_request, ConnectionResponse, NULL, NULL);
1657 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1659 hdr = create_hdr(connection_request, &len, &ptr, 0, *sdRef);
1660 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1662 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1663 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1664 return err;
1667 DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
1669 DNSServiceRef sdRef,
1670 DNSRecordRef *RecordRef,
1671 DNSServiceFlags flags,
1672 uint32_t interfaceIndex,
1673 const char *fullname,
1674 uint16_t rrtype,
1675 uint16_t rrclass,
1676 uint16_t rdlen,
1677 const void *rdata,
1678 uint32_t ttl,
1679 DNSServiceRegisterRecordReply callBack,
1680 void *context
1683 char *ptr;
1684 size_t len;
1685 ipc_msg_hdr *hdr = NULL;
1686 DNSRecordRef rref = NULL;
1687 DNSRecord **p;
1688 int f1 = (flags & kDNSServiceFlagsShared) != 0;
1689 int f2 = (flags & kDNSServiceFlagsUnique) != 0;
1690 if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
1692 if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
1693 flags |= kDNSServiceFlagsIncludeP2P;
1695 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
1697 if (!DNSServiceRefValid(sdRef))
1699 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
1700 return kDNSServiceErr_BadReference;
1703 if (sdRef->op != connection_request)
1705 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with non-DNSServiceCreateConnection DNSServiceRef %p %d", sdRef, sdRef->op);
1706 return kDNSServiceErr_BadReference;
1709 *RecordRef = NULL;
1711 len = sizeof(DNSServiceFlags);
1712 len += 2 * sizeof(uint32_t); // interfaceIndex, ttl
1713 len += 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen
1714 len += strlen(fullname) + 1;
1715 len += rdlen;
1717 // Bump up the uid. Normally for shared operations (kDNSServiceFlagsShareConnection), this
1718 // is done in ConnectToServer. For DNSServiceRegisterRecord, ConnectToServer has already
1719 // been called. As multiple DNSServiceRegisterRecords can be multiplexed over a single
1720 // connection, we need a way to demultiplex the response so that the callback corresponding
1721 // to the right DNSServiceRegisterRecord instance can be called. Use the same mechanism that
1722 // is used by kDNSServiceFlagsShareConnection. create_hdr copies the uid value to ipc
1723 // hdr->client_context which will be returned in the ipc response.
1724 if (++sdRef->uid.u32[0] == 0)
1725 ++sdRef->uid.u32[1];
1726 hdr = create_hdr(reg_record_request, &len, &ptr, 1, sdRef);
1727 if (!hdr) return kDNSServiceErr_NoMemory;
1729 put_flags(flags, &ptr);
1730 put_uint32(interfaceIndex, &ptr);
1731 put_string(fullname, &ptr);
1732 put_uint16(rrtype, &ptr);
1733 put_uint16(rrclass, &ptr);
1734 put_uint16(rdlen, &ptr);
1735 put_rdata(rdlen, rdata, &ptr);
1736 put_uint32(ttl, &ptr);
1738 rref = malloc(sizeof(DNSRecord));
1739 if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; }
1740 rref->AppContext = context;
1741 rref->AppCallback = callBack;
1742 rref->record_index = sdRef->max_index++;
1743 rref->sdr = sdRef;
1744 rref->recnext = NULL;
1745 *RecordRef = rref;
1746 // Remember the uid that we are sending across so that we can match
1747 // when the response comes back.
1748 rref->uid = sdRef->uid;
1749 hdr->reg_index = rref->record_index;
1751 p = &(sdRef)->rec;
1752 while (*p) p = &(*p)->recnext;
1753 *p = rref;
1755 return deliver_request(hdr, sdRef); // Will free hdr for us
1758 // sdRef returned by DNSServiceRegister()
1759 DNSServiceErrorType DNSSD_API DNSServiceAddRecord
1761 DNSServiceRef sdRef,
1762 DNSRecordRef *RecordRef,
1763 DNSServiceFlags flags,
1764 uint16_t rrtype,
1765 uint16_t rdlen,
1766 const void *rdata,
1767 uint32_t ttl
1770 ipc_msg_hdr *hdr;
1771 size_t len = 0;
1772 char *ptr;
1773 DNSRecordRef rref;
1774 DNSRecord **p;
1776 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
1777 if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSRecordRef pointer"); return kDNSServiceErr_BadParam; }
1778 if (sdRef->op != reg_service_request)
1780 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with non-DNSServiceRegister DNSServiceRef %p %d", sdRef, sdRef->op);
1781 return kDNSServiceErr_BadReference;
1784 if (!DNSServiceRefValid(sdRef))
1786 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
1787 return kDNSServiceErr_BadReference;
1790 *RecordRef = NULL;
1792 len += 2 * sizeof(uint16_t); // rrtype, rdlen
1793 len += rdlen;
1794 len += sizeof(uint32_t);
1795 len += sizeof(DNSServiceFlags);
1797 hdr = create_hdr(add_record_request, &len, &ptr, 1, sdRef);
1798 if (!hdr) return kDNSServiceErr_NoMemory;
1799 put_flags(flags, &ptr);
1800 put_uint16(rrtype, &ptr);
1801 put_uint16(rdlen, &ptr);
1802 put_rdata(rdlen, rdata, &ptr);
1803 put_uint32(ttl, &ptr);
1805 rref = malloc(sizeof(DNSRecord));
1806 if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; }
1807 rref->AppContext = NULL;
1808 rref->AppCallback = NULL;
1809 rref->record_index = sdRef->max_index++;
1810 rref->sdr = sdRef;
1811 rref->recnext = NULL;
1812 *RecordRef = rref;
1813 hdr->reg_index = rref->record_index;
1815 p = &(sdRef)->rec;
1816 while (*p) p = &(*p)->recnext;
1817 *p = rref;
1819 return deliver_request(hdr, sdRef); // Will free hdr for us
1822 // DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
1823 DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
1825 DNSServiceRef sdRef,
1826 DNSRecordRef RecordRef,
1827 DNSServiceFlags flags,
1828 uint16_t rdlen,
1829 const void *rdata,
1830 uint32_t ttl
1833 ipc_msg_hdr *hdr;
1834 size_t len = 0;
1835 char *ptr;
1837 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
1839 if (!DNSServiceRefValid(sdRef))
1841 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
1842 return kDNSServiceErr_BadReference;
1845 // Note: RecordRef is allowed to be NULL
1847 len += sizeof(uint16_t);
1848 len += rdlen;
1849 len += sizeof(uint32_t);
1850 len += sizeof(DNSServiceFlags);
1852 hdr = create_hdr(update_record_request, &len, &ptr, 1, sdRef);
1853 if (!hdr) return kDNSServiceErr_NoMemory;
1854 hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX;
1855 put_flags(flags, &ptr);
1856 put_uint16(rdlen, &ptr);
1857 put_rdata(rdlen, rdata, &ptr);
1858 put_uint32(ttl, &ptr);
1859 return deliver_request(hdr, sdRef); // Will free hdr for us
1862 DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
1864 DNSServiceRef sdRef,
1865 DNSRecordRef RecordRef,
1866 DNSServiceFlags flags
1869 ipc_msg_hdr *hdr;
1870 size_t len = 0;
1871 char *ptr;
1872 DNSServiceErrorType err;
1874 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
1875 if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSRecordRef"); return kDNSServiceErr_BadParam; }
1876 if (!sdRef->max_index) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with bad DNSServiceRef"); return kDNSServiceErr_BadReference; }
1878 if (!DNSServiceRefValid(sdRef))
1880 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
1881 return kDNSServiceErr_BadReference;
1884 len += sizeof(flags);
1885 hdr = create_hdr(remove_record_request, &len, &ptr, 1, sdRef);
1886 if (!hdr) return kDNSServiceErr_NoMemory;
1887 hdr->reg_index = RecordRef->record_index;
1888 put_flags(flags, &ptr);
1889 err = deliver_request(hdr, sdRef); // Will free hdr for us
1890 if (!err)
1892 // This RecordRef could have been allocated in DNSServiceRegisterRecord or DNSServiceAddRecord.
1893 // If so, delink from the list before freeing
1894 DNSRecord **p = &sdRef->rec;
1895 while (*p && *p != RecordRef) p = &(*p)->recnext;
1896 if (*p) *p = RecordRef->recnext;
1897 free(RecordRef);
1899 return err;
1902 DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
1904 DNSServiceFlags flags,
1905 uint32_t interfaceIndex,
1906 const char *fullname,
1907 uint16_t rrtype,
1908 uint16_t rrclass,
1909 uint16_t rdlen,
1910 const void *rdata
1913 char *ptr;
1914 size_t len;
1915 ipc_msg_hdr *hdr;
1916 DNSServiceOp *tmp;
1918 DNSServiceErrorType err = ConnectToServer(&tmp, flags, reconfirm_record_request, NULL, NULL, NULL);
1919 if (err) return err;
1921 len = sizeof(DNSServiceFlags);
1922 len += sizeof(uint32_t);
1923 len += strlen(fullname) + 1;
1924 len += 3 * sizeof(uint16_t);
1925 len += rdlen;
1926 hdr = create_hdr(reconfirm_record_request, &len, &ptr, 0, tmp);
1927 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
1929 put_flags(flags, &ptr);
1930 put_uint32(interfaceIndex, &ptr);
1931 put_string(fullname, &ptr);
1932 put_uint16(rrtype, &ptr);
1933 put_uint16(rrclass, &ptr);
1934 put_uint16(rdlen, &ptr);
1935 put_rdata(rdlen, rdata, &ptr);
1937 err = deliver_request(hdr, tmp); // Will free hdr for us
1938 DNSServiceRefDeallocate(tmp);
1939 return err;
1942 static void handle_port_mapping_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
1944 union { uint32_t l; u_char b[4]; } addr;
1945 uint8_t protocol;
1946 union { uint16_t s; u_char b[2]; } internalPort;
1947 union { uint16_t s; u_char b[2]; } externalPort;
1948 uint32_t ttl;
1950 if (!data || data + 13 > end) goto fail;
1952 addr.b[0] = *data++;
1953 addr.b[1] = *data++;
1954 addr.b[2] = *data++;
1955 addr.b[3] = *data++;
1956 protocol = *data++;
1957 internalPort.b[0] = *data++;
1958 internalPort.b[1] = *data++;
1959 externalPort.b[0] = *data++;
1960 externalPort.b[1] = *data++;
1961 ttl = get_uint32(&data, end);
1962 if (!data) goto fail;
1964 ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, addr.l, protocol, internalPort.s, externalPort.s, ttl, sdr->AppContext);
1965 return;
1966 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1968 fail :
1969 syslog(LOG_WARNING, "dnssd_clientstub handle_port_mapping_response: error reading result from daemon");
1972 DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
1974 DNSServiceRef *sdRef,
1975 DNSServiceFlags flags,
1976 uint32_t interfaceIndex,
1977 uint32_t protocol, /* TCP and/or UDP */
1978 uint16_t internalPortInNetworkByteOrder,
1979 uint16_t externalPortInNetworkByteOrder,
1980 uint32_t ttl, /* time to live in seconds */
1981 DNSServiceNATPortMappingReply callBack,
1982 void *context /* may be NULL */
1985 char *ptr;
1986 size_t len;
1987 ipc_msg_hdr *hdr;
1988 union { uint16_t s; u_char b[2]; } internalPort;
1989 union { uint16_t s; u_char b[2]; } externalPort;
1991 DNSServiceErrorType err = ConnectToServer(sdRef, flags, port_mapping_request, handle_port_mapping_response, callBack, context);
1992 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1994 internalPort.s = internalPortInNetworkByteOrder;
1995 externalPort.s = externalPortInNetworkByteOrder;
1997 len = sizeof(flags);
1998 len += sizeof(interfaceIndex);
1999 len += sizeof(protocol);
2000 len += sizeof(internalPort);
2001 len += sizeof(externalPort);
2002 len += sizeof(ttl);
2004 hdr = create_hdr(port_mapping_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
2005 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
2007 put_flags(flags, &ptr);
2008 put_uint32(interfaceIndex, &ptr);
2009 put_uint32(protocol, &ptr);
2010 *ptr++ = internalPort.b[0];
2011 *ptr++ = internalPort.b[1];
2012 *ptr++ = externalPort.b[0];
2013 *ptr++ = externalPort.b[1];
2014 put_uint32(ttl, &ptr);
2016 err = deliver_request(hdr, *sdRef); // Will free hdr for us
2017 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
2018 return err;
2021 #if _DNS_SD_LIBDISPATCH
2022 DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue
2024 DNSServiceRef service,
2025 dispatch_queue_t queue
2028 int dnssd_fd = DNSServiceRefSockFD(service);
2029 if (dnssd_fd == dnssd_InvalidSocket) return kDNSServiceErr_BadParam;
2030 if (!queue)
2032 syslog(LOG_WARNING, "dnssd_clientstub: DNSServiceSetDispatchQueue dispatch queue NULL");
2033 return kDNSServiceErr_BadParam;
2035 if (service->disp_queue)
2037 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch queue set already");
2038 return kDNSServiceErr_BadParam;
2040 if (service->disp_source)
2042 syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch source set already");
2043 return kDNSServiceErr_BadParam;
2045 service->disp_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, dnssd_fd, 0, queue);
2046 if (!service->disp_source)
2048 syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch_source_create failed");
2049 return kDNSServiceErr_NoMemory;
2051 service->disp_queue = queue;
2052 dispatch_source_set_event_handler(service->disp_source, ^{DNSServiceProcessResult(service);});
2053 dispatch_source_set_cancel_handler(service->disp_source, ^{dnssd_close(dnssd_fd);});
2054 dispatch_resume(service->disp_source);
2055 return kDNSServiceErr_NoError;
2057 #endif // _DNS_SD_LIBDISPATCH
2059 #if !defined(_WIN32)
2061 static void DNSSD_API SleepKeepaliveCallback(DNSServiceRef sdRef, DNSRecordRef rec, const DNSServiceFlags flags,
2062 DNSServiceErrorType errorCode, void *context)
2064 SleepKAContext *ka = (SleepKAContext *)context;
2065 (void)rec; // Unused
2066 (void)flags; // Unused
2068 if (sdRef->kacontext != context)
2069 syslog(LOG_WARNING, "SleepKeepaliveCallback context mismatch");
2071 if (ka->AppCallback)
2072 ((DNSServiceSleepKeepaliveReply)ka->AppCallback)(sdRef, errorCode, ka->AppContext);
2075 DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
2077 DNSServiceRef *sdRef,
2078 DNSServiceFlags flags,
2079 int fd,
2080 unsigned int timeout,
2081 DNSServiceSleepKeepaliveReply callBack,
2082 void *context
2085 char source_str[INET6_ADDRSTRLEN];
2086 char target_str[INET6_ADDRSTRLEN];
2087 struct sockaddr_storage lss;
2088 struct sockaddr_storage rss;
2089 socklen_t len1, len2;
2090 unsigned int len, proxyreclen;
2091 char buf[256];
2092 DNSServiceErrorType err;
2093 DNSRecordRef record = NULL;
2094 char name[10];
2095 char recname[128];
2096 SleepKAContext *ka;
2097 unsigned int i, unique;
2100 (void) flags; //unused
2101 if (!timeout) return kDNSServiceErr_BadParam;
2104 len1 = sizeof(lss);
2105 if (getsockname(fd, (struct sockaddr *)&lss, &len1) < 0)
2107 syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getsockname %d\n", errno);
2108 return kDNSServiceErr_BadParam;
2111 len2 = sizeof(rss);
2112 if (getpeername(fd, (struct sockaddr *)&rss, &len2) < 0)
2114 syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getpeername %d\n", errno);
2115 return kDNSServiceErr_BadParam;
2118 if (len1 != len2)
2120 syslog(LOG_WARNING, "DNSServiceSleepKeepalive local/remote info not same");
2121 return kDNSServiceErr_Unknown;
2124 unique = 0;
2125 if (lss.ss_family == AF_INET)
2127 struct sockaddr_in *sl = (struct sockaddr_in *)&lss;
2128 struct sockaddr_in *sr = (struct sockaddr_in *)&rss;
2129 unsigned char *ptr = (unsigned char *)&sl->sin_addr;
2131 if (!inet_ntop(AF_INET, (const void *)&sr->sin_addr, target_str, sizeof (target_str)))
2133 syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote info failed %d", errno);
2134 return kDNSServiceErr_Unknown;
2136 if (!inet_ntop(AF_INET, (const void *)&sl->sin_addr, source_str, sizeof (source_str)))
2138 syslog(LOG_WARNING, "DNSServiceSleepKeepalive local info failed %d", errno);
2139 return kDNSServiceErr_Unknown;
2141 // Sum of all bytes in the local address and port should result in a unique
2142 // number in the local network
2143 for (i = 0; i < sizeof(struct in_addr); i++)
2144 unique += ptr[i];
2145 unique += sl->sin_port;
2146 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));
2148 else
2150 struct sockaddr_in6 *sl6 = (struct sockaddr_in6 *)&lss;
2151 struct sockaddr_in6 *sr6 = (struct sockaddr_in6 *)&rss;
2152 unsigned char *ptr = (unsigned char *)&sl6->sin6_addr;
2154 if (!inet_ntop(AF_INET6, (const void *)&sr6->sin6_addr, target_str, sizeof (target_str)))
2156 syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote6 info failed %d", errno);
2157 return kDNSServiceErr_Unknown;
2159 if (!inet_ntop(AF_INET6, (const void *)&sl6->sin6_addr, source_str, sizeof (source_str)))
2161 syslog(LOG_WARNING, "DNSServiceSleepKeepalive local6 info failed %d", errno);
2162 return kDNSServiceErr_Unknown;
2164 for (i = 0; i < sizeof(struct in6_addr); i++)
2165 unique += ptr[i];
2166 unique += sl6->sin6_port;
2167 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));
2170 if (len >= (sizeof(buf) - 1))
2172 syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit local/remote info");
2173 return kDNSServiceErr_Unknown;
2175 // Include the NULL byte also in the first byte. The total length of the record includes the
2176 // first byte also.
2177 buf[0] = len + 1;
2178 proxyreclen = len + 2;
2180 len = snprintf(name, sizeof(name), "%u", unique);
2181 if (len >= sizeof(name))
2183 syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit unique");
2184 return kDNSServiceErr_Unknown;
2187 len = snprintf(recname, sizeof(recname), "%s.%s", name, "_keepalive._dns-sd._udp.local");
2188 if (len >= sizeof(recname))
2190 syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit name");
2191 return kDNSServiceErr_Unknown;
2194 ka = malloc(sizeof(SleepKAContext));
2195 if (!ka) return kDNSServiceErr_NoMemory;
2196 ka->AppCallback = callBack;
2197 ka->AppContext = context;
2199 err = DNSServiceCreateConnection(sdRef);
2200 if (err)
2202 syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection");
2203 free(ka);
2204 return err;
2207 // we don't care about the "record". When sdRef gets deallocated later, it will be freed too
2208 err = DNSServiceRegisterRecord(*sdRef, &record, kDNSServiceFlagsUnique, 0, recname,
2209 kDNSServiceType_NULL, kDNSServiceClass_IN, proxyreclen, buf, kDNSServiceInterfaceIndexAny, SleepKeepaliveCallback, ka);
2210 if (err)
2212 syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection");
2213 free(ka);
2214 return err;
2216 (*sdRef)->kacontext = ka;
2217 return kDNSServiceErr_NoError;
2219 #endif