dnssd_clientstub.c revision 4904:cd464a980538
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 $
31Revision 1.53  2006/09/07 04:43:12  herscher
32Fix compile error on Win32 platform by moving inclusion of syslog.h
33
34Revision 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
37Revision 1.51  2006/07/24 23:45:55  cheshire
38<rdar://problem/4605276> DNSServiceReconfirmRecord() should return error code
39
40Revision 1.50  2006/06/28 08:22:27  cheshire
41<rdar://problem/4605264> dnssd_clientstub.c needs to report unlink failures in syslog
42
43Revision 1.49  2006/06/28 07:58:59  cheshire
44Minor textual tidying
45
46Revision 1.48  2005/06/30 18:01:00  shersche
47<rdar://problem/4096913> Clients shouldn't wait ten seconds to connect to mDNSResponder
48
49Revision 1.47  2005/03/31 02:19:56  cheshire
50<rdar://problem/4021486> Fix build warnings
51Reviewed by: Scott Herscher
52
53Revision 1.46  2005/03/21 00:39:31  shersche
54<rdar://problem/4021486> Fix build warnings on Win32 platform
55
56Revision 1.45  2005/02/01 01:25:06  shersche
57Define sleep() to be Sleep() for Windows compatibility
58
59Revision 1.44  2005/01/27 22:57:56  cheshire
60Fix compile errors on gcc4
61
62Revision 1.43  2005/01/27 00:02:29  cheshire
63<rdar://problem/3947461> Handle case where client runs before daemon has finished launching
64
65Revision 1.42  2005/01/11 02:01:02  shersche
66Use dnssd_close() rather than close() for Windows compatibility
67
68Revision 1.41  2004/12/23 17:34:26  ksekar
69<rdar://problem/3931319> Calls leak sockets if mDNSResponder is not running
70
71Revision 1.40  2004/11/23 03:39:47  cheshire
72Let interface name/index mapping capability live directly in JNISupport.c,
73instead of having to call through to the daemon via IPC to get this information.
74
75Revision 1.39  2004/11/12 03:22:00  rpantos
76rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
77
78Revision 1.38  2004/11/02 02:51:23  cheshire
79<rdar://problem/3526342> Remove overly-restrictive flag checks
80
81Revision 1.37  2004/10/14 01:43:35  cheshire
82Fix opaque port passing problem
83
84Revision 1.36  2004/10/06 02:22:19  cheshire
85Changed MacRoman copyright symbol (should have been UTF-8 in any case :-) to ASCII-compatible "(c)"
86
87Revision 1.35  2004/10/01 22:15:55  rpantos
88rdar://problem/3824265: Replace APSL in client lib with BSD license.
89
90Revision 1.34  2004/09/17 22:36:13  cheshire
91Add comment explaining that deliver_request frees the message it sends
92
93Revision 1.33  2004/09/17 01:17:31  ksekar
94Remove double-free of msg header, freed automatically by deliver_request()
95
96Revision 1.32  2004/09/17 01:08:55  cheshire
97Renamed 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
102Revision 1.31  2004/09/16 23:37:19  cheshire
103Free hdr before returning
104
105Revision 1.30  2004/09/16 23:14:24  cheshire
106Changes for Windows compatibility
107
108Revision 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
111Revision 1.28  2004/08/11 17:10:04  cheshire
112Fix signed/unsigned warnings
113
114Revision 1.27  2004/08/11 00:54:16  cheshire
115Change "hdr->op.request_op" to just "hdr->op"
116
117Revision 1.26  2004/07/26 06:07:27  shersche
118fix bugs when using an error socket to communicate with the daemon
119
120Revision 1.25  2004/07/26 05:54:02  shersche
121DNSServiceProcessResult() returns NoError if socket read returns EWOULDBLOCK
122
123Revision 1.24  2004/07/20 06:46:21  shersche
124<rdar://problem/3730123> fix endless loop in read_all() if recv returns 0
125Bug #: 3730123
126
127Revision 1.23  2004/06/29 00:48:38  cheshire
128Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
129use an explicit while() loop instead.
130
131Revision 1.22  2004/06/26 03:16:34  shersche
132clean up warning messages on Win32 platform
133
134Submitted by: herscher
135
136Revision 1.21  2004/06/18 04:53:56  rpantos
137Use platform layer for socket types. Introduce USE_TCP_LOOPBACK. Remove dependency on mDNSEmbeddedAPI.h.
138
139Revision 1.20  2004/06/12 00:50:22  cheshire
140Changes for Windows compatibility
141
142Revision 1.19  2004/05/25 18:29:33  cheshire
143Move DNSServiceConstructFullName() from dnssd_clientstub.c to dnssd_clientlib.c,
144so that it's also accessible to dnssd_clientshim.c (single address space) clients.
145
146Revision 1.18  2004/05/18 23:51:27  cheshire
147Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
148
149Revision 1.17  2004/05/06 18:42:58  ksekar
150General 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
154Revision 1.16  2004/03/12 22:00:37  cheshire
155Added: #include <sys/socket.h>
156
157Revision 1.15  2004/01/20 18:36:29  ksekar
158Propagated Libinfo fix for <rdar://problem/3483971>: SU:
159DNSServiceUpdateRecord() doesn't allow you to update the TXT record
160into TOT mDNSResponder.
161
162Revision 1.14  2004/01/19 22:39:17  cheshire
163Don't use "MSG_WAITALL"; it makes send() return "Invalid argument" on Linux;
164use an explicit while() loop instead. (In any case, this should only make a difference
165with non-blocking sockets, which we don't use on the client side right now.)
166
167Revision 1.13  2004/01/19 21:46:52  cheshire
168Fix compiler warning
169
170Revision 1.12  2003/12/23 20:46:47  ksekar
171<rdar://problem/3497428>: sync dnssd files between libinfo & mDNSResponder
172
173Revision 1.11  2003/12/08 21:11:42  rpantos
174Changes necessary to support mDNSResponder on Linux.
175
176Revision 1.10  2003/10/13 23:50:53  ksekar
177Updated dns_sd clientstub files to bring copies in synch with
178top-of-tree Libinfo:  A memory leak in dnssd_clientstub.c is fixed,
179and comments in dns_sd.h are improved.
180
181Revision 1.9  2003/08/15 21:30:39  cheshire
182Bring up to date with LibInfo version
183
184Revision 1.8  2003/08/13 23:54:52  ksekar
185Bringing dnssd_clientstub.c up to date with Libinfo, per radar 3376640
186
187Revision 1.7  2003/08/12 19:56:25  cheshire
188Update 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
213extern BOOL IsSystemServiceDisabled();
214
215#define sleep(X) Sleep((X) * 1000)
216
217static 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
240typedef 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
250typedef 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
262static 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
277static 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
305static 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)
353static 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
416static 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
494cleanup:
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
510int 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.
518DNSServiceErrorType 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
549void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef)
550    {
551    if (!sdRef) return;
552    if (sdRef->sockfd > 0) dnssd_close(sdRef->sockfd);
553    free(sdRef);
554    }
555
556static 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
583DNSServiceErrorType 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
639error:
640    if (msg) free(msg);
641    if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
642    return kDNSServiceErr_Unknown;
643    }
644
645static 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
672DNSServiceErrorType 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
727error:
728    if (msg) free(msg);
729    if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
730    return kDNSServiceErr_Unknown;
731    }
732
733static 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
753DNSServiceErrorType 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
803error:
804    if (msg) free(msg);
805    if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
806    return kDNSServiceErr_Unknown;
807    }
808
809DNSServiceErrorType 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
833static 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
852DNSServiceErrorType 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
929error:
930    if (msg) free(msg);
931    if (*sdRef) 	{ free(*sdRef);  *sdRef = NULL; }
932    return kDNSServiceErr_Unknown;
933    }
934
935static 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
952DNSServiceErrorType 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
999error:
1000    if (msg) free(msg);
1001    if (*sdRef) { free(*sdRef);  *sdRef = NULL; }
1002    return kDNSServiceErr_Unknown;
1003    }
1004
1005static 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
1024DNSServiceErrorType 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
1035DNSServiceErrorType 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
1094error:
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()
1102DNSServiceErrorType 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
1146error:
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
1154DNSServiceErrorType 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
1185DNSServiceErrorType 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
1210DNSServiceErrorType 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