1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2003-2004, Apple Computer, Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
28 Change History (most recent first):
30 $Log: dnssd_clientstub.c,v $
31 Revision 1.44 2005/01/27 22:57:56 cheshire
32 Fix compile errors on gcc4
34 Revision 1.43 2005/01/27 00:02:29 cheshire
35 <rdar://problem/3947461> Handle case where client runs before daemon has finished launching
37 Revision 1.42 2005/01/11 02:01:02 shersche
38 Use dnssd_close() rather than close() for Windows compatibility
40 Revision 1.41 2004/12/23 17:34:26 ksekar
41 <rdar://problem/3931319> Rendevzous calls leak sockets if mDNSResponder is not running
43 Revision 1.40 2004/11/23 03:39:47 cheshire
44 Let interface name/index mapping capability live directly in JNISupport.c,
45 instead of having to call through to the daemon via IPC to get this information.
47 Revision 1.39 2004/11/12 03:22:00 rpantos
48 rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
50 Revision 1.38 2004/11/02 02:51:23 cheshire
51 <rdar://problem/3526342> Remove overly-restrictive flag checks
53 Revision 1.37 2004/10/14 01:43:35 cheshire
54 Fix opaque port passing problem
56 Revision 1.36 2004/10/06 02:22:19 cheshire
57 Changed MacRoman copyright symbol (should have been UTF-8 in any case :-) to ASCII-compatible "(c)"
59 Revision 1.35 2004/10/01 22:15:55 rpantos
60 rdar://problem/3824265: Replace APSL in client lib with BSD license.
62 Revision 1.34 2004/09/17 22:36:13 cheshire
63 Add comment explaining that deliver_request frees the message it sends
65 Revision 1.33 2004/09/17 01:17:31 ksekar
66 Remove double-free of msg header, freed automatically by deliver_request()
68 Revision 1.32 2004/09/17 01:08:55 cheshire
69 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
70 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
71 declared in that file are ONLY appropriate to single-address-space embedded applications.
72 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
74 Revision 1.31 2004/09/16 23:37:19 cheshire
75 Free hdr before returning
77 Revision 1.30 2004/09/16 23:14:24 cheshire
78 Changes for Windows compatibility
80 Revision 1.29 2004/09/16 21:46:38 ksekar
81 <rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area Rendezvous domain
83 Revision 1.28 2004/08/11 17:10:04 cheshire
84 Fix signed/unsigned warnings
86 Revision 1.27 2004/08/11 00:54:16 cheshire
87 Change "hdr->op.request_op" to just "hdr->op"
89 Revision 1.26 2004/07/26 06:07:27 shersche
90 fix bugs when using an error socket to communicate with the daemon
92 Revision 1.25 2004/07/26 05:54:02 shersche
93 DNSServiceProcessResult() returns NoError if socket read returns EWOULDBLOCK
95 Revision 1.24 2004/07/20 06:46:21 shersche
96 <rdar://problem/3730123> fix endless loop in my_read() if recv returns 0
99 Revision 1.23 2004/06/29 00:48:38 cheshire
100 Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
101 use an explicit while() loop instead.
103 Revision 1.22 2004/06/26 03:16:34 shersche
104 clean up warning messages on Win32 platform
106 Submitted by: herscher
108 Revision 1.21 2004/06/18 04:53:56 rpantos
109 Use platform layer for socket types. Introduce USE_TCP_LOOPBACK. Remove dependency on mDNSEmbeddedAPI.h.
111 Revision 1.20 2004/06/12 00:50:22 cheshire
112 Changes for Windows compatibility
114 Revision 1.19 2004/05/25 18:29:33 cheshire
115 Move DNSServiceConstructFullName() from dnssd_clientstub.c to dnssd_clientlib.c,
116 so that it's also accessible to dnssd_clientshim.c (single address space) clients.
118 Revision 1.18 2004/05/18 23:51:27 cheshire
119 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
121 Revision 1.17 2004/05/06 18:42:58 ksekar
122 General dns_sd.h API cleanup, including the following radars:
123 <rdar://problem/3592068>: Remove flags with zero value
124 <rdar://problem/3479569>: Passing in NULL causes a crash.
126 Revision 1.16 2004/03/12 22:00:37 cheshire
127 Added: #include <sys/socket.h>
129 Revision 1.15 2004/01/20 18:36:29 ksekar
130 Propagated Libinfo fix for <rdar://problem/3483971>: SU:
131 DNSServiceUpdateRecord() doesn't allow you to update the TXT record
132 into TOT mDNSResponder.
134 Revision 1.14 2004/01/19 22:39:17 cheshire
135 Don't use "MSG_WAITALL"; it makes send() return "Invalid argument" on Linux;
136 use an explicit while() loop instead. (In any case, this should only make a difference
137 with non-blocking sockets, which we don't use on the client side right now.)
139 Revision 1.13 2004/01/19 21:46:52 cheshire
142 Revision 1.12 2003/12/23 20:46:47 ksekar
143 <rdar://problem/3497428>: sync dnssd files between libinfo & mDNSResponder
145 Revision 1.11 2003/12/08 21:11:42 rpantos
146 Changes necessary to support mDNSResponder on Linux.
148 Revision 1.10 2003/10/13 23:50:53 ksekar
149 Updated dns_sd clientstub files to bring copies in synch with
150 top-of-tree Libinfo: A memory leak in dnssd_clientstub.c is fixed,
151 and comments in dns_sd.h are improved.
153 Revision 1.9 2003/08/15 21:30:39 cheshire
154 Bring up to date with LibInfo version
156 Revision 1.8 2003/08/13 23:54:52 ksekar
157 Bringing dnssd_clientstub.c up to date with Libinfo, per radar 3376640
159 Revision 1.7 2003/08/12 19:56:25 cheshire
167 #include <winsock2.h>
169 #define sockaddr_mdns sockaddr_in
170 #define AF_MDNS AF_INET
172 #include <sys/time.h>
173 #include <sys/socket.h>
174 #define sockaddr_mdns sockaddr_un
175 #define AF_MDNS AF_LOCAL
178 #include "dnssd_ipc.h"
181 // disable warning: "'type cast' : from data pointer 'void *' to
183 #pragma warning(disable:4055)
185 // disable warning: "nonstandard extension, function/data pointer
186 // conversion in expression"
187 #pragma warning(disable:4152)
189 static int g_initWinsock
= 0;
193 #define CTL_PATH_PREFIX "/tmp/dnssd_clippath."
194 // error socket (if needed) is named "dnssd_clipath.[pid].xxx:n" where xxx are the
195 // last 3 digits of the time (in seconds) and n is the 6-digit microsecond time
197 // general utility functions
198 typedef struct _DNSServiceRef_t
200 dnssd_sock_t sockfd
; // connected socket between client and daemon
201 uint32_t op
; // request_op_t or reply_op_t
202 process_reply_callback process_reply
;
205 uint32_t max_index
; //largest assigned record index - 0 if no additl. recs registered
208 typedef struct _DNSRecordRef_t
211 DNSServiceRegisterRecordReply app_callback
;
213 uint32_t record_index
; // index is unique to the ServiceDiscoveryRef
217 // exported functions
219 // write len bytes. return 0 on success, -1 on error
220 static int my_write(dnssd_sock_t sd
, char *buf
, int len
)
222 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
223 //if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
226 ssize_t num_written
= send(sd
, buf
, len
, 0);
227 if (num_written
< 0 || num_written
> len
) return -1;
234 // read len bytes. return 0 on success, -1 on error
235 static int my_read(dnssd_sock_t sd
, char *buf
, int len
)
237 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
238 //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1;
241 ssize_t num_read
= recv(sd
, buf
, len
, 0);
242 if ((num_read
== 0) || (num_read
< 0) || (num_read
> len
)) return -1;
251 * allocate and initialize an ipc message header. value of len should initially be the
252 * length of the data, and is set to the value of the data plus the header. data_start
253 * is set to point to the beginning of the data section. reuse_socket should be non-zero
254 * for calls that can receive an immediate error return value on their primary socket.
255 * if zero, the path to a control socket is appended at the beginning of the message buffer.
256 * data_start is set past this string.
259 static ipc_msg_hdr
*create_hdr(uint32_t op
, size_t *len
, char **data_start
, int reuse_socket
)
268 #if defined(USE_TCP_LOOPBACK)
269 *len
+= 2; // Allocate space for two-byte port number
272 if (gettimeofday(&time
, NULL
) < 0) return NULL
;
273 sprintf(ctrl_path
, "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX
, (int)getpid(),
274 (unsigned long)(time
.tv_sec
& 0xFFF), (unsigned long)(time
.tv_usec
));
275 *len
+= strlen(ctrl_path
) + 1;
279 datalen
= (int) *len
;
280 *len
+= sizeof(ipc_msg_hdr
);
282 // write message to buffer
284 if (!msg
) return NULL
;
288 hdr
->datalen
= datalen
;
289 hdr
->version
= VERSION
;
291 if (reuse_socket
) hdr
->flags
|= IPC_FLAGS_REUSE_SOCKET
;
292 *data_start
= msg
+ sizeof(ipc_msg_hdr
);
293 #if defined(USE_TCP_LOOPBACK)
294 // Put dummy data in for the port, since we don't know what
295 // it is yet. The data will get filled in before we
296 // send the message. This happens in deliver_request().
297 if (!reuse_socket
) put_short(0, data_start
);
299 if (!reuse_socket
) put_string(ctrl_path
, data_start
);
304 // return a connected service ref (deallocate with DNSServiceRefDeallocate)
305 static DNSServiceRef
connect_to_server(void)
307 dnssd_sockaddr_t saddr
;
315 DNSServiceErrorType err
;
319 err
= WSAStartup( MAKEWORD( 2, 2 ), &wsaData
);
321 if (err
!= 0) return NULL
;
325 sdr
= malloc(sizeof(_DNSServiceRef_t
));
326 if (!sdr
) return(NULL
);
327 sdr
->sockfd
= socket(AF_DNSSD
, SOCK_STREAM
, 0);
328 if (sdr
->sockfd
== dnssd_InvalidSocket
) { free(sdr
); return NULL
; }
329 #if defined(USE_TCP_LOOPBACK)
330 saddr
.sin_family
= AF_INET
;
331 saddr
.sin_addr
.s_addr
= inet_addr(MDNS_TCP_SERVERADDR
);
332 saddr
.sin_port
= htons(MDNS_TCP_SERVERPORT
);
334 saddr
.sun_family
= AF_LOCAL
;
335 strcpy(saddr
.sun_path
, MDNS_UDS_SERVERPATH
);
339 int err
= connect(sdr
->sockfd
, (struct sockaddr
*) &saddr
, sizeof(saddr
));
340 if (!err
) break; // If we succeeded, return sdr
341 // If we failed, then it may be because the daemon is still launching.
342 // This can happen for processes that launch early in the boot process, while the
343 // daemon is still coming up. Rather than fail here, we'll wait a bit and try again.
344 // If, after ten seconds, we still can't connect to the daemon,
345 // then we give up and return a failure code.
347 sleep(1); // Sleep a bit, then try again
350 dnssd_close(sdr
->sockfd
);
351 sdr
->sockfd
= dnssd_InvalidSocket
;
359 static DNSServiceErrorType
deliver_request(void *msg
, DNSServiceRef sdr
, int reuse_sd
)
361 ipc_msg_hdr
*hdr
= msg
;
362 uint32_t datalen
= hdr
->datalen
;
363 dnssd_sockaddr_t caddr
, daddr
; // (client and daemon address structs)
364 char *data
= (char *)msg
+ sizeof(ipc_msg_hdr
);
365 dnssd_sock_t listenfd
= dnssd_InvalidSocket
, errsd
= dnssd_InvalidSocket
;
367 unsigned int len
= sizeof(caddr
);
368 DNSServiceErrorType err
= kDNSServiceErr_Unknown
;
370 if (!hdr
|| sdr
->sockfd
< 0) return kDNSServiceErr_Unknown
;
374 // setup temporary error socket
375 if ((listenfd
= socket(AF_DNSSD
, SOCK_STREAM
, 0)) < 0)
377 bzero(&caddr
, sizeof(caddr
));
379 #if defined(USE_TCP_LOOPBACK)
381 union { uint16_t s
; u_char b
[2]; } port
;
382 caddr
.sin_family
= AF_INET
;
384 caddr
.sin_addr
.s_addr
= inet_addr(MDNS_TCP_SERVERADDR
);
385 ret
= bind(listenfd
, (struct sockaddr
*) &caddr
, sizeof(caddr
));
386 if (ret
< 0) goto cleanup
;
387 if (getsockname(listenfd
, (struct sockaddr
*) &caddr
, &len
) < 0) goto cleanup
;
389 port
.s
= caddr
.sin_port
;
390 data
[0] = port
.b
[0]; // don't switch the byte order, as the
391 data
[1] = port
.b
[1]; // daemon expects it in network byte order
395 mode_t mask
= umask(0);
396 caddr
.sun_family
= AF_LOCAL
;
397 #ifndef NOT_HAVE_SA_LEN // According to Stevens (section 3.2), there is no portable way to
398 // determine whether sa_len is defined on a particular platform.
399 caddr
.sun_len
= sizeof(struct sockaddr_un
);
401 strcpy(caddr
.sun_path
, data
);
402 ret
= bind(listenfd
, (struct sockaddr
*)&caddr
, sizeof(caddr
));
404 if (ret
< 0) goto cleanup
;
410 ConvertHeaderBytes(hdr
);
411 if (my_write(sdr
->sockfd
, msg
, datalen
+ sizeof(ipc_msg_hdr
)) < 0)
416 if (reuse_sd
) errsd
= sdr
->sockfd
;
420 errsd
= accept(listenfd
, (struct sockaddr
*)&daddr
, &len
);
421 if (errsd
< 0) goto cleanup
;
424 if (my_read(errsd
, (char*)&err
, (int)sizeof(err
)) < 0)
425 err
= kDNSServiceErr_Unknown
;
430 if (!reuse_sd
&& listenfd
> 0) dnssd_close(listenfd
);
431 if (!reuse_sd
&& errsd
> 0) dnssd_close(errsd
);
432 #if !defined(USE_TCP_LOOPBACK)
433 if (!reuse_sd
&& data
) unlink(data
);
439 int DNSSD_API
DNSServiceRefSockFD(DNSServiceRef sdRef
)
441 if (!sdRef
) return -1;
442 return (int) sdRef
->sockfd
;
445 // handle reply from server, calling application client callback. If there is no reply
446 // from the daemon on the socket contained in sdRef, the call will block.
447 DNSServiceErrorType DNSSD_API
DNSServiceProcessResult(DNSServiceRef sdRef
)
452 if (!sdRef
|| sdRef
->sockfd
< 0 || !sdRef
->process_reply
)
453 return kDNSServiceErr_BadReference
;
455 if (my_read(sdRef
->sockfd
, (void *)&hdr
, sizeof(hdr
)) < 0)
456 // return NoError on EWOULDBLOCK. This will handle the case
457 // where a non-blocking socket is told there is data, but
458 // it was a false positive.
459 return (dnssd_errno() == dnssd_EWOULDBLOCK
) ? kDNSServiceErr_NoError
: kDNSServiceErr_Unknown
;
460 ConvertHeaderBytes(&hdr
);
461 if (hdr
.version
!= VERSION
)
462 return kDNSServiceErr_Incompatible
;
463 data
= malloc(hdr
.datalen
);
464 if (!data
) return kDNSServiceErr_NoMemory
;
465 if (my_read(sdRef
->sockfd
, data
, hdr
.datalen
) < 0)
466 return kDNSServiceErr_Unknown
;
467 sdRef
->process_reply(sdRef
, &hdr
, data
);
469 return kDNSServiceErr_NoError
;
472 void DNSSD_API
DNSServiceRefDeallocate(DNSServiceRef sdRef
)
475 if (sdRef
->sockfd
> 0) dnssd_close(sdRef
->sockfd
);
479 static void handle_resolve_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
481 DNSServiceFlags flags
;
482 char fullname
[kDNSServiceMaxDomainName
];
483 char target
[kDNSServiceMaxDomainName
];
485 union { uint16_t s
; u_char b
[2]; } port
;
487 DNSServiceErrorType err
;
492 flags
= get_flags(&data
);
493 ifi
= get_long(&data
);
494 err
= get_error_code(&data
);
495 if (get_string(&data
, fullname
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
496 if (get_string(&data
, target
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
499 txtlen
= get_short(&data
);
500 txtrecord
= get_rdata(&data
, txtlen
);
502 if (!err
&& str_error
) err
= kDNSServiceErr_Unknown
;
503 ((DNSServiceResolveReply
)sdr
->app_callback
)(sdr
, flags
, ifi
, err
, fullname
, target
, port
.s
, txtlen
, txtrecord
, sdr
->app_context
);
506 DNSServiceErrorType DNSSD_API DNSServiceResolve
508 DNSServiceRef
*sdRef
,
509 DNSServiceFlags flags
,
510 uint32_t interfaceIndex
,
514 DNSServiceResolveReply callBack
,
518 char *msg
= NULL
, *ptr
;
522 DNSServiceErrorType err
;
524 if (!sdRef
) return kDNSServiceErr_BadParam
;
527 if (!name
|| !regtype
|| !domain
|| !callBack
) return kDNSServiceErr_BadParam
;
529 // calculate total message length
531 len
+= sizeof(interfaceIndex
);
532 len
+= strlen(name
) + 1;
533 len
+= strlen(regtype
) + 1;
534 len
+= strlen(domain
) + 1;
536 hdr
= create_hdr(resolve_request
, &len
, &ptr
, 1);
537 if (!hdr
) goto error
;
540 put_flags(flags
, &ptr
);
541 put_long(interfaceIndex
, &ptr
);
542 put_string(name
, &ptr
);
543 put_string(regtype
, &ptr
);
544 put_string(domain
, &ptr
);
546 sdr
= connect_to_server();
547 if (!sdr
) goto error
;
548 err
= deliver_request(msg
, sdr
, 1);
551 DNSServiceRefDeallocate(sdr
);
554 sdr
->op
= resolve_request
;
555 sdr
->process_reply
= handle_resolve_response
;
556 sdr
->app_callback
= callBack
;
557 sdr
->app_context
= context
;
564 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
565 return kDNSServiceErr_Unknown
;
568 static void handle_query_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
570 DNSServiceFlags flags
;
571 uint32_t interfaceIndex
, ttl
;
572 DNSServiceErrorType errorCode
;
573 char name
[kDNSServiceMaxDomainName
];
574 uint16_t rrtype
, rrclass
, rdlen
;
579 flags
= get_flags(&data
);
580 interfaceIndex
= get_long(&data
);
581 errorCode
= get_error_code(&data
);
582 if (get_string(&data
, name
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
583 rrtype
= get_short(&data
);
584 rrclass
= get_short(&data
);
585 rdlen
= get_short(&data
);
586 rdata
= get_rdata(&data
, rdlen
);
587 ttl
= get_long(&data
);
589 if (!errorCode
&& str_error
) errorCode
= kDNSServiceErr_Unknown
;
590 ((DNSServiceQueryRecordReply
)sdr
->app_callback
)(sdr
, flags
, interfaceIndex
, errorCode
, name
, rrtype
, rrclass
,
591 rdlen
, rdata
, ttl
, sdr
->app_context
);
595 DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
597 DNSServiceRef
*sdRef
,
598 DNSServiceFlags flags
,
599 uint32_t interfaceIndex
,
603 DNSServiceQueryRecordReply callBack
,
607 char *msg
= NULL
, *ptr
;
611 DNSServiceErrorType err
;
613 if (!sdRef
) return kDNSServiceErr_BadParam
;
616 if (!name
) name
= "\0";
618 // calculate total message length
620 len
+= sizeof(uint32_t); //interfaceIndex
621 len
+= strlen(name
) + 1;
622 len
+= 2 * sizeof(uint16_t); // rrtype, rrclass
624 hdr
= create_hdr(query_request
, &len
, &ptr
, 1);
625 if (!hdr
) goto error
;
628 put_flags(flags
, &ptr
);
629 put_long(interfaceIndex
, &ptr
);
630 put_string(name
, &ptr
);
631 put_short(rrtype
, &ptr
);
632 put_short(rrclass
, &ptr
);
634 sdr
= connect_to_server();
635 if (!sdr
) goto error
;
636 err
= deliver_request(msg
, sdr
, 1);
639 DNSServiceRefDeallocate(sdr
);
643 sdr
->op
= query_request
;
644 sdr
->process_reply
= handle_query_response
;
645 sdr
->app_callback
= callBack
;
646 sdr
->app_context
= context
;
652 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
653 return kDNSServiceErr_Unknown
;
656 static void handle_browse_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
658 DNSServiceFlags flags
;
659 uint32_t interfaceIndex
;
660 DNSServiceErrorType errorCode
;
661 char replyName
[256], replyType
[kDNSServiceMaxDomainName
],
662 replyDomain
[kDNSServiceMaxDomainName
];
666 flags
= get_flags(&data
);
667 interfaceIndex
= get_long(&data
);
668 errorCode
= get_error_code(&data
);
669 if (get_string(&data
, replyName
, 256) < 0) str_error
= 1;
670 if (get_string(&data
, replyType
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
671 if (get_string(&data
, replyDomain
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
672 if (!errorCode
&& str_error
) errorCode
= kDNSServiceErr_Unknown
;
673 ((DNSServiceBrowseReply
)sdr
->app_callback
)(sdr
, flags
, interfaceIndex
, errorCode
, replyName
, replyType
, replyDomain
, sdr
->app_context
);
676 DNSServiceErrorType DNSSD_API DNSServiceBrowse
678 DNSServiceRef
*sdRef
,
679 DNSServiceFlags flags
,
680 uint32_t interfaceIndex
,
683 DNSServiceBrowseReply callBack
,
687 char *msg
= NULL
, *ptr
;
691 DNSServiceErrorType err
;
693 if (!sdRef
) return kDNSServiceErr_BadParam
;
696 if (!domain
) domain
= "";
699 len
+= sizeof(interfaceIndex
);
700 len
+= strlen(regtype
) + 1;
701 len
+= strlen(domain
) + 1;
703 hdr
= create_hdr(browse_request
, &len
, &ptr
, 1);
704 if (!hdr
) goto error
;
706 put_flags(flags
, &ptr
);
707 put_long(interfaceIndex
, &ptr
);
708 put_string(regtype
, &ptr
);
709 put_string(domain
, &ptr
);
711 sdr
= connect_to_server();
712 if (!sdr
) goto error
;
713 err
= deliver_request(msg
, sdr
, 1);
716 DNSServiceRefDeallocate(sdr
);
719 sdr
->op
= browse_request
;
720 sdr
->process_reply
= handle_browse_response
;
721 sdr
->app_callback
= callBack
;
722 sdr
->app_context
= context
;
728 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
729 return kDNSServiceErr_Unknown
;
732 DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser
734 DNSServiceFlags flags
,
739 DNSServiceErrorType err
;
741 size_t len
= sizeof(flags
) + strlen(domain
) + 1;
742 ipc_msg_hdr
*hdr
= create_hdr(setdomain_request
, &len
, &ptr
, 1);
744 if (!hdr
) return kDNSServiceErr_Unknown
;
745 put_flags(flags
, &ptr
);
746 put_string(domain
, &ptr
);
748 sdr
= connect_to_server();
749 if (!sdr
) { free(hdr
); return kDNSServiceErr_Unknown
; }
750 err
= deliver_request((char *)hdr
, sdr
, 1); // deliver_request frees the message for us
751 DNSServiceRefDeallocate(sdr
);
756 static void handle_regservice_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
758 DNSServiceFlags flags
;
759 uint32_t interfaceIndex
;
760 DNSServiceErrorType errorCode
;
761 char name
[256], regtype
[kDNSServiceMaxDomainName
], domain
[kDNSServiceMaxDomainName
];
765 flags
= get_flags(&data
);
766 interfaceIndex
= get_long(&data
);
767 errorCode
= get_error_code(&data
);
768 if (get_string(&data
, name
, 256) < 0) str_error
= 1;
769 if (get_string(&data
, regtype
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
770 if (get_string(&data
, domain
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
771 if (!errorCode
&& str_error
) errorCode
= kDNSServiceErr_Unknown
;
772 ((DNSServiceRegisterReply
)sdr
->app_callback
)(sdr
, flags
, errorCode
, name
, regtype
, domain
, sdr
->app_context
);
775 DNSServiceErrorType DNSSD_API DNSServiceRegister
777 DNSServiceRef
*sdRef
,
778 DNSServiceFlags flags
,
779 uint32_t interfaceIndex
,
784 uint16_t PortInNetworkByteOrder
,
786 const void *txtRecord
,
787 DNSServiceRegisterReply callBack
,
791 char *msg
= NULL
, *ptr
;
795 DNSServiceErrorType err
;
796 union { uint16_t s
; u_char b
[2]; } port
= { PortInNetworkByteOrder
};
798 if (!sdRef
) return kDNSServiceErr_BadParam
;
801 if (!name
) name
= "";
802 if (!regtype
) return kDNSServiceErr_BadParam
;
803 if (!domain
) domain
= "";
804 if (!host
) host
= "";
805 if (!txtRecord
) txtRecord
= (void*)"";
807 // auto-name must also have auto-rename
808 if (!name
[0] && (flags
& kDNSServiceFlagsNoAutoRename
))
809 return kDNSServiceErr_BadParam
;
811 // no callback must have auto-name
812 if (!callBack
&& name
[0]) return kDNSServiceErr_BadParam
;
814 len
= sizeof(DNSServiceFlags
);
815 len
+= sizeof(uint32_t); // interfaceIndex
816 len
+= strlen(name
) + strlen(regtype
) + strlen(domain
) + strlen(host
) + 4;
817 len
+= 2 * sizeof(uint16_t); // port, txtLen
820 hdr
= create_hdr(reg_service_request
, &len
, &ptr
, 1);
821 if (!hdr
) goto error
;
822 if (!callBack
) hdr
->flags
|= IPC_FLAGS_NOREPLY
;
824 put_flags(flags
, &ptr
);
825 put_long(interfaceIndex
, &ptr
);
826 put_string(name
, &ptr
);
827 put_string(regtype
, &ptr
);
828 put_string(domain
, &ptr
);
829 put_string(host
, &ptr
);
832 put_short(txtLen
, &ptr
);
833 put_rdata(txtLen
, txtRecord
, &ptr
);
835 sdr
= connect_to_server();
836 if (!sdr
) goto error
;
837 err
= deliver_request(msg
, sdr
, 1);
840 DNSServiceRefDeallocate(sdr
);
844 sdr
->op
= reg_service_request
;
845 sdr
->process_reply
= callBack
? handle_regservice_response
: NULL
;
846 sdr
->app_callback
= callBack
;
847 sdr
->app_context
= context
;
854 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
855 return kDNSServiceErr_Unknown
;
858 static void handle_enumeration_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
860 DNSServiceFlags flags
;
861 uint32_t interfaceIndex
;
862 DNSServiceErrorType err
;
863 char domain
[kDNSServiceMaxDomainName
];
867 flags
= get_flags(&data
);
868 interfaceIndex
= get_long(&data
);
869 err
= get_error_code(&data
);
870 if (get_string(&data
, domain
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
871 if (!err
&& str_error
) err
= kDNSServiceErr_Unknown
;
872 ((DNSServiceDomainEnumReply
)sdr
->app_callback
)(sdr
, flags
, interfaceIndex
, err
, domain
, sdr
->app_context
);
875 DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
877 DNSServiceRef
*sdRef
,
878 DNSServiceFlags flags
,
879 uint32_t interfaceIndex
,
880 DNSServiceDomainEnumReply callBack
,
884 char *msg
= NULL
, *ptr
;
888 DNSServiceErrorType err
;
889 int f1
= (flags
& kDNSServiceFlagsBrowseDomains
) != 0;
890 int f2
= (flags
& kDNSServiceFlagsRegistrationDomains
) != 0;
891 if (f1
+ f2
!= 1) return kDNSServiceErr_BadParam
;
893 if (!sdRef
) return kDNSServiceErr_BadParam
;
896 len
= sizeof(DNSServiceFlags
);
897 len
+= sizeof(uint32_t);
899 hdr
= create_hdr(enumeration_request
, &len
, &ptr
, 1);
900 if (!hdr
) goto error
;
903 put_flags(flags
, &ptr
);
904 put_long(interfaceIndex
, &ptr
);
906 sdr
= connect_to_server();
907 if (!sdr
) goto error
;
908 err
= deliver_request(msg
, sdr
, 1);
911 DNSServiceRefDeallocate(sdr
);
915 sdr
->op
= enumeration_request
;
916 sdr
->process_reply
= handle_enumeration_response
;
917 sdr
->app_callback
= callBack
;
918 sdr
->app_context
= context
;
924 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
925 return kDNSServiceErr_Unknown
;
928 static void handle_regrecord_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
930 DNSServiceFlags flags
;
931 uint32_t interfaceIndex
;
932 DNSServiceErrorType errorCode
;
933 DNSRecordRef rref
= hdr
->client_context
.context
;
935 if (sdr
->op
!= connection
)
937 rref
->app_callback(rref
->sdr
, rref
, 0, kDNSServiceErr_Unknown
, rref
->app_context
);
940 flags
= get_flags(&data
);
941 interfaceIndex
= get_long(&data
);
942 errorCode
= get_error_code(&data
);
944 rref
->app_callback(rref
->sdr
, rref
, flags
, errorCode
, rref
->app_context
);
947 DNSServiceErrorType DNSSD_API
DNSServiceCreateConnection(DNSServiceRef
*sdRef
)
949 if (!sdRef
) return kDNSServiceErr_BadParam
;
950 *sdRef
= connect_to_server();
952 return kDNSServiceErr_Unknown
;
953 (*sdRef
)->op
= connection
;
954 (*sdRef
)->process_reply
= handle_regrecord_response
;
958 DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
961 DNSRecordRef
*RecordRef
,
962 DNSServiceFlags flags
,
963 uint32_t interfaceIndex
,
964 const char *fullname
,
970 DNSServiceRegisterRecordReply callBack
,
974 char *msg
= NULL
, *ptr
;
976 ipc_msg_hdr
*hdr
= NULL
;
977 DNSServiceRef tmp
= NULL
;
978 DNSRecordRef rref
= NULL
;
979 int f1
= (flags
& kDNSServiceFlagsShared
) != 0;
980 int f2
= (flags
& kDNSServiceFlagsUnique
) != 0;
981 if (f1
+ f2
!= 1) return kDNSServiceErr_BadParam
;
983 if (!sdRef
|| sdRef
->op
!= connection
|| sdRef
->sockfd
< 0)
984 return kDNSServiceErr_BadReference
;
987 len
= sizeof(DNSServiceFlags
);
988 len
+= 2 * sizeof(uint32_t); // interfaceIndex, ttl
989 len
+= 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen
990 len
+= strlen(fullname
) + 1;
993 hdr
= create_hdr(reg_record_request
, &len
, &ptr
, 0);
994 if (!hdr
) goto error
;
996 put_flags(flags
, &ptr
);
997 put_long(interfaceIndex
, &ptr
);
998 put_string(fullname
, &ptr
);
999 put_short(rrtype
, &ptr
);
1000 put_short(rrclass
, &ptr
);
1001 put_short(rdlen
, &ptr
);
1002 put_rdata(rdlen
, rdata
, &ptr
);
1003 put_long(ttl
, &ptr
);
1005 rref
= malloc(sizeof(_DNSRecordRef_t
));
1006 if (!rref
) goto error
;
1007 rref
->app_context
= context
;
1008 rref
->app_callback
= callBack
;
1009 rref
->record_index
= sdRef
->max_index
++;
1012 hdr
->client_context
.context
= rref
;
1013 hdr
->reg_index
= rref
->record_index
;
1015 return deliver_request(msg
, sdRef
, 0);
1018 if (rref
) free(rref
);
1021 return kDNSServiceErr_Unknown
;
1024 //sdRef returned by DNSServiceRegister()
1025 DNSServiceErrorType DNSSD_API DNSServiceAddRecord
1027 DNSServiceRef sdRef
,
1028 DNSRecordRef
*RecordRef
,
1029 DNSServiceFlags flags
,
1041 if (!sdRef
|| (sdRef
->op
!= reg_service_request
) || !RecordRef
)
1042 return kDNSServiceErr_BadReference
;
1045 len
+= 2 * sizeof(uint16_t); //rrtype, rdlen
1047 len
+= sizeof(uint32_t);
1048 len
+= sizeof(DNSServiceFlags
);
1050 hdr
= create_hdr(add_record_request
, &len
, &ptr
, 0);
1051 if (!hdr
) return kDNSServiceErr_Unknown
;
1052 put_flags(flags
, &ptr
);
1053 put_short(rrtype
, &ptr
);
1054 put_short(rdlen
, &ptr
);
1055 put_rdata(rdlen
, rdata
, &ptr
);
1056 put_long(ttl
, &ptr
);
1058 rref
= malloc(sizeof(_DNSRecordRef_t
));
1059 if (!rref
) goto error
;
1060 rref
->app_context
= NULL
;
1061 rref
->app_callback
= NULL
;
1062 rref
->record_index
= sdRef
->max_index
++;
1065 hdr
->client_context
.context
= rref
;
1066 hdr
->reg_index
= rref
->record_index
;
1067 return deliver_request((char *)hdr
, sdRef
, 0);
1071 if (rref
) free(rref
);
1072 if (*RecordRef
) *RecordRef
= NULL
;
1073 return kDNSServiceErr_Unknown
;
1076 //DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
1077 DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
1079 DNSServiceRef sdRef
,
1080 DNSRecordRef RecordRef
,
1081 DNSServiceFlags flags
,
1091 if (!sdRef
) return kDNSServiceErr_BadReference
;
1093 len
+= sizeof(uint16_t);
1095 len
+= sizeof(uint32_t);
1096 len
+= sizeof(DNSServiceFlags
);
1098 hdr
= create_hdr(update_record_request
, &len
, &ptr
, 0);
1099 if (!hdr
) return kDNSServiceErr_Unknown
;
1100 hdr
->reg_index
= RecordRef
? RecordRef
->record_index
: TXT_RECORD_INDEX
;
1101 put_flags(flags
, &ptr
);
1102 put_short(rdlen
, &ptr
);
1103 put_rdata(rdlen
, rdata
, &ptr
);
1104 put_long(ttl
, &ptr
);
1105 return deliver_request((char *)hdr
, sdRef
, 0);
1108 DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
1110 DNSServiceRef sdRef
,
1111 DNSRecordRef RecordRef
,
1112 DNSServiceFlags flags
1118 DNSServiceErrorType err
;
1120 if (!sdRef
|| !RecordRef
|| !sdRef
->max_index
)
1121 return kDNSServiceErr_BadReference
;
1123 len
+= sizeof(flags
);
1124 hdr
= create_hdr(remove_record_request
, &len
, &ptr
, 0);
1125 if (!hdr
) return kDNSServiceErr_Unknown
;
1126 hdr
->reg_index
= RecordRef
->record_index
;
1127 put_flags(flags
, &ptr
);
1128 err
= deliver_request((char *)hdr
, sdRef
, 0);
1129 if (!err
) free(RecordRef
);
1133 void DNSSD_API DNSServiceReconfirmRecord
1135 DNSServiceFlags flags
,
1136 uint32_t interfaceIndex
,
1137 const char *fullname
,
1149 len
= sizeof(DNSServiceFlags
);
1150 len
+= sizeof(uint32_t);
1151 len
+= strlen(fullname
) + 1;
1152 len
+= 3 * sizeof(uint16_t);
1154 tmp
= connect_to_server();
1156 hdr
= create_hdr(reconfirm_record_request
, &len
, &ptr
, 1);
1159 put_flags(flags
, &ptr
);
1160 put_long(interfaceIndex
, &ptr
);
1161 put_string(fullname
, &ptr
);
1162 put_short(rrtype
, &ptr
);
1163 put_short(rrclass
, &ptr
);
1164 put_short(rdlen
, &ptr
);
1165 put_rdata(rdlen
, rdata
, &ptr
);
1166 ConvertHeaderBytes(hdr
);
1167 my_write(tmp
->sockfd
, (char *)hdr
, (int) len
);
1169 DNSServiceRefDeallocate(tmp
);