Libinfo-222.4.6.tar.gz
[apple/libinfo.git] / mdns.subproj / 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.20.70.3 2006/05/02 16:17:04 majka
32 Make NumTries unsigned.
33
34 Revision 1.20.70.2 2006/05/01 21:43:09 majka
35 Additional change (make NumTries static) for 4527193
36 SUChardLondon Libinfo-222.4.6
37
38 Revision 1.20.70.1 2006/05/01 16:10:54 majka
39 Libinfo-222_4_5 is equivalent to Chardonnay Libinfo-222.0.5
40
41 Revision 1.20.60.1 2006/04/27 21:33:30 majka
42 Integrated 4527193
43
44 Revision 1.20 2005/02/03 00:39:05 majka
45 Integrated 3942900
46
47 Revision 1.19.4.1 2005/02/02 00:47:40 ksekar
48 <rdar://problem/3942900> dnd-sd shows the wrong port numbers
49
50 Revision 1.19 2004/12/23 23:10:59 majka
51 *** empty log message ***
52
53 Revision 1.18.8.1 2004/12/23 17:32:56 ksekar
54 <rdar://problem/3931319> Rendevzous calls leak sockets if mDNSResponder is not running
55
56 Revision 1.18 2004/12/14 18:02:00 majka
57 *** empty log message ***
58
59 Revision 1.17.36.1 2004/12/13 17:22:39 ksekar
60 <rdar://problem/3656389> Deprecate the DNSServiceDiscovery.h API in Tiger
61 <rdar://problem/3873869> Add kDNSServiceInterfaceForceMulticast to header
62 <rdar://problem/3526342> Remove overly-restrictive flag checks
63
64 Revision 1.17 2004/09/22 20:05:38 majka
65 Integrated
66 3725573 - Need Error Codes for handling Lighthouse setup failure on NAT
67 3805822 - Socket-based APIs aren't endian-safe
68 3806739 - DNSServiceSetDefaultDomainForUser header comments incorrect
69
70 Revision 1.16.2.1 2004/09/20 21:54:33 ksekar
71 <rdar://problem/3805822> Socket-based APIs aren't endian-safe
72
73 Revision 1.16 2004/09/17 20:19:00 majka
74 Integrated 3804522
75
76 Revision 1.15.2.1 2004/09/17 20:15:30 ksekar
77 *** empty log message ***
78
79 Revision 1.15 2004/09/16 23:45:24 majka
80 Integrated 3775315 and 3765280.
81
82 Revision 1.14.4.1 2004/09/02 19:43:41 ksekar
83 <rdar://problem/3775315>: Sync dns-sd client files between Libinfo and
84 mDNSResponder projects
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 mDNSClientAPI.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 static unsigned 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 < 3)
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