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