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.48 2005/06/30 18:01:00 shersche
32 <rdar://problem/4096913> Clients shouldn't wait ten seconds to connect to mDNSResponder
34 Revision 1.47 2005/03/31 02:19:56 cheshire
35 <rdar://problem/4021486> Fix build warnings
36 Reviewed by: Scott Herscher
38 Revision 1.46 2005/03/21 00:39:31 shersche
39 <rdar://problem/4021486> Fix build warnings on Win32 platform
41 Revision 1.45 2005/02/01 01:25:06 shersche
42 Define sleep() to be Sleep() for Windows compatibility
44 Revision 1.44 2005/01/27 22:57:56 cheshire
45 Fix compile errors on gcc4
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
50 Revision 1.42 2005/01/11 02:01:02 shersche
51 Use dnssd_close() rather than close() for Windows compatibility
53 Revision 1.41 2004/12/23 17:34:26 ksekar
54 <rdar://problem/3931319> Calls leak sockets if mDNSResponder is not running
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.
60 Revision 1.39 2004/11/12 03:22:00 rpantos
61 rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
63 Revision 1.38 2004/11/02 02:51:23 cheshire
64 <rdar://problem/3526342> Remove overly-restrictive flag checks
66 Revision 1.37 2004/10/14 01:43:35 cheshire
67 Fix opaque port passing problem
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)"
72 Revision 1.35 2004/10/01 22:15:55 rpantos
73 rdar://problem/3824265: Replace APSL in client lib with BSD license.
75 Revision 1.34 2004/09/17 22:36:13 cheshire
76 Add comment explaining that deliver_request frees the message it sends
78 Revision 1.33 2004/09/17 01:17:31 ksekar
79 Remove double-free of msg header, freed automatically by deliver_request()
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.
87 Revision 1.31 2004/09/16 23:37:19 cheshire
88 Free hdr before returning
90 Revision 1.30 2004/09/16 23:14:24 cheshire
91 Changes for Windows compatibility
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
96 Revision 1.28 2004/08/11 17:10:04 cheshire
97 Fix signed/unsigned warnings
99 Revision 1.27 2004/08/11 00:54:16 cheshire
100 Change "hdr->op.request_op" to just "hdr->op"
102 Revision 1.26 2004/07/26 06:07:27 shersche
103 fix bugs when using an error socket to communicate with the daemon
105 Revision 1.25 2004/07/26 05:54:02 shersche
106 DNSServiceProcessResult() returns NoError if socket read returns EWOULDBLOCK
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
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.
116 Revision 1.22 2004/06/26 03:16:34 shersche
117 clean up warning messages on Win32 platform
119 Submitted by: herscher
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.
124 Revision 1.20 2004/06/12 00:50:22 cheshire
125 Changes for Windows compatibility
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.
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
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.
139 Revision 1.16 2004/03/12 22:00:37 cheshire
140 Added: #include <sys/socket.h>
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.
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.)
152 Revision 1.13 2004/01/19 21:46:52 cheshire
155 Revision 1.12 2003/12/23 20:46:47 ksekar
156 <rdar://problem/3497428>: sync dnssd files between libinfo & mDNSResponder
158 Revision 1.11 2003/12/08 21:11:42 rpantos
159 Changes necessary to support mDNSResponder on Linux.
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.
166 Revision 1.9 2003/08/15 21:30:39 cheshire
167 Bring up to date with LibInfo version
169 Revision 1.8 2003/08/13 23:54:52 ksekar
170 Bringing dnssd_clientstub.c up to date with Libinfo, per radar 3376640
172 Revision 1.7 2003/08/12 19:56:25 cheshire
180 #include <winsock2.h>
182 #define sockaddr_mdns sockaddr_in
183 #define AF_MDNS AF_INET
185 IsSystemServiceDisabled();
187 #include <sys/time.h>
188 #include <sys/socket.h>
189 #define sockaddr_mdns sockaddr_un
190 #define AF_MDNS AF_LOCAL
193 #include "dnssd_ipc.h"
196 // disable warning: "'type cast' : from data pointer 'void *' to
198 #pragma warning(disable:4055)
200 // disable warning: "nonstandard extension, function/data pointer
201 // conversion in expression"
202 #pragma warning(disable:4152)
204 #define sleep(X) Sleep((X) * 1000)
206 static int g_initWinsock
= 0;
210 // <rdar://problem/4096913> Specifies how many times we'll try and connect to the
213 #define DNSSD_CLIENT_MAXTRIES 4
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
219 // general utility functions
220 typedef struct _DNSServiceRef_t
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
;
227 uint32_t max_index
; //largest assigned record index - 0 if no additl. recs registered
230 typedef struct _DNSRecordRef_t
233 DNSServiceRegisterRecordReply app_callback
;
235 uint32_t record_index
; // index is unique to the ServiceDiscoveryRef
239 // exported functions
241 // write len bytes. return 0 on success, -1 on error
242 static int my_write(dnssd_sock_t sd
, char *buf
, int len
)
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;
248 ssize_t num_written
= send(sd
, buf
, len
, 0);
249 if (num_written
< 0 || num_written
> len
) return -1;
256 // read len bytes. return 0 on success, -1 on error
257 static int my_read(dnssd_sock_t sd
, char *buf
, int len
)
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;
263 ssize_t num_read
= recv(sd
, buf
, len
, 0);
264 if ((num_read
== 0) || (num_read
< 0) || (num_read
> len
)) return -1;
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.
281 static ipc_msg_hdr
*create_hdr(uint32_t op
, size_t *len
, char **data_start
, int reuse_socket
)
286 #if !defined(USE_TCP_LOOPBACK)
292 #if defined(USE_TCP_LOOPBACK)
293 *len
+= 2; // Allocate space for two-byte port number
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;
303 datalen
= (int) *len
;
304 *len
+= sizeof(ipc_msg_hdr
);
306 // write message to buffer
308 if (!msg
) return NULL
;
312 hdr
->datalen
= datalen
;
313 hdr
->version
= VERSION
;
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
);
323 if (!reuse_socket
) put_string(ctrl_path
, data_start
);
328 // return a connected service ref (deallocate with DNSServiceRefDeallocate)
329 static DNSServiceRef
connect_to_server(void)
331 dnssd_sockaddr_t saddr
;
339 DNSServiceErrorType err
;
343 err
= WSAStartup( MAKEWORD( 2, 2 ), &wsaData
);
345 if (err
!= 0) return NULL
;
348 // <rdar://problem/4096913> If the system service is disabled, we only want to try
351 if ( IsSystemServiceDisabled() )
353 NumTries
= DNSSD_CLIENT_MAXTRIES
;
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
);
367 saddr
.sun_family
= AF_LOCAL
;
368 strcpy(saddr
.sun_path
, MDNS_UDS_SERVERPATH
);
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
383 dnssd_close(sdr
->sockfd
);
384 sdr
->sockfd
= dnssd_InvalidSocket
;
392 static DNSServiceErrorType
deliver_request(void *msg
, DNSServiceRef sdr
, int reuse_sd
)
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
;
400 dnssd_socklen_t len
= (dnssd_socklen_t
) sizeof(caddr
);
401 DNSServiceErrorType err
= kDNSServiceErr_Unknown
;
403 if (!hdr
|| sdr
->sockfd
< 0) return kDNSServiceErr_Unknown
;
407 // setup temporary error socket
408 if ((listenfd
= socket(AF_DNSSD
, SOCK_STREAM
, 0)) < 0)
410 bzero(&caddr
, sizeof(caddr
));
412 #if defined(USE_TCP_LOOPBACK)
414 union { uint16_t s
; u_char b
[2]; } port
;
415 caddr
.sin_family
= AF_INET
;
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
;
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
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
);
434 strcpy(caddr
.sun_path
, data
);
435 ret
= bind(listenfd
, (struct sockaddr
*)&caddr
, sizeof(caddr
));
437 if (ret
< 0) goto cleanup
;
443 ConvertHeaderBytes(hdr
);
444 if (my_write(sdr
->sockfd
, msg
, datalen
+ sizeof(ipc_msg_hdr
)) < 0)
449 if (reuse_sd
) errsd
= sdr
->sockfd
;
453 errsd
= accept(listenfd
, (struct sockaddr
*)&daddr
, &len
);
454 if (errsd
< 0) goto cleanup
;
457 if (my_read(errsd
, (char*)&err
, (int)sizeof(err
)) < 0)
458 err
= kDNSServiceErr_Unknown
;
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
);
472 int DNSSD_API
DNSServiceRefSockFD(DNSServiceRef sdRef
)
474 if (!sdRef
) return -1;
475 return (int) sdRef
->sockfd
;
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
)
485 if (!sdRef
|| sdRef
->sockfd
< 0 || !sdRef
->process_reply
)
486 return kDNSServiceErr_BadReference
;
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
);
502 return kDNSServiceErr_NoError
;
505 void DNSSD_API
DNSServiceRefDeallocate(DNSServiceRef sdRef
)
508 if (sdRef
->sockfd
> 0) dnssd_close(sdRef
->sockfd
);
512 static void handle_resolve_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
514 DNSServiceFlags flags
;
515 char fullname
[kDNSServiceMaxDomainName
];
516 char target
[kDNSServiceMaxDomainName
];
518 union { uint16_t s
; u_char b
[2]; } port
;
520 DNSServiceErrorType err
;
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;
532 txtlen
= get_short(&data
);
533 txtrecord
= get_rdata(&data
, txtlen
);
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
);
539 DNSServiceErrorType DNSSD_API DNSServiceResolve
541 DNSServiceRef
*sdRef
,
542 DNSServiceFlags flags
,
543 uint32_t interfaceIndex
,
547 DNSServiceResolveReply callBack
,
551 char *msg
= NULL
, *ptr
;
555 DNSServiceErrorType err
;
557 if (!sdRef
) return kDNSServiceErr_BadParam
;
560 if (!name
|| !regtype
|| !domain
|| !callBack
) return kDNSServiceErr_BadParam
;
562 // calculate total message length
564 len
+= sizeof(interfaceIndex
);
565 len
+= strlen(name
) + 1;
566 len
+= strlen(regtype
) + 1;
567 len
+= strlen(domain
) + 1;
569 hdr
= create_hdr(resolve_request
, &len
, &ptr
, 1);
570 if (!hdr
) goto error
;
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
);
579 sdr
= connect_to_server();
580 if (!sdr
) goto error
;
581 err
= deliver_request(msg
, sdr
, 1);
584 DNSServiceRefDeallocate(sdr
);
587 sdr
->op
= resolve_request
;
588 sdr
->process_reply
= handle_resolve_response
;
589 sdr
->app_callback
= callBack
;
590 sdr
->app_context
= context
;
597 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
598 return kDNSServiceErr_Unknown
;
601 static void handle_query_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
603 DNSServiceFlags flags
;
604 uint32_t interfaceIndex
, ttl
;
605 DNSServiceErrorType errorCode
;
606 char name
[kDNSServiceMaxDomainName
];
607 uint16_t rrtype
, rrclass
, rdlen
;
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
);
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
);
628 DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
630 DNSServiceRef
*sdRef
,
631 DNSServiceFlags flags
,
632 uint32_t interfaceIndex
,
636 DNSServiceQueryRecordReply callBack
,
640 char *msg
= NULL
, *ptr
;
644 DNSServiceErrorType err
;
646 if (!sdRef
) return kDNSServiceErr_BadParam
;
649 if (!name
) name
= "\0";
651 // calculate total message length
653 len
+= sizeof(uint32_t); //interfaceIndex
654 len
+= strlen(name
) + 1;
655 len
+= 2 * sizeof(uint16_t); // rrtype, rrclass
657 hdr
= create_hdr(query_request
, &len
, &ptr
, 1);
658 if (!hdr
) goto error
;
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
);
667 sdr
= connect_to_server();
668 if (!sdr
) goto error
;
669 err
= deliver_request(msg
, sdr
, 1);
672 DNSServiceRefDeallocate(sdr
);
676 sdr
->op
= query_request
;
677 sdr
->process_reply
= handle_query_response
;
678 sdr
->app_callback
= callBack
;
679 sdr
->app_context
= context
;
685 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
686 return kDNSServiceErr_Unknown
;
689 static void handle_browse_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
691 DNSServiceFlags flags
;
692 uint32_t interfaceIndex
;
693 DNSServiceErrorType errorCode
;
694 char replyName
[256], replyType
[kDNSServiceMaxDomainName
],
695 replyDomain
[kDNSServiceMaxDomainName
];
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
);
709 DNSServiceErrorType DNSSD_API DNSServiceBrowse
711 DNSServiceRef
*sdRef
,
712 DNSServiceFlags flags
,
713 uint32_t interfaceIndex
,
716 DNSServiceBrowseReply callBack
,
720 char *msg
= NULL
, *ptr
;
724 DNSServiceErrorType err
;
726 if (!sdRef
) return kDNSServiceErr_BadParam
;
729 if (!domain
) domain
= "";
732 len
+= sizeof(interfaceIndex
);
733 len
+= strlen(regtype
) + 1;
734 len
+= strlen(domain
) + 1;
736 hdr
= create_hdr(browse_request
, &len
, &ptr
, 1);
737 if (!hdr
) goto error
;
739 put_flags(flags
, &ptr
);
740 put_long(interfaceIndex
, &ptr
);
741 put_string(regtype
, &ptr
);
742 put_string(domain
, &ptr
);
744 sdr
= connect_to_server();
745 if (!sdr
) goto error
;
746 err
= deliver_request(msg
, sdr
, 1);
749 DNSServiceRefDeallocate(sdr
);
752 sdr
->op
= browse_request
;
753 sdr
->process_reply
= handle_browse_response
;
754 sdr
->app_callback
= callBack
;
755 sdr
->app_context
= context
;
761 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
762 return kDNSServiceErr_Unknown
;
765 DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser
767 DNSServiceFlags flags
,
772 DNSServiceErrorType err
;
774 size_t len
= sizeof(flags
) + strlen(domain
) + 1;
775 ipc_msg_hdr
*hdr
= create_hdr(setdomain_request
, &len
, &ptr
, 1);
777 if (!hdr
) return kDNSServiceErr_Unknown
;
778 put_flags(flags
, &ptr
);
779 put_string(domain
, &ptr
);
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
);
789 static void handle_regservice_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
791 DNSServiceFlags flags
;
792 uint32_t interfaceIndex
;
793 DNSServiceErrorType errorCode
;
794 char name
[256], regtype
[kDNSServiceMaxDomainName
], domain
[kDNSServiceMaxDomainName
];
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
);
808 DNSServiceErrorType DNSSD_API DNSServiceRegister
810 DNSServiceRef
*sdRef
,
811 DNSServiceFlags flags
,
812 uint32_t interfaceIndex
,
817 uint16_t PortInNetworkByteOrder
,
819 const void *txtRecord
,
820 DNSServiceRegisterReply callBack
,
824 char *msg
= NULL
, *ptr
;
828 DNSServiceErrorType err
;
829 union { uint16_t s
; u_char b
[2]; } port
= { PortInNetworkByteOrder
};
831 if (!sdRef
) return kDNSServiceErr_BadParam
;
834 if (!name
) name
= "";
835 if (!regtype
) return kDNSServiceErr_BadParam
;
836 if (!domain
) domain
= "";
837 if (!host
) host
= "";
838 if (!txtRecord
) txtRecord
= (void*)"";
840 // auto-name must also have auto-rename
841 if (!name
[0] && (flags
& kDNSServiceFlagsNoAutoRename
))
842 return kDNSServiceErr_BadParam
;
844 // no callback must have auto-name
845 if (!callBack
&& name
[0]) return kDNSServiceErr_BadParam
;
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
853 hdr
= create_hdr(reg_service_request
, &len
, &ptr
, 1);
854 if (!hdr
) goto error
;
855 if (!callBack
) hdr
->flags
|= IPC_FLAGS_NOREPLY
;
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
);
865 put_short(txtLen
, &ptr
);
866 put_rdata(txtLen
, txtRecord
, &ptr
);
868 sdr
= connect_to_server();
869 if (!sdr
) goto error
;
870 err
= deliver_request(msg
, sdr
, 1);
873 DNSServiceRefDeallocate(sdr
);
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
;
887 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
888 return kDNSServiceErr_Unknown
;
891 static void handle_enumeration_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
893 DNSServiceFlags flags
;
894 uint32_t interfaceIndex
;
895 DNSServiceErrorType err
;
896 char domain
[kDNSServiceMaxDomainName
];
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
);
908 DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
910 DNSServiceRef
*sdRef
,
911 DNSServiceFlags flags
,
912 uint32_t interfaceIndex
,
913 DNSServiceDomainEnumReply callBack
,
917 char *msg
= NULL
, *ptr
;
921 DNSServiceErrorType err
;
922 int f1
= (flags
& kDNSServiceFlagsBrowseDomains
) != 0;
923 int f2
= (flags
& kDNSServiceFlagsRegistrationDomains
) != 0;
924 if (f1
+ f2
!= 1) return kDNSServiceErr_BadParam
;
926 if (!sdRef
) return kDNSServiceErr_BadParam
;
929 len
= sizeof(DNSServiceFlags
);
930 len
+= sizeof(uint32_t);
932 hdr
= create_hdr(enumeration_request
, &len
, &ptr
, 1);
933 if (!hdr
) goto error
;
936 put_flags(flags
, &ptr
);
937 put_long(interfaceIndex
, &ptr
);
939 sdr
= connect_to_server();
940 if (!sdr
) goto error
;
941 err
= deliver_request(msg
, sdr
, 1);
944 DNSServiceRefDeallocate(sdr
);
948 sdr
->op
= enumeration_request
;
949 sdr
->process_reply
= handle_enumeration_response
;
950 sdr
->app_callback
= callBack
;
951 sdr
->app_context
= context
;
957 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
958 return kDNSServiceErr_Unknown
;
961 static void handle_regrecord_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
963 DNSServiceFlags flags
;
964 uint32_t interfaceIndex
;
965 DNSServiceErrorType errorCode
;
966 DNSRecordRef rref
= hdr
->client_context
.context
;
968 if (sdr
->op
!= connection
)
970 rref
->app_callback(rref
->sdr
, rref
, 0, kDNSServiceErr_Unknown
, rref
->app_context
);
973 flags
= get_flags(&data
);
974 interfaceIndex
= get_long(&data
);
975 errorCode
= get_error_code(&data
);
977 rref
->app_callback(rref
->sdr
, rref
, flags
, errorCode
, rref
->app_context
);
980 DNSServiceErrorType DNSSD_API
DNSServiceCreateConnection(DNSServiceRef
*sdRef
)
982 if (!sdRef
) return kDNSServiceErr_BadParam
;
983 *sdRef
= connect_to_server();
985 return kDNSServiceErr_Unknown
;
986 (*sdRef
)->op
= connection
;
987 (*sdRef
)->process_reply
= handle_regrecord_response
;
991 DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
994 DNSRecordRef
*RecordRef
,
995 DNSServiceFlags flags
,
996 uint32_t interfaceIndex
,
997 const char *fullname
,
1003 DNSServiceRegisterRecordReply callBack
,
1007 char *msg
= NULL
, *ptr
;
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
;
1016 if (!sdRef
|| sdRef
->op
!= connection
|| sdRef
->sockfd
< 0)
1017 return kDNSServiceErr_BadReference
;
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;
1026 hdr
= create_hdr(reg_record_request
, &len
, &ptr
, 0);
1027 if (!hdr
) goto error
;
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
);
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
++;
1045 hdr
->client_context
.context
= rref
;
1046 hdr
->reg_index
= rref
->record_index
;
1048 return deliver_request(msg
, sdRef
, 0);
1051 if (rref
) free(rref
);
1054 return kDNSServiceErr_Unknown
;
1057 //sdRef returned by DNSServiceRegister()
1058 DNSServiceErrorType DNSSD_API DNSServiceAddRecord
1060 DNSServiceRef sdRef
,
1061 DNSRecordRef
*RecordRef
,
1062 DNSServiceFlags flags
,
1074 if (!sdRef
|| (sdRef
->op
!= reg_service_request
) || !RecordRef
)
1075 return kDNSServiceErr_BadReference
;
1078 len
+= 2 * sizeof(uint16_t); //rrtype, rdlen
1080 len
+= sizeof(uint32_t);
1081 len
+= sizeof(DNSServiceFlags
);
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
);
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
++;
1098 hdr
->client_context
.context
= rref
;
1099 hdr
->reg_index
= rref
->record_index
;
1100 return deliver_request((char *)hdr
, sdRef
, 0);
1104 if (rref
) free(rref
);
1105 if (*RecordRef
) *RecordRef
= NULL
;
1106 return kDNSServiceErr_Unknown
;
1109 //DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
1110 DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
1112 DNSServiceRef sdRef
,
1113 DNSRecordRef RecordRef
,
1114 DNSServiceFlags flags
,
1124 if (!sdRef
) return kDNSServiceErr_BadReference
;
1126 len
+= sizeof(uint16_t);
1128 len
+= sizeof(uint32_t);
1129 len
+= sizeof(DNSServiceFlags
);
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);
1141 DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
1143 DNSServiceRef sdRef
,
1144 DNSRecordRef RecordRef
,
1145 DNSServiceFlags flags
1151 DNSServiceErrorType err
;
1153 if (!sdRef
|| !RecordRef
|| !sdRef
->max_index
)
1154 return kDNSServiceErr_BadReference
;
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
);
1166 void DNSSD_API DNSServiceReconfirmRecord
1168 DNSServiceFlags flags
,
1169 uint32_t interfaceIndex
,
1170 const char *fullname
,
1182 len
= sizeof(DNSServiceFlags
);
1183 len
+= sizeof(uint32_t);
1184 len
+= strlen(fullname
) + 1;
1185 len
+= 3 * sizeof(uint16_t);
1187 tmp
= connect_to_server();
1189 hdr
= create_hdr(reconfirm_record_request
, &len
, &ptr
, 1);
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
);
1202 DNSServiceRefDeallocate(tmp
);