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 2005/02/03 00:39:05 majka
34 Revision 1.19.4.1 2005/02/02 00:47:40 ksekar
35 <rdar://problem/3942900> dnd-sd shows the wrong port numbers
37 Revision 1.19 2004/12/23 23:10:59 majka
38 *** empty log message ***
40 Revision 1.18.8.1 2004/12/23 17:32:56 ksekar
41 <rdar://problem/3931319> Rendevzous calls leak sockets if mDNSResponder is not running
43 Revision 1.18 2004/12/14 18:02:00 majka
44 *** empty log message ***
46 Revision 1.17.36.1 2004/12/13 17:22:39 ksekar
47 <rdar://problem/3656389> Deprecate the DNSServiceDiscovery.h API in Tiger
48 <rdar://problem/3873869> Add kDNSServiceInterfaceForceMulticast to header
49 <rdar://problem/3526342> Remove overly-restrictive flag checks
51 Revision 1.17 2004/09/22 20:05:38 majka
53 3725573 - Need Error Codes for handling Lighthouse setup failure on NAT
54 3805822 - Socket-based APIs aren't endian-safe
55 3806739 - DNSServiceSetDefaultDomainForUser header comments incorrect
57 Revision 1.16.2.1 2004/09/20 21:54:33 ksekar
58 <rdar://problem/3805822> Socket-based APIs aren't endian-safe
60 Revision 1.16 2004/09/17 20:19:00 majka
63 Revision 1.15.2.1 2004/09/17 20:15:30 ksekar
64 *** empty log message ***
66 Revision 1.15 2004/09/16 23:45:24 majka
67 Integrated 3775315 and 3765280.
69 Revision 1.14.4.1 2004/09/02 19:43:41 ksekar
70 <rdar://problem/3775315>: Sync dns-sd client files between Libinfo and
71 mDNSResponder projects
73 Revision 1.28 2004/08/11 17:10:04 cheshire
74 Fix signed/unsigned warnings
76 Revision 1.27 2004/08/11 00:54:16 cheshire
77 Change "hdr->op.request_op" to just "hdr->op"
79 Revision 1.26 2004/07/26 06:07:27 shersche
80 fix bugs when using an error socket to communicate with the daemon
82 Revision 1.25 2004/07/26 05:54:02 shersche
83 DNSServiceProcessResult() returns NoError if socket read returns EWOULDBLOCK
85 Revision 1.24 2004/07/20 06:46:21 shersche
86 <rdar://problem/3730123> fix endless loop in my_read() if recv returns 0
89 Revision 1.23 2004/06/29 00:48:38 cheshire
90 Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
91 use an explicit while() loop instead.
93 Revision 1.22 2004/06/26 03:16:34 shersche
94 clean up warning messages on Win32 platform
96 Submitted by: herscher
98 Revision 1.21 2004/06/18 04:53:56 rpantos
99 Use platform layer for socket types. Introduce USE_TCP_LOOPBACK. Remove dependency on mDNSClientAPI.h.
101 Revision 1.20 2004/06/12 00:50:22 cheshire
102 Changes for Windows compatibility
104 Revision 1.19 2004/05/25 18:29:33 cheshire
105 Move DNSServiceConstructFullName() from dnssd_clientstub.c to dnssd_clientlib.c,
106 so that it's also accessible to dnssd_clientshim.c (single address space) clients.
108 Revision 1.18 2004/05/18 23:51:27 cheshire
109 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
111 Revision 1.17 2004/05/06 18:42:58 ksekar
112 General dns_sd.h API cleanup, including the following radars:
113 <rdar://problem/3592068>: Remove flags with zero value
114 <rdar://problem/3479569>: Passing in NULL causes a crash.
116 Revision 1.16 2004/03/12 22:00:37 cheshire
117 Added: #include <sys/socket.h>
119 Revision 1.15 2004/01/20 18:36:29 ksekar
120 Propagated Libinfo fix for <rdar://problem/3483971>: SU:
121 DNSServiceUpdateRecord() doesn't allow you to update the TXT record
122 into TOT mDNSResponder.
124 Revision 1.14 2004/01/19 22:39:17 cheshire
125 Don't use "MSG_WAITALL"; it makes send() return "Invalid argument" on Linux;
126 use an explicit while() loop instead. (In any case, this should only make a difference
127 with non-blocking sockets, which we don't use on the client side right now.)
129 Revision 1.13 2004/01/19 21:46:52 cheshire
132 Revision 1.12 2003/12/23 20:46:47 ksekar
133 <rdar://problem/3497428>: sync dnssd files between libinfo & mDNSResponder
135 Revision 1.11 2003/12/08 21:11:42 rpantos
136 Changes necessary to support mDNSResponder on Linux.
138 Revision 1.10 2003/10/13 23:50:53 ksekar
139 Updated dns_sd clientstub files to bring copies in synch with
140 top-of-tree Libinfo: A memory leak in dnssd_clientstub.c is fixed,
141 and comments in dns_sd.h are improved.
143 Revision 1.9 2003/08/15 21:30:39 cheshire
144 Bring up to date with LibInfo version
146 Revision 1.8 2003/08/13 23:54:52 ksekar
147 Bringing dnssd_clientstub.c up to date with Libinfo, per radar 3376640
149 Revision 1.7 2003/08/12 19:56:25 cheshire
157 #include <winsock2.h>
159 #define sockaddr_mdns sockaddr_in
160 #define AF_MDNS AF_INET
162 #include <sys/time.h>
163 #include <sys/socket.h>
164 #define sockaddr_mdns sockaddr_un
165 #define AF_MDNS AF_LOCAL
168 #include "dnssd_ipc.h"
171 // disable warning: "'type cast' : from data pointer 'void *' to
173 #pragma warning(disable:4055)
175 // disable warning: "nonstandard extension, function/data pointer
176 // conversion in expression"
177 #pragma warning(disable:4152)
179 #define sleep(X) Sleep((X) * 1000)
181 static int g_initWinsock
= 0;
185 #define CTL_PATH_PREFIX "/tmp/dnssd_clippath."
186 // error socket (if needed) is named "dnssd_clipath.[pid].xxx:n" where xxx are the
187 // last 3 digits of the time (in seconds) and n is the 6-digit microsecond time
189 // general utility functions
190 typedef struct _DNSServiceRef_t
192 dnssd_sock_t sockfd
; // connected socket between client and daemon
193 uint32_t op
; // request_op_t or reply_op_t
194 process_reply_callback process_reply
;
197 uint32_t max_index
; //largest assigned record index - 0 if no additl. recs registered
200 typedef struct _DNSRecordRef_t
203 DNSServiceRegisterRecordReply app_callback
;
205 uint32_t record_index
; // index is unique to the ServiceDiscoveryRef
209 // exported functions
211 // write len bytes. return 0 on success, -1 on error
212 static int my_write(dnssd_sock_t sd
, char *buf
, int len
)
214 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
215 //if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
218 ssize_t num_written
= send(sd
, buf
, len
, 0);
219 if (num_written
< 0 || num_written
> len
) return -1;
226 // read len bytes. return 0 on success, -1 on error
227 static int my_read(dnssd_sock_t sd
, char *buf
, int len
)
229 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
230 //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1;
233 ssize_t num_read
= recv(sd
, buf
, len
, 0);
234 if ((num_read
== 0) || (num_read
< 0) || (num_read
> len
)) return -1;
243 * allocate and initialize an ipc message header. value of len should initially be the
244 * length of the data, and is set to the value of the data plus the header. data_start
245 * is set to point to the beginning of the data section. reuse_socket should be non-zero
246 * for calls that can receive an immediate error return value on their primary socket.
247 * if zero, the path to a control socket is appended at the beginning of the message buffer.
248 * data_start is set past this string.
251 static ipc_msg_hdr
*create_hdr(uint32_t op
, size_t *len
, char **data_start
, int reuse_socket
)
260 #if defined(USE_TCP_LOOPBACK)
261 *len
+= 2; // Allocate space for two-byte port number
264 if (gettimeofday(&time
, NULL
) < 0) return NULL
;
265 sprintf(ctrl_path
, "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX
, (int)getpid(),
266 (unsigned long)(time
.tv_sec
& 0xFFF), (unsigned long)(time
.tv_usec
));
267 *len
+= strlen(ctrl_path
) + 1;
271 datalen
= (int) *len
;
272 *len
+= sizeof(ipc_msg_hdr
);
274 // write message to buffer
276 if (!msg
) return NULL
;
280 hdr
->datalen
= datalen
;
281 hdr
->version
= VERSION
;
283 if (reuse_socket
) hdr
->flags
|= IPC_FLAGS_REUSE_SOCKET
;
284 *data_start
= msg
+ sizeof(ipc_msg_hdr
);
285 #if defined(USE_TCP_LOOPBACK)
286 // Put dummy data in for the port, since we don't know what
287 // it is yet. The data will get filled in before we
288 // send the message. This happens in deliver_request().
289 if (!reuse_socket
) put_short(0, data_start
);
291 if (!reuse_socket
) put_string(ctrl_path
, data_start
);
296 // return a connected service ref (deallocate with DNSServiceRefDeallocate)
297 static DNSServiceRef
connect_to_server(void)
299 dnssd_sockaddr_t saddr
;
307 DNSServiceErrorType err
;
311 err
= WSAStartup( MAKEWORD( 2, 2 ), &wsaData
);
313 if (err
!= 0) return NULL
;
317 sdr
= malloc(sizeof(_DNSServiceRef_t
));
318 if (!sdr
) return(NULL
);
319 sdr
->sockfd
= socket(AF_DNSSD
, SOCK_STREAM
, 0);
320 if (sdr
->sockfd
== dnssd_InvalidSocket
) { free(sdr
); return NULL
; }
321 #if defined(USE_TCP_LOOPBACK)
322 saddr
.sin_family
= AF_INET
;
323 saddr
.sin_addr
.s_addr
= inet_addr(MDNS_TCP_SERVERADDR
);
324 saddr
.sin_port
= htons(MDNS_TCP_SERVERPORT
);
326 saddr
.sun_family
= AF_LOCAL
;
327 strcpy(saddr
.sun_path
, MDNS_UDS_SERVERPATH
);
331 int err
= connect(sdr
->sockfd
, (struct sockaddr
*) &saddr
, sizeof(saddr
));
332 if (!err
) break; // If we succeeded, return sdr
333 // If we failed, then it may be because the daemon is still launching.
334 // This can happen for processes that launch early in the boot process, while the
335 // daemon is still coming up. Rather than fail here, we'll wait a bit and try again.
336 // If, after ten seconds, we still can't connect to the daemon,
337 // then we give up and return a failure code.
339 sleep(1); // Sleep a bit, then try again
342 dnssd_close(sdr
->sockfd
);
343 sdr
->sockfd
= dnssd_InvalidSocket
;
351 static DNSServiceErrorType
deliver_request(void *msg
, DNSServiceRef sdr
, int reuse_sd
)
353 ipc_msg_hdr
*hdr
= msg
;
354 uint32_t datalen
= hdr
->datalen
;
355 dnssd_sockaddr_t caddr
, daddr
; // (client and daemon address structs)
356 char *data
= (char *)msg
+ sizeof(ipc_msg_hdr
);
357 dnssd_sock_t listenfd
= dnssd_InvalidSocket
, errsd
= dnssd_InvalidSocket
;
359 unsigned int len
= sizeof(caddr
);
360 DNSServiceErrorType err
= kDNSServiceErr_Unknown
;
362 if (!hdr
|| sdr
->sockfd
< 0) return kDNSServiceErr_Unknown
;
366 // setup temporary error socket
367 if ((listenfd
= socket(AF_DNSSD
, SOCK_STREAM
, 0)) < 0)
369 bzero(&caddr
, sizeof(caddr
));
371 #if defined(USE_TCP_LOOPBACK)
373 union { uint16_t s
; u_char b
[2]; } port
;
374 caddr
.sin_family
= AF_INET
;
376 caddr
.sin_addr
.s_addr
= inet_addr(MDNS_TCP_SERVERADDR
);
377 ret
= bind(listenfd
, (struct sockaddr
*) &caddr
, sizeof(caddr
));
378 if (ret
< 0) goto cleanup
;
379 if (getsockname(listenfd
, (struct sockaddr
*) &caddr
, &len
) < 0) goto cleanup
;
381 port
.s
= caddr
.sin_port
;
382 data
[0] = port
.b
[0]; // don't switch the byte order, as the
383 data
[1] = port
.b
[1]; // daemon expects it in network byte order
387 mode_t mask
= umask(0);
388 caddr
.sun_family
= AF_LOCAL
;
389 #ifndef NOT_HAVE_SA_LEN // According to Stevens (section 3.2), there is no portable way to
390 // determine whether sa_len is defined on a particular platform.
391 caddr
.sun_len
= sizeof(struct sockaddr_un
);
393 strcpy(caddr
.sun_path
, data
);
394 ret
= bind(listenfd
, (struct sockaddr
*)&caddr
, sizeof(caddr
));
396 if (ret
< 0) goto cleanup
;
402 ConvertHeaderBytes(hdr
);
403 if (my_write(sdr
->sockfd
, msg
, datalen
+ sizeof(ipc_msg_hdr
)) < 0)
408 if (reuse_sd
) errsd
= sdr
->sockfd
;
412 errsd
= accept(listenfd
, (struct sockaddr
*)&daddr
, &len
);
413 if (errsd
< 0) goto cleanup
;
416 if (my_read(errsd
, (char*)&err
, (int)sizeof(err
)) < 0)
417 err
= kDNSServiceErr_Unknown
;
422 if (!reuse_sd
&& listenfd
> 0) dnssd_close(listenfd
);
423 if (!reuse_sd
&& errsd
> 0) dnssd_close(errsd
);
424 #if !defined(USE_TCP_LOOPBACK)
425 if (!reuse_sd
&& data
) unlink(data
);
431 int DNSSD_API
DNSServiceRefSockFD(DNSServiceRef sdRef
)
433 if (!sdRef
) return -1;
434 return (int) sdRef
->sockfd
;
437 // handle reply from server, calling application client callback. If there is no reply
438 // from the daemon on the socket contained in sdRef, the call will block.
439 DNSServiceErrorType DNSSD_API
DNSServiceProcessResult(DNSServiceRef sdRef
)
444 if (!sdRef
|| sdRef
->sockfd
< 0 || !sdRef
->process_reply
)
445 return kDNSServiceErr_BadReference
;
447 if (my_read(sdRef
->sockfd
, (void *)&hdr
, sizeof(hdr
)) < 0)
448 // return NoError on EWOULDBLOCK. This will handle the case
449 // where a non-blocking socket is told there is data, but
450 // it was a false positive.
451 return (dnssd_errno() == dnssd_EWOULDBLOCK
) ? kDNSServiceErr_NoError
: kDNSServiceErr_Unknown
;
452 ConvertHeaderBytes(&hdr
);
453 if (hdr
.version
!= VERSION
)
454 return kDNSServiceErr_Incompatible
;
455 data
= malloc(hdr
.datalen
);
456 if (!data
) return kDNSServiceErr_NoMemory
;
457 if (my_read(sdRef
->sockfd
, data
, hdr
.datalen
) < 0)
458 return kDNSServiceErr_Unknown
;
459 sdRef
->process_reply(sdRef
, &hdr
, data
);
461 return kDNSServiceErr_NoError
;
464 void DNSSD_API
DNSServiceRefDeallocate(DNSServiceRef sdRef
)
467 if (sdRef
->sockfd
> 0) dnssd_close(sdRef
->sockfd
);
471 static void handle_resolve_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
473 DNSServiceFlags flags
;
474 char fullname
[kDNSServiceMaxDomainName
];
475 char target
[kDNSServiceMaxDomainName
];
477 union { uint16_t s
; u_char b
[2]; } port
;
479 DNSServiceErrorType err
;
484 flags
= get_flags(&data
);
485 ifi
= get_long(&data
);
486 err
= get_error_code(&data
);
487 if (get_string(&data
, fullname
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
488 if (get_string(&data
, target
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
491 txtlen
= get_short(&data
);
492 txtrecord
= get_rdata(&data
, txtlen
);
494 if (!err
&& str_error
) err
= kDNSServiceErr_Unknown
;
495 ((DNSServiceResolveReply
)sdr
->app_callback
)(sdr
, flags
, ifi
, err
, fullname
, target
, port
.s
, txtlen
, txtrecord
, sdr
->app_context
);
498 DNSServiceErrorType DNSSD_API DNSServiceResolve
500 DNSServiceRef
*sdRef
,
501 DNSServiceFlags flags
,
502 uint32_t interfaceIndex
,
506 DNSServiceResolveReply callBack
,
510 char *msg
= NULL
, *ptr
;
514 DNSServiceErrorType err
;
516 if (!sdRef
) return kDNSServiceErr_BadParam
;
519 if (!name
|| !regtype
|| !domain
|| !callBack
) return kDNSServiceErr_BadParam
;
521 // calculate total message length
523 len
+= sizeof(interfaceIndex
);
524 len
+= strlen(name
) + 1;
525 len
+= strlen(regtype
) + 1;
526 len
+= strlen(domain
) + 1;
528 hdr
= create_hdr(resolve_request
, &len
, &ptr
, 1);
529 if (!hdr
) goto error
;
532 put_flags(flags
, &ptr
);
533 put_long(interfaceIndex
, &ptr
);
534 put_string(name
, &ptr
);
535 put_string(regtype
, &ptr
);
536 put_string(domain
, &ptr
);
538 sdr
= connect_to_server();
539 if (!sdr
) goto error
;
540 err
= deliver_request(msg
, sdr
, 1);
543 DNSServiceRefDeallocate(sdr
);
546 sdr
->op
= resolve_request
;
547 sdr
->process_reply
= handle_resolve_response
;
548 sdr
->app_callback
= callBack
;
549 sdr
->app_context
= context
;
556 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
557 return kDNSServiceErr_Unknown
;
560 static void handle_query_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
562 DNSServiceFlags flags
;
563 uint32_t interfaceIndex
, ttl
;
564 DNSServiceErrorType errorCode
;
565 char name
[kDNSServiceMaxDomainName
];
566 uint16_t rrtype
, rrclass
, rdlen
;
571 flags
= get_flags(&data
);
572 interfaceIndex
= get_long(&data
);
573 errorCode
= get_error_code(&data
);
574 if (get_string(&data
, name
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
575 rrtype
= get_short(&data
);
576 rrclass
= get_short(&data
);
577 rdlen
= get_short(&data
);
578 rdata
= get_rdata(&data
, rdlen
);
579 ttl
= get_long(&data
);
581 if (!errorCode
&& str_error
) errorCode
= kDNSServiceErr_Unknown
;
582 ((DNSServiceQueryRecordReply
)sdr
->app_callback
)(sdr
, flags
, interfaceIndex
, errorCode
, name
, rrtype
, rrclass
,
583 rdlen
, rdata
, ttl
, sdr
->app_context
);
587 DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
589 DNSServiceRef
*sdRef
,
590 DNSServiceFlags flags
,
591 uint32_t interfaceIndex
,
595 DNSServiceQueryRecordReply callBack
,
599 char *msg
= NULL
, *ptr
;
603 DNSServiceErrorType err
;
605 if (!sdRef
) return kDNSServiceErr_BadParam
;
608 if (!name
) name
= "\0";
610 // calculate total message length
612 len
+= sizeof(uint32_t); //interfaceIndex
613 len
+= strlen(name
) + 1;
614 len
+= 2 * sizeof(uint16_t); // rrtype, rrclass
616 hdr
= create_hdr(query_request
, &len
, &ptr
, 1);
617 if (!hdr
) goto error
;
620 put_flags(flags
, &ptr
);
621 put_long(interfaceIndex
, &ptr
);
622 put_string(name
, &ptr
);
623 put_short(rrtype
, &ptr
);
624 put_short(rrclass
, &ptr
);
626 sdr
= connect_to_server();
627 if (!sdr
) goto error
;
628 err
= deliver_request(msg
, sdr
, 1);
631 DNSServiceRefDeallocate(sdr
);
635 sdr
->op
= query_request
;
636 sdr
->process_reply
= handle_query_response
;
637 sdr
->app_callback
= callBack
;
638 sdr
->app_context
= context
;
644 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
645 return kDNSServiceErr_Unknown
;
648 static void handle_browse_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
650 DNSServiceFlags flags
;
651 uint32_t interfaceIndex
;
652 DNSServiceErrorType errorCode
;
653 char replyName
[256], replyType
[kDNSServiceMaxDomainName
],
654 replyDomain
[kDNSServiceMaxDomainName
];
658 flags
= get_flags(&data
);
659 interfaceIndex
= get_long(&data
);
660 errorCode
= get_error_code(&data
);
661 if (get_string(&data
, replyName
, 256) < 0) str_error
= 1;
662 if (get_string(&data
, replyType
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
663 if (get_string(&data
, replyDomain
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
664 if (!errorCode
&& str_error
) errorCode
= kDNSServiceErr_Unknown
;
665 ((DNSServiceBrowseReply
)sdr
->app_callback
)(sdr
, flags
, interfaceIndex
, errorCode
, replyName
, replyType
, replyDomain
, sdr
->app_context
);
668 DNSServiceErrorType DNSSD_API DNSServiceBrowse
670 DNSServiceRef
*sdRef
,
671 DNSServiceFlags flags
,
672 uint32_t interfaceIndex
,
675 DNSServiceBrowseReply callBack
,
679 char *msg
= NULL
, *ptr
;
683 DNSServiceErrorType err
;
685 if (!sdRef
) return kDNSServiceErr_BadParam
;
688 if (!domain
) domain
= "";
691 len
+= sizeof(interfaceIndex
);
692 len
+= strlen(regtype
) + 1;
693 len
+= strlen(domain
) + 1;
695 hdr
= create_hdr(browse_request
, &len
, &ptr
, 1);
696 if (!hdr
) goto error
;
698 put_flags(flags
, &ptr
);
699 put_long(interfaceIndex
, &ptr
);
700 put_string(regtype
, &ptr
);
701 put_string(domain
, &ptr
);
703 sdr
= connect_to_server();
704 if (!sdr
) goto error
;
705 err
= deliver_request(msg
, sdr
, 1);
708 DNSServiceRefDeallocate(sdr
);
711 sdr
->op
= browse_request
;
712 sdr
->process_reply
= handle_browse_response
;
713 sdr
->app_callback
= callBack
;
714 sdr
->app_context
= context
;
720 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
721 return kDNSServiceErr_Unknown
;
724 DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser
726 DNSServiceFlags flags
,
731 DNSServiceErrorType err
;
733 size_t len
= sizeof(flags
) + strlen(domain
) + 1;
734 ipc_msg_hdr
*hdr
= create_hdr(setdomain_request
, &len
, &ptr
, 1);
736 if (!hdr
) return kDNSServiceErr_Unknown
;
737 put_flags(flags
, &ptr
);
738 put_string(domain
, &ptr
);
740 sdr
= connect_to_server();
741 if (!sdr
) { free(hdr
); return kDNSServiceErr_Unknown
; }
742 err
= deliver_request((char *)hdr
, sdr
, 1); // deliver_request frees the message for us
743 DNSServiceRefDeallocate(sdr
);
748 static void handle_regservice_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
750 DNSServiceFlags flags
;
751 uint32_t interfaceIndex
;
752 DNSServiceErrorType errorCode
;
753 char name
[256], regtype
[kDNSServiceMaxDomainName
], domain
[kDNSServiceMaxDomainName
];
757 flags
= get_flags(&data
);
758 interfaceIndex
= get_long(&data
);
759 errorCode
= get_error_code(&data
);
760 if (get_string(&data
, name
, 256) < 0) str_error
= 1;
761 if (get_string(&data
, regtype
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
762 if (get_string(&data
, domain
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
763 if (!errorCode
&& str_error
) errorCode
= kDNSServiceErr_Unknown
;
764 ((DNSServiceRegisterReply
)sdr
->app_callback
)(sdr
, flags
, errorCode
, name
, regtype
, domain
, sdr
->app_context
);
767 DNSServiceErrorType DNSSD_API DNSServiceRegister
769 DNSServiceRef
*sdRef
,
770 DNSServiceFlags flags
,
771 uint32_t interfaceIndex
,
776 uint16_t PortInNetworkByteOrder
,
778 const void *txtRecord
,
779 DNSServiceRegisterReply callBack
,
783 char *msg
= NULL
, *ptr
;
787 DNSServiceErrorType err
;
788 union { uint16_t s
; u_char b
[2]; } port
= { PortInNetworkByteOrder
};
790 if (!sdRef
) return kDNSServiceErr_BadParam
;
793 if (!name
) name
= "";
794 if (!regtype
) return kDNSServiceErr_BadParam
;
795 if (!domain
) domain
= "";
796 if (!host
) host
= "";
797 if (!txtRecord
) txtRecord
= (void*)"";
799 // auto-name must also have auto-rename
800 if (!name
[0] && (flags
& kDNSServiceFlagsNoAutoRename
))
801 return kDNSServiceErr_BadParam
;
803 // no callback must have auto-name
804 if (!callBack
&& name
[0]) return kDNSServiceErr_BadParam
;
806 len
= sizeof(DNSServiceFlags
);
807 len
+= sizeof(uint32_t); // interfaceIndex
808 len
+= strlen(name
) + strlen(regtype
) + strlen(domain
) + strlen(host
) + 4;
809 len
+= 2 * sizeof(uint16_t); // port, txtLen
812 hdr
= create_hdr(reg_service_request
, &len
, &ptr
, 1);
813 if (!hdr
) goto error
;
814 if (!callBack
) hdr
->flags
|= IPC_FLAGS_NOREPLY
;
816 put_flags(flags
, &ptr
);
817 put_long(interfaceIndex
, &ptr
);
818 put_string(name
, &ptr
);
819 put_string(regtype
, &ptr
);
820 put_string(domain
, &ptr
);
821 put_string(host
, &ptr
);
824 put_short(txtLen
, &ptr
);
825 put_rdata(txtLen
, txtRecord
, &ptr
);
827 sdr
= connect_to_server();
828 if (!sdr
) goto error
;
829 err
= deliver_request(msg
, sdr
, 1);
832 DNSServiceRefDeallocate(sdr
);
836 sdr
->op
= reg_service_request
;
837 sdr
->process_reply
= callBack
? handle_regservice_response
: NULL
;
838 sdr
->app_callback
= callBack
;
839 sdr
->app_context
= context
;
846 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
847 return kDNSServiceErr_Unknown
;
850 static void handle_enumeration_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
852 DNSServiceFlags flags
;
853 uint32_t interfaceIndex
;
854 DNSServiceErrorType err
;
855 char domain
[kDNSServiceMaxDomainName
];
859 flags
= get_flags(&data
);
860 interfaceIndex
= get_long(&data
);
861 err
= get_error_code(&data
);
862 if (get_string(&data
, domain
, kDNSServiceMaxDomainName
) < 0) str_error
= 1;
863 if (!err
&& str_error
) err
= kDNSServiceErr_Unknown
;
864 ((DNSServiceDomainEnumReply
)sdr
->app_callback
)(sdr
, flags
, interfaceIndex
, err
, domain
, sdr
->app_context
);
867 DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
869 DNSServiceRef
*sdRef
,
870 DNSServiceFlags flags
,
871 uint32_t interfaceIndex
,
872 DNSServiceDomainEnumReply callBack
,
876 char *msg
= NULL
, *ptr
;
880 DNSServiceErrorType err
;
881 int f1
= (flags
& kDNSServiceFlagsBrowseDomains
) != 0;
882 int f2
= (flags
& kDNSServiceFlagsRegistrationDomains
) != 0;
883 if (f1
+ f2
!= 1) return kDNSServiceErr_BadParam
;
885 if (!sdRef
) return kDNSServiceErr_BadParam
;
888 len
= sizeof(DNSServiceFlags
);
889 len
+= sizeof(uint32_t);
891 hdr
= create_hdr(enumeration_request
, &len
, &ptr
, 1);
892 if (!hdr
) goto error
;
895 put_flags(flags
, &ptr
);
896 put_long(interfaceIndex
, &ptr
);
898 sdr
= connect_to_server();
899 if (!sdr
) goto error
;
900 err
= deliver_request(msg
, sdr
, 1);
903 DNSServiceRefDeallocate(sdr
);
907 sdr
->op
= enumeration_request
;
908 sdr
->process_reply
= handle_enumeration_response
;
909 sdr
->app_callback
= callBack
;
910 sdr
->app_context
= context
;
916 if (*sdRef
) { free(*sdRef
); *sdRef
= NULL
; }
917 return kDNSServiceErr_Unknown
;
920 static void handle_regrecord_response(DNSServiceRef sdr
, ipc_msg_hdr
*hdr
, char *data
)
922 DNSServiceFlags flags
;
923 uint32_t interfaceIndex
;
924 DNSServiceErrorType errorCode
;
925 DNSRecordRef rref
= hdr
->client_context
.context
;
927 if (sdr
->op
!= connection
)
929 rref
->app_callback(rref
->sdr
, rref
, 0, kDNSServiceErr_Unknown
, rref
->app_context
);
932 flags
= get_flags(&data
);
933 interfaceIndex
= get_long(&data
);
934 errorCode
= get_error_code(&data
);
936 rref
->app_callback(rref
->sdr
, rref
, flags
, errorCode
, rref
->app_context
);
939 DNSServiceErrorType DNSSD_API
DNSServiceCreateConnection(DNSServiceRef
*sdRef
)
941 if (!sdRef
) return kDNSServiceErr_BadParam
;
942 *sdRef
= connect_to_server();
944 return kDNSServiceErr_Unknown
;
945 (*sdRef
)->op
= connection
;
946 (*sdRef
)->process_reply
= handle_regrecord_response
;
950 DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
953 DNSRecordRef
*RecordRef
,
954 DNSServiceFlags flags
,
955 uint32_t interfaceIndex
,
956 const char *fullname
,
962 DNSServiceRegisterRecordReply callBack
,
966 char *msg
= NULL
, *ptr
;
968 ipc_msg_hdr
*hdr
= NULL
;
969 DNSServiceRef tmp
= NULL
;
970 DNSRecordRef rref
= NULL
;
971 int f1
= (flags
& kDNSServiceFlagsShared
) != 0;
972 int f2
= (flags
& kDNSServiceFlagsUnique
) != 0;
973 if (f1
+ f2
!= 1) return kDNSServiceErr_BadParam
;
975 if (!sdRef
|| sdRef
->op
!= connection
|| sdRef
->sockfd
< 0)
976 return kDNSServiceErr_BadReference
;
979 len
= sizeof(DNSServiceFlags
);
980 len
+= 2 * sizeof(uint32_t); // interfaceIndex, ttl
981 len
+= 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen
982 len
+= strlen(fullname
) + 1;
985 hdr
= create_hdr(reg_record_request
, &len
, &ptr
, 0);
986 if (!hdr
) goto error
;
988 put_flags(flags
, &ptr
);
989 put_long(interfaceIndex
, &ptr
);
990 put_string(fullname
, &ptr
);
991 put_short(rrtype
, &ptr
);
992 put_short(rrclass
, &ptr
);
993 put_short(rdlen
, &ptr
);
994 put_rdata(rdlen
, rdata
, &ptr
);
997 rref
= malloc(sizeof(_DNSRecordRef_t
));
998 if (!rref
) goto error
;
999 rref
->app_context
= context
;
1000 rref
->app_callback
= callBack
;
1001 rref
->record_index
= sdRef
->max_index
++;
1004 hdr
->client_context
.context
= rref
;
1005 hdr
->reg_index
= rref
->record_index
;
1007 return deliver_request(msg
, sdRef
, 0);
1010 if (rref
) free(rref
);
1013 return kDNSServiceErr_Unknown
;
1016 //sdRef returned by DNSServiceRegister()
1017 DNSServiceErrorType DNSSD_API DNSServiceAddRecord
1019 DNSServiceRef sdRef
,
1020 DNSRecordRef
*RecordRef
,
1021 DNSServiceFlags flags
,
1033 if (!sdRef
|| (sdRef
->op
!= reg_service_request
) || !RecordRef
)
1034 return kDNSServiceErr_BadReference
;
1037 len
+= 2 * sizeof(uint16_t); //rrtype, rdlen
1039 len
+= sizeof(uint32_t);
1040 len
+= sizeof(DNSServiceFlags
);
1042 hdr
= create_hdr(add_record_request
, &len
, &ptr
, 0);
1043 if (!hdr
) return kDNSServiceErr_Unknown
;
1044 put_flags(flags
, &ptr
);
1045 put_short(rrtype
, &ptr
);
1046 put_short(rdlen
, &ptr
);
1047 put_rdata(rdlen
, rdata
, &ptr
);
1048 put_long(ttl
, &ptr
);
1050 rref
= malloc(sizeof(_DNSRecordRef_t
));
1051 if (!rref
) goto error
;
1052 rref
->app_context
= NULL
;
1053 rref
->app_callback
= NULL
;
1054 rref
->record_index
= sdRef
->max_index
++;
1057 hdr
->client_context
.context
= rref
;
1058 hdr
->reg_index
= rref
->record_index
;
1059 return deliver_request((char *)hdr
, sdRef
, 0);
1063 if (rref
) free(rref
);
1064 if (*RecordRef
) *RecordRef
= NULL
;
1065 return kDNSServiceErr_Unknown
;
1068 //DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
1069 DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
1071 DNSServiceRef sdRef
,
1072 DNSRecordRef RecordRef
,
1073 DNSServiceFlags flags
,
1083 if (!sdRef
) return kDNSServiceErr_BadReference
;
1085 len
+= sizeof(uint16_t);
1087 len
+= sizeof(uint32_t);
1088 len
+= sizeof(DNSServiceFlags
);
1090 hdr
= create_hdr(update_record_request
, &len
, &ptr
, 0);
1091 if (!hdr
) return kDNSServiceErr_Unknown
;
1092 hdr
->reg_index
= RecordRef
? RecordRef
->record_index
: TXT_RECORD_INDEX
;
1093 put_flags(flags
, &ptr
);
1094 put_short(rdlen
, &ptr
);
1095 put_rdata(rdlen
, rdata
, &ptr
);
1096 put_long(ttl
, &ptr
);
1097 return deliver_request((char *)hdr
, sdRef
, 0);
1100 DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
1102 DNSServiceRef sdRef
,
1103 DNSRecordRef RecordRef
,
1104 DNSServiceFlags flags
1110 DNSServiceErrorType err
;
1112 if (!sdRef
|| !RecordRef
|| !sdRef
->max_index
)
1113 return kDNSServiceErr_BadReference
;
1115 len
+= sizeof(flags
);
1116 hdr
= create_hdr(remove_record_request
, &len
, &ptr
, 0);
1117 if (!hdr
) return kDNSServiceErr_Unknown
;
1118 hdr
->reg_index
= RecordRef
->record_index
;
1119 put_flags(flags
, &ptr
);
1120 err
= deliver_request((char *)hdr
, sdRef
, 0);
1121 if (!err
) free(RecordRef
);
1125 void DNSSD_API DNSServiceReconfirmRecord
1127 DNSServiceFlags flags
,
1128 uint32_t interfaceIndex
,
1129 const char *fullname
,
1141 len
= sizeof(DNSServiceFlags
);
1142 len
+= sizeof(uint32_t);
1143 len
+= strlen(fullname
) + 1;
1144 len
+= 3 * sizeof(uint16_t);
1146 tmp
= connect_to_server();
1148 hdr
= create_hdr(reconfirm_record_request
, &len
, &ptr
, 1);
1151 put_flags(flags
, &ptr
);
1152 put_long(interfaceIndex
, &ptr
);
1153 put_string(fullname
, &ptr
);
1154 put_short(rrtype
, &ptr
);
1155 put_short(rrclass
, &ptr
);
1156 put_short(rdlen
, &ptr
);
1157 put_rdata(rdlen
, rdata
, &ptr
);
1158 ConvertHeaderBytes(hdr
);
1159 my_write(tmp
->sockfd
, (char *)hdr
, (int) len
);
1161 DNSServiceRefDeallocate(tmp
);