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