]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSShared/dnssd_clientstub.c
mDNSResponder-161.1.tar.gz
[apple/mdnsresponder.git] / mDNSShared / dnssd_clientstub.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2003-2004, Apple Computer, Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 Change History (most recent first):
29
30 $Log: dnssd_clientstub.c,v $
31 Revision 1.93 2007/10/10 00:48:54 cheshire
32 <rdar://problem/5526379> Daemon spins in an infinite loop when it doesn't get the control message it's expecting
33
34 Revision 1.92 2007/10/06 03:44:44 cheshire
35 Testing code for <rdar://problem/5526374> kqueue does not get a kevent to wake it up when a control message arrives on a socket
36
37 Revision 1.91 2007/10/04 20:53:59 cheshire
38 Improved debugging message when sendmsg fails
39
40 Revision 1.90 2007/09/30 00:09:27 cheshire
41 <rdar://problem/5492315> Pass socket fd via SCM_RIGHTS sendmsg instead of using named UDS in the filesystem
42
43 Revision 1.89 2007/09/19 23:53:12 cheshire
44 Fixed spelling mistake in comment
45
46 Revision 1.88 2007/09/07 23:18:27 cheshire
47 <rdar://problem/5467542> Change "client_context" to be an incrementing 64-bit counter
48
49 Revision 1.87 2007/09/07 22:50:09 cheshire
50 Added comment explaining moreptr field in DNSServiceOp structure
51
52 Revision 1.86 2007/09/07 20:21:22 cheshire
53 <rdar://problem/5462371> Make DNSSD library more resilient
54 Add more comments explaining the moreptr/morebytes logic; don't allow DNSServiceRefSockFD or
55 DNSServiceProcessResult for subordinate DNSServiceRefs created using kDNSServiceFlagsShareConnection
56
57 Revision 1.85 2007/09/06 21:43:23 cheshire
58 <rdar://problem/5462371> Make DNSSD library more resilient
59 Allow DNSServiceRefDeallocate from within DNSServiceProcessResult callback
60
61 Revision 1.84 2007/09/06 18:31:47 cheshire
62 <rdar://problem/5462371> Make DNSSD library more resilient against client programming errors
63
64 Revision 1.83 2007/08/28 20:45:45 cheshire
65 Typo: ctrl_path needs to be 64 bytes, not 44 bytes
66
67 Revision 1.82 2007/08/28 19:53:52 cheshire
68 <rdar://problem/5437423> Bonjour failures when /tmp is not writable (e.g. when booted from installer disc)
69
70 Revision 1.81 2007/07/27 00:03:20 cheshire
71 Fixed compiler warnings that showed up now we're building optimized ("-Os")
72
73 Revision 1.80 2007/07/23 22:12:53 cheshire
74 <rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients
75
76 Revision 1.79 2007/07/23 19:58:24 cheshire
77 <rdar://problem/5351640> Library: Leak in DNSServiceRefDeallocate
78
79 Revision 1.78 2007/07/12 20:42:27 cheshire
80 <rdar://problem/5280735> If daemon is killed, return kDNSServiceErr_ServiceNotRunning
81 to clients instead of kDNSServiceErr_Unknown
82
83 Revision 1.77 2007/07/02 23:07:13 cheshire
84 <rdar://problem/5308280> Reduce DNS-SD client syslog error messages
85
86 Revision 1.76 2007/06/22 20:12:18 cheshire
87 <rdar://problem/5277024> Leak in DNSServiceRefDeallocate
88
89 Revision 1.75 2007/05/23 18:59:22 cheshire
90 Remove unnecessary IPC_FLAGS_REUSE_SOCKET
91
92 Revision 1.74 2007/05/22 18:28:38 cheshire
93 Fixed compile errors in posix build
94
95 Revision 1.73 2007/05/22 01:20:47 cheshire
96 To determine current operation, need to check hdr->op, not sdr->op
97
98 Revision 1.72 2007/05/22 01:07:42 cheshire
99 <rdar://problem/3563675> API: Need a way to get version/feature information
100
101 Revision 1.71 2007/05/18 23:55:22 cheshire
102 <rdar://problem/4454655> Allow multiple register/browse/resolve operations to share single Unix Domain Socket
103
104 Revision 1.70 2007/05/17 20:58:22 cheshire
105 <rdar://problem/4647145> DNSServiceQueryRecord should return useful information with NXDOMAIN
106
107 Revision 1.69 2007/05/16 16:58:27 cheshire
108 <rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines
109 As long as select indicates that data is waiting, loop within DNSServiceProcessResult delivering additional results
110
111 Revision 1.68 2007/05/16 01:06:52 cheshire
112 <rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines
113
114 Revision 1.67 2007/05/15 21:57:16 cheshire
115 <rdar://problem/4608220> Use dnssd_SocketValid(x) macro instead of just
116 assuming that all negative values (or zero!) are invalid socket numbers
117
118 Revision 1.66 2007/03/27 22:23:04 cheshire
119 Add "dnssd_clientstub" prefix onto syslog messages
120
121 Revision 1.65 2007/03/21 22:25:23 cheshire
122 <rdar://problem/4172796> Remove client retry logic now that mDNSResponder uses launchd for its Unix Domain Socket
123
124 Revision 1.64 2007/03/21 19:01:56 cheshire
125 <rdar://problem/5078494> IPC code not 64-bit-savvy: assumes long=32bits, and short=16bits
126
127 Revision 1.63 2007/03/12 21:48:21 cheshire
128 <rdar://problem/5000162> Scary unlink errors in system.log
129 Code was using memory after it had been freed
130
131 Revision 1.62 2007/02/28 01:44:30 cheshire
132 <rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
133
134 Revision 1.61 2007/02/09 03:09:42 cheshire
135 <rdar://problem/3869251> Cleanup: Stop returning kDNSServiceErr_Unknown so often
136 <rdar://problem/4177924> API: Should return kDNSServiceErr_ServiceNotRunning
137
138 Revision 1.60 2007/02/08 20:33:44 cheshire
139 <rdar://problem/4985095> Leak on error path in DNSServiceProcessResult
140
141 Revision 1.59 2007/01/05 08:30:55 cheshire
142 Trim excessive "$Log" checkin history from before 2006
143 (checkin history still available via "cvs log ..." of course)
144
145 Revision 1.58 2006/10/27 00:38:22 cheshire
146 Strip accidental trailing whitespace from lines
147
148 Revision 1.57 2006/09/30 01:06:54 cheshire
149 Protocol field should be uint32_t
150
151 Revision 1.56 2006/09/27 00:44:16 herscher
152 <rdar://problem/4249761> API: Need DNSServiceGetAddrInfo()
153
154 Revision 1.55 2006/09/26 01:52:01 herscher
155 <rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
156
157 Revision 1.54 2006/09/21 21:34:09 cheshire
158 <rdar://problem/4100000> Allow empty string name when using kDNSServiceFlagsNoAutoRename
159
160 Revision 1.53 2006/09/07 04:43:12 herscher
161 Fix compile error on Win32 platform by moving inclusion of syslog.h
162
163 Revision 1.52 2006/08/15 23:04:21 mkrochma
164 <rdar://problem/4090354> Client should be able to specify service name w/o callback
165
166 Revision 1.51 2006/07/24 23:45:55 cheshire
167 <rdar://problem/4605276> DNSServiceReconfirmRecord() should return error code
168
169 Revision 1.50 2006/06/28 08:22:27 cheshire
170 <rdar://problem/4605264> dnssd_clientstub.c needs to report unlink failures in syslog
171
172 Revision 1.49 2006/06/28 07:58:59 cheshire
173 Minor textual tidying
174
175 */
176
177 #include <errno.h>
178 #include <stdlib.h>
179
180 #include "dnssd_ipc.h"
181
182 #if defined(_WIN32)
183
184 #include <winsock2.h>
185 #include <ws2tcpip.h>
186 #include <windows.h>
187
188 #define sockaddr_mdns sockaddr_in
189 #define AF_MDNS AF_INET
190
191 // Disable warning: "'type cast' : from data pointer 'void *' to function pointer"
192 #pragma warning(disable:4055)
193
194 // Disable warning: "nonstandard extension, function/data pointer conversion in expression"
195 #pragma warning(disable:4152)
196
197 extern BOOL IsSystemServiceDisabled();
198
199 #define sleep(X) Sleep((X) * 1000)
200
201 static int g_initWinsock = 0;
202
203 #else
204
205 #include <sys/time.h>
206 #include <sys/socket.h>
207 #include <syslog.h>
208
209 #define sockaddr_mdns sockaddr_un
210 #define AF_MDNS AF_LOCAL
211
212 #endif
213
214 // <rdar://problem/4096913> Specifies how many times we'll try and connect to the server.
215
216 #define DNSSD_CLIENT_MAXTRIES 4
217
218 // Uncomment the line below to use the old error return mechanism of creating a temporary named socket (e.g. in /var/tmp)
219 //#define USE_NAMED_ERROR_RETURN_SOCKET 1
220
221 #ifndef CTL_PATH_PREFIX
222 #define CTL_PATH_PREFIX "/var/tmp/dnssd_result_socket."
223 #endif
224
225 typedef struct
226 {
227 ipc_msg_hdr ipc_hdr;
228 DNSServiceFlags cb_flags;
229 uint32_t cb_interface;
230 DNSServiceErrorType cb_err;
231 } CallbackHeader;
232
233 typedef struct _DNSServiceRef_t DNSServiceOp;
234 typedef struct _DNSRecordRef_t DNSRecord;
235
236 // client stub callback to process message from server and deliver results to client application
237 typedef void (*ProcessReplyFn)(DNSServiceOp *sdr, CallbackHeader *cbh, char *msg, char *end);
238
239 #define ValidatorBits 0x12345678
240 #define DNSServiceRefValid(X) (dnssd_SocketValid((X)->sockfd) && (((X)->sockfd ^ (X)->validator) == ValidatorBits))
241
242 // When using kDNSServiceFlagsShareConnection, there is one primary _DNSServiceOp_t, and zero or more subordinates
243 // For the primary, the 'next' field points to the first subordinate, and its 'next' field points to the next, and so on.
244 // For the primary, the 'primary' field is NULL; for subordinates the 'primary' field points back to the associated primary
245 struct _DNSServiceRef_t
246 {
247 DNSServiceOp *next; // For shared connection
248 DNSServiceOp *primary; // For shared connection
249 dnssd_sock_t sockfd; // Connected socket between client and daemon
250 dnssd_sock_t validator; // Used to detect memory corruption, double disposals, etc.
251 client_context_t uid; // For shared connection requests, each subordinate DNSServiceRef has its own ID,
252 // unique within the scope of the same shared parent DNSServiceRef
253 uint32_t op; // request_op_t or reply_op_t
254 uint32_t max_index; // Largest assigned record index - 0 if no additional records registered
255 uint32_t logcounter; // Counter used to control number of syslog messages we write
256 int *moreptr; // Set while DNSServiceProcessResult working on this particular DNSServiceRef
257 ProcessReplyFn ProcessReply; // Function pointer to the code to handle received messages
258 void *AppCallback; // Client callback function and context
259 void *AppContext;
260 };
261
262 struct _DNSRecordRef_t
263 {
264 void *AppContext;
265 DNSServiceRegisterRecordReply AppCallback;
266 DNSRecordRef recref;
267 uint32_t record_index; // index is unique to the ServiceDiscoveryRef
268 DNSServiceOp *sdr;
269 };
270
271 // Write len bytes. Return 0 on success, -1 on error
272 static int write_all(dnssd_sock_t sd, char *buf, int len)
273 {
274 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
275 //if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
276 while (len)
277 {
278 ssize_t num_written = send(sd, buf, len, 0);
279 if (num_written < 0 || num_written > len)
280 {
281 // Should never happen. If it does, it indicates some OS bug,
282 // or that the mDNSResponder daemon crashed (which should never happen).
283 syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %d/%d %d %s", sd, num_written, len,
284 (num_written < 0) ? errno : 0,
285 (num_written < 0) ? strerror(errno) : "");
286 return -1;
287 }
288 buf += num_written;
289 len -= num_written;
290 }
291 return 0;
292 }
293
294 // Read len bytes. Return 0 on success, -1 on error
295 static int read_all(dnssd_sock_t sd, char *buf, int len)
296 {
297 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
298 //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1;
299
300 while (len)
301 {
302 ssize_t num_read = recv(sd, buf, len, 0);
303 if ((num_read == 0) || (num_read < 0) || (num_read > len))
304 {
305 // Should never happen. If it does, it indicates some OS bug,
306 // or that the mDNSResponder daemon crashed (which should never happen).
307 syslog(LOG_WARNING, "dnssd_clientstub read_all(%d) failed %d/%d %d %s", sd, num_read, len,
308 (num_read < 0) ? errno : 0,
309 (num_read < 0) ? strerror(errno) : "");
310 return -1;
311 }
312 buf += num_read;
313 len -= num_read;
314 }
315 return 0;
316 }
317
318 // Returns 1 if more bytes remain to be read on socket descriptor sd, 0 otherwise
319 static int more_bytes(dnssd_sock_t sd)
320 {
321 struct timeval tv = { 0, 0 };
322 fd_set readfds;
323 FD_ZERO(&readfds);
324 FD_SET(sd, &readfds);
325 return(select(sd+1, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv) > 0);
326 }
327
328 /* create_hdr
329 *
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.
337 */
338 static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int SeparateReturnSocket, DNSServiceOp *ref)
339 {
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
346
347 if (SeparateReturnSocket)
348 {
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 time;
353 if (gettimeofday(&time, NULL) < 0)
354 { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: gettimeofday failed %d %s", errno, strerror(errno)); return NULL; }
355 sprintf(ctrl_path, "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(),
356 (unsigned long)(time.tv_sec & 0xFFF), (unsigned long)(time.tv_usec));
357 *len += strlen(ctrl_path) + 1;
358 #else
359 *len += 1; // Allocate space for single zero byte (empty C string)
360 #endif
361 }
362
363 datalen = (int) *len;
364 *len += sizeof(ipc_msg_hdr);
365
366 // Write message to buffer
367 msg = malloc(*len);
368 if (!msg) { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: malloc failed"); return NULL; }
369
370 bzero(msg, *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;
387 }
388
389 static void FreeDNSServiceOp(DNSServiceOp *x)
390 {
391 // We don't use our DNSServiceRefValid macro here because if we're cleaning up after a socket() call failed
392 // then sockfd could legitimately contain a failing value (e.g. dnssd_InvalidSocket)
393 if ((x->sockfd ^ x->validator) != ValidatorBits)
394 syslog(LOG_WARNING, "dnssd_clientstub attempt to dispose invalid DNSServiceRef %p %08X %08X", x, x->sockfd, x->validator);
395 else
396 {
397 x->next = NULL;
398 x->primary = NULL;
399 x->sockfd = dnssd_InvalidSocket;
400 x->validator = 0xDDDDDDDD;
401 x->op = request_op_none;
402 x->max_index = 0;
403 x->logcounter = 0;
404 x->moreptr = NULL;
405 x->ProcessReply = NULL;
406 x->AppCallback = NULL;
407 x->AppContext = NULL;
408 free(x);
409 }
410 }
411
412 // Return a connected service ref (deallocate with DNSServiceRefDeallocate)
413 static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags flags, uint32_t op, ProcessReplyFn ProcessReply, void *AppCallback, void *AppContext)
414 {
415 #if APPLE_OSX_mDNSResponder
416 int NumTries = DNSSD_CLIENT_MAXTRIES;
417 #else
418 int NumTries = 0;
419 #endif
420
421 dnssd_sockaddr_t saddr;
422 DNSServiceOp *sdr;
423
424 if (!ref) { syslog(LOG_WARNING, "dnssd_clientstub DNSService operation with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
425
426 if (flags & kDNSServiceFlagsShareConnection)
427 {
428 if (!*ref)
429 {
430 syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with NULL DNSServiceRef");
431 return kDNSServiceErr_BadParam;
432 }
433 if (!DNSServiceRefValid(*ref))
434 {
435 syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with invalid DNSServiceRef %p %08X %08X",
436 (*ref), (*ref)->sockfd, (*ref)->validator);
437 *ref = NULL;
438 return kDNSServiceErr_BadReference;
439 }
440 }
441
442 #if defined(_WIN32)
443 if (!g_initWinsock)
444 {
445 WSADATA wsaData;
446 g_initWinsock = 1;
447 if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { *ref = NULL; return kDNSServiceErr_ServiceNotRunning; }
448 }
449 // <rdar://problem/4096913> If the system service is disabled, we only want to try to connect once
450 if (IsSystemServiceDisabled()) NumTries = DNSSD_CLIENT_MAXTRIES;
451 #endif
452
453 sdr = malloc(sizeof(DNSServiceOp));
454 if (!sdr) { syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: malloc failed"); *ref = NULL; return kDNSServiceErr_NoMemory; }
455 sdr->next = NULL;
456 sdr->primary = NULL;
457 sdr->sockfd = dnssd_InvalidSocket;
458 sdr->validator = sdr->sockfd ^ ValidatorBits;
459 sdr->op = op;
460 sdr->max_index = 0;
461 sdr->logcounter = 0;
462 sdr->moreptr = NULL;
463 sdr->uid.u32[0] = 0;
464 sdr->uid.u32[1] = 0;
465 sdr->ProcessReply = ProcessReply;
466 sdr->AppCallback = AppCallback;
467 sdr->AppContext = AppContext;
468
469 if (flags & kDNSServiceFlagsShareConnection)
470 {
471 DNSServiceOp **p = &(*ref)->next; // Append ourselves to end of primary's list
472 while (*p) p = &(*p)->next;
473 *p = sdr;
474 sdr->primary = *ref; // Set our primary pointer
475 sdr->sockfd = (*ref)->sockfd; // Inherit primary's socket
476 sdr->validator = (*ref)->validator;
477 sdr->uid = (*ref)->uid;
478 if (++(*ref)->uid.u32[0] == 0) ++(*ref)->uid.u32[1]; // In parent DNSServiceOp increment UID counter
479 //printf("ConnectToServer sharing socket %d\n", sdr->sockfd);
480 }
481 else
482 {
483 *ref = NULL;
484 sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0);
485 sdr->validator = sdr->sockfd ^ ValidatorBits;
486 if (!dnssd_SocketValid(sdr->sockfd))
487 {
488 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: socket failed %d %s", errno, strerror(errno));
489 FreeDNSServiceOp(sdr);
490 return kDNSServiceErr_NoMemory;
491 }
492 #if defined(USE_TCP_LOOPBACK)
493 saddr.sin_family = AF_INET;
494 saddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
495 saddr.sin_port = htons(MDNS_TCP_SERVERPORT);
496 #else
497 saddr.sun_family = AF_LOCAL;
498 strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH);
499 #endif
500
501 while (1)
502 {
503 int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
504 if (!err) break; // If we succeeded, return sdr
505 // If we failed, then it may be because the daemon is still launching.
506 // This can happen for processes that launch early in the boot process, while the
507 // daemon is still coming up. Rather than fail here, we'll wait a bit and try again.
508 // If, after four seconds, we still can't connect to the daemon,
509 // then we give up and return a failure code.
510 if (++NumTries < DNSSD_CLIENT_MAXTRIES) sleep(1); // Sleep a bit, then try again
511 else { dnssd_close(sdr->sockfd); FreeDNSServiceOp(sdr); return kDNSServiceErr_ServiceNotRunning; }
512 }
513 //printf("ConnectToServer opened socket %d\n", sdr->sockfd);
514 }
515
516 *ref = sdr;
517 return kDNSServiceErr_NoError;
518 }
519
520 static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
521 {
522 uint32_t datalen = hdr->datalen; // We take a copy here because we're going to convert hdr->datalen to network byte order
523 #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
524 char *const data = (char *)hdr + sizeof(ipc_msg_hdr);
525 #endif
526 dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
527 DNSServiceErrorType err;
528 int MakeSeparateReturnSocket = 0;
529
530 // Note: need to check hdr->op, not sdr->op.
531 // hdr->op contains the code for the specific operation we're currently doing, whereas sdr->op
532 // contains the original parent DNSServiceOp (e.g. for an add_record_request, hdr->op will be
533 // add_record_request but the parent sdr->op will be connection_request or reg_service_request)
534 if (sdr->primary ||
535 hdr->op == reg_record_request || hdr->op == add_record_request || hdr->op == update_record_request || hdr->op == remove_record_request)
536 MakeSeparateReturnSocket = 1;
537
538 if (!DNSServiceRefValid(sdr))
539 {
540 syslog(LOG_WARNING, "dnssd_clientstub deliver_request: invalid DNSServiceRef %p %08X %08X", sdr, sdr->sockfd, sdr->validator);
541 return kDNSServiceErr_BadReference;
542 }
543
544 if (!hdr) { syslog(LOG_WARNING, "dnssd_clientstub deliver_request: !hdr"); return kDNSServiceErr_Unknown; }
545
546 if (MakeSeparateReturnSocket)
547 {
548 #if defined(USE_TCP_LOOPBACK)
549 {
550 union { uint16_t s; u_char b[2]; } port;
551 dnssd_sockaddr_t caddr;
552 dnssd_socklen_t len = (dnssd_socklen_t) sizeof(caddr);
553 listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
554 if (!dnssd_SocketValid(listenfd)) goto cleanup;
555
556 caddr.sin_family = AF_INET;
557 caddr.sin_port = 0;
558 caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
559 if (bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr)) < 0) goto cleanup;
560 if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) goto cleanup;
561 listen(listenfd, 1);
562 port.s = caddr.sin_port;
563 data[0] = port.b[0]; // don't switch the byte order, as the
564 data[1] = port.b[1]; // daemon expects it in network byte order
565 }
566 #elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
567 {
568 dnssd_sockaddr_t caddr;
569 mode_t mask = umask(0);
570 listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
571 if (!dnssd_SocketValid(listenfd)) goto cleanup;
572
573 caddr.sun_family = AF_LOCAL;
574 // According to Stevens (section 3.2), there is no portable way to
575 // determine whether sa_len is defined on a particular platform.
576 #ifndef NOT_HAVE_SA_LEN
577 caddr.sun_len = sizeof(struct sockaddr_un);
578 #endif
579 strcpy(caddr.sun_path, data);
580 umask(mask);
581 if (bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr)) < 0) goto cleanup;
582 listen(listenfd, 1);
583 }
584 #else
585 {
586 dnssd_sock_t sp[2];
587 //if (pipe(sp) < 0)
588 // syslog(LOG_WARNING, "dnssd_clientstub ERROR: pipe() failed errno %d (%s)", errno, strerror(errno));
589 if (socketpair(AF_DNSSD, SOCK_STREAM, 0, sp) < 0)
590 syslog(LOG_WARNING, "dnssd_clientstub ERROR: socketpair() failed errno %d (%s)", errno, strerror(errno));
591 else
592 {
593 errsd = sp[0]; // We'll read our four-byte error code from sp[0]
594 listenfd = sp[1]; // We'll send sp[1] to the daemon
595 }
596 }
597 #endif
598 }
599
600 #if !defined(USE_TCP_LOOPBACK) && !defined(USE_NAMED_ERROR_RETURN_SOCKET)
601 // If we're going to make a separate error return socket, and pass it to the daemon
602 // using sendmsg, then we'll hold back one data byte to go with it.
603 // On some versions of Unix (including Leopard) sending a control message without
604 // any associated data does not work reliably -- e.g. one particular issue we ran
605 // into is that if the receiving program is in a kqueue loop waiting to be notified
606 // of the received message, it doesn't get woken up when the control message arrives.
607 if (MakeSeparateReturnSocket) datalen--;
608 #endif
609
610 // At this point, our listening socket is set up and waiting, if necessary, for the daemon to connect back to
611 ConvertHeaderBytes(hdr);
612 //syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %ld bytes", datalen + sizeof(ipc_msg_hdr));
613 //if (MakeSeparateReturnSocket) syslog(LOG_WARNING, "dnssd_clientstub deliver_request name is %s", data);
614 #if TEST_SENDING_ONE_BYTE_AT_A_TIME
615 unsigned int i;
616 for (i=0; i<datalen + sizeof(ipc_msg_hdr); i++)
617 {
618 syslog(LOG_WARNING, "dnssd_clientstub writing %d", i);
619 if (write_all(sdr->sockfd, ((char *)hdr)+i, 1) < 0) goto cleanup;
620 usleep(10000);
621 }
622 #else
623 if (write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr)) < 0) goto cleanup;
624 #endif
625
626 if (!MakeSeparateReturnSocket) errsd = sdr->sockfd;
627 else
628 {
629 #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
630 // At this point we may block in accept for a few milliseconds waiting for the daemon to connect back to us,
631 // but that's okay -- the daemon is a trusted service and we know if won't take more than a few milliseconds to respond.
632 dnssd_sockaddr_t daddr;
633 dnssd_socklen_t len = sizeof(daddr);
634 errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
635 if (!dnssd_SocketValid(errsd)) goto cleanup;
636 #else
637 struct iovec vec = { ((char *)hdr) + sizeof(ipc_msg_hdr) + datalen, 1 }; // Send the last byte along with the SCM_RIGHTS
638 struct msghdr msg;
639 struct cmsghdr *cmsg;
640 char cbuf[sizeof(struct cmsghdr) + sizeof(dnssd_sock_t)];
641 msg.msg_name = 0;
642 msg.msg_namelen = 0;
643 msg.msg_iov = &vec;
644 msg.msg_iovlen = 1;
645 msg.msg_control = cbuf;
646 msg.msg_controllen = sizeof(cbuf);
647 msg.msg_flags = 0;
648 cmsg = CMSG_FIRSTHDR(&msg);
649 cmsg->cmsg_len = sizeof(cbuf);
650 cmsg->cmsg_level = SOL_SOCKET;
651 cmsg->cmsg_type = SCM_RIGHTS;
652 *((dnssd_sock_t *)CMSG_DATA(cmsg)) = listenfd;
653 #if TEST_KQUEUE_CONTROL_MESSAGE_BUG
654 sleep(1);
655 #endif
656 if (sendmsg(sdr->sockfd, &msg, 0) < 0)
657 syslog(LOG_WARNING, "dnssd_clientstub ERROR: sendmsg failed read sd=%d write sd=%d errno %d (%s)",
658 errsd, listenfd, errno, strerror(errno));
659 #endif
660 }
661
662 // At this point we may block in read_all for a few milliseconds waiting for the daemon to send us the error code,
663 // but that's okay -- the daemon is a trusted service and we know if won't take more than a few milliseconds to respond.
664 if (read_all(errsd, (char*)&err, (int)sizeof(err)) < 0)
665 err = kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us
666 else
667 err = ntohl(err);
668
669 //syslog(LOG_WARNING, "dnssd_clientstub deliver_request: retrieved error code %d", err);
670
671 cleanup:
672 if (MakeSeparateReturnSocket)
673 {
674 if (dnssd_SocketValid(listenfd)) dnssd_close(listenfd);
675 if (dnssd_SocketValid(errsd)) dnssd_close(errsd);
676 #if defined(USE_NAMED_ERROR_RETURN_SOCKET)
677 // syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removing UDS: %s", data);
678 if (unlink(data) != 0)
679 syslog(LOG_WARNING, "dnssd_clientstub WARNING: unlink(\"%s\") failed errno %d (%s)", data, errno, strerror(errno));
680 // else syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removed UDS: %s", data);
681 #endif
682 }
683 free(hdr);
684 return err;
685 }
686
687 int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef)
688 {
689 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with NULL DNSServiceRef"); return dnssd_InvalidSocket; }
690
691 if (!DNSServiceRefValid(sdRef))
692 {
693 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with invalid DNSServiceRef %p %08X %08X",
694 sdRef, sdRef->sockfd, sdRef->validator);
695 return dnssd_InvalidSocket;
696 }
697
698 if (sdRef->primary)
699 {
700 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
701 return dnssd_InvalidSocket;
702 }
703
704 return (int) sdRef->sockfd;
705 }
706
707 // Handle reply from server, calling application client callback. If there is no reply
708 // from the daemon on the socket contained in sdRef, the call will block.
709 DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
710 {
711 int morebytes = 0;
712
713 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
714
715 if (!DNSServiceRefValid(sdRef))
716 {
717 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
718 return kDNSServiceErr_BadReference;
719 }
720
721 if (sdRef->primary)
722 {
723 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
724 return kDNSServiceErr_BadReference;
725 }
726
727 if (!sdRef->ProcessReply)
728 {
729 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function");
730 return kDNSServiceErr_BadReference;
731 }
732
733 do
734 {
735 CallbackHeader cbh;
736 char *data;
737
738 // return NoError on EWOULDBLOCK. This will handle the case
739 // where a non-blocking socket is told there is data, but it was a false positive.
740 // On error, read_all will write a message to syslog for us, so don't need to duplicate that here
741 if (read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr)) < 0)
742 {
743 if (dnssd_errno() != dnssd_EWOULDBLOCK)
744 {
745 sdRef->ProcessReply = NULL;
746 return kDNSServiceErr_ServiceNotRunning;
747 }
748 else
749 {
750 if (morebytes && sdRef->logcounter < 100)
751 {
752 sdRef->logcounter++;
753 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult error: select indicated data was waiting but read_all returned EWOULDBLOCK");
754 }
755 return kDNSServiceErr_NoError;
756 }
757 }
758
759 ConvertHeaderBytes(&cbh.ipc_hdr);
760 if (cbh.ipc_hdr.version != VERSION)
761 {
762 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult daemon version %d does not match client version %d", cbh.ipc_hdr.version, VERSION);
763 sdRef->ProcessReply = NULL;
764 return kDNSServiceErr_Incompatible;
765 }
766
767 data = malloc(cbh.ipc_hdr.datalen);
768 if (!data) return kDNSServiceErr_NoMemory;
769 if (read_all(sdRef->sockfd, data, cbh.ipc_hdr.datalen) < 0) // On error, read_all will write a message to syslog for us
770 {
771 free(data);
772 sdRef->ProcessReply = NULL;
773 return kDNSServiceErr_ServiceNotRunning;
774 }
775 else
776 {
777 char *ptr = data;
778 cbh.cb_flags = get_flags (&ptr, data + cbh.ipc_hdr.datalen);
779 cbh.cb_interface = get_uint32 (&ptr, data + cbh.ipc_hdr.datalen);
780 cbh.cb_err = get_error_code(&ptr, data + cbh.ipc_hdr.datalen);
781
782 // CAUTION: We have to handle the case where the client calls DNSServiceRefDeallocate from within the callback function.
783 // To do this we set moreptr to point to morebytes. If the client does call DNSServiceRefDeallocate(),
784 // then that routine will clear morebytes for us, and cause us to exit our loop.
785 morebytes = more_bytes(sdRef->sockfd);
786 if (morebytes)
787 {
788 cbh.cb_flags |= kDNSServiceFlagsMoreComing;
789 sdRef->moreptr = &morebytes;
790 }
791 if (ptr) sdRef->ProcessReply(sdRef, &cbh, ptr, data + cbh.ipc_hdr.datalen);
792 // Careful code here:
793 // If morebytes is non-zero, that means we set sdRef->moreptr above, and the operation was not
794 // cancelled out from under us, so now we need to clear sdRef->moreptr so we don't leave a stray
795 // dangling pointer pointing to a long-gone stack variable.
796 // If morebytes is zero, then one of two thing happened:
797 // (a) morebytes was 0 above, so we didn't set sdRef->moreptr, so we don't need to clear it
798 // (b) morebytes was 1 above, and we set sdRef->moreptr, but the operation was cancelled (with DNSServiceRefDeallocate()),
799 // so we MUST NOT try to dereference our stale sdRef pointer.
800 if (morebytes) sdRef->moreptr = NULL;
801 }
802 free(data);
803 } while (morebytes);
804
805 return kDNSServiceErr_NoError;
806 }
807
808 void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef)
809 {
810 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with NULL DNSServiceRef"); return; }
811
812 if (!DNSServiceRefValid(sdRef)) // Also verifies dnssd_SocketValid(sdRef->sockfd) for us too
813 {
814 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
815 return;
816 }
817
818 // 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
819 if (sdRef->moreptr) *(sdRef->moreptr) = 0;
820
821 if (sdRef->primary) // If this is a subordinate DNSServiceOp, just send a 'stop' command
822 {
823 DNSServiceOp **p = &sdRef->primary->next;
824 while (*p && *p != sdRef) p = &(*p)->next;
825 if (*p)
826 {
827 char *ptr;
828 size_t len = 0;
829 ipc_msg_hdr *hdr = create_hdr(cancel_request, &len, &ptr, 0, sdRef);
830 ConvertHeaderBytes(hdr);
831 write_all(sdRef->sockfd, (char *)hdr, len);
832 free(hdr);
833 *p = sdRef->next;
834 FreeDNSServiceOp(sdRef);
835 }
836 }
837 else // else, make sure to terminate all subordinates as well
838 {
839 dnssd_close(sdRef->sockfd);
840 while (sdRef)
841 {
842 DNSServiceOp *p = sdRef;
843 sdRef = sdRef->next;
844 FreeDNSServiceOp(p);
845 }
846 }
847 }
848
849 DNSServiceErrorType DNSSD_API DNSServiceGetProperty(const char *property, void *result, uint32_t *size)
850 {
851 char *ptr;
852 size_t len = strlen(property) + 1;
853 ipc_msg_hdr *hdr;
854 DNSServiceOp *tmp;
855 uint32_t actualsize;
856
857 DNSServiceErrorType err = ConnectToServer(&tmp, 0, getproperty_request, NULL, NULL, NULL);
858 if (err) return err;
859
860 hdr = create_hdr(getproperty_request, &len, &ptr, 0, tmp);
861 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
862
863 put_string(property, &ptr);
864 err = deliver_request(hdr, tmp); // Will free hdr for us
865 if (read_all(tmp->sockfd, (char*)&actualsize, (int)sizeof(actualsize)) < 0)
866 { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
867
868 actualsize = ntohl(actualsize);
869 if (read_all(tmp->sockfd, (char*)result, actualsize < *size ? actualsize : *size) < 0)
870 { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
871 DNSServiceRefDeallocate(tmp);
872
873 // Swap version result back to local process byte order
874 if (!strcmp(property, kDNSServiceProperty_DaemonVersion) && *size >= 4)
875 *(uint32_t*)result = ntohl(*(uint32_t*)result);
876
877 *size = actualsize;
878 return kDNSServiceErr_NoError;
879 }
880
881 static void handle_resolve_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
882 {
883 char fullname[kDNSServiceMaxDomainName];
884 char target[kDNSServiceMaxDomainName];
885 uint16_t txtlen;
886 union { uint16_t s; u_char b[2]; } port;
887 unsigned char *txtrecord;
888
889 get_string(&data, end, fullname, kDNSServiceMaxDomainName);
890 get_string(&data, end, target, kDNSServiceMaxDomainName);
891 if (data + 2 > end) data = NULL;
892 else
893 {
894 port.b[0] = *data++;
895 port.b[1] = *data++;
896 }
897 txtlen = get_uint16(&data, end);
898 txtrecord = (unsigned char *)get_rdata(&data, end, txtlen);
899
900 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_resolve_response: error reading result from daemon");
901 else ((DNSServiceResolveReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, fullname, target, port.s, txtlen, txtrecord, sdr->AppContext);
902 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
903 }
904
905 DNSServiceErrorType DNSSD_API DNSServiceResolve
906 (
907 DNSServiceRef *sdRef,
908 DNSServiceFlags flags,
909 uint32_t interfaceIndex,
910 const char *name,
911 const char *regtype,
912 const char *domain,
913 DNSServiceResolveReply callBack,
914 void *context
915 )
916 {
917 char *ptr;
918 size_t len;
919 ipc_msg_hdr *hdr;
920 DNSServiceErrorType err;
921
922 if (!name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam;
923
924 err = ConnectToServer(sdRef, flags, resolve_request, handle_resolve_response, callBack, context);
925 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
926
927 // Calculate total message length
928 len = sizeof(flags);
929 len += sizeof(interfaceIndex);
930 len += strlen(name) + 1;
931 len += strlen(regtype) + 1;
932 len += strlen(domain) + 1;
933
934 hdr = create_hdr(resolve_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
935 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
936
937 put_flags(flags, &ptr);
938 put_uint32(interfaceIndex, &ptr);
939 put_string(name, &ptr);
940 put_string(regtype, &ptr);
941 put_string(domain, &ptr);
942
943 err = deliver_request(hdr, *sdRef); // Will free hdr for us
944 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
945 return err;
946 }
947
948 static void handle_query_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
949 {
950 uint32_t ttl;
951 char name[kDNSServiceMaxDomainName];
952 uint16_t rrtype, rrclass, rdlen;
953 char *rdata;
954
955 get_string(&data, end, name, kDNSServiceMaxDomainName);
956 rrtype = get_uint16(&data, end);
957 rrclass = get_uint16(&data, end);
958 rdlen = get_uint16(&data, end);
959 rdata = get_rdata(&data, end, rdlen);
960 ttl = get_uint32(&data, end);
961
962 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_query_response: error reading result from daemon");
963 else ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, name, rrtype, rrclass, rdlen, rdata, ttl, sdr->AppContext);
964 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
965 }
966
967 DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
968 (
969 DNSServiceRef *sdRef,
970 DNSServiceFlags flags,
971 uint32_t interfaceIndex,
972 const char *name,
973 uint16_t rrtype,
974 uint16_t rrclass,
975 DNSServiceQueryRecordReply callBack,
976 void *context
977 )
978 {
979 char *ptr;
980 size_t len;
981 ipc_msg_hdr *hdr;
982 DNSServiceErrorType err = ConnectToServer(sdRef, flags, query_request, handle_query_response, callBack, context);
983 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
984
985 if (!name) name = "\0";
986
987 // Calculate total message length
988 len = sizeof(flags);
989 len += sizeof(uint32_t); // interfaceIndex
990 len += strlen(name) + 1;
991 len += 2 * sizeof(uint16_t); // rrtype, rrclass
992
993 hdr = create_hdr(query_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
994 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
995
996 put_flags(flags, &ptr);
997 put_uint32(interfaceIndex, &ptr);
998 put_string(name, &ptr);
999 put_uint16(rrtype, &ptr);
1000 put_uint16(rrclass, &ptr);
1001
1002 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1003 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1004 return err;
1005 }
1006
1007 static void handle_addrinfo_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
1008 {
1009 uint32_t ttl;
1010 char hostname[kDNSServiceMaxDomainName];
1011 uint16_t rrtype, rrclass, rdlen;
1012 char *rdata;
1013 struct sockaddr_in sa4;
1014 struct sockaddr_in6 sa6;
1015 struct sockaddr * sa = NULL;
1016
1017 get_string(&data, end, hostname, kDNSServiceMaxDomainName);
1018 rrtype = get_uint16(&data, end);
1019 rrclass = get_uint16(&data, end);
1020 rdlen = get_uint16(&data, end);
1021 rdata = get_rdata(&data, end, rdlen);
1022 ttl = get_uint32(&data, end);
1023
1024 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_addrinfo_response: error reading result from daemon");
1025 else
1026 {
1027 if (rrtype == kDNSServiceType_A)
1028 {
1029 sa = (struct sockaddr *)&sa4;
1030 bzero(&sa4, sizeof(sa4));
1031 #ifndef NOT_HAVE_SA_LEN
1032 sa->sa_len = sizeof(struct sockaddr_in);
1033 #endif
1034 sa->sa_family = AF_INET;
1035 if (!cbh->cb_err) memcpy(&sa4.sin_addr, rdata, rdlen);
1036 }
1037 else if (rrtype == kDNSServiceType_AAAA)
1038 {
1039 sa = (struct sockaddr *)&sa6;
1040 bzero(&sa6, sizeof(sa6));
1041 #ifndef NOT_HAVE_SA_LEN
1042 sa->sa_len = sizeof(struct sockaddr_in6);
1043 #endif
1044 sa->sa_family = AF_INET6;
1045 if (!cbh->cb_err) memcpy(&sa6.sin6_addr, rdata, rdlen);
1046 }
1047 ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, sa, ttl, sdr->AppContext);
1048 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1049 }
1050 }
1051
1052 DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
1053 (
1054 DNSServiceRef *sdRef,
1055 DNSServiceFlags flags,
1056 uint32_t interfaceIndex,
1057 uint32_t protocol,
1058 const char *hostname,
1059 DNSServiceGetAddrInfoReply callBack,
1060 void *context /* may be NULL */
1061 )
1062 {
1063 char *ptr;
1064 size_t len;
1065 ipc_msg_hdr *hdr;
1066 DNSServiceErrorType err;
1067
1068 if (!hostname) return kDNSServiceErr_BadParam;
1069
1070 err = ConnectToServer(sdRef, flags, addrinfo_request, handle_addrinfo_response, callBack, context);
1071 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1072
1073 // Calculate total message length
1074 len = sizeof(flags);
1075 len += sizeof(uint32_t); // interfaceIndex
1076 len += sizeof(uint32_t); // protocol
1077 len += strlen(hostname) + 1;
1078
1079 hdr = create_hdr(addrinfo_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1080 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1081
1082 put_flags(flags, &ptr);
1083 put_uint32(interfaceIndex, &ptr);
1084 put_uint32(protocol, &ptr);
1085 put_string(hostname, &ptr);
1086
1087 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1088 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1089 return err;
1090 }
1091
1092 static void handle_browse_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
1093 {
1094 char replyName[256], replyType[kDNSServiceMaxDomainName], replyDomain[kDNSServiceMaxDomainName];
1095 get_string(&data, end, replyName, 256);
1096 get_string(&data, end, replyType, kDNSServiceMaxDomainName);
1097 get_string(&data, end, replyDomain, kDNSServiceMaxDomainName);
1098 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_browse_response: error reading result from daemon");
1099 else ((DNSServiceBrowseReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, replyName, replyType, replyDomain, sdr->AppContext);
1100 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1101 }
1102
1103 DNSServiceErrorType DNSSD_API DNSServiceBrowse
1104 (
1105 DNSServiceRef *sdRef,
1106 DNSServiceFlags flags,
1107 uint32_t interfaceIndex,
1108 const char *regtype,
1109 const char *domain,
1110 DNSServiceBrowseReply callBack,
1111 void *context
1112 )
1113 {
1114 char *ptr;
1115 size_t len;
1116 ipc_msg_hdr *hdr;
1117 DNSServiceErrorType err = ConnectToServer(sdRef, flags, browse_request, handle_browse_response, callBack, context);
1118 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1119
1120 if (!domain) domain = "";
1121 len = sizeof(flags);
1122 len += sizeof(interfaceIndex);
1123 len += strlen(regtype) + 1;
1124 len += strlen(domain) + 1;
1125
1126 hdr = create_hdr(browse_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1127 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1128
1129 put_flags(flags, &ptr);
1130 put_uint32(interfaceIndex, &ptr);
1131 put_string(regtype, &ptr);
1132 put_string(domain, &ptr);
1133
1134 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1135 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1136 return err;
1137 }
1138
1139 DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain)
1140 {
1141 DNSServiceOp *tmp;
1142 char *ptr;
1143 size_t len = sizeof(flags) + strlen(domain) + 1;
1144 ipc_msg_hdr *hdr;
1145 DNSServiceErrorType err = ConnectToServer(&tmp, 0, setdomain_request, NULL, NULL, NULL);
1146 if (err) return err;
1147
1148 hdr = create_hdr(setdomain_request, &len, &ptr, 0, tmp);
1149 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
1150
1151 put_flags(flags, &ptr);
1152 put_string(domain, &ptr);
1153 err = deliver_request(hdr, tmp); // Will free hdr for us
1154 DNSServiceRefDeallocate(tmp);
1155 return err;
1156 }
1157
1158 static void handle_regservice_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
1159 {
1160 char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
1161 get_string(&data, end, name, 256);
1162 get_string(&data, end, regtype, kDNSServiceMaxDomainName);
1163 get_string(&data, end, domain, kDNSServiceMaxDomainName);
1164 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_regservice_response: error reading result from daemon");
1165 else ((DNSServiceRegisterReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_err, name, regtype, domain, sdr->AppContext);
1166 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1167 }
1168
1169 DNSServiceErrorType DNSSD_API DNSServiceRegister
1170 (
1171 DNSServiceRef *sdRef,
1172 DNSServiceFlags flags,
1173 uint32_t interfaceIndex,
1174 const char *name,
1175 const char *regtype,
1176 const char *domain,
1177 const char *host,
1178 uint16_t PortInNetworkByteOrder,
1179 uint16_t txtLen,
1180 const void *txtRecord,
1181 DNSServiceRegisterReply callBack,
1182 void *context
1183 )
1184 {
1185 char *ptr;
1186 size_t len;
1187 ipc_msg_hdr *hdr;
1188 DNSServiceErrorType err;
1189 union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder };
1190
1191 if (!name) name = "";
1192 if (!regtype) return kDNSServiceErr_BadParam;
1193 if (!domain) domain = "";
1194 if (!host) host = "";
1195 if (!txtRecord) txtRecord = (void*)"";
1196
1197 // No callback must have auto-rename
1198 if (!callBack && (flags & kDNSServiceFlagsNoAutoRename)) return kDNSServiceErr_BadParam;
1199
1200 err = ConnectToServer(sdRef, flags, reg_service_request, callBack ? handle_regservice_response : NULL, callBack, context);
1201 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1202
1203 len = sizeof(DNSServiceFlags);
1204 len += sizeof(uint32_t); // interfaceIndex
1205 len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4;
1206 len += 2 * sizeof(uint16_t); // port, txtLen
1207 len += txtLen;
1208
1209 hdr = create_hdr(reg_service_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1210 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1211 if (!callBack) hdr->ipc_flags |= IPC_FLAGS_NOREPLY;
1212
1213 put_flags(flags, &ptr);
1214 put_uint32(interfaceIndex, &ptr);
1215 put_string(name, &ptr);
1216 put_string(regtype, &ptr);
1217 put_string(domain, &ptr);
1218 put_string(host, &ptr);
1219 *ptr++ = port.b[0];
1220 *ptr++ = port.b[1];
1221 put_uint16(txtLen, &ptr);
1222 put_rdata(txtLen, txtRecord, &ptr);
1223
1224 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1225 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1226 return err;
1227 }
1228
1229 static void handle_enumeration_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
1230 {
1231 char domain[kDNSServiceMaxDomainName];
1232 get_string(&data, end, domain, kDNSServiceMaxDomainName);
1233 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_enumeration_response: error reading result from daemon");
1234 else ((DNSServiceDomainEnumReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, domain, sdr->AppContext);
1235 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1236 }
1237
1238 DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
1239 (
1240 DNSServiceRef *sdRef,
1241 DNSServiceFlags flags,
1242 uint32_t interfaceIndex,
1243 DNSServiceDomainEnumReply callBack,
1244 void *context
1245 )
1246 {
1247 char *ptr;
1248 size_t len;
1249 ipc_msg_hdr *hdr;
1250 DNSServiceErrorType err;
1251
1252 int f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0;
1253 int f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0;
1254 if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
1255
1256 err = ConnectToServer(sdRef, flags, enumeration_request, handle_enumeration_response, callBack, context);
1257 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1258
1259 len = sizeof(DNSServiceFlags);
1260 len += sizeof(uint32_t);
1261
1262 hdr = create_hdr(enumeration_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1263 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1264
1265 put_flags(flags, &ptr);
1266 put_uint32(interfaceIndex, &ptr);
1267
1268 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1269 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1270 return err;
1271 }
1272
1273 static void ConnectionResponse(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
1274 {
1275 DNSRecordRef rref = cbh->ipc_hdr.client_context.context;
1276 (void)data; // Unused
1277
1278 //printf("ConnectionResponse got %d\n", cbh->ipc_hdr.op);
1279 if (cbh->ipc_hdr.op != reg_record_reply_op)
1280 {
1281 // When using kDNSServiceFlagsShareConnection, need to search the list of associated DNSServiceOps
1282 // to find the one this response is intended for, and then call through to its ProcessReply handler
1283 while (sdr && (sdr->uid.u32[0] != cbh->ipc_hdr.client_context.u32[0] || sdr->uid.u32[1] != cbh->ipc_hdr.client_context.u32[1]))
1284 sdr = sdr->next;
1285 // NOTE: We may sometimes not find a matching DNSServiceOp, in the case where the client has
1286 // cancelled the subordinate DNSServiceOp, but there are still messages in the pipeline from the daemon
1287 if (sdr && sdr->ProcessReply) sdr->ProcessReply(sdr, cbh, data, end);
1288 // WARNING: Don't touch sdr after this -- client may have called DNSServiceRefDeallocate
1289 return;
1290 }
1291
1292 if (sdr->op == connection_request)
1293 rref->AppCallback(rref->sdr, rref, cbh->cb_flags, cbh->cb_err, rref->AppContext);
1294 else
1295 {
1296 syslog(LOG_WARNING, "dnssd_clientstub handle_regrecord_response: sdr->op != connection_request");
1297 rref->AppCallback(rref->sdr, rref, 0, kDNSServiceErr_Unknown, rref->AppContext);
1298 }
1299 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1300 }
1301
1302 DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef)
1303 {
1304 char *ptr;
1305 size_t len = 0;
1306 ipc_msg_hdr *hdr;
1307 DNSServiceErrorType err = ConnectToServer(sdRef, 0, connection_request, ConnectionResponse, NULL, NULL);
1308 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1309
1310 hdr = create_hdr(connection_request, &len, &ptr, 0, *sdRef);
1311 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1312
1313 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1314 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1315 return err;
1316 }
1317
1318 DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
1319 (
1320 DNSServiceRef sdRef,
1321 DNSRecordRef *RecordRef,
1322 DNSServiceFlags flags,
1323 uint32_t interfaceIndex,
1324 const char *fullname,
1325 uint16_t rrtype,
1326 uint16_t rrclass,
1327 uint16_t rdlen,
1328 const void *rdata,
1329 uint32_t ttl,
1330 DNSServiceRegisterRecordReply callBack,
1331 void *context
1332 )
1333 {
1334 char *ptr;
1335 size_t len;
1336 ipc_msg_hdr *hdr = NULL;
1337 DNSRecordRef rref = NULL;
1338 int f1 = (flags & kDNSServiceFlagsShared) != 0;
1339 int f2 = (flags & kDNSServiceFlagsUnique) != 0;
1340 if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
1341
1342 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
1343
1344 if (!DNSServiceRefValid(sdRef))
1345 {
1346 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
1347 return kDNSServiceErr_BadReference;
1348 }
1349
1350 if (sdRef->op != connection_request)
1351 {
1352 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with non-DNSServiceCreateConnection DNSServiceRef %p %d", sdRef, sdRef->op);
1353 return kDNSServiceErr_BadReference;
1354 }
1355
1356 *RecordRef = NULL;
1357
1358 len = sizeof(DNSServiceFlags);
1359 len += 2 * sizeof(uint32_t); // interfaceIndex, ttl
1360 len += 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen
1361 len += strlen(fullname) + 1;
1362 len += rdlen;
1363
1364 hdr = create_hdr(reg_record_request, &len, &ptr, 1, sdRef);
1365 if (!hdr) return kDNSServiceErr_NoMemory;
1366
1367 put_flags(flags, &ptr);
1368 put_uint32(interfaceIndex, &ptr);
1369 put_string(fullname, &ptr);
1370 put_uint16(rrtype, &ptr);
1371 put_uint16(rrclass, &ptr);
1372 put_uint16(rdlen, &ptr);
1373 put_rdata(rdlen, rdata, &ptr);
1374 put_uint32(ttl, &ptr);
1375
1376 rref = malloc(sizeof(DNSRecord));
1377 if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; }
1378 rref->AppContext = context;
1379 rref->AppCallback = callBack;
1380 rref->record_index = sdRef->max_index++;
1381 rref->sdr = sdRef;
1382 *RecordRef = rref;
1383 hdr->client_context.context = rref;
1384 hdr->reg_index = rref->record_index;
1385
1386 return deliver_request(hdr, sdRef); // Will free hdr for us
1387 }
1388
1389 // sdRef returned by DNSServiceRegister()
1390 DNSServiceErrorType DNSSD_API DNSServiceAddRecord
1391 (
1392 DNSServiceRef sdRef,
1393 DNSRecordRef *RecordRef,
1394 DNSServiceFlags flags,
1395 uint16_t rrtype,
1396 uint16_t rdlen,
1397 const void *rdata,
1398 uint32_t ttl
1399 )
1400 {
1401 ipc_msg_hdr *hdr;
1402 size_t len = 0;
1403 char *ptr;
1404 DNSRecordRef rref;
1405
1406 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
1407 if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSRecordRef pointer"); return kDNSServiceErr_BadParam; }
1408 if (sdRef->op != reg_service_request)
1409 {
1410 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with non-DNSServiceRegister DNSServiceRef %p %d", sdRef, sdRef->op);
1411 return kDNSServiceErr_BadReference;
1412 }
1413
1414 if (!DNSServiceRefValid(sdRef))
1415 {
1416 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
1417 return kDNSServiceErr_BadReference;
1418 }
1419
1420 *RecordRef = NULL;
1421
1422 len += 2 * sizeof(uint16_t); // rrtype, rdlen
1423 len += rdlen;
1424 len += sizeof(uint32_t);
1425 len += sizeof(DNSServiceFlags);
1426
1427 hdr = create_hdr(add_record_request, &len, &ptr, 1, sdRef);
1428 if (!hdr) return kDNSServiceErr_NoMemory;
1429 put_flags(flags, &ptr);
1430 put_uint16(rrtype, &ptr);
1431 put_uint16(rdlen, &ptr);
1432 put_rdata(rdlen, rdata, &ptr);
1433 put_uint32(ttl, &ptr);
1434
1435 rref = malloc(sizeof(DNSRecord));
1436 if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; }
1437 rref->AppContext = NULL;
1438 rref->AppCallback = NULL;
1439 rref->record_index = sdRef->max_index++;
1440 rref->sdr = sdRef;
1441 *RecordRef = rref;
1442 hdr->client_context.context = rref;
1443 hdr->reg_index = rref->record_index;
1444
1445 return deliver_request(hdr, sdRef); // Will free hdr for us
1446 }
1447
1448 // DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
1449 DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
1450 (
1451 DNSServiceRef sdRef,
1452 DNSRecordRef RecordRef,
1453 DNSServiceFlags flags,
1454 uint16_t rdlen,
1455 const void *rdata,
1456 uint32_t ttl
1457 )
1458 {
1459 ipc_msg_hdr *hdr;
1460 size_t len = 0;
1461 char *ptr;
1462
1463 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
1464
1465 if (!DNSServiceRefValid(sdRef))
1466 {
1467 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
1468 return kDNSServiceErr_BadReference;
1469 }
1470
1471 // Note: RecordRef is allowed to be NULL
1472
1473 len += sizeof(uint16_t);
1474 len += rdlen;
1475 len += sizeof(uint32_t);
1476 len += sizeof(DNSServiceFlags);
1477
1478 hdr = create_hdr(update_record_request, &len, &ptr, 1, sdRef);
1479 if (!hdr) return kDNSServiceErr_NoMemory;
1480 hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX;
1481 put_flags(flags, &ptr);
1482 put_uint16(rdlen, &ptr);
1483 put_rdata(rdlen, rdata, &ptr);
1484 put_uint32(ttl, &ptr);
1485 return deliver_request(hdr, sdRef); // Will free hdr for us
1486 }
1487
1488 DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
1489 (
1490 DNSServiceRef sdRef,
1491 DNSRecordRef RecordRef,
1492 DNSServiceFlags flags
1493 )
1494 {
1495 ipc_msg_hdr *hdr;
1496 size_t len = 0;
1497 char *ptr;
1498 DNSServiceErrorType err;
1499
1500 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
1501 if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSRecordRef"); return kDNSServiceErr_BadParam; }
1502 if (!sdRef->max_index) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with bad DNSServiceRef"); return kDNSServiceErr_BadReference; }
1503
1504 if (!DNSServiceRefValid(sdRef))
1505 {
1506 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
1507 return kDNSServiceErr_BadReference;
1508 }
1509
1510 len += sizeof(flags);
1511 hdr = create_hdr(remove_record_request, &len, &ptr, 1, sdRef);
1512 if (!hdr) return kDNSServiceErr_NoMemory;
1513 hdr->reg_index = RecordRef->record_index;
1514 put_flags(flags, &ptr);
1515 err = deliver_request(hdr, sdRef); // Will free hdr for us
1516 if (!err) free(RecordRef);
1517 return err;
1518 }
1519
1520 DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
1521 (
1522 DNSServiceFlags flags,
1523 uint32_t interfaceIndex,
1524 const char *fullname,
1525 uint16_t rrtype,
1526 uint16_t rrclass,
1527 uint16_t rdlen,
1528 const void *rdata
1529 )
1530 {
1531 char *ptr;
1532 size_t len;
1533 ipc_msg_hdr *hdr;
1534 DNSServiceOp *tmp;
1535
1536 DNSServiceErrorType err = ConnectToServer(&tmp, flags, reconfirm_record_request, NULL, NULL, NULL);
1537 if (err) return err;
1538
1539 len = sizeof(DNSServiceFlags);
1540 len += sizeof(uint32_t);
1541 len += strlen(fullname) + 1;
1542 len += 3 * sizeof(uint16_t);
1543 len += rdlen;
1544 hdr = create_hdr(reconfirm_record_request, &len, &ptr, 0, tmp);
1545 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
1546
1547 put_flags(flags, &ptr);
1548 put_uint32(interfaceIndex, &ptr);
1549 put_string(fullname, &ptr);
1550 put_uint16(rrtype, &ptr);
1551 put_uint16(rrclass, &ptr);
1552 put_uint16(rdlen, &ptr);
1553 put_rdata(rdlen, rdata, &ptr);
1554
1555 err = deliver_request(hdr, tmp); // Will free hdr for us
1556 DNSServiceRefDeallocate(tmp);
1557 return err;
1558 }
1559
1560 static void handle_port_mapping_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end)
1561 {
1562 union { uint32_t l; u_char b[4]; } addr;
1563 uint8_t protocol = 0;
1564 union { uint16_t s; u_char b[2]; } privatePort;
1565 union { uint16_t s; u_char b[2]; } publicPort;
1566 uint32_t ttl = 0;
1567
1568 if (data + 13 > end) data = NULL;
1569 else
1570 {
1571 addr .b[0] = *data++;
1572 addr .b[1] = *data++;
1573 addr .b[2] = *data++;
1574 addr .b[3] = *data++;
1575 protocol = *data++;
1576 privatePort.b[0] = *data++;
1577 privatePort.b[1] = *data++;
1578 publicPort .b[0] = *data++;
1579 publicPort .b[1] = *data++;
1580 ttl = get_uint32(&data, end);
1581 }
1582
1583 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_port_mapping_response: error reading result from daemon");
1584 else ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, addr.l, protocol, privatePort.s, publicPort.s, ttl, sdr->AppContext);
1585 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1586 }
1587
1588 DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
1589 (
1590 DNSServiceRef *sdRef,
1591 DNSServiceFlags flags,
1592 uint32_t interfaceIndex,
1593 uint32_t protocol, /* TCP and/or UDP */
1594 uint16_t privatePortInNetworkByteOrder,
1595 uint16_t publicPortInNetworkByteOrder,
1596 uint32_t ttl, /* time to live in seconds */
1597 DNSServiceNATPortMappingReply callBack,
1598 void *context /* may be NULL */
1599 )
1600 {
1601 char *ptr;
1602 size_t len;
1603 ipc_msg_hdr *hdr;
1604 union { uint16_t s; u_char b[2]; } privatePort = { privatePortInNetworkByteOrder };
1605 union { uint16_t s; u_char b[2]; } publicPort = { publicPortInNetworkByteOrder };
1606
1607 DNSServiceErrorType err = ConnectToServer(sdRef, flags, port_mapping_request, handle_port_mapping_response, callBack, context);
1608 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1609
1610 len = sizeof(flags);
1611 len += sizeof(interfaceIndex);
1612 len += sizeof(protocol);
1613 len += sizeof(privatePort);
1614 len += sizeof(publicPort);
1615 len += sizeof(ttl);
1616
1617 hdr = create_hdr(port_mapping_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1618 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1619
1620 put_flags(flags, &ptr);
1621 put_uint32(interfaceIndex, &ptr);
1622 put_uint32(protocol, &ptr);
1623 *ptr++ = privatePort.b[0];
1624 *ptr++ = privatePort.b[1];
1625 *ptr++ = publicPort .b[0];
1626 *ptr++ = publicPort .b[1];
1627 put_uint32(ttl, &ptr);
1628
1629 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1630 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1631 return err;
1632 }