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.20.70.3 2006/05/02 16:17:04 majka
32 Make NumTries unsigned.
34 Revision 1.20.70.2 2006/05/01 21:43:09 majka
35 Additional change (make NumTries static) for 4527193
36 SUChardLondon Libinfo-222.4.6
38 Revision 1.20.70.1 2006/05/01 16:10:54 majka
39 Libinfo-222_4_5 is equivalent to Chardonnay Libinfo-222.0.5
41 Revision 1.20.60.1 2006/04/27 21:33:30 majka
44 Revision 1.20 2005/02/03 00:39:05 majka
47 Revision 1.19.4.1 2005/02/02 00:47:40 ksekar
48 <rdar://problem/3942900> dnd-sd shows the wrong port numbers
50 Revision 1.19 2004/12/23 23:10:59 majka
51 *** empty log message ***
53 Revision 1.18.8.1 2004/12/23 17:32:56 ksekar
54 <rdar://problem/3931319> Rendevzous calls leak sockets if mDNSResponder is not running
56 Revision 1.18 2004/12/14 18:02:00 majka
57 *** empty log message ***
59 Revision 1.17.36.1 2004/12/13 17:22:39 ksekar
60 <rdar://problem/3656389> Deprecate the DNSServiceDiscovery.h API in Tiger
61 <rdar://problem/3873869> Add kDNSServiceInterfaceForceMulticast to header
62 <rdar://problem/3526342> Remove overly-restrictive flag checks
64 Revision 1.17 2004/09/22 20:05:38 majka
66 3725573 - Need Error Codes for handling Lighthouse setup failure on NAT
67 3805822 - Socket-based APIs aren't endian-safe
68 3806739 - DNSServiceSetDefaultDomainForUser header comments incorrect
70 Revision 1.16.2.1 2004/09/20 21:54:33 ksekar
71 <rdar://problem/3805822> Socket-based APIs aren't endian-safe
73 Revision 1.16 2004/09/17 20:19:00 majka
76 Revision 1.15.2.1 2004/09/17 20:15:30 ksekar
77 *** empty log message ***
79 Revision 1.15 2004/09/16 23:45:24 majka
80 Integrated 3775315 and 3765280.
82 Revision 1.14.4.1 2004/09/02 19:43:41 ksekar
83 <rdar://problem/3775315>: Sync dns-sd client files between Libinfo and
84 mDNSResponder projects
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 mDNSClientAPI.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
;
314 static unsigned int NumTries
= 0;
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
);