2N/A/* -*- Mode: C; tab-width: 4 -*-
2N/A *
2N/A * Copyright (c) 2003-2004, Apple Computer, Inc. All rights reserved.
2N/A *
2N/A * Redistribution and use in source and binary forms, with or without
2N/A * modification, are permitted provided that the following conditions are met:
2N/A *
2N/A * 1. Redistributions of source code must retain the above copyright notice,
2N/A * this list of conditions and the following disclaimer.
2N/A * 2. Redistributions in binary form must reproduce the above copyright notice,
2N/A * this list of conditions and the following disclaimer in the documentation
2N/A * and/or other materials provided with the distribution.
2N/A * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
2N/A * contributors may be used to endorse or promote products derived from this
2N/A * software without specific prior written permission.
2N/A *
2N/A * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
2N/A * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2N/A * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2N/A * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
2N/A * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2N/A * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2N/A * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2N/A * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2N/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2N/A * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2N/A
2N/A Change History (most recent first):
2N/A
2N/A$Log: dnssd_clientstub.c,v $
2N/ARevision 1.53 2006/09/07 04:43:12 herscher
2N/AFix compile error on Win32 platform by moving inclusion of syslog.h
2N/A
2N/ARevision 1.52 2006/08/15 23:04:21 mkrochma
2N/A<rdar://problem/4090354> Client should be able to specify service name w/o callback
2N/A
2N/ARevision 1.51 2006/07/24 23:45:55 cheshire
2N/A<rdar://problem/4605276> DNSServiceReconfirmRecord() should return error code
2N/A
2N/ARevision 1.50 2006/06/28 08:22:27 cheshire
2N/A<rdar://problem/4605264> dnssd_clientstub.c needs to report unlink failures in syslog
2N/A
2N/ARevision 1.49 2006/06/28 07:58:59 cheshire
2N/AMinor textual tidying
2N/A
2N/ARevision 1.48 2005/06/30 18:01:00 shersche
2N/A<rdar://problem/4096913> Clients shouldn't wait ten seconds to connect to mDNSResponder
2N/A
2N/ARevision 1.47 2005/03/31 02:19:56 cheshire
2N/A<rdar://problem/4021486> Fix build warnings
2N/AReviewed by: Scott Herscher
2N/A
2N/ARevision 1.46 2005/03/21 00:39:31 shersche
2N/A<rdar://problem/4021486> Fix build warnings on Win32 platform
2N/A
2N/ARevision 1.45 2005/02/01 01:25:06 shersche
2N/ADefine sleep() to be Sleep() for Windows compatibility
2N/A
2N/ARevision 1.44 2005/01/27 22:57:56 cheshire
2N/AFix compile errors on gcc4
2N/A
2N/ARevision 1.43 2005/01/27 00:02:29 cheshire
2N/A<rdar://problem/3947461> Handle case where client runs before daemon has finished launching
2N/A
2N/ARevision 1.42 2005/01/11 02:01:02 shersche
2N/AUse dnssd_close() rather than close() for Windows compatibility
2N/A
2N/ARevision 1.41 2004/12/23 17:34:26 ksekar
2N/A<rdar://problem/3931319> Calls leak sockets if mDNSResponder is not running
2N/A
2N/ARevision 1.40 2004/11/23 03:39:47 cheshire
2N/ALet interface name/index mapping capability live directly in JNISupport.c,
2N/Ainstead of having to call through to the daemon via IPC to get this information.
2N/A
2N/ARevision 1.39 2004/11/12 03:22:00 rpantos
2N/Ardar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
2N/A
2N/ARevision 1.38 2004/11/02 02:51:23 cheshire
2N/A<rdar://problem/3526342> Remove overly-restrictive flag checks
2N/A
2N/ARevision 1.37 2004/10/14 01:43:35 cheshire
2N/AFix opaque port passing problem
2N/A
2N/ARevision 1.36 2004/10/06 02:22:19 cheshire
2N/AChanged MacRoman copyright symbol (should have been UTF-8 in any case :-) to ASCII-compatible "(c)"
2N/A
2N/ARevision 1.35 2004/10/01 22:15:55 rpantos
2N/Ardar://problem/3824265: Replace APSL in client lib with BSD license.
2N/A
2N/ARevision 1.34 2004/09/17 22:36:13 cheshire
2N/AAdd comment explaining that deliver_request frees the message it sends
2N/A
2N/ARevision 1.33 2004/09/17 01:17:31 ksekar
2N/ARemove double-free of msg header, freed automatically by deliver_request()
2N/A
2N/ARevision 1.32 2004/09/17 01:08:55 cheshire
2N/ARenamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
2N/A The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
2N/A declared in that file are ONLY appropriate to single-address-space embedded applications.
2N/A For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
2N/A
2N/ARevision 1.31 2004/09/16 23:37:19 cheshire
2N/AFree hdr before returning
2N/A
2N/ARevision 1.30 2004/09/16 23:14:24 cheshire
2N/AChanges for Windows compatibility
2N/A
2N/ARevision 1.29 2004/09/16 21:46:38 ksekar
2N/A<rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area domain
2N/A
2N/ARevision 1.28 2004/08/11 17:10:04 cheshire
2N/AFix signed/unsigned warnings
2N/A
2N/ARevision 1.27 2004/08/11 00:54:16 cheshire
2N/AChange "hdr->op.request_op" to just "hdr->op"
2N/A
2N/ARevision 1.26 2004/07/26 06:07:27 shersche
2N/Afix bugs when using an error socket to communicate with the daemon
2N/A
2N/ARevision 1.25 2004/07/26 05:54:02 shersche
2N/ADNSServiceProcessResult() returns NoError if socket read returns EWOULDBLOCK
2N/A
2N/ARevision 1.24 2004/07/20 06:46:21 shersche
2N/A<rdar://problem/3730123> fix endless loop in read_all() if recv returns 0
2N/ABug #: 3730123
2N/A
2N/ARevision 1.23 2004/06/29 00:48:38 cheshire
2N/ADon't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
2N/Ause an explicit while() loop instead.
2N/A
2N/ARevision 1.22 2004/06/26 03:16:34 shersche
2N/Aclean up warning messages on Win32 platform
2N/A
2N/ASubmitted by: herscher
2N/A
2N/ARevision 1.21 2004/06/18 04:53:56 rpantos
2N/AUse platform layer for socket types. Introduce USE_TCP_LOOPBACK. Remove dependency on mDNSEmbeddedAPI.h.
2N/A
2N/ARevision 1.20 2004/06/12 00:50:22 cheshire
2N/AChanges for Windows compatibility
2N/A
2N/ARevision 1.19 2004/05/25 18:29:33 cheshire
2N/AMove DNSServiceConstructFullName() from dnssd_clientstub.c to dnssd_clientlib.c,
2N/Aso that it's also accessible to dnssd_clientshim.c (single address space) clients.
2N/A
2N/ARevision 1.18 2004/05/18 23:51:27 cheshire
2N/ATidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
2N/A
2N/ARevision 1.17 2004/05/06 18:42:58 ksekar
2N/AGeneral dns_sd.h API cleanup, including the following radars:
2N/A<rdar://problem/3592068>: Remove flags with zero value
2N/A<rdar://problem/3479569>: Passing in NULL causes a crash.
2N/A
2N/ARevision 1.16 2004/03/12 22:00:37 cheshire
2N/AAdded: #include <sys/socket.h>
2N/A
2N/ARevision 1.15 2004/01/20 18:36:29 ksekar
2N/APropagated Libinfo fix for <rdar://problem/3483971>: SU:
2N/ADNSServiceUpdateRecord() doesn't allow you to update the TXT record
2N/Ainto TOT mDNSResponder.
2N/A
2N/ARevision 1.14 2004/01/19 22:39:17 cheshire
2N/ADon't use "MSG_WAITALL"; it makes send() return "Invalid argument" on Linux;
2N/Ause an explicit while() loop instead. (In any case, this should only make a difference
2N/Awith non-blocking sockets, which we don't use on the client side right now.)
2N/A
2N/ARevision 1.13 2004/01/19 21:46:52 cheshire
2N/AFix compiler warning
2N/A
2N/ARevision 1.12 2003/12/23 20:46:47 ksekar
2N/A<rdar://problem/3497428>: sync dnssd files between libinfo & mDNSResponder
2N/A
2N/ARevision 1.11 2003/12/08 21:11:42 rpantos
2N/AChanges necessary to support mDNSResponder on Linux.
2N/A
2N/ARevision 1.10 2003/10/13 23:50:53 ksekar
2N/AUpdated dns_sd clientstub files to bring copies in synch with
2N/Atop-of-tree Libinfo: A memory leak in dnssd_clientstub.c is fixed,
2N/Aand comments in dns_sd.h are improved.
2N/A
2N/ARevision 1.9 2003/08/15 21:30:39 cheshire
2N/ABring up to date with LibInfo version
2N/A
2N/ARevision 1.8 2003/08/13 23:54:52 ksekar
2N/ABringing dnssd_clientstub.c up to date with Libinfo, per radar 3376640
2N/A
2N/ARevision 1.7 2003/08/12 19:56:25 cheshire
2N/AUpdate to APSL 2.0
2N/A
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A#include <errno.h>
2N/A#include <stdlib.h>
2N/A
2N/A#include "dnssd_ipc.h"
2N/A
2N/A#if defined(_WIN32)
2N/A
2N/A#include <winsock2.h>
2N/A#include <windows.h>
2N/A
2N/A#define sockaddr_mdns sockaddr_in
2N/A#define AF_MDNS AF_INET
2N/A
2N/A// disable warning: "'type cast' : from data pointer 'void *' to function pointer"
2N/A#pragma warning(disable:4055)
2N/A
2N/A// disable warning: "nonstandard extension, function/data pointer conversion in expression"
2N/A#pragma warning(disable:4152)
2N/A
2N/Aextern BOOL IsSystemServiceDisabled();
2N/A
2N/A#define sleep(X) Sleep((X) * 1000)
2N/A
2N/Astatic int g_initWinsock = 0;
2N/A
2N/A#else
2N/A
2N/A#include <sys/time.h>
2N/A#include <sys/socket.h>
2N/A#include <syslog.h>
2N/A
2N/A#define sockaddr_mdns sockaddr_un
2N/A#define AF_MDNS AF_LOCAL
2N/A
2N/A#endif
2N/A
2N/A// <rdar://problem/4096913> Specifies how many times we'll try and connect to the
2N/A// server.
2N/A
2N/A#define DNSSD_CLIENT_MAXTRIES 4
2N/A
2N/A#define CTL_PATH_PREFIX "/tmp/dnssd_clippath."
2N/A// error socket (if needed) is named "dnssd_clipath.[pid].xxx:n" where xxx are the
2N/A// last 3 digits of the time (in seconds) and n is the 6-digit microsecond time
2N/A
2N/A// general utility functions
2N/Atypedef struct _DNSServiceRef_t
2N/A {
2N/A dnssd_sock_t sockfd; // connected socket between client and daemon
2N/A uint32_t op; // request_op_t or reply_op_t
2N/A process_reply_callback process_reply;
2N/A void *app_callback;
2N/A void *app_context;
2N/A uint32_t max_index; //largest assigned record index - 0 if no additl. recs registered
2N/A } _DNSServiceRef_t;
2N/A
2N/Atypedef struct _DNSRecordRef_t
2N/A {
2N/A void *app_context;
2N/A DNSServiceRegisterRecordReply app_callback;
2N/A DNSRecordRef recref;
2N/A uint32_t record_index; // index is unique to the ServiceDiscoveryRef
2N/A DNSServiceRef sdr;
2N/A } _DNSRecordRef_t;
2N/A
2N/A// exported functions
2N/A
2N/A// write len bytes. return 0 on success, -1 on error
2N/Astatic int write_all(dnssd_sock_t sd, char *buf, int len)
2N/A {
2N/A // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
2N/A //if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
2N/A while (len)
2N/A {
2N/A ssize_t num_written = send(sd, buf, len, 0);
2N/A if (num_written < 0 || num_written > len) return -1;
2N/A buf += num_written;
2N/A len -= num_written;
2N/A }
2N/A return 0;
2N/A }
2N/A
2N/A// read len bytes. return 0 on success, -1 on error
2N/Astatic int read_all(dnssd_sock_t sd, char *buf, int len)
2N/A {
2N/A // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
2N/A //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1;
2N/A while (len)
2N/A {
2N/A ssize_t num_read = recv(sd, buf, len, 0);
2N/A if ((num_read == -1) && (errno == EINTR))
2N/A continue;
2N/A if ((num_read < 0) || (num_read > len)) return -1;
2N/A // Return error -2 when no data received and errno is not set
2N/A if (num_read == 0) return -2;
2N/A buf += num_read;
2N/A len -= num_read;
2N/A }
2N/A return 0;
2N/A }
2N/A
2N/A/* create_hdr
2N/A *
2N/A * allocate and initialize an ipc message header. value of len should initially be the
2N/A * length of the data, and is set to the value of the data plus the header. data_start
2N/A * is set to point to the beginning of the data section. reuse_socket should be non-zero
2N/A * for calls that can receive an immediate error return value on their primary socket.
2N/A * if zero, the path to a control socket is appended at the beginning of the message buffer.
2N/A * data_start is set past this string.
2N/A */
2N/A
2N/Astatic ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int reuse_socket)
2N/A {
2N/A char *msg = NULL;
2N/A ipc_msg_hdr *hdr;
2N/A int datalen;
2N/A#if !defined(USE_TCP_LOOPBACK)
2N/A char ctrl_path[256];
2N/A#endif
2N/A
2N/A if (!reuse_socket)
2N/A {
2N/A#if defined(USE_TCP_LOOPBACK)
2N/A *len += 2; // Allocate space for two-byte port number
2N/A#else
2N/A struct timeval time;
2N/A if (gettimeofday(&time, NULL) < 0) return NULL;
2N/A sprintf(ctrl_path, "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(),
2N/A (unsigned long)(time.tv_sec & 0xFFF), (unsigned long)(time.tv_usec));
2N/A *len += strlen(ctrl_path) + 1;
2N/A#endif
2N/A }
2N/A
2N/A datalen = (int) *len;
2N/A *len += sizeof(ipc_msg_hdr);
2N/A
2N/A // write message to buffer
2N/A msg = malloc(*len);
2N/A if (!msg) return NULL;
2N/A
2N/A bzero(msg, *len);
2N/A hdr = (void *)msg;
2N/A hdr->datalen = datalen;
2N/A hdr->version = VERSION;
2N/A hdr->op = op;
2N/A if (reuse_socket) hdr->flags |= IPC_FLAGS_REUSE_SOCKET;
2N/A *data_start = msg + sizeof(ipc_msg_hdr);
2N/A#if defined(USE_TCP_LOOPBACK)
2N/A // Put dummy data in for the port, since we don't know what
2N/A // it is yet. The data will get filled in before we
2N/A // send the message. This happens in deliver_request().
2N/A if (!reuse_socket) put_short(0, data_start);
2N/A#else
2N/A if (!reuse_socket) put_string(ctrl_path, data_start);
2N/A#endif
2N/A return hdr;
2N/A }
2N/A
2N/A // return a connected service ref (deallocate with DNSServiceRefDeallocate)
2N/Astatic DNSServiceRef connect_to_server(void)
2N/A {
2N/A dnssd_sockaddr_t saddr;
2N/A DNSServiceRef sdr;
2N/A int NumTries = 0;
2N/A
2N/A#if defined(_WIN32)
2N/A if (!g_initWinsock)
2N/A {
2N/A WSADATA wsaData;
2N/A DNSServiceErrorType err;
2N/A
2N/A g_initWinsock = 1;
2N/A
2N/A err = WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
2N/A
2N/A if (err != 0) return NULL;
2N/A }
2N/A
2N/A // <rdar://problem/4096913> If the system service is disabled, we only want to try
2N/A // to connect once
2N/A
2N/A if ( IsSystemServiceDisabled() )
2N/A {
2N/A NumTries = DNSSD_CLIENT_MAXTRIES;
2N/A }
2N/A
2N/A#endif
2N/A
2N/A sdr = malloc(sizeof(_DNSServiceRef_t));
2N/A if (!sdr) return(NULL);
2N/A sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0);
2N/A if (sdr->sockfd == dnssd_InvalidSocket) { free(sdr); return NULL; }
2N/A#if defined(USE_TCP_LOOPBACK)
2N/A saddr.sin_family = AF_INET;
2N/A saddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
2N/A saddr.sin_port = htons(MDNS_TCP_SERVERPORT);
2N/A#else
2N/A saddr.sun_family = AF_LOCAL;
2N/A strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH);
2N/A#endif
2N/A while (1)
2N/A {
2N/A int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
2N/A if (!err) break; // If we succeeded, return sdr
2N/A // If we failed, then it may be because the daemon is still launching.
2N/A // This can happen for processes that launch early in the boot process, while the
2N/A // daemon is still coming up. Rather than fail here, we'll wait a bit and try again.
2N/A // If, after four seconds, we still can't connect to the daemon,
2N/A // then we give up and return a failure code.
2N/A if (++NumTries < DNSSD_CLIENT_MAXTRIES)
2N/A sleep(1); // Sleep a bit, then try again
2N/A else
2N/A {
2N/A dnssd_close(sdr->sockfd);
2N/A sdr->sockfd = dnssd_InvalidSocket;
2N/A free(sdr);
2N/A return NULL;
2N/A }
2N/A }
2N/A return sdr;
2N/A }
2N/A
2N/Astatic DNSServiceErrorType deliver_request(void *msg, DNSServiceRef sdr, int reuse_sd)
2N/A {
2N/A ipc_msg_hdr *hdr = msg;
2N/A uint32_t datalen = hdr->datalen;
2N/A dnssd_sockaddr_t caddr, daddr; // (client and daemon address structs)
2N/A char *const data = (char *)msg + sizeof(ipc_msg_hdr);
2N/A dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
2N/A int ret;
2N/A dnssd_socklen_t len = (dnssd_socklen_t) sizeof(caddr);
2N/A DNSServiceErrorType err = kDNSServiceErr_Unknown;
2N/A
2N/A if (!hdr || sdr->sockfd < 0) return kDNSServiceErr_Unknown;
2N/A
2N/A if (!reuse_sd)
2N/A {
2N/A // setup temporary error socket
2N/A if ((listenfd = socket(AF_DNSSD, SOCK_STREAM, 0)) < 0)
2N/A goto cleanup;
2N/A bzero(&caddr, sizeof(caddr));
2N/A
2N/A#if defined(USE_TCP_LOOPBACK)
2N/A {
2N/A union { uint16_t s; u_char b[2]; } port;
2N/A caddr.sin_family = AF_INET;
2N/A caddr.sin_port = 0;
2N/A caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
2N/A ret = bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr));
2N/A if (ret < 0) goto cleanup;
2N/A if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) goto cleanup;
2N/A listen(listenfd, 1);
2N/A port.s = caddr.sin_port;
2N/A data[0] = port.b[0]; // don't switch the byte order, as the
2N/A data[1] = port.b[1]; // daemon expects it in network byte order
2N/A }
2N/A#else
2N/A {
2N/A mode_t mask = umask(0);
2N/A caddr.sun_family = AF_LOCAL;
2N/A// According to Stevens (section 3.2), there is no portable way to
2N/A// determine whether sa_len is defined on a particular platform.
2N/A#ifndef NOT_HAVE_SA_LEN
2N/A caddr.sun_len = sizeof(struct sockaddr_un);
2N/A#endif
2N/A //syslog(LOG_WARNING, "deliver_request: creating UDS: %s\n", data);
2N/A strcpy(caddr.sun_path, data);
2N/A ret = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr));
2N/A umask(mask);
2N/A if (ret < 0) goto cleanup;
2N/A listen(listenfd, 1);
2N/A }
2N/A#endif
2N/A }
2N/A
2N/A ConvertHeaderBytes(hdr);
2N/A //syslog(LOG_WARNING, "deliver_request writing %ld bytes\n", datalen + sizeof(ipc_msg_hdr));
2N/A //syslog(LOG_WARNING, "deliver_request name is %s\n", (char *)msg + sizeof(ipc_msg_hdr));
2N/A if (write_all(sdr->sockfd, msg, datalen + sizeof(ipc_msg_hdr)) < 0)
2N/A goto cleanup;
2N/A free(msg);
2N/A msg = NULL;
2N/A
2N/A if (reuse_sd) errsd = sdr->sockfd;
2N/A else
2N/A {
2N/A //syslog(LOG_WARNING, "deliver_request: accept\n");
2N/A len = sizeof(daddr);
2N/A errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
2N/A //syslog(LOG_WARNING, "deliver_request: accept returned %d\n", errsd);
2N/A if (errsd < 0) goto cleanup;
2N/A }
2N/A
2N/A if (read_all(errsd, (char*)&err, (int)sizeof(err)) < 0)
2N/A err = kDNSServiceErr_Unknown;
2N/A else
2N/A err = ntohl(err);
2N/A
2N/A //syslog(LOG_WARNING, "deliver_request: retrieved error code %d\n", err);
2N/A
2N/Acleanup:
2N/A if (!reuse_sd)
2N/A {
2N/A if (listenfd > 0) dnssd_close(listenfd);
2N/A if (errsd > 0) dnssd_close(errsd);
2N/A#if !defined(USE_TCP_LOOPBACK)
2N/A // syslog(LOG_WARNING, "deliver_request: removing UDS: %s\n", data);
2N/A if (unlink(data) != 0)
2N/A syslog(LOG_WARNING, "WARNING: unlink(\"%s\") failed errno %d (%s)", data, errno, strerror(errno));
2N/A // else syslog(LOG_WARNING, "deliver_request: removed UDS: %s\n", data);
2N/A#endif
2N/A }
2N/A if (msg) free(msg);
2N/A return err;
2N/A }
2N/A
2N/Aint DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef)
2N/A {
2N/A if (!sdRef) return -1;
2N/A return (int) sdRef->sockfd;
2N/A }
2N/A
2N/A// handle reply from server, calling application client callback. If there is no reply
2N/A// from the daemon on the socket contained in sdRef, the call will block.
2N/ADNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
2N/A {
2N/A ipc_msg_hdr hdr;
2N/A char *data;
2N/A int rderr;
2N/A
2N/A if (!sdRef || sdRef->sockfd < 0 || !sdRef->process_reply)
2N/A return kDNSServiceErr_BadReference;
2N/A
2N/A rderr = read_all(sdRef->sockfd, (void *)&hdr, sizeof(hdr));
2N/A if (rderr < 0) {
2N/A // return NoError on EWOULDBLOCK. This will handle the case
2N/A // where a non-blocking socket is told there is data, but
2N/A // it was a false positive. Can check errno when error
2N/A // code returned is -1
2N/A if ((rderr == -1) && (dnssd_errno() == dnssd_EWOULDBLOCK))
2N/A return kDNSServiceErr_NoError;
2N/A return kDNSServiceErr_Unknown;
2N/A }
2N/A ConvertHeaderBytes(&hdr);
2N/A if (hdr.version != VERSION)
2N/A return kDNSServiceErr_Incompatible;
2N/A data = malloc(hdr.datalen);
2N/A if (!data) return kDNSServiceErr_NoMemory;
2N/A if (read_all(sdRef->sockfd, data, hdr.datalen) < 0)
2N/A return kDNSServiceErr_Unknown;
2N/A sdRef->process_reply(sdRef, &hdr, data);
2N/A free(data);
2N/A return kDNSServiceErr_NoError;
2N/A }
2N/A
2N/Avoid DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef)
2N/A {
2N/A if (!sdRef) return;
2N/A if (sdRef->sockfd > 0) dnssd_close(sdRef->sockfd);
2N/A free(sdRef);
2N/A }
2N/A
2N/Astatic void handle_resolve_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
2N/A {
2N/A DNSServiceFlags flags;
2N/A char fullname[kDNSServiceMaxDomainName];
2N/A char target[kDNSServiceMaxDomainName];
2N/A uint16_t txtlen;
2N/A union { uint16_t s; u_char b[2]; } port;
2N/A uint32_t ifi;
2N/A DNSServiceErrorType err;
2N/A unsigned char *txtrecord;
2N/A int str_error = 0;
2N/A (void)hdr; //unused
2N/A
2N/A flags = get_flags(&data);
2N/A ifi = get_long(&data);
2N/A err = get_error_code(&data);
2N/A if (get_string(&data, fullname, kDNSServiceMaxDomainName) < 0) str_error = 1;
2N/A if (get_string(&data, target, kDNSServiceMaxDomainName) < 0) str_error = 1;
2N/A port.b[0] = *data++;
2N/A port.b[1] = *data++;
2N/A txtlen = get_short(&data);
2N/A txtrecord = (unsigned char *)get_rdata(&data, txtlen);
2N/A
2N/A if (!err && str_error) err = kDNSServiceErr_Unknown;
2N/A ((DNSServiceResolveReply)sdr->app_callback)(sdr, flags, ifi, err, fullname, target, port.s, txtlen, txtrecord, sdr->app_context);
2N/A }
2N/A
2N/ADNSServiceErrorType DNSSD_API DNSServiceResolve
2N/A (
2N/A DNSServiceRef *sdRef,
2N/A DNSServiceFlags flags,
2N/A uint32_t interfaceIndex,
2N/A const char *name,
2N/A const char *regtype,
2N/A const char *domain,
2N/A DNSServiceResolveReply callBack,
2N/A void *context
2N/A )
2N/A {
2N/A char *msg = NULL, *ptr;
2N/A size_t len;
2N/A ipc_msg_hdr *hdr;
2N/A DNSServiceRef sdr;
2N/A DNSServiceErrorType err;
2N/A
2N/A if (!sdRef) return kDNSServiceErr_BadParam;
2N/A *sdRef = NULL;
2N/A
2N/A if (!name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam;
2N/A
2N/A // calculate total message length
2N/A len = sizeof(flags);
2N/A len += sizeof(interfaceIndex);
2N/A len += strlen(name) + 1;
2N/A len += strlen(regtype) + 1;
2N/A len += strlen(domain) + 1;
2N/A
2N/A hdr = create_hdr(resolve_request, &len, &ptr, 1);
2N/A if (!hdr) goto error;
2N/A msg = (void *)hdr;
2N/A
2N/A put_flags(flags, &ptr);
2N/A put_long(interfaceIndex, &ptr);
2N/A put_string(name, &ptr);
2N/A put_string(regtype, &ptr);
2N/A put_string(domain, &ptr);
2N/A
2N/A sdr = connect_to_server();
2N/A if (!sdr) goto error;
2N/A err = deliver_request(msg, sdr, 1);
2N/A if (err)
2N/A {
2N/A DNSServiceRefDeallocate(sdr);
2N/A return err;
2N/A }
2N/A sdr->op = resolve_request;
2N/A sdr->process_reply = handle_resolve_response;
2N/A sdr->app_callback = callBack;
2N/A sdr->app_context = context;
2N/A *sdRef = sdr;
2N/A
2N/A return err;
2N/A
2N/Aerror:
2N/A if (msg) free(msg);
2N/A if (*sdRef) { free(*sdRef); *sdRef = NULL; }
2N/A return kDNSServiceErr_Unknown;
2N/A }
2N/A
2N/Astatic void handle_query_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
2N/A {
2N/A DNSServiceFlags flags;
2N/A uint32_t interfaceIndex, ttl;
2N/A DNSServiceErrorType errorCode;
2N/A char name[kDNSServiceMaxDomainName];
2N/A uint16_t rrtype, rrclass, rdlen;
2N/A char *rdata;
2N/A int str_error = 0;
2N/A (void)hdr;//Unused
2N/A
2N/A flags = get_flags(&data);
2N/A interfaceIndex = get_long(&data);
2N/A errorCode = get_error_code(&data);
2N/A if (get_string(&data, name, kDNSServiceMaxDomainName) < 0) str_error = 1;
2N/A rrtype = get_short(&data);
2N/A rrclass = get_short(&data);
2N/A rdlen = get_short(&data);
2N/A rdata = get_rdata(&data, rdlen);
2N/A ttl = get_long(&data);
2N/A
2N/A if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown;
2N/A ((DNSServiceQueryRecordReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, name, rrtype, rrclass,
2N/A rdlen, rdata, ttl, sdr->app_context);
2N/A return;
2N/A }
2N/A
2N/ADNSServiceErrorType DNSSD_API DNSServiceQueryRecord
2N/A (
2N/A DNSServiceRef *sdRef,
2N/A DNSServiceFlags flags,
2N/A uint32_t interfaceIndex,
2N/A const char *name,
2N/A uint16_t rrtype,
2N/A uint16_t rrclass,
2N/A DNSServiceQueryRecordReply callBack,
2N/A void *context
2N/A )
2N/A {
2N/A char *msg = NULL, *ptr;
2N/A size_t len;
2N/A ipc_msg_hdr *hdr;
2N/A DNSServiceRef sdr;
2N/A DNSServiceErrorType err;
2N/A
2N/A if (!sdRef) return kDNSServiceErr_BadParam;
2N/A *sdRef = NULL;
2N/A
2N/A if (!name) name = "\0";
2N/A
2N/A // calculate total message length
2N/A len = sizeof(flags);
2N/A len += sizeof(uint32_t); //interfaceIndex
2N/A len += strlen(name) + 1;
2N/A len += 2 * sizeof(uint16_t); // rrtype, rrclass
2N/A
2N/A hdr = create_hdr(query_request, &len, &ptr, 1);
2N/A if (!hdr) goto error;
2N/A msg = (void *)hdr;
2N/A
2N/A put_flags(flags, &ptr);
2N/A put_long(interfaceIndex, &ptr);
2N/A put_string(name, &ptr);
2N/A put_short(rrtype, &ptr);
2N/A put_short(rrclass, &ptr);
2N/A
2N/A sdr = connect_to_server();
2N/A if (!sdr) goto error;
2N/A err = deliver_request(msg, sdr, 1);
2N/A if (err)
2N/A {
2N/A DNSServiceRefDeallocate(sdr);
2N/A return err;
2N/A }
2N/A
2N/A sdr->op = query_request;
2N/A sdr->process_reply = handle_query_response;
2N/A sdr->app_callback = callBack;
2N/A sdr->app_context = context;
2N/A *sdRef = sdr;
2N/A return err;
2N/A
2N/Aerror:
2N/A if (msg) free(msg);
2N/A if (*sdRef) { free(*sdRef); *sdRef = NULL; }
2N/A return kDNSServiceErr_Unknown;
2N/A }
2N/A
2N/Astatic void handle_browse_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
2N/A {
2N/A DNSServiceFlags flags;
2N/A uint32_t interfaceIndex;
2N/A DNSServiceErrorType errorCode;
2N/A char replyName[256], replyType[kDNSServiceMaxDomainName],
2N/A replyDomain[kDNSServiceMaxDomainName];
2N/A int str_error = 0;
2N/A (void)hdr;//Unused
2N/A
2N/A flags = get_flags(&data);
2N/A interfaceIndex = get_long(&data);
2N/A errorCode = get_error_code(&data);
2N/A if (get_string(&data, replyName, 256) < 0) str_error = 1;
2N/A if (get_string(&data, replyType, kDNSServiceMaxDomainName) < 0) str_error = 1;
2N/A if (get_string(&data, replyDomain, kDNSServiceMaxDomainName) < 0) str_error = 1;
2N/A if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown;
2N/A ((DNSServiceBrowseReply)sdr->app_callback)(sdr, flags, interfaceIndex, errorCode, replyName, replyType, replyDomain, sdr->app_context);
2N/A }
2N/A
2N/ADNSServiceErrorType DNSSD_API DNSServiceBrowse
2N/A (
2N/A DNSServiceRef *sdRef,
2N/A DNSServiceFlags flags,
2N/A uint32_t interfaceIndex,
2N/A const char *regtype,
2N/A const char *domain,
2N/A DNSServiceBrowseReply callBack,
2N/A void *context
2N/A )
2N/A {
2N/A char *msg = NULL, *ptr;
2N/A size_t len;
2N/A ipc_msg_hdr *hdr;
2N/A DNSServiceRef sdr;
2N/A DNSServiceErrorType err;
2N/A
2N/A if (!sdRef) return kDNSServiceErr_BadParam;
2N/A *sdRef = NULL;
2N/A
2N/A if (!domain) domain = "";
2N/A
2N/A len = sizeof(flags);
2N/A len += sizeof(interfaceIndex);
2N/A len += strlen(regtype) + 1;
2N/A len += strlen(domain) + 1;
2N/A
2N/A hdr = create_hdr(browse_request, &len, &ptr, 1);
2N/A if (!hdr) goto error;
2N/A msg = (char *)hdr;
2N/A put_flags(flags, &ptr);
2N/A put_long(interfaceIndex, &ptr);
2N/A put_string(regtype, &ptr);
2N/A put_string(domain, &ptr);
2N/A
2N/A sdr = connect_to_server();
2N/A if (!sdr) goto error;
2N/A err = deliver_request(msg, sdr, 1);
2N/A if (err)
2N/A {
2N/A DNSServiceRefDeallocate(sdr);
2N/A return err;
2N/A }
2N/A sdr->op = browse_request;
2N/A sdr->process_reply = handle_browse_response;
2N/A sdr->app_callback = callBack;
2N/A sdr->app_context = context;
2N/A *sdRef = sdr;
2N/A return err;
2N/A
2N/Aerror:
2N/A if (msg) free(msg);
2N/A if (*sdRef) { free(*sdRef); *sdRef = NULL; }
2N/A return kDNSServiceErr_Unknown;
2N/A }
2N/A
2N/ADNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser
2N/A (
2N/A DNSServiceFlags flags,
2N/A const char *domain
2N/A )
2N/A {
2N/A DNSServiceRef sdr;
2N/A DNSServiceErrorType err;
2N/A char *ptr = NULL;
2N/A size_t len = sizeof(flags) + strlen(domain) + 1;
2N/A ipc_msg_hdr *hdr = create_hdr(setdomain_request, &len, &ptr, 1);
2N/A
2N/A if (!hdr) return kDNSServiceErr_Unknown;
2N/A put_flags(flags, &ptr);
2N/A put_string(domain, &ptr);
2N/A
2N/A sdr = connect_to_server();
2N/A if (!sdr) { free(hdr); return kDNSServiceErr_Unknown; }
2N/A err = deliver_request((char *)hdr, sdr, 1); // deliver_request frees the message for us
2N/A DNSServiceRefDeallocate(sdr);
2N/A return err;
2N/A }
2N/A
2N/A
2N/Astatic void handle_regservice_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
2N/A {
2N/A DNSServiceFlags flags;
2N/A uint32_t interfaceIndex;
2N/A DNSServiceErrorType errorCode;
2N/A char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
2N/A int str_error = 0;
2N/A (void)hdr;//Unused
2N/A
2N/A flags = get_flags(&data);
2N/A interfaceIndex = get_long(&data);
2N/A errorCode = get_error_code(&data);
2N/A if (get_string(&data, name, 256) < 0) str_error = 1;
2N/A if (get_string(&data, regtype, kDNSServiceMaxDomainName) < 0) str_error = 1;
2N/A if (get_string(&data, domain, kDNSServiceMaxDomainName) < 0) str_error = 1;
2N/A if (!errorCode && str_error) errorCode = kDNSServiceErr_Unknown;
2N/A ((DNSServiceRegisterReply)sdr->app_callback)(sdr, flags, errorCode, name, regtype, domain, sdr->app_context);
2N/A }
2N/A
2N/ADNSServiceErrorType DNSSD_API DNSServiceRegister
2N/A (
2N/A DNSServiceRef *sdRef,
2N/A DNSServiceFlags flags,
2N/A uint32_t interfaceIndex,
2N/A const char *name,
2N/A const char *regtype,
2N/A const char *domain,
2N/A const char *host,
2N/A uint16_t PortInNetworkByteOrder,
2N/A uint16_t txtLen,
2N/A const void *txtRecord,
2N/A DNSServiceRegisterReply callBack,
2N/A void *context
2N/A )
2N/A {
2N/A char *msg = NULL, *ptr;
2N/A size_t len;
2N/A ipc_msg_hdr *hdr;
2N/A DNSServiceRef sdr;
2N/A DNSServiceErrorType err;
2N/A union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder };
2N/A
2N/A if (!sdRef) return kDNSServiceErr_BadParam;
2N/A *sdRef = NULL;
2N/A
2N/A if (!name) name = "";
2N/A if (!regtype) return kDNSServiceErr_BadParam;
2N/A if (!domain) domain = "";
2N/A if (!host) host = "";
2N/A if (!txtRecord) txtRecord = (void*)"";
2N/A
2N/A // auto-name must also have auto-rename
2N/A if (!name[0] && (flags & kDNSServiceFlagsNoAutoRename))
2N/A return kDNSServiceErr_BadParam;
2N/A
2N/A // no callback must have auto-rename
2N/A if (!callBack && (flags & kDNSServiceFlagsNoAutoRename)) return kDNSServiceErr_BadParam;
2N/A
2N/A len = sizeof(DNSServiceFlags);
2N/A len += sizeof(uint32_t); // interfaceIndex
2N/A len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4;
2N/A len += 2 * sizeof(uint16_t); // port, txtLen
2N/A len += txtLen;
2N/A
2N/A hdr = create_hdr(reg_service_request, &len, &ptr, 1);
2N/A if (!hdr) goto error;
2N/A if (!callBack) hdr->flags |= IPC_FLAGS_NOREPLY;
2N/A msg = (char *)hdr;
2N/A put_flags(flags, &ptr);
2N/A put_long(interfaceIndex, &ptr);
2N/A put_string(name, &ptr);
2N/A put_string(regtype, &ptr);
2N/A put_string(domain, &ptr);
2N/A put_string(host, &ptr);
2N/A *ptr++ = port.b[0];
2N/A *ptr++ = port.b[1];
2N/A put_short(txtLen, &ptr);
2N/A put_rdata(txtLen, txtRecord, &ptr);
2N/A
2N/A sdr = connect_to_server();
2N/A if (!sdr) goto error;
2N/A err = deliver_request(msg, sdr, 1);
2N/A if (err)
2N/A {
2N/A DNSServiceRefDeallocate(sdr);
2N/A return err;
2N/A }
2N/A
2N/A sdr->op = reg_service_request;
2N/A sdr->process_reply = callBack ? handle_regservice_response : NULL;
2N/A sdr->app_callback = callBack;
2N/A sdr->app_context = context;
2N/A *sdRef = sdr;
2N/A
2N/A return err;
2N/A
2N/Aerror:
2N/A if (msg) free(msg);
2N/A if (*sdRef) { free(*sdRef); *sdRef = NULL; }
2N/A return kDNSServiceErr_Unknown;
2N/A }
2N/A
2N/Astatic void handle_enumeration_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
2N/A {
2N/A DNSServiceFlags flags;
2N/A uint32_t interfaceIndex;
2N/A DNSServiceErrorType err;
2N/A char domain[kDNSServiceMaxDomainName];
2N/A int str_error = 0;
2N/A (void)hdr;//Unused
2N/A
2N/A flags = get_flags(&data);
2N/A interfaceIndex = get_long(&data);
2N/A err = get_error_code(&data);
2N/A if (get_string(&data, domain, kDNSServiceMaxDomainName) < 0) str_error = 1;
2N/A if (!err && str_error) err = kDNSServiceErr_Unknown;
2N/A ((DNSServiceDomainEnumReply)sdr->app_callback)(sdr, flags, interfaceIndex, err, domain, sdr->app_context);
2N/A }
2N/A
2N/ADNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
2N/A (
2N/A DNSServiceRef *sdRef,
2N/A DNSServiceFlags flags,
2N/A uint32_t interfaceIndex,
2N/A DNSServiceDomainEnumReply callBack,
2N/A void *context
2N/A )
2N/A {
2N/A char *msg = NULL, *ptr;
2N/A size_t len;
2N/A ipc_msg_hdr *hdr;
2N/A DNSServiceRef sdr;
2N/A DNSServiceErrorType err;
2N/A int f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0;
2N/A int f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0;
2N/A if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
2N/A
2N/A if (!sdRef) return kDNSServiceErr_BadParam;
2N/A *sdRef = NULL;
2N/A
2N/A len = sizeof(DNSServiceFlags);
2N/A len += sizeof(uint32_t);
2N/A
2N/A hdr = create_hdr(enumeration_request, &len, &ptr, 1);
2N/A if (!hdr) goto error;
2N/A msg = (void *)hdr;
2N/A
2N/A put_flags(flags, &ptr);
2N/A put_long(interfaceIndex, &ptr);
2N/A
2N/A sdr = connect_to_server();
2N/A if (!sdr) goto error;
2N/A err = deliver_request(msg, sdr, 1);
2N/A if (err)
2N/A {
2N/A DNSServiceRefDeallocate(sdr);
2N/A return err;
2N/A }
2N/A
2N/A sdr->op = enumeration_request;
2N/A sdr->process_reply = handle_enumeration_response;
2N/A sdr->app_callback = callBack;
2N/A sdr->app_context = context;
2N/A *sdRef = sdr;
2N/A return err;
2N/A
2N/Aerror:
2N/A if (msg) free(msg);
2N/A if (*sdRef) { free(*sdRef); *sdRef = NULL; }
2N/A return kDNSServiceErr_Unknown;
2N/A }
2N/A
2N/Astatic void handle_regrecord_response(DNSServiceRef sdr, ipc_msg_hdr *hdr, char *data)
2N/A {
2N/A DNSServiceFlags flags;
2N/A uint32_t interfaceIndex;
2N/A DNSServiceErrorType errorCode;
2N/A DNSRecordRef rref = hdr->client_context.context;
2N/A
2N/A if (sdr->op != connection)
2N/A {
2N/A rref->app_callback(rref->sdr, rref, 0, kDNSServiceErr_Unknown, rref->app_context);
2N/A return;
2N/A }
2N/A flags = get_flags(&data);
2N/A interfaceIndex = get_long(&data);
2N/A errorCode = get_error_code(&data);
2N/A
2N/A rref->app_callback(rref->sdr, rref, flags, errorCode, rref->app_context);
2N/A }
2N/A
2N/ADNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef)
2N/A {
2N/A if (!sdRef) return kDNSServiceErr_BadParam;
2N/A *sdRef = connect_to_server();
2N/A if (!*sdRef)
2N/A return kDNSServiceErr_Unknown;
2N/A (*sdRef)->op = connection;
2N/A (*sdRef)->process_reply = handle_regrecord_response;
2N/A return 0;
2N/A }
2N/A
2N/ADNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
2N/A (
2N/A DNSServiceRef sdRef,
2N/A DNSRecordRef *RecordRef,
2N/A DNSServiceFlags flags,
2N/A uint32_t interfaceIndex,
2N/A const char *fullname,
2N/A uint16_t rrtype,
2N/A uint16_t rrclass,
2N/A uint16_t rdlen,
2N/A const void *rdata,
2N/A uint32_t ttl,
2N/A DNSServiceRegisterRecordReply callBack,
2N/A void *context
2N/A )
2N/A {
2N/A char *msg = NULL, *ptr;
2N/A size_t len;
2N/A ipc_msg_hdr *hdr = NULL;
2N/A DNSServiceRef tmp = NULL;
2N/A DNSRecordRef rref = NULL;
2N/A int f1 = (flags & kDNSServiceFlagsShared) != 0;
2N/A int f2 = (flags & kDNSServiceFlagsUnique) != 0;
2N/A if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
2N/A
2N/A if (!sdRef || sdRef->op != connection || sdRef->sockfd < 0)
2N/A return kDNSServiceErr_BadReference;
2N/A *RecordRef = NULL;
2N/A
2N/A len = sizeof(DNSServiceFlags);
2N/A len += 2 * sizeof(uint32_t); // interfaceIndex, ttl
2N/A len += 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen
2N/A len += strlen(fullname) + 1;
2N/A len += rdlen;
2N/A
2N/A hdr = create_hdr(reg_record_request, &len, &ptr, 0);
2N/A if (!hdr) goto error;
2N/A msg = (char *)hdr;
2N/A put_flags(flags, &ptr);
2N/A put_long(interfaceIndex, &ptr);
2N/A put_string(fullname, &ptr);
2N/A put_short(rrtype, &ptr);
2N/A put_short(rrclass, &ptr);
2N/A put_short(rdlen, &ptr);
2N/A put_rdata(rdlen, rdata, &ptr);
2N/A put_long(ttl, &ptr);
2N/A
2N/A rref = malloc(sizeof(_DNSRecordRef_t));
2N/A if (!rref) goto error;
2N/A rref->app_context = context;
2N/A rref->app_callback = callBack;
2N/A rref->record_index = sdRef->max_index++;
2N/A rref->sdr = sdRef;
2N/A *RecordRef = rref;
2N/A hdr->client_context.context = rref;
2N/A hdr->reg_index = rref->record_index;
2N/A
2N/A return deliver_request(msg, sdRef, 0);
2N/A
2N/Aerror:
2N/A if (rref) free(rref);
2N/A if (tmp) free(tmp);
2N/A if (hdr) free(hdr);
2N/A return kDNSServiceErr_Unknown;
2N/A }
2N/A
2N/A//sdRef returned by DNSServiceRegister()
2N/ADNSServiceErrorType DNSSD_API DNSServiceAddRecord
2N/A (
2N/A DNSServiceRef sdRef,
2N/A DNSRecordRef *RecordRef,
2N/A DNSServiceFlags flags,
2N/A uint16_t rrtype,
2N/A uint16_t rdlen,
2N/A const void *rdata,
2N/A uint32_t ttl
2N/A )
2N/A {
2N/A ipc_msg_hdr *hdr;
2N/A size_t len = 0;
2N/A char *ptr;
2N/A DNSRecordRef rref;
2N/A
2N/A if (!sdRef || (sdRef->op != reg_service_request) || !RecordRef)
2N/A return kDNSServiceErr_BadReference;
2N/A *RecordRef = NULL;
2N/A
2N/A len += 2 * sizeof(uint16_t); //rrtype, rdlen
2N/A len += rdlen;
2N/A len += sizeof(uint32_t);
2N/A len += sizeof(DNSServiceFlags);
2N/A
2N/A hdr = create_hdr(add_record_request, &len, &ptr, 0);
2N/A if (!hdr) return kDNSServiceErr_Unknown;
2N/A put_flags(flags, &ptr);
2N/A put_short(rrtype, &ptr);
2N/A put_short(rdlen, &ptr);
2N/A put_rdata(rdlen, rdata, &ptr);
2N/A put_long(ttl, &ptr);
2N/A
2N/A rref = malloc(sizeof(_DNSRecordRef_t));
2N/A if (!rref) goto error;
2N/A rref->app_context = NULL;
2N/A rref->app_callback = NULL;
2N/A rref->record_index = sdRef->max_index++;
2N/A rref->sdr = sdRef;
2N/A *RecordRef = rref;
2N/A hdr->client_context.context = rref;
2N/A hdr->reg_index = rref->record_index;
2N/A return deliver_request((char *)hdr, sdRef, 0);
2N/A
2N/Aerror:
2N/A if (hdr) free(hdr);
2N/A if (rref) free(rref);
2N/A if (*RecordRef) *RecordRef = NULL;
2N/A return kDNSServiceErr_Unknown;
2N/A}
2N/A
2N/A//DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
2N/ADNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
2N/A (
2N/A DNSServiceRef sdRef,
2N/A DNSRecordRef RecordRef,
2N/A DNSServiceFlags flags,
2N/A uint16_t rdlen,
2N/A const void *rdata,
2N/A uint32_t ttl
2N/A )
2N/A {
2N/A ipc_msg_hdr *hdr;
2N/A size_t len = 0;
2N/A char *ptr;
2N/A
2N/A if (!sdRef) return kDNSServiceErr_BadReference;
2N/A
2N/A len += sizeof(uint16_t);
2N/A len += rdlen;
2N/A len += sizeof(uint32_t);
2N/A len += sizeof(DNSServiceFlags);
2N/A
2N/A hdr = create_hdr(update_record_request, &len, &ptr, 0);
2N/A if (!hdr) return kDNSServiceErr_Unknown;
2N/A hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX;
2N/A put_flags(flags, &ptr);
2N/A put_short(rdlen, &ptr);
2N/A put_rdata(rdlen, rdata, &ptr);
2N/A put_long(ttl, &ptr);
2N/A return deliver_request((char *)hdr, sdRef, 0);
2N/A }
2N/A
2N/ADNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
2N/A (
2N/A DNSServiceRef sdRef,
2N/A DNSRecordRef RecordRef,
2N/A DNSServiceFlags flags
2N/A )
2N/A {
2N/A ipc_msg_hdr *hdr;
2N/A size_t len = 0;
2N/A char *ptr;
2N/A DNSServiceErrorType err;
2N/A
2N/A if (!sdRef || !RecordRef || !sdRef->max_index)
2N/A return kDNSServiceErr_BadReference;
2N/A
2N/A len += sizeof(flags);
2N/A hdr = create_hdr(remove_record_request, &len, &ptr, 0);
2N/A if (!hdr) return kDNSServiceErr_Unknown;
2N/A hdr->reg_index = RecordRef->record_index;
2N/A put_flags(flags, &ptr);
2N/A err = deliver_request((char *)hdr, sdRef, 0);
2N/A if (!err) free(RecordRef);
2N/A return err;
2N/A }
2N/A
2N/ADNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
2N/A (
2N/A DNSServiceFlags flags,
2N/A uint32_t interfaceIndex,
2N/A const char *fullname,
2N/A uint16_t rrtype,
2N/A uint16_t rrclass,
2N/A uint16_t rdlen,
2N/A const void *rdata
2N/A )
2N/A {
2N/A char *ptr;
2N/A size_t len;
2N/A ipc_msg_hdr *hdr;
2N/A DNSServiceRef tmp;
2N/A
2N/A len = sizeof(DNSServiceFlags);
2N/A len += sizeof(uint32_t);
2N/A len += strlen(fullname) + 1;
2N/A len += 3 * sizeof(uint16_t);
2N/A len += rdlen;
2N/A tmp = connect_to_server();
2N/A if (!tmp) return(kDNSServiceErr_Unknown);
2N/A hdr = create_hdr(reconfirm_record_request, &len, &ptr, 1);
2N/A if (!hdr) return(kDNSServiceErr_Unknown);
2N/A
2N/A put_flags(flags, &ptr);
2N/A put_long(interfaceIndex, &ptr);
2N/A put_string(fullname, &ptr);
2N/A put_short(rrtype, &ptr);
2N/A put_short(rrclass, &ptr);
2N/A put_short(rdlen, &ptr);
2N/A put_rdata(rdlen, rdata, &ptr);
2N/A ConvertHeaderBytes(hdr);
2N/A write_all(tmp->sockfd, (char *)hdr, (int) len);
2N/A free(hdr);
2N/A DNSServiceRefDeallocate(tmp);
2N/A return(kDNSServiceErr_NoError);
2N/A }
2N/A