-/*
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+/* -*- Mode: C; tab-width: 4 -*-
*
- * @APPLE_LICENSE_HEADER_START@
- *
- * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
+ * Copyright (c) 2003-2004, Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Change History (most recent first):
+
+$Log: dnssd_clientstub.c,v $
+Revision 1.20.70.3 2006/05/02 16:17:04 majka
+Make NumTries unsigned.
+
+Revision 1.20.70.2 2006/05/01 21:43:09 majka
+Additional change (make NumTries static) for 4527193
+SUChardLondon Libinfo-222.4.6
+
+Revision 1.20.70.1 2006/05/01 16:10:54 majka
+Libinfo-222_4_5 is equivalent to Chardonnay Libinfo-222.0.5
+
+Revision 1.20.60.1 2006/04/27 21:33:30 majka
+Integrated 4527193
+
+Revision 1.20 2005/02/03 00:39:05 majka
+Integrated 3942900
+
+Revision 1.19.4.1 2005/02/02 00:47:40 ksekar
+<rdar://problem/3942900> dnd-sd shows the wrong port numbers
+
+Revision 1.19 2004/12/23 23:10:59 majka
+*** empty log message ***
+
+Revision 1.18.8.1 2004/12/23 17:32:56 ksekar
+<rdar://problem/3931319> Rendevzous calls leak sockets if mDNSResponder is not running
+
+Revision 1.18 2004/12/14 18:02:00 majka
+*** empty log message ***
+
+Revision 1.17.36.1 2004/12/13 17:22:39 ksekar
+<rdar://problem/3656389> Deprecate the DNSServiceDiscovery.h API in Tiger
+<rdar://problem/3873869> Add kDNSServiceInterfaceForceMulticast to header
+<rdar://problem/3526342> Remove overly-restrictive flag checks
+
+Revision 1.17 2004/09/22 20:05:38 majka
+Integrated
+3725573 - Need Error Codes for handling Lighthouse setup failure on NAT
+3805822 - Socket-based APIs aren't endian-safe
+3806739 - DNSServiceSetDefaultDomainForUser header comments incorrect
+
+Revision 1.16.2.1 2004/09/20 21:54:33 ksekar
+<rdar://problem/3805822> Socket-based APIs aren't endian-safe
+
+Revision 1.16 2004/09/17 20:19:00 majka
+Integrated 3804522
+
+Revision 1.15.2.1 2004/09/17 20:15:30 ksekar
+*** empty log message ***
+
+Revision 1.15 2004/09/16 23:45:24 majka
+Integrated 3775315 and 3765280.
+
+Revision 1.14.4.1 2004/09/02 19:43:41 ksekar
+<rdar://problem/3775315>: Sync dns-sd client files between Libinfo and
+mDNSResponder projects
+
+Revision 1.28 2004/08/11 17:10:04 cheshire
+Fix signed/unsigned warnings
+
+Revision 1.27 2004/08/11 00:54:16 cheshire
+Change "hdr->op.request_op" to just "hdr->op"
+
+Revision 1.26 2004/07/26 06:07:27 shersche
+fix bugs when using an error socket to communicate with the daemon
+
+Revision 1.25 2004/07/26 05:54:02 shersche
+DNSServiceProcessResult() returns NoError if socket read returns EWOULDBLOCK
+
+Revision 1.24 2004/07/20 06:46:21 shersche
+<rdar://problem/3730123> fix endless loop in my_read() if recv returns 0
+Bug #: 3730123
+
+Revision 1.23 2004/06/29 00:48:38 cheshire
+Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
+use an explicit while() loop instead.
+
+Revision 1.22 2004/06/26 03:16:34 shersche
+clean up warning messages on Win32 platform
+
+Submitted by: herscher
+
+Revision 1.21 2004/06/18 04:53:56 rpantos
+Use platform layer for socket types. Introduce USE_TCP_LOOPBACK. Remove dependency on mDNSClientAPI.h.
+
+Revision 1.20 2004/06/12 00:50:22 cheshire
+Changes for Windows compatibility
+
+Revision 1.19 2004/05/25 18:29:33 cheshire
+Move DNSServiceConstructFullName() from dnssd_clientstub.c to dnssd_clientlib.c,
+so that it's also accessible to dnssd_clientshim.c (single address space) clients.
+
+Revision 1.18 2004/05/18 23:51:27 cheshire
+Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
+
+Revision 1.17 2004/05/06 18:42:58 ksekar
+General dns_sd.h API cleanup, including the following radars:
+<rdar://problem/3592068>: Remove flags with zero value
+<rdar://problem/3479569>: Passing in NULL causes a crash.
+
+Revision 1.16 2004/03/12 22:00:37 cheshire
+Added: #include <sys/socket.h>
+
+Revision 1.15 2004/01/20 18:36:29 ksekar
+Propagated Libinfo fix for <rdar://problem/3483971>: SU:
+DNSServiceUpdateRecord() doesn't allow you to update the TXT record
+into TOT mDNSResponder.
+
+Revision 1.14 2004/01/19 22:39:17 cheshire
+Don't use "MSG_WAITALL"; it makes send() return "Invalid argument" on Linux;
+use an explicit while() loop instead. (In any case, this should only make a difference
+with non-blocking sockets, which we don't use on the client side right now.)
+
+Revision 1.13 2004/01/19 21:46:52 cheshire
+Fix compiler warning
+
+Revision 1.12 2003/12/23 20:46:47 ksekar
+<rdar://problem/3497428>: sync dnssd files between libinfo & mDNSResponder
+
+Revision 1.11 2003/12/08 21:11:42 rpantos
+Changes necessary to support mDNSResponder on Linux.
+
+Revision 1.10 2003/10/13 23:50:53 ksekar
+Updated dns_sd clientstub files to bring copies in synch with
+top-of-tree Libinfo: A memory leak in dnssd_clientstub.c is fixed,
+and comments in dns_sd.h are improved.
+
+Revision 1.9 2003/08/15 21:30:39 cheshire
+Bring up to date with LibInfo version
+
+Revision 1.8 2003/08/13 23:54:52 ksekar
+Bringing dnssd_clientstub.c up to date with Libinfo, per radar 3376640
+
+Revision 1.7 2003/08/12 19:56:25 cheshire
+Update to APSL 2.0
+
*/
-#include "dnssd_ipc.h"
#include <errno.h>
+#include <stdlib.h>
+#if defined(_WIN32)
+#include <winsock2.h>
+#include <windows.h>
+#define sockaddr_mdns sockaddr_in
+#define AF_MDNS AF_INET
+#else
#include <sys/time.h>
+#include <sys/socket.h>
+#define sockaddr_mdns sockaddr_un
+#define AF_MDNS AF_LOCAL
+#endif
+
+#include "dnssd_ipc.h"
+
+#if defined(_WIN32)
+// disable warning: "'type cast' : from data pointer 'void *' to
+// function pointer"
+#pragma warning(disable:4055)
+// disable warning: "nonstandard extension, function/data pointer
+// conversion in expression"
+#pragma warning(disable:4152)
+
+#define sleep(X) Sleep((X) * 1000)
+
+static int g_initWinsock = 0;
+#endif
#define CTL_PATH_PREFIX "/tmp/dnssd_clippath."
// last 3 digits of the time (in seconds) and n is the 6-digit microsecond time
// general utility functions
-static DNSServiceRef connect_to_server(void);
-DNSServiceErrorType deliver_request(void *msg, DNSServiceRef sdr, int reuse_sd);
-static ipc_msg_hdr *create_hdr(int op, int *len, char **data_start, int reuse_socket);
-static int my_read(int sd, char *buf, int len);
-static int my_write(int sd, char *buf, int len);
-static int domain_ends_in_dot(const char *dom);
-// server response handlers
-static void handle_query_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *msg);
-static void handle_browse_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data);
-static void handle_regservice_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data);
-static void handle_regrecord_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data);
-static void handle_enumeration_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data);
-static void handle_resolve_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data);
-
typedef struct _DNSServiceRef_t
{
- int sockfd; // connected socket between client and daemon
- int op; // request/reply_op_t
+ dnssd_sock_t sockfd; // connected socket between client and daemon
+ uint32_t op; // request_op_t or reply_op_t
process_reply_callback process_reply;
void *app_callback;
void *app_context;
uint32_t max_index; //largest assigned record index - 0 if no additl. recs registered
- } _DNSServiceRef_t;
+ } _DNSServiceRef_t;
typedef struct _DNSRecordRef_t
{
void *app_context;
DNSServiceRegisterRecordReply app_callback;
DNSRecordRef recref;
- int record_index; // index is unique to the ServiceDiscoveryRef
+ uint32_t record_index; // index is unique to the ServiceDiscoveryRef
DNSServiceRef sdr;
} _DNSRecordRef_t;
-
// exported functions
-int DNSServiceRefSockFD(DNSServiceRef sdRef)
+// write len bytes. return 0 on success, -1 on error
+static int my_write(dnssd_sock_t sd, char *buf, int len)
+ {
+ // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
+ //if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
+ while (len)
+ {
+ ssize_t num_written = send(sd, buf, len, 0);
+ if (num_written < 0 || num_written > len) return -1;
+ buf += num_written;
+ len -= num_written;
+ }
+ return 0;
+ }
+
+// read len bytes. return 0 on success, -1 on error
+static int my_read(dnssd_sock_t sd, char *buf, int len)
+ {
+ // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
+ //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1;
+ while (len)
+ {
+ ssize_t num_read = recv(sd, buf, len, 0);
+ if ((num_read == 0) || (num_read < 0) || (num_read > len)) return -1;
+ buf += num_read;
+ len -= num_read;
+ }
+ return 0;
+ }
+
+/* create_hdr
+ *
+ * allocate and initialize an ipc message header. value of len should initially be the
+ * length of the data, and is set to the value of the data plus the header. data_start
+ * is set to point to the beginning of the data section. reuse_socket should be non-zero
+ * for calls that can receive an immediate error return value on their primary socket.
+ * if zero, the path to a control socket is appended at the beginning of the message buffer.
+ * data_start is set past this string.
+ */
+
+static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int reuse_socket)
+ {
+ char *msg = NULL;
+ ipc_msg_hdr *hdr;
+ int datalen;
+ char ctrl_path[256];
+
+ if (!reuse_socket)
+ {
+#if defined(USE_TCP_LOOPBACK)
+ *len += 2; // Allocate space for two-byte port number
+#else
+ struct timeval time;
+ if (gettimeofday(&time, NULL) < 0) return NULL;
+ sprintf(ctrl_path, "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(),
+ (unsigned long)(time.tv_sec & 0xFFF), (unsigned long)(time.tv_usec));
+ *len += strlen(ctrl_path) + 1;
+#endif
+ }
+
+ datalen = (int) *len;
+ *len += sizeof(ipc_msg_hdr);
+
+ // write message to buffer
+ msg = malloc(*len);
+ if (!msg) return NULL;
+
+ bzero(msg, *len);
+ hdr = (void *)msg;
+ hdr->datalen = datalen;
+ hdr->version = VERSION;
+ hdr->op = op;
+ if (reuse_socket) hdr->flags |= IPC_FLAGS_REUSE_SOCKET;
+ *data_start = msg + sizeof(ipc_msg_hdr);
+#if defined(USE_TCP_LOOPBACK)
+ // Put dummy data in for the port, since we don't know what
+ // it is yet. The data will get filled in before we
+ // send the message. This happens in deliver_request().
+ if (!reuse_socket) put_short(0, data_start);
+#else
+ if (!reuse_socket) put_string(ctrl_path, data_start);
+#endif
+ return hdr;
+ }
+
+ // return a connected service ref (deallocate with DNSServiceRefDeallocate)
+static DNSServiceRef connect_to_server(void)
+ {
+ dnssd_sockaddr_t saddr;
+ DNSServiceRef sdr;
+ static unsigned int NumTries = 0;
+
+#if defined(_WIN32)
+ if (!g_initWinsock)
+ {
+ WSADATA wsaData;
+ DNSServiceErrorType err;
+
+ g_initWinsock = 1;
+
+ err = WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
+
+ if (err != 0) return NULL;
+ }
+#endif
+
+ sdr = malloc(sizeof(_DNSServiceRef_t));
+ if (!sdr) return(NULL);
+ sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0);
+ if (sdr->sockfd == dnssd_InvalidSocket) { free(sdr); return NULL; }
+#if defined(USE_TCP_LOOPBACK)
+ saddr.sin_family = AF_INET;
+ saddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
+ saddr.sin_port = htons(MDNS_TCP_SERVERPORT);
+#else
+ saddr.sun_family = AF_LOCAL;
+ strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH);
+#endif
+ while (1)
+ {
+ int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
+ if (!err) break; // If we succeeded, return sdr
+ // If we failed, then it may be because the daemon is still launching.
+ // This can happen for processes that launch early in the boot process, while the
+ // daemon is still coming up. Rather than fail here, we'll wait a bit and try again.
+ // If, after ten seconds, we still can't connect to the daemon,
+ // then we give up and return a failure code.
+ if (++NumTries < 3)
+ sleep(1); // Sleep a bit, then try again
+ else
+ {
+ dnssd_close(sdr->sockfd);
+ sdr->sockfd = dnssd_InvalidSocket;
+ free(sdr);
+ return NULL;
+ }
+ }
+ return sdr;
+ }
+
+static DNSServiceErrorType deliver_request(void *msg, DNSServiceRef sdr, int reuse_sd)
+ {
+ ipc_msg_hdr *hdr = msg;
+ uint32_t datalen = hdr->datalen;
+ dnssd_sockaddr_t caddr, daddr; // (client and daemon address structs)
+ char *data = (char *)msg + sizeof(ipc_msg_hdr);
+ dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
+ int ret;
+ unsigned int len = sizeof(caddr);
+ DNSServiceErrorType err = kDNSServiceErr_Unknown;
+
+ if (!hdr || sdr->sockfd < 0) return kDNSServiceErr_Unknown;
+
+ if (!reuse_sd)
+ {
+ // setup temporary error socket
+ if ((listenfd = socket(AF_DNSSD, SOCK_STREAM, 0)) < 0)
+ goto cleanup;
+ bzero(&caddr, sizeof(caddr));
+
+#if defined(USE_TCP_LOOPBACK)
+ {
+ union { uint16_t s; u_char b[2]; } port;
+ caddr.sin_family = AF_INET;
+ caddr.sin_port = 0;
+ caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
+ ret = bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr));
+ if (ret < 0) goto cleanup;
+ if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) goto cleanup;
+ listen(listenfd, 1);
+ port.s = caddr.sin_port;
+ data[0] = port.b[0]; // don't switch the byte order, as the
+ data[1] = port.b[1]; // daemon expects it in network byte order
+ }
+#else
+ {
+ mode_t mask = umask(0);
+ caddr.sun_family = AF_LOCAL;
+#ifndef NOT_HAVE_SA_LEN // According to Stevens (section 3.2), there is no portable way to
+ // determine whether sa_len is defined on a particular platform.
+ caddr.sun_len = sizeof(struct sockaddr_un);
+#endif
+ strcpy(caddr.sun_path, data);
+ ret = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr));
+ umask(mask);
+ if (ret < 0) goto cleanup;
+ listen(listenfd, 1);
+ }
+#endif
+ }
+
+ ConvertHeaderBytes(hdr);
+ if (my_write(sdr->sockfd, msg, datalen + sizeof(ipc_msg_hdr)) < 0)
+ goto cleanup;
+ free(msg);
+ msg = NULL;
+
+ if (reuse_sd) errsd = sdr->sockfd;
+ else
+ {
+ len = sizeof(daddr);
+ errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
+ if (errsd < 0) goto cleanup;
+ }
+
+ if (my_read(errsd, (char*)&err, (int)sizeof(err)) < 0)
+ err = kDNSServiceErr_Unknown;
+ else
+ err = ntohl(err);
+
+cleanup:
+ if (!reuse_sd && listenfd > 0) dnssd_close(listenfd);
+ if (!reuse_sd && errsd > 0) dnssd_close(errsd);
+#if !defined(USE_TCP_LOOPBACK)
+ if (!reuse_sd && data) unlink(data);
+#endif
+ if (msg) free(msg);
+ return err;
+ }
+
+int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef)
{
if (!sdRef) return -1;
- return sdRef->sockfd;
+ return (int) sdRef->sockfd;
}
// handle reply from server, calling application client callback. If there is no reply
// from the daemon on the socket contained in sdRef, the call will block.
-DNSServiceErrorType DNSServiceProcessResult(DNSServiceRef sdRef)
+DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
{
ipc_msg_hdr hdr;
char *data;
- if (!sdRef || sdRef->sockfd < 0 || !sdRef->process_reply)
+ if (!sdRef || sdRef->sockfd < 0 || !sdRef->process_reply)
return kDNSServiceErr_BadReference;
- if (my_read(sdRef->sockfd, (void *)&hdr, sizeof(hdr)) < 0)
- return kDNSServiceErr_Unknown;
+ if (my_read(sdRef->sockfd, (void *)&hdr, sizeof(hdr)) < 0)
+ // return NoError on EWOULDBLOCK. This will handle the case
+ // where a non-blocking socket is told there is data, but
+ // it was a false positive.
+ return (dnssd_errno() == dnssd_EWOULDBLOCK) ? kDNSServiceErr_NoError : kDNSServiceErr_Unknown;
+ ConvertHeaderBytes(&hdr);
if (hdr.version != VERSION)
return kDNSServiceErr_Incompatible;
data = malloc(hdr.datalen);
if (!data) return kDNSServiceErr_NoMemory;
- if (my_read(sdRef->sockfd, data, hdr.datalen) < 0)
+ if (my_read(sdRef->sockfd, data, hdr.datalen) < 0)
return kDNSServiceErr_Unknown;
sdRef->process_reply(sdRef, &hdr, data);
free(data);
return kDNSServiceErr_NoError;
}
-
-void DNSServiceRefDeallocate(DNSServiceRef sdRef)
+void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef)
{
if (!sdRef) return;
- if (sdRef->sockfd > 0) close(sdRef->sockfd);
+ if (sdRef->sockfd > 0) dnssd_close(sdRef->sockfd);
free(sdRef);
}
+static void handle_resolve_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
+ {
+ DNSServiceFlags flags;
+ char fullname[kDNSServiceMaxDomainName];
+ char target[kDNSServiceMaxDomainName];
+ uint16_t txtlen;
+ union { uint16_t s; u_char b[2]; } port;
+ uint32_t ifi;
+ DNSServiceErrorType err;
+ char *txtrecord;
+ int str_error = 0;
+ (void)hdr; //unused
+
+ flags = get_flags(&data);
+ ifi = get_long(&data);
+ err = get_error_code(&data);
+ if (get_string(&data, fullname, kDNSServiceMaxDomainName) < 0) str_error = 1;
+ if (get_string(&data, target, kDNSServiceMaxDomainName) < 0) str_error = 1;
+ port.b[0] = *data++;
+ port.b[1] = *data++;
+ txtlen = get_short(&data);
+ txtrecord = get_rdata(&data, txtlen);
+
+ if (!err && str_error) err = kDNSServiceErr_Unknown;
+ ((DNSServiceResolveReply)sdr->app_callback)(sdr, flags, ifi, err, fullname, target, port.s, txtlen, txtrecord, sdr->app_context);
+ }
-DNSServiceErrorType DNSServiceResolve
+DNSServiceErrorType DNSSD_API DNSServiceResolve
(
DNSServiceRef *sdRef,
- const DNSServiceFlags flags,
- const uint32_t interfaceIndex,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
const char *name,
const char *regtype,
const char *domain,
- const DNSServiceResolveReply callBack,
+ DNSServiceResolveReply callBack,
void *context
)
{
char *msg = NULL, *ptr;
- int len;
+ size_t len;
ipc_msg_hdr *hdr;
DNSServiceRef sdr;
DNSServiceErrorType err;
-
+
if (!sdRef) return kDNSServiceErr_BadParam;
*sdRef = NULL;
-
+
+ if (!name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam;
+
// calculate total message length
len = sizeof(flags);
len += sizeof(interfaceIndex);
put_string(name, &ptr);
put_string(regtype, &ptr);
put_string(domain, &ptr);
-
+
sdr = connect_to_server();
if (!sdr) goto error;
err = deliver_request(msg, sdr, 1);
sdr->app_callback = callBack;
sdr->app_context = context;
*sdRef = sdr;
-
+
return err;
error:
if (*sdRef) { free(*sdRef); *sdRef = NULL; }
return kDNSServiceErr_Unknown;
}
-
-
-static void handle_resolve_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
+
+static void handle_query_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
{
DNSServiceFlags flags;
- char fullname[kDNSServiceMaxDomainName];
- char target[kDNSServiceMaxDomainName];
- uint16_t port, txtlen;
- uint32_t ifi;
- DNSServiceErrorType err;
- char *txtrecord;
-
- (void)hdr; //unused
-
+ uint32_t interfaceIndex, ttl;
+ DNSServiceErrorType errorCode;
+ char name[kDNSServiceMaxDomainName];
+ uint16_t rrtype, rrclass, rdlen;
+ char *rdata;
+ int str_error = 0;
+ (void)hdr;//Unused
+
flags = get_flags(&data);
- ifi = get_long(&data);
- err = get_error_code(&data);
- get_string(&data, fullname, kDNSServiceMaxDomainName);
- get_string(&data, target, kDNSServiceMaxDomainName);
- port = get_short(&data);
- txtlen = get_short(&data);
- txtrecord = get_rdata(&data, txtlen);
-
- ((DNSServiceResolveReply)sdr->app_callback)(sdr, flags, ifi, err, fullname, target, port, txtlen, txtrecord, sdr->app_context);
- }
-
-
+ interfaceIndex = get_long(&data);
+ errorCode = get_error_code(&data);
+ if (get_string(&data, name, kDNSServiceMaxDomainName) < 0) str_error = 1;
+ rrtype = get_short(&data);
+ rrclass = get_short(&data);
+ rdlen = get_short(&data);
+ rdata = get_rdata(&data, rdlen);
+ ttl = get_long(&data);
+ if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown;
+ ((DNSServiceQueryRecordReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, name, rrtype, rrclass,
+ rdlen, rdata, ttl, sdr->app_context);
+ return;
+ }
-DNSServiceErrorType DNSServiceQueryRecord
+DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
(
DNSServiceRef *sdRef,
- const DNSServiceFlags flags,
- const uint32_t interfaceIndex,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
const char *name,
- const uint16_t rrtype,
- const uint16_t rrclass,
- const DNSServiceQueryRecordReply callBack,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ DNSServiceQueryRecordReply callBack,
void *context
)
{
char *msg = NULL, *ptr;
- int len;
+ size_t len;
ipc_msg_hdr *hdr;
DNSServiceRef sdr;
DNSServiceErrorType err;
-
+
if (!sdRef) return kDNSServiceErr_BadParam;
*sdRef = NULL;
return kDNSServiceErr_Unknown;
}
-
-static void handle_query_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
+static void handle_browse_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
{
- DNSServiceFlags flags;
- uint32_t interfaceIndex, ttl;
- DNSServiceErrorType errorCode;
- char name[256];
- uint16_t rrtype, rrclass, rdlen;
- char *rdata;
- (void)hdr;//Unused
+ DNSServiceFlags flags;
+ uint32_t interfaceIndex;
+ DNSServiceErrorType errorCode;
+ char replyName[256], replyType[kDNSServiceMaxDomainName],
+ replyDomain[kDNSServiceMaxDomainName];
+ int str_error = 0;
+ (void)hdr;//Unused
flags = get_flags(&data);
interfaceIndex = get_long(&data);
errorCode = get_error_code(&data);
- (get_string(&data, name, 256) < 0);
- rrtype = get_short(&data);
- rrclass = get_short(&data);
- rdlen = get_short(&data);
- rdata = get_rdata(&data, rdlen);
- ttl = get_long(&data);
- if (!rdata) return;
- ((DNSServiceQueryRecordReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, name, rrtype, rrclass,
- rdlen, rdata, ttl, sdr->app_context);
- return;
+ if (get_string(&data, replyName, 256) < 0) str_error = 1;
+ if (get_string(&data, replyType, kDNSServiceMaxDomainName) < 0) str_error = 1;
+ if (get_string(&data, replyDomain, kDNSServiceMaxDomainName) < 0) str_error = 1;
+ if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown;
+ ((DNSServiceBrowseReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, replyName, replyType, replyDomain, sdr->app_context);
}
-DNSServiceErrorType DNSServiceBrowse
+DNSServiceErrorType DNSSD_API DNSServiceBrowse
(
DNSServiceRef *sdRef,
- const DNSServiceFlags flags,
- const uint32_t interfaceIndex,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
const char *regtype,
const char *domain,
- const DNSServiceBrowseReply callBack,
+ DNSServiceBrowseReply callBack,
void *context
)
{
char *msg = NULL, *ptr;
- int len;
+ size_t len;
ipc_msg_hdr *hdr;
DNSServiceRef sdr;
DNSServiceErrorType err;
return kDNSServiceErr_Unknown;
}
+DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser
+(
+ DNSServiceFlags flags,
+ const char *domain
+ )
+ {
+ DNSServiceRef sdr;
+ DNSServiceErrorType err;
+ char *ptr = NULL;
+ size_t len = sizeof(flags) + strlen(domain) + 1;
+ ipc_msg_hdr *hdr = create_hdr(setdomain_request, &len, &ptr, 1);
+
+ if (!hdr) return kDNSServiceErr_Unknown;
+ put_flags(flags, &ptr);
+ put_string(domain, &ptr);
+ sdr = connect_to_server();
+ if (!sdr) { free(hdr); return kDNSServiceErr_Unknown; }
+ err = deliver_request((char *)hdr, sdr, 1); // deliver_request frees the message for us
+ DNSServiceRefDeallocate(sdr);
+ return err;
+ }
-static void handle_browse_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
+static void handle_regservice_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
{
- DNSServiceFlags flags;
- uint32_t interfaceIndex;
- DNSServiceErrorType errorCode;
- char replyName[256], replyType[256], replyDomain[256];
+ DNSServiceFlags flags;
+ uint32_t interfaceIndex;
+ DNSServiceErrorType errorCode;
+ char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
+ int str_error = 0;
(void)hdr;//Unused
flags = get_flags(&data);
interfaceIndex = get_long(&data);
errorCode = get_error_code(&data);
- get_string(&data, replyName, 256);
- get_string(&data, replyType, 256);
- get_string(&data, replyDomain, 256);
- ((DNSServiceBrowseReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, replyName, replyType, replyDomain, sdr->app_context);
+ if (get_string(&data, name, 256) < 0) str_error = 1;
+ if (get_string(&data, regtype, kDNSServiceMaxDomainName) < 0) str_error = 1;
+ if (get_string(&data, domain, kDNSServiceMaxDomainName) < 0) str_error = 1;
+ if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown;
+ ((DNSServiceRegisterReply)sdr->app_callback)(sdr, flags, errorCode, name, regtype, domain, sdr->app_context);
}
-
-DNSServiceErrorType DNSServiceRegister
+DNSServiceErrorType DNSSD_API DNSServiceRegister
(
DNSServiceRef *sdRef,
- const DNSServiceFlags flags,
- const uint32_t interfaceIndex,
- const char *name,
- const char *regtype,
- const char *domain,
- const char *host,
- const uint16_t port,
- const uint16_t txtLen,
- const void *txtRecord,
- const DNSServiceRegisterReply callBack,
- void *context
+ 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
)
{
char *msg = NULL, *ptr;
- int len;
+ size_t len;
ipc_msg_hdr *hdr;
DNSServiceRef sdr;
DNSServiceErrorType err;
+ union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder };
if (!sdRef) return kDNSServiceErr_BadParam;
*sdRef = NULL;
if (!regtype) return kDNSServiceErr_BadParam;
if (!domain) domain = "";
if (!host) host = "";
- if (!txtRecord) (char *)txtRecord = "";
-
+ if (!txtRecord) txtRecord = (void*)"";
+
// auto-name must also have auto-rename
if (!name[0] && (flags & kDNSServiceFlagsNoAutoRename))
return kDNSServiceErr_BadParam;
put_string(regtype, &ptr);
put_string(domain, &ptr);
put_string(host, &ptr);
- put_short(port, &ptr);
+ *ptr++ = port.b[0];
+ *ptr++ = port.b[1];
put_short(txtLen, &ptr);
put_rdata(txtLen, txtRecord, &ptr);
DNSServiceRefDeallocate(sdr);
return err;
}
-
+
sdr->op = reg_service_request;
sdr->process_reply = callBack ? handle_regservice_response : NULL;
sdr->app_callback = callBack;
*sdRef = sdr;
return err;
-
+
error:
if (msg) free(msg);
if (*sdRef) { free(*sdRef); *sdRef = NULL; }
return kDNSServiceErr_Unknown;
}
-
-static void handle_regservice_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
+static void handle_enumeration_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
{
DNSServiceFlags flags;
uint32_t interfaceIndex;
- DNSServiceErrorType errorCode;
- char name[256], regtype[256], domain[256];
+ DNSServiceErrorType err;
+ char domain[kDNSServiceMaxDomainName];
+ int str_error = 0;
(void)hdr;//Unused
flags = get_flags(&data);
interfaceIndex = get_long(&data);
- errorCode = get_error_code(&data);
- get_string(&data, name, 256);
- get_string(&data, regtype, 256);
- get_string(&data, domain, 256);
- ((DNSServiceRegisterReply)sdr->app_callback)(sdr, flags, errorCode, name, regtype, domain, sdr->app_context);
+ err = get_error_code(&data);
+ if (get_string(&data, domain, kDNSServiceMaxDomainName) < 0) str_error = 1;
+ if (!err && str_error) err = kDNSServiceErr_Unknown;
+ ((DNSServiceDomainEnumReply)sdr->app_callback)(sdr, flags, interfaceIndex, err, domain, sdr->app_context);
}
-DNSServiceErrorType DNSServiceEnumerateDomains
+DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
(
DNSServiceRef *sdRef,
- const DNSServiceFlags flags,
- const uint32_t interfaceIndex,
- const DNSServiceDomainEnumReply callBack,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceDomainEnumReply callBack,
void *context
)
{
char *msg = NULL, *ptr;
- int len;
+ size_t len;
ipc_msg_hdr *hdr;
DNSServiceRef sdr;
DNSServiceErrorType err;
-
+ int f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0;
+ int f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0;
+ if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
if (!sdRef) return kDNSServiceErr_BadParam;
*sdRef = NULL;
- len = sizeof(DNSServiceFlags);
+ len = sizeof(DNSServiceFlags);
len += sizeof(uint32_t);
hdr = create_hdr(enumeration_request, &len, &ptr, 1);
return kDNSServiceErr_Unknown;
}
-
-static void handle_enumeration_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
+static void handle_regrecord_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
{
DNSServiceFlags flags;
uint32_t interfaceIndex;
- DNSServiceErrorType err;
- char domain[256];
- (void)hdr;//Unused
+ DNSServiceErrorType errorCode;
+ DNSRecordRef rref = hdr->client_context.context;
+ if (sdr->op != connection)
+ {
+ rref->app_callback(rref->sdr, rref, 0, kDNSServiceErr_Unknown, rref->app_context);
+ return;
+ }
flags = get_flags(&data);
interfaceIndex = get_long(&data);
- err = get_error_code(&data);
- get_string(&data, domain, 256);
- ((DNSServiceDomainEnumReply)sdr->app_callback)(sdr, flags, interfaceIndex, err, domain, sdr->app_context);
- }
+ errorCode = get_error_code(&data);
+ rref->app_callback(rref->sdr, rref, flags, errorCode, rref->app_context);
+ }
-DNSServiceErrorType DNSServiceCreateConnection(DNSServiceRef *sdRef)
+DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef)
{
if (!sdRef) return kDNSServiceErr_BadParam;
*sdRef = connect_to_server();
return 0;
}
-
-
-static void handle_regrecord_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
- {
- DNSServiceFlags flags;
- uint32_t interfaceIndex;
- DNSServiceErrorType errorCode;
- DNSRecordRef rref = hdr->client_context.context;
-
- if (sdr->op != connection)
- {
- rref->app_callback(rref->sdr, rref, 0, kDNSServiceErr_Unknown, rref->app_context);
- return;
- }
- flags = get_flags(&data);
- interfaceIndex = get_long(&data);
- errorCode = get_error_code(&data);
-
- rref->app_callback(rref->sdr, rref, flags, errorCode, rref->app_context);
- }
-
-DNSServiceErrorType DNSServiceRegisterRecord
+DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
(
- const DNSServiceRef sdRef,
- DNSRecordRef *RecordRef,
- const DNSServiceFlags flags,
- const uint32_t interfaceIndex,
+ DNSServiceRef sdRef,
+ DNSRecordRef *RecordRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
const char *fullname,
- const uint16_t rrtype,
- const uint16_t rrclass,
- const uint16_t rdlen,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ uint16_t rdlen,
const void *rdata,
- const uint32_t ttl,
- const DNSServiceRegisterRecordReply callBack,
+ uint32_t ttl,
+ DNSServiceRegisterRecordReply callBack,
void *context
)
{
char *msg = NULL, *ptr;
- int len;
+ size_t len;
ipc_msg_hdr *hdr = NULL;
DNSServiceRef tmp = NULL;
DNSRecordRef rref = NULL;
-
- if (!sdRef || sdRef->op != connection || sdRef->sockfd < 0)
+ int f1 = (flags & kDNSServiceFlagsShared) != 0;
+ int f2 = (flags & kDNSServiceFlagsUnique) != 0;
+ if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
+
+ if (!sdRef || sdRef->op != connection || sdRef->sockfd < 0)
return kDNSServiceErr_BadReference;
*RecordRef = NULL;
-
- len = sizeof(DNSServiceFlags);
+
+ len = sizeof(DNSServiceFlags);
len += 2 * sizeof(uint32_t); // interfaceIndex, ttl
len += 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen
len += strlen(fullname) + 1;
rref->sdr = sdRef;
*RecordRef = rref;
hdr->client_context.context = rref;
- hdr->reg_index = rref->record_index;
-
+ hdr->reg_index = rref->record_index;
+
return deliver_request(msg, sdRef, 0);
error:
}
//sdRef returned by DNSServiceRegister()
-DNSServiceErrorType DNSServiceAddRecord
+DNSServiceErrorType DNSSD_API DNSServiceAddRecord
(
- const DNSServiceRef sdRef,
+ DNSServiceRef sdRef,
DNSRecordRef *RecordRef,
- const DNSServiceFlags flags,
- const uint16_t rrtype,
- const uint16_t rdlen,
+ DNSServiceFlags flags,
+ uint16_t rrtype,
+ uint16_t rdlen,
const void *rdata,
- const uint32_t ttl
+ uint32_t ttl
)
{
ipc_msg_hdr *hdr;
- int len = 0;
+ size_t len = 0;
char *ptr;
DNSRecordRef rref;
- if (!sdRef || (sdRef->op != reg_service_request) || !RecordRef)
+ if (!sdRef || (sdRef->op != reg_service_request) || !RecordRef)
return kDNSServiceErr_BadReference;
*RecordRef = NULL;
-
+
len += 2 * sizeof(uint16_t); //rrtype, rdlen
len += rdlen;
len += sizeof(uint32_t);
rref->sdr = sdRef;
*RecordRef = rref;
hdr->client_context.context = rref;
- hdr->reg_index = rref->record_index;
+ hdr->reg_index = rref->record_index;
return deliver_request((char *)hdr, sdRef, 0);
error:
if (*RecordRef) *RecordRef = NULL;
return kDNSServiceErr_Unknown;
}
-
//DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
-DNSServiceErrorType DNSServiceUpdateRecord
+DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
(
- const DNSServiceRef sdRef,
+ DNSServiceRef sdRef,
DNSRecordRef RecordRef,
- const DNSServiceFlags flags,
- const uint16_t rdlen,
+ DNSServiceFlags flags,
+ uint16_t rdlen,
const void *rdata,
- const uint32_t ttl
+ uint32_t ttl
)
{
ipc_msg_hdr *hdr;
- int len = 0;
+ size_t len = 0;
char *ptr;
- if (!sdRef || !RecordRef || !sdRef->max_index)
- return kDNSServiceErr_BadReference;
-
+ if (!sdRef) return kDNSServiceErr_BadReference;
+
len += sizeof(uint16_t);
len += rdlen;
len += sizeof(uint32_t);
put_long(ttl, &ptr);
return deliver_request((char *)hdr, sdRef, 0);
}
-
-
-DNSServiceErrorType DNSServiceRemoveRecord
+DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
(
- const DNSServiceRef sdRef,
- const DNSRecordRef RecordRef,
- const DNSServiceFlags flags
+ DNSServiceRef sdRef,
+ DNSRecordRef RecordRef,
+ DNSServiceFlags flags
)
{
ipc_msg_hdr *hdr;
- int len = 0;
+ size_t len = 0;
char *ptr;
DNSServiceErrorType err;
- if (!sdRef || !RecordRef || !sdRef->max_index)
+ if (!sdRef || !RecordRef || !sdRef->max_index)
return kDNSServiceErr_BadReference;
-
+
len += sizeof(flags);
hdr = create_hdr(remove_record_request, &len, &ptr, 0);
if (!hdr) return kDNSServiceErr_Unknown;
return err;
}
-
-void DNSServiceReconfirmRecord
+void DNSSD_API DNSServiceReconfirmRecord
(
- const DNSServiceFlags flags,
- const uint32_t interfaceIndex,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
const char *fullname,
- const uint16_t rrtype,
- const uint16_t rrclass,
- const uint16_t rdlen,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ uint16_t rdlen,
const void *rdata
)
{
char *ptr;
- int len;
+ size_t len;
ipc_msg_hdr *hdr;
DNSServiceRef tmp;
put_short(rrclass, &ptr);
put_short(rdlen, &ptr);
put_rdata(rdlen, rdata, &ptr);
- my_write(tmp->sockfd, (char *)hdr, len);
+ ConvertHeaderBytes(hdr);
+ my_write(tmp->sockfd, (char *)hdr, (int) len);
+ free(hdr);
DNSServiceRefDeallocate(tmp);
}
-
-
-int DNSServiceConstructFullName
- (
- char *fullName,
- const char *service, /* may be NULL */
- const char *regtype,
- const char *domain
- )
- {
- int len;
- u_char c;
- char *fn = fullName;
- const char *s = service;
- const char *r = regtype;
- const char *d = domain;
-
- if (service)
- {
- while(*s)
- {
- c = *s++;
- if (c == '.' || (c == '\\')) *fn++ = '\\'; // escape dot and backslash literals
- else if (c <= ' ') // escape non-printable characters
- {
- *fn++ = '\\';
- *fn++ = (char) ('0' + (c / 100));
- *fn++ = (char) ('0' + (c / 10) % 10);
- c = (u_char)('0' + (c % 10));
- }
- *fn++ = c;
- }
- *fn++ = '.';
- }
-
- if (!regtype) return -1;
- len = strlen(regtype);
- if (domain_ends_in_dot(regtype)) len--;
- if (len < 4) return -1; // regtype must end in _udp or _tcp
- if (strncmp((regtype + len - 4), "_tcp", 4) && strncmp((regtype + len - 4), "_udp", 4)) return -1;
- while(*r)
- *fn++ = *r++;
- if (!domain_ends_in_dot(regtype)) *fn++ = '.';
-
- if (!domain) return -1;
- len = strlen(domain);
- if (!len) return -1;
- while(*d)
- *fn++ = *d++;
- if (!domain_ends_in_dot(domain)) *fn++ = '.';
- *fn = '\0';
- return 0;
- }
-
-static int domain_ends_in_dot(const char *dom)
- {
- while(*dom && *(dom + 1))
- {
- if (*dom == '\\') // advance past escaped byte sequence
- {
- if (*(dom + 1) >= '0' && *(dom + 1) <= '9') dom += 4;
- else dom += 2;
- }
- else dom++; // else read one character
- }
- return (*dom == '.');
- }
-
-
-
- // return a connected service ref (deallocate with DNSServiceRefDeallocate)
-static DNSServiceRef connect_to_server(void)
- {
- struct sockaddr_un saddr;
- DNSServiceRef sdr;
-
- sdr = malloc(sizeof(_DNSServiceRef_t));
- if (!sdr) return NULL;
-
- if ((sdr->sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
- {
- free(sdr);
- return NULL;
- }
-
- saddr.sun_family = AF_LOCAL;
- strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH);
- if (connect(sdr->sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
- {
- free(sdr);
- return NULL;
- }
- return sdr;
- }
-
-
-
-
-int my_write(int sd, char *buf, int len)
- {
- if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
- return 0;
- }
-
-
-// read len bytes. return 0 on success, -1 on error
-int my_read(int sd, char *buf, int len)
- {
- if (recv(sd, buf, len, MSG_WAITALL) != len) return -1;
- return 0;
- }
-
-
-DNSServiceErrorType deliver_request(void *msg, DNSServiceRef sdr, int reuse_sd)
- {
- ipc_msg_hdr *hdr = msg;
- mode_t mask;
- struct sockaddr_un caddr, daddr; // (client and daemon address structs)
- char *path = NULL;
- int listenfd = -1, errsd = -1, len;
- DNSServiceErrorType err = kDNSServiceErr_Unknown;
-
- if (!hdr || sdr->sockfd < 0) return kDNSServiceErr_Unknown;
-
- if (!reuse_sd)
- {
- // setup temporary error socket
- if ((listenfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0)
- goto cleanup;
-
- bzero(&caddr, sizeof(caddr));
- caddr.sun_family = AF_LOCAL;
- caddr.sun_len = sizeof(struct sockaddr_un);
- path = (char *)msg + sizeof(ipc_msg_hdr);
- strcpy(caddr.sun_path, path);
- mask = umask(0);
- if (bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr)) < 0)
- {
- umask(mask);
- goto cleanup;
- }
- umask(mask);
- listen(listenfd, 1);
- }
-
- if (my_write(sdr->sockfd, msg, hdr->datalen + sizeof(ipc_msg_hdr)) < 0)
- goto cleanup;
- free(msg);
- msg = NULL;
- if (reuse_sd) errsd = sdr->sockfd;
- else
- {
- len = sizeof(daddr);
- errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
- if (errsd < 0) goto cleanup;
- }
-
- len = recv(errsd, &err, sizeof(err), MSG_WAITALL);
- if (len != sizeof(err))
- {
- err = kDNSServiceErr_Unknown;
- }
-cleanup:
- if (!reuse_sd && listenfd > 0) close(listenfd);
- if (!reuse_sd && errsd > 0) close(errsd);
- if (!reuse_sd && path) unlink(path);
- if (msg) free(msg);
- return err;
- }
-
-
-
-/* create_hdr
- *
- * allocate and initialize an ipc message header. value of len should initially be the
- * length of the data, and is set to the value of the data plus the header. data_start
- * is set to point to the beginning of the data section. reuse_socket should be non-zero
- * for calls that can receive an immediate error return value on their primary socket.
- * if zero, the path to a control socket is appended at the beginning of the message buffer.
- * data_start is set past this string.
- */
-
-static ipc_msg_hdr *create_hdr(int op, int *len, char **data_start, int reuse_socket)
- {
- char *msg = NULL;
- ipc_msg_hdr *hdr;
- int datalen;
- char ctrl_path[256];
- struct timeval time;
-
- if (!reuse_socket)
- {
- if (gettimeofday(&time, NULL) < 0) return NULL;
- sprintf(ctrl_path, "%s%d-%.3x-%.6u", CTL_PATH_PREFIX, (int)getpid(),
- time.tv_sec & 0xFFF, time.tv_usec);
-
- *len += strlen(ctrl_path) + 1;
- }
-
-
- datalen = *len;
- *len += sizeof(ipc_msg_hdr);
-
- // write message to buffer
- msg = malloc(*len);
- if (!msg) return NULL;
-
- bzero(msg, *len);
- hdr = (void *)msg;
- hdr->datalen = datalen;
- hdr->version = VERSION;
- hdr->op.request_op = op;
- if (reuse_socket) hdr->flags |= IPC_FLAGS_REUSE_SOCKET;
- *data_start = msg + sizeof(ipc_msg_hdr);
- if (!reuse_socket) put_string(ctrl_path, data_start);
- return hdr;
- }