]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSShared/dnssd_clientstub.c
mDNSResponder-107.4.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.45 2005/02/01 01:25:06 shersche
32 Define sleep() to be Sleep() for Windows compatibility
33
34 Revision 1.44 2005/01/27 22:57:56 cheshire
35 Fix compile errors on gcc4
36
37 Revision 1.43 2005/01/27 00:02:29 cheshire
38 <rdar://problem/3947461> Handle case where client runs before daemon has finished launching
39
40 Revision 1.42 2005/01/11 02:01:02 shersche
41 Use dnssd_close() rather than close() for Windows compatibility
42
43 Revision 1.41 2004/12/23 17:34:26 ksekar
44 <rdar://problem/3931319> Calls leak sockets if mDNSResponder is not running
45
46 Revision 1.40 2004/11/23 03:39:47 cheshire
47 Let interface name/index mapping capability live directly in JNISupport.c,
48 instead of having to call through to the daemon via IPC to get this information.
49
50 Revision 1.39 2004/11/12 03:22:00 rpantos
51 rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
52
53 Revision 1.38 2004/11/02 02:51:23 cheshire
54 <rdar://problem/3526342> Remove overly-restrictive flag checks
55
56 Revision 1.37 2004/10/14 01:43:35 cheshire
57 Fix opaque port passing problem
58
59 Revision 1.36 2004/10/06 02:22:19 cheshire
60 Changed MacRoman copyright symbol (should have been UTF-8 in any case :-) to ASCII-compatible "(c)"
61
62 Revision 1.35 2004/10/01 22:15:55 rpantos
63 rdar://problem/3824265: Replace APSL in client lib with BSD license.
64
65 Revision 1.34 2004/09/17 22:36:13 cheshire
66 Add comment explaining that deliver_request frees the message it sends
67
68 Revision 1.33 2004/09/17 01:17:31 ksekar
69 Remove double-free of msg header, freed automatically by deliver_request()
70
71 Revision 1.32 2004/09/17 01:08:55 cheshire
72 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
73 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
74 declared in that file are ONLY appropriate to single-address-space embedded applications.
75 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
76
77 Revision 1.31 2004/09/16 23:37:19 cheshire
78 Free hdr before returning
79
80 Revision 1.30 2004/09/16 23:14:24 cheshire
81 Changes for Windows compatibility
82
83 Revision 1.29 2004/09/16 21:46:38 ksekar
84 <rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area domain
85
86 Revision 1.28 2004/08/11 17:10:04 cheshire
87 Fix signed/unsigned warnings
88
89 Revision 1.27 2004/08/11 00:54:16 cheshire
90 Change "hdr->op.request_op" to just "hdr->op"
91
92 Revision 1.26 2004/07/26 06:07:27 shersche
93 fix bugs when using an error socket to communicate with the daemon
94
95 Revision 1.25 2004/07/26 05:54:02 shersche
96 DNSServiceProcessResult() returns NoError if socket read returns EWOULDBLOCK
97
98 Revision 1.24 2004/07/20 06:46:21 shersche
99 <rdar://problem/3730123> fix endless loop in my_read() if recv returns 0
100 Bug #: 3730123
101
102 Revision 1.23 2004/06/29 00:48:38 cheshire
103 Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
104 use an explicit while() loop instead.
105
106 Revision 1.22 2004/06/26 03:16:34 shersche
107 clean up warning messages on Win32 platform
108
109 Submitted by: herscher
110
111 Revision 1.21 2004/06/18 04:53:56 rpantos
112 Use platform layer for socket types. Introduce USE_TCP_LOOPBACK. Remove dependency on mDNSEmbeddedAPI.h.
113
114 Revision 1.20 2004/06/12 00:50:22 cheshire
115 Changes for Windows compatibility
116
117 Revision 1.19 2004/05/25 18:29:33 cheshire
118 Move DNSServiceConstructFullName() from dnssd_clientstub.c to dnssd_clientlib.c,
119 so that it's also accessible to dnssd_clientshim.c (single address space) clients.
120
121 Revision 1.18 2004/05/18 23:51:27 cheshire
122 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
123
124 Revision 1.17 2004/05/06 18:42:58 ksekar
125 General dns_sd.h API cleanup, including the following radars:
126 <rdar://problem/3592068>: Remove flags with zero value
127 <rdar://problem/3479569>: Passing in NULL causes a crash.
128
129 Revision 1.16 2004/03/12 22:00:37 cheshire
130 Added: #include <sys/socket.h>
131
132 Revision 1.15 2004/01/20 18:36:29 ksekar
133 Propagated Libinfo fix for <rdar://problem/3483971>: SU:
134 DNSServiceUpdateRecord() doesn't allow you to update the TXT record
135 into TOT mDNSResponder.
136
137 Revision 1.14 2004/01/19 22:39:17 cheshire
138 Don't use "MSG_WAITALL"; it makes send() return "Invalid argument" on Linux;
139 use an explicit while() loop instead. (In any case, this should only make a difference
140 with non-blocking sockets, which we don't use on the client side right now.)
141
142 Revision 1.13 2004/01/19 21:46:52 cheshire
143 Fix compiler warning
144
145 Revision 1.12 2003/12/23 20:46:47 ksekar
146 <rdar://problem/3497428>: sync dnssd files between libinfo & mDNSResponder
147
148 Revision 1.11 2003/12/08 21:11:42 rpantos
149 Changes necessary to support mDNSResponder on Linux.
150
151 Revision 1.10 2003/10/13 23:50:53 ksekar
152 Updated dns_sd clientstub files to bring copies in synch with
153 top-of-tree Libinfo: A memory leak in dnssd_clientstub.c is fixed,
154 and comments in dns_sd.h are improved.
155
156 Revision 1.9 2003/08/15 21:30:39 cheshire
157 Bring up to date with LibInfo version
158
159 Revision 1.8 2003/08/13 23:54:52 ksekar
160 Bringing dnssd_clientstub.c up to date with Libinfo, per radar 3376640
161
162 Revision 1.7 2003/08/12 19:56:25 cheshire
163 Update to APSL 2.0
164
165 */
166
167 #include <errno.h>
168 #include <stdlib.h>
169 #if defined(_WIN32)
170 #include <winsock2.h>
171 #include <windows.h>
172 #define sockaddr_mdns sockaddr_in
173 #define AF_MDNS AF_INET
174 #else
175 #include <sys/time.h>
176 #include <sys/socket.h>
177 #define sockaddr_mdns sockaddr_un
178 #define AF_MDNS AF_LOCAL
179 #endif
180
181 #include "dnssd_ipc.h"
182
183 #if defined(_WIN32)
184 // disable warning: "'type cast' : from data pointer 'void *' to
185 // function pointer"
186 #pragma warning(disable:4055)
187
188 // disable warning: "nonstandard extension, function/data pointer
189 // conversion in expression"
190 #pragma warning(disable:4152)
191
192 #define sleep(X) Sleep((X) * 1000)
193
194 static int g_initWinsock = 0;
195 #endif
196
197
198 #define CTL_PATH_PREFIX "/tmp/dnssd_clippath."
199 // error socket (if needed) is named "dnssd_clipath.[pid].xxx:n" where xxx are the
200 // last 3 digits of the time (in seconds) and n is the 6-digit microsecond time
201
202 // general utility functions
203 typedef struct _DNSServiceRef_t
204 {
205 dnssd_sock_t sockfd; // connected socket between client and daemon
206 uint32_t op; // request_op_t or reply_op_t
207 process_reply_callback process_reply;
208 void *app_callback;
209 void *app_context;
210 uint32_t max_index; //largest assigned record index - 0 if no additl. recs registered
211 } _DNSServiceRef_t;
212
213 typedef struct _DNSRecordRef_t
214 {
215 void *app_context;
216 DNSServiceRegisterRecordReply app_callback;
217 DNSRecordRef recref;
218 uint32_t record_index; // index is unique to the ServiceDiscoveryRef
219 DNSServiceRef sdr;
220 } _DNSRecordRef_t;
221
222 // exported functions
223
224 // write len bytes. return 0 on success, -1 on error
225 static int my_write(dnssd_sock_t sd, char *buf, int len)
226 {
227 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
228 //if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
229 while (len)
230 {
231 ssize_t num_written = send(sd, buf, len, 0);
232 if (num_written < 0 || num_written > len) return -1;
233 buf += num_written;
234 len -= num_written;
235 }
236 return 0;
237 }
238
239 // read len bytes. return 0 on success, -1 on error
240 static int my_read(dnssd_sock_t sd, char *buf, int len)
241 {
242 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
243 //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1;
244 while (len)
245 {
246 ssize_t num_read = recv(sd, buf, len, 0);
247 if ((num_read == 0) || (num_read < 0) || (num_read > len)) return -1;
248 buf += num_read;
249 len -= num_read;
250 }
251 return 0;
252 }
253
254 /* create_hdr
255 *
256 * allocate and initialize an ipc message header. value of len should initially be the
257 * length of the data, and is set to the value of the data plus the header. data_start
258 * is set to point to the beginning of the data section. reuse_socket should be non-zero
259 * for calls that can receive an immediate error return value on their primary socket.
260 * if zero, the path to a control socket is appended at the beginning of the message buffer.
261 * data_start is set past this string.
262 */
263
264 static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int reuse_socket)
265 {
266 char *msg = NULL;
267 ipc_msg_hdr *hdr;
268 int datalen;
269 char ctrl_path[256];
270
271 if (!reuse_socket)
272 {
273 #if defined(USE_TCP_LOOPBACK)
274 *len += 2; // Allocate space for two-byte port number
275 #else
276 struct timeval time;
277 if (gettimeofday(&time, NULL) < 0) return NULL;
278 sprintf(ctrl_path, "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(),
279 (unsigned long)(time.tv_sec & 0xFFF), (unsigned long)(time.tv_usec));
280 *len += strlen(ctrl_path) + 1;
281 #endif
282 }
283
284 datalen = (int) *len;
285 *len += sizeof(ipc_msg_hdr);
286
287 // write message to buffer
288 msg = malloc(*len);
289 if (!msg) return NULL;
290
291 bzero(msg, *len);
292 hdr = (void *)msg;
293 hdr->datalen = datalen;
294 hdr->version = VERSION;
295 hdr->op = op;
296 if (reuse_socket) hdr->flags |= IPC_FLAGS_REUSE_SOCKET;
297 *data_start = msg + sizeof(ipc_msg_hdr);
298 #if defined(USE_TCP_LOOPBACK)
299 // Put dummy data in for the port, since we don't know what
300 // it is yet. The data will get filled in before we
301 // send the message. This happens in deliver_request().
302 if (!reuse_socket) put_short(0, data_start);
303 #else
304 if (!reuse_socket) put_string(ctrl_path, data_start);
305 #endif
306 return hdr;
307 }
308
309 // return a connected service ref (deallocate with DNSServiceRefDeallocate)
310 static DNSServiceRef connect_to_server(void)
311 {
312 dnssd_sockaddr_t saddr;
313 DNSServiceRef sdr;
314 int NumTries = 0;
315
316 #if defined(_WIN32)
317 if (!g_initWinsock)
318 {
319 WSADATA wsaData;
320 DNSServiceErrorType err;
321
322 g_initWinsock = 1;
323
324 err = WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
325
326 if (err != 0) return NULL;
327 }
328 #endif
329
330 sdr = malloc(sizeof(_DNSServiceRef_t));
331 if (!sdr) return(NULL);
332 sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0);
333 if (sdr->sockfd == dnssd_InvalidSocket) { free(sdr); return NULL; }
334 #if defined(USE_TCP_LOOPBACK)
335 saddr.sin_family = AF_INET;
336 saddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
337 saddr.sin_port = htons(MDNS_TCP_SERVERPORT);
338 #else
339 saddr.sun_family = AF_LOCAL;
340 strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH);
341 #endif
342 while (1)
343 {
344 int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
345 if (!err) break; // If we succeeded, return sdr
346 // If we failed, then it may be because the daemon is still launching.
347 // This can happen for processes that launch early in the boot process, while the
348 // daemon is still coming up. Rather than fail here, we'll wait a bit and try again.
349 // If, after ten seconds, we still can't connect to the daemon,
350 // then we give up and return a failure code.
351 if (++NumTries < 10)
352 sleep(1); // Sleep a bit, then try again
353 else
354 {
355 dnssd_close(sdr->sockfd);
356 sdr->sockfd = dnssd_InvalidSocket;
357 free(sdr);
358 return NULL;
359 }
360 }
361 return sdr;
362 }
363
364 static DNSServiceErrorType deliver_request(void *msg, DNSServiceRef sdr, int reuse_sd)
365 {
366 ipc_msg_hdr *hdr = msg;
367 uint32_t datalen = hdr->datalen;
368 dnssd_sockaddr_t caddr, daddr; // (client and daemon address structs)
369 char *data = (char *)msg + sizeof(ipc_msg_hdr);
370 dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
371 int ret;
372 unsigned int len = sizeof(caddr);
373 DNSServiceErrorType err = kDNSServiceErr_Unknown;
374
375 if (!hdr || sdr->sockfd < 0) return kDNSServiceErr_Unknown;
376
377 if (!reuse_sd)
378 {
379 // setup temporary error socket
380 if ((listenfd = socket(AF_DNSSD, SOCK_STREAM, 0)) < 0)
381 goto cleanup;
382 bzero(&caddr, sizeof(caddr));
383
384 #if defined(USE_TCP_LOOPBACK)
385 {
386 union { uint16_t s; u_char b[2]; } port;
387 caddr.sin_family = AF_INET;
388 caddr.sin_port = 0;
389 caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
390 ret = bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr));
391 if (ret < 0) goto cleanup;
392 if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) goto cleanup;
393 listen(listenfd, 1);
394 port.s = caddr.sin_port;
395 data[0] = port.b[0]; // don't switch the byte order, as the
396 data[1] = port.b[1]; // daemon expects it in network byte order
397 }
398 #else
399 {
400 mode_t mask = umask(0);
401 caddr.sun_family = AF_LOCAL;
402 #ifndef NOT_HAVE_SA_LEN // According to Stevens (section 3.2), there is no portable way to
403 // determine whether sa_len is defined on a particular platform.
404 caddr.sun_len = sizeof(struct sockaddr_un);
405 #endif
406 strcpy(caddr.sun_path, data);
407 ret = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr));
408 umask(mask);
409 if (ret < 0) goto cleanup;
410 listen(listenfd, 1);
411 }
412 #endif
413 }
414
415 ConvertHeaderBytes(hdr);
416 if (my_write(sdr->sockfd, msg, datalen + sizeof(ipc_msg_hdr)) < 0)
417 goto cleanup;
418 free(msg);
419 msg = NULL;
420
421 if (reuse_sd) errsd = sdr->sockfd;
422 else
423 {
424 len = sizeof(daddr);
425 errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
426 if (errsd < 0) goto cleanup;
427 }
428
429 if (my_read(errsd, (char*)&err, (int)sizeof(err)) < 0)
430 err = kDNSServiceErr_Unknown;
431 else
432 err = ntohl(err);
433
434 cleanup:
435 if (!reuse_sd && listenfd > 0) dnssd_close(listenfd);
436 if (!reuse_sd && errsd > 0) dnssd_close(errsd);
437 #if !defined(USE_TCP_LOOPBACK)
438 if (!reuse_sd && data) unlink(data);
439 #endif
440 if (msg) free(msg);
441 return err;
442 }
443
444 int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef)
445 {
446 if (!sdRef) return -1;
447 return (int) sdRef->sockfd;
448 }
449
450 // handle reply from server, calling application client callback. If there is no reply
451 // from the daemon on the socket contained in sdRef, the call will block.
452 DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
453 {
454 ipc_msg_hdr hdr;
455 char *data;
456
457 if (!sdRef || sdRef->sockfd < 0 || !sdRef->process_reply)
458 return kDNSServiceErr_BadReference;
459
460 if (my_read(sdRef->sockfd, (void *)&hdr, sizeof(hdr)) < 0)
461 // return NoError on EWOULDBLOCK. This will handle the case
462 // where a non-blocking socket is told there is data, but
463 // it was a false positive.
464 return (dnssd_errno() == dnssd_EWOULDBLOCK) ? kDNSServiceErr_NoError : kDNSServiceErr_Unknown;
465 ConvertHeaderBytes(&hdr);
466 if (hdr.version != VERSION)
467 return kDNSServiceErr_Incompatible;
468 data = malloc(hdr.datalen);
469 if (!data) return kDNSServiceErr_NoMemory;
470 if (my_read(sdRef->sockfd, data, hdr.datalen) < 0)
471 return kDNSServiceErr_Unknown;
472 sdRef->process_reply(sdRef, &hdr, data);
473 free(data);
474 return kDNSServiceErr_NoError;
475 }
476
477 void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef)
478 {
479 if (!sdRef) return;
480 if (sdRef->sockfd > 0) dnssd_close(sdRef->sockfd);
481 free(sdRef);
482 }
483
484 static void handle_resolve_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
485 {
486 DNSServiceFlags flags;
487 char fullname[kDNSServiceMaxDomainName];
488 char target[kDNSServiceMaxDomainName];
489 uint16_t txtlen;
490 union { uint16_t s; u_char b[2]; } port;
491 uint32_t ifi;
492 DNSServiceErrorType err;
493 char *txtrecord;
494 int str_error = 0;
495 (void)hdr; //unused
496
497 flags = get_flags(&data);
498 ifi = get_long(&data);
499 err = get_error_code(&data);
500 if (get_string(&data, fullname, kDNSServiceMaxDomainName) < 0) str_error = 1;
501 if (get_string(&data, target, kDNSServiceMaxDomainName) < 0) str_error = 1;
502 port.b[0] = *data++;
503 port.b[1] = *data++;
504 txtlen = get_short(&data);
505 txtrecord = get_rdata(&data, txtlen);
506
507 if (!err && str_error) err = kDNSServiceErr_Unknown;
508 ((DNSServiceResolveReply)sdr->app_callback)(sdr, flags, ifi, err, fullname, target, port.s, txtlen, txtrecord, sdr->app_context);
509 }
510
511 DNSServiceErrorType DNSSD_API DNSServiceResolve
512 (
513 DNSServiceRef *sdRef,
514 DNSServiceFlags flags,
515 uint32_t interfaceIndex,
516 const char *name,
517 const char *regtype,
518 const char *domain,
519 DNSServiceResolveReply callBack,
520 void *context
521 )
522 {
523 char *msg = NULL, *ptr;
524 size_t len;
525 ipc_msg_hdr *hdr;
526 DNSServiceRef sdr;
527 DNSServiceErrorType err;
528
529 if (!sdRef) return kDNSServiceErr_BadParam;
530 *sdRef = NULL;
531
532 if (!name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam;
533
534 // calculate total message length
535 len = sizeof(flags);
536 len += sizeof(interfaceIndex);
537 len += strlen(name) + 1;
538 len += strlen(regtype) + 1;
539 len += strlen(domain) + 1;
540
541 hdr = create_hdr(resolve_request, &len, &ptr, 1);
542 if (!hdr) goto error;
543 msg = (void *)hdr;
544
545 put_flags(flags, &ptr);
546 put_long(interfaceIndex, &ptr);
547 put_string(name, &ptr);
548 put_string(regtype, &ptr);
549 put_string(domain, &ptr);
550
551 sdr = connect_to_server();
552 if (!sdr) goto error;
553 err = deliver_request(msg, sdr, 1);
554 if (err)
555 {
556 DNSServiceRefDeallocate(sdr);
557 return err;
558 }
559 sdr->op = resolve_request;
560 sdr->process_reply = handle_resolve_response;
561 sdr->app_callback = callBack;
562 sdr->app_context = context;
563 *sdRef = sdr;
564
565 return err;
566
567 error:
568 if (msg) free(msg);
569 if (*sdRef) { free(*sdRef); *sdRef = NULL; }
570 return kDNSServiceErr_Unknown;
571 }
572
573 static void handle_query_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
574 {
575 DNSServiceFlags flags;
576 uint32_t interfaceIndex, ttl;
577 DNSServiceErrorType errorCode;
578 char name[kDNSServiceMaxDomainName];
579 uint16_t rrtype, rrclass, rdlen;
580 char *rdata;
581 int str_error = 0;
582 (void)hdr;//Unused
583
584 flags = get_flags(&data);
585 interfaceIndex = get_long(&data);
586 errorCode = get_error_code(&data);
587 if (get_string(&data, name, kDNSServiceMaxDomainName) < 0) str_error = 1;
588 rrtype = get_short(&data);
589 rrclass = get_short(&data);
590 rdlen = get_short(&data);
591 rdata = get_rdata(&data, rdlen);
592 ttl = get_long(&data);
593
594 if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown;
595 ((DNSServiceQueryRecordReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, name, rrtype, rrclass,
596 rdlen, rdata, ttl, sdr->app_context);
597 return;
598 }
599
600 DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
601 (
602 DNSServiceRef *sdRef,
603 DNSServiceFlags flags,
604 uint32_t interfaceIndex,
605 const char *name,
606 uint16_t rrtype,
607 uint16_t rrclass,
608 DNSServiceQueryRecordReply callBack,
609 void *context
610 )
611 {
612 char *msg = NULL, *ptr;
613 size_t len;
614 ipc_msg_hdr *hdr;
615 DNSServiceRef sdr;
616 DNSServiceErrorType err;
617
618 if (!sdRef) return kDNSServiceErr_BadParam;
619 *sdRef = NULL;
620
621 if (!name) name = "\0";
622
623 // calculate total message length
624 len = sizeof(flags);
625 len += sizeof(uint32_t); //interfaceIndex
626 len += strlen(name) + 1;
627 len += 2 * sizeof(uint16_t); // rrtype, rrclass
628
629 hdr = create_hdr(query_request, &len, &ptr, 1);
630 if (!hdr) goto error;
631 msg = (void *)hdr;
632
633 put_flags(flags, &ptr);
634 put_long(interfaceIndex, &ptr);
635 put_string(name, &ptr);
636 put_short(rrtype, &ptr);
637 put_short(rrclass, &ptr);
638
639 sdr = connect_to_server();
640 if (!sdr) goto error;
641 err = deliver_request(msg, sdr, 1);
642 if (err)
643 {
644 DNSServiceRefDeallocate(sdr);
645 return err;
646 }
647
648 sdr->op = query_request;
649 sdr->process_reply = handle_query_response;
650 sdr->app_callback = callBack;
651 sdr->app_context = context;
652 *sdRef = sdr;
653 return err;
654
655 error:
656 if (msg) free(msg);
657 if (*sdRef) { free(*sdRef); *sdRef = NULL; }
658 return kDNSServiceErr_Unknown;
659 }
660
661 static void handle_browse_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
662 {
663 DNSServiceFlags flags;
664 uint32_t interfaceIndex;
665 DNSServiceErrorType errorCode;
666 char replyName[256], replyType[kDNSServiceMaxDomainName],
667 replyDomain[kDNSServiceMaxDomainName];
668 int str_error = 0;
669 (void)hdr;//Unused
670
671 flags = get_flags(&data);
672 interfaceIndex = get_long(&data);
673 errorCode = get_error_code(&data);
674 if (get_string(&data, replyName, 256) < 0) str_error = 1;
675 if (get_string(&data, replyType, kDNSServiceMaxDomainName) < 0) str_error = 1;
676 if (get_string(&data, replyDomain, kDNSServiceMaxDomainName) < 0) str_error = 1;
677 if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown;
678 ((DNSServiceBrowseReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, replyName, replyType, replyDomain, sdr->app_context);
679 }
680
681 DNSServiceErrorType DNSSD_API DNSServiceBrowse
682 (
683 DNSServiceRef *sdRef,
684 DNSServiceFlags flags,
685 uint32_t interfaceIndex,
686 const char *regtype,
687 const char *domain,
688 DNSServiceBrowseReply callBack,
689 void *context
690 )
691 {
692 char *msg = NULL, *ptr;
693 size_t len;
694 ipc_msg_hdr *hdr;
695 DNSServiceRef sdr;
696 DNSServiceErrorType err;
697
698 if (!sdRef) return kDNSServiceErr_BadParam;
699 *sdRef = NULL;
700
701 if (!domain) domain = "";
702
703 len = sizeof(flags);
704 len += sizeof(interfaceIndex);
705 len += strlen(regtype) + 1;
706 len += strlen(domain) + 1;
707
708 hdr = create_hdr(browse_request, &len, &ptr, 1);
709 if (!hdr) goto error;
710 msg = (char *)hdr;
711 put_flags(flags, &ptr);
712 put_long(interfaceIndex, &ptr);
713 put_string(regtype, &ptr);
714 put_string(domain, &ptr);
715
716 sdr = connect_to_server();
717 if (!sdr) goto error;
718 err = deliver_request(msg, sdr, 1);
719 if (err)
720 {
721 DNSServiceRefDeallocate(sdr);
722 return err;
723 }
724 sdr->op = browse_request;
725 sdr->process_reply = handle_browse_response;
726 sdr->app_callback = callBack;
727 sdr->app_context = context;
728 *sdRef = sdr;
729 return err;
730
731 error:
732 if (msg) free(msg);
733 if (*sdRef) { free(*sdRef); *sdRef = NULL; }
734 return kDNSServiceErr_Unknown;
735 }
736
737 DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser
738 (
739 DNSServiceFlags flags,
740 const char *domain
741 )
742 {
743 DNSServiceRef sdr;
744 DNSServiceErrorType err;
745 char *ptr = NULL;
746 size_t len = sizeof(flags) + strlen(domain) + 1;
747 ipc_msg_hdr *hdr = create_hdr(setdomain_request, &len, &ptr, 1);
748
749 if (!hdr) return kDNSServiceErr_Unknown;
750 put_flags(flags, &ptr);
751 put_string(domain, &ptr);
752
753 sdr = connect_to_server();
754 if (!sdr) { free(hdr); return kDNSServiceErr_Unknown; }
755 err = deliver_request((char *)hdr, sdr, 1); // deliver_request frees the message for us
756 DNSServiceRefDeallocate(sdr);
757 return err;
758 }
759
760
761 static void handle_regservice_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
762 {
763 DNSServiceFlags flags;
764 uint32_t interfaceIndex;
765 DNSServiceErrorType errorCode;
766 char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
767 int str_error = 0;
768 (void)hdr;//Unused
769
770 flags = get_flags(&data);
771 interfaceIndex = get_long(&data);
772 errorCode = get_error_code(&data);
773 if (get_string(&data, name, 256) < 0) str_error = 1;
774 if (get_string(&data, regtype, kDNSServiceMaxDomainName) < 0) str_error = 1;
775 if (get_string(&data, domain, kDNSServiceMaxDomainName) < 0) str_error = 1;
776 if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown;
777 ((DNSServiceRegisterReply)sdr->app_callback)(sdr, flags, errorCode, name, regtype, domain, sdr->app_context);
778 }
779
780 DNSServiceErrorType DNSSD_API DNSServiceRegister
781 (
782 DNSServiceRef *sdRef,
783 DNSServiceFlags flags,
784 uint32_t interfaceIndex,
785 const char *name,
786 const char *regtype,
787 const char *domain,
788 const char *host,
789 uint16_t PortInNetworkByteOrder,
790 uint16_t txtLen,
791 const void *txtRecord,
792 DNSServiceRegisterReply callBack,
793 void *context
794 )
795 {
796 char *msg = NULL, *ptr;
797 size_t len;
798 ipc_msg_hdr *hdr;
799 DNSServiceRef sdr;
800 DNSServiceErrorType err;
801 union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder };
802
803 if (!sdRef) return kDNSServiceErr_BadParam;
804 *sdRef = NULL;
805
806 if (!name) name = "";
807 if (!regtype) return kDNSServiceErr_BadParam;
808 if (!domain) domain = "";
809 if (!host) host = "";
810 if (!txtRecord) txtRecord = (void*)"";
811
812 // auto-name must also have auto-rename
813 if (!name[0] && (flags & kDNSServiceFlagsNoAutoRename))
814 return kDNSServiceErr_BadParam;
815
816 // no callback must have auto-name
817 if (!callBack && name[0]) return kDNSServiceErr_BadParam;
818
819 len = sizeof(DNSServiceFlags);
820 len += sizeof(uint32_t); // interfaceIndex
821 len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4;
822 len += 2 * sizeof(uint16_t); // port, txtLen
823 len += txtLen;
824
825 hdr = create_hdr(reg_service_request, &len, &ptr, 1);
826 if (!hdr) goto error;
827 if (!callBack) hdr->flags |= IPC_FLAGS_NOREPLY;
828 msg = (char *)hdr;
829 put_flags(flags, &ptr);
830 put_long(interfaceIndex, &ptr);
831 put_string(name, &ptr);
832 put_string(regtype, &ptr);
833 put_string(domain, &ptr);
834 put_string(host, &ptr);
835 *ptr++ = port.b[0];
836 *ptr++ = port.b[1];
837 put_short(txtLen, &ptr);
838 put_rdata(txtLen, txtRecord, &ptr);
839
840 sdr = connect_to_server();
841 if (!sdr) goto error;
842 err = deliver_request(msg, sdr, 1);
843 if (err)
844 {
845 DNSServiceRefDeallocate(sdr);
846 return err;
847 }
848
849 sdr->op = reg_service_request;
850 sdr->process_reply = callBack ? handle_regservice_response : NULL;
851 sdr->app_callback = callBack;
852 sdr->app_context = context;
853 *sdRef = sdr;
854
855 return err;
856
857 error:
858 if (msg) free(msg);
859 if (*sdRef) { free(*sdRef); *sdRef = NULL; }
860 return kDNSServiceErr_Unknown;
861 }
862
863 static void handle_enumeration_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
864 {
865 DNSServiceFlags flags;
866 uint32_t interfaceIndex;
867 DNSServiceErrorType err;
868 char domain[kDNSServiceMaxDomainName];
869 int str_error = 0;
870 (void)hdr;//Unused
871
872 flags = get_flags(&data);
873 interfaceIndex = get_long(&data);
874 err = get_error_code(&data);
875 if (get_string(&data, domain, kDNSServiceMaxDomainName) < 0) str_error = 1;
876 if (!err && str_error) err = kDNSServiceErr_Unknown;
877 ((DNSServiceDomainEnumReply)sdr->app_callback)(sdr, flags, interfaceIndex, err, domain, sdr->app_context);
878 }
879
880 DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
881 (
882 DNSServiceRef *sdRef,
883 DNSServiceFlags flags,
884 uint32_t interfaceIndex,
885 DNSServiceDomainEnumReply callBack,
886 void *context
887 )
888 {
889 char *msg = NULL, *ptr;
890 size_t len;
891 ipc_msg_hdr *hdr;
892 DNSServiceRef sdr;
893 DNSServiceErrorType err;
894 int f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0;
895 int f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0;
896 if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
897
898 if (!sdRef) return kDNSServiceErr_BadParam;
899 *sdRef = NULL;
900
901 len = sizeof(DNSServiceFlags);
902 len += sizeof(uint32_t);
903
904 hdr = create_hdr(enumeration_request, &len, &ptr, 1);
905 if (!hdr) goto error;
906 msg = (void *)hdr;
907
908 put_flags(flags, &ptr);
909 put_long(interfaceIndex, &ptr);
910
911 sdr = connect_to_server();
912 if (!sdr) goto error;
913 err = deliver_request(msg, sdr, 1);
914 if (err)
915 {
916 DNSServiceRefDeallocate(sdr);
917 return err;
918 }
919
920 sdr->op = enumeration_request;
921 sdr->process_reply = handle_enumeration_response;
922 sdr->app_callback = callBack;
923 sdr->app_context = context;
924 *sdRef = sdr;
925 return err;
926
927 error:
928 if (msg) free(msg);
929 if (*sdRef) { free(*sdRef); *sdRef = NULL; }
930 return kDNSServiceErr_Unknown;
931 }
932
933 static void handle_regrecord_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
934 {
935 DNSServiceFlags flags;
936 uint32_t interfaceIndex;
937 DNSServiceErrorType errorCode;
938 DNSRecordRef rref = hdr->client_context.context;
939
940 if (sdr->op != connection)
941 {
942 rref->app_callback(rref->sdr, rref, 0, kDNSServiceErr_Unknown, rref->app_context);
943 return;
944 }
945 flags = get_flags(&data);
946 interfaceIndex = get_long(&data);
947 errorCode = get_error_code(&data);
948
949 rref->app_callback(rref->sdr, rref, flags, errorCode, rref->app_context);
950 }
951
952 DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef)
953 {
954 if (!sdRef) return kDNSServiceErr_BadParam;
955 *sdRef = connect_to_server();
956 if (!*sdRef)
957 return kDNSServiceErr_Unknown;
958 (*sdRef)->op = connection;
959 (*sdRef)->process_reply = handle_regrecord_response;
960 return 0;
961 }
962
963 DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
964 (
965 DNSServiceRef sdRef,
966 DNSRecordRef *RecordRef,
967 DNSServiceFlags flags,
968 uint32_t interfaceIndex,
969 const char *fullname,
970 uint16_t rrtype,
971 uint16_t rrclass,
972 uint16_t rdlen,
973 const void *rdata,
974 uint32_t ttl,
975 DNSServiceRegisterRecordReply callBack,
976 void *context
977 )
978 {
979 char *msg = NULL, *ptr;
980 size_t len;
981 ipc_msg_hdr *hdr = NULL;
982 DNSServiceRef tmp = NULL;
983 DNSRecordRef rref = NULL;
984 int f1 = (flags & kDNSServiceFlagsShared) != 0;
985 int f2 = (flags & kDNSServiceFlagsUnique) != 0;
986 if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
987
988 if (!sdRef || sdRef->op != connection || sdRef->sockfd < 0)
989 return kDNSServiceErr_BadReference;
990 *RecordRef = NULL;
991
992 len = sizeof(DNSServiceFlags);
993 len += 2 * sizeof(uint32_t); // interfaceIndex, ttl
994 len += 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen
995 len += strlen(fullname) + 1;
996 len += rdlen;
997
998 hdr = create_hdr(reg_record_request, &len, &ptr, 0);
999 if (!hdr) goto error;
1000 msg = (char *)hdr;
1001 put_flags(flags, &ptr);
1002 put_long(interfaceIndex, &ptr);
1003 put_string(fullname, &ptr);
1004 put_short(rrtype, &ptr);
1005 put_short(rrclass, &ptr);
1006 put_short(rdlen, &ptr);
1007 put_rdata(rdlen, rdata, &ptr);
1008 put_long(ttl, &ptr);
1009
1010 rref = malloc(sizeof(_DNSRecordRef_t));
1011 if (!rref) goto error;
1012 rref->app_context = context;
1013 rref->app_callback = callBack;
1014 rref->record_index = sdRef->max_index++;
1015 rref->sdr = sdRef;
1016 *RecordRef = rref;
1017 hdr->client_context.context = rref;
1018 hdr->reg_index = rref->record_index;
1019
1020 return deliver_request(msg, sdRef, 0);
1021
1022 error:
1023 if (rref) free(rref);
1024 if (tmp) free(tmp);
1025 if (hdr) free(hdr);
1026 return kDNSServiceErr_Unknown;
1027 }
1028
1029 //sdRef returned by DNSServiceRegister()
1030 DNSServiceErrorType DNSSD_API DNSServiceAddRecord
1031 (
1032 DNSServiceRef sdRef,
1033 DNSRecordRef *RecordRef,
1034 DNSServiceFlags flags,
1035 uint16_t rrtype,
1036 uint16_t rdlen,
1037 const void *rdata,
1038 uint32_t ttl
1039 )
1040 {
1041 ipc_msg_hdr *hdr;
1042 size_t len = 0;
1043 char *ptr;
1044 DNSRecordRef rref;
1045
1046 if (!sdRef || (sdRef->op != reg_service_request) || !RecordRef)
1047 return kDNSServiceErr_BadReference;
1048 *RecordRef = NULL;
1049
1050 len += 2 * sizeof(uint16_t); //rrtype, rdlen
1051 len += rdlen;
1052 len += sizeof(uint32_t);
1053 len += sizeof(DNSServiceFlags);
1054
1055 hdr = create_hdr(add_record_request, &len, &ptr, 0);
1056 if (!hdr) return kDNSServiceErr_Unknown;
1057 put_flags(flags, &ptr);
1058 put_short(rrtype, &ptr);
1059 put_short(rdlen, &ptr);
1060 put_rdata(rdlen, rdata, &ptr);
1061 put_long(ttl, &ptr);
1062
1063 rref = malloc(sizeof(_DNSRecordRef_t));
1064 if (!rref) goto error;
1065 rref->app_context = NULL;
1066 rref->app_callback = NULL;
1067 rref->record_index = sdRef->max_index++;
1068 rref->sdr = sdRef;
1069 *RecordRef = rref;
1070 hdr->client_context.context = rref;
1071 hdr->reg_index = rref->record_index;
1072 return deliver_request((char *)hdr, sdRef, 0);
1073
1074 error:
1075 if (hdr) free(hdr);
1076 if (rref) free(rref);
1077 if (*RecordRef) *RecordRef = NULL;
1078 return kDNSServiceErr_Unknown;
1079 }
1080
1081 //DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
1082 DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
1083 (
1084 DNSServiceRef sdRef,
1085 DNSRecordRef RecordRef,
1086 DNSServiceFlags flags,
1087 uint16_t rdlen,
1088 const void *rdata,
1089 uint32_t ttl
1090 )
1091 {
1092 ipc_msg_hdr *hdr;
1093 size_t len = 0;
1094 char *ptr;
1095
1096 if (!sdRef) return kDNSServiceErr_BadReference;
1097
1098 len += sizeof(uint16_t);
1099 len += rdlen;
1100 len += sizeof(uint32_t);
1101 len += sizeof(DNSServiceFlags);
1102
1103 hdr = create_hdr(update_record_request, &len, &ptr, 0);
1104 if (!hdr) return kDNSServiceErr_Unknown;
1105 hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX;
1106 put_flags(flags, &ptr);
1107 put_short(rdlen, &ptr);
1108 put_rdata(rdlen, rdata, &ptr);
1109 put_long(ttl, &ptr);
1110 return deliver_request((char *)hdr, sdRef, 0);
1111 }
1112
1113 DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
1114 (
1115 DNSServiceRef sdRef,
1116 DNSRecordRef RecordRef,
1117 DNSServiceFlags flags
1118 )
1119 {
1120 ipc_msg_hdr *hdr;
1121 size_t len = 0;
1122 char *ptr;
1123 DNSServiceErrorType err;
1124
1125 if (!sdRef || !RecordRef || !sdRef->max_index)
1126 return kDNSServiceErr_BadReference;
1127
1128 len += sizeof(flags);
1129 hdr = create_hdr(remove_record_request, &len, &ptr, 0);
1130 if (!hdr) return kDNSServiceErr_Unknown;
1131 hdr->reg_index = RecordRef->record_index;
1132 put_flags(flags, &ptr);
1133 err = deliver_request((char *)hdr, sdRef, 0);
1134 if (!err) free(RecordRef);
1135 return err;
1136 }
1137
1138 void DNSSD_API DNSServiceReconfirmRecord
1139 (
1140 DNSServiceFlags flags,
1141 uint32_t interfaceIndex,
1142 const char *fullname,
1143 uint16_t rrtype,
1144 uint16_t rrclass,
1145 uint16_t rdlen,
1146 const void *rdata
1147 )
1148 {
1149 char *ptr;
1150 size_t len;
1151 ipc_msg_hdr *hdr;
1152 DNSServiceRef tmp;
1153
1154 len = sizeof(DNSServiceFlags);
1155 len += sizeof(uint32_t);
1156 len += strlen(fullname) + 1;
1157 len += 3 * sizeof(uint16_t);
1158 len += rdlen;
1159 tmp = connect_to_server();
1160 if (!tmp) return;
1161 hdr = create_hdr(reconfirm_record_request, &len, &ptr, 1);
1162 if (!hdr) return;
1163
1164 put_flags(flags, &ptr);
1165 put_long(interfaceIndex, &ptr);
1166 put_string(fullname, &ptr);
1167 put_short(rrtype, &ptr);
1168 put_short(rrclass, &ptr);
1169 put_short(rdlen, &ptr);
1170 put_rdata(rdlen, rdata, &ptr);
1171 ConvertHeaderBytes(hdr);
1172 my_write(tmp->sockfd, (char *)hdr, (int) len);
1173 free(hdr);
1174 DNSServiceRefDeallocate(tmp);
1175 }
1176