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.47 2005/03/31 02:19:56 cheshire
32 <rdar://problem/4021486> Fix build warnings
33 Reviewed by: Scott Herscher
35 Revision 1.46 2005/03/21 00:39:31 shersche
36 <rdar://problem/4021486> Fix build warnings on Win32 platform
38 Revision 1.45 2005/02/01 01:25:06 shersche
39 Define sleep() to be Sleep() for Windows compatibility
41 Revision 1.44 2005/01/27 22:57:56 cheshire
42 Fix compile errors on gcc4
44 Revision 1.43 2005/01/27 00:02:29 cheshire
45 <rdar://problem/3947461> Handle case where client runs before daemon has finished launching
47 Revision 1.42 2005/01/11 02:01:02 shersche
48 Use dnssd_close() rather than close() for Windows compatibility
50 Revision 1.41 2004/12/23 17:34:26 ksekar
51 <rdar://problem/3931319> Calls leak sockets if mDNSResponder is not running
53 Revision 1.40 2004/11/23 03:39:47 cheshire
54 Let interface name/index mapping capability live directly in JNISupport.c,
55 instead of having to call through to the daemon via IPC to get this information.
57 Revision 1.39 2004/11/12 03:22:00 rpantos
58 rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
60 Revision 1.38 2004/11/02 02:51:23 cheshire
61 <rdar://problem/3526342> Remove overly-restrictive flag checks
63 Revision 1.37 2004/10/14 01:43:35 cheshire
64 Fix opaque port passing problem
66 Revision 1.36 2004/10/06 02:22:19 cheshire
67 Changed MacRoman copyright symbol (should have been UTF-8 in any case :-) to ASCII-compatible "(c)"
69 Revision 1.35 2004/10/01 22:15:55 rpantos
70 rdar://problem/3824265: Replace APSL in client lib with BSD license.
72 Revision 1.34 2004/09/17 22:36:13 cheshire
73 Add comment explaining that deliver_request frees the message it sends
75 Revision 1.33 2004/09/17 01:17:31 ksekar
76 Remove double-free of msg header, freed automatically by deliver_request()
78 Revision 1.32 2004/09/17 01:08:55 cheshire
79 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
80 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
81 declared in that file are ONLY appropriate to single-address-space embedded applications.
82 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
84 Revision 1.31 2004/09/16 23:37:19 cheshire
85 Free hdr before returning
87 Revision 1.30 2004/09/16 23:14:24 cheshire
88 Changes for Windows compatibility
90 Revision 1.29 2004/09/16 21:46:38 ksekar
91 <rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area domain
93 Revision 1.28 2004/08/11 17:10:04 cheshire
94 Fix signed/unsigned warnings
96 Revision 1.27 2004/08/11 00:54:16 cheshire
97 Change "hdr->op.request_op" to just "hdr->op"
99 Revision 1.26 2004/07/26 06:07:27 shersche
100 fix bugs when using an error socket to communicate with the daemon
102 Revision 1.25 2004/07/26 05:54:02 shersche
103 DNSServiceProcessResult() returns NoError if socket read returns EWOULDBLOCK
105 Revision 1.24 2004/07/20 06:46:21 shersche
106 <rdar://problem/3730123> fix endless loop in my_read() if recv returns 0
109 Revision 1.23 2004/06/29 00:48:38 cheshire
110 Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
111 use an explicit while() loop instead.
113 Revision 1.22 2004/06/26 03:16:34 shersche
114 clean up warning messages on Win32 platform
116 Submitted by: herscher
118 Revision 1.21 2004/06/18 04:53:56 rpantos
119 Use platform layer for socket types. Introduce USE_TCP_LOOPBACK. Remove dependency on mDNSEmbeddedAPI.h.
121 Revision 1.20 2004/06/12 00:50:22 cheshire
122 Changes for Windows compatibility
124 Revision 1.19 2004/05/25 18:29:33 cheshire
125 Move DNSServiceConstructFullName() from dnssd_clientstub.c to dnssd_clientlib.c,
126 so that it's also accessible to dnssd_clientshim.c (single address space) clients.
128 Revision 1.18 2004/05/18 23:51:27 cheshire
129 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
131 Revision 1.17 2004/05/06 18:42:58 ksekar
132 General dns_sd.h API cleanup, including the following radars:
133 <rdar://problem/3592068>: Remove flags with zero value
134 <rdar://problem/3479569>: Passing in NULL causes a crash.
136 Revision 1.16 2004/03/12 22:00:37 cheshire
137 Added: #include <sys/socket.h>
139 Revision 1.15 2004/01/20 18:36:29 ksekar
140 Propagated Libinfo fix for <rdar://problem/3483971>: SU:
141 DNSServiceUpdateRecord() doesn't allow you to update the TXT record
142 into TOT mDNSResponder.
144 Revision 1.14 2004/01/19 22:39:17 cheshire
145 Don't use "MSG_WAITALL"; it makes send() return "Invalid argument" on Linux;
146 use an explicit while() loop instead. (In any case, this should only make a difference
147 with non-blocking sockets, which we don't use on the client side right now.)
149 Revision 1.13 2004/01/19 21:46:52 cheshire
152 Revision 1.12 2003/12/23 20:46:47 ksekar
153 <rdar://problem/3497428>: sync dnssd files between libinfo & mDNSResponder
155 Revision 1.11 2003/12/08 21:11:42 rpantos
156 Changes necessary to support mDNSResponder on Linux.
158 Revision 1.10 2003/10/13 23:50:53 ksekar
159 Updated dns_sd clientstub files to bring copies in synch with
160 top-of-tree Libinfo: A memory leak in dnssd_clientstub.c is fixed,
161 and comments in dns_sd.h are improved.
163 Revision 1.9 2003/08/15 21:30:39 cheshire
164 Bring up to date with LibInfo version
166 Revision 1.8 2003/08/13 23:54:52 ksekar
167 Bringing dnssd_clientstub.c up to date with Libinfo, per radar 3376640
169 Revision 1.7 2003/08/12 19:56:25 cheshire
177 #include <winsock2.h>
179 #define sockaddr_mdns sockaddr_in
180 #define AF_MDNS AF_INET
182 #include <sys/time.h>
183 #include <sys/socket.h>
184 #define sockaddr_mdns sockaddr_un
185 #define AF_MDNS AF_LOCAL
188 #include "dnssd_ipc.h"
191 // disable warning: "'type cast' : from data pointer 'void *' to
193 #pragma warning(disable:4055)
195 // disable warning: "nonstandard extension, function/data pointer
196 // conversion in expression"
197 #pragma warning(disable:4152)
199 #define sleep(X) Sleep((X) * 1000)
201 static int g_initWinsock
= 0;
205 #define CTL_PATH_PREFIX "/tmp/dnssd_clippath."
206 // error socket (if needed) is named "dnssd_clipath.[pid].xxx:n" where xxx are the
207 // last 3 digits of the time (in seconds) and n is the 6-digit microsecond time
209 // general utility functions
210 typedef struct _DNSServiceRef_t
212 dnssd_sock_t sockfd
; // connected socket between client and daemon
213 uint32_t op
; // request_op_t or reply_op_t
214 process_reply_callback process_reply
;
217 uint32_t max_index
; //largest assigned record index - 0 if no additl. recs registered
220 typedef struct _DNSRecordRef_t
223 DNSServiceRegisterRecordReply app_callback
;
225 uint32_t record_index
; // index is unique to the ServiceDiscoveryRef
229 // exported functions
231 // write len bytes. return 0 on success, -1 on error
232 static int my_write(dnssd_sock_t sd
, char *buf
, int len
)
234 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
235 //if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
238 ssize_t num_written
= send(sd
, buf
, len
, 0);
239 if (num_written
< 0 || num_written
> len
) return -1;
246 // read len bytes. return 0 on success, -1 on error
247 static int my_read(dnssd_sock_t sd
, char *buf
, int len
)
249 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
250 //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1;
253 ssize_t num_read
= recv(sd
, buf
, len
, 0);
254 if ((num_read
== 0) || (num_read
< 0) || (num_read
> len
)) return -1;
263 * allocate and initialize an ipc message header. value of len should initially be the
264 * length of the data, and is set to the value of the data plus the header. data_start
265 * is set to point to the beginning of the data section. reuse_socket should be non-zero
266 * for calls that can receive an immediate error return value on their primary socket.
267 * if zero, the path to a control socket is appended at the beginning of the message buffer.
268 * data_start is set past this string.
271 static ipc_msg_hdr
*create_hdr(uint32_t op
, size_t *len
, char **data_start
, int reuse_socket
)
276 #if !defined(USE_TCP_LOOPBACK)
282 #if defined(USE_TCP_LOOPBACK)
283 *len
+= 2; // Allocate space for two-byte port number
286 if (gettimeofday(&time
, NULL
) < 0) return NULL
;
287 sprintf(ctrl_path
, "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX
, (int)getpid(),
288 (unsigned long)(time
.tv_sec
& 0xFFF), (unsigned long)(time
.tv_usec
));
289 *len
+= strlen(ctrl_path
) + 1;
293 datalen
= (int) *len
;
294 *len
+= sizeof(ipc_msg_hdr
);
296 // write message to buffer
298 if (!msg
) return NULL
;
302 hdr
->datalen
= datalen
;
303 hdr
->version
= VERSION
;
305 if (reuse_socket
) hdr
->flags
|= IPC_FLAGS_REUSE_SOCKET
;
306 *data_start
= msg
+ sizeof(ipc_msg_hdr
);
307 #if defined(USE_TCP_LOOPBACK)
308 // Put dummy data in for the port, since we don't know what
309 // it is yet. The data will get filled in before we
310 // send the message. This happens in deliver_request().
311 if (!reuse_socket
) put_short(0, data_start
);
313 if (!reuse_socket
) put_string(ctrl_path
, data_start
);
318 // return a connected service ref (deallocate with DNSServiceRefDeallocate)
319 static DNSServiceRef
connect_to_server(void)
321 dnssd_sockaddr_t saddr
;
329 DNSServiceErrorType err
;
333 err
= WSAStartup( MAKEWORD( 2, 2 ), &wsaData
);
335 if (err
!= 0) return NULL
;
339 sdr
= malloc(sizeof(_DNSServiceRef_t
));
340 if (!sdr
) return(NULL
);
341 sdr
->sockfd
= socket(AF_DNSSD
, SOCK_STREAM
, 0);
342 if (sdr
->sockfd
== dnssd_InvalidSocket
) { free(sdr
); return NULL
; }
343 #if defined(USE_TCP_LOOPBACK)
344 saddr
.sin_family
= AF_INET
;
345 saddr
.sin_addr
.s_addr
= inet_addr(MDNS_TCP_SERVERADDR
);
346 saddr
.sin_port
= htons(MDNS_TCP_SERVERPORT
);
348 saddr
.sun_family
= AF_LOCAL
;
349 strcpy(saddr
.sun_path
, MDNS_UDS_SERVERPATH
);
353 int err
= connect(sdr
->sockfd
, (struct sockaddr
*) &saddr
, sizeof(saddr
));
354 if (!err
) break; // If we succeeded, return sdr
355 // If we failed, then it may be because the daemon is still launching.
356 // This can happen for processes that launch early in the boot process, while the
357 // daemon is still coming up. Rather than fail here, we'll wait a bit and try again.
358 // If, after ten seconds, we still can't connect to the daemon,
359 // then we give up and return a failure code.
361 sleep(1); // Sleep a bit, then try again
364 dnssd_close(sdr
->sockfd
);
365 sdr
->sockfd
= dnssd_InvalidSocket
;
373 static DNSServiceErrorType
deliver_request(void *msg
, DNSServiceRef sdr
, int reuse_sd
)
375 ipc_msg_hdr
*hdr
= msg
;
376 uint32_t datalen
= hdr
->datalen
;
377 dnssd_sockaddr_t caddr
, daddr
; // (client and daemon address structs)
378 char *data
= (char *)msg
+ sizeof(ipc_msg_hdr
);
379 dnssd_sock_t listenfd
= dnssd_InvalidSocket
, errsd
= dnssd_InvalidSocket
;
381 dnssd_socklen_t len
= (dnssd_socklen_t
) sizeof(caddr
);
382 DNSServiceErrorType err
= kDNSServiceErr_Unknown
;
384 if (!hdr
|| sdr
->sockfd
< 0) return kDNSServiceErr_Unknown
;
388 // setup temporary error socket
389 if ((listenfd
= socket(AF_DNSSD
, SOCK_STREAM
, 0)) < 0)
391 bzero(&caddr
, sizeof(caddr
));
393 #if defined(USE_TCP_LOOPBACK)
395 union { uint16_t s
; u_char b
[2]; } port
;
396 caddr
.sin_family
= AF_INET
;
398 caddr
.sin_addr
.s_addr
= inet_addr(MDNS_TCP_SERVERADDR
);
399 ret
= bind(listenfd
, (struct sockaddr
*) &caddr
, sizeof(caddr
));
400 if (ret
< 0) goto cleanup
;
401 if (getsockname(listenfd
, (struct sockaddr
*) &caddr
, &len
) < 0) goto cleanup
;
403 port
.s
= caddr
.sin_port
;
404 data
[0] = port
.b
[0]; // don't switch the byte order, as the
405 data
[1] = port
.b
[1]; // daemon expects it in network byte order
409 mode_t mask
= umask(0);
410 caddr
.sun_family
= AF_LOCAL
;
411 #ifndef NOT_HAVE_SA_LEN // According to Stevens (section 3.2), there is no portable way to
412 // determine whether sa_len is defined on a particular platform.
413 caddr
.sun_len
= sizeof(struct sockaddr_un
);
415 strcpy(caddr
.sun_path
, data
);
416 ret
= bind(listenfd
, (struct sockaddr
*)&caddr
, sizeof(caddr
));
418 if (ret
< 0) goto cleanup
;
424 ConvertHeaderBytes(hdr
);
425 if (my_write(sdr
->sockfd
, msg
, datalen
+ sizeof(ipc_msg_hdr
)) < 0)
430 if (reuse_sd
) errsd
= sdr
->sockfd
;
434 errsd
= accept(listenfd
, (struct sockaddr
*)&daddr
, &len
);
435 if (errsd
< 0) goto cleanup
;
438 if (my_read(errsd
, (char*)&err
, (int)sizeof(err
)) < 0)
439 err
= kDNSServiceErr_Unknown
;
444 if (!reuse_sd
&& listenfd
> 0) dnssd_close(listenfd
);
445 if (!reuse_sd
&& errsd
> 0) dnssd_close(errsd
);
446 #if !defined(USE_TCP_LOOPBACK)
447 if (!reuse_sd
&& data
) unlink(data
);
453 int DNSSD_API
DNSServiceRefSockFD(DNSServiceRef sdRef
)
455 if (!sdRef
) return -1;
456 return (int) sdRef
->sockfd
;
459 // handle reply from server, calling application client callback. If there is no reply
460 // from the daemon on the socket contained in sdRef, the call will block.
461 DNSServiceErrorType DNSSD_API
DNSServiceProcessResult(DNSServiceRef sdRef
)
466 if (!sdRef
|| sdRef
->sockfd
< 0 || !sdRef
->process_reply
)
467 return kDNSServiceErr_BadReference
;
469 if (my_read(sdRef
->sockfd
, (void *)&hdr
, sizeof(hdr
)) < 0)
470 // return NoError on EWOULDBLOCK. This will handle the case
471 // where a non-blocking socket is told there is data, but
472 // it was a false positive.
473 return (dnssd_errno() == dnssd_EWOULDBLOCK
) ? kDNSServiceErr_NoError
: kDNSServiceErr_Unknown
;
474 ConvertHeaderBytes(&hdr
);
475 if (hdr
.version
!= VERSION
)
476 return kDNSServiceErr_Incompatible
;
477 data
= malloc(hdr
.datalen
);
478 if (!data
) return kDNSServiceErr_NoMemory
;
479 if (my_read(sdRef
->sockfd
, data
, hdr
.datalen
) < 0)
480 return kDNSServiceErr_Unknown
;
481 sdRef
->process_reply(sdRef
, &hdr
, data
);
483 return kDNSServiceErr_NoError
;
486 void DNSSD_API
DNSServiceRefDeallocate(DNSServiceRef sdRef
)
489 if (sdRef
->sockfd
> 0) dnssd_close(sdRef
->sockfd
);
493 static void handle_resolve_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
495 DNSServiceFlags flags
;
496 char fullname
[kDNSServiceMaxDomainName
];
497 char target
[kDNSServiceMaxDomainName
];
499 union { uint16_t s
; u_char b
[2]; } port
;
501 DNSServiceErrorType err
;
506 flags
= get_flags(&data
);
507 ifi
= get_long(&data
);
508 err
= get_error_code(&data
);
509 if (get_string(&data
, fullname
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
510 if (get_string(&data
, target
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
513 txtlen
= get_short(&data
);
514 txtrecord
= get_rdata(&data
, txtlen
);
516 if (!err
&& str_error
) err
= kDNSServiceErr_Unknown
;
517 ((DNSServiceResolveReply
)sdr
->app_callback
)(sdr
, flags
, ifi
, err
, fullname
, target
, port
.s
, txtlen
, txtrecord
, sdr
->app_context
);
520 DNSServiceErrorType DNSSD_API DNSServiceResolve
522 DNSServiceRef
*sdRef
,
523 DNSServiceFlags flags
,
524 uint32_t interfaceIndex
,
528 DNSServiceResolveReply callBack
,
532 char *msg
= NULL
, *ptr
;
536 DNSServiceErrorType err
;
538 if (!sdRef
) return kDNSServiceErr_BadParam
;
541 if (!name
|| !regtype
|| !domain
|| !callBack
) return kDNSServiceErr_BadParam
;
543 // calculate total message length
545 len
+= sizeof(interfaceIndex
);
546 len
+= strlen(name
) + 1;
547 len
+= strlen(regtype
) + 1;
548 len
+= strlen(domain
) + 1;
550 hdr
= create_hdr(resolve_request
, &len
, &ptr
, 1);
551 if (!hdr
) goto error
;
554 put_flags(flags
, &ptr
);
555 put_long(interfaceIndex
, &ptr
);
556 put_string(name
, &ptr
);
557 put_string(regtype
, &ptr
);
558 put_string(domain
, &ptr
);
560 sdr
= connect_to_server();
561 if (!sdr
) goto error
;
562 err
= deliver_request(msg
, sdr
, 1);
565 DNSServiceRefDeallocate(sdr
);
568 sdr
->op
= resolve_request
;
569 sdr
->process_reply
= handle_resolve_response
;
570 sdr
->app_callback
= callBack
;
571 sdr
->app_context
= context
;
578 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
579 return kDNSServiceErr_Unknown
;
582 static void handle_query_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
584 DNSServiceFlags flags
;
585 uint32_t interfaceIndex
, ttl
;
586 DNSServiceErrorType errorCode
;
587 char name
[kDNSServiceMaxDomainName
];
588 uint16_t rrtype
, rrclass
, rdlen
;
593 flags
= get_flags(&data
);
594 interfaceIndex
= get_long(&data
);
595 errorCode
= get_error_code(&data
);
596 if (get_string(&data
, name
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
597 rrtype
= get_short(&data
);
598 rrclass
= get_short(&data
);
599 rdlen
= get_short(&data
);
600 rdata
= get_rdata(&data
, rdlen
);
601 ttl
= get_long(&data
);
603 if (!errorCode
&& str_error
) errorCode
= kDNSServiceErr_Unknown
;
604 ((DNSServiceQueryRecordReply
)sdr
->app_callback
)(sdr
, flags
, interfaceIndex
, errorCode
, name
, rrtype
, rrclass
,
605 rdlen
, rdata
, ttl
, sdr
->app_context
);
609 DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
611 DNSServiceRef
*sdRef
,
612 DNSServiceFlags flags
,
613 uint32_t interfaceIndex
,
617 DNSServiceQueryRecordReply callBack
,
621 char *msg
= NULL
, *ptr
;
625 DNSServiceErrorType err
;
627 if (!sdRef
) return kDNSServiceErr_BadParam
;
630 if (!name
) name
= "\0";
632 // calculate total message length
634 len
+= sizeof(uint32_t); //interfaceIndex
635 len
+= strlen(name
) + 1;
636 len
+= 2 * sizeof(uint16_t); // rrtype, rrclass
638 hdr
= create_hdr(query_request
, &len
, &ptr
, 1);
639 if (!hdr
) goto error
;
642 put_flags(flags
, &ptr
);
643 put_long(interfaceIndex
, &ptr
);
644 put_string(name
, &ptr
);
645 put_short(rrtype
, &ptr
);
646 put_short(rrclass
, &ptr
);
648 sdr
= connect_to_server();
649 if (!sdr
) goto error
;
650 err
= deliver_request(msg
, sdr
, 1);
653 DNSServiceRefDeallocate(sdr
);
657 sdr
->op
= query_request
;
658 sdr
->process_reply
= handle_query_response
;
659 sdr
->app_callback
= callBack
;
660 sdr
->app_context
= context
;
666 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
667 return kDNSServiceErr_Unknown
;
670 static void handle_browse_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
672 DNSServiceFlags flags
;
673 uint32_t interfaceIndex
;
674 DNSServiceErrorType errorCode
;
675 char replyName
[256], replyType
[kDNSServiceMaxDomainName
],
676 replyDomain
[kDNSServiceMaxDomainName
];
680 flags
= get_flags(&data
);
681 interfaceIndex
= get_long(&data
);
682 errorCode
= get_error_code(&data
);
683 if (get_string(&data
, replyName
, 256) < 0) str_error
= 1;
684 if (get_string(&data
, replyType
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
685 if (get_string(&data
, replyDomain
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
686 if (!errorCode
&& str_error
) errorCode
= kDNSServiceErr_Unknown
;
687 ((DNSServiceBrowseReply
)sdr
->app_callback
)(sdr
, flags
, interfaceIndex
, errorCode
, replyName
, replyType
, replyDomain
, sdr
->app_context
);
690 DNSServiceErrorType DNSSD_API DNSServiceBrowse
692 DNSServiceRef
*sdRef
,
693 DNSServiceFlags flags
,
694 uint32_t interfaceIndex
,
697 DNSServiceBrowseReply callBack
,
701 char *msg
= NULL
, *ptr
;
705 DNSServiceErrorType err
;
707 if (!sdRef
) return kDNSServiceErr_BadParam
;
710 if (!domain
) domain
= "";
713 len
+= sizeof(interfaceIndex
);
714 len
+= strlen(regtype
) + 1;
715 len
+= strlen(domain
) + 1;
717 hdr
= create_hdr(browse_request
, &len
, &ptr
, 1);
718 if (!hdr
) goto error
;
720 put_flags(flags
, &ptr
);
721 put_long(interfaceIndex
, &ptr
);
722 put_string(regtype
, &ptr
);
723 put_string(domain
, &ptr
);
725 sdr
= connect_to_server();
726 if (!sdr
) goto error
;
727 err
= deliver_request(msg
, sdr
, 1);
730 DNSServiceRefDeallocate(sdr
);
733 sdr
->op
= browse_request
;
734 sdr
->process_reply
= handle_browse_response
;
735 sdr
->app_callback
= callBack
;
736 sdr
->app_context
= context
;
742 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
743 return kDNSServiceErr_Unknown
;
746 DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser
748 DNSServiceFlags flags
,
753 DNSServiceErrorType err
;
755 size_t len
= sizeof(flags
) + strlen(domain
) + 1;
756 ipc_msg_hdr
*hdr
= create_hdr(setdomain_request
, &len
, &ptr
, 1);
758 if (!hdr
) return kDNSServiceErr_Unknown
;
759 put_flags(flags
, &ptr
);
760 put_string(domain
, &ptr
);
762 sdr
= connect_to_server();
763 if (!sdr
) { free(hdr
); return kDNSServiceErr_Unknown
; }
764 err
= deliver_request((char *)hdr
, sdr
, 1); // deliver_request frees the message for us
765 DNSServiceRefDeallocate(sdr
);
770 static void handle_regservice_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
772 DNSServiceFlags flags
;
773 uint32_t interfaceIndex
;
774 DNSServiceErrorType errorCode
;
775 char name
[256], regtype
[kDNSServiceMaxDomainName
], domain
[kDNSServiceMaxDomainName
];
779 flags
= get_flags(&data
);
780 interfaceIndex
= get_long(&data
);
781 errorCode
= get_error_code(&data
);
782 if (get_string(&data
, name
, 256) < 0) str_error
= 1;
783 if (get_string(&data
, regtype
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
784 if (get_string(&data
, domain
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
785 if (!errorCode
&& str_error
) errorCode
= kDNSServiceErr_Unknown
;
786 ((DNSServiceRegisterReply
)sdr
->app_callback
)(sdr
, flags
, errorCode
, name
, regtype
, domain
, sdr
->app_context
);
789 DNSServiceErrorType DNSSD_API DNSServiceRegister
791 DNSServiceRef
*sdRef
,
792 DNSServiceFlags flags
,
793 uint32_t interfaceIndex
,
798 uint16_t PortInNetworkByteOrder
,
800 const void *txtRecord
,
801 DNSServiceRegisterReply callBack
,
805 char *msg
= NULL
, *ptr
;
809 DNSServiceErrorType err
;
810 union { uint16_t s
; u_char b
[2]; } port
= { PortInNetworkByteOrder
};
812 if (!sdRef
) return kDNSServiceErr_BadParam
;
815 if (!name
) name
= "";
816 if (!regtype
) return kDNSServiceErr_BadParam
;
817 if (!domain
) domain
= "";
818 if (!host
) host
= "";
819 if (!txtRecord
) txtRecord
= (void*)"";
821 // auto-name must also have auto-rename
822 if (!name
[0] && (flags
& kDNSServiceFlagsNoAutoRename
))
823 return kDNSServiceErr_BadParam
;
825 // no callback must have auto-name
826 if (!callBack
&& name
[0]) return kDNSServiceErr_BadParam
;
828 len
= sizeof(DNSServiceFlags
);
829 len
+= sizeof(uint32_t); // interfaceIndex
830 len
+= strlen(name
) + strlen(regtype
) + strlen(domain
) + strlen(host
) + 4;
831 len
+= 2 * sizeof(uint16_t); // port, txtLen
834 hdr
= create_hdr(reg_service_request
, &len
, &ptr
, 1);
835 if (!hdr
) goto error
;
836 if (!callBack
) hdr
->flags
|= IPC_FLAGS_NOREPLY
;
838 put_flags(flags
, &ptr
);
839 put_long(interfaceIndex
, &ptr
);
840 put_string(name
, &ptr
);
841 put_string(regtype
, &ptr
);
842 put_string(domain
, &ptr
);
843 put_string(host
, &ptr
);
846 put_short(txtLen
, &ptr
);
847 put_rdata(txtLen
, txtRecord
, &ptr
);
849 sdr
= connect_to_server();
850 if (!sdr
) goto error
;
851 err
= deliver_request(msg
, sdr
, 1);
854 DNSServiceRefDeallocate(sdr
);
858 sdr
->op
= reg_service_request
;
859 sdr
->process_reply
= callBack
? handle_regservice_response
: NULL
;
860 sdr
->app_callback
= callBack
;
861 sdr
->app_context
= context
;
868 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
869 return kDNSServiceErr_Unknown
;
872 static void handle_enumeration_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
874 DNSServiceFlags flags
;
875 uint32_t interfaceIndex
;
876 DNSServiceErrorType err
;
877 char domain
[kDNSServiceMaxDomainName
];
881 flags
= get_flags(&data
);
882 interfaceIndex
= get_long(&data
);
883 err
= get_error_code(&data
);
884 if (get_string(&data
, domain
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
885 if (!err
&& str_error
) err
= kDNSServiceErr_Unknown
;
886 ((DNSServiceDomainEnumReply
)sdr
->app_callback
)(sdr
, flags
, interfaceIndex
, err
, domain
, sdr
->app_context
);
889 DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
891 DNSServiceRef
*sdRef
,
892 DNSServiceFlags flags
,
893 uint32_t interfaceIndex
,
894 DNSServiceDomainEnumReply callBack
,
898 char *msg
= NULL
, *ptr
;
902 DNSServiceErrorType err
;
903 int f1
= (flags
& kDNSServiceFlagsBrowseDomains
) != 0;
904 int f2
= (flags
& kDNSServiceFlagsRegistrationDomains
) != 0;
905 if (f1
+ f2
!= 1) return kDNSServiceErr_BadParam
;
907 if (!sdRef
) return kDNSServiceErr_BadParam
;
910 len
= sizeof(DNSServiceFlags
);
911 len
+= sizeof(uint32_t);
913 hdr
= create_hdr(enumeration_request
, &len
, &ptr
, 1);
914 if (!hdr
) goto error
;
917 put_flags(flags
, &ptr
);
918 put_long(interfaceIndex
, &ptr
);
920 sdr
= connect_to_server();
921 if (!sdr
) goto error
;
922 err
= deliver_request(msg
, sdr
, 1);
925 DNSServiceRefDeallocate(sdr
);
929 sdr
->op
= enumeration_request
;
930 sdr
->process_reply
= handle_enumeration_response
;
931 sdr
->app_callback
= callBack
;
932 sdr
->app_context
= context
;
938 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
939 return kDNSServiceErr_Unknown
;
942 static void handle_regrecord_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
944 DNSServiceFlags flags
;
945 uint32_t interfaceIndex
;
946 DNSServiceErrorType errorCode
;
947 DNSRecordRef rref
= hdr
->client_context
.context
;
949 if (sdr
->op
!= connection
)
951 rref
->app_callback(rref
->sdr
, rref
, 0, kDNSServiceErr_Unknown
, rref
->app_context
);
954 flags
= get_flags(&data
);
955 interfaceIndex
= get_long(&data
);
956 errorCode
= get_error_code(&data
);
958 rref
->app_callback(rref
->sdr
, rref
, flags
, errorCode
, rref
->app_context
);
961 DNSServiceErrorType DNSSD_API
DNSServiceCreateConnection(DNSServiceRef
*sdRef
)
963 if (!sdRef
) return kDNSServiceErr_BadParam
;
964 *sdRef
= connect_to_server();
966 return kDNSServiceErr_Unknown
;
967 (*sdRef
)->op
= connection
;
968 (*sdRef
)->process_reply
= handle_regrecord_response
;
972 DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
975 DNSRecordRef
*RecordRef
,
976 DNSServiceFlags flags
,
977 uint32_t interfaceIndex
,
978 const char *fullname
,
984 DNSServiceRegisterRecordReply callBack
,
988 char *msg
= NULL
, *ptr
;
990 ipc_msg_hdr
*hdr
= NULL
;
991 DNSServiceRef tmp
= NULL
;
992 DNSRecordRef rref
= NULL
;
993 int f1
= (flags
& kDNSServiceFlagsShared
) != 0;
994 int f2
= (flags
& kDNSServiceFlagsUnique
) != 0;
995 if (f1
+ f2
!= 1) return kDNSServiceErr_BadParam
;
997 if (!sdRef
|| sdRef
->op
!= connection
|| sdRef
->sockfd
< 0)
998 return kDNSServiceErr_BadReference
;
1001 len
= sizeof(DNSServiceFlags
);
1002 len
+= 2 * sizeof(uint32_t); // interfaceIndex, ttl
1003 len
+= 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen
1004 len
+= strlen(fullname
) + 1;
1007 hdr
= create_hdr(reg_record_request
, &len
, &ptr
, 0);
1008 if (!hdr
) goto error
;
1010 put_flags(flags
, &ptr
);
1011 put_long(interfaceIndex
, &ptr
);
1012 put_string(fullname
, &ptr
);
1013 put_short(rrtype
, &ptr
);
1014 put_short(rrclass
, &ptr
);
1015 put_short(rdlen
, &ptr
);
1016 put_rdata(rdlen
, rdata
, &ptr
);
1017 put_long(ttl
, &ptr
);
1019 rref
= malloc(sizeof(_DNSRecordRef_t
));
1020 if (!rref
) goto error
;
1021 rref
->app_context
= context
;
1022 rref
->app_callback
= callBack
;
1023 rref
->record_index
= sdRef
->max_index
++;
1026 hdr
->client_context
.context
= rref
;
1027 hdr
->reg_index
= rref
->record_index
;
1029 return deliver_request(msg
, sdRef
, 0);
1032 if (rref
) free(rref
);
1035 return kDNSServiceErr_Unknown
;
1038 //sdRef returned by DNSServiceRegister()
1039 DNSServiceErrorType DNSSD_API DNSServiceAddRecord
1041 DNSServiceRef sdRef
,
1042 DNSRecordRef
*RecordRef
,
1043 DNSServiceFlags flags
,
1055 if (!sdRef
|| (sdRef
->op
!= reg_service_request
) || !RecordRef
)
1056 return kDNSServiceErr_BadReference
;
1059 len
+= 2 * sizeof(uint16_t); //rrtype, rdlen
1061 len
+= sizeof(uint32_t);
1062 len
+= sizeof(DNSServiceFlags
);
1064 hdr
= create_hdr(add_record_request
, &len
, &ptr
, 0);
1065 if (!hdr
) return kDNSServiceErr_Unknown
;
1066 put_flags(flags
, &ptr
);
1067 put_short(rrtype
, &ptr
);
1068 put_short(rdlen
, &ptr
);
1069 put_rdata(rdlen
, rdata
, &ptr
);
1070 put_long(ttl
, &ptr
);
1072 rref
= malloc(sizeof(_DNSRecordRef_t
));
1073 if (!rref
) goto error
;
1074 rref
->app_context
= NULL
;
1075 rref
->app_callback
= NULL
;
1076 rref
->record_index
= sdRef
->max_index
++;
1079 hdr
->client_context
.context
= rref
;
1080 hdr
->reg_index
= rref
->record_index
;
1081 return deliver_request((char *)hdr
, sdRef
, 0);
1085 if (rref
) free(rref
);
1086 if (*RecordRef
) *RecordRef
= NULL
;
1087 return kDNSServiceErr_Unknown
;
1090 //DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
1091 DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
1093 DNSServiceRef sdRef
,
1094 DNSRecordRef RecordRef
,
1095 DNSServiceFlags flags
,
1105 if (!sdRef
) return kDNSServiceErr_BadReference
;
1107 len
+= sizeof(uint16_t);
1109 len
+= sizeof(uint32_t);
1110 len
+= sizeof(DNSServiceFlags
);
1112 hdr
= create_hdr(update_record_request
, &len
, &ptr
, 0);
1113 if (!hdr
) return kDNSServiceErr_Unknown
;
1114 hdr
->reg_index
= RecordRef
? RecordRef
->record_index
: TXT_RECORD_INDEX
;
1115 put_flags(flags
, &ptr
);
1116 put_short(rdlen
, &ptr
);
1117 put_rdata(rdlen
, rdata
, &ptr
);
1118 put_long(ttl
, &ptr
);
1119 return deliver_request((char *)hdr
, sdRef
, 0);
1122 DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
1124 DNSServiceRef sdRef
,
1125 DNSRecordRef RecordRef
,
1126 DNSServiceFlags flags
1132 DNSServiceErrorType err
;
1134 if (!sdRef
|| !RecordRef
|| !sdRef
->max_index
)
1135 return kDNSServiceErr_BadReference
;
1137 len
+= sizeof(flags
);
1138 hdr
= create_hdr(remove_record_request
, &len
, &ptr
, 0);
1139 if (!hdr
) return kDNSServiceErr_Unknown
;
1140 hdr
->reg_index
= RecordRef
->record_index
;
1141 put_flags(flags
, &ptr
);
1142 err
= deliver_request((char *)hdr
, sdRef
, 0);
1143 if (!err
) free(RecordRef
);
1147 void DNSSD_API DNSServiceReconfirmRecord
1149 DNSServiceFlags flags
,
1150 uint32_t interfaceIndex
,
1151 const char *fullname
,
1163 len
= sizeof(DNSServiceFlags
);
1164 len
+= sizeof(uint32_t);
1165 len
+= strlen(fullname
) + 1;
1166 len
+= 3 * sizeof(uint16_t);
1168 tmp
= connect_to_server();
1170 hdr
= create_hdr(reconfirm_record_request
, &len
, &ptr
, 1);
1173 put_flags(flags
, &ptr
);
1174 put_long(interfaceIndex
, &ptr
);
1175 put_string(fullname
, &ptr
);
1176 put_short(rrtype
, &ptr
);
1177 put_short(rrclass
, &ptr
);
1178 put_short(rdlen
, &ptr
);
1179 put_rdata(rdlen
, rdata
, &ptr
);
1180 ConvertHeaderBytes(hdr
);
1181 my_write(tmp
->sockfd
, (char *)hdr
, (int) len
);
1183 DNSServiceRefDeallocate(tmp
);