xref: /titanic_44/usr/src/lib/libdns_sd/common/dnssd_clientstub.c (revision 4b22b9337f359bfd063322244f5336cc7c6ffcfa)
1*4b22b933Srs200217 /* -*- Mode: C; tab-width: 4 -*-
2*4b22b933Srs200217  *
3*4b22b933Srs200217  * Copyright (c) 2003-2004, Apple Computer, Inc. All rights reserved.
4*4b22b933Srs200217  *
5*4b22b933Srs200217  * Redistribution and use in source and binary forms, with or without
6*4b22b933Srs200217  * modification, are permitted provided that the following conditions are met:
7*4b22b933Srs200217  *
8*4b22b933Srs200217  * 1.  Redistributions of source code must retain the above copyright notice,
9*4b22b933Srs200217  *     this list of conditions and the following disclaimer.
10*4b22b933Srs200217  * 2.  Redistributions in binary form must reproduce the above copyright notice,
11*4b22b933Srs200217  *     this list of conditions and the following disclaimer in the documentation
12*4b22b933Srs200217  *     and/or other materials provided with the distribution.
13*4b22b933Srs200217  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
14*4b22b933Srs200217  *     contributors may be used to endorse or promote products derived from this
15*4b22b933Srs200217  *     software without specific prior written permission.
16*4b22b933Srs200217  *
17*4b22b933Srs200217  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18*4b22b933Srs200217  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19*4b22b933Srs200217  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20*4b22b933Srs200217  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21*4b22b933Srs200217  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22*4b22b933Srs200217  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23*4b22b933Srs200217  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24*4b22b933Srs200217  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25*4b22b933Srs200217  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26*4b22b933Srs200217  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27*4b22b933Srs200217 
28*4b22b933Srs200217     Change History (most recent first):
29*4b22b933Srs200217 
30*4b22b933Srs200217 $Log: dnssd_clientstub.c,v $
31*4b22b933Srs200217 Revision 1.53  2006/09/07 04:43:12  herscher
32*4b22b933Srs200217 Fix compile error on Win32 platform by moving inclusion of syslog.h
33*4b22b933Srs200217 
34*4b22b933Srs200217 Revision 1.52  2006/08/15 23:04:21  mkrochma
35*4b22b933Srs200217 <rdar://problem/4090354> Client should be able to specify service name w/o callback
36*4b22b933Srs200217 
37*4b22b933Srs200217 Revision 1.51  2006/07/24 23:45:55  cheshire
38*4b22b933Srs200217 <rdar://problem/4605276> DNSServiceReconfirmRecord() should return error code
39*4b22b933Srs200217 
40*4b22b933Srs200217 Revision 1.50  2006/06/28 08:22:27  cheshire
41*4b22b933Srs200217 <rdar://problem/4605264> dnssd_clientstub.c needs to report unlink failures in syslog
42*4b22b933Srs200217 
43*4b22b933Srs200217 Revision 1.49  2006/06/28 07:58:59  cheshire
44*4b22b933Srs200217 Minor textual tidying
45*4b22b933Srs200217 
46*4b22b933Srs200217 Revision 1.48  2005/06/30 18:01:00  shersche
47*4b22b933Srs200217 <rdar://problem/4096913> Clients shouldn't wait ten seconds to connect to mDNSResponder
48*4b22b933Srs200217 
49*4b22b933Srs200217 Revision 1.47  2005/03/31 02:19:56  cheshire
50*4b22b933Srs200217 <rdar://problem/4021486> Fix build warnings
51*4b22b933Srs200217 Reviewed by: Scott Herscher
52*4b22b933Srs200217 
53*4b22b933Srs200217 Revision 1.46  2005/03/21 00:39:31  shersche
54*4b22b933Srs200217 <rdar://problem/4021486> Fix build warnings on Win32 platform
55*4b22b933Srs200217 
56*4b22b933Srs200217 Revision 1.45  2005/02/01 01:25:06  shersche
57*4b22b933Srs200217 Define sleep() to be Sleep() for Windows compatibility
58*4b22b933Srs200217 
59*4b22b933Srs200217 Revision 1.44  2005/01/27 22:57:56  cheshire
60*4b22b933Srs200217 Fix compile errors on gcc4
61*4b22b933Srs200217 
62*4b22b933Srs200217 Revision 1.43  2005/01/27 00:02:29  cheshire
63*4b22b933Srs200217 <rdar://problem/3947461> Handle case where client runs before daemon has finished launching
64*4b22b933Srs200217 
65*4b22b933Srs200217 Revision 1.42  2005/01/11 02:01:02  shersche
66*4b22b933Srs200217 Use dnssd_close() rather than close() for Windows compatibility
67*4b22b933Srs200217 
68*4b22b933Srs200217 Revision 1.41  2004/12/23 17:34:26  ksekar
69*4b22b933Srs200217 <rdar://problem/3931319> Calls leak sockets if mDNSResponder is not running
70*4b22b933Srs200217 
71*4b22b933Srs200217 Revision 1.40  2004/11/23 03:39:47  cheshire
72*4b22b933Srs200217 Let interface name/index mapping capability live directly in JNISupport.c,
73*4b22b933Srs200217 instead of having to call through to the daemon via IPC to get this information.
74*4b22b933Srs200217 
75*4b22b933Srs200217 Revision 1.39  2004/11/12 03:22:00  rpantos
76*4b22b933Srs200217 rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
77*4b22b933Srs200217 
78*4b22b933Srs200217 Revision 1.38  2004/11/02 02:51:23  cheshire
79*4b22b933Srs200217 <rdar://problem/3526342> Remove overly-restrictive flag checks
80*4b22b933Srs200217 
81*4b22b933Srs200217 Revision 1.37  2004/10/14 01:43:35  cheshire
82*4b22b933Srs200217 Fix opaque port passing problem
83*4b22b933Srs200217 
84*4b22b933Srs200217 Revision 1.36  2004/10/06 02:22:19  cheshire
85*4b22b933Srs200217 Changed MacRoman copyright symbol (should have been UTF-8 in any case :-) to ASCII-compatible "(c)"
86*4b22b933Srs200217 
87*4b22b933Srs200217 Revision 1.35  2004/10/01 22:15:55  rpantos
88*4b22b933Srs200217 rdar://problem/3824265: Replace APSL in client lib with BSD license.
89*4b22b933Srs200217 
90*4b22b933Srs200217 Revision 1.34  2004/09/17 22:36:13  cheshire
91*4b22b933Srs200217 Add comment explaining that deliver_request frees the message it sends
92*4b22b933Srs200217 
93*4b22b933Srs200217 Revision 1.33  2004/09/17 01:17:31  ksekar
94*4b22b933Srs200217 Remove double-free of msg header, freed automatically by deliver_request()
95*4b22b933Srs200217 
96*4b22b933Srs200217 Revision 1.32  2004/09/17 01:08:55  cheshire
97*4b22b933Srs200217 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
98*4b22b933Srs200217   The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
99*4b22b933Srs200217   declared in that file are ONLY appropriate to single-address-space embedded applications.
100*4b22b933Srs200217   For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
101*4b22b933Srs200217 
102*4b22b933Srs200217 Revision 1.31  2004/09/16 23:37:19  cheshire
103*4b22b933Srs200217 Free hdr before returning
104*4b22b933Srs200217 
105*4b22b933Srs200217 Revision 1.30  2004/09/16 23:14:24  cheshire
106*4b22b933Srs200217 Changes for Windows compatibility
107*4b22b933Srs200217 
108*4b22b933Srs200217 Revision 1.29  2004/09/16 21:46:38  ksekar
109*4b22b933Srs200217 <rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area domain
110*4b22b933Srs200217 
111*4b22b933Srs200217 Revision 1.28  2004/08/11 17:10:04  cheshire
112*4b22b933Srs200217 Fix signed/unsigned warnings
113*4b22b933Srs200217 
114*4b22b933Srs200217 Revision 1.27  2004/08/11 00:54:16  cheshire
115*4b22b933Srs200217 Change "hdr->op.request_op" to just "hdr->op"
116*4b22b933Srs200217 
117*4b22b933Srs200217 Revision 1.26  2004/07/26 06:07:27  shersche
118*4b22b933Srs200217 fix bugs when using an error socket to communicate with the daemon
119*4b22b933Srs200217 
120*4b22b933Srs200217 Revision 1.25  2004/07/26 05:54:02  shersche
121*4b22b933Srs200217 DNSServiceProcessResult() returns NoError if socket read returns EWOULDBLOCK
122*4b22b933Srs200217 
123*4b22b933Srs200217 Revision 1.24  2004/07/20 06:46:21  shersche
124*4b22b933Srs200217 <rdar://problem/3730123> fix endless loop in read_all() if recv returns 0
125*4b22b933Srs200217 Bug #: 3730123
126*4b22b933Srs200217 
127*4b22b933Srs200217 Revision 1.23  2004/06/29 00:48:38  cheshire
128*4b22b933Srs200217 Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
129*4b22b933Srs200217 use an explicit while() loop instead.
130*4b22b933Srs200217 
131*4b22b933Srs200217 Revision 1.22  2004/06/26 03:16:34  shersche
132*4b22b933Srs200217 clean up warning messages on Win32 platform
133*4b22b933Srs200217 
134*4b22b933Srs200217 Submitted by: herscher
135*4b22b933Srs200217 
136*4b22b933Srs200217 Revision 1.21  2004/06/18 04:53:56  rpantos
137*4b22b933Srs200217 Use platform layer for socket types. Introduce USE_TCP_LOOPBACK. Remove dependency on mDNSEmbeddedAPI.h.
138*4b22b933Srs200217 
139*4b22b933Srs200217 Revision 1.20  2004/06/12 00:50:22  cheshire
140*4b22b933Srs200217 Changes for Windows compatibility
141*4b22b933Srs200217 
142*4b22b933Srs200217 Revision 1.19  2004/05/25 18:29:33  cheshire
143*4b22b933Srs200217 Move DNSServiceConstructFullName() from dnssd_clientstub.c to dnssd_clientlib.c,
144*4b22b933Srs200217 so that it's also accessible to dnssd_clientshim.c (single address space) clients.
145*4b22b933Srs200217 
146*4b22b933Srs200217 Revision 1.18  2004/05/18 23:51:27  cheshire
147*4b22b933Srs200217 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
148*4b22b933Srs200217 
149*4b22b933Srs200217 Revision 1.17  2004/05/06 18:42:58  ksekar
150*4b22b933Srs200217 General dns_sd.h API cleanup, including the following radars:
151*4b22b933Srs200217 <rdar://problem/3592068>: Remove flags with zero value
152*4b22b933Srs200217 <rdar://problem/3479569>: Passing in NULL causes a crash.
153*4b22b933Srs200217 
154*4b22b933Srs200217 Revision 1.16  2004/03/12 22:00:37  cheshire
155*4b22b933Srs200217 Added: #include <sys/socket.h>
156*4b22b933Srs200217 
157*4b22b933Srs200217 Revision 1.15  2004/01/20 18:36:29  ksekar
158*4b22b933Srs200217 Propagated Libinfo fix for <rdar://problem/3483971>: SU:
159*4b22b933Srs200217 DNSServiceUpdateRecord() doesn't allow you to update the TXT record
160*4b22b933Srs200217 into TOT mDNSResponder.
161*4b22b933Srs200217 
162*4b22b933Srs200217 Revision 1.14  2004/01/19 22:39:17  cheshire
163*4b22b933Srs200217 Don't use "MSG_WAITALL"; it makes send() return "Invalid argument" on Linux;
164*4b22b933Srs200217 use an explicit while() loop instead. (In any case, this should only make a difference
165*4b22b933Srs200217 with non-blocking sockets, which we don't use on the client side right now.)
166*4b22b933Srs200217 
167*4b22b933Srs200217 Revision 1.13  2004/01/19 21:46:52  cheshire
168*4b22b933Srs200217 Fix compiler warning
169*4b22b933Srs200217 
170*4b22b933Srs200217 Revision 1.12  2003/12/23 20:46:47  ksekar
171*4b22b933Srs200217 <rdar://problem/3497428>: sync dnssd files between libinfo & mDNSResponder
172*4b22b933Srs200217 
173*4b22b933Srs200217 Revision 1.11  2003/12/08 21:11:42  rpantos
174*4b22b933Srs200217 Changes necessary to support mDNSResponder on Linux.
175*4b22b933Srs200217 
176*4b22b933Srs200217 Revision 1.10  2003/10/13 23:50:53  ksekar
177*4b22b933Srs200217 Updated dns_sd clientstub files to bring copies in synch with
178*4b22b933Srs200217 top-of-tree Libinfo:  A memory leak in dnssd_clientstub.c is fixed,
179*4b22b933Srs200217 and comments in dns_sd.h are improved.
180*4b22b933Srs200217 
181*4b22b933Srs200217 Revision 1.9  2003/08/15 21:30:39  cheshire
182*4b22b933Srs200217 Bring up to date with LibInfo version
183*4b22b933Srs200217 
184*4b22b933Srs200217 Revision 1.8  2003/08/13 23:54:52  ksekar
185*4b22b933Srs200217 Bringing dnssd_clientstub.c up to date with Libinfo, per radar 3376640
186*4b22b933Srs200217 
187*4b22b933Srs200217 Revision 1.7  2003/08/12 19:56:25  cheshire
188*4b22b933Srs200217 Update to APSL 2.0
189*4b22b933Srs200217 
190*4b22b933Srs200217  */
191*4b22b933Srs200217 
192*4b22b933Srs200217 #pragma ident	"%Z%%M%	%I%	%E% SMI"
193*4b22b933Srs200217 
194*4b22b933Srs200217 #include <errno.h>
195*4b22b933Srs200217 #include <stdlib.h>
196*4b22b933Srs200217 
197*4b22b933Srs200217 #include "dnssd_ipc.h"
198*4b22b933Srs200217 
199*4b22b933Srs200217 #if defined(_WIN32)
200*4b22b933Srs200217 
201*4b22b933Srs200217 #include <winsock2.h>
202*4b22b933Srs200217 #include <windows.h>
203*4b22b933Srs200217 
204*4b22b933Srs200217 #define sockaddr_mdns sockaddr_in
205*4b22b933Srs200217 #define AF_MDNS AF_INET
206*4b22b933Srs200217 
207*4b22b933Srs200217 // disable warning: "'type cast' : from data pointer 'void *' to function pointer"
208*4b22b933Srs200217 #pragma warning(disable:4055)
209*4b22b933Srs200217 
210*4b22b933Srs200217 // disable warning: "nonstandard extension, function/data pointer conversion in expression"
211*4b22b933Srs200217 #pragma warning(disable:4152)
212*4b22b933Srs200217 
213*4b22b933Srs200217 extern BOOL IsSystemServiceDisabled();
214*4b22b933Srs200217 
215*4b22b933Srs200217 #define sleep(X) Sleep((X) * 1000)
216*4b22b933Srs200217 
217*4b22b933Srs200217 static int g_initWinsock = 0;
218*4b22b933Srs200217 
219*4b22b933Srs200217 #else
220*4b22b933Srs200217 
221*4b22b933Srs200217 #include <sys/time.h>
222*4b22b933Srs200217 #include <sys/socket.h>
223*4b22b933Srs200217 #include <syslog.h>
224*4b22b933Srs200217 
225*4b22b933Srs200217 #define sockaddr_mdns sockaddr_un
226*4b22b933Srs200217 #define AF_MDNS AF_LOCAL
227*4b22b933Srs200217 
228*4b22b933Srs200217 #endif
229*4b22b933Srs200217 
230*4b22b933Srs200217 // <rdar://problem/4096913> Specifies how many times we'll try and connect to the
231*4b22b933Srs200217 // server.
232*4b22b933Srs200217 
233*4b22b933Srs200217 #define DNSSD_CLIENT_MAXTRIES 4
234*4b22b933Srs200217 
235*4b22b933Srs200217 #define CTL_PATH_PREFIX "/tmp/dnssd_clippath."
236*4b22b933Srs200217 // error socket (if needed) is named "dnssd_clipath.[pid].xxx:n" where xxx are the
237*4b22b933Srs200217 // last 3 digits of the time (in seconds) and n is the 6-digit microsecond time
238*4b22b933Srs200217 
239*4b22b933Srs200217 // general utility functions
240*4b22b933Srs200217 typedef struct _DNSServiceRef_t
241*4b22b933Srs200217     {
242*4b22b933Srs200217     dnssd_sock_t sockfd;  // connected socket between client and daemon
243*4b22b933Srs200217     uint32_t op;          // request_op_t or reply_op_t
244*4b22b933Srs200217     process_reply_callback process_reply;
245*4b22b933Srs200217     void *app_callback;
246*4b22b933Srs200217     void *app_context;
247*4b22b933Srs200217     uint32_t max_index;  //largest assigned record index - 0 if no additl. recs registered
248*4b22b933Srs200217     } _DNSServiceRef_t;
249*4b22b933Srs200217 
250*4b22b933Srs200217 typedef struct _DNSRecordRef_t
251*4b22b933Srs200217     {
252*4b22b933Srs200217     void *app_context;
253*4b22b933Srs200217     DNSServiceRegisterRecordReply app_callback;
254*4b22b933Srs200217     DNSRecordRef recref;
255*4b22b933Srs200217     uint32_t record_index;  // index is unique to the ServiceDiscoveryRef
256*4b22b933Srs200217     DNSServiceRef sdr;
257*4b22b933Srs200217     } _DNSRecordRef_t;
258*4b22b933Srs200217 
259*4b22b933Srs200217 // exported functions
260*4b22b933Srs200217 
261*4b22b933Srs200217 // write len bytes.  return 0 on success, -1 on error
write_all(dnssd_sock_t sd,char * buf,int len)262*4b22b933Srs200217 static int write_all(dnssd_sock_t sd, char *buf, int len)
263*4b22b933Srs200217     {
264*4b22b933Srs200217     // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
265*4b22b933Srs200217     //if (send(sd, buf, len, MSG_WAITALL) != len)   return -1;
266*4b22b933Srs200217     while (len)
267*4b22b933Srs200217     	{
268*4b22b933Srs200217     	ssize_t num_written = send(sd, buf, len, 0);
269*4b22b933Srs200217     	if (num_written < 0 || num_written > len) return -1;
270*4b22b933Srs200217     	buf += num_written;
271*4b22b933Srs200217     	len -= num_written;
272*4b22b933Srs200217     	}
273*4b22b933Srs200217     return 0;
274*4b22b933Srs200217     }
275*4b22b933Srs200217 
276*4b22b933Srs200217 // read len bytes.  return 0 on success, -1 on error
read_all(dnssd_sock_t sd,char * buf,int len)277*4b22b933Srs200217 static int read_all(dnssd_sock_t sd, char *buf, int len)
278*4b22b933Srs200217     {
279*4b22b933Srs200217     // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
280*4b22b933Srs200217     //if (recv(sd, buf, len, MSG_WAITALL) != len)  return -1;
281*4b22b933Srs200217     while (len)
282*4b22b933Srs200217     	{
283*4b22b933Srs200217     	ssize_t num_read = recv(sd, buf, len, 0);
284*4b22b933Srs200217 	if ((num_read == -1) && (errno == EINTR))
285*4b22b933Srs200217 		continue;
286*4b22b933Srs200217 	if ((num_read < 0) || (num_read > len)) return -1;
287*4b22b933Srs200217 	// Return error -2 when no data received and errno is not set
288*4b22b933Srs200217 	if (num_read == 0) return -2;
289*4b22b933Srs200217     	buf += num_read;
290*4b22b933Srs200217     	len -= num_read;
291*4b22b933Srs200217     	}
292*4b22b933Srs200217     return 0;
293*4b22b933Srs200217     }
294*4b22b933Srs200217 
295*4b22b933Srs200217 /* create_hdr
296*4b22b933Srs200217  *
297*4b22b933Srs200217  * allocate and initialize an ipc message header.  value of len should initially be the
298*4b22b933Srs200217  * length of the data, and is set to the value of the data plus the header.  data_start
299*4b22b933Srs200217  * is set to point to the beginning of the data section.  reuse_socket should be non-zero
300*4b22b933Srs200217  * for calls that can receive an immediate error return value on their primary socket.
301*4b22b933Srs200217  * if zero, the path to a control socket is appended at the beginning of the message buffer.
302*4b22b933Srs200217  * data_start is set past this string.
303*4b22b933Srs200217  */
304*4b22b933Srs200217 
create_hdr(uint32_t op,size_t * len,char ** data_start,int reuse_socket)305*4b22b933Srs200217 static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int reuse_socket)
306*4b22b933Srs200217     {
307*4b22b933Srs200217     char *msg = NULL;
308*4b22b933Srs200217     ipc_msg_hdr *hdr;
309*4b22b933Srs200217     int datalen;
310*4b22b933Srs200217 #if !defined(USE_TCP_LOOPBACK)
311*4b22b933Srs200217     char ctrl_path[256];
312*4b22b933Srs200217 #endif
313*4b22b933Srs200217 
314*4b22b933Srs200217     if (!reuse_socket)
315*4b22b933Srs200217         {
316*4b22b933Srs200217 #if defined(USE_TCP_LOOPBACK)
317*4b22b933Srs200217 		*len += 2;  // Allocate space for two-byte port number
318*4b22b933Srs200217 #else
319*4b22b933Srs200217 		struct timeval time;
320*4b22b933Srs200217 		if (gettimeofday(&time, NULL) < 0) return NULL;
321*4b22b933Srs200217 		sprintf(ctrl_path, "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(),
322*4b22b933Srs200217 			(unsigned long)(time.tv_sec & 0xFFF), (unsigned long)(time.tv_usec));
323*4b22b933Srs200217         *len += strlen(ctrl_path) + 1;
324*4b22b933Srs200217 #endif
325*4b22b933Srs200217         }
326*4b22b933Srs200217 
327*4b22b933Srs200217     datalen = (int) *len;
328*4b22b933Srs200217     *len += sizeof(ipc_msg_hdr);
329*4b22b933Srs200217 
330*4b22b933Srs200217     // write message to buffer
331*4b22b933Srs200217     msg = malloc(*len);
332*4b22b933Srs200217     if (!msg) return NULL;
333*4b22b933Srs200217 
334*4b22b933Srs200217     bzero(msg, *len);
335*4b22b933Srs200217     hdr = (void *)msg;
336*4b22b933Srs200217     hdr->datalen = datalen;
337*4b22b933Srs200217     hdr->version = VERSION;
338*4b22b933Srs200217     hdr->op = op;
339*4b22b933Srs200217     if (reuse_socket) hdr->flags |= IPC_FLAGS_REUSE_SOCKET;
340*4b22b933Srs200217     *data_start = msg + sizeof(ipc_msg_hdr);
341*4b22b933Srs200217 #if defined(USE_TCP_LOOPBACK)
342*4b22b933Srs200217 	// Put dummy data in for the port, since we don't know what
343*4b22b933Srs200217 	// it is yet.  The data will get filled in before we
344*4b22b933Srs200217 	// send the message. This happens in deliver_request().
345*4b22b933Srs200217 	if (!reuse_socket)  put_short(0, data_start);
346*4b22b933Srs200217 #else
347*4b22b933Srs200217     if (!reuse_socket)  put_string(ctrl_path, data_start);
348*4b22b933Srs200217 #endif
349*4b22b933Srs200217     return hdr;
350*4b22b933Srs200217     }
351*4b22b933Srs200217 
352*4b22b933Srs200217     // return a connected service ref (deallocate with DNSServiceRefDeallocate)
connect_to_server(void)353*4b22b933Srs200217 static DNSServiceRef connect_to_server(void)
354*4b22b933Srs200217     {
355*4b22b933Srs200217 	dnssd_sockaddr_t saddr;
356*4b22b933Srs200217 	DNSServiceRef sdr;
357*4b22b933Srs200217 	int NumTries = 0;
358*4b22b933Srs200217 
359*4b22b933Srs200217 #if defined(_WIN32)
360*4b22b933Srs200217 	if (!g_initWinsock)
361*4b22b933Srs200217 		{
362*4b22b933Srs200217 		WSADATA wsaData;
363*4b22b933Srs200217 		DNSServiceErrorType err;
364*4b22b933Srs200217 
365*4b22b933Srs200217 		g_initWinsock = 1;
366*4b22b933Srs200217 
367*4b22b933Srs200217 		err = WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
368*4b22b933Srs200217 
369*4b22b933Srs200217 		if (err != 0) return NULL;
370*4b22b933Srs200217 		}
371*4b22b933Srs200217 
372*4b22b933Srs200217 	// <rdar://problem/4096913> If the system service is disabled, we only want to try
373*4b22b933Srs200217 	// to connect once
374*4b22b933Srs200217 
375*4b22b933Srs200217 	if ( IsSystemServiceDisabled() )
376*4b22b933Srs200217 		{
377*4b22b933Srs200217 		NumTries = DNSSD_CLIENT_MAXTRIES;
378*4b22b933Srs200217 		}
379*4b22b933Srs200217 
380*4b22b933Srs200217 #endif
381*4b22b933Srs200217 
382*4b22b933Srs200217 	sdr = malloc(sizeof(_DNSServiceRef_t));
383*4b22b933Srs200217 	if (!sdr) return(NULL);
384*4b22b933Srs200217 	sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0);
385*4b22b933Srs200217 	if (sdr->sockfd == dnssd_InvalidSocket) { free(sdr); return NULL; }
386*4b22b933Srs200217 #if defined(USE_TCP_LOOPBACK)
387*4b22b933Srs200217 	saddr.sin_family      = AF_INET;
388*4b22b933Srs200217 	saddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
389*4b22b933Srs200217 	saddr.sin_port        = htons(MDNS_TCP_SERVERPORT);
390*4b22b933Srs200217 #else
391*4b22b933Srs200217 	saddr.sun_family = AF_LOCAL;
392*4b22b933Srs200217 	strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH);
393*4b22b933Srs200217 #endif
394*4b22b933Srs200217 	while (1)
395*4b22b933Srs200217 		{
396*4b22b933Srs200217 		int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
397*4b22b933Srs200217 		if (!err) break; // If we succeeded, return sdr
398*4b22b933Srs200217 		// If we failed, then it may be because the daemon is still launching.
399*4b22b933Srs200217 		// This can happen for processes that launch early in the boot process, while the
400*4b22b933Srs200217 		// daemon is still coming up. Rather than fail here, we'll wait a bit and try again.
401*4b22b933Srs200217 		// If, after four seconds, we still can't connect to the daemon,
402*4b22b933Srs200217 		// then we give up and return a failure code.
403*4b22b933Srs200217 		if (++NumTries < DNSSD_CLIENT_MAXTRIES)
404*4b22b933Srs200217 			sleep(1); // Sleep a bit, then try again
405*4b22b933Srs200217 		else
406*4b22b933Srs200217 			{
407*4b22b933Srs200217 			dnssd_close(sdr->sockfd);
408*4b22b933Srs200217 			sdr->sockfd = dnssd_InvalidSocket;
409*4b22b933Srs200217 			free(sdr);
410*4b22b933Srs200217 			return NULL;
411*4b22b933Srs200217 			}
412*4b22b933Srs200217 		}
413*4b22b933Srs200217     return sdr;
414*4b22b933Srs200217 	}
415*4b22b933Srs200217 
deliver_request(void * msg,DNSServiceRef sdr,int reuse_sd)416*4b22b933Srs200217 static DNSServiceErrorType deliver_request(void *msg, DNSServiceRef sdr, int reuse_sd)
417*4b22b933Srs200217     {
418*4b22b933Srs200217     ipc_msg_hdr *hdr = msg;
419*4b22b933Srs200217     uint32_t datalen = hdr->datalen;
420*4b22b933Srs200217     dnssd_sockaddr_t caddr, daddr;  // (client and daemon address structs)
421*4b22b933Srs200217     char *const data = (char *)msg + sizeof(ipc_msg_hdr);
422*4b22b933Srs200217     dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
423*4b22b933Srs200217 	int ret;
424*4b22b933Srs200217 	dnssd_socklen_t len = (dnssd_socklen_t) sizeof(caddr);
425*4b22b933Srs200217     DNSServiceErrorType err = kDNSServiceErr_Unknown;
426*4b22b933Srs200217 
427*4b22b933Srs200217     if (!hdr || sdr->sockfd < 0) return kDNSServiceErr_Unknown;
428*4b22b933Srs200217 
429*4b22b933Srs200217 	if (!reuse_sd)
430*4b22b933Srs200217 		{
431*4b22b933Srs200217         // setup temporary error socket
432*4b22b933Srs200217         if ((listenfd = socket(AF_DNSSD, SOCK_STREAM, 0)) < 0)
433*4b22b933Srs200217             goto cleanup;
434*4b22b933Srs200217         bzero(&caddr, sizeof(caddr));
435*4b22b933Srs200217 
436*4b22b933Srs200217 #if defined(USE_TCP_LOOPBACK)
437*4b22b933Srs200217 			{
438*4b22b933Srs200217 			union { uint16_t s; u_char b[2]; } port;
439*4b22b933Srs200217 			caddr.sin_family      = AF_INET;
440*4b22b933Srs200217 			caddr.sin_port        = 0;
441*4b22b933Srs200217 			caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
442*4b22b933Srs200217 			ret = bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr));
443*4b22b933Srs200217 			if (ret < 0) goto cleanup;
444*4b22b933Srs200217 			if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) goto cleanup;
445*4b22b933Srs200217 			listen(listenfd, 1);
446*4b22b933Srs200217 			port.s = caddr.sin_port;
447*4b22b933Srs200217 			data[0] = port.b[0];  // don't switch the byte order, as the
448*4b22b933Srs200217 			data[1] = port.b[1];  // daemon expects it in network byte order
449*4b22b933Srs200217 			}
450*4b22b933Srs200217 #else
451*4b22b933Srs200217 			{
452*4b22b933Srs200217 			mode_t mask = umask(0);
453*4b22b933Srs200217 			caddr.sun_family = AF_LOCAL;
454*4b22b933Srs200217 // According to Stevens (section 3.2), there is no portable way to
455*4b22b933Srs200217 // determine whether sa_len is defined on a particular platform.
456*4b22b933Srs200217 #ifndef NOT_HAVE_SA_LEN
457*4b22b933Srs200217 			caddr.sun_len = sizeof(struct sockaddr_un);
458*4b22b933Srs200217 #endif
459*4b22b933Srs200217 			//syslog(LOG_WARNING, "deliver_request: creating UDS: %s\n", data);
460*4b22b933Srs200217 			strcpy(caddr.sun_path, data);
461*4b22b933Srs200217 			ret = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr));
462*4b22b933Srs200217 			umask(mask);
463*4b22b933Srs200217 			if (ret < 0) goto cleanup;
464*4b22b933Srs200217 			listen(listenfd, 1);
465*4b22b933Srs200217 			}
466*4b22b933Srs200217 #endif
467*4b22b933Srs200217 		}
468*4b22b933Srs200217 
469*4b22b933Srs200217 	ConvertHeaderBytes(hdr);
470*4b22b933Srs200217 	//syslog(LOG_WARNING, "deliver_request writing %ld bytes\n", datalen + sizeof(ipc_msg_hdr));
471*4b22b933Srs200217 	//syslog(LOG_WARNING, "deliver_request name is %s\n", (char *)msg + sizeof(ipc_msg_hdr));
472*4b22b933Srs200217     if (write_all(sdr->sockfd, msg, datalen + sizeof(ipc_msg_hdr)) < 0)
473*4b22b933Srs200217         goto cleanup;
474*4b22b933Srs200217     free(msg);
475*4b22b933Srs200217     msg = NULL;
476*4b22b933Srs200217 
477*4b22b933Srs200217     if (reuse_sd) errsd = sdr->sockfd;
478*4b22b933Srs200217     else
479*4b22b933Srs200217         {
480*4b22b933Srs200217 		//syslog(LOG_WARNING, "deliver_request: accept\n");
481*4b22b933Srs200217         len = sizeof(daddr);
482*4b22b933Srs200217         errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
483*4b22b933Srs200217 		//syslog(LOG_WARNING, "deliver_request: accept returned %d\n", errsd);
484*4b22b933Srs200217         if (errsd < 0)  goto cleanup;
485*4b22b933Srs200217         }
486*4b22b933Srs200217 
487*4b22b933Srs200217     if (read_all(errsd, (char*)&err, (int)sizeof(err)) < 0)
488*4b22b933Srs200217         err = kDNSServiceErr_Unknown;
489*4b22b933Srs200217     else
490*4b22b933Srs200217     	err = ntohl(err);
491*4b22b933Srs200217 
492*4b22b933Srs200217 	//syslog(LOG_WARNING, "deliver_request: retrieved error code %d\n", err);
493*4b22b933Srs200217 
494*4b22b933Srs200217 cleanup:
495*4b22b933Srs200217 	if (!reuse_sd)
496*4b22b933Srs200217 		{
497*4b22b933Srs200217 		if (listenfd > 0) dnssd_close(listenfd);
498*4b22b933Srs200217 		if (errsd    > 0) dnssd_close(errsd);
499*4b22b933Srs200217 #if !defined(USE_TCP_LOOPBACK)
500*4b22b933Srs200217 		// syslog(LOG_WARNING, "deliver_request: removing UDS: %s\n", data);
501*4b22b933Srs200217 		if (unlink(data) != 0)
502*4b22b933Srs200217 			syslog(LOG_WARNING, "WARNING: unlink(\"%s\") failed errno %d (%s)", data, errno, strerror(errno));
503*4b22b933Srs200217 		// else syslog(LOG_WARNING, "deliver_request: removed UDS: %s\n", data);
504*4b22b933Srs200217 #endif
505*4b22b933Srs200217 		}
506*4b22b933Srs200217     if (msg) free(msg);
507*4b22b933Srs200217     return err;
508*4b22b933Srs200217     }
509*4b22b933Srs200217 
DNSServiceRefSockFD(DNSServiceRef sdRef)510*4b22b933Srs200217 int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef)
511*4b22b933Srs200217     {
512*4b22b933Srs200217     if (!sdRef) return -1;
513*4b22b933Srs200217     return (int) sdRef->sockfd;
514*4b22b933Srs200217     }
515*4b22b933Srs200217 
516*4b22b933Srs200217 // handle reply from server, calling application client callback.  If there is no reply
517*4b22b933Srs200217 // from the daemon on the socket contained in sdRef, the call will block.
DNSServiceProcessResult(DNSServiceRef sdRef)518*4b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
519*4b22b933Srs200217     {
520*4b22b933Srs200217     ipc_msg_hdr hdr;
521*4b22b933Srs200217     char *data;
522*4b22b933Srs200217     int rderr;
523*4b22b933Srs200217 
524*4b22b933Srs200217     if (!sdRef || sdRef->sockfd < 0 || !sdRef->process_reply)
525*4b22b933Srs200217         return kDNSServiceErr_BadReference;
526*4b22b933Srs200217 
527*4b22b933Srs200217     rderr = read_all(sdRef->sockfd, (void *)&hdr, sizeof(hdr));
528*4b22b933Srs200217     if (rderr < 0) {
529*4b22b933Srs200217 		// return NoError on EWOULDBLOCK. This will handle the case
530*4b22b933Srs200217 		// where a non-blocking socket is told there is data, but
531*4b22b933Srs200217 		// it was a false positive. Can check errno when error
532*4b22b933Srs200217 		// code returned is -1
533*4b22b933Srs200217 		if ((rderr == -1) && (dnssd_errno() == dnssd_EWOULDBLOCK))
534*4b22b933Srs200217 				return kDNSServiceErr_NoError;
535*4b22b933Srs200217 	        return kDNSServiceErr_Unknown;
536*4b22b933Srs200217     }
537*4b22b933Srs200217 	ConvertHeaderBytes(&hdr);
538*4b22b933Srs200217     if (hdr.version != VERSION)
539*4b22b933Srs200217         return kDNSServiceErr_Incompatible;
540*4b22b933Srs200217     data = malloc(hdr.datalen);
541*4b22b933Srs200217     if (!data) return kDNSServiceErr_NoMemory;
542*4b22b933Srs200217     if (read_all(sdRef->sockfd, data, hdr.datalen) < 0)
543*4b22b933Srs200217         return kDNSServiceErr_Unknown;
544*4b22b933Srs200217     sdRef->process_reply(sdRef, &hdr, data);
545*4b22b933Srs200217     free(data);
546*4b22b933Srs200217     return kDNSServiceErr_NoError;
547*4b22b933Srs200217     }
548*4b22b933Srs200217 
DNSServiceRefDeallocate(DNSServiceRef sdRef)549*4b22b933Srs200217 void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef)
550*4b22b933Srs200217     {
551*4b22b933Srs200217     if (!sdRef) return;
552*4b22b933Srs200217     if (sdRef->sockfd > 0) dnssd_close(sdRef->sockfd);
553*4b22b933Srs200217     free(sdRef);
554*4b22b933Srs200217     }
555*4b22b933Srs200217 
handle_resolve_response(DNSServiceRef sdr,ipc_msg_hdr * hdr,char * data)556*4b22b933Srs200217 static void handle_resolve_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
557*4b22b933Srs200217     {
558*4b22b933Srs200217     DNSServiceFlags flags;
559*4b22b933Srs200217     char fullname[kDNSServiceMaxDomainName];
560*4b22b933Srs200217     char target[kDNSServiceMaxDomainName];
561*4b22b933Srs200217     uint16_t txtlen;
562*4b22b933Srs200217     union { uint16_t s; u_char b[2]; } port;
563*4b22b933Srs200217     uint32_t ifi;
564*4b22b933Srs200217     DNSServiceErrorType err;
565*4b22b933Srs200217     unsigned char *txtrecord;
566*4b22b933Srs200217     int str_error = 0;
567*4b22b933Srs200217     (void)hdr; 		//unused
568*4b22b933Srs200217 
569*4b22b933Srs200217     flags = get_flags(&data);
570*4b22b933Srs200217     ifi = get_long(&data);
571*4b22b933Srs200217     err = get_error_code(&data);
572*4b22b933Srs200217     if (get_string(&data, fullname, kDNSServiceMaxDomainName) < 0) str_error = 1;
573*4b22b933Srs200217     if (get_string(&data, target, kDNSServiceMaxDomainName) < 0) str_error = 1;
574*4b22b933Srs200217     port.b[0] = *data++;
575*4b22b933Srs200217     port.b[1] = *data++;
576*4b22b933Srs200217     txtlen = get_short(&data);
577*4b22b933Srs200217     txtrecord = (unsigned char *)get_rdata(&data, txtlen);
578*4b22b933Srs200217 
579*4b22b933Srs200217 	if (!err && str_error) err = kDNSServiceErr_Unknown;
580*4b22b933Srs200217     ((DNSServiceResolveReply)sdr->app_callback)(sdr, flags, ifi, err, fullname, target, port.s, txtlen, txtrecord, sdr->app_context);
581*4b22b933Srs200217     }
582*4b22b933Srs200217 
DNSServiceResolve(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * name,const char * regtype,const char * domain,DNSServiceResolveReply callBack,void * context)583*4b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceResolve
584*4b22b933Srs200217     (
585*4b22b933Srs200217     DNSServiceRef                  	*sdRef,
586*4b22b933Srs200217     DNSServiceFlags               flags,
587*4b22b933Srs200217     uint32_t                      interfaceIndex,
588*4b22b933Srs200217     const char                         	*name,
589*4b22b933Srs200217     const char                         	*regtype,
590*4b22b933Srs200217     const char                         	*domain,
591*4b22b933Srs200217     DNSServiceResolveReply        callBack,
592*4b22b933Srs200217     void                               	*context
593*4b22b933Srs200217     )
594*4b22b933Srs200217     {
595*4b22b933Srs200217     char *msg = NULL, *ptr;
596*4b22b933Srs200217     size_t len;
597*4b22b933Srs200217     ipc_msg_hdr *hdr;
598*4b22b933Srs200217     DNSServiceRef sdr;
599*4b22b933Srs200217     DNSServiceErrorType err;
600*4b22b933Srs200217 
601*4b22b933Srs200217     if (!sdRef) return kDNSServiceErr_BadParam;
602*4b22b933Srs200217     *sdRef = NULL;
603*4b22b933Srs200217 
604*4b22b933Srs200217 	if (!name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam;
605*4b22b933Srs200217 
606*4b22b933Srs200217     // calculate total message length
607*4b22b933Srs200217     len = sizeof(flags);
608*4b22b933Srs200217     len += sizeof(interfaceIndex);
609*4b22b933Srs200217     len += strlen(name) + 1;
610*4b22b933Srs200217     len += strlen(regtype) + 1;
611*4b22b933Srs200217     len += strlen(domain) + 1;
612*4b22b933Srs200217 
613*4b22b933Srs200217     hdr = create_hdr(resolve_request, &len, &ptr, 1);
614*4b22b933Srs200217     if (!hdr) goto error;
615*4b22b933Srs200217     msg = (void *)hdr;
616*4b22b933Srs200217 
617*4b22b933Srs200217     put_flags(flags, &ptr);
618*4b22b933Srs200217     put_long(interfaceIndex, &ptr);
619*4b22b933Srs200217     put_string(name, &ptr);
620*4b22b933Srs200217     put_string(regtype, &ptr);
621*4b22b933Srs200217     put_string(domain, &ptr);
622*4b22b933Srs200217 
623*4b22b933Srs200217     sdr = connect_to_server();
624*4b22b933Srs200217     if (!sdr) goto error;
625*4b22b933Srs200217     err = deliver_request(msg, sdr, 1);
626*4b22b933Srs200217     if (err)
627*4b22b933Srs200217         {
628*4b22b933Srs200217         DNSServiceRefDeallocate(sdr);
629*4b22b933Srs200217         return err;
630*4b22b933Srs200217         }
631*4b22b933Srs200217     sdr->op = resolve_request;
632*4b22b933Srs200217     sdr->process_reply = handle_resolve_response;
633*4b22b933Srs200217     sdr->app_callback = callBack;
634*4b22b933Srs200217     sdr->app_context = context;
635*4b22b933Srs200217     *sdRef = sdr;
636*4b22b933Srs200217 
637*4b22b933Srs200217     return err;
638*4b22b933Srs200217 
639*4b22b933Srs200217 error:
640*4b22b933Srs200217     if (msg) free(msg);
641*4b22b933Srs200217     if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
642*4b22b933Srs200217     return kDNSServiceErr_Unknown;
643*4b22b933Srs200217     }
644*4b22b933Srs200217 
handle_query_response(DNSServiceRef sdr,ipc_msg_hdr * hdr,char * data)645*4b22b933Srs200217 static void handle_query_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
646*4b22b933Srs200217     {
647*4b22b933Srs200217     DNSServiceFlags flags;
648*4b22b933Srs200217     uint32_t interfaceIndex, ttl;
649*4b22b933Srs200217     DNSServiceErrorType errorCode;
650*4b22b933Srs200217     char name[kDNSServiceMaxDomainName];
651*4b22b933Srs200217     uint16_t rrtype, rrclass, rdlen;
652*4b22b933Srs200217     char *rdata;
653*4b22b933Srs200217     int str_error = 0;
654*4b22b933Srs200217     (void)hdr;//Unused
655*4b22b933Srs200217 
656*4b22b933Srs200217     flags = get_flags(&data);
657*4b22b933Srs200217     interfaceIndex = get_long(&data);
658*4b22b933Srs200217     errorCode = get_error_code(&data);
659*4b22b933Srs200217     if (get_string(&data, name, kDNSServiceMaxDomainName) < 0) str_error = 1;
660*4b22b933Srs200217     rrtype = get_short(&data);
661*4b22b933Srs200217     rrclass = get_short(&data);
662*4b22b933Srs200217     rdlen = get_short(&data);
663*4b22b933Srs200217     rdata = get_rdata(&data, rdlen);
664*4b22b933Srs200217 	ttl = get_long(&data);
665*4b22b933Srs200217 
666*4b22b933Srs200217 	if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown;
667*4b22b933Srs200217 	((DNSServiceQueryRecordReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, name, rrtype, rrclass,
668*4b22b933Srs200217 													rdlen, rdata, ttl, sdr->app_context);
669*4b22b933Srs200217     return;
670*4b22b933Srs200217     }
671*4b22b933Srs200217 
DNSServiceQueryRecord(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * name,uint16_t rrtype,uint16_t rrclass,DNSServiceQueryRecordReply callBack,void * context)672*4b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
673*4b22b933Srs200217     (
674*4b22b933Srs200217     DNSServiceRef              *sdRef,
675*4b22b933Srs200217     DNSServiceFlags             flags,
676*4b22b933Srs200217     uint32_t                    interfaceIndex,
677*4b22b933Srs200217     const char                 *name,
678*4b22b933Srs200217     uint16_t                    rrtype,
679*4b22b933Srs200217     uint16_t                    rrclass,
680*4b22b933Srs200217     DNSServiceQueryRecordReply  callBack,
681*4b22b933Srs200217     void                       *context
682*4b22b933Srs200217     )
683*4b22b933Srs200217     {
684*4b22b933Srs200217     char *msg = NULL, *ptr;
685*4b22b933Srs200217     size_t len;
686*4b22b933Srs200217     ipc_msg_hdr *hdr;
687*4b22b933Srs200217     DNSServiceRef sdr;
688*4b22b933Srs200217     DNSServiceErrorType err;
689*4b22b933Srs200217 
690*4b22b933Srs200217     if (!sdRef) return kDNSServiceErr_BadParam;
691*4b22b933Srs200217     *sdRef = NULL;
692*4b22b933Srs200217 
693*4b22b933Srs200217     if (!name) name = "\0";
694*4b22b933Srs200217 
695*4b22b933Srs200217     // calculate total message length
696*4b22b933Srs200217     len = sizeof(flags);
697*4b22b933Srs200217     len += sizeof(uint32_t);  //interfaceIndex
698*4b22b933Srs200217     len += strlen(name) + 1;
699*4b22b933Srs200217     len += 2 * sizeof(uint16_t);  // rrtype, rrclass
700*4b22b933Srs200217 
701*4b22b933Srs200217     hdr = create_hdr(query_request, &len, &ptr, 1);
702*4b22b933Srs200217     if (!hdr) goto error;
703*4b22b933Srs200217     msg = (void *)hdr;
704*4b22b933Srs200217 
705*4b22b933Srs200217     put_flags(flags, &ptr);
706*4b22b933Srs200217     put_long(interfaceIndex, &ptr);
707*4b22b933Srs200217     put_string(name, &ptr);
708*4b22b933Srs200217     put_short(rrtype, &ptr);
709*4b22b933Srs200217     put_short(rrclass, &ptr);
710*4b22b933Srs200217 
711*4b22b933Srs200217     sdr = connect_to_server();
712*4b22b933Srs200217     if (!sdr) goto error;
713*4b22b933Srs200217     err = deliver_request(msg, sdr, 1);
714*4b22b933Srs200217     if (err)
715*4b22b933Srs200217         {
716*4b22b933Srs200217         DNSServiceRefDeallocate(sdr);
717*4b22b933Srs200217         return err;
718*4b22b933Srs200217         }
719*4b22b933Srs200217 
720*4b22b933Srs200217     sdr->op = query_request;
721*4b22b933Srs200217     sdr->process_reply = handle_query_response;
722*4b22b933Srs200217     sdr->app_callback = callBack;
723*4b22b933Srs200217     sdr->app_context = context;
724*4b22b933Srs200217     *sdRef = sdr;
725*4b22b933Srs200217     return err;
726*4b22b933Srs200217 
727*4b22b933Srs200217 error:
728*4b22b933Srs200217     if (msg) free(msg);
729*4b22b933Srs200217     if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
730*4b22b933Srs200217     return kDNSServiceErr_Unknown;
731*4b22b933Srs200217     }
732*4b22b933Srs200217 
handle_browse_response(DNSServiceRef sdr,ipc_msg_hdr * hdr,char * data)733*4b22b933Srs200217 static void handle_browse_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
734*4b22b933Srs200217     {
735*4b22b933Srs200217     DNSServiceFlags      flags;
736*4b22b933Srs200217     uint32_t                      interfaceIndex;
737*4b22b933Srs200217     DNSServiceErrorType      errorCode;
738*4b22b933Srs200217     char replyName[256], replyType[kDNSServiceMaxDomainName],
739*4b22b933Srs200217         replyDomain[kDNSServiceMaxDomainName];
740*4b22b933Srs200217     int str_error = 0;
741*4b22b933Srs200217 	(void)hdr;//Unused
742*4b22b933Srs200217 
743*4b22b933Srs200217     flags = get_flags(&data);
744*4b22b933Srs200217     interfaceIndex = get_long(&data);
745*4b22b933Srs200217     errorCode = get_error_code(&data);
746*4b22b933Srs200217     if (get_string(&data, replyName, 256) < 0) str_error = 1;
747*4b22b933Srs200217     if (get_string(&data, replyType, kDNSServiceMaxDomainName) < 0) str_error = 1;
748*4b22b933Srs200217     if (get_string(&data, replyDomain, kDNSServiceMaxDomainName) < 0) str_error = 1;
749*4b22b933Srs200217 	if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown;
750*4b22b933Srs200217 	((DNSServiceBrowseReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, replyName, replyType, replyDomain, sdr->app_context);
751*4b22b933Srs200217     }
752*4b22b933Srs200217 
DNSServiceBrowse(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * regtype,const char * domain,DNSServiceBrowseReply callBack,void * context)753*4b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceBrowse
754*4b22b933Srs200217 	(
755*4b22b933Srs200217 	DNSServiceRef         *sdRef,
756*4b22b933Srs200217 	DNSServiceFlags        flags,
757*4b22b933Srs200217 	uint32_t               interfaceIndex,
758*4b22b933Srs200217 	const char            *regtype,
759*4b22b933Srs200217 	const char            *domain,
760*4b22b933Srs200217 	DNSServiceBrowseReply  callBack,
761*4b22b933Srs200217 	void                  *context
762*4b22b933Srs200217 	)
763*4b22b933Srs200217     {
764*4b22b933Srs200217     char *msg = NULL, *ptr;
765*4b22b933Srs200217     size_t len;
766*4b22b933Srs200217     ipc_msg_hdr *hdr;
767*4b22b933Srs200217     DNSServiceRef sdr;
768*4b22b933Srs200217     DNSServiceErrorType err;
769*4b22b933Srs200217 
770*4b22b933Srs200217     if (!sdRef) return kDNSServiceErr_BadParam;
771*4b22b933Srs200217     *sdRef = NULL;
772*4b22b933Srs200217 
773*4b22b933Srs200217     if (!domain) domain = "";
774*4b22b933Srs200217 
775*4b22b933Srs200217     len = sizeof(flags);
776*4b22b933Srs200217     len += sizeof(interfaceIndex);
777*4b22b933Srs200217     len += strlen(regtype) + 1;
778*4b22b933Srs200217     len += strlen(domain) + 1;
779*4b22b933Srs200217 
780*4b22b933Srs200217     hdr = create_hdr(browse_request, &len, &ptr, 1);
781*4b22b933Srs200217     if (!hdr) goto error;
782*4b22b933Srs200217     msg = (char *)hdr;
783*4b22b933Srs200217     put_flags(flags, &ptr);
784*4b22b933Srs200217     put_long(interfaceIndex, &ptr);
785*4b22b933Srs200217     put_string(regtype, &ptr);
786*4b22b933Srs200217     put_string(domain, &ptr);
787*4b22b933Srs200217 
788*4b22b933Srs200217     sdr = connect_to_server();
789*4b22b933Srs200217     if (!sdr) goto error;
790*4b22b933Srs200217     err = deliver_request(msg, sdr, 1);
791*4b22b933Srs200217     if (err)
792*4b22b933Srs200217         {
793*4b22b933Srs200217         DNSServiceRefDeallocate(sdr);
794*4b22b933Srs200217         return err;
795*4b22b933Srs200217         }
796*4b22b933Srs200217     sdr->op = browse_request;
797*4b22b933Srs200217     sdr->process_reply = handle_browse_response;
798*4b22b933Srs200217     sdr->app_callback = callBack;
799*4b22b933Srs200217     sdr->app_context = context;
800*4b22b933Srs200217     *sdRef = sdr;
801*4b22b933Srs200217     return err;
802*4b22b933Srs200217 
803*4b22b933Srs200217 error:
804*4b22b933Srs200217     if (msg) free(msg);
805*4b22b933Srs200217     if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
806*4b22b933Srs200217     return kDNSServiceErr_Unknown;
807*4b22b933Srs200217     }
808*4b22b933Srs200217 
DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags,const char * domain)809*4b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser
810*4b22b933Srs200217 	(
811*4b22b933Srs200217 	DNSServiceFlags  flags,
812*4b22b933Srs200217 	const char      *domain
813*4b22b933Srs200217 	)
814*4b22b933Srs200217     {
815*4b22b933Srs200217     DNSServiceRef sdr;
816*4b22b933Srs200217     DNSServiceErrorType err;
817*4b22b933Srs200217     char *ptr = NULL;
818*4b22b933Srs200217     size_t len = sizeof(flags) + strlen(domain) + 1;
819*4b22b933Srs200217     ipc_msg_hdr *hdr = create_hdr(setdomain_request, &len, &ptr, 1);
820*4b22b933Srs200217 
821*4b22b933Srs200217     if (!hdr) return kDNSServiceErr_Unknown;
822*4b22b933Srs200217     put_flags(flags, &ptr);
823*4b22b933Srs200217     put_string(domain, &ptr);
824*4b22b933Srs200217 
825*4b22b933Srs200217     sdr = connect_to_server();
826*4b22b933Srs200217     if (!sdr) { free(hdr); return kDNSServiceErr_Unknown; }
827*4b22b933Srs200217     err = deliver_request((char *)hdr, sdr, 1); // deliver_request frees the message for us
828*4b22b933Srs200217 	DNSServiceRefDeallocate(sdr);
829*4b22b933Srs200217 	return err;
830*4b22b933Srs200217     }
831*4b22b933Srs200217 
832*4b22b933Srs200217 
handle_regservice_response(DNSServiceRef sdr,ipc_msg_hdr * hdr,char * data)833*4b22b933Srs200217 static void handle_regservice_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
834*4b22b933Srs200217     {
835*4b22b933Srs200217     DNSServiceFlags flags;
836*4b22b933Srs200217     uint32_t interfaceIndex;
837*4b22b933Srs200217     DNSServiceErrorType errorCode;
838*4b22b933Srs200217     char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
839*4b22b933Srs200217     int str_error = 0;
840*4b22b933Srs200217 	(void)hdr;//Unused
841*4b22b933Srs200217 
842*4b22b933Srs200217     flags = get_flags(&data);
843*4b22b933Srs200217     interfaceIndex = get_long(&data);
844*4b22b933Srs200217     errorCode = get_error_code(&data);
845*4b22b933Srs200217     if (get_string(&data, name, 256) < 0) str_error = 1;
846*4b22b933Srs200217     if (get_string(&data, regtype, kDNSServiceMaxDomainName) < 0) str_error = 1;
847*4b22b933Srs200217     if (get_string(&data, domain, kDNSServiceMaxDomainName) < 0) str_error = 1;
848*4b22b933Srs200217 	if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown;
849*4b22b933Srs200217     ((DNSServiceRegisterReply)sdr->app_callback)(sdr, flags, errorCode, name, regtype, domain, sdr->app_context);
850*4b22b933Srs200217     }
851*4b22b933Srs200217 
DNSServiceRegister(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * name,const char * regtype,const char * domain,const char * host,uint16_t PortInNetworkByteOrder,uint16_t txtLen,const void * txtRecord,DNSServiceRegisterReply callBack,void * context)852*4b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceRegister
853*4b22b933Srs200217     (
854*4b22b933Srs200217     DNSServiceRef                       *sdRef,
855*4b22b933Srs200217     DNSServiceFlags                     flags,
856*4b22b933Srs200217     uint32_t                            interfaceIndex,
857*4b22b933Srs200217     const char                          *name,
858*4b22b933Srs200217     const char                          *regtype,
859*4b22b933Srs200217     const char                          *domain,
860*4b22b933Srs200217     const char                          *host,
861*4b22b933Srs200217     uint16_t                            PortInNetworkByteOrder,
862*4b22b933Srs200217     uint16_t                            txtLen,
863*4b22b933Srs200217     const void                          *txtRecord,
864*4b22b933Srs200217     DNSServiceRegisterReply             callBack,
865*4b22b933Srs200217     void                                *context
866*4b22b933Srs200217     )
867*4b22b933Srs200217     {
868*4b22b933Srs200217     char *msg = NULL, *ptr;
869*4b22b933Srs200217     size_t len;
870*4b22b933Srs200217     ipc_msg_hdr *hdr;
871*4b22b933Srs200217     DNSServiceRef sdr;
872*4b22b933Srs200217     DNSServiceErrorType err;
873*4b22b933Srs200217     union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder };
874*4b22b933Srs200217 
875*4b22b933Srs200217     if (!sdRef) return kDNSServiceErr_BadParam;
876*4b22b933Srs200217     *sdRef = NULL;
877*4b22b933Srs200217 
878*4b22b933Srs200217     if (!name) name = "";
879*4b22b933Srs200217     if (!regtype) return kDNSServiceErr_BadParam;
880*4b22b933Srs200217     if (!domain) domain = "";
881*4b22b933Srs200217     if (!host) host = "";
882*4b22b933Srs200217     if (!txtRecord) txtRecord = (void*)"";
883*4b22b933Srs200217 
884*4b22b933Srs200217     // auto-name must also have auto-rename
885*4b22b933Srs200217     if (!name[0]  && (flags & kDNSServiceFlagsNoAutoRename))
886*4b22b933Srs200217         return kDNSServiceErr_BadParam;
887*4b22b933Srs200217 
888*4b22b933Srs200217     // no callback must have auto-rename
889*4b22b933Srs200217     if (!callBack && (flags & kDNSServiceFlagsNoAutoRename)) return kDNSServiceErr_BadParam;
890*4b22b933Srs200217 
891*4b22b933Srs200217     len = sizeof(DNSServiceFlags);
892*4b22b933Srs200217     len += sizeof(uint32_t);  // interfaceIndex
893*4b22b933Srs200217     len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4;
894*4b22b933Srs200217     len += 2 * sizeof(uint16_t);  // port, txtLen
895*4b22b933Srs200217     len += txtLen;
896*4b22b933Srs200217 
897*4b22b933Srs200217     hdr = create_hdr(reg_service_request, &len, &ptr, 1);
898*4b22b933Srs200217     if (!hdr) goto error;
899*4b22b933Srs200217     if (!callBack) hdr->flags |= IPC_FLAGS_NOREPLY;
900*4b22b933Srs200217     msg = (char *)hdr;
901*4b22b933Srs200217     put_flags(flags, &ptr);
902*4b22b933Srs200217     put_long(interfaceIndex, &ptr);
903*4b22b933Srs200217     put_string(name, &ptr);
904*4b22b933Srs200217     put_string(regtype, &ptr);
905*4b22b933Srs200217     put_string(domain, &ptr);
906*4b22b933Srs200217     put_string(host, &ptr);
907*4b22b933Srs200217     *ptr++ = port.b[0];
908*4b22b933Srs200217     *ptr++ = port.b[1];
909*4b22b933Srs200217     put_short(txtLen, &ptr);
910*4b22b933Srs200217     put_rdata(txtLen, txtRecord, &ptr);
911*4b22b933Srs200217 
912*4b22b933Srs200217     sdr = connect_to_server();
913*4b22b933Srs200217     if (!sdr) goto error;
914*4b22b933Srs200217     err = deliver_request(msg, sdr, 1);
915*4b22b933Srs200217     if (err)
916*4b22b933Srs200217         {
917*4b22b933Srs200217         DNSServiceRefDeallocate(sdr);
918*4b22b933Srs200217         return err;
919*4b22b933Srs200217         }
920*4b22b933Srs200217 
921*4b22b933Srs200217     sdr->op = reg_service_request;
922*4b22b933Srs200217     sdr->process_reply = callBack ? handle_regservice_response : NULL;
923*4b22b933Srs200217     sdr->app_callback = callBack;
924*4b22b933Srs200217     sdr->app_context = context;
925*4b22b933Srs200217     *sdRef = sdr;
926*4b22b933Srs200217 
927*4b22b933Srs200217     return err;
928*4b22b933Srs200217 
929*4b22b933Srs200217 error:
930*4b22b933Srs200217     if (msg) free(msg);
931*4b22b933Srs200217     if (*sdRef) 	{ free(*sdRef);  *sdRef = NULL; }
932*4b22b933Srs200217     return kDNSServiceErr_Unknown;
933*4b22b933Srs200217     }
934*4b22b933Srs200217 
handle_enumeration_response(DNSServiceRef sdr,ipc_msg_hdr * hdr,char * data)935*4b22b933Srs200217 static void handle_enumeration_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
936*4b22b933Srs200217     {
937*4b22b933Srs200217     DNSServiceFlags flags;
938*4b22b933Srs200217     uint32_t interfaceIndex;
939*4b22b933Srs200217     DNSServiceErrorType err;
940*4b22b933Srs200217     char domain[kDNSServiceMaxDomainName];
941*4b22b933Srs200217     int str_error = 0;
942*4b22b933Srs200217 	(void)hdr;//Unused
943*4b22b933Srs200217 
944*4b22b933Srs200217     flags = get_flags(&data);
945*4b22b933Srs200217     interfaceIndex = get_long(&data);
946*4b22b933Srs200217     err = get_error_code(&data);
947*4b22b933Srs200217     if (get_string(&data, domain, kDNSServiceMaxDomainName) < 0) str_error = 1;
948*4b22b933Srs200217 	if (!err && str_error) err = kDNSServiceErr_Unknown;
949*4b22b933Srs200217     ((DNSServiceDomainEnumReply)sdr->app_callback)(sdr, flags, interfaceIndex, err, domain, sdr->app_context);
950*4b22b933Srs200217     }
951*4b22b933Srs200217 
DNSServiceEnumerateDomains(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,DNSServiceDomainEnumReply callBack,void * context)952*4b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
953*4b22b933Srs200217 	(
954*4b22b933Srs200217 	DNSServiceRef             *sdRef,
955*4b22b933Srs200217 	DNSServiceFlags            flags,
956*4b22b933Srs200217 	uint32_t                   interfaceIndex,
957*4b22b933Srs200217 	DNSServiceDomainEnumReply  callBack,
958*4b22b933Srs200217 	void                      *context
959*4b22b933Srs200217 	)
960*4b22b933Srs200217     {
961*4b22b933Srs200217     char *msg = NULL, *ptr;
962*4b22b933Srs200217     size_t len;
963*4b22b933Srs200217     ipc_msg_hdr *hdr;
964*4b22b933Srs200217     DNSServiceRef sdr;
965*4b22b933Srs200217     DNSServiceErrorType err;
966*4b22b933Srs200217     int f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0;
967*4b22b933Srs200217     int f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0;
968*4b22b933Srs200217     if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
969*4b22b933Srs200217 
970*4b22b933Srs200217     if (!sdRef) return kDNSServiceErr_BadParam;
971*4b22b933Srs200217     *sdRef = NULL;
972*4b22b933Srs200217 
973*4b22b933Srs200217 	len = sizeof(DNSServiceFlags);
974*4b22b933Srs200217     len += sizeof(uint32_t);
975*4b22b933Srs200217 
976*4b22b933Srs200217     hdr = create_hdr(enumeration_request, &len, &ptr, 1);
977*4b22b933Srs200217     if (!hdr) goto error;
978*4b22b933Srs200217     msg = (void *)hdr;
979*4b22b933Srs200217 
980*4b22b933Srs200217     put_flags(flags, &ptr);
981*4b22b933Srs200217     put_long(interfaceIndex, &ptr);
982*4b22b933Srs200217 
983*4b22b933Srs200217     sdr = connect_to_server();
984*4b22b933Srs200217     if (!sdr) goto error;
985*4b22b933Srs200217     err = deliver_request(msg, sdr, 1);
986*4b22b933Srs200217     if (err)
987*4b22b933Srs200217         {
988*4b22b933Srs200217         DNSServiceRefDeallocate(sdr);
989*4b22b933Srs200217         return err;
990*4b22b933Srs200217         }
991*4b22b933Srs200217 
992*4b22b933Srs200217     sdr->op = enumeration_request;
993*4b22b933Srs200217     sdr->process_reply = handle_enumeration_response;
994*4b22b933Srs200217     sdr->app_callback = callBack;
995*4b22b933Srs200217     sdr->app_context = context;
996*4b22b933Srs200217     *sdRef = sdr;
997*4b22b933Srs200217     return err;
998*4b22b933Srs200217 
999*4b22b933Srs200217 error:
1000*4b22b933Srs200217     if (msg) free(msg);
1001*4b22b933Srs200217     if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
1002*4b22b933Srs200217     return kDNSServiceErr_Unknown;
1003*4b22b933Srs200217     }
1004*4b22b933Srs200217 
handle_regrecord_response(DNSServiceRef sdr,ipc_msg_hdr * hdr,char * data)1005*4b22b933Srs200217 static void handle_regrecord_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
1006*4b22b933Srs200217     {
1007*4b22b933Srs200217     DNSServiceFlags flags;
1008*4b22b933Srs200217     uint32_t interfaceIndex;
1009*4b22b933Srs200217     DNSServiceErrorType errorCode;
1010*4b22b933Srs200217     DNSRecordRef rref = hdr->client_context.context;
1011*4b22b933Srs200217 
1012*4b22b933Srs200217     if (sdr->op != connection)
1013*4b22b933Srs200217         {
1014*4b22b933Srs200217         rref->app_callback(rref->sdr, rref, 0, kDNSServiceErr_Unknown, rref->app_context);
1015*4b22b933Srs200217         return;
1016*4b22b933Srs200217         }
1017*4b22b933Srs200217     flags = get_flags(&data);
1018*4b22b933Srs200217     interfaceIndex = get_long(&data);
1019*4b22b933Srs200217     errorCode = get_error_code(&data);
1020*4b22b933Srs200217 
1021*4b22b933Srs200217     rref->app_callback(rref->sdr, rref, flags, errorCode, rref->app_context);
1022*4b22b933Srs200217     }
1023*4b22b933Srs200217 
DNSServiceCreateConnection(DNSServiceRef * sdRef)1024*4b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef)
1025*4b22b933Srs200217     {
1026*4b22b933Srs200217     if (!sdRef) return kDNSServiceErr_BadParam;
1027*4b22b933Srs200217     *sdRef = connect_to_server();
1028*4b22b933Srs200217     if (!*sdRef)
1029*4b22b933Srs200217             return kDNSServiceErr_Unknown;
1030*4b22b933Srs200217     (*sdRef)->op = connection;
1031*4b22b933Srs200217     (*sdRef)->process_reply = handle_regrecord_response;
1032*4b22b933Srs200217     return 0;
1033*4b22b933Srs200217     }
1034*4b22b933Srs200217 
DNSServiceRegisterRecord(DNSServiceRef sdRef,DNSRecordRef * RecordRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * fullname,uint16_t rrtype,uint16_t rrclass,uint16_t rdlen,const void * rdata,uint32_t ttl,DNSServiceRegisterRecordReply callBack,void * context)1035*4b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
1036*4b22b933Srs200217     (
1037*4b22b933Srs200217     DNSServiceRef                  sdRef,
1038*4b22b933Srs200217     DNSRecordRef                  *RecordRef,
1039*4b22b933Srs200217     DNSServiceFlags                flags,
1040*4b22b933Srs200217     uint32_t                       interfaceIndex,
1041*4b22b933Srs200217     const char                    *fullname,
1042*4b22b933Srs200217     uint16_t                       rrtype,
1043*4b22b933Srs200217     uint16_t                       rrclass,
1044*4b22b933Srs200217     uint16_t                       rdlen,
1045*4b22b933Srs200217     const void                    *rdata,
1046*4b22b933Srs200217     uint32_t                       ttl,
1047*4b22b933Srs200217     DNSServiceRegisterRecordReply  callBack,
1048*4b22b933Srs200217     void                          *context
1049*4b22b933Srs200217     )
1050*4b22b933Srs200217     {
1051*4b22b933Srs200217     char *msg = NULL, *ptr;
1052*4b22b933Srs200217     size_t len;
1053*4b22b933Srs200217     ipc_msg_hdr *hdr = NULL;
1054*4b22b933Srs200217     DNSServiceRef tmp = NULL;
1055*4b22b933Srs200217     DNSRecordRef rref = NULL;
1056*4b22b933Srs200217     int f1 = (flags & kDNSServiceFlagsShared) != 0;
1057*4b22b933Srs200217     int f2 = (flags & kDNSServiceFlagsUnique) != 0;
1058*4b22b933Srs200217     if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
1059*4b22b933Srs200217 
1060*4b22b933Srs200217     if (!sdRef || sdRef->op != connection || sdRef->sockfd < 0)
1061*4b22b933Srs200217         return kDNSServiceErr_BadReference;
1062*4b22b933Srs200217     *RecordRef = NULL;
1063*4b22b933Srs200217 
1064*4b22b933Srs200217 	len = sizeof(DNSServiceFlags);
1065*4b22b933Srs200217     len += 2 * sizeof(uint32_t);  // interfaceIndex, ttl
1066*4b22b933Srs200217     len += 3 * sizeof(uint16_t);  // rrtype, rrclass, rdlen
1067*4b22b933Srs200217     len += strlen(fullname) + 1;
1068*4b22b933Srs200217     len += rdlen;
1069*4b22b933Srs200217 
1070*4b22b933Srs200217     hdr = create_hdr(reg_record_request, &len, &ptr, 0);
1071*4b22b933Srs200217     if (!hdr) goto error;
1072*4b22b933Srs200217     msg = (char *)hdr;
1073*4b22b933Srs200217     put_flags(flags, &ptr);
1074*4b22b933Srs200217     put_long(interfaceIndex, &ptr);
1075*4b22b933Srs200217     put_string(fullname, &ptr);
1076*4b22b933Srs200217     put_short(rrtype, &ptr);
1077*4b22b933Srs200217     put_short(rrclass, &ptr);
1078*4b22b933Srs200217     put_short(rdlen, &ptr);
1079*4b22b933Srs200217     put_rdata(rdlen, rdata, &ptr);
1080*4b22b933Srs200217     put_long(ttl, &ptr);
1081*4b22b933Srs200217 
1082*4b22b933Srs200217     rref = malloc(sizeof(_DNSRecordRef_t));
1083*4b22b933Srs200217     if (!rref) goto error;
1084*4b22b933Srs200217     rref->app_context = context;
1085*4b22b933Srs200217     rref->app_callback = callBack;
1086*4b22b933Srs200217     rref->record_index = sdRef->max_index++;
1087*4b22b933Srs200217     rref->sdr = sdRef;
1088*4b22b933Srs200217     *RecordRef = rref;
1089*4b22b933Srs200217     hdr->client_context.context = rref;
1090*4b22b933Srs200217     hdr->reg_index = rref->record_index;
1091*4b22b933Srs200217 
1092*4b22b933Srs200217     return deliver_request(msg, sdRef, 0);
1093*4b22b933Srs200217 
1094*4b22b933Srs200217 error:
1095*4b22b933Srs200217     if (rref) free(rref);
1096*4b22b933Srs200217     if (tmp) free(tmp);
1097*4b22b933Srs200217     if (hdr) free(hdr);
1098*4b22b933Srs200217     return kDNSServiceErr_Unknown;
1099*4b22b933Srs200217     }
1100*4b22b933Srs200217 
1101*4b22b933Srs200217 //sdRef returned by DNSServiceRegister()
DNSServiceAddRecord(DNSServiceRef sdRef,DNSRecordRef * RecordRef,DNSServiceFlags flags,uint16_t rrtype,uint16_t rdlen,const void * rdata,uint32_t ttl)1102*4b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceAddRecord
1103*4b22b933Srs200217     (
1104*4b22b933Srs200217     DNSServiceRef    sdRef,
1105*4b22b933Srs200217     DNSRecordRef    *RecordRef,
1106*4b22b933Srs200217     DNSServiceFlags  flags,
1107*4b22b933Srs200217     uint16_t         rrtype,
1108*4b22b933Srs200217     uint16_t         rdlen,
1109*4b22b933Srs200217     const void      *rdata,
1110*4b22b933Srs200217     uint32_t         ttl
1111*4b22b933Srs200217     )
1112*4b22b933Srs200217     {
1113*4b22b933Srs200217     ipc_msg_hdr *hdr;
1114*4b22b933Srs200217     size_t len = 0;
1115*4b22b933Srs200217     char *ptr;
1116*4b22b933Srs200217     DNSRecordRef rref;
1117*4b22b933Srs200217 
1118*4b22b933Srs200217     if (!sdRef || (sdRef->op != reg_service_request) || !RecordRef)
1119*4b22b933Srs200217         return kDNSServiceErr_BadReference;
1120*4b22b933Srs200217     *RecordRef = NULL;
1121*4b22b933Srs200217 
1122*4b22b933Srs200217     len += 2 * sizeof(uint16_t);  //rrtype, rdlen
1123*4b22b933Srs200217     len += rdlen;
1124*4b22b933Srs200217     len += sizeof(uint32_t);
1125*4b22b933Srs200217     len += sizeof(DNSServiceFlags);
1126*4b22b933Srs200217 
1127*4b22b933Srs200217     hdr = create_hdr(add_record_request, &len, &ptr, 0);
1128*4b22b933Srs200217     if (!hdr) return kDNSServiceErr_Unknown;
1129*4b22b933Srs200217     put_flags(flags, &ptr);
1130*4b22b933Srs200217     put_short(rrtype, &ptr);
1131*4b22b933Srs200217     put_short(rdlen, &ptr);
1132*4b22b933Srs200217     put_rdata(rdlen, rdata, &ptr);
1133*4b22b933Srs200217     put_long(ttl, &ptr);
1134*4b22b933Srs200217 
1135*4b22b933Srs200217     rref = malloc(sizeof(_DNSRecordRef_t));
1136*4b22b933Srs200217     if (!rref) goto error;
1137*4b22b933Srs200217     rref->app_context = NULL;
1138*4b22b933Srs200217     rref->app_callback = NULL;
1139*4b22b933Srs200217     rref->record_index = sdRef->max_index++;
1140*4b22b933Srs200217     rref->sdr = sdRef;
1141*4b22b933Srs200217     *RecordRef = rref;
1142*4b22b933Srs200217     hdr->client_context.context = rref;
1143*4b22b933Srs200217     hdr->reg_index = rref->record_index;
1144*4b22b933Srs200217     return deliver_request((char *)hdr, sdRef, 0);
1145*4b22b933Srs200217 
1146*4b22b933Srs200217 error:
1147*4b22b933Srs200217     if (hdr) free(hdr);
1148*4b22b933Srs200217     if (rref) free(rref);
1149*4b22b933Srs200217     if (*RecordRef) *RecordRef = NULL;
1150*4b22b933Srs200217     return kDNSServiceErr_Unknown;
1151*4b22b933Srs200217 }
1152*4b22b933Srs200217 
1153*4b22b933Srs200217 //DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
DNSServiceUpdateRecord(DNSServiceRef sdRef,DNSRecordRef RecordRef,DNSServiceFlags flags,uint16_t rdlen,const void * rdata,uint32_t ttl)1154*4b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
1155*4b22b933Srs200217     (
1156*4b22b933Srs200217     DNSServiceRef    sdRef,
1157*4b22b933Srs200217     DNSRecordRef     RecordRef,
1158*4b22b933Srs200217     DNSServiceFlags  flags,
1159*4b22b933Srs200217     uint16_t         rdlen,
1160*4b22b933Srs200217     const void      *rdata,
1161*4b22b933Srs200217     uint32_t         ttl
1162*4b22b933Srs200217     )
1163*4b22b933Srs200217     {
1164*4b22b933Srs200217     ipc_msg_hdr *hdr;
1165*4b22b933Srs200217     size_t len = 0;
1166*4b22b933Srs200217     char *ptr;
1167*4b22b933Srs200217 
1168*4b22b933Srs200217 	if (!sdRef) return kDNSServiceErr_BadReference;
1169*4b22b933Srs200217 
1170*4b22b933Srs200217     len += sizeof(uint16_t);
1171*4b22b933Srs200217     len += rdlen;
1172*4b22b933Srs200217     len += sizeof(uint32_t);
1173*4b22b933Srs200217     len += sizeof(DNSServiceFlags);
1174*4b22b933Srs200217 
1175*4b22b933Srs200217     hdr = create_hdr(update_record_request, &len, &ptr, 0);
1176*4b22b933Srs200217     if (!hdr) return kDNSServiceErr_Unknown;
1177*4b22b933Srs200217     hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX;
1178*4b22b933Srs200217     put_flags(flags, &ptr);
1179*4b22b933Srs200217     put_short(rdlen, &ptr);
1180*4b22b933Srs200217     put_rdata(rdlen, rdata, &ptr);
1181*4b22b933Srs200217     put_long(ttl, &ptr);
1182*4b22b933Srs200217     return deliver_request((char *)hdr, sdRef, 0);
1183*4b22b933Srs200217     }
1184*4b22b933Srs200217 
DNSServiceRemoveRecord(DNSServiceRef sdRef,DNSRecordRef RecordRef,DNSServiceFlags flags)1185*4b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
1186*4b22b933Srs200217 	(
1187*4b22b933Srs200217 	DNSServiceRef    sdRef,
1188*4b22b933Srs200217 	DNSRecordRef     RecordRef,
1189*4b22b933Srs200217 	DNSServiceFlags  flags
1190*4b22b933Srs200217 	)
1191*4b22b933Srs200217     {
1192*4b22b933Srs200217     ipc_msg_hdr *hdr;
1193*4b22b933Srs200217     size_t len = 0;
1194*4b22b933Srs200217     char *ptr;
1195*4b22b933Srs200217     DNSServiceErrorType err;
1196*4b22b933Srs200217 
1197*4b22b933Srs200217     if (!sdRef || !RecordRef || !sdRef->max_index)
1198*4b22b933Srs200217         return kDNSServiceErr_BadReference;
1199*4b22b933Srs200217 
1200*4b22b933Srs200217     len += sizeof(flags);
1201*4b22b933Srs200217     hdr = create_hdr(remove_record_request, &len, &ptr, 0);
1202*4b22b933Srs200217     if (!hdr) return kDNSServiceErr_Unknown;
1203*4b22b933Srs200217     hdr->reg_index = RecordRef->record_index;
1204*4b22b933Srs200217     put_flags(flags, &ptr);
1205*4b22b933Srs200217     err = deliver_request((char *)hdr, sdRef, 0);
1206*4b22b933Srs200217     if (!err) free(RecordRef);
1207*4b22b933Srs200217     return err;
1208*4b22b933Srs200217     }
1209*4b22b933Srs200217 
DNSServiceReconfirmRecord(DNSServiceFlags flags,uint32_t interfaceIndex,const char * fullname,uint16_t rrtype,uint16_t rrclass,uint16_t rdlen,const void * rdata)1210*4b22b933Srs200217 DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
1211*4b22b933Srs200217 	(
1212*4b22b933Srs200217 	DNSServiceFlags  flags,
1213*4b22b933Srs200217 	uint32_t         interfaceIndex,
1214*4b22b933Srs200217 	const char      *fullname,
1215*4b22b933Srs200217 	uint16_t         rrtype,
1216*4b22b933Srs200217 	uint16_t         rrclass,
1217*4b22b933Srs200217 	uint16_t         rdlen,
1218*4b22b933Srs200217 	const void      *rdata
1219*4b22b933Srs200217 	)
1220*4b22b933Srs200217     {
1221*4b22b933Srs200217     char *ptr;
1222*4b22b933Srs200217     size_t len;
1223*4b22b933Srs200217     ipc_msg_hdr *hdr;
1224*4b22b933Srs200217     DNSServiceRef tmp;
1225*4b22b933Srs200217 
1226*4b22b933Srs200217     len = sizeof(DNSServiceFlags);
1227*4b22b933Srs200217     len += sizeof(uint32_t);
1228*4b22b933Srs200217     len += strlen(fullname) + 1;
1229*4b22b933Srs200217     len += 3 * sizeof(uint16_t);
1230*4b22b933Srs200217     len += rdlen;
1231*4b22b933Srs200217     tmp = connect_to_server();
1232*4b22b933Srs200217     if (!tmp) return(kDNSServiceErr_Unknown);
1233*4b22b933Srs200217     hdr = create_hdr(reconfirm_record_request, &len, &ptr, 1);
1234*4b22b933Srs200217     if (!hdr) return(kDNSServiceErr_Unknown);
1235*4b22b933Srs200217 
1236*4b22b933Srs200217     put_flags(flags, &ptr);
1237*4b22b933Srs200217     put_long(interfaceIndex, &ptr);
1238*4b22b933Srs200217     put_string(fullname, &ptr);
1239*4b22b933Srs200217     put_short(rrtype, &ptr);
1240*4b22b933Srs200217     put_short(rrclass, &ptr);
1241*4b22b933Srs200217     put_short(rdlen, &ptr);
1242*4b22b933Srs200217     put_rdata(rdlen, rdata, &ptr);
1243*4b22b933Srs200217 	ConvertHeaderBytes(hdr);
1244*4b22b933Srs200217     write_all(tmp->sockfd, (char *)hdr, (int) len);
1245*4b22b933Srs200217     free(hdr);
1246*4b22b933Srs200217     DNSServiceRefDeallocate(tmp);
1247*4b22b933Srs200217     return(kDNSServiceErr_NoError);
1248*4b22b933Srs200217     }
1249*4b22b933Srs200217 
1250