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.45 2005/02/01 01:25:06 shersche
32 Define sleep() to be Sleep() for Windows compatibility
34 Revision 1.44 2005/01/27 22:57:56 cheshire
35 Fix compile errors on gcc4
37 Revision 1.43 2005/01/27 00:02:29 cheshire
38 <rdar://problem/3947461> Handle case where client runs before daemon has finished launching
40 Revision 1.42 2005/01/11 02:01:02 shersche
41 Use dnssd_close() rather than close() for Windows compatibility
43 Revision 1.41 2004/12/23 17:34:26 ksekar
44 <rdar://problem/3931319> Calls leak sockets if mDNSResponder is not running
46 Revision 1.40 2004/11/23 03:39:47 cheshire
47 Let interface name/index mapping capability live directly in JNISupport.c,
48 instead of having to call through to the daemon via IPC to get this information.
50 Revision 1.39 2004/11/12 03:22:00 rpantos
51 rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
53 Revision 1.38 2004/11/02 02:51:23 cheshire
54 <rdar://problem/3526342> Remove overly-restrictive flag checks
56 Revision 1.37 2004/10/14 01:43:35 cheshire
57 Fix opaque port passing problem
59 Revision 1.36 2004/10/06 02:22:19 cheshire
60 Changed MacRoman copyright symbol (should have been UTF-8 in any case :-) to ASCII-compatible "(c)"
62 Revision 1.35 2004/10/01 22:15:55 rpantos
63 rdar://problem/3824265: Replace APSL in client lib with BSD license.
65 Revision 1.34 2004/09/17 22:36:13 cheshire
66 Add comment explaining that deliver_request frees the message it sends
68 Revision 1.33 2004/09/17 01:17:31 ksekar
69 Remove double-free of msg header, freed automatically by deliver_request()
71 Revision 1.32 2004/09/17 01:08:55 cheshire
72 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
73 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
74 declared in that file are ONLY appropriate to single-address-space embedded applications.
75 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
77 Revision 1.31 2004/09/16 23:37:19 cheshire
78 Free hdr before returning
80 Revision 1.30 2004/09/16 23:14:24 cheshire
81 Changes for Windows compatibility
83 Revision 1.29 2004/09/16 21:46:38 ksekar
84 <rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area domain
86 Revision 1.28 2004/08/11 17:10:04 cheshire
87 Fix signed/unsigned warnings
89 Revision 1.27 2004/08/11 00:54:16 cheshire
90 Change "hdr->op.request_op" to just "hdr->op"
92 Revision 1.26 2004/07/26 06:07:27 shersche
93 fix bugs when using an error socket to communicate with the daemon
95 Revision 1.25 2004/07/26 05:54:02 shersche
96 DNSServiceProcessResult() returns NoError if socket read returns EWOULDBLOCK
98 Revision 1.24 2004/07/20 06:46:21 shersche
99 <rdar://problem/3730123> fix endless loop in my_read() if recv returns 0
102 Revision 1.23 2004/06/29 00:48:38 cheshire
103 Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
104 use an explicit while() loop instead.
106 Revision 1.22 2004/06/26 03:16:34 shersche
107 clean up warning messages on Win32 platform
109 Submitted by: herscher
111 Revision 1.21 2004/06/18 04:53:56 rpantos
112 Use platform layer for socket types. Introduce USE_TCP_LOOPBACK. Remove dependency on mDNSEmbeddedAPI.h.
114 Revision 1.20 2004/06/12 00:50:22 cheshire
115 Changes for Windows compatibility
117 Revision 1.19 2004/05/25 18:29:33 cheshire
118 Move DNSServiceConstructFullName() from dnssd_clientstub.c to dnssd_clientlib.c,
119 so that it's also accessible to dnssd_clientshim.c (single address space) clients.
121 Revision 1.18 2004/05/18 23:51:27 cheshire
122 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
124 Revision 1.17 2004/05/06 18:42:58 ksekar
125 General dns_sd.h API cleanup, including the following radars:
126 <rdar://problem/3592068>: Remove flags with zero value
127 <rdar://problem/3479569>: Passing in NULL causes a crash.
129 Revision 1.16 2004/03/12 22:00:37 cheshire
130 Added: #include <sys/socket.h>
132 Revision 1.15 2004/01/20 18:36:29 ksekar
133 Propagated Libinfo fix for <rdar://problem/3483971>: SU:
134 DNSServiceUpdateRecord() doesn't allow you to update the TXT record
135 into TOT mDNSResponder.
137 Revision 1.14 2004/01/19 22:39:17 cheshire
138 Don't use "MSG_WAITALL"; it makes send() return "Invalid argument" on Linux;
139 use an explicit while() loop instead. (In any case, this should only make a difference
140 with non-blocking sockets, which we don't use on the client side right now.)
142 Revision 1.13 2004/01/19 21:46:52 cheshire
145 Revision 1.12 2003/12/23 20:46:47 ksekar
146 <rdar://problem/3497428>: sync dnssd files between libinfo & mDNSResponder
148 Revision 1.11 2003/12/08 21:11:42 rpantos
149 Changes necessary to support mDNSResponder on Linux.
151 Revision 1.10 2003/10/13 23:50:53 ksekar
152 Updated dns_sd clientstub files to bring copies in synch with
153 top-of-tree Libinfo: A memory leak in dnssd_clientstub.c is fixed,
154 and comments in dns_sd.h are improved.
156 Revision 1.9 2003/08/15 21:30:39 cheshire
157 Bring up to date with LibInfo version
159 Revision 1.8 2003/08/13 23:54:52 ksekar
160 Bringing dnssd_clientstub.c up to date with Libinfo, per radar 3376640
162 Revision 1.7 2003/08/12 19:56:25 cheshire
170 #include <winsock2.h>
172 #define sockaddr_mdns sockaddr_in
173 #define AF_MDNS AF_INET
175 #include <sys/time.h>
176 #include <sys/socket.h>
177 #define sockaddr_mdns sockaddr_un
178 #define AF_MDNS AF_LOCAL
181 #include "dnssd_ipc.h"
184 // disable warning: "'type cast' : from data pointer 'void *' to
186 #pragma warning(disable:4055)
188 // disable warning: "nonstandard extension, function/data pointer
189 // conversion in expression"
190 #pragma warning(disable:4152)
192 #define sleep(X) Sleep((X) * 1000)
194 static int g_initWinsock
= 0;
198 #define CTL_PATH_PREFIX "/tmp/dnssd_clippath."
199 // error socket (if needed) is named "dnssd_clipath.[pid].xxx:n" where xxx are the
200 // last 3 digits of the time (in seconds) and n is the 6-digit microsecond time
202 // general utility functions
203 typedef struct _DNSServiceRef_t
205 dnssd_sock_t sockfd
; // connected socket between client and daemon
206 uint32_t op
; // request_op_t or reply_op_t
207 process_reply_callback process_reply
;
210 uint32_t max_index
; //largest assigned record index - 0 if no additl. recs registered
213 typedef struct _DNSRecordRef_t
216 DNSServiceRegisterRecordReply app_callback
;
218 uint32_t record_index
; // index is unique to the ServiceDiscoveryRef
222 // exported functions
224 // write len bytes. return 0 on success, -1 on error
225 static int my_write(dnssd_sock_t sd
, char *buf
, int len
)
227 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
228 //if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
231 ssize_t num_written
= send(sd
, buf
, len
, 0);
232 if (num_written
< 0 || num_written
> len
) return -1;
239 // read len bytes. return 0 on success, -1 on error
240 static int my_read(dnssd_sock_t sd
, char *buf
, int len
)
242 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
243 //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1;
246 ssize_t num_read
= recv(sd
, buf
, len
, 0);
247 if ((num_read
== 0) || (num_read
< 0) || (num_read
> len
)) return -1;
256 * allocate and initialize an ipc message header. value of len should initially be the
257 * length of the data, and is set to the value of the data plus the header. data_start
258 * is set to point to the beginning of the data section. reuse_socket should be non-zero
259 * for calls that can receive an immediate error return value on their primary socket.
260 * if zero, the path to a control socket is appended at the beginning of the message buffer.
261 * data_start is set past this string.
264 static ipc_msg_hdr
*create_hdr(uint32_t op
, size_t *len
, char **data_start
, int reuse_socket
)
273 #if defined(USE_TCP_LOOPBACK)
274 *len
+= 2; // Allocate space for two-byte port number
277 if (gettimeofday(&time
, NULL
) < 0) return NULL
;
278 sprintf(ctrl_path
, "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX
, (int)getpid(),
279 (unsigned long)(time
.tv_sec
& 0xFFF), (unsigned long)(time
.tv_usec
));
280 *len
+= strlen(ctrl_path
) + 1;
284 datalen
= (int) *len
;
285 *len
+= sizeof(ipc_msg_hdr
);
287 // write message to buffer
289 if (!msg
) return NULL
;
293 hdr
->datalen
= datalen
;
294 hdr
->version
= VERSION
;
296 if (reuse_socket
) hdr
->flags
|= IPC_FLAGS_REUSE_SOCKET
;
297 *data_start
= msg
+ sizeof(ipc_msg_hdr
);
298 #if defined(USE_TCP_LOOPBACK)
299 // Put dummy data in for the port, since we don't know what
300 // it is yet. The data will get filled in before we
301 // send the message. This happens in deliver_request().
302 if (!reuse_socket
) put_short(0, data_start
);
304 if (!reuse_socket
) put_string(ctrl_path
, data_start
);
309 // return a connected service ref (deallocate with DNSServiceRefDeallocate)
310 static DNSServiceRef
connect_to_server(void)
312 dnssd_sockaddr_t saddr
;
320 DNSServiceErrorType err
;
324 err
= WSAStartup( MAKEWORD( 2, 2 ), &wsaData
);
326 if (err
!= 0) return NULL
;
330 sdr
= malloc(sizeof(_DNSServiceRef_t
));
331 if (!sdr
) return(NULL
);
332 sdr
->sockfd
= socket(AF_DNSSD
, SOCK_STREAM
, 0);
333 if (sdr
->sockfd
== dnssd_InvalidSocket
) { free(sdr
); return NULL
; }
334 #if defined(USE_TCP_LOOPBACK)
335 saddr
.sin_family
= AF_INET
;
336 saddr
.sin_addr
.s_addr
= inet_addr(MDNS_TCP_SERVERADDR
);
337 saddr
.sin_port
= htons(MDNS_TCP_SERVERPORT
);
339 saddr
.sun_family
= AF_LOCAL
;
340 strcpy(saddr
.sun_path
, MDNS_UDS_SERVERPATH
);
344 int err
= connect(sdr
->sockfd
, (struct sockaddr
*) &saddr
, sizeof(saddr
));
345 if (!err
) break; // If we succeeded, return sdr
346 // If we failed, then it may be because the daemon is still launching.
347 // This can happen for processes that launch early in the boot process, while the
348 // daemon is still coming up. Rather than fail here, we'll wait a bit and try again.
349 // If, after ten seconds, we still can't connect to the daemon,
350 // then we give up and return a failure code.
352 sleep(1); // Sleep a bit, then try again
355 dnssd_close(sdr
->sockfd
);
356 sdr
->sockfd
= dnssd_InvalidSocket
;
364 static DNSServiceErrorType
deliver_request(void *msg
, DNSServiceRef sdr
, int reuse_sd
)
366 ipc_msg_hdr
*hdr
= msg
;
367 uint32_t datalen
= hdr
->datalen
;
368 dnssd_sockaddr_t caddr
, daddr
; // (client and daemon address structs)
369 char *data
= (char *)msg
+ sizeof(ipc_msg_hdr
);
370 dnssd_sock_t listenfd
= dnssd_InvalidSocket
, errsd
= dnssd_InvalidSocket
;
372 unsigned int len
= sizeof(caddr
);
373 DNSServiceErrorType err
= kDNSServiceErr_Unknown
;
375 if (!hdr
|| sdr
->sockfd
< 0) return kDNSServiceErr_Unknown
;
379 // setup temporary error socket
380 if ((listenfd
= socket(AF_DNSSD
, SOCK_STREAM
, 0)) < 0)
382 bzero(&caddr
, sizeof(caddr
));
384 #if defined(USE_TCP_LOOPBACK)
386 union { uint16_t s
; u_char b
[2]; } port
;
387 caddr
.sin_family
= AF_INET
;
389 caddr
.sin_addr
.s_addr
= inet_addr(MDNS_TCP_SERVERADDR
);
390 ret
= bind(listenfd
, (struct sockaddr
*) &caddr
, sizeof(caddr
));
391 if (ret
< 0) goto cleanup
;
392 if (getsockname(listenfd
, (struct sockaddr
*) &caddr
, &len
) < 0) goto cleanup
;
394 port
.s
= caddr
.sin_port
;
395 data
[0] = port
.b
[0]; // don't switch the byte order, as the
396 data
[1] = port
.b
[1]; // daemon expects it in network byte order
400 mode_t mask
= umask(0);
401 caddr
.sun_family
= AF_LOCAL
;
402 #ifndef NOT_HAVE_SA_LEN // According to Stevens (section 3.2), there is no portable way to
403 // determine whether sa_len is defined on a particular platform.
404 caddr
.sun_len
= sizeof(struct sockaddr_un
);
406 strcpy(caddr
.sun_path
, data
);
407 ret
= bind(listenfd
, (struct sockaddr
*)&caddr
, sizeof(caddr
));
409 if (ret
< 0) goto cleanup
;
415 ConvertHeaderBytes(hdr
);
416 if (my_write(sdr
->sockfd
, msg
, datalen
+ sizeof(ipc_msg_hdr
)) < 0)
421 if (reuse_sd
) errsd
= sdr
->sockfd
;
425 errsd
= accept(listenfd
, (struct sockaddr
*)&daddr
, &len
);
426 if (errsd
< 0) goto cleanup
;
429 if (my_read(errsd
, (char*)&err
, (int)sizeof(err
)) < 0)
430 err
= kDNSServiceErr_Unknown
;
435 if (!reuse_sd
&& listenfd
> 0) dnssd_close(listenfd
);
436 if (!reuse_sd
&& errsd
> 0) dnssd_close(errsd
);
437 #if !defined(USE_TCP_LOOPBACK)
438 if (!reuse_sd
&& data
) unlink(data
);
444 int DNSSD_API
DNSServiceRefSockFD(DNSServiceRef sdRef
)
446 if (!sdRef
) return -1;
447 return (int) sdRef
->sockfd
;
450 // handle reply from server, calling application client callback. If there is no reply
451 // from the daemon on the socket contained in sdRef, the call will block.
452 DNSServiceErrorType DNSSD_API
DNSServiceProcessResult(DNSServiceRef sdRef
)
457 if (!sdRef
|| sdRef
->sockfd
< 0 || !sdRef
->process_reply
)
458 return kDNSServiceErr_BadReference
;
460 if (my_read(sdRef
->sockfd
, (void *)&hdr
, sizeof(hdr
)) < 0)
461 // return NoError on EWOULDBLOCK. This will handle the case
462 // where a non-blocking socket is told there is data, but
463 // it was a false positive.
464 return (dnssd_errno() == dnssd_EWOULDBLOCK
) ? kDNSServiceErr_NoError
: kDNSServiceErr_Unknown
;
465 ConvertHeaderBytes(&hdr
);
466 if (hdr
.version
!= VERSION
)
467 return kDNSServiceErr_Incompatible
;
468 data
= malloc(hdr
.datalen
);
469 if (!data
) return kDNSServiceErr_NoMemory
;
470 if (my_read(sdRef
->sockfd
, data
, hdr
.datalen
) < 0)
471 return kDNSServiceErr_Unknown
;
472 sdRef
->process_reply(sdRef
, &hdr
, data
);
474 return kDNSServiceErr_NoError
;
477 void DNSSD_API
DNSServiceRefDeallocate(DNSServiceRef sdRef
)
480 if (sdRef
->sockfd
> 0) dnssd_close(sdRef
->sockfd
);
484 static void handle_resolve_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
486 DNSServiceFlags flags
;
487 char fullname
[kDNSServiceMaxDomainName
];
488 char target
[kDNSServiceMaxDomainName
];
490 union { uint16_t s
; u_char b
[2]; } port
;
492 DNSServiceErrorType err
;
497 flags
= get_flags(&data
);
498 ifi
= get_long(&data
);
499 err
= get_error_code(&data
);
500 if (get_string(&data
, fullname
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
501 if (get_string(&data
, target
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
504 txtlen
= get_short(&data
);
505 txtrecord
= get_rdata(&data
, txtlen
);
507 if (!err
&& str_error
) err
= kDNSServiceErr_Unknown
;
508 ((DNSServiceResolveReply
)sdr
->app_callback
)(sdr
, flags
, ifi
, err
, fullname
, target
, port
.s
, txtlen
, txtrecord
, sdr
->app_context
);
511 DNSServiceErrorType DNSSD_API DNSServiceResolve
513 DNSServiceRef
*sdRef
,
514 DNSServiceFlags flags
,
515 uint32_t interfaceIndex
,
519 DNSServiceResolveReply callBack
,
523 char *msg
= NULL
, *ptr
;
527 DNSServiceErrorType err
;
529 if (!sdRef
) return kDNSServiceErr_BadParam
;
532 if (!name
|| !regtype
|| !domain
|| !callBack
) return kDNSServiceErr_BadParam
;
534 // calculate total message length
536 len
+= sizeof(interfaceIndex
);
537 len
+= strlen(name
) + 1;
538 len
+= strlen(regtype
) + 1;
539 len
+= strlen(domain
) + 1;
541 hdr
= create_hdr(resolve_request
, &len
, &ptr
, 1);
542 if (!hdr
) goto error
;
545 put_flags(flags
, &ptr
);
546 put_long(interfaceIndex
, &ptr
);
547 put_string(name
, &ptr
);
548 put_string(regtype
, &ptr
);
549 put_string(domain
, &ptr
);
551 sdr
= connect_to_server();
552 if (!sdr
) goto error
;
553 err
= deliver_request(msg
, sdr
, 1);
556 DNSServiceRefDeallocate(sdr
);
559 sdr
->op
= resolve_request
;
560 sdr
->process_reply
= handle_resolve_response
;
561 sdr
->app_callback
= callBack
;
562 sdr
->app_context
= context
;
569 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
570 return kDNSServiceErr_Unknown
;
573 static void handle_query_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
575 DNSServiceFlags flags
;
576 uint32_t interfaceIndex
, ttl
;
577 DNSServiceErrorType errorCode
;
578 char name
[kDNSServiceMaxDomainName
];
579 uint16_t rrtype
, rrclass
, rdlen
;
584 flags
= get_flags(&data
);
585 interfaceIndex
= get_long(&data
);
586 errorCode
= get_error_code(&data
);
587 if (get_string(&data
, name
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
588 rrtype
= get_short(&data
);
589 rrclass
= get_short(&data
);
590 rdlen
= get_short(&data
);
591 rdata
= get_rdata(&data
, rdlen
);
592 ttl
= get_long(&data
);
594 if (!errorCode
&& str_error
) errorCode
= kDNSServiceErr_Unknown
;
595 ((DNSServiceQueryRecordReply
)sdr
->app_callback
)(sdr
, flags
, interfaceIndex
, errorCode
, name
, rrtype
, rrclass
,
596 rdlen
, rdata
, ttl
, sdr
->app_context
);
600 DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
602 DNSServiceRef
*sdRef
,
603 DNSServiceFlags flags
,
604 uint32_t interfaceIndex
,
608 DNSServiceQueryRecordReply callBack
,
612 char *msg
= NULL
, *ptr
;
616 DNSServiceErrorType err
;
618 if (!sdRef
) return kDNSServiceErr_BadParam
;
621 if (!name
) name
= "\0";
623 // calculate total message length
625 len
+= sizeof(uint32_t); //interfaceIndex
626 len
+= strlen(name
) + 1;
627 len
+= 2 * sizeof(uint16_t); // rrtype, rrclass
629 hdr
= create_hdr(query_request
, &len
, &ptr
, 1);
630 if (!hdr
) goto error
;
633 put_flags(flags
, &ptr
);
634 put_long(interfaceIndex
, &ptr
);
635 put_string(name
, &ptr
);
636 put_short(rrtype
, &ptr
);
637 put_short(rrclass
, &ptr
);
639 sdr
= connect_to_server();
640 if (!sdr
) goto error
;
641 err
= deliver_request(msg
, sdr
, 1);
644 DNSServiceRefDeallocate(sdr
);
648 sdr
->op
= query_request
;
649 sdr
->process_reply
= handle_query_response
;
650 sdr
->app_callback
= callBack
;
651 sdr
->app_context
= context
;
657 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
658 return kDNSServiceErr_Unknown
;
661 static void handle_browse_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
663 DNSServiceFlags flags
;
664 uint32_t interfaceIndex
;
665 DNSServiceErrorType errorCode
;
666 char replyName
[256], replyType
[kDNSServiceMaxDomainName
],
667 replyDomain
[kDNSServiceMaxDomainName
];
671 flags
= get_flags(&data
);
672 interfaceIndex
= get_long(&data
);
673 errorCode
= get_error_code(&data
);
674 if (get_string(&data
, replyName
, 256) < 0) str_error
= 1;
675 if (get_string(&data
, replyType
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
676 if (get_string(&data
, replyDomain
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
677 if (!errorCode
&& str_error
) errorCode
= kDNSServiceErr_Unknown
;
678 ((DNSServiceBrowseReply
)sdr
->app_callback
)(sdr
, flags
, interfaceIndex
, errorCode
, replyName
, replyType
, replyDomain
, sdr
->app_context
);
681 DNSServiceErrorType DNSSD_API DNSServiceBrowse
683 DNSServiceRef
*sdRef
,
684 DNSServiceFlags flags
,
685 uint32_t interfaceIndex
,
688 DNSServiceBrowseReply callBack
,
692 char *msg
= NULL
, *ptr
;
696 DNSServiceErrorType err
;
698 if (!sdRef
) return kDNSServiceErr_BadParam
;
701 if (!domain
) domain
= "";
704 len
+= sizeof(interfaceIndex
);
705 len
+= strlen(regtype
) + 1;
706 len
+= strlen(domain
) + 1;
708 hdr
= create_hdr(browse_request
, &len
, &ptr
, 1);
709 if (!hdr
) goto error
;
711 put_flags(flags
, &ptr
);
712 put_long(interfaceIndex
, &ptr
);
713 put_string(regtype
, &ptr
);
714 put_string(domain
, &ptr
);
716 sdr
= connect_to_server();
717 if (!sdr
) goto error
;
718 err
= deliver_request(msg
, sdr
, 1);
721 DNSServiceRefDeallocate(sdr
);
724 sdr
->op
= browse_request
;
725 sdr
->process_reply
= handle_browse_response
;
726 sdr
->app_callback
= callBack
;
727 sdr
->app_context
= context
;
733 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
734 return kDNSServiceErr_Unknown
;
737 DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser
739 DNSServiceFlags flags
,
744 DNSServiceErrorType err
;
746 size_t len
= sizeof(flags
) + strlen(domain
) + 1;
747 ipc_msg_hdr
*hdr
= create_hdr(setdomain_request
, &len
, &ptr
, 1);
749 if (!hdr
) return kDNSServiceErr_Unknown
;
750 put_flags(flags
, &ptr
);
751 put_string(domain
, &ptr
);
753 sdr
= connect_to_server();
754 if (!sdr
) { free(hdr
); return kDNSServiceErr_Unknown
; }
755 err
= deliver_request((char *)hdr
, sdr
, 1); // deliver_request frees the message for us
756 DNSServiceRefDeallocate(sdr
);
761 static void handle_regservice_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
763 DNSServiceFlags flags
;
764 uint32_t interfaceIndex
;
765 DNSServiceErrorType errorCode
;
766 char name
[256], regtype
[kDNSServiceMaxDomainName
], domain
[kDNSServiceMaxDomainName
];
770 flags
= get_flags(&data
);
771 interfaceIndex
= get_long(&data
);
772 errorCode
= get_error_code(&data
);
773 if (get_string(&data
, name
, 256) < 0) str_error
= 1;
774 if (get_string(&data
, regtype
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
775 if (get_string(&data
, domain
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
776 if (!errorCode
&& str_error
) errorCode
= kDNSServiceErr_Unknown
;
777 ((DNSServiceRegisterReply
)sdr
->app_callback
)(sdr
, flags
, errorCode
, name
, regtype
, domain
, sdr
->app_context
);
780 DNSServiceErrorType DNSSD_API DNSServiceRegister
782 DNSServiceRef
*sdRef
,
783 DNSServiceFlags flags
,
784 uint32_t interfaceIndex
,
789 uint16_t PortInNetworkByteOrder
,
791 const void *txtRecord
,
792 DNSServiceRegisterReply callBack
,
796 char *msg
= NULL
, *ptr
;
800 DNSServiceErrorType err
;
801 union { uint16_t s
; u_char b
[2]; } port
= { PortInNetworkByteOrder
};
803 if (!sdRef
) return kDNSServiceErr_BadParam
;
806 if (!name
) name
= "";
807 if (!regtype
) return kDNSServiceErr_BadParam
;
808 if (!domain
) domain
= "";
809 if (!host
) host
= "";
810 if (!txtRecord
) txtRecord
= (void*)"";
812 // auto-name must also have auto-rename
813 if (!name
[0] && (flags
& kDNSServiceFlagsNoAutoRename
))
814 return kDNSServiceErr_BadParam
;
816 // no callback must have auto-name
817 if (!callBack
&& name
[0]) return kDNSServiceErr_BadParam
;
819 len
= sizeof(DNSServiceFlags
);
820 len
+= sizeof(uint32_t); // interfaceIndex
821 len
+= strlen(name
) + strlen(regtype
) + strlen(domain
) + strlen(host
) + 4;
822 len
+= 2 * sizeof(uint16_t); // port, txtLen
825 hdr
= create_hdr(reg_service_request
, &len
, &ptr
, 1);
826 if (!hdr
) goto error
;
827 if (!callBack
) hdr
->flags
|= IPC_FLAGS_NOREPLY
;
829 put_flags(flags
, &ptr
);
830 put_long(interfaceIndex
, &ptr
);
831 put_string(name
, &ptr
);
832 put_string(regtype
, &ptr
);
833 put_string(domain
, &ptr
);
834 put_string(host
, &ptr
);
837 put_short(txtLen
, &ptr
);
838 put_rdata(txtLen
, txtRecord
, &ptr
);
840 sdr
= connect_to_server();
841 if (!sdr
) goto error
;
842 err
= deliver_request(msg
, sdr
, 1);
845 DNSServiceRefDeallocate(sdr
);
849 sdr
->op
= reg_service_request
;
850 sdr
->process_reply
= callBack
? handle_regservice_response
: NULL
;
851 sdr
->app_callback
= callBack
;
852 sdr
->app_context
= context
;
859 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
860 return kDNSServiceErr_Unknown
;
863 static void handle_enumeration_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
865 DNSServiceFlags flags
;
866 uint32_t interfaceIndex
;
867 DNSServiceErrorType err
;
868 char domain
[kDNSServiceMaxDomainName
];
872 flags
= get_flags(&data
);
873 interfaceIndex
= get_long(&data
);
874 err
= get_error_code(&data
);
875 if (get_string(&data
, domain
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
876 if (!err
&& str_error
) err
= kDNSServiceErr_Unknown
;
877 ((DNSServiceDomainEnumReply
)sdr
->app_callback
)(sdr
, flags
, interfaceIndex
, err
, domain
, sdr
->app_context
);
880 DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
882 DNSServiceRef
*sdRef
,
883 DNSServiceFlags flags
,
884 uint32_t interfaceIndex
,
885 DNSServiceDomainEnumReply callBack
,
889 char *msg
= NULL
, *ptr
;
893 DNSServiceErrorType err
;
894 int f1
= (flags
& kDNSServiceFlagsBrowseDomains
) != 0;
895 int f2
= (flags
& kDNSServiceFlagsRegistrationDomains
) != 0;
896 if (f1
+ f2
!= 1) return kDNSServiceErr_BadParam
;
898 if (!sdRef
) return kDNSServiceErr_BadParam
;
901 len
= sizeof(DNSServiceFlags
);
902 len
+= sizeof(uint32_t);
904 hdr
= create_hdr(enumeration_request
, &len
, &ptr
, 1);
905 if (!hdr
) goto error
;
908 put_flags(flags
, &ptr
);
909 put_long(interfaceIndex
, &ptr
);
911 sdr
= connect_to_server();
912 if (!sdr
) goto error
;
913 err
= deliver_request(msg
, sdr
, 1);
916 DNSServiceRefDeallocate(sdr
);
920 sdr
->op
= enumeration_request
;
921 sdr
->process_reply
= handle_enumeration_response
;
922 sdr
->app_callback
= callBack
;
923 sdr
->app_context
= context
;
929 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
930 return kDNSServiceErr_Unknown
;
933 static void handle_regrecord_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
935 DNSServiceFlags flags
;
936 uint32_t interfaceIndex
;
937 DNSServiceErrorType errorCode
;
938 DNSRecordRef rref
= hdr
->client_context
.context
;
940 if (sdr
->op
!= connection
)
942 rref
->app_callback(rref
->sdr
, rref
, 0, kDNSServiceErr_Unknown
, rref
->app_context
);
945 flags
= get_flags(&data
);
946 interfaceIndex
= get_long(&data
);
947 errorCode
= get_error_code(&data
);
949 rref
->app_callback(rref
->sdr
, rref
, flags
, errorCode
, rref
->app_context
);
952 DNSServiceErrorType DNSSD_API
DNSServiceCreateConnection(DNSServiceRef
*sdRef
)
954 if (!sdRef
) return kDNSServiceErr_BadParam
;
955 *sdRef
= connect_to_server();
957 return kDNSServiceErr_Unknown
;
958 (*sdRef
)->op
= connection
;
959 (*sdRef
)->process_reply
= handle_regrecord_response
;
963 DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
966 DNSRecordRef
*RecordRef
,
967 DNSServiceFlags flags
,
968 uint32_t interfaceIndex
,
969 const char *fullname
,
975 DNSServiceRegisterRecordReply callBack
,
979 char *msg
= NULL
, *ptr
;
981 ipc_msg_hdr
*hdr
= NULL
;
982 DNSServiceRef tmp
= NULL
;
983 DNSRecordRef rref
= NULL
;
984 int f1
= (flags
& kDNSServiceFlagsShared
) != 0;
985 int f2
= (flags
& kDNSServiceFlagsUnique
) != 0;
986 if (f1
+ f2
!= 1) return kDNSServiceErr_BadParam
;
988 if (!sdRef
|| sdRef
->op
!= connection
|| sdRef
->sockfd
< 0)
989 return kDNSServiceErr_BadReference
;
992 len
= sizeof(DNSServiceFlags
);
993 len
+= 2 * sizeof(uint32_t); // interfaceIndex, ttl
994 len
+= 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen
995 len
+= strlen(fullname
) + 1;
998 hdr
= create_hdr(reg_record_request
, &len
, &ptr
, 0);
999 if (!hdr
) goto error
;
1001 put_flags(flags
, &ptr
);
1002 put_long(interfaceIndex
, &ptr
);
1003 put_string(fullname
, &ptr
);
1004 put_short(rrtype
, &ptr
);
1005 put_short(rrclass
, &ptr
);
1006 put_short(rdlen
, &ptr
);
1007 put_rdata(rdlen
, rdata
, &ptr
);
1008 put_long(ttl
, &ptr
);
1010 rref
= malloc(sizeof(_DNSRecordRef_t
));
1011 if (!rref
) goto error
;
1012 rref
->app_context
= context
;
1013 rref
->app_callback
= callBack
;
1014 rref
->record_index
= sdRef
->max_index
++;
1017 hdr
->client_context
.context
= rref
;
1018 hdr
->reg_index
= rref
->record_index
;
1020 return deliver_request(msg
, sdRef
, 0);
1023 if (rref
) free(rref
);
1026 return kDNSServiceErr_Unknown
;
1029 //sdRef returned by DNSServiceRegister()
1030 DNSServiceErrorType DNSSD_API DNSServiceAddRecord
1032 DNSServiceRef sdRef
,
1033 DNSRecordRef
*RecordRef
,
1034 DNSServiceFlags flags
,
1046 if (!sdRef
|| (sdRef
->op
!= reg_service_request
) || !RecordRef
)
1047 return kDNSServiceErr_BadReference
;
1050 len
+= 2 * sizeof(uint16_t); //rrtype, rdlen
1052 len
+= sizeof(uint32_t);
1053 len
+= sizeof(DNSServiceFlags
);
1055 hdr
= create_hdr(add_record_request
, &len
, &ptr
, 0);
1056 if (!hdr
) return kDNSServiceErr_Unknown
;
1057 put_flags(flags
, &ptr
);
1058 put_short(rrtype
, &ptr
);
1059 put_short(rdlen
, &ptr
);
1060 put_rdata(rdlen
, rdata
, &ptr
);
1061 put_long(ttl
, &ptr
);
1063 rref
= malloc(sizeof(_DNSRecordRef_t
));
1064 if (!rref
) goto error
;
1065 rref
->app_context
= NULL
;
1066 rref
->app_callback
= NULL
;
1067 rref
->record_index
= sdRef
->max_index
++;
1070 hdr
->client_context
.context
= rref
;
1071 hdr
->reg_index
= rref
->record_index
;
1072 return deliver_request((char *)hdr
, sdRef
, 0);
1076 if (rref
) free(rref
);
1077 if (*RecordRef
) *RecordRef
= NULL
;
1078 return kDNSServiceErr_Unknown
;
1081 //DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
1082 DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
1084 DNSServiceRef sdRef
,
1085 DNSRecordRef RecordRef
,
1086 DNSServiceFlags flags
,
1096 if (!sdRef
) return kDNSServiceErr_BadReference
;
1098 len
+= sizeof(uint16_t);
1100 len
+= sizeof(uint32_t);
1101 len
+= sizeof(DNSServiceFlags
);
1103 hdr
= create_hdr(update_record_request
, &len
, &ptr
, 0);
1104 if (!hdr
) return kDNSServiceErr_Unknown
;
1105 hdr
->reg_index
= RecordRef
? RecordRef
->record_index
: TXT_RECORD_INDEX
;
1106 put_flags(flags
, &ptr
);
1107 put_short(rdlen
, &ptr
);
1108 put_rdata(rdlen
, rdata
, &ptr
);
1109 put_long(ttl
, &ptr
);
1110 return deliver_request((char *)hdr
, sdRef
, 0);
1113 DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
1115 DNSServiceRef sdRef
,
1116 DNSRecordRef RecordRef
,
1117 DNSServiceFlags flags
1123 DNSServiceErrorType err
;
1125 if (!sdRef
|| !RecordRef
|| !sdRef
->max_index
)
1126 return kDNSServiceErr_BadReference
;
1128 len
+= sizeof(flags
);
1129 hdr
= create_hdr(remove_record_request
, &len
, &ptr
, 0);
1130 if (!hdr
) return kDNSServiceErr_Unknown
;
1131 hdr
->reg_index
= RecordRef
->record_index
;
1132 put_flags(flags
, &ptr
);
1133 err
= deliver_request((char *)hdr
, sdRef
, 0);
1134 if (!err
) free(RecordRef
);
1138 void DNSSD_API DNSServiceReconfirmRecord
1140 DNSServiceFlags flags
,
1141 uint32_t interfaceIndex
,
1142 const char *fullname
,
1154 len
= sizeof(DNSServiceFlags
);
1155 len
+= sizeof(uint32_t);
1156 len
+= strlen(fullname
) + 1;
1157 len
+= 3 * sizeof(uint16_t);
1159 tmp
= connect_to_server();
1161 hdr
= create_hdr(reconfirm_record_request
, &len
, &ptr
, 1);
1164 put_flags(flags
, &ptr
);
1165 put_long(interfaceIndex
, &ptr
);
1166 put_string(fullname
, &ptr
);
1167 put_short(rrtype
, &ptr
);
1168 put_short(rrclass
, &ptr
);
1169 put_short(rdlen
, &ptr
);
1170 put_rdata(rdlen
, rdata
, &ptr
);
1171 ConvertHeaderBytes(hdr
);
1172 my_write(tmp
->sockfd
, (char *)hdr
, (int) len
);
1174 DNSServiceRefDeallocate(tmp
);