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