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