summaryrefslogtreecommitdiff
path: root/sd
diff options
context:
space:
mode:
authorSiqi LIU <yy_sq_000@Siqi-PC.(none)>2013-08-15 15:18:33 +0200
committersiqi <me@siqi.fr>2013-08-16 16:41:50 +0200
commit03fd0a02f2c0868c40853aa974ed20b8026fed17 (patch)
tree006c8938ee39063b317209d19840ac258ea5f6fa /sd
parent61a2c9fbacebb15511dfc233ffbd25937ea2d04f (diff)
build mDNSResponder on Windows within LibO
Change-Id: I6973be21f6f4009d6934220f978e9369fef67ede
Diffstat (limited to 'sd')
-rw-r--r--sd/Library_sd.mk17
-rw-r--r--sd/source/ui/remotecontrol/AvahiNetworkService.cxx2
-rw-r--r--sd/source/ui/remotecontrol/DiscoveryService.cxx10
-rw-r--r--sd/source/ui/remotecontrol/OSXNetworkService.mm2
-rwxr-xr-xsd/source/ui/remotecontrol/WINNetworkService.cxx19
-rwxr-xr-xsd/source/ui/remotecontrol/WINNetworkService.hxx26
-rw-r--r--sd/source/ui/remotecontrol/ZeroconfService.hxx2
-rwxr-xr-xsd/source/ui/remotecontrol/mDNSResponder/CommonServices.h1537
-rwxr-xr-xsd/source/ui/remotecontrol/mDNSResponder/DebugServices.c3075
-rwxr-xr-xsd/source/ui/remotecontrol/mDNSResponder/DebugServices.h1607
-rwxr-xr-xsd/source/ui/remotecontrol/mDNSResponder/GenLinkedList.c319
-rwxr-xr-xsd/source/ui/remotecontrol/mDNSResponder/GenLinkedList.h90
-rwxr-xr-xsd/source/ui/remotecontrol/mDNSResponder/dllmain.c113
-rwxr-xr-xsd/source/ui/remotecontrol/mDNSResponder/dns_sd.h2492
-rwxr-xr-xsd/source/ui/remotecontrol/mDNSResponder/dnssd_clientlib.c366
-rwxr-xr-xsd/source/ui/remotecontrol/mDNSResponder/dnssd_clientstub.c2206
-rwxr-xr-xsd/source/ui/remotecontrol/mDNSResponder/dnssd_ipc.c161
-rwxr-xr-xsd/source/ui/remotecontrol/mDNSResponder/dnssd_ipc.h223
18 files changed, 12263 insertions, 4 deletions
diff --git a/sd/Library_sd.mk b/sd/Library_sd.mk
index 2adb1595a654..e791d03488e6 100644
--- a/sd/Library_sd.mk
+++ b/sd/Library_sd.mk
@@ -562,6 +562,23 @@ $(eval $(call gb_Library_add_exception_objects,sd,\
sd/source/ui/remotecontrol/DiscoveryService \
))
+ifeq ($(OS),WNT)
+
+$(eval $(call gb_Library_add_exception_objects,sd,\
+ sd/source/ui/remotecontrol/WINNetworkService \
+))
+
+$(eval $(call gb_Library_add_cobjects,sd,\
+ sd/source/ui/remotecontrol/mDNSResponder/DebugServices \
+ sd/source/ui/remotecontrol/mDNSResponder/dnssd_clientlib \
+ sd/source/ui/remotecontrol/mDNSResponder/dnssd_clientstub \
+ sd/source/ui/remotecontrol/mDNSResponder/dnssd_ipc \
+ sd/source/ui/remotecontrol/mDNSResponder/GenLinkedList \
+ sd/source/ui/remotecontrol/mDNSResponder/dllmain \
+))
+
+endif
+
endif
$(eval $(call gb_Library_add_defs,sd,\
diff --git a/sd/source/ui/remotecontrol/AvahiNetworkService.cxx b/sd/source/ui/remotecontrol/AvahiNetworkService.cxx
index 19f9f842309a..8fc4eb7216bb 100644
--- a/sd/source/ui/remotecontrol/AvahiNetworkService.cxx
+++ b/sd/source/ui/remotecontrol/AvahiNetworkService.cxx
@@ -95,7 +95,7 @@ static void create_services(AvahiClient *c) {
if (avahi_entry_group_is_empty(group)) {
fprintf(stderr, "Adding service '%s'\n", avahiService->getName().c_str());
snprintf(r, sizeof(r), "random=%i", rand());
- if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, static_cast<AvahiPublishFlags>(0), avahiService->getName().c_str(), "_impressremote._tcp", NULL, NULL, 1599, "local", r, NULL)) < 0) {
+ if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, static_cast<AvahiPublishFlags>(0), avahiService->getName().c_str(), kREG_TYPE, NULL, NULL, 1599, "local", r, NULL)) < 0) {
if (ret == AVAHI_ERR_COLLISION){
/* A service name collision with a local service happened. Let's
diff --git a/sd/source/ui/remotecontrol/DiscoveryService.cxx b/sd/source/ui/remotecontrol/DiscoveryService.cxx
index 22aca47fd33f..94252f7f4603 100644
--- a/sd/source/ui/remotecontrol/DiscoveryService.cxx
+++ b/sd/source/ui/remotecontrol/DiscoveryService.cxx
@@ -27,6 +27,8 @@
#include <winsock2.h>
#include <ws2tcpip.h>
+
+ #include "WINNetworkService.hxx"
typedef int socklen_t;
#else
#include <unistd.h>
@@ -70,6 +72,10 @@ DiscoveryService::DiscoveryService()
zService = new AvahiNetworkService(hostname);
#endif
+#ifdef WIN32
+ zService = new WINNetworkService();
+#endif
+
if (zService)
zService->setup();
@@ -111,9 +117,9 @@ DiscoveryService::DiscoveryService()
DiscoveryService::~DiscoveryService()
{
#ifdef WNT
- closesocket( mSocket );
+ closesocket( mSocket );
#else
- close( mSocket );
+ close( mSocket );
#endif
if (zService)
diff --git a/sd/source/ui/remotecontrol/OSXNetworkService.mm b/sd/source/ui/remotecontrol/OSXNetworkService.mm
index d7f3ebc3ba0b..892439951e0a 100644
--- a/sd/source/ui/remotecontrol/OSXNetworkService.mm
+++ b/sd/source/ui/remotecontrol/OSXNetworkService.mm
@@ -17,7 +17,7 @@
- (void) publishImpressRemoteServiceOnLocalNetworkWithName:(NSString *)sName
{
- netService = [[NSNetService alloc] initWithDomain:@"local" type:@"_impressremote._tcp" name:sName port:1599];
+ netService = [[NSNetService alloc] initWithDomain:@"local" type:@kREG_TYPE name:sName port:1599];
if (netService != nil)
{
diff --git a/sd/source/ui/remotecontrol/WINNetworkService.cxx b/sd/source/ui/remotecontrol/WINNetworkService.cxx
new file mode 100755
index 000000000000..341b01e2da0c
--- /dev/null
+++ b/sd/source/ui/remotecontrol/WINNetworkService.cxx
@@ -0,0 +1,19 @@
+#include <string>
+#include <iostream>
+#include "WINNetworkService.hxx"
+#include "mDNSResponder/dns_sd.h"
+
+void sd::WINNetworkService::setup()
+{
+ DNSServiceErrorType err = DNSServiceRegister(&client, 0, 0, NULL, kREG_TYPE, NULL, NULL, 1599, 1, "", NULL, this );
+
+ if ( err == 0 ) {
+ SAL_INFO("sd", "Windows bonjour service setup");
+ } // Fail silently otherwise
+}
+
+void sd::WINNetworkService::clear()
+{
+ DNSServiceRefDeallocate(client);
+ SAL_INFO("sd", "Windows mDNSResponder removed");
+} \ No newline at end of file
diff --git a/sd/source/ui/remotecontrol/WINNetworkService.hxx b/sd/source/ui/remotecontrol/WINNetworkService.hxx
new file mode 100755
index 000000000000..bf59d7ae32e6
--- /dev/null
+++ b/sd/source/ui/remotecontrol/WINNetworkService.hxx
@@ -0,0 +1,26 @@
+#ifndef WINNETWORKSERVICE_HXX
+#define WINNETWORKSERVICE_HXX
+
+#include <string>
+#undef WB_LEFT
+#undef WB_RIGHT
+#include "mDNSResponder/dns_sd.h"
+#include "ZeroconfService.hxx"
+
+namespace sd{
+ class WINNetworkService : public ZeroconfService
+ {
+ private:
+ DNSServiceRef client;
+
+ public:
+ WINNetworkService(const std::string& aname = "", unsigned int aport = 1599)
+ : ZeroconfService(aname, aport), client(0) {}
+ virtual ~WINNetworkService(){}
+
+ void clear();
+ void setup();
+
+ };
+}
+#endif \ No newline at end of file
diff --git a/sd/source/ui/remotecontrol/ZeroconfService.hxx b/sd/source/ui/remotecontrol/ZeroconfService.hxx
index 0418dd8c28e6..246efced5683 100644
--- a/sd/source/ui/remotecontrol/ZeroconfService.hxx
+++ b/sd/source/ui/remotecontrol/ZeroconfService.hxx
@@ -19,6 +19,8 @@
#define PORT_DISCOVERY 1598
#define BUFFER_SIZE 200
+#define kREG_TYPE "_impressremote._tcp"
+
#define CHARSET RTL_TEXTENCODING_UTF8
struct sockaddr_in;
diff --git a/sd/source/ui/remotecontrol/mDNSResponder/CommonServices.h b/sd/source/ui/remotecontrol/mDNSResponder/CommonServices.h
new file mode 100755
index 000000000000..8326ea0e0e16
--- /dev/null
+++ b/sd/source/ui/remotecontrol/mDNSResponder/CommonServices.h
@@ -0,0 +1,1537 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @header CommonServices
+
+ Common Services for Mac OS X, Linux, Palm, VxWorks, Windows, and Windows CE.
+ */
+
+#ifndef __COMMON_SERVICES__
+#define __COMMON_SERVICES__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if 0
+#pragma mark == Target ==
+#endif
+
+//===========================================================================================================================
+// Target
+//===========================================================================================================================
+
+// Macintosh
+
+#if ( !defined( TARGET_OS_MAC ) )
+ #if ( ( macintosh || __MACH__ ) && !KERNEL )
+// ConditionalMacros.h in CoreServices will define this TARGET_* flag.
+ #else
+ #define TARGET_OS_MAC 0
+ #endif
+#endif
+
+#if ( !defined( TARGET_API_MAC_OSX_KERNEL ) )
+ #if ( __MACH__ && KERNEL )
+ #define TARGET_API_MAC_OSX_KERNEL 1
+ #else
+ #define TARGET_API_MAC_OSX_KERNEL 0
+ #endif
+#endif
+
+// FreeBSD
+
+#if ( !defined( TARGET_OS_FREEBSD ) )
+ #if ( defined( __FreeBSD__ ) )
+ #define TARGET_OS_FREEBSD 1
+ #else
+ #define TARGET_OS_FREEBSD 0
+ #endif
+#endif
+
+// Linux
+
+#if ( !defined( TARGET_OS_LINUX ) )
+ #if ( defined( __linux__ ) )
+ #define TARGET_OS_LINUX 1
+ #else
+ #define TARGET_OS_LINUX 0
+ #endif
+#endif
+
+// Solaris
+
+#if ( !defined( TARGET_OS_SOLARIS ) )
+ #if ( defined(solaris) || (defined(__SVR4) && defined(sun)) )
+ #define TARGET_OS_SOLARIS 1
+ #else
+ #define TARGET_OS_SOLARIS 0
+ #endif
+#endif
+
+// Palm
+
+#if ( !defined( TARGET_OS_PALM ) )
+ #if ( defined( __PALMOS_TRAPS__ ) || defined( __PALMOS_ARMLET__ ) )
+ #define TARGET_OS_PALM 1
+ #else
+ #define TARGET_OS_PALM 0
+ #endif
+#endif
+
+// VxWorks
+
+#if ( !defined( TARGET_OS_VXWORKS ) )
+
+// No predefined macro for VxWorks so just assume VxWorks if nothing else is set.
+
+ #if ( !macintosh && !__MACH__ && !defined( __FreeBSD__ ) && !defined( __linux__ ) && !defined ( __SVR4 ) && !defined ( __sun ) && !defined( __PALMOS_TRAPS__ ) && !defined( __PALMOS_ARMLET__ ) && !defined( _WIN32 ) )
+ #define TARGET_OS_VXWORKS 1
+ #else
+ #define TARGET_OS_VXWORKS 0
+ #endif
+#endif
+
+// Windows
+
+#if ( !defined( TARGET_OS_WIN32 ) )
+ #if ( macintosh || __MACH__ )
+// ConditionalMacros.h in CoreServices will define this TARGET_* flag.
+ #else
+ #if ( defined( _WIN32 ) )
+ #define TARGET_OS_WIN32 1
+ #else
+ #define TARGET_OS_WIN32 0
+ #endif
+ #endif
+#endif
+
+// Windows CE
+
+#if ( !defined( TARGET_OS_WINDOWS_CE ) )
+ #if ( defined( _WIN32_WCE ) )
+ #define TARGET_OS_WINDOWS_CE 1
+ #else
+ #define TARGET_OS_WINDOWS_CE 0
+ #endif
+#endif
+
+#if 0
+#pragma mark == Includes ==
+#endif
+
+//===========================================================================================================================
+// Includes
+//===========================================================================================================================
+
+#if ( !KERNEL )
+ #if defined(WIN32) && !defined(_WSPIAPI_COUNTOF)
+ #define _WSPIAPI_COUNTOF(_Array) (sizeof(_Array) / sizeof(_Array[0]))
+ #endif
+ #include <stddef.h>
+#endif
+
+#if ( ( macintosh || __MACH__ ) && !KERNEL )
+
+ #if ( defined( __MWERKS__ ) )
+ #if ( __option( c9x ) )
+ #include <stdbool.h>
+ #endif
+ #else
+ #include <stdbool.h>
+ #endif
+
+ #include <stdint.h>
+
+ #if ( __MACH__ )
+
+// Mac OS X
+
+ #include <sys/types.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include <fcntl.h>
+ #include <pthread.h>
+ #include <sys/ioctl.h>
+ #include <sys/socket.h>
+ #include <unistd.h>
+
+ #else
+
+// Classic Mac OS
+
+ #include <ConditionalMacros.h>
+ #include <MacTypes.h>
+
+ #endif
+
+#elif ( KERNEL )
+
+// Mac OS X Kernel
+
+ #include <stdint.h>
+
+ #include <libkern/OSTypes.h>
+ #include <sys/types.h>
+
+#elif ( TARGET_OS_FREEBSD )
+
+// FreeBSD
+ #include <stdint.h>
+ #include <pthread.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include <sys/socket.h>
+
+#elif ( TARGET_OS_LINUX )
+
+// Linux
+
+ #include <stdint.h>
+ #include <arpa/inet.h>
+
+#elif ( TARGET_OS_SOLARIS )
+
+// Solaris
+
+ #include <stdint.h>
+
+ #include <arpa/inet.h>
+ #include <arpa/nameser.h>
+
+ #if ( defined( BYTE_ORDER ) && defined( LITTLE_ENDIAN ) && ( BYTE_ORDER == LITTLE_ENDIAN ) )
+ #define TARGET_RT_LITTLE_ENDIAN 1
+ #endif
+ #if ( defined( BYTE_ORDER ) && defined( BIG_ENDIAN ) && ( BYTE_ORDER == BIG_ENDIAN ) )
+ #define TARGET_RT_BIG_ENDIAN 1
+ #endif
+
+#elif ( TARGET_OS_PALM )
+
+// Palm (no special includes yet).
+
+#elif ( TARGET_OS_VXWORKS )
+
+// VxWorks
+
+ #include "vxWorks.h"
+
+#elif ( TARGET_OS_WIN32 )
+
+// Windows
+
+ #if ( !defined( WIN32_WINDOWS ) )
+ #define WIN32_WINDOWS 0x0401
+ #endif
+
+ #if ( !defined( _WIN32_WINDOWS ) )
+ #define _WIN32_WINDOWS 0x0401
+ #endif
+
+ #if ( !defined( WIN32_LEAN_AND_MEAN ) )
+ #define WIN32_LEAN_AND_MEAN // Needed to avoid redefinitions by Windows interfaces.
+ #endif
+
+ #if ( defined( __MWERKS__ ) )
+
+ #if ( __option( c9x ) )
+ #include <stdbool.h>
+ #endif
+
+ #include <stdint.h>
+
+ #elif ( defined( _MSC_VER ) )
+
+ #pragma warning( disable:4127 ) // Disable "conditional expression is constant" warning for debug macros.
+ #pragma warning( disable:4706 ) // Disable "assignment within conditional expression" for Microsoft headers.
+
+ #endif
+
+ #include <windows.h>
+ #include <winsock2.h>
+ #include <Ws2tcpip.h>
+
+ #if ( defined( _MSC_VER ) )
+ #pragma warning( default:4706 )
+ #endif
+
+#else
+ #error unknown OS - update this file to support your OS
+#endif
+
+#if ( !defined( TARGET_BUILD_MAIN ) )
+ #if ( !TARGET_OS_VXWORKS )
+ #define TARGET_BUILD_MAIN 1
+ #endif
+#endif
+
+#if ( __GNUC__ || !TARGET_OS_VXWORKS )
+ #define TARGET_LANGUAGE_C_LIKE 1
+#else
+ #define TARGET_LANGUAGE_C_LIKE 0
+#endif
+
+#if 0
+#pragma mark == CPU ==
+#endif
+
+//===========================================================================================================================
+// CPU
+//===========================================================================================================================
+
+// PowerPC
+
+#if ( !defined( TARGET_CPU_PPC ) )
+ #if ( defined( __ppc__ ) || defined( __PPC__ ) || defined( powerpc ) || defined( ppc ) || defined( _M_MPPC ) )
+ #define TARGET_CPU_PPC 1
+ #else
+ #define TARGET_CPU_PPC 0
+ #endif
+#endif
+
+// x86
+
+#if ( !defined( TARGET_CPU_X86 ) )
+ #if ( __INTEL__ || defined( __i386__ ) || defined( i386 ) || defined( intel ) || defined( _M_IX86 ) )
+ #define TARGET_CPU_X86 1
+ #else
+ #define TARGET_CPU_X86 0
+ #endif
+#endif
+
+// MIPS
+
+#if ( !defined( TARGET_CPU_MIPS ) )
+ #if ( __MIPS__ || defined( MIPS32 ) || defined( R3000 ) || defined( R4000 ) || defined( R4650 ) || defined( _M_MRX000 ) )
+ #define TARGET_CPU_MIPS 1
+ #else
+ #define TARGET_CPU_MIPS 0
+ #endif
+#endif
+
+#if ( !defined( TARGET_CPU_PPC ) && !defined( TARGET_CPU_X86 ) && !defined( TARGET_CPU_MIPS ) )
+ #error unknown CPU - update this file to support your CPU
+#endif
+
+#if 0
+#pragma mark == Byte Order ==
+#endif
+
+//===========================================================================================================================
+// Byte Order
+//===========================================================================================================================
+
+// TARGET_RT_LITTLE_ENDIAN
+
+#if ( !defined( TARGET_RT_LITTLE_ENDIAN ) )
+ #if ( MIPSEL || IL_LITTLE_ENDIAN || defined( __LITTLE_ENDIAN__ ) || \
+ ( defined( BYTE_ORDER ) && defined( LITTLE_ENDIAN ) && ( BYTE_ORDER == LITTLE_ENDIAN ) ) || \
+ ( defined( _BYTE_ORDER ) && defined( _LITTLE_ENDIAN ) && ( _BYTE_ORDER == _LITTLE_ENDIAN ) ) || \
+ ( defined( __BYTE_ORDER ) && defined( __LITTLE_ENDIAN ) && ( __BYTE_ORDER == __LITTLE_ENDIAN ) ) || \
+ TARGET_CPU_X86 || ( defined( TARGET_RT_BIG_ENDIAN ) && !TARGET_RT_BIG_ENDIAN ) )
+ #define TARGET_RT_LITTLE_ENDIAN 1
+ #else
+ #define TARGET_RT_LITTLE_ENDIAN 0
+ #endif
+#endif
+
+// TARGET_RT_BIG_ENDIAN
+
+#if ( !defined( TARGET_RT_BIG_ENDIAN ) )
+ #if ( MIPSEB || IL_BIG_ENDIAN || defined( __BIG_ENDIAN__ ) || \
+ ( defined( BYTE_ORDER ) && defined( BIG_ENDIAN ) && ( BYTE_ORDER == BIG_ENDIAN ) ) || \
+ ( defined( _BYTE_ORDER ) && defined( _BIG_ENDIAN ) && ( _BYTE_ORDER == _BIG_ENDIAN ) ) || \
+ ( defined( __BYTE_ORDER ) && defined( __BIG_ENDIAN ) && ( __BYTE_ORDER == __BIG_ENDIAN ) ) || \
+ ( defined( TARGET_RT_LITTLE_ENDIAN ) && !TARGET_RT_LITTLE_ENDIAN ) )
+ #define TARGET_RT_BIG_ENDIAN 1
+ #else
+ #define TARGET_RT_BIG_ENDIAN 0
+ #endif
+#endif
+
+#if ( defined( TARGET_RT_LITTLE_ENDIAN ) && !defined( TARGET_RT_BIG_ENDIAN ) )
+ #if ( TARGET_RT_LITTLE_ENDIAN )
+ #define TARGET_RT_BIG_ENDIAN 0
+ #else
+ #define TARGET_RT_BIG_ENDIAN 1
+ #endif
+#endif
+
+#if ( defined( TARGET_RT_BIG_ENDIAN ) && !defined( TARGET_RT_LITTLE_ENDIAN ) )
+ #if ( TARGET_RT_BIG_ENDIAN )
+ #define TARGET_RT_LITTLE_ENDIAN 0
+ #else
+ #define TARGET_RT_LITTLE_ENDIAN 1
+ #endif
+#endif
+
+#if ( !defined( TARGET_RT_LITTLE_ENDIAN ) || !defined( TARGET_RT_BIG_ENDIAN ) )
+ #error unknown byte order - update this file to support your byte order
+#endif
+
+// TARGET_RT_BYTE_ORDER
+
+#if ( !defined( TARGET_RT_BYTE_ORDER_BIG_ENDIAN ) )
+ #define TARGET_RT_BYTE_ORDER_BIG_ENDIAN 1234
+#endif
+
+#if ( !defined( TARGET_RT_BYTE_ORDER_LITTLE_ENDIAN ) )
+ #define TARGET_RT_BYTE_ORDER_LITTLE_ENDIAN 4321
+#endif
+
+#if ( !defined( TARGET_RT_BYTE_ORDER ) )
+ #if ( TARGET_RT_LITTLE_ENDIAN )
+ #define TARGET_RT_BYTE_ORDER TARGET_RT_BYTE_ORDER_LITTLE_ENDIAN
+ #else
+ #define TARGET_RT_BYTE_ORDER TARGET_RT_BYTE_ORDER_BIG_ENDIAN
+ #endif
+#endif
+
+#if 0
+#pragma mark == Constants ==
+#endif
+
+//===========================================================================================================================
+// Constants
+//===========================================================================================================================
+
+#if ( !TARGET_OS_MAC )
+ #define CR '\r'
+#endif
+
+#define LF '\n'
+#define CRSTR "\r"
+#define LFSTR "\n"
+#define CRLF "\r\n"
+#define CRCR "\r\r"
+
+#if 0
+#pragma mark == Compatibility ==
+#endif
+
+//===========================================================================================================================
+// Compatibility
+//===========================================================================================================================
+
+// Macros to allow the same code to work on Windows and other sockets API-compatible platforms.
+
+#if ( TARGET_OS_WIN32 )
+ #define close_compat( X ) closesocket( X )
+ #define errno_compat() (int) GetLastError()
+ #define set_errno_compat( X ) SetLastError( X )
+ #define EWOULDBLOCK_compat WSAEWOULDBLOCK
+ #define ETIMEDOUT_compat WSAETIMEDOUT
+ #define ENOTCONN_compat WSAENOTCONN
+ #define IsValidSocket( X ) ( ( X ) != INVALID_SOCKET )
+ #define kInvalidSocketRef INVALID_SOCKET
+ #if ( TARGET_LANGUAGE_C_LIKE )
+typedef SOCKET SocketRef;
+ #endif
+#else
+ #define close_compat( X ) close( X )
+ #define errno_compat() errno
+ #define set_errno_compat( X ) do { errno = ( X ); } while( 0 )
+ #define EWOULDBLOCK_compat EWOULDBLOCK
+ #define ETIMEDOUT_compat ETIMEDOUT
+ #define ENOTCONN_compat ENOTCONN
+ #define IsValidSocket( X ) ( ( X ) >= 0 )
+ #define kInvalidSocketRef -1
+ #if ( TARGET_LANGUAGE_C_LIKE )
+typedef int SocketRef;
+ #endif
+#endif
+
+// socklen_t is not defined on the following platforms so emulate it if not defined:
+//
+// - Pre-Panther Mac OS X. Panther defines SO_NOADDRERR so trigger off that.
+// - Windows SDK prior to 2003. 2003+ SDK's define EAI_AGAIN so trigger off that.
+// - VxWorks
+
+#if ( TARGET_LANGUAGE_C_LIKE )
+ #if ( ( TARGET_OS_MAC && !defined( SO_NOADDRERR ) ) || ( TARGET_OS_WIN32 && !defined( EAI_AGAIN ) ) || TARGET_OS_VXWORKS )
+typedef int socklen_t;
+ #endif
+#endif
+
+// ssize_t is not defined on the following platforms so emulate it if not defined:
+//
+// - Mac OS X when not building with BSD headers
+// - Windows
+
+#if ( TARGET_LANGUAGE_C_LIKE )
+ #if ( !defined(_SSIZE_T) && ( TARGET_OS_WIN32 || !defined( _BSD_SSIZE_T_DEFINED_ ) ) && !TARGET_OS_FREEBSD && !TARGET_OS_LINUX && !TARGET_OS_VXWORKS && !TARGET_OS_MAC)
+typedef int ssize_t;
+ #endif
+#endif
+
+// sockaddr_storage is not supported on non-IPv6 machines so alias it to an IPv4-compatible structure.
+
+#if ( TARGET_LANGUAGE_C_LIKE )
+ #if ( !defined( AF_INET6 ) )
+ #define sockaddr_storage sockaddr_in
+ #define ss_family sin_family
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined SOCKADDR_IS_IP_LOOPBACK
+
+ @abstract Determines if a sockaddr is an IPv4 or IPv6 loopback address (if IPv6 is supported).
+ */
+
+#if ( defined( AF_INET6 ) )
+ #define SOCKADDR_IS_IP_LOOPBACK( SA ) \
+ ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET ) \
+ ? ( ( (const struct sockaddr_in *)( SA ) )->sin_addr.s_addr == htonl( INADDR_LOOPBACK ) ) \
+ : ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET6 ) \
+ ? IN6_IS_ADDR_LOOPBACK( &( (const struct sockaddr_in6 *)( SA ) )->sin6_addr ) \
+ : 0
+#else
+ #define SOCKADDR_IS_IP_LOOPBACK( SA ) \
+ ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET ) \
+ ? ( ( (const struct sockaddr_in *)( SA ) )->sin_addr.s_addr == htonl( INADDR_LOOPBACK ) ) \
+ : 0
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined SOCKADDR_IS_IP_LINK_LOCAL
+
+ @abstract Determines if a sockaddr is an IPv4 or IPv6 link-local address (if IPv6 is supported).
+ */
+
+#if ( defined( AF_INET6 ) )
+ #define SOCKADDR_IS_IP_LINK_LOCAL( SA ) \
+ ( ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET ) \
+ ? ( ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 0 ] == 169 ) && \
+ ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 1 ] == 254 ) ) \
+ : IN6_IS_ADDR_LOOPBACK( &( (const struct sockaddr_in6 *)( SA ) )->sin6_addr ) )
+#else
+ #define SOCKADDR_IS_IP_LINK_LOCAL( SA ) \
+ ( ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET ) \
+ ? ( ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 0 ] == 169 ) && \
+ ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 1 ] == 254 ) ) \
+ : 0 )
+#endif
+
+// _beginthreadex and _endthreadex are not supported on Windows CE 2.1 or later (the C runtime issues with leaking
+// resources have apparently been resolved and they seem to have just ripped out support for the API) so map it to
+// CreateThread on Windows CE.
+
+#if ( TARGET_OS_WINDOWS_CE )
+ #define _beginthreadex_compat( SECURITY_PTR, STACK_SIZE, START_ADDRESS, ARG_LIST, FLAGS, THREAD_ID_PTR ) \
+ (uintptr_t) CreateThread( SECURITY_PTR, STACK_SIZE, (LPTHREAD_START_ROUTINE) START_ADDRESS, ARG_LIST, FLAGS, \
+ (LPDWORD) THREAD_ID_PTR )
+
+ #define _endthreadex_compat( RESULT ) ExitThread( (DWORD) RESULT )
+#elif ( TARGET_OS_WIN32 )
+ #define _beginthreadex_compat _beginthreadex
+ #define _endthreadex_compat _endthreadex
+#endif
+
+// The C99 "inline" keyword is not supported by Microsoft compilers, but they do support __inline so map it when needed.
+
+#if ( defined( _MSC_VER ) )
+ #define inline_compat __inline
+#else
+ #define inline_compat inline
+#endif
+
+// Calling conventions
+
+#if ( !defined( CALLBACK_COMPAT ) )
+ #if ( TARGET_OS_WIN32 || TARGET_OS_WINDOWS_CE )
+ #define CALLBACK_COMPAT CALLBACK
+ #else
+ #define CALLBACK_COMPAT
+ #endif
+#endif
+
+#if 0
+#pragma mark == Macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined kSizeCString
+
+ @abstract A meta-value to pass to supported routines to indicate the size should be calculated with strlen.
+ */
+
+#define kSizeCString ( (size_t) -1 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined sizeof_array
+
+ @abstract Determines the number of elements in an array.
+ */
+
+#define sizeof_array( X ) ( sizeof( X ) / sizeof( X[ 0 ] ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined sizeof_element
+
+ @abstract Determines the size of an array element.
+ */
+
+#define sizeof_element( X ) sizeof( X[ 0 ] )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined sizeof_string
+
+ @abstract Determines the size of a constant C string, excluding the null terminator.
+ */
+
+#define sizeof_string( X ) ( sizeof( ( X ) ) - 1 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined sizeof_field
+
+ @abstract Determines the size of a field of a type.
+ */
+
+#define sizeof_field( TYPE, FIELD ) sizeof( ( ( (TYPE *) 0 )->FIELD ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function RoundUp
+
+ @abstract Rounds X up to a multiple of Y.
+ */
+
+#define RoundUp( X, Y ) ( ( X ) + ( ( Y ) -( ( X ) % ( Y ) ) ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function IsAligned
+
+ @abstract Returns non-zero if X is aligned to a Y byte boundary and 0 if not. Y must be a power of 2.
+ */
+
+#define IsAligned( X, Y ) ( ( ( X ) &( ( Y ) -1 ) ) == 0 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function IsFieldAligned
+
+ @abstract Returns non-zero if FIELD of type TYPE is aligned to a Y byte boundary and 0 if not. Y must be a power of 2.
+ */
+
+#define IsFieldAligned( X, TYPE, FIELD, Y ) IsAligned( ( (uintptr_t)( X ) ) + offsetof( TYPE, FIELD ), ( Y ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function AlignDown
+
+ @abstract Aligns X down to a Y byte boundary. Y must be a power of 2.
+ */
+
+#define AlignDown( X, Y ) ( ( X ) &~( ( Y ) -1 ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function AlignUp
+
+ @abstract Aligns X up to a Y byte boundary. Y must be a power of 2.
+ */
+
+#define AlignUp( X, Y ) ( ( ( X ) + ( ( Y ) -1 ) ) & ~( ( Y ) -1 ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function Min
+
+ @abstract Returns the lesser of X and Y.
+ */
+
+#if ( !defined( Min ) )
+ #define Min( X, Y ) ( ( ( X ) < ( Y ) ) ? ( X ) : ( Y ) )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function Max
+
+ @abstract Returns the greater of X and Y.
+ */
+
+#if ( !defined( Max ) )
+ #define Max( X, Y ) ( ( ( X ) > ( Y ) ) ? ( X ) : ( Y ) )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function InsertBits
+
+ @abstract Inserts BITS (both 0 and 1 bits) into X, controlled by MASK and SHIFT, and returns the result.
+
+ @discussion
+
+ MASK is the bitmask of the bits in the final position.
+ SHIFT is the number of bits to shift left for 1 to reach the first bit position of MASK.
+
+ For example, if you wanted to insert 0x3 into the leftmost 4 bits of a 32-bit value:
+
+ InsertBits( 0, 0x3, 0xF0000000U, 28 ) == 0x30000000
+ */
+
+#define InsertBits( X, BITS, MASK, SHIFT ) ( ( ( X ) &~( MASK ) ) | ( ( ( BITS ) << ( SHIFT ) ) & ( MASK ) ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function ExtractBits
+
+ @abstract Extracts bits from X, controlled by MASK and SHIFT, and returns the result.
+
+ @discussion
+
+ MASK is the bitmask of the bits in the final position.
+ SHIFT is the number of bits to shift right to right justify MASK.
+
+ For example, if you had a 32-bit value (e.g. 0x30000000) wanted the left-most 4 bits (e.g. 3 in this example):
+
+ ExtractBits( 0x30000000U, 0xF0000000U, 28 ) == 0x3
+ */
+
+#define ExtractBits( X, MASK, SHIFT ) ( ( ( X ) >> ( SHIFT ) ) & ( ( MASK ) >> ( SHIFT ) ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function Stringify
+
+ @abstract Stringify's an expression.
+
+ @discussion
+
+ Stringify macros to process raw text passed via -D options to C string constants. The double-wrapping is necessary
+ because the C preprocessor doesn't perform its normal argument expansion pre-scan with stringified macros so the
+ -D macro needs to be expanded once via the wrapper macro then stringified so the raw text is stringified. Otherwise,
+ the replacement value would be used instead of the symbolic name (only for preprocessor symbols like #defines).
+
+ For example:
+
+ #define kMyConstant 1
+
+ printf( "%s", Stringify( kMyConstant ) ); // Prints "kMyConstant"
+ printf( "%s", StringifyExpansion( kMyConstant ) ); // Prints "1"
+
+ Non-preprocessor symbols do not have this issue. For example:
+
+ enum
+ {
+ kMyConstant = 1
+ };
+
+ printf( "%s", Stringify( kMyConstant ) ); // Prints "kMyConstant"
+ printf( "%s", StringifyExpansion( kMyConstant ) ); // Prints "kMyConstant"
+
+ See <http://gcc.gnu.org/onlinedocs/cpp/Argument-Prescan.html> for more info on C preprocessor pre-scanning.
+ */
+
+#define Stringify( X ) # X
+#define StringifyExpansion( X ) Stringify( X )
+
+#if 0
+#pragma mark == Types ==
+#endif
+
+#if ( TARGET_LANGUAGE_C_LIKE )
+//===========================================================================================================================
+// Standard Types
+//===========================================================================================================================
+
+#if ( !defined( INT8_MIN ) )
+
+ #define INT8_MIN SCHAR_MIN
+
+ #if ( defined( _MSC_VER ) )
+
+// C99 stdint.h not supported in VC++/VS.NET yet.
+
+typedef INT8 int8_t;
+typedef UINT8 uint8_t;
+typedef INT16 int16_t;
+typedef UINT16 uint16_t;
+typedef INT32 int32_t;
+typedef UINT32 uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+ #elif ( TARGET_OS_VXWORKS && ( TORNADO_VERSION < 220 ) )
+typedef long long int64_t;
+typedef unsigned long long uint64_t;
+ #endif
+
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
+
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
+
+typedef int8_t int_fast8_t;
+typedef int16_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef int64_t int_fast64_t;
+
+typedef uint8_t uint_fast8_t;
+typedef uint16_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+typedef uint64_t uint_fast64_t;
+
+ #if ( !defined( _MSC_VER ) || TARGET_OS_WINDOWS_CE )
+typedef long int intptr_t;
+typedef unsigned long int uintptr_t;
+ #endif
+
+#endif
+
+// Macros for minimum-width integer constants
+
+#if ( !defined( INT8_C ) )
+ #define INT8_C( value ) value
+#endif
+
+#if ( !defined( INT16_C ) )
+ #define INT16_C( value ) value
+#endif
+
+#if ( !defined( INT32_C ) )
+ #define INT32_C( value ) value ## L
+#endif
+
+#if ( !defined( INT64_C ) )
+ #if ( defined( _MSC_VER ) )
+ #define INT64_C( value ) value ## i64
+ #else
+ #define INT64_C( value ) value ## LL
+ #endif
+#endif
+
+#if ( !defined( UINT8_C ) )
+ #define UINT8_C( value ) value ## U
+#endif
+
+#if ( !defined( UINT16_C ) )
+ #define UINT16_C( value ) value ## U
+#endif
+
+#if ( !defined( UINT32_C ) )
+ #define UINT32_C( value ) value ## UL
+#endif
+
+#if ( !defined( UINT64_C ) )
+ #if ( defined( _MSC_VER ) )
+ #define UINT64_C( value ) value ## UI64
+ #else
+ #define UINT64_C( value ) value ## ULL
+ #endif
+#endif
+
+#if 0
+#pragma mark == bool ==
+#endif
+
+//===========================================================================================================================
+// Boolean Constants and Types
+//===========================================================================================================================
+
+// C++ defines bool, true, and false. Metrowerks allows this to be controlled by the "bool" option though.
+// C99 defines __bool_true_false_are_defined when bool, true, and false are defined.
+// MacTypes.h defines true and false (Mac builds only).
+//
+// Note: The Metrowerks has to be in its own block because Microsoft Visual Studio .NET does not completely
+// short-circuit and gets confused by the option( bool ) portion of the conditional.
+
+#if ( defined( __MWERKS__ ) )
+
+// Note: The following test is done on separate lines because CodeWarrior doesn't like it all on one line.
+
+ #if ( !__bool_true_false_are_defined && ( !defined( __cplusplus ) || !__option( bool ) ) )
+ #define COMMON_SERVICES_NEEDS_BOOL 1
+ #else
+ #define COMMON_SERVICES_NEEDS_BOOL 0
+ #endif
+
+// Workaround when building with CodeWarrior, but using the Apple stdbool.h header, which uses _Bool.
+
+ #if ( __bool_true_false_are_defined && !defined( __cplusplus ) && !__option( c9x ) )
+ #define _Bool int
+ #endif
+
+// Workaround when building with CodeWarrior for C++ with bool disabled and using the Apple stdbool.h header,
+// which defines true and false to map to C++ true and false (which are not enabled). Serenity Now!
+
+ #if ( __bool_true_false_are_defined && defined( __cplusplus ) && !__option( bool ) )
+ #define true 1
+ #define false 0
+ #endif
+#else
+ #define COMMON_SERVICES_NEEDS_BOOL ( !defined( __cplusplus ) && !__bool_true_false_are_defined )
+#endif
+
+#if ( COMMON_SERVICES_NEEDS_BOOL )
+
+typedef int bool;
+
+ #define bool bool
+
+ #if ( !defined( __MACTYPES__ ) && !defined( true ) && !defined( false ) )
+ #define true 1
+ #define false 0
+ #endif
+
+ #define __bool_true_false_are_defined 1
+#endif
+
+// IOKit IOTypes.h typedef's bool if TYPE_BOOL is not defined so define it here to prevent redefinition by IOTypes.h.
+
+#if ( TARGET_API_MAC_OSX_KERNEL )
+ #define TYPE_BOOL 1
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef CStr255
+
+ @abstract 255 character null-terminated (C-style) string.
+ */
+
+#if ( TARGET_LANGUAGE_C_LIKE )
+typedef char CStr255[ 256 ];
+#endif
+
+#endif // TARGET_LANGUAGE_C_LIKE
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined TYPE_LONGLONG_NATIVE
+
+ @abstract Defines whether long long (or its equivalent) is natively supported or requires special libraries.
+ */
+
+#if ( !defined( TYPE_LONGLONG_NATIVE ) )
+ #if ( !TARGET_OS_VXWORKS )
+ #define TYPE_LONGLONG_NATIVE 1
+ #else
+ #define TYPE_LONGLONG_NATIVE 0
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined long_long_compat
+
+ @abstract Compatibility type to map to the closest thing to long long and unsigned long long.
+
+ @discussion
+
+ Neither long long nor unsigned long long are supported by Microsoft compilers, but they do support proprietary
+ "__int64" and "unsigned __int64" equivalents so map to those types if the real long long is not supported.
+ */
+
+#if ( TARGET_LANGUAGE_C_LIKE )
+ #if ( TARGET_OS_WIN32 )
+typedef __int64 long_long_compat;
+typedef unsigned __int64 unsigned_long_long_compat;
+ #else
+typedef signed long long long_long_compat;
+typedef unsigned long long unsigned_long_long_compat;
+ #endif
+#endif
+
+#if 0
+#pragma mark == Errors ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @enum OSStatus
+
+ @abstract Status Code
+
+ @constant kNoErr 0 No error occurred.
+ @constant kInProgressErr 1 Operation in progress.
+ @constant kUnknownErr -6700 Unknown error occurred.
+ @constant kOptionErr -6701 Option was not acceptable.
+ @constant kSelectorErr -6702 Selector passed in is invalid or unknown.
+ @constant kExecutionStateErr -6703 Call made in the wrong execution state (e.g. called at interrupt time).
+ @constant kPathErr -6704 Path is invalid, too long, or otherwise not usable.
+ @constant kParamErr -6705 Parameter is incorrect, missing, or not appropriate.
+ @constant kParamCountErr -6706 Incorrect or unsupported number of parameters.
+ @constant kCommandErr -6707 Command invalid or not supported.
+ @constant kIDErr -6708 Unknown, invalid, or inappropriate identifier.
+ @constant kStateErr -6709 Not in appropriate state to perform operation.
+ @constant kRangeErr -6710 Index is out of range or not valid.
+ @constant kRequestErr -6711 Request was improperly formed or not appropriate.
+ @constant kResponseErr -6712 Response was incorrect or out of sequence.
+ @constant kChecksumErr -6713 Checksum does not match the actual data.
+ @constant kNotHandledErr -6714 Operation was not handled (or not handled completely).
+ @constant kVersionErr -6715 Version is not incorrect or not compatibile.
+ @constant kSignatureErr -6716 Signature did not match what was expected.
+ @constant kFormatErr -6717 Unknown, invalid, or inappropriate file/data format.
+ @constant kNotInitializedErr -6718 Action request before needed services were initialized.
+ @constant kAlreadyInitializedErr -6719 Attempt made to initialize when already initialized.
+ @constant kNotInUseErr -6720 Object not in use (e.g. cannot abort if not already in use).
+ @constant kInUseErr -6721 Object is in use (e.g. cannot reuse active param blocks).
+ @constant kTimeoutErr -6722 Timeout occurred.
+ @constant kCanceledErr -6723 Operation canceled (successful cancel).
+ @constant kAlreadyCanceledErr -6724 Operation has already been canceled.
+ @constant kCannotCancelErr -6725 Operation could not be canceled (maybe already done or invalid).
+ @constant kDeletedErr -6726 Object has already been deleted.
+ @constant kNotFoundErr -6727 Something was not found.
+ @constant kNoMemoryErr -6728 Not enough memory was available to perform the operation.
+ @constant kNoResourcesErr -6729 Resources unavailable to perform the operation.
+ @constant kDuplicateErr -6730 Duplicate found or something is a duplicate.
+ @constant kImmutableErr -6731 Entity is not changeable.
+ @constant kUnsupportedDataErr -6732 Data is unknown or not supported.
+ @constant kIntegrityErr -6733 Data is corrupt.
+ @constant kIncompatibleErr -6734 Data is not compatible or it is in an incompatible format.
+ @constant kUnsupportedErr -6735 Feature or option is not supported.
+ @constant kUnexpectedErr -6736 Error occurred that was not expected.
+ @constant kValueErr -6737 Value is not appropriate.
+ @constant kNotReadableErr -6738 Could not read or reading is not allowed.
+ @constant kNotWritableErr -6739 Could not write or writing is not allowed.
+ @constant kBadReferenceErr -6740 An invalid or inappropriate reference was specified.
+ @constant kFlagErr -6741 An invalid, inappropriate, or unsupported flag was specified.
+ @constant kMalformedErr -6742 Something was not formed correctly.
+ @constant kSizeErr -6743 Size was too big, too small, or not appropriate.
+ @constant kNameErr -6744 Name was not correct, allowed, or appropriate.
+ @constant kNotReadyErr -6745 Device or service is not ready.
+ @constant kReadErr -6746 Could not read.
+ @constant kWriteErr -6747 Could not write.
+ @constant kMismatchErr -6748 Something does not match.
+ @constant kDateErr -6749 Date is invalid or out-of-range.
+ @constant kUnderrunErr -6750 Less data than expected.
+ @constant kOverrunErr -6751 More data than expected.
+ @constant kEndingErr -6752 Connection, session, or something is ending.
+ @constant kConnectionErr -6753 Connection failed or could not be established.
+ @constant kAuthenticationErr -6754 Authentication failed or is not supported.
+ @constant kOpenErr -6755 Could not open file, pipe, device, etc.
+ @constant kTypeErr -6756 Incorrect or incompatible type (e.g. file, data, etc.).
+ @constant kSkipErr -6757 Items should be or was skipped.
+ @constant kNoAckErr -6758 No acknowledge.
+ @constant kCollisionErr -6759 Collision occurred (e.g. two on bus at same time).
+ @constant kBackoffErr -6760 Backoff in progress and operation intentionally failed.
+ @constant kNoAddressAckErr -6761 No acknowledge of address.
+ @constant kBusyErr -6762 Cannot perform because something is busy.
+ @constant kNoSpaceErr -6763 Not enough space to perform operation.
+ */
+
+#if ( TARGET_LANGUAGE_C_LIKE )
+ #if ( !TARGET_OS_MAC && !TARGET_API_MAC_OSX_KERNEL )
+typedef int32_t OSStatus;
+ #endif
+#endif
+
+#define kNoErr 0
+#define kInProgressErr 1
+
+// Generic error codes are in the range -6700 to -6779.
+
+#define kGenericErrorBase -6700 // Starting error code for all generic errors.
+
+#define kUnknownErr -6700
+#define kOptionErr -6701
+#define kSelectorErr -6702
+#define kExecutionStateErr -6703
+#define kPathErr -6704
+#define kParamErr -6705
+#define kParamCountErr -6706
+#define kCommandErr -6707
+#define kIDErr -6708
+#define kStateErr -6709
+#define kRangeErr -6710
+#define kRequestErr -6711
+#define kResponseErr -6712
+#define kChecksumErr -6713
+#define kNotHandledErr -6714
+#define kVersionErr -6715
+#define kSignatureErr -6716
+#define kFormatErr -6717
+#define kNotInitializedErr -6718
+#define kAlreadyInitializedErr -6719
+#define kNotInUseErr -6720
+#define kInUseErr -6721
+#define kTimeoutErr -6722
+#define kCanceledErr -6723
+#define kAlreadyCanceledErr -6724
+#define kCannotCancelErr -6725
+#define kDeletedErr -6726
+#define kNotFoundErr -6727
+#define kNoMemoryErr -6728
+#define kNoResourcesErr -6729
+#define kDuplicateErr -6730
+#define kImmutableErr -6731
+#define kUnsupportedDataErr -6732
+#define kIntegrityErr -6733
+#define kIncompatibleErr -6734
+#define kUnsupportedErr -6735
+#define kUnexpectedErr -6736
+#define kValueErr -6737
+#define kNotReadableErr -6738
+#define kNotWritableErr -6739
+#define kBadReferenceErr -6740
+#define kFlagErr -6741
+#define kMalformedErr -6742
+#define kSizeErr -6743
+#define kNameErr -6744
+#define kNotReadyErr -6745
+#define kReadErr -6746
+#define kWriteErr -6747
+#define kMismatchErr -6748
+#define kDateErr -6749
+#define kUnderrunErr -6750
+#define kOverrunErr -6751
+#define kEndingErr -6752
+#define kConnectionErr -6753
+#define kAuthenticationErr -6754
+#define kOpenErr -6755
+#define kTypeErr -6756
+#define kSkipErr -6757
+#define kNoAckErr -6758
+#define kCollisionErr -6759
+#define kBackoffErr -6760
+#define kNoAddressAckErr -6761
+#define kBusyErr -6762
+#define kNoSpaceErr -6763
+
+#define kGenericErrorEnd -6779 // Last generic error code (inclusive)
+
+#if 0
+#pragma mark == Mac Compatibility ==
+#endif
+
+//===========================================================================================================================
+// Mac Compatibility
+//===========================================================================================================================
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @enum Duration
+
+ @abstract Type used to specify a duration of time.
+
+ @constant kDurationImmediate Indicates no delay/wait time.
+ @constant kDurationMicrosecond Microsecond units.
+ @constant kDurationMillisecond Millisecond units.
+ @constant kDurationSecond Second units.
+ @constant kDurationMinute Minute units.
+ @constant kDurationHour Hour units.
+ @constant kDurationDay Day units.
+ @constant kDurationForever Infinite period of time (no timeout).
+
+ @discussion
+
+ Duration values are intended to be multiplied by the specific interval to achieve an actual duration. For example,
+ to wait for 5 seconds you would use "5 * kDurationSecond".
+ */
+
+#if ( TARGET_LANGUAGE_C_LIKE )
+ #if ( !TARGET_OS_MAC )
+typedef int32_t Duration;
+ #endif
+#endif
+
+#define kDurationImmediate 0L
+#define kDurationMicrosecond -1L
+#define kDurationMillisecond 1L
+#define kDurationSecond ( 1000L * kDurationMillisecond )
+#define kDurationMinute ( 60L * kDurationSecond )
+#define kDurationHour ( 60L * kDurationMinute )
+#define kDurationDay ( 24L * kDurationHour )
+#define kDurationForever 0x7FFFFFFFL
+
+// Seconds <-> Minutes <-> Hours <-> Days <-> Weeks <-> Months <-> Years conversions
+
+#define kNanosecondsPerMicrosecond 1000
+#define kNanosecondsPerMillisecond 1000000
+#define kNanosecondsPerSecond 1000000000
+#define kMicrosecondsPerSecond 1000000
+#define kMicrosecondsPerMillisecond 1000
+#define kMillisecondsPerSecond 1000
+#define kSecondsPerMinute 60
+#define kSecondsPerHour ( 60 * 60 ) // 3600
+#define kSecondsPerDay ( 60 * 60 * 24 ) // 86400
+#define kSecondsPerWeek ( 60 * 60 * 24 * 7 ) // 604800
+#define kMinutesPerHour 60
+#define kMinutesPerDay ( 60 * 24 ) // 1440
+#define kHoursPerDay 24
+#define kDaysPerWeek 7
+#define kWeeksPerYear 52
+#define kMonthsPerYear 12
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined VersionStages
+
+ @abstract NumVersion-style version stages.
+ */
+
+#define kVersionStageDevelopment 0x20
+#define kVersionStageAlpha 0x40
+#define kVersionStageBeta 0x60
+#define kVersionStageFinal 0x80
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function NumVersionBuild
+
+ @abstract Builds a 32-bit Mac-style NumVersion value (e.g. NumVersionBuild( 1, 2, 3, kVersionStageBeta, 4 ) -> 1.2.3b4).
+ */
+
+#define NumVersionBuild( MAJOR, MINOR, BUGFIX, STAGE, REV ) \
+ ( ( ( ( MAJOR ) & 0xFF ) << 24 ) | \
+ ( ( ( MINOR ) & 0x0F ) << 20 ) | \
+ ( ( ( BUGFIX ) & 0x0F ) << 16 ) | \
+ ( ( ( STAGE ) & 0xFF ) << 8 ) | \
+ ( ( ( REV ) & 0xFF ) ) )
+
+#define NumVersionExtractMajor( VERSION ) ( (uint8_t)( ( ( VERSION ) >> 24 ) & 0xFF ) )
+#define NumVersionExtractMinorAndBugFix( VERSION ) ( (uint8_t)( ( ( VERSION ) >> 16 ) & 0xFF ) )
+#define NumVersionExtractMinor( VERSION ) ( (uint8_t)( ( ( VERSION ) >> 20 ) & 0x0F ) )
+#define NumVersionExtractBugFix( VERSION ) ( (uint8_t)( ( ( VERSION ) >> 16 ) & 0x0F ) )
+#define NumVersionExtractStage( VERSION ) ( (uint8_t)( ( ( VERSION ) >> 8 ) & 0xFF ) )
+#define NumVersionExtractRevision( VERSION ) ( (uint8_t)( ( VERSION ) & 0xFF ) )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function NumVersionCompare
+
+ @abstract Compares two NumVersion values and returns the following values:
+
+ left < right -> -1
+ left > right -> 1
+ left = right -> 0
+ */
+
+#if ( TARGET_LANGUAGE_C_LIKE )
+int NumVersionCompare( uint32_t inLeft, uint32_t inRight );
+#endif
+
+#if 0
+#pragma mark == Binary Constants ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined binary_4
+
+ @abstract Macro to generate an 4-bit constant using binary notation (e.g. binary_4( 1010 ) == 0xA).
+ */
+
+#define binary_4( a ) binary_4_hex_wrap( hex_digit4( a ) )
+#define binary_4_hex_wrap( a ) binary_4_hex( a )
+#define binary_4_hex( a ) ( 0x ## a )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined binary_8
+
+ @abstract Macro to generate an 8-bit constant using binary notation (e.g. binary_8( 01111011 ) == 0x7B).
+ */
+
+#define binary_8( a ) binary_8_hex_wrap( hex_digit8( a ) )
+#define binary_8_hex_wrap( a ) binary_8_hex( a )
+#define binary_8_hex( a ) ( 0x ## a )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined binary_16
+
+ @abstract Macro to generate an 16-bit constant using binary notation (e.g. binary_16( 01111011, 01111011 ) == 0x7B7B).
+ */
+
+#define binary_16( a, b ) binary_16_hex_wrap( hex_digit8( a ), hex_digit8( b ) )
+#define binary_16_hex_wrap( a, b ) binary_16_hex( a, b )
+#define binary_16_hex( a, b ) ( 0x ## a ## b )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined binary_32
+
+ @abstract Macro to generate an 32-bit constant using binary notation
+ (e.g. binary_32( 01111011, 01111011, 01111011, 01111011 ) == 0x7B7B7B7B).
+ */
+
+#define binary_32( a, b, c, d ) binary_32_hex_wrap( hex_digit8( a ), hex_digit8( b ), hex_digit8( c ), hex_digit8( d ) )
+#define binary_32_hex_wrap( a, b, c, d ) binary_32_hex( a, b, c, d )
+#define binary_32_hex( a, b, c, d ) ( 0x ## a ## b ## c ## d )
+
+// Binary Constant Helpers
+
+#define hex_digit8( a ) HEX_DIGIT_ ## a
+#define hex_digit4( a ) HEX_DIGIT_ ## 0000 ## a
+
+#define HEX_DIGIT_00000000 00
+#define HEX_DIGIT_00000001 01
+#define HEX_DIGIT_00000010 02
+#define HEX_DIGIT_00000011 03
+#define HEX_DIGIT_00000100 04
+#define HEX_DIGIT_00000101 05
+#define HEX_DIGIT_00000110 06
+#define HEX_DIGIT_00000111 07
+#define HEX_DIGIT_00001000 08
+#define HEX_DIGIT_00001001 09
+#define HEX_DIGIT_00001010 0A
+#define HEX_DIGIT_00001011 0B
+#define HEX_DIGIT_00001100 0C
+#define HEX_DIGIT_00001101 0D
+#define HEX_DIGIT_00001110 0E
+#define HEX_DIGIT_00001111 0F
+#define HEX_DIGIT_00010000 10
+#define HEX_DIGIT_00010001 11
+#define HEX_DIGIT_00010010 12
+#define HEX_DIGIT_00010011 13
+#define HEX_DIGIT_00010100 14
+#define HEX_DIGIT_00010101 15
+#define HEX_DIGIT_00010110 16
+#define HEX_DIGIT_00010111 17
+#define HEX_DIGIT_00011000 18
+#define HEX_DIGIT_00011001 19
+#define HEX_DIGIT_00011010 1A
+#define HEX_DIGIT_00011011 1B
+#define HEX_DIGIT_00011100 1C
+#define HEX_DIGIT_00011101 1D
+#define HEX_DIGIT_00011110 1E
+#define HEX_DIGIT_00011111 1F
+#define HEX_DIGIT_00100000 20
+#define HEX_DIGIT_00100001 21
+#define HEX_DIGIT_00100010 22
+#define HEX_DIGIT_00100011 23
+#define HEX_DIGIT_00100100 24
+#define HEX_DIGIT_00100101 25
+#define HEX_DIGIT_00100110 26
+#define HEX_DIGIT_00100111 27
+#define HEX_DIGIT_00101000 28
+#define HEX_DIGIT_00101001 29
+#define HEX_DIGIT_00101010 2A
+#define HEX_DIGIT_00101011 2B
+#define HEX_DIGIT_00101100 2C
+#define HEX_DIGIT_00101101 2D
+#define HEX_DIGIT_00101110 2E
+#define HEX_DIGIT_00101111 2F
+#define HEX_DIGIT_00110000 30
+#define HEX_DIGIT_00110001 31
+#define HEX_DIGIT_00110010 32
+#define HEX_DIGIT_00110011 33
+#define HEX_DIGIT_00110100 34
+#define HEX_DIGIT_00110101 35
+#define HEX_DIGIT_00110110 36
+#define HEX_DIGIT_00110111 37
+#define HEX_DIGIT_00111000 38
+#define HEX_DIGIT_00111001 39
+#define HEX_DIGIT_00111010 3A
+#define HEX_DIGIT_00111011 3B
+#define HEX_DIGIT_00111100 3C
+#define HEX_DIGIT_00111101 3D
+#define HEX_DIGIT_00111110 3E
+#define HEX_DIGIT_00111111 3F
+#define HEX_DIGIT_01000000 40
+#define HEX_DIGIT_01000001 41
+#define HEX_DIGIT_01000010 42
+#define HEX_DIGIT_01000011 43
+#define HEX_DIGIT_01000100 44
+#define HEX_DIGIT_01000101 45
+#define HEX_DIGIT_01000110 46
+#define HEX_DIGIT_01000111 47
+#define HEX_DIGIT_01001000 48
+#define HEX_DIGIT_01001001 49
+#define HEX_DIGIT_01001010 4A
+#define HEX_DIGIT_01001011 4B
+#define HEX_DIGIT_01001100 4C
+#define HEX_DIGIT_01001101 4D
+#define HEX_DIGIT_01001110 4E
+#define HEX_DIGIT_01001111 4F
+#define HEX_DIGIT_01010000 50
+#define HEX_DIGIT_01010001 51
+#define HEX_DIGIT_01010010 52
+#define HEX_DIGIT_01010011 53
+#define HEX_DIGIT_01010100 54
+#define HEX_DIGIT_01010101 55
+#define HEX_DIGIT_01010110 56
+#define HEX_DIGIT_01010111 57
+#define HEX_DIGIT_01011000 58
+#define HEX_DIGIT_01011001 59
+#define HEX_DIGIT_01011010 5A
+#define HEX_DIGIT_01011011 5B
+#define HEX_DIGIT_01011100 5C
+#define HEX_DIGIT_01011101 5D
+#define HEX_DIGIT_01011110 5E
+#define HEX_DIGIT_01011111 5F
+#define HEX_DIGIT_01100000 60
+#define HEX_DIGIT_01100001 61
+#define HEX_DIGIT_01100010 62
+#define HEX_DIGIT_01100011 63
+#define HEX_DIGIT_01100100 64
+#define HEX_DIGIT_01100101 65
+#define HEX_DIGIT_01100110 66
+#define HEX_DIGIT_01100111 67
+#define HEX_DIGIT_01101000 68
+#define HEX_DIGIT_01101001 69
+#define HEX_DIGIT_01101010 6A
+#define HEX_DIGIT_01101011 6B
+#define HEX_DIGIT_01101100 6C
+#define HEX_DIGIT_01101101 6D
+#define HEX_DIGIT_01101110 6E
+#define HEX_DIGIT_01101111 6F
+#define HEX_DIGIT_01110000 70
+#define HEX_DIGIT_01110001 71
+#define HEX_DIGIT_01110010 72
+#define HEX_DIGIT_01110011 73
+#define HEX_DIGIT_01110100 74
+#define HEX_DIGIT_01110101 75
+#define HEX_DIGIT_01110110 76
+#define HEX_DIGIT_01110111 77
+#define HEX_DIGIT_01111000 78
+#define HEX_DIGIT_01111001 79
+#define HEX_DIGIT_01111010 7A
+#define HEX_DIGIT_01111011 7B
+#define HEX_DIGIT_01111100 7C
+#define HEX_DIGIT_01111101 7D
+#define HEX_DIGIT_01111110 7E
+#define HEX_DIGIT_01111111 7F
+#define HEX_DIGIT_10000000 80
+#define HEX_DIGIT_10000001 81
+#define HEX_DIGIT_10000010 82
+#define HEX_DIGIT_10000011 83
+#define HEX_DIGIT_10000100 84
+#define HEX_DIGIT_10000101 85
+#define HEX_DIGIT_10000110 86
+#define HEX_DIGIT_10000111 87
+#define HEX_DIGIT_10001000 88
+#define HEX_DIGIT_10001001 89
+#define HEX_DIGIT_10001010 8A
+#define HEX_DIGIT_10001011 8B
+#define HEX_DIGIT_10001100 8C
+#define HEX_DIGIT_10001101 8D
+#define HEX_DIGIT_10001110 8E
+#define HEX_DIGIT_10001111 8F
+#define HEX_DIGIT_10010000 90
+#define HEX_DIGIT_10010001 91
+#define HEX_DIGIT_10010010 92
+#define HEX_DIGIT_10010011 93
+#define HEX_DIGIT_10010100 94
+#define HEX_DIGIT_10010101 95
+#define HEX_DIGIT_10010110 96
+#define HEX_DIGIT_10010111 97
+#define HEX_DIGIT_10011000 98
+#define HEX_DIGIT_10011001 99
+#define HEX_DIGIT_10011010 9A
+#define HEX_DIGIT_10011011 9B
+#define HEX_DIGIT_10011100 9C
+#define HEX_DIGIT_10011101 9D
+#define HEX_DIGIT_10011110 9E
+#define HEX_DIGIT_10011111 9F
+#define HEX_DIGIT_10100000 A0
+#define HEX_DIGIT_10100001 A1
+#define HEX_DIGIT_10100010 A2
+#define HEX_DIGIT_10100011 A3
+#define HEX_DIGIT_10100100 A4
+#define HEX_DIGIT_10100101 A5
+#define HEX_DIGIT_10100110 A6
+#define HEX_DIGIT_10100111 A7
+#define HEX_DIGIT_10101000 A8
+#define HEX_DIGIT_10101001 A9
+#define HEX_DIGIT_10101010 AA
+#define HEX_DIGIT_10101011 AB
+#define HEX_DIGIT_10101100 AC
+#define HEX_DIGIT_10101101 AD
+#define HEX_DIGIT_10101110 AE
+#define HEX_DIGIT_10101111 AF
+#define HEX_DIGIT_10110000 B0
+#define HEX_DIGIT_10110001 B1
+#define HEX_DIGIT_10110010 B2
+#define HEX_DIGIT_10110011 B3
+#define HEX_DIGIT_10110100 B4
+#define HEX_DIGIT_10110101 B5
+#define HEX_DIGIT_10110110 B6
+#define HEX_DIGIT_10110111 B7
+#define HEX_DIGIT_10111000 B8
+#define HEX_DIGIT_10111001 B9
+#define HEX_DIGIT_10111010 BA
+#define HEX_DIGIT_10111011 BB
+#define HEX_DIGIT_10111100 BC
+#define HEX_DIGIT_10111101 BD
+#define HEX_DIGIT_10111110 BE
+#define HEX_DIGIT_10111111 BF
+#define HEX_DIGIT_11000000 C0
+#define HEX_DIGIT_11000001 C1
+#define HEX_DIGIT_11000010 C2
+#define HEX_DIGIT_11000011 C3
+#define HEX_DIGIT_11000100 C4
+#define HEX_DIGIT_11000101 C5
+#define HEX_DIGIT_11000110 C6
+#define HEX_DIGIT_11000111 C7
+#define HEX_DIGIT_11001000 C8
+#define HEX_DIGIT_11001001 C9
+#define HEX_DIGIT_11001010 CA
+#define HEX_DIGIT_11001011 CB
+#define HEX_DIGIT_11001100 CC
+#define HEX_DIGIT_11001101 CD
+#define HEX_DIGIT_11001110 CE
+#define HEX_DIGIT_11001111 CF
+#define HEX_DIGIT_11010000 D0
+#define HEX_DIGIT_11010001 D1
+#define HEX_DIGIT_11010010 D2
+#define HEX_DIGIT_11010011 D3
+#define HEX_DIGIT_11010100 D4
+#define HEX_DIGIT_11010101 D5
+#define HEX_DIGIT_11010110 D6
+#define HEX_DIGIT_11010111 D7
+#define HEX_DIGIT_11011000 D8
+#define HEX_DIGIT_11011001 D9
+#define HEX_DIGIT_11011010 DA
+#define HEX_DIGIT_11011011 DB
+#define HEX_DIGIT_11011100 DC
+#define HEX_DIGIT_11011101 DD
+#define HEX_DIGIT_11011110 DE
+#define HEX_DIGIT_11011111 DF
+#define HEX_DIGIT_11100000 E0
+#define HEX_DIGIT_11100001 E1
+#define HEX_DIGIT_11100010 E2
+#define HEX_DIGIT_11100011 E3
+#define HEX_DIGIT_11100100 E4
+#define HEX_DIGIT_11100101 E5
+#define HEX_DIGIT_11100110 E6
+#define HEX_DIGIT_11100111 E7
+#define HEX_DIGIT_11101000 E8
+#define HEX_DIGIT_11101001 E9
+#define HEX_DIGIT_11101010 EA
+#define HEX_DIGIT_11101011 EB
+#define HEX_DIGIT_11101100 EC
+#define HEX_DIGIT_11101101 ED
+#define HEX_DIGIT_11101110 EE
+#define HEX_DIGIT_11101111 EF
+#define HEX_DIGIT_11110000 F0
+#define HEX_DIGIT_11110001 F1
+#define HEX_DIGIT_11110010 F2
+#define HEX_DIGIT_11110011 F3
+#define HEX_DIGIT_11110100 F4
+#define HEX_DIGIT_11110101 F5
+#define HEX_DIGIT_11110110 F6
+#define HEX_DIGIT_11110111 F7
+#define HEX_DIGIT_11111000 F8
+#define HEX_DIGIT_11111001 F9
+#define HEX_DIGIT_11111010 FA
+#define HEX_DIGIT_11111011 FB
+#define HEX_DIGIT_11111100 FC
+#define HEX_DIGIT_11111101 FD
+#define HEX_DIGIT_11111110 FE
+#define HEX_DIGIT_11111111 FF
+
+#if 0
+#pragma mark == Debugging ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function CommonServicesTest
+
+ @abstract Unit test.
+ */
+
+#if ( DEBUG )
+ #if ( TARGET_LANGUAGE_C_LIKE )
+OSStatus CommonServicesTest( void );
+ #endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __COMMON_SERVICES__
diff --git a/sd/source/ui/remotecontrol/mDNSResponder/DebugServices.c b/sd/source/ui/remotecontrol/mDNSResponder/DebugServices.c
new file mode 100755
index 000000000000..3bcc42380d8c
--- /dev/null
+++ b/sd/source/ui/remotecontrol/mDNSResponder/DebugServices.c
@@ -0,0 +1,3075 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ To Do:
+
+ - Use StackWalk on Windows to optionally print stack frames.
+ */
+
+#if 0
+#pragma mark == Includes ==
+#endif
+
+//===========================================================================================================================
+// Includes
+//===========================================================================================================================
+
+#if ( !KERNEL )
+ #include <ctype.h>
+ #include <stdio.h>
+ #include <string.h>
+#endif
+
+#include "CommonServices.h"
+
+#include "DebugServices.h"
+
+#if ( DEBUG )
+
+#if ( TARGET_OS_VXWORKS )
+ #include "intLib.h"
+#endif
+
+#if ( TARGET_OS_WIN32 )
+ #include <time.h>
+
+ #if ( !TARGET_OS_WINDOWS_CE )
+ #include <fcntl.h>
+ #include <io.h>
+ #endif
+#endif
+
+#if ( DEBUG_IDEBUG_ENABLED && TARGET_API_MAC_OSX_KERNEL )
+ #include <IOKit/IOLib.h>
+#endif
+
+// If MDNS_DEBUGMSGS is defined (even if defined 0), it is aware of mDNS and it is probably safe to include mDNSEmbeddedAPI.h.
+
+#if ( defined( MDNS_DEBUGMSGS ) )
+ #include "mDNSEmbeddedAPI.h"
+#endif
+
+#if 0
+#pragma mark == Macros ==
+#endif
+
+//===========================================================================================================================
+// Macros
+//===========================================================================================================================
+
+#define DebugIsPrint( C ) ( ( ( C ) >= 0x20 ) && ( ( C ) <= 0x7E ) )
+
+#if 0
+#pragma mark == Prototypes ==
+#endif
+
+//===========================================================================================================================
+// Prototypes
+//===========================================================================================================================
+
+static OSStatus DebugPrint( DebugLevel inLevel, char *inData, size_t inSize );
+
+// fprintf
+
+#if ( DEBUG_FPRINTF_ENABLED )
+static OSStatus DebugFPrintFInit( DebugOutputTypeFlags inFlags, const char *inFilename );
+static void DebugFPrintFPrint( char *inData, size_t inSize );
+#endif
+
+// iDebug (Mac OS X user and kernel)
+
+#if ( DEBUG_IDEBUG_ENABLED )
+static OSStatus DebugiDebugInit( void );
+static void DebugiDebugPrint( char *inData, size_t inSize );
+#endif
+
+// kprintf (Mac OS X Kernel)
+
+#if ( DEBUG_KPRINTF_ENABLED )
+static void DebugKPrintFPrint( char *inData, size_t inSize );
+#endif
+
+// Mac OS X IOLog (Mac OS X Kernel)
+
+#if ( DEBUG_MAC_OS_X_IOLOG_ENABLED )
+static void DebugMacOSXIOLogPrint( char *inData, size_t inSize );
+#endif
+
+// Mac OS X Log
+
+#if ( TARGET_OS_MAC )
+static OSStatus DebugMacOSXLogInit( void );
+static void DebugMacOSXLogPrint( char *inData, size_t inSize );
+#endif
+
+// Windows Debugger
+
+#if ( TARGET_OS_WIN32 )
+static void DebugWindowsDebuggerPrint( char *inData, size_t inSize );
+#endif
+
+// Windows Event Log
+
+#if ( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+static OSStatus DebugWindowsEventLogInit( const char *inName, HMODULE inModule );
+static void DebugWindowsEventLogPrint( DebugLevel inLevel, char *inData, size_t inSize );
+#endif
+
+// DebugLib support
+
+#if ( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
+static pascal void
+DebugAssertOutputHandler(
+ OSType inComponentSignature,
+ UInt32 inOptions,
+ const char * inAssertionString,
+ const char * inExceptionString,
+ const char * inErrorString,
+ const char * inFileName,
+ long inLineNumber,
+ void * inValue,
+ ConstStr255Param inOutputMsg );
+#endif
+
+// Utilities
+
+static char * DebugNumVersionToString( uint32_t inVersion, char *inString );
+
+#if ( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+static void DebugWinEnableConsole( void );
+#endif
+
+#if ( TARGET_OS_WIN32 )
+static TCHAR *
+DebugWinCharToTCharString(
+ const char * inCharString,
+ size_t inCharCount,
+ TCHAR * outTCharString,
+ size_t inTCharCountMax,
+ size_t * outTCharCount );
+#endif
+
+#if 0
+#pragma mark == Globals ==
+#endif
+
+//===========================================================================================================================
+// Private Globals
+//===========================================================================================================================
+
+#if ( TARGET_OS_VXWORKS )
+// TCP States for inetstatShow.
+
+extern char ** pTcpstates; // defined in tcpLib.c
+
+const char * kDebugTCPStates[] =
+{
+ "(0) TCPS_CLOSED",
+ "(1) TCPS_LISTEN",
+ "(2) TCPS_SYN_SENT",
+ "(3) TCPS_SYN_RECEIVED",
+ "(4) TCPS_ESTABLISHED",
+ "(5) TCPS_CLOSE_WAIT",
+ "(6) TCPS_FIN_WAIT_1",
+ "(7) TCPS_CLOSING",
+ "(8) TCPS_LAST_ACK",
+ "(9) TCPS_FIN_WAIT_2",
+ "(10) TCPS_TIME_WAIT",
+};
+#endif
+
+// General
+
+static bool gDebugInitialized = false;
+static DebugOutputType gDebugOutputType = kDebugOutputTypeNone;
+static DebugLevel gDebugPrintLevelMin = kDebugLevelInfo;
+static DebugLevel gDebugPrintLevelMax = kDebugLevelMax;
+static DebugLevel gDebugBreakLevel = kDebugLevelAssert;
+#if ( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
+static DebugAssertOutputHandlerUPP gDebugAssertOutputHandlerUPP = NULL;
+#endif
+
+// Custom
+
+static DebugOutputFunctionPtr gDebugCustomOutputFunction = NULL;
+static void * gDebugCustomOutputContext = NULL;
+
+// fprintf
+
+#if ( DEBUG_FPRINTF_ENABLED )
+static FILE * gDebugFPrintFFile = NULL;
+#endif
+
+// MacOSXLog
+
+#if ( TARGET_OS_MAC )
+typedef int ( *DebugMacOSXLogFunctionPtr )( const char *inFormat, ... );
+
+static DebugMacOSXLogFunctionPtr gDebugMacOSXLogFunction = NULL;
+#endif
+
+// WindowsEventLog
+
+
+#if ( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+static HANDLE gDebugWindowsEventLogEventSource = NULL;
+#endif
+
+#if 0
+#pragma mark -
+#pragma mark == General ==
+#endif
+
+//===========================================================================================================================
+// DebugInitialize
+//===========================================================================================================================
+
+DEBUG_EXPORT OSStatus DebugInitialize( DebugOutputType inType, ... )
+{
+ OSStatus err;
+ DebugOutputType type;
+ va_list args;
+
+ va_start( args, inType );
+
+#if ( TARGET_OS_VXWORKS )
+ // Set up the TCP state strings if they are not already set up by VxWorks (normally not set up for some reason).
+
+ if( !pTcpstates )
+ {
+ pTcpstates = (char **) kDebugTCPStates;
+ }
+#endif
+
+ // Set up DebugLib stuff (if building with Debugging.h).
+
+#if ( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
+ if( !gDebugAssertOutputHandlerUPP )
+ {
+ gDebugAssertOutputHandlerUPP = NewDebugAssertOutputHandlerUPP( DebugAssertOutputHandler );
+ check( gDebugAssertOutputHandlerUPP );
+ if( gDebugAssertOutputHandlerUPP )
+ {
+ InstallDebugAssertOutputHandler( gDebugAssertOutputHandlerUPP );
+ }
+ }
+#endif
+
+ // Pre-process meta-output kind to pick an appropriate output kind for the platform.
+
+ type = inType;
+ if( type == kDebugOutputTypeMetaConsole )
+ {
+ #if ( TARGET_OS_MAC )
+ type = kDebugOutputTypeMacOSXLog;
+ #elif ( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+ #if ( DEBUG_FPRINTF_ENABLED )
+ type = kDebugOutputTypeFPrintF;
+ #else
+ type = kDebugOutputTypeWindowsDebugger;
+ #endif
+ #elif ( TARGET_API_MAC_OSX_KERNEL )
+ #if ( DEBUG_MAC_OS_X_IOLOG_ENABLED )
+ type = kDebugOutputTypeMacOSXIOLog;
+ #elif ( DEBUG_IDEBUG_ENABLED )
+ type = kDebugOutputTypeiDebug;
+ #elif ( DEBUG_KPRINTF_ENABLED )
+ type = kDebugOutputTypeKPrintF;
+ #endif
+ #elif ( TARGET_OS_VXWORKS )
+ #if ( DEBUG_FPRINTF_ENABLED )
+ type = kDebugOutputTypeFPrintF;
+ #else
+ #error target is VxWorks, but fprintf output is disabled
+ #endif
+ #else
+ #if ( DEBUG_FPRINTF_ENABLED )
+ type = kDebugOutputTypeFPrintF;
+ #endif
+ #endif
+ }
+
+ // Process output kind.
+
+ gDebugOutputType = type;
+ switch( type )
+ {
+ case kDebugOutputTypeNone:
+ err = kNoErr;
+ break;
+
+ case kDebugOutputTypeCustom:
+ gDebugCustomOutputFunction = va_arg( args, DebugOutputFunctionPtr );
+ gDebugCustomOutputContext = va_arg( args, void * );
+ err = kNoErr;
+ break;
+
+#if ( DEBUG_FPRINTF_ENABLED )
+ case kDebugOutputTypeFPrintF:
+ if( inType == kDebugOutputTypeMetaConsole )
+ {
+ err = DebugFPrintFInit( kDebugOutputTypeFlagsStdErr, NULL );
+ }
+ else
+ {
+ DebugOutputTypeFlags flags;
+ const char * filename;
+
+ flags = (DebugOutputTypeFlags) va_arg( args, unsigned int );
+ if( ( flags & kDebugOutputTypeFlagsTypeMask ) == kDebugOutputTypeFlagsFile )
+ {
+ filename = va_arg( args, const char * );
+ }
+ else
+ {
+ filename = NULL;
+ }
+ err = DebugFPrintFInit( flags, filename );
+ }
+ break;
+#endif
+
+#if ( DEBUG_IDEBUG_ENABLED )
+ case kDebugOutputTypeiDebug:
+ err = DebugiDebugInit();
+ break;
+#endif
+
+#if ( DEBUG_KPRINTF_ENABLED )
+ case kDebugOutputTypeKPrintF:
+ err = kNoErr;
+ break;
+#endif
+
+#if ( DEBUG_MAC_OS_X_IOLOG_ENABLED )
+ case kDebugOutputTypeMacOSXIOLog:
+ err = kNoErr;
+ break;
+#endif
+
+#if ( TARGET_OS_MAC )
+ case kDebugOutputTypeMacOSXLog:
+ err = DebugMacOSXLogInit();
+ break;
+#endif
+
+#if ( TARGET_OS_WIN32 )
+ case kDebugOutputTypeWindowsDebugger:
+ err = kNoErr;
+ break;
+#endif
+
+#if ( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+ case kDebugOutputTypeWindowsEventLog:
+ {
+ const char * name;
+ HMODULE module;
+
+ name = va_arg( args, const char * );
+ module = va_arg( args, HMODULE );
+ err = DebugWindowsEventLogInit( name, module );
+ }
+ break;
+#endif
+
+ default:
+ err = kParamErr;
+ goto exit;
+ }
+ gDebugInitialized = true;
+
+exit:
+ va_end( args );
+ return( err );
+}
+
+//===========================================================================================================================
+// DebugFinalize
+//===========================================================================================================================
+
+DEBUG_EXPORT void DebugFinalize( void )
+{
+#if ( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
+ check( gDebugAssertOutputHandlerUPP );
+ if( gDebugAssertOutputHandlerUPP )
+ {
+ InstallDebugAssertOutputHandler( NULL );
+ DisposeDebugAssertOutputHandlerUPP( gDebugAssertOutputHandlerUPP );
+ gDebugAssertOutputHandlerUPP = NULL;
+ }
+#endif
+}
+
+//===========================================================================================================================
+// DebugGetProperty
+//===========================================================================================================================
+
+DEBUG_EXPORT OSStatus DebugGetProperty( DebugPropertyTag inTag, ... )
+{
+ OSStatus err;
+ va_list args;
+ DebugLevel * level;
+
+ va_start( args, inTag );
+ switch( inTag )
+ {
+ case kDebugPropertyTagPrintLevelMin:
+ level = va_arg( args, DebugLevel * );
+ *level = gDebugPrintLevelMin;
+ err = kNoErr;
+ break;
+
+ case kDebugPropertyTagPrintLevelMax:
+ level = va_arg( args, DebugLevel * );
+ *level = gDebugPrintLevelMax;
+ err = kNoErr;
+ break;
+
+ case kDebugPropertyTagBreakLevel:
+ level = va_arg( args, DebugLevel * );
+ *level = gDebugBreakLevel;
+ err = kNoErr;
+ break;
+
+ default:
+ err = kUnsupportedErr;
+ break;
+ }
+ va_end( args );
+ return( err );
+}
+
+//===========================================================================================================================
+// DebugSetProperty
+//===========================================================================================================================
+
+DEBUG_EXPORT OSStatus DebugSetProperty( DebugPropertyTag inTag, ... )
+{
+ OSStatus err;
+ va_list args;
+ DebugLevel level;
+
+ va_start( args, inTag );
+ switch( inTag )
+ {
+ case kDebugPropertyTagPrintLevelMin:
+ level = va_arg( args, DebugLevel );
+ gDebugPrintLevelMin = level;
+ err = kNoErr;
+ break;
+
+ case kDebugPropertyTagPrintLevelMax:
+ level = va_arg( args, DebugLevel );
+ gDebugPrintLevelMax = level;
+ err = kNoErr;
+ break;
+
+ case kDebugPropertyTagBreakLevel:
+ level = va_arg( args, DebugLevel );
+ gDebugBreakLevel = level;
+ err = kNoErr;
+ break;
+
+ default:
+ err = kUnsupportedErr;
+ break;
+ }
+ va_end( args );
+ return( err );
+}
+
+#if 0
+#pragma mark -
+#pragma mark == Output ==
+#endif
+
+//===========================================================================================================================
+// DebugPrintF
+//===========================================================================================================================
+
+DEBUG_EXPORT size_t DebugPrintF( DebugLevel inLevel, const char *inFormat, ... )
+{
+ va_list args;
+ size_t n;
+
+ // Skip if the level is not in the enabled range..
+
+ if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
+ {
+ n = 0;
+ goto exit;
+ }
+
+ va_start( args, inFormat );
+ n = DebugPrintFVAList( inLevel, inFormat, args );
+ va_end( args );
+
+exit:
+ return( n );
+}
+
+//===========================================================================================================================
+// DebugPrintFVAList
+//===========================================================================================================================
+
+DEBUG_EXPORT size_t DebugPrintFVAList( DebugLevel inLevel, const char *inFormat, va_list inArgs )
+{
+ size_t n;
+ char buffer[ 512 ];
+
+ // Skip if the level is not in the enabled range..
+
+ if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
+ {
+ n = 0;
+ goto exit;
+ }
+
+ n = DebugSNPrintFVAList( buffer, sizeof( buffer ), inFormat, inArgs );
+ DebugPrint( inLevel, buffer, (size_t) n );
+
+exit:
+ return( n );
+}
+
+//===========================================================================================================================
+// DebugPrint
+//===========================================================================================================================
+
+static OSStatus DebugPrint( DebugLevel inLevel, char *inData, size_t inSize )
+{
+ OSStatus err;
+
+ // Skip if the level is not in the enabled range..
+
+ if( ( inLevel < gDebugPrintLevelMin ) || ( inLevel > gDebugPrintLevelMax ) )
+ {
+ err = kRangeErr;
+ goto exit;
+ }
+
+ // Printing is not safe at interrupt time so check for this and warn with an interrupt safe mechanism (if available).
+
+ if( DebugTaskLevel() & kDebugInterruptLevelMask )
+ {
+ #if ( TARGET_OS_VXWORKS )
+ logMsg( "\ncannot print at interrupt time\n\n", 1, 2, 3, 4, 5, 6 );
+ #endif
+
+ err = kExecutionStateErr;
+ goto exit;
+ }
+
+ // Initialize the debugging library if it hasn't already been initialized (allows for zero-config usage).
+
+ if( !gDebugInitialized )
+ {
+ debug_initialize( kDebugOutputTypeMetaConsole );
+ }
+
+ // Print based on the current output type.
+
+ switch( gDebugOutputType )
+ {
+ case kDebugOutputTypeNone:
+ break;
+
+ case kDebugOutputTypeCustom:
+ if( gDebugCustomOutputFunction )
+ {
+ gDebugCustomOutputFunction( inData, inSize, gDebugCustomOutputContext );
+ }
+ break;
+
+#if ( DEBUG_FPRINTF_ENABLED )
+ case kDebugOutputTypeFPrintF:
+ DebugFPrintFPrint( inData, inSize );
+ break;
+#endif
+
+#if ( DEBUG_IDEBUG_ENABLED )
+ case kDebugOutputTypeiDebug:
+ DebugiDebugPrint( inData, inSize );
+ break;
+#endif
+
+#if ( DEBUG_KPRINTF_ENABLED )
+ case kDebugOutputTypeKPrintF:
+ DebugKPrintFPrint( inData, inSize );
+ break;
+#endif
+
+#if ( DEBUG_MAC_OS_X_IOLOG_ENABLED )
+ case kDebugOutputTypeMacOSXIOLog:
+ DebugMacOSXIOLogPrint( inData, inSize );
+ break;
+#endif
+
+#if ( TARGET_OS_MAC )
+ case kDebugOutputTypeMacOSXLog:
+ DebugMacOSXLogPrint( inData, inSize );
+ break;
+#endif
+
+#if ( TARGET_OS_WIN32 )
+ case kDebugOutputTypeWindowsDebugger:
+ DebugWindowsDebuggerPrint( inData, inSize );
+ break;
+#endif
+
+#if ( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+ case kDebugOutputTypeWindowsEventLog:
+ DebugWindowsEventLogPrint( inLevel, inData, inSize );
+ break;
+#endif
+
+ default:
+ break;
+ }
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// DebugPrintAssert
+//
+// Warning: This routine relies on several of the strings being string constants that will exist forever because the
+// underlying logMsg API that does the printing is asynchronous so it cannot use temporary/stack-based
+// pointer variables (e.g. local strings). The debug macros that invoke this function only use constant
+// constant strings, but if this function is invoked directly from other places, it must use constant strings.
+//===========================================================================================================================
+
+DEBUG_EXPORT void
+DebugPrintAssert(
+ int_least32_t inErrorCode,
+ const char * inAssertString,
+ const char * inMessage,
+ const char * inFilename,
+ int_least32_t inLineNumber,
+ const char * inFunction )
+{
+ // Skip if the level is not in the enabled range..
+
+ if( ( kDebugLevelAssert < gDebugPrintLevelMin ) || ( kDebugLevelAssert > gDebugPrintLevelMax ) )
+ {
+ return;
+ }
+
+ if( inErrorCode != 0 )
+ {
+ DebugPrintF(
+ kDebugLevelAssert,
+ "\n"
+ "[ASSERT] error: %ld (%m)\n"
+ "[ASSERT] where: \"%s\", line %ld, \"%s\"\n"
+ "\n",
+ inErrorCode, inErrorCode,
+ inFilename ? inFilename : "",
+ inLineNumber,
+ inFunction ? inFunction : "" );
+ }
+ else
+ {
+ DebugPrintF(
+ kDebugLevelAssert,
+ "\n"
+ "[ASSERT] assert: \"%s\" %s\n"
+ "[ASSERT] where: \"%s\", line %ld, \"%s\"\n"
+ "\n",
+ inAssertString ? inAssertString : "",
+ inMessage ? inMessage : "",
+ inFilename ? inFilename : "",
+ inLineNumber,
+ inFunction ? inFunction : "" );
+ }
+
+ // Break into the debugger if enabled.
+
+ #if ( TARGET_OS_WIN32 )
+ if( gDebugBreakLevel <= kDebugLevelAssert )
+ {
+ if( IsDebuggerPresent() )
+ {
+ DebugBreak();
+ }
+ }
+ #endif
+}
+
+#if 0
+#pragma mark -
+#endif
+
+#if ( DEBUG_FPRINTF_ENABLED )
+//===========================================================================================================================
+// DebugFPrintFInit
+//===========================================================================================================================
+
+static OSStatus DebugFPrintFInit( DebugOutputTypeFlags inFlags, const char *inFilename )
+{
+ OSStatus err;
+ DebugOutputTypeFlags typeFlags;
+
+ typeFlags = inFlags & kDebugOutputTypeFlagsTypeMask;
+ if( typeFlags == kDebugOutputTypeFlagsStdOut )
+ {
+ #if ( TARGET_OS_WIN32 )
+ DebugWinEnableConsole();
+ #endif
+
+ gDebugFPrintFFile = stdout;
+ }
+ else if( typeFlags == kDebugOutputTypeFlagsStdErr )
+ {
+ #if ( TARGET_OS_WIN32 )
+ DebugWinEnableConsole();
+ #endif
+
+ gDebugFPrintFFile = stdout;
+ }
+ else if( typeFlags == kDebugOutputTypeFlagsFile )
+ {
+ require_action_quiet( inFilename && ( *inFilename != '\0' ), exit, err = kOpenErr );
+
+ gDebugFPrintFFile = fopen( inFilename, "a" );
+ require_action_quiet( gDebugFPrintFFile, exit, err = kOpenErr );
+ }
+ else
+ {
+ err = kParamErr;
+ goto exit;
+ }
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// DebugFPrintFPrint
+//===========================================================================================================================
+
+static void DebugFPrintFPrint( char *inData, size_t inSize )
+{
+ char * p;
+ char * q;
+
+ // Convert \r to \n. fprintf will interpret \n and convert to whatever is appropriate for the platform.
+
+ p = inData;
+ q = p + inSize;
+ while( p < q )
+ {
+ if( *p == '\r' )
+ {
+ *p = '\n';
+ }
+ ++p;
+ }
+
+ // Write the data and flush.
+
+ if( gDebugFPrintFFile )
+ {
+ fprintf( gDebugFPrintFFile, "%.*s", (int) inSize, inData );
+ fflush( gDebugFPrintFFile );
+ }
+}
+#endif // DEBUG_FPRINTF_ENABLED
+
+#if ( DEBUG_IDEBUG_ENABLED )
+//===========================================================================================================================
+// DebugiDebugInit
+//===========================================================================================================================
+
+static OSStatus DebugiDebugInit( void )
+{
+ OSStatus err;
+
+ #if ( TARGET_API_MAC_OSX_KERNEL )
+
+ extern uint32_t * _giDebugReserved1;
+
+ // Emulate the iDebugSetOutputType macro in iDebugServices.h.
+ // Note: This is not thread safe, but neither is iDebugServices.h nor iDebugKext.
+
+ if( !_giDebugReserved1 )
+ {
+ _giDebugReserved1 = (uint32_t *) IOMalloc( sizeof( uint32_t ) );
+ require_action_quiet( _giDebugReserved1, exit, err = kNoMemoryErr );
+ }
+ *_giDebugReserved1 = 0x00010000U;
+ err = kNoErr;
+exit:
+ #else
+
+ __private_extern__ void iDebugSetOutputTypeInternal( uint32_t inType );
+
+ iDebugSetOutputTypeInternal( 0x00010000U );
+ err = kNoErr;
+
+ #endif
+
+ return( err );
+}
+
+//===========================================================================================================================
+// DebugiDebugPrint
+//===========================================================================================================================
+
+static void DebugiDebugPrint( char *inData, size_t inSize )
+{
+ #if ( TARGET_API_MAC_OSX_KERNEL )
+
+ // Locally declared here so we do not need to include iDebugKext.h.
+ // Note: IOKit uses a global namespace for all code and only a partial link occurs at build time. When the
+ // KEXT is loaded, the runtime linker will link in this extern'd symbol (assuming iDebug is present).
+ // _giDebugLogInternal is actually part of IOKit proper so this should link even if iDebug is not present.
+
+ typedef void ( *iDebugLogFunctionPtr )( uint32_t inLevel, uint32_t inTag, const char *inFormat, ... );
+
+ extern iDebugLogFunctionPtr _giDebugLogInternal;
+
+ if( _giDebugLogInternal )
+ {
+ _giDebugLogInternal( 0, 0, "%.*s", (int) inSize, inData );
+ }
+
+ #else
+
+ __private_extern__ void iDebugLogInternal( uint32_t inLevel, uint32_t inTag, const char *inFormat, ... );
+
+ iDebugLogInternal( 0, 0, "%.*s", (int) inSize, inData );
+
+ #endif
+}
+#endif
+
+#if ( DEBUG_KPRINTF_ENABLED )
+//===========================================================================================================================
+// DebugKPrintFPrint
+//===========================================================================================================================
+
+static void DebugKPrintFPrint( char *inData, size_t inSize )
+{
+ extern void kprintf( const char *inFormat, ... );
+
+ kprintf( "%.*s", (int) inSize, inData );
+}
+#endif
+
+#if ( DEBUG_MAC_OS_X_IOLOG_ENABLED )
+//===========================================================================================================================
+// DebugMacOSXIOLogPrint
+//===========================================================================================================================
+
+static void DebugMacOSXIOLogPrint( char *inData, size_t inSize )
+{
+ extern void IOLog( const char *inFormat, ... );
+
+ IOLog( "%.*s", (int) inSize, inData );
+}
+#endif
+
+#if ( TARGET_OS_MAC )
+//===========================================================================================================================
+// DebugMacOSXLogInit
+//===========================================================================================================================
+
+static OSStatus DebugMacOSXLogInit( void )
+{
+ OSStatus err;
+ CFStringRef path;
+ CFURLRef url;
+ CFBundleRef bundle;
+ CFStringRef functionName;
+ void * functionPtr;
+
+ bundle = NULL;
+
+ // Create a bundle reference for System.framework.
+
+ path = CFSTR( "/System/Library/Frameworks/System.framework" );
+ url = CFURLCreateWithFileSystemPath( NULL, path, kCFURLPOSIXPathStyle, true );
+ require_action_quiet( url, exit, err = memFullErr );
+
+ bundle = CFBundleCreate( NULL, url );
+ CFRelease( url );
+ require_action_quiet( bundle, exit, err = memFullErr );
+
+ // Get a ptr to the system's "printf" function from System.framework.
+
+ functionName = CFSTR( "printf" );
+ functionPtr = CFBundleGetFunctionPointerForName( bundle, functionName );
+ require_action_quiet( functionPtr, exit, err = memFullErr );
+
+ // Success! Note: The bundle cannot be released because it would invalidate the function ptr.
+
+ gDebugMacOSXLogFunction = (DebugMacOSXLogFunctionPtr) functionPtr;
+ bundle = NULL;
+ err = noErr;
+
+exit:
+ if( bundle )
+ {
+ CFRelease( bundle );
+ }
+ return( err );
+}
+
+//===========================================================================================================================
+// DebugMacOSXLogPrint
+//===========================================================================================================================
+
+static void DebugMacOSXLogPrint( char *inData, size_t inSize )
+{
+ if( gDebugMacOSXLogFunction )
+ {
+ gDebugMacOSXLogFunction( "%.*s", (int) inSize, inData );
+ }
+}
+#endif
+
+#if ( TARGET_OS_WIN32 )
+//===========================================================================================================================
+// DebugWindowsDebuggerPrint
+//===========================================================================================================================
+
+void DebugWindowsDebuggerPrint( char *inData, size_t inSize )
+{
+ TCHAR buffer[ 512 ];
+ const char * src;
+ const char * end;
+ TCHAR * dst;
+ char c;
+
+ // Copy locally and null terminate the string. This also converts from char to TCHAR in case we are
+ // building with UNICODE enabled since the input is always char. Also convert \r to \n in the process.
+
+ src = inData;
+ if( inSize >= sizeof_array( buffer ) )
+ {
+ inSize = sizeof_array( buffer ) - 1;
+ }
+ end = src + inSize;
+ dst = buffer;
+ while( src < end )
+ {
+ c = *src++;
+ if( c == '\r' )
+ {
+ c = '\n';
+ }
+ *dst++ = (TCHAR) c;
+ }
+ *dst = 0;
+
+ // Print out the string to the debugger.
+
+ OutputDebugString( buffer );
+}
+#endif
+
+#if ( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+//===========================================================================================================================
+// DebugWindowsEventLogInit
+//===========================================================================================================================
+
+static OSStatus DebugWindowsEventLogInit( const char *inName, HMODULE inModule )
+{
+ OSStatus err;
+ HKEY key;
+ TCHAR name[ 128 ];
+ const char * src;
+ TCHAR path[ MAX_PATH ];
+ size_t size;
+ DWORD typesSupported;
+ DWORD n;
+
+ key = NULL;
+
+ // Use a default name if needed then convert the name to TCHARs so it works on ANSI or Unicode builds.
+
+ if( !inName || ( *inName == '\0' ) )
+ {
+ inName = "DefaultApp";
+ }
+ DebugWinCharToTCharString( inName, kSizeCString, name, sizeof( name ), NULL );
+
+ // Build the path string using the fixed registry path and app name.
+
+ src = "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\";
+ DebugWinCharToTCharString( src, kSizeCString, path, sizeof_array( path ), &size );
+ DebugWinCharToTCharString( inName, kSizeCString, path + size, sizeof_array( path ) - size, NULL );
+
+ // Add/Open the source name as a sub-key under the Application key in the EventLog registry key.
+
+ err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, path, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, NULL );
+ require_noerr_quiet( err, exit );
+
+ // Set the path in the EventMessageFile subkey. Add 1 to the TCHAR count to include the null terminator.
+
+ n = GetModuleFileName( inModule, path, sizeof_array( path ) );
+ err = translate_errno( n > 0, (OSStatus) GetLastError(), kParamErr );
+ require_noerr_quiet( err, exit );
+ n += 1;
+ n *= sizeof( TCHAR );
+
+ err = RegSetValueEx( key, TEXT( "EventMessageFile" ), 0, REG_EXPAND_SZ, (const LPBYTE) path, n );
+ require_noerr_quiet( err, exit );
+
+ // Set the supported event types in the TypesSupported subkey.
+
+ typesSupported = EVENTLOG_SUCCESS | EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE |
+ EVENTLOG_AUDIT_SUCCESS | EVENTLOG_AUDIT_FAILURE;
+ err = RegSetValueEx( key, TEXT( "TypesSupported" ), 0, REG_DWORD, (const LPBYTE) &typesSupported, sizeof( DWORD ) );
+ require_noerr_quiet( err, exit );
+
+ // Set up the event source.
+
+ gDebugWindowsEventLogEventSource = RegisterEventSource( NULL, name );
+ err = translate_errno( gDebugWindowsEventLogEventSource, (OSStatus) GetLastError(), kParamErr );
+ require_noerr_quiet( err, exit );
+
+exit:
+ if( key )
+ {
+ RegCloseKey( key );
+ }
+ return( err );
+}
+
+//===========================================================================================================================
+// DebugWindowsEventLogPrint
+//===========================================================================================================================
+
+static void DebugWindowsEventLogPrint( DebugLevel inLevel, char *inData, size_t inSize )
+{
+ WORD type;
+ TCHAR buffer[ 512 ];
+ const char * src;
+ const char * end;
+ TCHAR * dst;
+ char c;
+ const TCHAR * array[ 1 ];
+
+ // Map the debug level to a Windows EventLog type.
+
+ if( inLevel <= kDebugLevelNotice )
+ {
+ type = EVENTLOG_INFORMATION_TYPE;
+ }
+ else if( inLevel <= kDebugLevelWarning )
+ {
+ type = EVENTLOG_WARNING_TYPE;
+ }
+ else
+ {
+ type = EVENTLOG_ERROR_TYPE;
+ }
+
+ // Copy locally and null terminate the string. This also converts from char to TCHAR in case we are
+ // building with UNICODE enabled since the input is always char. Also convert \r to \n in the process.
+
+ src = inData;
+ if( inSize >= sizeof_array( buffer ) )
+ {
+ inSize = sizeof_array( buffer ) - 1;
+ }
+ end = src + inSize;
+ dst = buffer;
+ while( src < end )
+ {
+ c = *src++;
+ if( c == '\r' )
+ {
+ c = '\n';
+ }
+ *dst++ = (TCHAR) c;
+ }
+ *dst = 0;
+
+ // Add the the string to the event log.
+
+ array[ 0 ] = buffer;
+ if( gDebugWindowsEventLogEventSource )
+ {
+ ReportEvent( gDebugWindowsEventLogEventSource, type, 0, 0x20000001L, NULL, 1, 0, array, NULL );
+ }
+}
+#endif // TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE
+
+#if ( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
+//===========================================================================================================================
+// DebugAssertOutputHandler
+//===========================================================================================================================
+
+static pascal void
+DebugAssertOutputHandler(
+ OSType inComponentSignature,
+ UInt32 inOptions,
+ const char * inAssertString,
+ const char * inExceptionString,
+ const char * inErrorString,
+ const char * inFileName,
+ long inLineNumber,
+ void * inValue,
+ ConstStr255Param inOutputMsg )
+{
+ DEBUG_UNUSED( inComponentSignature );
+ DEBUG_UNUSED( inOptions );
+ DEBUG_UNUSED( inExceptionString );
+ DEBUG_UNUSED( inValue );
+ DEBUG_UNUSED( inOutputMsg );
+
+ DebugPrintAssert( 0, inAssertString, inErrorString, inFileName, (int_least32_t) inLineNumber, "" );
+}
+#endif
+
+#if 0
+#pragma mark -
+#pragma mark == Utilities ==
+#endif
+
+//===========================================================================================================================
+// DebugSNPrintF
+//
+// Stolen from mDNS.c's mDNS_snprintf/mDNS_vsnprintf with the following changes:
+//
+// Changed names to avoid name collisions with the mDNS versions.
+// Changed types to standard C types since mDNSEmbeddedAPI.h may not be available.
+// Conditionalized mDNS stuff so it can be used with or with mDNSEmbeddedAPI.h.
+// Added 64-bit support for %d (%lld), %i (%lli), %u (%llu), %o (%llo), %x (%llx), and %b (%llb).
+// Added %@ - Cocoa/CoreFoundation object. Param is the object. Strings are used directly. Others use CFCopyDescription.
+// Added %.8a - FIbre Channel address. Arg=ptr to address.
+// Added %##a - IPv4 (if AF_INET defined) or IPv6 (if AF_INET6 defined) sockaddr. Arg=ptr to sockaddr.
+// Added %b - Binary representation of integer (e.g. 01101011). Modifiers and arg=the same as %d, %x, etc.
+// Added %C - Mac-style FourCharCode (e.g. 'APPL'). Arg=32-bit value to print as a Mac-style FourCharCode.
+// Added %H - Hex Dump (e.g. "\x6b\xa7" -> "6B A7"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
+// Added %#H - Hex Dump & ASCII (e.g. "\x41\x62" -> "6B A7 'Ab'"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
+// Added %m - Error Message (e.g. 0 -> "kNoErr"). Modifiers and error code args are the same as %d, %x, etc.
+// Added %S - UTF-16 string. Host order if no BOM. Precision is UTF-16 char count. BOM counts in any precision. Arg=ptr.
+// Added %#S - Big Endian UTF-16 string (unless BOM overrides). Otherwise the same as %S.
+// Added %##S - Little Endian UTF-16 string (unless BOM overrides). Otherwise the same as %S.
+// Added %U - Universally Unique Identifier (UUID) (e.g. 6ba7b810-9dad-11d1-80b4-00c04fd430c8). Arg=ptr to 16-byte UUID.
+//===========================================================================================================================
+
+DEBUG_EXPORT size_t DebugSNPrintF(char *sbuffer, size_t buflen, const char *fmt, ...)
+{
+ size_t length;
+
+ va_list ptr;
+ va_start(ptr,fmt);
+ length = DebugSNPrintFVAList(sbuffer, buflen, fmt, ptr);
+ va_end(ptr);
+
+ return(length);
+}
+
+//===========================================================================================================================
+// DebugSNPrintFVAList - va_list version of DebugSNPrintF. See DebugSNPrintF for more info.
+//===========================================================================================================================
+
+DEBUG_EXPORT size_t DebugSNPrintFVAList(char *sbuffer, size_t buflen, const char *fmt, va_list arg)
+{
+ static const struct DebugSNPrintF_format
+ {
+ unsigned leftJustify : 1;
+ unsigned forceSign : 1;
+ unsigned zeroPad : 1;
+ unsigned havePrecision : 1;
+ unsigned hSize : 1;
+ char lSize;
+ char altForm;
+ char sign; // +, - or space
+ unsigned int fieldWidth;
+ unsigned int precision;
+ } DebugSNPrintF_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ size_t nwritten = 0;
+ int c;
+ if (buflen == 0) return(0);
+ buflen--; // Pre-reserve one space in the buffer for the terminating nul
+ if (buflen == 0) goto exit;
+
+ for (c = *fmt; c != 0; c = *++fmt)
+ {
+ if (c != '%')
+ {
+ *sbuffer++ = (char)c;
+ if (++nwritten >= buflen) goto exit;
+ }
+ else
+ {
+ size_t i=0, j;
+ // The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for
+ // generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc.
+ // The size needs to be enough for a 256-byte domain name plus some error text.
+ #define mDNS_VACB_Size 300
+ char mDNS_VACB[mDNS_VACB_Size];
+ #define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size])
+ #define mDNS_VACB_Remain(s) ((size_t)(mDNS_VACB_Lim - s))
+ char *s = mDNS_VACB_Lim;
+ const char *digits = "0123456789ABCDEF";
+ struct DebugSNPrintF_format F = DebugSNPrintF_format_default;
+
+ for(;;) // decode flags
+ {
+ c = *++fmt;
+ if (c == '-') F.leftJustify = 1;
+ else if (c == '+') F.forceSign = 1;
+ else if (c == ' ') F.sign = ' ';
+ else if (c == '#') F.altForm++;
+ else if (c == '0') F.zeroPad = 1;
+ else break;
+ }
+
+ if (c == '*') // decode field width
+ {
+ int f = va_arg(arg, int);
+ if (f < 0) { f = -f; F.leftJustify = 1; }
+ F.fieldWidth = (unsigned int)f;
+ c = *++fmt;
+ }
+ else
+ {
+ for (; c >= '0' && c <= '9'; c = *++fmt)
+ F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
+ }
+
+ if (c == '.') // decode precision
+ {
+ if ((c = *++fmt) == '*')
+ { F.precision = va_arg(arg, unsigned int); c = *++fmt; }
+ else for (; c >= '0' && c <= '9'; c = *++fmt)
+ F.precision = (10 * F.precision) + (c - '0');
+ F.havePrecision = 1;
+ }
+
+ if (F.leftJustify) F.zeroPad = 0;
+
+conv:
+ switch (c) // perform appropriate conversion
+ {
+ #if TYPE_LONGLONG_NATIVE
+ unsigned_long_long_compat n;
+ unsigned_long_long_compat base;
+ #else
+ unsigned long n;
+ unsigned long base;
+ #endif
+ case 'h': F.hSize = 1; c = *++fmt; goto conv;
+ case 'l': // fall through
+ case 'L': F.lSize++; c = *++fmt; goto conv;
+ case 'd':
+ case 'i': base = 10;
+ goto canBeSigned;
+ case 'u': base = 10;
+ goto notSigned;
+ case 'o': base = 8;
+ goto notSigned;
+ case 'b': base = 2;
+ goto notSigned;
+ case 'p': n = va_arg(arg, uintptr_t);
+ F.havePrecision = 1;
+ F.precision = (sizeof(uintptr_t) == 4) ? 8 : 16;
+ F.sign = 0;
+ base = 16;
+ c = 'x';
+ goto number;
+ case 'x': digits = "0123456789abcdef";
+ case 'X': base = 16;
+ goto notSigned;
+canBeSigned:
+ #if TYPE_LONGLONG_NATIVE
+ if (F.lSize == 1) n = (unsigned_long_long_compat)va_arg(arg, long);
+ else if (F.lSize == 2) n = (unsigned_long_long_compat)va_arg(arg, long_long_compat);
+ else n = (unsigned_long_long_compat)va_arg(arg, int);
+ #else
+ if (F.lSize == 1) n = (unsigned long)va_arg(arg, long);
+ else if (F.lSize == 2) goto exit;
+ else n = (unsigned long)va_arg(arg, int);
+ #endif
+ if (F.hSize) n = (short) n;
+ #if TYPE_LONGLONG_NATIVE
+ if ((long_long_compat) n < 0) { n = (unsigned_long_long_compat)-(long_long_compat)n; F.sign = '-'; }
+ #else
+ if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; }
+ #endif
+ else if (F.forceSign) F.sign = '+';
+ goto number;
+
+notSigned: if (F.lSize == 1) n = va_arg(arg, unsigned long);
+ else if (F.lSize == 2)
+ {
+ #if TYPE_LONGLONG_NATIVE
+ n = va_arg(arg, unsigned_long_long_compat);
+ #else
+ goto exit;
+ #endif
+ }
+ else n = va_arg(arg, unsigned int);
+ if (F.hSize) n = (unsigned short) n;
+ F.sign = 0;
+ goto number;
+
+number: if (!F.havePrecision)
+ {
+ if (F.zeroPad)
+ {
+ F.precision = F.fieldWidth;
+ if (F.altForm) F.precision -= 2;
+ if (F.sign) --F.precision;
+ }
+ if (F.precision < 1) F.precision = 1;
+ }
+ if (F.precision > mDNS_VACB_Size - 1)
+ F.precision = mDNS_VACB_Size - 1;
+ for (i = 0; n; n /= base, i++) *--s = (char)(digits[n % base]);
+ for (; i < F.precision; i++) *--s = '0';
+ if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; }
+ if (F.sign) { *--s = F.sign; i++; }
+ break;
+
+ case 'a': {
+ unsigned char *a = va_arg(arg, unsigned char *);
+ char pre[4] = "";
+ char post[32] = "";
+ if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
+ else
+ {
+ s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
+ if (F.altForm == 1)
+ {
+ #if (defined(MDNS_DEBUGMSGS))
+ mDNSAddr *ip = (mDNSAddr*)a;
+ switch (ip->type)
+ {
+ case mDNSAddrType_IPv4: F.precision = 4; a = (unsigned char *)&ip->ip.v4; break;
+ case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break;
+ default: F.precision = 0; break;
+ }
+ #else
+ F.precision = 0; // mDNSEmbeddedAPI.h not included so no mDNSAddr support
+ #endif
+ }
+ else if (F.altForm == 2)
+ {
+ #ifdef AF_INET
+ const struct sockaddr *sa;
+ unsigned char *port;
+ sa = (const struct sockaddr*)a;
+ switch (sa->sa_family)
+ {
+ case AF_INET: F.precision = 4; a = (unsigned char*)&((const struct sockaddr_in *)a)->sin_addr;
+ port = (unsigned char*)&((const struct sockaddr_in *)sa)->sin_port;
+ DebugSNPrintF(post, sizeof(post), ":%d", (port[0] << 8) | port[1]); break;
+ #ifdef AF_INET6
+ case AF_INET6: F.precision = 16; a = (unsigned char*)&((const struct sockaddr_in6 *)a)->sin6_addr;
+ pre[0] = '['; pre[1] = '\0';
+ port = (unsigned char*)&((const struct sockaddr_in6 *)sa)->sin6_port;
+ DebugSNPrintF(post, sizeof(post), "%%%d]:%d",
+ (int)((const struct sockaddr_in6 *)sa)->sin6_scope_id,
+ (port[0] << 8) | port[1]); break;
+ #endif
+ default: F.precision = 0; break;
+ }
+ #else
+ F.precision = 0; // socket interfaces not included so no sockaddr support
+ #endif
+ }
+ switch (F.precision)
+ {
+ case 4: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d%s",
+ a[0], a[1], a[2], a[3], post); break;
+ case 6: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X",
+ a[0], a[1], a[2], a[3], a[4], a[5]); break;
+ case 8: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
+ a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]); break;
+ case 16: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB),
+ "%s%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X%s",
+ pre, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8],
+ a[9], a[10], a[11], a[12], a[13], a[14], a[15], post); break;
+ default: i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify address size "
+ "(i.e. %.4a=IPv4, %.6a=Ethernet, %.8a=Fibre Channel %.16a=IPv6) >>"); break;
+ }
+ }
+ }
+ break;
+
+ case 'U': {
+ unsigned char *a = va_arg(arg, unsigned char *);
+ if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
+ else
+ {
+ s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
+ i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ *((uint32_t*) &a[0]), *((uint16_t*) &a[4]), *((uint16_t*) &a[6]),
+ a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); break;
+ }
+ }
+ break;
+
+ case 'c': *--s = (char)va_arg(arg, int); i = 1; break;
+
+ case 'C': if (F.lSize) n = va_arg(arg, unsigned long);
+ else n = va_arg(arg, unsigned int);
+ if (F.hSize) n = (unsigned short) n;
+ c = (int)( n & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
+ c = (int)((n >> 8) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
+ c = (int)((n >> 16) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
+ c = (int)((n >> 24) & 0xFF); *--s = (char)(DebugIsPrint(c) ? c : '^');
+ i = 4;
+ break;
+
+ case 's': s = va_arg(arg, char *);
+ if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
+ else switch (F.altForm)
+ {
+ case 0: i=0;
+ if (F.havePrecision) // C string
+ {
+ while((i < F.precision) && s[i]) i++;
+ // Make sure we don't truncate in the middle of a UTF-8 character.
+ // If the last character is part of a multi-byte UTF-8 character, back up to the start of it.
+ j=0;
+ while((i > 0) && ((c = s[i-1]) & 0x80)) { j++; i--; if((c & 0xC0) != 0x80) break;}
+ // If the actual count of UTF-8 characters matches the encoded UTF-8 count, add it back.
+ if((j > 1) && (j <= 6))
+ {
+ int test = (0xFF << (8-j)) & 0xFF;
+ int mask = test | (1 << ((8-j)-1));
+ if((c & mask) == test) i += j;
+ }
+ }
+ else
+ while(s[i]) i++;
+ break;
+ case 1: i = (unsigned char) *s++; break; // Pascal string
+ case 2: { // DNS label-sequence name
+ unsigned char *a = (unsigned char *)s;
+ s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
+ if (*a == 0) *s++ = '.'; // Special case for root DNS name
+ while (*a)
+ {
+ if (*a > 63) { s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; }
+ if (s + *a >= &mDNS_VACB[254]) { s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; }
+ s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "%#s.", a);
+ a += 1 + *a;
+ }
+ i = (size_t)(s - mDNS_VACB);
+ s = mDNS_VACB; // Reset s back to the start of the buffer
+ break;
+ }
+ }
+ if (F.havePrecision && i > F.precision) // Make sure we don't truncate in the middle of a UTF-8 character
+ { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--;}
+ break;
+
+ case 'S': { // UTF-16 string
+ unsigned char *a = va_arg(arg, unsigned char *);
+ uint16_t *u = (uint16_t*)a;
+ if (!u) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
+ if ((!F.havePrecision || F.precision))
+ {
+ if ((a[0] == 0xFE) && (a[1] == 0xFF)) { F.altForm = 1; u += 1; a += 2; F.precision--; } // Big Endian
+ else if ((a[0] == 0xFF) && (a[1] == 0xFE)) { F.altForm = 2; u += 1; a += 2; F.precision--; } // Little Endian
+ }
+ s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
+ switch (F.altForm)
+ {
+ case 0: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s)) // Host Endian
+ { c = u[i]; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; }
+ break;
+ case 1: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s)) // Big Endian
+ { c = ((a[0] << 8) | a[1]) & 0xFF; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; a += 2; }
+ break;
+ case 2: while ((!F.havePrecision || (i < F.precision)) && u[i] && mDNS_VACB_Remain(s)) // Little Endian
+ { c = ((a[1] << 8) | a[0]) & 0xFF; *s++ = (char)(DebugIsPrint(c) ? c : '^'); i++; a += 2; }
+ break;
+ }
+ }
+ s = mDNS_VACB; // Reset s back to the start of the buffer
+ break;
+
+ #if TARGET_OS_MAC
+ case '@': { // Cocoa/CoreFoundation object
+ CFTypeRef cfObj;
+ CFStringRef cfStr;
+ cfObj = (CFTypeRef) va_arg(arg, void *);
+ cfStr = (CFGetTypeID(cfObj) == CFStringGetTypeID()) ? (CFStringRef)CFRetain(cfObj) : CFCopyDescription(cfObj);
+ s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
+ if (cfStr)
+ {
+ CFRange range;
+ CFIndex m;
+ range = CFRangeMake(0, CFStringGetLength(cfStr));
+ m = 0;
+ CFStringGetBytes(cfStr, range, kCFStringEncodingUTF8, '^', false, (UInt8*)mDNS_VACB, (CFIndex)sizeof(mDNS_VACB), &m);
+ CFRelease(cfStr);
+ i = (size_t) m;
+ }
+ else
+ {
+ i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "%s", "ERROR: <invalid CF object>" );
+ }
+ }
+ if (F.havePrecision && i > F.precision) // Make sure we don't truncate in the middle of a UTF-8 character
+ { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--;}
+ break;
+ #endif
+
+ case 'm': { // Error Message
+ long err;
+ if (F.lSize) err = va_arg(arg, long);
+ else err = va_arg(arg, int);
+ if (F.hSize) err = (short)err;
+ DebugGetErrorString(err, mDNS_VACB, sizeof(mDNS_VACB));
+ s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
+ for(i=0; s[i]; i++) {}
+ }
+ break;
+
+ case 'H': { // Hex Dump
+ void *a = va_arg(arg, void *);
+ size_t size = (size_t)va_arg(arg, int);
+ size_t max = (size_t)va_arg(arg, int);
+ DebugFlags flags =
+ kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoNewLine |
+ kDebugFlags8BitSeparator | kDebugFlagsNo32BitSeparator |
+ kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount;
+ if (F.altForm == 0) flags |= kDebugFlagsNoASCII;
+ size = (max < size) ? max : size;
+ s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
+ i = DebugHexDump(kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, a, a, size, flags, mDNS_VACB, sizeof(mDNS_VACB));
+ }
+ break;
+
+ case 'v': { // Version
+ uint32_t version;
+ version = va_arg(arg, unsigned int);
+ DebugNumVersionToString(version, mDNS_VACB);
+ s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end
+ for(i=0; s[i]; i++) {}
+ }
+ break;
+
+ case 'n': s = va_arg(arg, char *);
+ if (F.hSize) *(short *) s = (short)nwritten;
+ else if (F.lSize) *(long *) s = (long)nwritten;
+ else *(int *) s = (int)nwritten;
+ continue;
+
+ default: s = mDNS_VACB;
+ i = DebugSNPrintF(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c);
+
+ case '%': *sbuffer++ = (char)c;
+ if (++nwritten >= buflen) goto exit;
+ break;
+ }
+
+ if (i < F.fieldWidth && !F.leftJustify) // Pad on the left
+ do {
+ *sbuffer++ = ' ';
+ if (++nwritten >= buflen) goto exit;
+ } while (i < --F.fieldWidth);
+
+ if (i > buflen - nwritten) // Make sure we don't truncate in the middle of a UTF-8 character
+ { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--;}
+ for (j=0; j<i; j++) *sbuffer++ = *s++; // Write the converted result
+ nwritten += i;
+ if (nwritten >= buflen) goto exit;
+
+ for (; i < F.fieldWidth; i++) // Pad on the right
+ {
+ *sbuffer++ = ' ';
+ if (++nwritten >= buflen) goto exit;
+ }
+ }
+ }
+exit:
+ *sbuffer++ = 0;
+ return(nwritten);
+}
+
+//===========================================================================================================================
+// DebugGetErrorString
+//===========================================================================================================================
+
+DEBUG_EXPORT const char * DebugGetErrorString( int_least32_t inErrorCode, char *inBuffer, size_t inBufferSize )
+{
+ const char * s;
+ char * dst;
+ char * end;
+#if ( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+ char buffer[ 256 ];
+#endif
+
+ switch( inErrorCode )
+ {
+ #define CaseErrorString( X, STR ) case X: s = STR; break
+ #define CaseErrorStringify( X ) case X: s = # X; break
+ #define CaseErrorStringifyHardCode( VALUE, X ) case VALUE: s = # X; break
+
+ // General Errors
+
+ CaseErrorString( 0, "no error" );
+ CaseErrorString( 1, "in-progress/waiting" );
+ CaseErrorString( -1, "catch-all unknown error" );
+
+ // ACP Errors
+
+ CaseErrorStringifyHardCode( -2, kACPBadRequestErr );
+ CaseErrorStringifyHardCode( -3, kACPNoMemoryErr );
+ CaseErrorStringifyHardCode( -4, kACPBadParamErr );
+ CaseErrorStringifyHardCode( -5, kACPNotFoundErr );
+ CaseErrorStringifyHardCode( -6, kACPBadChecksumErr );
+ CaseErrorStringifyHardCode( -7, kACPCommandNotHandledErr );
+ CaseErrorStringifyHardCode( -8, kACPNetworkErr );
+ CaseErrorStringifyHardCode( -9, kACPDuplicateCommandHandlerErr );
+ CaseErrorStringifyHardCode( -10, kACPUnknownPropertyErr );
+ CaseErrorStringifyHardCode( -11, kACPImmutablePropertyErr );
+ CaseErrorStringifyHardCode( -12, kACPBadPropertyValueErr );
+ CaseErrorStringifyHardCode( -13, kACPNoResourcesErr );
+ CaseErrorStringifyHardCode( -14, kACPBadOptionErr );
+ CaseErrorStringifyHardCode( -15, kACPBadSizeErr );
+ CaseErrorStringifyHardCode( -16, kACPBadPasswordErr );
+ CaseErrorStringifyHardCode( -17, kACPNotInitializedErr );
+ CaseErrorStringifyHardCode( -18, kACPNonReadablePropertyErr );
+ CaseErrorStringifyHardCode( -19, kACPBadVersionErr );
+ CaseErrorStringifyHardCode( -20, kACPBadSignatureErr );
+ CaseErrorStringifyHardCode( -21, kACPBadIndexErr );
+ CaseErrorStringifyHardCode( -22, kACPUnsupportedErr );
+ CaseErrorStringifyHardCode( -23, kACPInUseErr );
+ CaseErrorStringifyHardCode( -24, kACPParamCountErr );
+ CaseErrorStringifyHardCode( -25, kACPIDErr );
+ CaseErrorStringifyHardCode( -26, kACPFormatErr );
+ CaseErrorStringifyHardCode( -27, kACPUnknownUserErr );
+ CaseErrorStringifyHardCode( -28, kACPAccessDeniedErr );
+ CaseErrorStringifyHardCode( -29, kACPIncorrectFWErr );
+
+ // Common Services Errors
+
+ CaseErrorStringify( kUnknownErr );
+ CaseErrorStringify( kOptionErr );
+ CaseErrorStringify( kSelectorErr );
+ CaseErrorStringify( kExecutionStateErr );
+ CaseErrorStringify( kPathErr );
+ CaseErrorStringify( kParamErr );
+ CaseErrorStringify( kParamCountErr );
+ CaseErrorStringify( kCommandErr );
+ CaseErrorStringify( kIDErr );
+ CaseErrorStringify( kStateErr );
+ CaseErrorStringify( kRangeErr );
+ CaseErrorStringify( kRequestErr );
+ CaseErrorStringify( kResponseErr );
+ CaseErrorStringify( kChecksumErr );
+ CaseErrorStringify( kNotHandledErr );
+ CaseErrorStringify( kVersionErr );
+ CaseErrorStringify( kSignatureErr );
+ CaseErrorStringify( kFormatErr );
+ CaseErrorStringify( kNotInitializedErr );
+ CaseErrorStringify( kAlreadyInitializedErr );
+ CaseErrorStringify( kNotInUseErr );
+ CaseErrorStringify( kInUseErr );
+ CaseErrorStringify( kTimeoutErr );
+ CaseErrorStringify( kCanceledErr );
+ CaseErrorStringify( kAlreadyCanceledErr );
+ CaseErrorStringify( kCannotCancelErr );
+ CaseErrorStringify( kDeletedErr );
+ CaseErrorStringify( kNotFoundErr );
+ CaseErrorStringify( kNoMemoryErr );
+ CaseErrorStringify( kNoResourcesErr );
+ CaseErrorStringify( kDuplicateErr );
+ CaseErrorStringify( kImmutableErr );
+ CaseErrorStringify( kUnsupportedDataErr );
+ CaseErrorStringify( kIntegrityErr );
+ CaseErrorStringify( kIncompatibleErr );
+ CaseErrorStringify( kUnsupportedErr );
+ CaseErrorStringify( kUnexpectedErr );
+ CaseErrorStringify( kValueErr );
+ CaseErrorStringify( kNotReadableErr );
+ CaseErrorStringify( kNotWritableErr );
+ CaseErrorStringify( kBadReferenceErr );
+ CaseErrorStringify( kFlagErr );
+ CaseErrorStringify( kMalformedErr );
+ CaseErrorStringify( kSizeErr );
+ CaseErrorStringify( kNameErr );
+ CaseErrorStringify( kNotReadyErr );
+ CaseErrorStringify( kReadErr );
+ CaseErrorStringify( kWriteErr );
+ CaseErrorStringify( kMismatchErr );
+ CaseErrorStringify( kDateErr );
+ CaseErrorStringify( kUnderrunErr );
+ CaseErrorStringify( kOverrunErr );
+ CaseErrorStringify( kEndingErr );
+ CaseErrorStringify( kConnectionErr );
+ CaseErrorStringify( kAuthenticationErr );
+ CaseErrorStringify( kOpenErr );
+ CaseErrorStringify( kTypeErr );
+ CaseErrorStringify( kSkipErr );
+ CaseErrorStringify( kNoAckErr );
+ CaseErrorStringify( kCollisionErr );
+ CaseErrorStringify( kBackoffErr );
+ CaseErrorStringify( kNoAddressAckErr );
+ CaseErrorStringify( kBusyErr );
+ CaseErrorStringify( kNoSpaceErr );
+
+ // mDNS/DNS-SD Errors
+
+ CaseErrorStringifyHardCode( -65537, mStatus_UnknownErr );
+ CaseErrorStringifyHardCode( -65538, mStatus_NoSuchNameErr );
+ CaseErrorStringifyHardCode( -65539, mStatus_NoMemoryErr );
+ CaseErrorStringifyHardCode( -65540, mStatus_BadParamErr );
+ CaseErrorStringifyHardCode( -65541, mStatus_BadReferenceErr );
+ CaseErrorStringifyHardCode( -65542, mStatus_BadStateErr );
+ CaseErrorStringifyHardCode( -65543, mStatus_BadFlagsErr );
+ CaseErrorStringifyHardCode( -65544, mStatus_UnsupportedErr );
+ CaseErrorStringifyHardCode( -65545, mStatus_NotInitializedErr );
+ CaseErrorStringifyHardCode( -65546, mStatus_NoCache );
+ CaseErrorStringifyHardCode( -65547, mStatus_AlreadyRegistered );
+ CaseErrorStringifyHardCode( -65548, mStatus_NameConflict );
+ CaseErrorStringifyHardCode( -65549, mStatus_Invalid );
+ CaseErrorStringifyHardCode( -65550, mStatus_GrowCache );
+ CaseErrorStringifyHardCode( -65551, mStatus_BadInterfaceErr );
+ CaseErrorStringifyHardCode( -65552, mStatus_Incompatible );
+ CaseErrorStringifyHardCode( -65791, mStatus_ConfigChanged );
+ CaseErrorStringifyHardCode( -65792, mStatus_MemFree );
+
+ // RSP Errors
+
+ CaseErrorStringifyHardCode( -400000, kRSPUnknownErr );
+ CaseErrorStringifyHardCode( -400050, kRSPParamErr );
+ CaseErrorStringifyHardCode( -400108, kRSPNoMemoryErr );
+ CaseErrorStringifyHardCode( -405246, kRSPRangeErr );
+ CaseErrorStringifyHardCode( -409057, kRSPSizeErr );
+ CaseErrorStringifyHardCode( -400200, kRSPHardwareErr );
+ CaseErrorStringifyHardCode( -401712, kRSPTimeoutErr );
+ CaseErrorStringifyHardCode( -402053, kRSPUnsupportedErr );
+ CaseErrorStringifyHardCode( -402419, kRSPIDErr );
+ CaseErrorStringifyHardCode( -403165, kRSPFlagErr );
+ CaseErrorString( -200000, "kRSPControllerStatusBase - 0x50" );
+ CaseErrorString( -200080, "kRSPCommandSucceededErr - 0x50" );
+ CaseErrorString( -200001, "kRSPCommandFailedErr - 0x01" );
+ CaseErrorString( -200051, "kRSPChecksumErr - 0x33" );
+ CaseErrorString( -200132, "kRSPCommandTimeoutErr - 0x84" );
+ CaseErrorString( -200034, "kRSPPasswordRequiredErr - 0x22 OBSOLETE" );
+ CaseErrorString( -200128, "kRSPCanceledErr - 0x02 Async" );
+
+ // XML Errors
+
+ CaseErrorStringifyHardCode( -100043, kXMLNotFoundErr );
+ CaseErrorStringifyHardCode( -100050, kXMLParamErr );
+ CaseErrorStringifyHardCode( -100108, kXMLNoMemoryErr );
+ CaseErrorStringifyHardCode( -100206, kXMLFormatErr );
+ CaseErrorStringifyHardCode( -100586, kXMLNoRootElementErr );
+ CaseErrorStringifyHardCode( -101703, kXMLWrongDataTypeErr );
+ CaseErrorStringifyHardCode( -101726, kXMLKeyErr );
+ CaseErrorStringifyHardCode( -102053, kXMLUnsupportedErr );
+ CaseErrorStringifyHardCode( -102063, kXMLMissingElementErr );
+ CaseErrorStringifyHardCode( -103026, kXMLParseErr );
+ CaseErrorStringifyHardCode( -103159, kXMLBadDataErr );
+ CaseErrorStringifyHardCode( -103170, kXMLBadNameErr );
+ CaseErrorStringifyHardCode( -105246, kXMLRangeErr );
+ CaseErrorStringifyHardCode( -105251, kXMLUnknownElementErr );
+ CaseErrorStringifyHardCode( -108739, kXMLMalformedInputErr );
+ CaseErrorStringifyHardCode( -109057, kXMLBadSizeErr );
+ CaseErrorStringifyHardCode( -101730, kXMLMissingChildElementErr );
+ CaseErrorStringifyHardCode( -102107, kXMLMissingParentElementErr );
+ CaseErrorStringifyHardCode( -130587, kXMLNonRootElementErr );
+ CaseErrorStringifyHardCode( -102015, kXMLDateErr );
+
+ #if ( __MACH__ )
+
+ // Mach Errors
+
+ CaseErrorStringifyHardCode( 0x00002000, MACH_MSG_IPC_SPACE );
+ CaseErrorStringifyHardCode( 0x00001000, MACH_MSG_VM_SPACE );
+ CaseErrorStringifyHardCode( 0x00000800, MACH_MSG_IPC_KERNEL );
+ CaseErrorStringifyHardCode( 0x00000400, MACH_MSG_VM_KERNEL );
+ CaseErrorStringifyHardCode( 0x10000001, MACH_SEND_IN_PROGRESS );
+ CaseErrorStringifyHardCode( 0x10000002, MACH_SEND_INVALID_DATA );
+ CaseErrorStringifyHardCode( 0x10000003, MACH_SEND_INVALID_DEST );
+ CaseErrorStringifyHardCode( 0x10000004, MACH_SEND_TIMED_OUT );
+ CaseErrorStringifyHardCode( 0x10000007, MACH_SEND_INTERRUPTED );
+ CaseErrorStringifyHardCode( 0x10000008, MACH_SEND_MSG_TOO_SMALL );
+ CaseErrorStringifyHardCode( 0x10000009, MACH_SEND_INVALID_REPLY );
+ CaseErrorStringifyHardCode( 0x1000000A, MACH_SEND_INVALID_RIGHT );
+ CaseErrorStringifyHardCode( 0x1000000B, MACH_SEND_INVALID_NOTIFY );
+ CaseErrorStringifyHardCode( 0x1000000C, MACH_SEND_INVALID_MEMORY );
+ CaseErrorStringifyHardCode( 0x1000000D, MACH_SEND_NO_BUFFER );
+ CaseErrorStringifyHardCode( 0x1000000E, MACH_SEND_TOO_LARGE );
+ CaseErrorStringifyHardCode( 0x1000000F, MACH_SEND_INVALID_TYPE );
+ CaseErrorStringifyHardCode( 0x10000010, MACH_SEND_INVALID_HEADER );
+ CaseErrorStringifyHardCode( 0x10000011, MACH_SEND_INVALID_TRAILER );
+ CaseErrorStringifyHardCode( 0x10000015, MACH_SEND_INVALID_RT_OOL_SIZE );
+ CaseErrorStringifyHardCode( 0x10004001, MACH_RCV_IN_PROGRESS );
+ CaseErrorStringifyHardCode( 0x10004002, MACH_RCV_INVALID_NAME );
+ CaseErrorStringifyHardCode( 0x10004003, MACH_RCV_TIMED_OUT );
+ CaseErrorStringifyHardCode( 0x10004004, MACH_RCV_TOO_LARGE );
+ CaseErrorStringifyHardCode( 0x10004005, MACH_RCV_INTERRUPTED );
+ CaseErrorStringifyHardCode( 0x10004006, MACH_RCV_PORT_CHANGED );
+ CaseErrorStringifyHardCode( 0x10004007, MACH_RCV_INVALID_NOTIFY );
+ CaseErrorStringifyHardCode( 0x10004008, MACH_RCV_INVALID_DATA );
+ CaseErrorStringifyHardCode( 0x10004009, MACH_RCV_PORT_DIED );
+ CaseErrorStringifyHardCode( 0x1000400A, MACH_RCV_IN_SET );
+ CaseErrorStringifyHardCode( 0x1000400B, MACH_RCV_HEADER_ERROR );
+ CaseErrorStringifyHardCode( 0x1000400C, MACH_RCV_BODY_ERROR );
+ CaseErrorStringifyHardCode( 0x1000400D, MACH_RCV_INVALID_TYPE );
+ CaseErrorStringifyHardCode( 0x1000400E, MACH_RCV_SCATTER_SMALL );
+ CaseErrorStringifyHardCode( 0x1000400F, MACH_RCV_INVALID_TRAILER );
+ CaseErrorStringifyHardCode( 0x10004011, MACH_RCV_IN_PROGRESS_TIMED );
+
+ // Mach OSReturn Errors
+
+ CaseErrorStringifyHardCode( 0xDC000001, kOSReturnError );
+ CaseErrorStringifyHardCode( 0xDC004001, kOSMetaClassInternal );
+ CaseErrorStringifyHardCode( 0xDC004002, kOSMetaClassHasInstances );
+ CaseErrorStringifyHardCode( 0xDC004003, kOSMetaClassNoInit );
+ CaseErrorStringifyHardCode( 0xDC004004, kOSMetaClassNoTempData );
+ CaseErrorStringifyHardCode( 0xDC004005, kOSMetaClassNoDicts );
+ CaseErrorStringifyHardCode( 0xDC004006, kOSMetaClassNoKModSet );
+ CaseErrorStringifyHardCode( 0xDC004007, kOSMetaClassNoInsKModSet );
+ CaseErrorStringifyHardCode( 0xDC004008, kOSMetaClassNoSuper );
+ CaseErrorStringifyHardCode( 0xDC004009, kOSMetaClassInstNoSuper );
+ CaseErrorStringifyHardCode( 0xDC00400A, kOSMetaClassDuplicateClass );
+
+ // IOKit Errors
+
+ CaseErrorStringifyHardCode( 0xE00002BC, kIOReturnError );
+ CaseErrorStringifyHardCode( 0xE00002BD, kIOReturnNoMemory );
+ CaseErrorStringifyHardCode( 0xE00002BE, kIOReturnNoResources );
+ CaseErrorStringifyHardCode( 0xE00002BF, kIOReturnIPCError );
+ CaseErrorStringifyHardCode( 0xE00002C0, kIOReturnNoDevice );
+ CaseErrorStringifyHardCode( 0xE00002C1, kIOReturnNotPrivileged );
+ CaseErrorStringifyHardCode( 0xE00002C2, kIOReturnBadArgument );
+ CaseErrorStringifyHardCode( 0xE00002C3, kIOReturnLockedRead );
+ CaseErrorStringifyHardCode( 0xE00002C4, kIOReturnLockedWrite );
+ CaseErrorStringifyHardCode( 0xE00002C5, kIOReturnExclusiveAccess );
+ CaseErrorStringifyHardCode( 0xE00002C6, kIOReturnBadMessageID );
+ CaseErrorStringifyHardCode( 0xE00002C7, kIOReturnUnsupported );
+ CaseErrorStringifyHardCode( 0xE00002C8, kIOReturnVMError );
+ CaseErrorStringifyHardCode( 0xE00002C9, kIOReturnInternalError );
+ CaseErrorStringifyHardCode( 0xE00002CA, kIOReturnIOError );
+ CaseErrorStringifyHardCode( 0xE00002CC, kIOReturnCannotLock );
+ CaseErrorStringifyHardCode( 0xE00002CD, kIOReturnNotOpen );
+ CaseErrorStringifyHardCode( 0xE00002CE, kIOReturnNotReadable );
+ CaseErrorStringifyHardCode( 0xE00002CF, kIOReturnNotWritable );
+ CaseErrorStringifyHardCode( 0xE00002D0, kIOReturnNotAligned );
+ CaseErrorStringifyHardCode( 0xE00002D1, kIOReturnBadMedia );
+ CaseErrorStringifyHardCode( 0xE00002D2, kIOReturnStillOpen );
+ CaseErrorStringifyHardCode( 0xE00002D3, kIOReturnRLDError );
+ CaseErrorStringifyHardCode( 0xE00002D4, kIOReturnDMAError );
+ CaseErrorStringifyHardCode( 0xE00002D5, kIOReturnBusy );
+ CaseErrorStringifyHardCode( 0xE00002D6, kIOReturnTimeout );
+ CaseErrorStringifyHardCode( 0xE00002D7, kIOReturnOffline );
+ CaseErrorStringifyHardCode( 0xE00002D8, kIOReturnNotReady );
+ CaseErrorStringifyHardCode( 0xE00002D9, kIOReturnNotAttached );
+ CaseErrorStringifyHardCode( 0xE00002DA, kIOReturnNoChannels );
+ CaseErrorStringifyHardCode( 0xE00002DB, kIOReturnNoSpace );
+ CaseErrorStringifyHardCode( 0xE00002DD, kIOReturnPortExists );
+ CaseErrorStringifyHardCode( 0xE00002DE, kIOReturnCannotWire );
+ CaseErrorStringifyHardCode( 0xE00002DF, kIOReturnNoInterrupt );
+ CaseErrorStringifyHardCode( 0xE00002E0, kIOReturnNoFrames );
+ CaseErrorStringifyHardCode( 0xE00002E1, kIOReturnMessageTooLarge );
+ CaseErrorStringifyHardCode( 0xE00002E2, kIOReturnNotPermitted );
+ CaseErrorStringifyHardCode( 0xE00002E3, kIOReturnNoPower );
+ CaseErrorStringifyHardCode( 0xE00002E4, kIOReturnNoMedia );
+ CaseErrorStringifyHardCode( 0xE00002E5, kIOReturnUnformattedMedia );
+ CaseErrorStringifyHardCode( 0xE00002E6, kIOReturnUnsupportedMode );
+ CaseErrorStringifyHardCode( 0xE00002E7, kIOReturnUnderrun );
+ CaseErrorStringifyHardCode( 0xE00002E8, kIOReturnOverrun );
+ CaseErrorStringifyHardCode( 0xE00002E9, kIOReturnDeviceError );
+ CaseErrorStringifyHardCode( 0xE00002EA, kIOReturnNoCompletion );
+ CaseErrorStringifyHardCode( 0xE00002EB, kIOReturnAborted );
+ CaseErrorStringifyHardCode( 0xE00002EC, kIOReturnNoBandwidth );
+ CaseErrorStringifyHardCode( 0xE00002ED, kIOReturnNotResponding );
+ CaseErrorStringifyHardCode( 0xE00002EE, kIOReturnIsoTooOld );
+ CaseErrorStringifyHardCode( 0xE00002EF, kIOReturnIsoTooNew );
+ CaseErrorStringifyHardCode( 0xE00002F0, kIOReturnNotFound );
+ CaseErrorStringifyHardCode( 0xE0000001, kIOReturnInvalid );
+
+ // IOKit FireWire Errors
+
+ CaseErrorStringifyHardCode( 0xE0008010, kIOFireWireResponseBase );
+ CaseErrorStringifyHardCode( 0xE0008020, kIOFireWireBusReset );
+ CaseErrorStringifyHardCode( 0xE0008001, kIOConfigNoEntry );
+ CaseErrorStringifyHardCode( 0xE0008002, kIOFireWirePending );
+ CaseErrorStringifyHardCode( 0xE0008003, kIOFireWireLastDCLToken );
+ CaseErrorStringifyHardCode( 0xE0008004, kIOFireWireConfigROMInvalid );
+ CaseErrorStringifyHardCode( 0xE0008005, kIOFireWireAlreadyRegistered );
+ CaseErrorStringifyHardCode( 0xE0008006, kIOFireWireMultipleTalkers );
+ CaseErrorStringifyHardCode( 0xE0008007, kIOFireWireChannelActive );
+ CaseErrorStringifyHardCode( 0xE0008008, kIOFireWireNoListenerOrTalker );
+ CaseErrorStringifyHardCode( 0xE0008009, kIOFireWireNoChannels );
+ CaseErrorStringifyHardCode( 0xE000800A, kIOFireWireChannelNotAvailable );
+ CaseErrorStringifyHardCode( 0xE000800B, kIOFireWireSeparateBus );
+ CaseErrorStringifyHardCode( 0xE000800C, kIOFireWireBadSelfIDs );
+ CaseErrorStringifyHardCode( 0xE000800D, kIOFireWireLowCableVoltage );
+ CaseErrorStringifyHardCode( 0xE000800E, kIOFireWireInsufficientPower );
+ CaseErrorStringifyHardCode( 0xE000800F, kIOFireWireOutOfTLabels );
+ CaseErrorStringifyHardCode( 0xE0008101, kIOFireWireBogusDCLProgram );
+ CaseErrorStringifyHardCode( 0xE0008102, kIOFireWireTalkingAndListening );
+ CaseErrorStringifyHardCode( 0xE0008103, kIOFireWireHardwareSlept );
+ CaseErrorStringifyHardCode( 0xE00087D0, kIOFWMessageServiceIsRequestingClose );
+ CaseErrorStringifyHardCode( 0xE00087D1, kIOFWMessagePowerStateChanged );
+ CaseErrorStringifyHardCode( 0xE00087D2, kIOFWMessageTopologyChanged );
+
+ // IOKit USB Errors
+
+ CaseErrorStringifyHardCode( 0xE0004061, kIOUSBUnknownPipeErr );
+ CaseErrorStringifyHardCode( 0xE0004060, kIOUSBTooManyPipesErr );
+ CaseErrorStringifyHardCode( 0xE000405F, kIOUSBNoAsyncPortErr );
+ CaseErrorStringifyHardCode( 0xE000405E, kIOUSBNotEnoughPipesErr );
+ CaseErrorStringifyHardCode( 0xE000405D, kIOUSBNotEnoughPowerErr );
+ CaseErrorStringifyHardCode( 0xE0004057, kIOUSBEndpointNotFound );
+ CaseErrorStringifyHardCode( 0xE0004056, kIOUSBConfigNotFound );
+ CaseErrorStringifyHardCode( 0xE0004051, kIOUSBTransactionTimeout );
+ CaseErrorStringifyHardCode( 0xE0004050, kIOUSBTransactionReturned );
+ CaseErrorStringifyHardCode( 0xE000404F, kIOUSBPipeStalled );
+ CaseErrorStringifyHardCode( 0xE000404E, kIOUSBInterfaceNotFound );
+ CaseErrorStringifyHardCode( 0xE000404D, kIOUSBLowLatencyBufferNotPreviouslyAllocated );
+ CaseErrorStringifyHardCode( 0xE000404C, kIOUSBLowLatencyFrameListNotPreviouslyAllocated );
+ CaseErrorStringifyHardCode( 0xE000404B, kIOUSBHighSpeedSplitError );
+ CaseErrorStringifyHardCode( 0xE0004010, kIOUSBLinkErr );
+ CaseErrorStringifyHardCode( 0xE000400F, kIOUSBNotSent2Err );
+ CaseErrorStringifyHardCode( 0xE000400E, kIOUSBNotSent1Err );
+ CaseErrorStringifyHardCode( 0xE000400D, kIOUSBBufferUnderrunErr );
+ CaseErrorStringifyHardCode( 0xE000400C, kIOUSBBufferOverrunErr );
+ CaseErrorStringifyHardCode( 0xE000400B, kIOUSBReserved2Err );
+ CaseErrorStringifyHardCode( 0xE000400A, kIOUSBReserved1Err );
+ CaseErrorStringifyHardCode( 0xE0004007, kIOUSBWrongPIDErr );
+ CaseErrorStringifyHardCode( 0xE0004006, kIOUSBPIDCheckErr );
+ CaseErrorStringifyHardCode( 0xE0004003, kIOUSBDataToggleErr );
+ CaseErrorStringifyHardCode( 0xE0004002, kIOUSBBitstufErr );
+ CaseErrorStringifyHardCode( 0xE0004001, kIOUSBCRCErr );
+
+ #endif // __MACH__
+
+ // Other Errors
+
+ default:
+ s = NULL;
+ #if ( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+ if( inBuffer && ( inBufferSize > 0 ) )
+ {
+ DWORD n;
+
+ n = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, (DWORD) inErrorCode,
+ MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), buffer, sizeof( buffer ), NULL );
+ if( n > 0 )
+ {
+ // Remove any trailing CR's or LF's since some messages have them.
+
+ while( ( n > 0 ) && isspace( ( (unsigned char *) buffer )[ n - 1 ] ) )
+ {
+ buffer[ --n ] = '\0';
+ }
+ s = buffer;
+ }
+ }
+ #endif
+
+ if( !s )
+ {
+ #if ( !TARGET_API_MAC_OSX_KERNEL && !TARGET_OS_WINDOWS_CE )
+ s = strerror( inErrorCode );
+ #endif
+ if( !s )
+ {
+ s = "<unknown error code>";
+ }
+ }
+ break;
+ }
+
+ // Copy the string to the output buffer. If no buffer is supplied or it is empty, return an empty string.
+
+ if( inBuffer && ( inBufferSize > 0 ) )
+ {
+ dst = inBuffer;
+ end = dst + ( inBufferSize - 1 );
+ while( ( ( end - dst ) > 0 ) && ( *s != '\0' ) )
+ {
+ *dst++ = *s++;
+ }
+ *dst = '\0';
+ s = inBuffer;
+ }
+ return( s );
+}
+
+//===========================================================================================================================
+// DebugHexDump
+//===========================================================================================================================
+
+DEBUG_EXPORT size_t
+DebugHexDump(
+ DebugLevel inLevel,
+ int inIndent,
+ const char * inLabel,
+ size_t inLabelSize,
+ int inLabelMinWidth,
+ const char * inType,
+ size_t inTypeSize,
+ const void * inDataStart,
+ const void * inData,
+ size_t inDataSize,
+ DebugFlags inFlags,
+ char * outBuffer,
+ size_t inBufferSize )
+{
+ static const char kHexChars[] = "0123456789ABCDEF";
+ const uint8_t * start;
+ const uint8_t * src;
+ char * dst;
+ char * end;
+ size_t n;
+ int offset;
+ int width;
+ const char * newline;
+ char separator[ 8 ];
+ char * s;
+
+ DEBUG_UNUSED( inType );
+ DEBUG_UNUSED( inTypeSize );
+
+ // Set up the function-wide variables.
+
+ if( inLabelSize == kSizeCString )
+ {
+ inLabelSize = strlen( inLabel );
+ }
+ start = (const uint8_t *) inData;
+ src = start;
+ dst = outBuffer;
+ end = dst + inBufferSize;
+ offset = (int)( (intptr_t) inData - (intptr_t) inDataStart );
+ width = ( (int) inLabelSize > inLabelMinWidth ) ? (int) inLabelSize : inLabelMinWidth;
+ newline = ( inFlags & kDebugFlagsNoNewLine ) ? "" : "\n";
+
+ // Set up the separator string. This is used to insert spaces on subsequent "lines" when not using newlines.
+
+ s = separator;
+ if( inFlags & kDebugFlagsNoNewLine )
+ {
+ if( inFlags & kDebugFlags8BitSeparator )
+ {
+ *s++ = ' ';
+ }
+ if( inFlags & kDebugFlags16BitSeparator )
+ {
+ *s++ = ' ';
+ }
+ if( !( inFlags & kDebugFlagsNo32BitSeparator ) )
+ {
+ *s++ = ' ';
+ }
+ check( ( (size_t)( s - separator ) ) < sizeof( separator ) );
+ }
+ *s = '\0';
+
+ for( ;; )
+ {
+ char prefixString[ 32 ];
+ char hexString[ 64 ];
+ char asciiString[ 32 ];
+ char byteCountString[ 32 ];
+ int c;
+ size_t chunkSize;
+ size_t i;
+
+ // If this is a label-only item (i.e. no data), print the label (accounting for prefix string spacing) and exit.
+
+ if( inDataSize == 0 )
+ {
+ if( inLabel && ( inLabelSize > 0 ) )
+ {
+ width = 0;
+ if( !( inFlags & kDebugFlagsNoAddress ) )
+ {
+ width += 8; // "00000000"
+ if( !( inFlags & kDebugFlagsNoOffset ) )
+ {
+ width += 1; // "+"
+ }
+ }
+ if( inFlags & kDebugFlags32BitOffset )
+ {
+ width += 8; // "00000000"
+ }
+ else if( !( inFlags & kDebugFlagsNoOffset ) )
+ {
+ width += 4; // "0000"
+ }
+
+ if( outBuffer )
+ {
+ dst += DebugSNPrintF( dst, (size_t)( end - dst ), "%*s" "%-*.*s" "%.*s" "%s",
+ width, "",
+ ( width > 0 ) ? ": " : "",
+ width, (int) inLabelSize, inLabel,
+ newline );
+ }
+ else
+ {
+ dst += DebugPrintF( inLevel, "%*s" "%-*.*s" "%.*s" "%s",
+ width, "",
+ ( width > 0 ) ? ": " : "",
+ width, (int) inLabelSize, inLabel,
+ newline );
+ }
+ }
+ break;
+ }
+
+ // Build the prefix string. It will be in one of the following formats:
+ //
+ // 1) "00000000+0000[0000]" (address and offset)
+ // 2) "00000000" (address only)
+ // 3) "0000[0000]" (offset only)
+ // 4) "" (no address or offset)
+ //
+ // Note: If we're printing multiple "lines", but not printing newlines, a space is used to separate.
+
+ s = prefixString;
+ if( !( inFlags & kDebugFlagsNoAddress ) )
+ {
+ *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 28 ) & 0xF ];
+ *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 24 ) & 0xF ];
+ *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 20 ) & 0xF ];
+ *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 16 ) & 0xF ];
+ *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 12 ) & 0xF ];
+ *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 8 ) & 0xF ];
+ *s++ = kHexChars[ ( ( (uintptr_t) src ) >> 4 ) & 0xF ];
+ *s++ = kHexChars[ ( (uintptr_t) src ) & 0xF ];
+
+ if( !( inFlags & kDebugFlagsNoOffset ) )
+ {
+ *s++ = '+';
+ }
+ }
+ if( !( inFlags & kDebugFlagsNoOffset ) )
+ {
+ if( inFlags & kDebugFlags32BitOffset )
+ {
+ *s++ = kHexChars[ ( offset >> 28 ) & 0xF ];
+ *s++ = kHexChars[ ( offset >> 24 ) & 0xF ];
+ *s++ = kHexChars[ ( offset >> 20 ) & 0xF ];
+ *s++ = kHexChars[ ( offset >> 16 ) & 0xF ];
+ }
+ *s++ = kHexChars[ ( offset >> 12 ) & 0xF ];
+ *s++ = kHexChars[ ( offset >> 8 ) & 0xF ];
+ *s++ = kHexChars[ ( offset >> 4 ) & 0xF ];
+ *s++ = kHexChars[ offset & 0xF ];
+ }
+ if( s != prefixString )
+ {
+ *s++ = ':';
+ *s++ = ' ';
+ }
+ check( ( (size_t)( s - prefixString ) ) < sizeof( prefixString ) );
+ *s = '\0';
+
+ // Build a hex string with a optional spaces after every 1, 2, and/or 4 bytes to make it easier to read.
+ // Optionally pads the hex string with space to fill the full 16 byte range (so it lines up).
+
+ s = hexString;
+ chunkSize = ( inDataSize < 16 ) ? inDataSize : 16;
+ n = ( inFlags & kDebugFlagsNo16ByteHexPad ) ? chunkSize : 16;
+ for( i = 0; i < n; ++i )
+ {
+ if( ( inFlags & kDebugFlags8BitSeparator ) && ( i > 0 ) )
+ {
+ *s++ = ' ';
+ }
+ if( ( inFlags & kDebugFlags16BitSeparator ) && ( i > 0 ) && ( ( i % 2 ) == 0 ) )
+ {
+ *s++ = ' ';
+ }
+ if( !( inFlags & kDebugFlagsNo32BitSeparator ) && ( i > 0 ) && ( ( i % 4 ) == 0 ) )
+ {
+ *s++ = ' ';
+ }
+ if( i < chunkSize )
+ {
+ *s++ = kHexChars[ src[ i ] >> 4 ];
+ *s++ = kHexChars[ src[ i ] & 0xF ];
+ }
+ else
+ {
+ *s++ = ' ';
+ *s++ = ' ';
+ }
+ }
+ check( ( (size_t)( s - hexString ) ) < sizeof( hexString ) );
+ *s = '\0';
+
+ // Build a string with the ASCII version of the data (replaces non-printable characters with '^').
+ // Optionally pads the string with '`' to fill the full 16 byte range (so it lines up).
+
+ s = asciiString;
+ if( !( inFlags & kDebugFlagsNoASCII ) )
+ {
+ *s++ = ' ';
+ *s++ = '|';
+ for( i = 0; i < n; ++i )
+ {
+ if( i < chunkSize )
+ {
+ c = src[ i ];
+ if( !DebugIsPrint( c ) )
+ {
+ c = '^';
+ }
+ }
+ else
+ {
+ c = '`';
+ }
+ *s++ = (char) c;
+ }
+ *s++ = '|';
+ check( ( (size_t)( s - asciiString ) ) < sizeof( asciiString ) );
+ }
+ *s = '\0';
+
+ // Build a string indicating how bytes are in the hex dump. Only printed on the first line.
+
+ s = byteCountString;
+ if( !( inFlags & kDebugFlagsNoByteCount ) )
+ {
+ if( src == start )
+ {
+ s += DebugSNPrintF( s, sizeof( byteCountString ), " (%d bytes)", (int) inDataSize );
+ }
+ }
+ check( ( (size_t)( s - byteCountString ) ) < sizeof( byteCountString ) );
+ *s = '\0';
+
+ // Build the entire line from all the pieces we've previously built.
+
+ if( outBuffer )
+ {
+ if( src == start )
+ {
+ dst += DebugSNPrintF( dst, (size_t)( end - dst ),
+ "%*s" // Indention
+ "%s" // Separator (only if needed)
+ "%s" // Prefix
+ "%-*.*s" // Label
+ "%s" // Separator
+ "%s" // Hex
+ "%s" // ASCII
+ "%s" // Byte Count
+ "%s", // Newline
+ inIndent, "",
+ ( src != start ) ? separator : "",
+ prefixString,
+ width, (int) inLabelSize, inLabel ? inLabel : "",
+ ( width > 0 ) ? " " : "",
+ hexString,
+ asciiString,
+ byteCountString,
+ newline );
+ }
+ else
+ {
+ dst += DebugSNPrintF( dst, (size_t)( end - dst ),
+ "%*s" // Indention
+ "%s" // Separator (only if needed)
+ "%s" // Prefix
+ "%*s" // Label Spacing
+ "%s" // Separator
+ "%s" // Hex
+ "%s" // ASCII
+ "%s" // Byte Count
+ "%s", // Newline
+ inIndent, "",
+ ( src != start ) ? separator : "",
+ prefixString,
+ width, "",
+ ( width > 0 ) ? " " : "",
+ hexString,
+ asciiString,
+ byteCountString,
+ newline );
+ }
+ }
+ else
+ {
+ if( src == start )
+ {
+ dst += DebugPrintF( inLevel,
+ "%*s" // Indention
+ "%s" // Separator (only if needed)
+ "%s" // Prefix
+ "%-*.*s" // Label
+ "%s" // Separator
+ "%s" // Hex
+ "%s" // ASCII
+ "%s" // Byte Count
+ "%s", // Newline
+ inIndent, "",
+ ( src != start ) ? separator : "",
+ prefixString,
+ width, (int) inLabelSize, inLabel,
+ ( width > 0 ) ? " " : "",
+ hexString,
+ asciiString,
+ byteCountString,
+ newline );
+ }
+ else
+ {
+ dst += DebugPrintF( inLevel,
+ "%*s" // Indention
+ "%s" // Separator (only if needed)
+ "%s" // Prefix
+ "%*s" // Label Spacing
+ "%s" // Separator
+ "%s" // Hex
+ "%s" // ASCII
+ "%s" // Byte Count
+ "%s", // Newline
+ inIndent, "",
+ ( src != start ) ? separator : "",
+ prefixString,
+ width, "",
+ ( width > 0 ) ? " " : "",
+ hexString,
+ asciiString,
+ byteCountString,
+ newline );
+ }
+ }
+
+ // Move to the next chunk. Exit if there is no more data.
+
+ offset += (int) chunkSize;
+ src += chunkSize;
+ inDataSize -= chunkSize;
+ if( inDataSize == 0 )
+ {
+ break;
+ }
+ }
+
+ // Note: The "dst - outBuffer" size calculation works even if "outBuffer" is NULL because it's all relative.
+
+ return( (size_t)( dst - outBuffer ) );
+}
+
+//===========================================================================================================================
+// DebugNumVersionToString
+//===========================================================================================================================
+
+static char * DebugNumVersionToString( uint32_t inVersion, char *inString )
+{
+ char * s;
+ uint8_t majorRev;
+ uint8_t minor;
+ uint8_t bugFix;
+ uint8_t stage;
+ uint8_t revision;
+
+ check( inString );
+
+ majorRev = (uint8_t)( ( inVersion >> 24 ) & 0xFF );
+ minor = (uint8_t)( ( inVersion >> 20 ) & 0x0F );
+ bugFix = (uint8_t)( ( inVersion >> 16 ) & 0x0F );
+ stage = (uint8_t)( ( inVersion >> 8 ) & 0xFF );
+ revision = (uint8_t)( inVersion & 0xFF );
+
+ // Convert the major, minor, and bugfix numbers.
+
+ s = inString;
+ s += sprintf( s, "%u", majorRev );
+ s += sprintf( s, ".%u", minor );
+ if( bugFix != 0 )
+ {
+ s += sprintf( s, ".%u", bugFix );
+ }
+
+ // Convert the version stage and non-release revision number.
+
+ switch( stage )
+ {
+ case kVersionStageDevelopment:
+ s += sprintf( s, "d%u", revision );
+ break;
+
+ case kVersionStageAlpha:
+ s += sprintf( s, "a%u", revision );
+ break;
+
+ case kVersionStageBeta:
+ s += sprintf( s, "b%u", revision );
+ break;
+
+ case kVersionStageFinal:
+
+ // A non-release revision of zero is a special case indicating the software is GM (at the golden master
+ // stage) and therefore, the non-release revision should not be added to the string.
+
+ if( revision != 0 )
+ {
+ s += sprintf( s, "f%u", revision );
+ }
+ break;
+
+ default:
+ dlog( kDebugLevelError, "invalid NumVersion stage (0x%02X)\n", stage );
+ break;
+ }
+ return( inString );
+}
+
+//===========================================================================================================================
+// DebugTaskLevel
+//===========================================================================================================================
+
+DEBUG_EXPORT uint32_t DebugTaskLevel( void )
+{
+ uint32_t level;
+
+ level = 0;
+
+#if ( TARGET_OS_VXWORKS )
+ if( intContext() )
+ {
+ level |= ( ( 1 << kDebugInterruptLevelShift ) & kDebugInterruptLevelMask );
+ }
+#endif
+
+ return( level );
+}
+
+#if ( TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE )
+//===========================================================================================================================
+// DebugWinEnableConsole
+//===========================================================================================================================
+
+#pragma warning( disable:4311 )
+
+static void DebugWinEnableConsole( void )
+{
+ static bool sConsoleEnabled = false;
+ BOOL result;
+ int fileHandle;
+ FILE * file;
+ int err;
+
+ if( sConsoleEnabled )
+ {
+ goto exit;
+ }
+
+ // Create console window.
+
+ result = AllocConsole();
+ require_quiet( result, exit );
+
+ // Redirect stdin to the console stdin.
+
+ fileHandle = _open_osfhandle( (long) GetStdHandle( STD_INPUT_HANDLE ), _O_TEXT );
+
+ #if ( defined( __MWERKS__ ) )
+ file = __handle_reopen( (unsigned long) fileHandle, "r", stdin );
+ require_quiet( file, exit );
+ #else
+ file = _fdopen( fileHandle, "r" );
+ require_quiet( file, exit );
+
+ *stdin = *file;
+ #endif
+
+ err = setvbuf( stdin, NULL, _IONBF, 0 );
+ require_noerr_quiet( err, exit );
+
+ // Redirect stdout to the console stdout.
+
+ fileHandle = _open_osfhandle( (long) GetStdHandle( STD_OUTPUT_HANDLE ), _O_TEXT );
+
+ #if ( defined( __MWERKS__ ) )
+ file = __handle_reopen( (unsigned long) fileHandle, "w", stdout );
+ require_quiet( file, exit );
+ #else
+ file = _fdopen( fileHandle, "w" );
+ require_quiet( file, exit );
+
+ *stdout = *file;
+ #endif
+
+ err = setvbuf( stdout, NULL, _IONBF, 0 );
+ require_noerr_quiet( err, exit );
+
+ // Redirect stderr to the console stdout.
+
+ fileHandle = _open_osfhandle( (long) GetStdHandle( STD_OUTPUT_HANDLE ), _O_TEXT );
+
+ #if ( defined( __MWERKS__ ) )
+ file = __handle_reopen( (unsigned long) fileHandle, "w", stderr );
+ require_quiet( file, exit );
+ #else
+ file = _fdopen( fileHandle, "w" );
+ require_quiet( file, exit );
+
+ *stderr = *file;
+ #endif
+
+ err = setvbuf( stderr, NULL, _IONBF, 0 );
+ require_noerr_quiet( err, exit );
+
+ sConsoleEnabled = true;
+
+exit:
+ return;
+}
+
+#pragma warning( default:4311 )
+
+#endif // TARGET_OS_WIN32 && !TARGET_OS_WINDOWS_CE
+
+#if ( TARGET_OS_WIN32 )
+//===========================================================================================================================
+// DebugWinCharToTCharString
+//===========================================================================================================================
+
+static TCHAR *
+DebugWinCharToTCharString(
+ const char * inCharString,
+ size_t inCharCount,
+ TCHAR * outTCharString,
+ size_t inTCharCountMax,
+ size_t * outTCharCount )
+{
+ const char * src;
+ TCHAR * dst;
+ TCHAR * end;
+
+ if( inCharCount == kSizeCString )
+ {
+ inCharCount = strlen( inCharString );
+ }
+ src = inCharString;
+ dst = outTCharString;
+ if( inTCharCountMax > 0 )
+ {
+ inTCharCountMax -= 1;
+ if( inTCharCountMax > inCharCount )
+ {
+ inTCharCountMax = inCharCount;
+ }
+
+ end = dst + inTCharCountMax;
+ while( dst < end )
+ {
+ *dst++ = (TCHAR) *src++;
+ }
+ *dst = 0;
+ }
+ if( outTCharCount )
+ {
+ *outTCharCount = (size_t)( dst - outTCharString );
+ }
+ return( outTCharString );
+}
+#endif
+
+#if 0
+#pragma mark -
+#pragma mark == Debugging ==
+#endif
+
+//===========================================================================================================================
+// DebugServicesTest
+//===========================================================================================================================
+
+DEBUG_EXPORT OSStatus DebugServicesTest( void )
+{
+ OSStatus err;
+ char s[ 512 ];
+ uint8_t * p;
+ uint8_t data[] =
+ {
+ 0x11, 0x22, 0x33, 0x44,
+ 0x55, 0x66,
+ 0x77, 0x88, 0x99, 0xAA,
+ 0xBB, 0xCC, 0xDD,
+ 0xEE,
+ 0xFF,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
+ 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0,
+ 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, 0x81, 0x91, 0xA1
+ };
+
+ debug_initialize( kDebugOutputTypeMetaConsole );
+
+ // check's
+
+ check( 0 && "SHOULD SEE: check" );
+ check( 1 && "SHOULD *NOT* SEE: check (valid)" );
+ check_string( 0, "SHOULD SEE: check_string" );
+ check_string( 1, "SHOULD *NOT* SEE: check_string (valid)" );
+ check_noerr( -123 );
+ check_noerr( 10038 );
+ check_noerr( 22 );
+ check_noerr( 0 );
+ check_noerr_string( -6712, "SHOULD SEE: check_noerr_string" );
+ check_noerr_string( 0, "SHOULD *NOT* SEE: check_noerr_string (valid)" );
+ check_translated_errno( 0 >= 0 && "SHOULD *NOT* SEE", -384, -999 );
+ check_translated_errno( -1 >= 0 && "SHOULD SEE", -384, -999 );
+ check_translated_errno( -1 >= 0 && "SHOULD SEE", 0, -999 );
+ check_ptr_overlap( "SHOULD *NOT* SEE" ? 10 : 0, 10, 22, 10 );
+ check_ptr_overlap( "SHOULD SEE" ? 10 : 0, 10, 5, 10 );
+ check_ptr_overlap( "SHOULD SEE" ? 10 : 0, 10, 12, 6 );
+ check_ptr_overlap( "SHOULD SEE" ? 12 : 0, 6, 10, 10 );
+ check_ptr_overlap( "SHOULD SEE" ? 12 : 0, 10, 10, 10 );
+ check_ptr_overlap( "SHOULD *NOT* SEE" ? 22 : 0, 10, 10, 10 );
+ check_ptr_overlap( "SHOULD *NOT* SEE" ? 10 : 0, 10, 20, 10 );
+ check_ptr_overlap( "SHOULD *NOT* SEE" ? 20 : 0, 10, 10, 10 );
+
+ // require's
+
+ require( 0 && "SHOULD SEE", require1 );
+ { err = kResponseErr; goto exit; }
+require1:
+ require( 1 && "SHOULD *NOT* SEE", require2 );
+ goto require2Good;
+require2:
+ { err = kResponseErr; goto exit; }
+require2Good:
+ require_string( 0 && "SHOULD SEE", require3, "SHOULD SEE: require_string" );
+ { err = kResponseErr; goto exit; }
+require3:
+ require_string( 1 && "SHOULD *NOT* SEE", require4, "SHOULD *NOT* SEE: require_string (valid)" );
+ goto require4Good;
+require4:
+ { err = kResponseErr; goto exit; }
+require4Good:
+ require_quiet( 0 && "SHOULD SEE", require5 );
+ { err = kResponseErr; goto exit; }
+require5:
+ require_quiet( 1 && "SHOULD *NOT* SEE", require6 );
+ goto require6Good;
+require6:
+ { err = kResponseErr; goto exit; }
+require6Good:
+ require_noerr( -1, require7 );
+ { err = kResponseErr; goto exit; }
+require7:
+ require_noerr( 0, require8 );
+ goto require8Good;
+require8:
+ { err = kResponseErr; goto exit; }
+require8Good:
+ require_noerr_string( -2, require9, "SHOULD SEE: require_noerr_string");
+ { err = kResponseErr; goto exit; }
+require9:
+ require_noerr_string( 0, require10, "SHOULD *NOT* SEE: require_noerr_string (valid)" );
+ goto require10Good;
+require10:
+ { err = kResponseErr; goto exit; }
+require10Good:
+ require_noerr_action_string( -3, require11, dlog( kDebugLevelMax, "action 1 (expected)\n" ), "require_noerr_action_string" );
+ { err = kResponseErr; goto exit; }
+require11:
+ require_noerr_action_string( 0, require12, dlog( kDebugLevelMax, "action 2\n" ), "require_noerr_action_string (valid)" );
+ goto require12Good;
+require12:
+ { err = kResponseErr; goto exit; }
+require12Good:
+ require_noerr_quiet( -4, require13 );
+ { err = kResponseErr; goto exit; }
+require13:
+ require_noerr_quiet( 0, require14 );
+ goto require14Good;
+require14:
+ { err = kResponseErr; goto exit; }
+require14Good:
+ require_noerr_action( -5, require15, dlog( kDebugLevelMax, "SHOULD SEE: action 3 (expected)\n" ) );
+ { err = kResponseErr; goto exit; }
+require15:
+ require_noerr_action( 0, require16, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 4\n" ) );
+ goto require16Good;
+require16:
+ { err = kResponseErr; goto exit; }
+require16Good:
+ require_noerr_action_quiet( -4, require17, dlog( kDebugLevelMax, "SHOULD SEE: action 5 (expected)\n" ) );
+ { err = kResponseErr; goto exit; }
+require17:
+ require_noerr_action_quiet( 0, require18, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 6\n" ) );
+ goto require18Good;
+require18:
+ { err = kResponseErr; goto exit; }
+require18Good:
+ require_action( 0 && "SHOULD SEE", require19, dlog( kDebugLevelMax, "SHOULD SEE: action 7 (expected)\n" ) );
+ { err = kResponseErr; goto exit; }
+require19:
+ require_action( 1 && "SHOULD *NOT* SEE", require20, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 8\n" ) );
+ goto require20Good;
+require20:
+ { err = kResponseErr; goto exit; }
+require20Good:
+ require_action_quiet( 0, require21, dlog( kDebugLevelMax, "SHOULD SEE: action 9 (expected)\n" ) );
+ { err = kResponseErr; goto exit; }
+require21:
+ require_action_quiet( 1, require22, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 10\n" ) );
+ goto require22Good;
+require22:
+ { err = kResponseErr; goto exit; }
+require22Good:
+ require_action_string( 0, require23, dlog( kDebugLevelMax, "SHOULD SEE: action 11 (expected)\n" ), "SHOULD SEE: require_action_string" );
+ { err = kResponseErr; goto exit; }
+require23:
+ require_action_string( 1, require24, dlog( kDebugLevelMax, "SHOULD *NOT* SEE: action 12\n" ), "SHOULD *NOT* SEE: require_action_string" );
+ goto require24Good;
+require24:
+ { err = kResponseErr; goto exit; }
+require24Good:
+
+#if ( defined( __MWERKS__ ) )
+ #if ( defined( __cplusplus ) && __option( exceptions ) )
+ #define COMPILER_HAS_EXCEPTIONS 1
+ #else
+ #define COMPILER_HAS_EXCEPTIONS 0
+ #endif
+#else
+ #if ( defined( __cplusplus ) )
+ #define COMPILER_HAS_EXCEPTIONS 1
+ #else
+ #define COMPILER_HAS_EXCEPTIONS 0
+ #endif
+#endif
+
+#if ( COMPILER_HAS_EXCEPTIONS )
+ try
+ {
+ require_throw( 1 && "SHOULD *NOT* SEE" );
+ require_throw( 0 && "SHOULD SEE" );
+ }
+ catch(... )
+ {
+ goto require26Good;
+ }
+ { err = kResponseErr; goto exit; }
+require26Good:
+#endif
+
+ // translate_errno
+
+ err = translate_errno( 1 != -1, -123, -567 );
+ require( ( err == 0 ) && "SHOULD *NOT* SEE", exit );
+
+ err = translate_errno( -1 != -1, -123, -567 );
+ require( ( err == -123 ) && "SHOULD *NOT* SEE", exit );
+
+ err = translate_errno( -1 != -1, 0, -567 );
+ require( ( err == -567 ) && "SHOULD *NOT* SEE", exit );
+
+ // debug_string
+
+ debug_string( "debug_string" );
+
+ // DebugSNPrintF
+
+ DebugSNPrintF( s, sizeof( s ), "%d", 1234 );
+ require_action( strcmp( s, "1234" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%X", 0x2345 );
+ require_action( strcmp( s, "2345" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%#s", "\05test" );
+ require_action( strcmp( s, "test" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%##s", "\03www\05apple\03com" );
+ require_action( strcmp( s, "www.apple.com." ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%ld", (long) INT32_C( 2147483647 ) );
+ require_action( strcmp( s, "2147483647" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%lu", (unsigned long) UINT32_C( 4294967295 ) );
+ require_action( strcmp( s, "4294967295" ) == 0, exit, err = -1 );
+
+ #if ( TYPE_LONGLONG_NATIVE )
+ DebugSNPrintF( s, sizeof( s ), "%lld", (long_long_compat) INT64_C( 9223372036854775807 ) );
+ require_action( strcmp( s, "9223372036854775807" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%lld", (long_long_compat) INT64_C( -9223372036854775807 ) );
+ require_action( strcmp( s, "-9223372036854775807" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%llu", (unsigned_long_long_compat) UINT64_C( 18446744073709551615 ) );
+ require_action( strcmp( s, "18446744073709551615" ) == 0, exit, err = -1 );
+ #endif
+
+ DebugSNPrintF( s, sizeof( s ), "%lb", (unsigned long) binary_32( 01111011, 01111011, 01111011, 01111011 ) );
+ require_action( strcmp( s, "1111011011110110111101101111011" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%C", 0x41624364 ); // 'AbCd'
+ require_action( strcmp( s, "AbCd" ) == 0, exit, err = -1 );
+
+ #if ( defined( MDNS_DEBUGMSGS ) )
+ {
+ mDNSAddr maddr;
+
+ memset( &maddr, 0, sizeof( maddr ) );
+ maddr.type = mDNSAddrType_IPv4;
+ maddr.ip.v4.b[ 0 ] = 127;
+ maddr.ip.v4.b[ 1 ] = 0;
+ maddr.ip.v4.b[ 2 ] = 0;
+ maddr.ip.v4.b[ 3 ] = 1;
+ DebugSNPrintF( s, sizeof( s ), "%#a", &maddr );
+ require_action( strcmp( s, "127.0.0.1" ) == 0, exit, err = -1 );
+
+ memset( &maddr, 0, sizeof( maddr ) );
+ maddr.type = mDNSAddrType_IPv6;
+ maddr.ip.v6.b[ 0 ] = 0xFE;
+ maddr.ip.v6.b[ 1 ] = 0x80;
+ maddr.ip.v6.b[ 15 ] = 0x01;
+ DebugSNPrintF( s, sizeof( s ), "%#a", &maddr );
+ require_action( strcmp( s, "FE80:0000:0000:0000:0000:0000:0000:0001" ) == 0, exit, err = -1 );
+ }
+ #endif
+
+ #if ( AF_INET )
+ {
+ struct sockaddr_in sa4;
+
+ memset( &sa4, 0, sizeof( sa4 ) );
+ sa4.sin_family = AF_INET;
+ p = (uint8_t *) &sa4.sin_port;
+ p[ 0 ] = (uint8_t)( ( 80 >> 8 ) & 0xFF );
+ p[ 1 ] = (uint8_t)( 80 & 0xFF );
+ p = (uint8_t *) &sa4.sin_addr.s_addr;
+ p[ 0 ] = (uint8_t)( ( INADDR_LOOPBACK >> 24 ) & 0xFF );
+ p[ 1 ] = (uint8_t)( ( INADDR_LOOPBACK >> 16 ) & 0xFF );
+ p[ 2 ] = (uint8_t)( ( INADDR_LOOPBACK >> 8 ) & 0xFF );
+ p[ 3 ] = (uint8_t)( INADDR_LOOPBACK & 0xFF );
+ DebugSNPrintF( s, sizeof( s ), "%##a", &sa4 );
+ require_action( strcmp( s, "127.0.0.1:80" ) == 0, exit, err = -1 );
+ }
+ #endif
+
+ #if ( AF_INET6 )
+ {
+ struct sockaddr_in6 sa6;
+
+ memset( &sa6, 0, sizeof( sa6 ) );
+ sa6.sin6_family = AF_INET6;
+ p = (uint8_t *) &sa6.sin6_port;
+ p[ 0 ] = (uint8_t)( ( 80 >> 8 ) & 0xFF );
+ p[ 1 ] = (uint8_t)( 80 & 0xFF );
+ sa6.sin6_addr.s6_addr[ 0 ] = 0xFE;
+ sa6.sin6_addr.s6_addr[ 1 ] = 0x80;
+ sa6.sin6_addr.s6_addr[ 15 ] = 0x01;
+ sa6.sin6_scope_id = 2;
+ DebugSNPrintF( s, sizeof( s ), "%##a", &sa6 );
+ require_action( strcmp( s, "[FE80:0000:0000:0000:0000:0000:0000:0001%2]:80" ) == 0, exit, err = -1 );
+ }
+ #endif
+
+ // Unicode
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 4, "tes" );
+ require_action( strcmp( s, "tes" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 4, "test" );
+ require_action( strcmp( s, "test" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 4, "testing" );
+ require_action( strcmp( s, "test" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xC3\xA9" );
+ require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xC3\xA9ing" );
+ require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 4, "tes\xC3\xA9ing" );
+ require_action( strcmp( s, "tes" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 4, "t\xed\x9f\xbf" );
+ require_action( strcmp( s, "t\xed\x9f\xbf" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 4, "t\xed\x9f\xbfing" );
+ require_action( strcmp( s, "t\xed\x9f\xbf" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xed\x9f\xbf" );
+ require_action( strcmp( s, "te" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 4, "te\xed\x9f\xbfing" );
+ require_action( strcmp( s, "te" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 7, "te\xC3\xA9\xed\x9f\xbfing" );
+ require_action( strcmp( s, "te\xC3\xA9\xed\x9f\xbf" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 6, "te\xC3\xA9\xed\x9f\xbfing" );
+ require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
+
+ DebugSNPrintF(s, sizeof(s), "%.*s", 5, "te\xC3\xA9\xed\x9f\xbfing" );
+ require_action( strcmp( s, "te\xC3\xA9" ) == 0, exit, err = kResponseErr );
+
+ #if ( TARGET_RT_BIG_ENDIAN )
+ DebugSNPrintF( s, sizeof( s ), "%S", "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" );
+ require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+ #else
+ DebugSNPrintF( s, sizeof( s ), "%S", "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" );
+ require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+ #endif
+
+ DebugSNPrintF( s, sizeof( s ), "%S",
+ "\xFE\xFF" "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" ); // Big Endian BOM
+ require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%S",
+ "\xFF\xFE" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" ); // Little Endian BOM
+ require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%#S", "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" ); // Big Endian
+ require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%##S", "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" "\x00" "\x00" ); // Little Endian
+ require_action( strcmp( s, "abcd" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%.*S",
+ 4, "\xFE\xFF" "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" ); // Big Endian BOM
+ require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%.*S",
+ 4, "\xFF\xFE" "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" ); // Little Endian BOM
+ require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+
+ #if ( TARGET_RT_BIG_ENDIAN )
+ DebugSNPrintF( s, sizeof( s ), "%.*S", 3, "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" );
+ require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+ #else
+ DebugSNPrintF( s, sizeof( s ), "%.*S", 3, "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" );
+ require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+ #endif
+
+ DebugSNPrintF( s, sizeof( s ), "%#.*S", 3, "\x00" "a" "\x00" "b" "\x00" "c" "\x00" "d" ); // Big Endian
+ require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%##.*S", 3, "a" "\x00" "b" "\x00" "c" "\x00" "d" "\x00" ); // Little Endian
+ require_action( strcmp( s, "abc" ) == 0, exit, err = -1 );
+
+ // Misc
+
+ DebugSNPrintF( s, sizeof( s ), "%U", "\x10\xb8\xa7\x6b" "\xad\x9d" "\xd1\x11" "\x80\xb4" "\x00\xc0\x4f\xd4\x30\xc8" );
+ require_action( strcmp( s, "6ba7b810-9dad-11d1-80b4-00c04fd430c8" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%m", 0 );
+ require_action( strcmp( s, "no error" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "%lm", (long) 0 );
+ require_action( strcmp( s, "no error" ) == 0, exit, err = -1 );
+
+ DebugSNPrintF( s, sizeof( s ), "\"%H\"", "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8", 16, 16 );
+ DebugPrintF( kDebugLevelMax, "%s\n\n", s );
+
+ DebugSNPrintF( s, sizeof( s ), "\"%H\"",
+ "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8"
+ "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8",
+ 32, 32 );
+ DebugPrintF( kDebugLevelMax, "%s\n\n", s );
+
+ DebugSNPrintF( s, sizeof( s ), "\"%H\"", "\x6b\xa7", 2, 2 );
+ DebugPrintF( kDebugLevelMax, "%s\n\n", s );
+
+ // Hex Dumps
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ),
+ kDebugFlagsNone, s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
+ kDebugFlagsNoAddress | kDebugFlagsNoOffset, s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ),
+ kDebugFlagsNoAddress | kDebugFlagsNoOffset, s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 0, "My Label", kSizeCString, 0, NULL, 0, data, data, sizeof( data ),
+ kDebugFlagsNoAddress, s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
+ kDebugFlagsNoOffset, s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
+ kDebugFlagsNoAddress, s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
+ kDebugFlagsNoOffset, s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
+ kDebugFlagsNoByteCount, s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, "\x41\x62\x43\x64", "\x41\x62\x43\x64", 4, // 'AbCd'
+ kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoNewLine |
+ kDebugFlagsNo32BitSeparator | kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount,
+ s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 0, NULL, 0, 0, NULL, 0, data, data, sizeof( data ),
+ kDebugFlagsNoAddress | kDebugFlagsNoOffset | kDebugFlagsNoASCII | kDebugFlagsNoNewLine |
+ kDebugFlags16BitSeparator | kDebugFlagsNo32BitSeparator |
+ kDebugFlagsNo16ByteHexPad | kDebugFlagsNoByteCount, s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ s[ 0 ] = '\0';
+ DebugHexDump( kDebugLevelMax, 8, NULL, 0, 0, NULL, 0, data, data, sizeof( data ), kDebugFlagsNone, s, sizeof( s ) );
+ DebugPrintF( kDebugLevelMax, "%s\n", s );
+
+ // dlog's
+
+ dlog( kDebugLevelNotice, "dlog\n" );
+ dlog( kDebugLevelNotice, "dlog integer: %d\n", 123 );
+ dlog( kDebugLevelNotice, "dlog string: \"%s\"\n", "test string" );
+ dlogmem( kDebugLevelNotice, data, sizeof( data ) );
+
+ // Done
+
+ DebugPrintF( kDebugLevelMax, "\n\nALL TESTS DONE\n\n" );
+ err = kNoErr;
+
+exit:
+ if( err )
+ {
+ DebugPrintF( kDebugLevelMax, "\n\n### TEST FAILED ###\n\n" );
+ }
+ return( err );
+}
+
+#endif // DEBUG
diff --git a/sd/source/ui/remotecontrol/mDNSResponder/DebugServices.h b/sd/source/ui/remotecontrol/mDNSResponder/DebugServices.h
new file mode 100755
index 000000000000..cb0ef4d1acae
--- /dev/null
+++ b/sd/source/ui/remotecontrol/mDNSResponder/DebugServices.h
@@ -0,0 +1,1607 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @header DebugServices
+
+ Debugging Library
+ */
+
+#ifndef __DEBUG_SERVICES__
+#define __DEBUG_SERVICES__
+
+#include <stdarg.h>
+
+#include "CommonServices.h"
+
+#if ( TARGET_OS_VXWORKS )
+ #include "logLib.h"
+#endif
+
+#if 0
+#pragma mark == Settings ==
+#endif
+
+//===========================================================================================================================
+// Settings
+//===========================================================================================================================
+
+// General
+
+#if ( !defined( DEBUG ) )
+ #define DEBUG 0
+#endif
+
+#if ( defined( NDEBUG ) && DEBUG )
+ #error NDEBUG defined and DEBUG is also enabled...they need to be in-sync
+#endif
+
+// AssertMacros.h/Debugging.h overrides.
+
+#if ( !defined( DEBUG_OVERRIDE_APPLE_MACROS ) )
+ #define DEBUG_OVERRIDE_APPLE_MACROS 1
+#endif
+
+// Routine name. Uses ISO __func__ where possible. Otherwise, uses the best thing that is available (if anything).
+
+#if ( defined( __MWERKS__ ) || ( __GNUC__ > 2 ) || ( ( __GNUC__ == 2 ) && ( __GNUC_MINOR__ >= 9 ) ) )
+ #define __ROUTINE__ __func__
+#elif ( defined( __GNUC__ ) )
+ #define __ROUTINE__ __PRETTY_FUNCTION__
+#elif ( defined( _MSC_VER ) && !defined( _WIN32_WCE ) )
+ #define __ROUTINE__ __FUNCTION__
+#else
+ #define __ROUTINE__ ""
+#endif
+
+// Variable argument macro support. Use ANSI C99 __VA_ARGS__ where possible. Otherwise, use the next best thing.
+
+#if ( defined( __GNUC__ ) )
+ #if ( ( __GNUC__ > 3 ) || ( ( __GNUC__ == 3 ) && ( __GNUC_MINOR__ >= 3) ) )
+ #define DEBUG_C99_VA_ARGS 1
+ #define DEBUG_GNU_VA_ARGS 0
+ #else
+ #define DEBUG_C99_VA_ARGS 0
+ #define DEBUG_GNU_VA_ARGS 1
+ #endif
+#elif ( defined( __MWERKS__ ) )
+ #define DEBUG_C99_VA_ARGS 1
+ #define DEBUG_GNU_VA_ARGS 0
+#else
+ #define DEBUG_C99_VA_ARGS 0
+ #define DEBUG_GNU_VA_ARGS 0
+#endif
+
+#if 0
+#pragma mark == Output ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DEBUG_FPRINTF_ENABLED
+
+ @abstract Enables ANSI C fprintf output.
+ */
+
+#if ( !defined( DEBUG_FPRINTF_ENABLED ) )
+ #if ( !TARGET_API_MAC_OSX_KERNEL && !TARGET_OS_WINDOWS_CE )
+ #define DEBUG_FPRINTF_ENABLED 1
+ #else
+ #define DEBUG_FPRINTF_ENABLED 0
+ #endif
+#else
+ #if ( TARGET_API_MAC_OSX_KERNEL || TARGET_OS_WINDOWS_CE )
+ #error fprintf enabled, but not supported on Mac OS X kernel or Windows CE
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DEBUG_MAC_OS_X_IOLOG_ENABLED
+
+ @abstract Enables IOLog (Mac OS X Kernel) output.
+ */
+
+#if ( !defined( DEBUG_MAC_OS_X_IOLOG_ENABLED ) )
+ #define DEBUG_MAC_OS_X_IOLOG_ENABLED TARGET_API_MAC_OSX_KERNEL
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DEBUG_KPRINTF_ENABLED
+
+ @abstract Enables kprintf (Mac OS X Kernel) output.
+ */
+
+#if ( !defined( DEBUG_KPRINTF_ENABLED ) )
+ #define DEBUG_KPRINTF_ENABLED TARGET_API_MAC_OSX_KERNEL
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DEBUG_IDEBUG_ENABLED
+
+ @abstract Enables iDebug (Mac OS X user and Kernel) output.
+
+ @discussion
+
+ For Mac OS X kernel development, iDebug is enabled by default because we can dynamically check for the presence
+ of iDebug via some exported IOKit symbols. Mac OS X app usage doesn't allow dynamic detection because it relies
+ on statically linking to the iDebugServices.cp file so for Mac OS X app usage, you have to manually enable iDebug.
+ */
+
+#if ( !defined( DEBUG_IDEBUG_ENABLED ) )
+ #define DEBUG_IDEBUG_ENABLED TARGET_API_MAC_OSX_KERNEL
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DEBUG_CORE_SERVICE_ASSERTS_ENABLED
+
+ @abstract Controls whether Core Services assert handling is enabled. Enabling requires CoreServices framework.
+ */
+
+#if ( !defined( DEBUG_CORE_SERVICE_ASSERTS_ENABLED ) )
+ #if ( defined( __DEBUGGING__ ) )
+ #define DEBUG_CORE_SERVICE_ASSERTS_ENABLED 1
+ #else
+ #define DEBUG_CORE_SERVICE_ASSERTS_ENABLED 0
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef DebugOutputType
+
+ @abstract Type of debug output (i.e. where the output goes).
+ */
+
+typedef uint32_t DebugOutputType;
+
+#define kDebugOutputTypeNone 0x6E6F6E65U // 'none' - no params
+#define kDebugOutputTypeCustom 0x63757374U // 'cust' - 1st param = function ptr, 2nd param = context
+#define kDebugOutputTypeFPrintF 0x66707269U // 'fpri' - 1st param = DebugOutputTypeFlags [, 2nd param = filename]
+#define kDebugOutputTypeiDebug 0x69646267U // 'idbg' - no params
+#define kDebugOutputTypeKPrintF 0x6B707266U // 'kprf' - no params
+#define kDebugOutputTypeMacOSXIOLog 0x696C6F67U // 'ilog' - no params
+#define kDebugOutputTypeMacOSXLog 0x786C6F67U // 'xlog' - no params
+#define kDebugOutputTypeWindowsDebugger 0x77696E64U // 'wind' - no params
+#define kDebugOutputTypeWindowsEventLog 0x7765766CU // 'wevl' - 1st param = C-string name, 2nd param = HMODULE or NULL.
+
+// Console meta output kind - Any kind of Console output (in horizontal order of preference):
+//
+// Mac OS X = ANSI printf (viewable in Console.app)
+// Mac OS X Kernel = IOLog (/var/log/system.log) or kprintf (serial).
+// Windows = ANSI printf (Console window) or OutputDebugString (debugger).
+// Other = ANSI printf (viewer varies).
+
+#define kDebugOutputTypeMetaConsole 0x434F4E53U // 'CONS' - no params
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef DebugOutputTypeFlags
+
+ @abstract Flags controlling how the output type is configured.
+
+ @constant kDebugOutputTypeFlagsTypeMask Bit mask for the output type (e.g. stdout, stderr, file, etc.).
+ @constant kDebugOutputTypeFlagsStdOut fprintf should go to stdout.
+ @constant kDebugOutputTypeFlagsStdErr fprintf should go to stderr.
+ @constant kDebugOutputTypeFlagsFile fprintf should go to a specific file (filename passed as va_arg).
+ */
+
+typedef unsigned int DebugOutputTypeFlags;
+
+#define kDebugOutputTypeFlagsTypeMask 0xF
+#define kDebugOutputTypeFlagsStdOut 1
+#define kDebugOutputTypeFlagsStdErr 2
+#define kDebugOutputTypeFlagsFile 10
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef DebugOutputFunctionPtr
+
+ @abstract Function ptr for a custom callback to print debug output.
+ */
+
+typedef void ( *DebugOutputFunctionPtr )( char *inData, size_t inSize, void *inContext );
+
+//===========================================================================================================================
+// Constants
+//===========================================================================================================================
+
+#if 0
+#pragma mark == Flags ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef DebugFlags
+
+ @abstract Flags controlling how output is printed.
+ */
+
+typedef uint32_t DebugFlags;
+
+#define kDebugFlagsNone 0
+#define kDebugFlagsNoAddress ( 1 << 0 )
+#define kDebugFlagsNoOffset ( 1 << 1 )
+#define kDebugFlags32BitOffset ( 1 << 2 )
+#define kDebugFlagsNoASCII ( 1 << 3 )
+#define kDebugFlagsNoNewLine ( 1 << 4 )
+#define kDebugFlags8BitSeparator ( 1 << 5 )
+#define kDebugFlags16BitSeparator ( 1 << 6 )
+#define kDebugFlagsNo32BitSeparator ( 1 << 7 )
+#define kDebugFlagsNo16ByteHexPad ( 1 << 8 )
+#define kDebugFlagsNoByteCount ( 1 << 9 )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @enum DebugTaskLevelFlags
+
+ @abstract Flags indicating the task level.
+ */
+
+enum
+{
+ kDebugInterruptLevelShift = 0,
+ kDebugInterruptLevelMask = 0x00000007,
+ kDebugInVBLTaskMask = 0x00000010,
+ kDebugInDeferredTaskMask = 0x00000020,
+ kDebugInSecondaryInterruptHandlerMask = 0x00000040,
+ kDebugPageFaultFatalMask = 0x00000100, // There should be a "kPageFaultFatalMask" in Debugging.h.
+ kDebugMPTaskLevelMask = 0x00000200, // There should be a "kMPTaskLevelMask" in Debugging.h.
+ kDebugInterruptDepthShift = 16,
+ kDebugInterruptDepthMask = 0x00FF0000
+};
+
+#define DebugExtractTaskLevelInterruptLevel( LEVEL ) \
+ ( ( ( LEVEL ) &kDebugInterruptLevelMask ) >> kDebugInterruptLevelShift )
+
+#define DebugExtractTaskLevelInterruptDepth( LEVEL ) \
+ ( ( ( LEVEL ) &kDebugInterruptDepthMask ) >> kDebugInterruptDepthShift )
+
+#if 0
+#pragma mark == Levels ==
+#endif
+
+//===========================================================================================================================
+// Constants & Types - Levels
+//===========================================================================================================================
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef DebugLevel
+
+ @abstract Level used to control debug logging.
+ */
+
+typedef int32_t DebugLevel;
+
+// Levels
+
+#define kDebugLevelMask 0x0000FFFF
+#define kDebugLevelChatty 100
+#define kDebugLevelVerbose 500
+#define kDebugLevelTrace 800
+#define kDebugLevelInfo 1000
+#define kDebugLevelNotice 3000
+#define kDebugLevelWarning 5000
+#define kDebugLevelAssert 6000
+#define kDebugLevelRequire 7000
+#define kDebugLevelError 8000
+#define kDebugLevelCritical 9000
+#define kDebugLevelAlert 10000
+#define kDebugLevelEmergency 11000
+#define kDebugLevelTragic 12000
+#define kDebugLevelMax 0x0000FFFF
+
+// Level Flags
+
+#define kDebugLevelFlagMask 0xFFFF0000
+#define kDebugLevelFlagStackTrace 0x00010000
+#define kDebugLevelFlagDebugBreak 0x00020000
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef LogLevel
+
+ @abstract Level used to control which events are logged.
+ */
+
+typedef int32_t LogLevel;
+
+#define kLogLevelUninitialized -1L
+#define kLogLevelAll 0L
+#define kLogLevelChatty 100L
+#define kLogLevelVerbose 500L
+#define kLogLevelTrace 800L
+#define kLogLevelInfo 1000L
+#define kLogLevelNotice 3000L
+#define kLogLevelWarning 4000L
+#define kLogLevelAssert 6000L
+#define kLogLevelRequire 7000L
+#define kLogLevelError 8000L
+#define kLogLevelCritical 9000L
+#define kLogLevelAlert 10000L
+#define kLogLevelEmergency 11000L
+#define kLogLevelTragic 12000L
+#define kLogLevelOff 0x0000FFFEL
+
+#if 0
+#pragma mark == Properties ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @typedef DebugPropertyTag
+
+ @abstract Tag for properties.
+ */
+
+typedef uint32_t DebugPropertyTag;
+
+#define kDebugPropertyTagPrintLevelMin 0x6D696E70U // 'minp' Get: 1st param = DebugLevel *
+ // Set: 1st param = DebugLevel
+
+#define kDebugPropertyTagPrintLevel kDebugPropertyTagPrintLevelMin
+
+#define kDebugPropertyTagPrintLevelMax 0x706D786CU // 'maxp' Get: 1st param = DebugLevel *
+ // Set: 1st param = DebugLevel
+
+#define kDebugPropertyTagBreakLevel 0x62726B6CU // 'brkl' Get: 1st param = DebugLevel *
+ // Set: 1st param = DebugLevel
+#if 0
+#pragma mark == General macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DEBUG_UNUSED
+
+ @abstract Macro to mark a paramter as unused to avoid unused parameter warnings.
+
+ @discussion
+
+ There is no universally supported pragma/attribute for indicating a variable is unused. DEBUG_UNUSED lets us
+ indicate a variable is unused in a manner that is supported by most compilers.
+ */
+
+#define DEBUG_UNUSED( X ) (void)( X )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DEBUG_USE_ONLY
+
+ @abstract Macro to mark a variable as used only when debugging is enabled.
+
+ @discussion
+
+ Variables are sometimes needed only for debugging. When debugging is turned off, these debug-only variables generate
+ compiler warnings about unused variables. To eliminate these warnings, use these macros to indicate variables that
+ are only used for debugging.
+ */
+
+#if ( DEBUG )
+ #define DEBUG_USE_ONLY( X )
+#else
+ #define DEBUG_USE_ONLY( X ) (void)( X )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DEBUG_LOCAL
+
+ @abstract Macros to make variables and functions static when debugging is off, but extern when debugging is on.
+
+ @discussion
+
+ Rather than using "static" directly, using this macros allows you to access these variables external while
+ debugging without being penalized for production builds.
+ */
+
+#if ( DEBUG )
+ #define DEBUG_LOCAL
+#else
+ #define DEBUG_LOCAL static
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DEBUG_STATIC
+
+ @abstract Macros to make variables and functions static when debugging is off, but extern when debugging is on.
+
+ @discussion
+
+ Rather than using "static" directly, using this macros allows you to access these variables external while
+ debugging without being penalized for production builds.
+ */
+
+#if ( DEBUG )
+ #define DEBUG_STATIC
+#else
+ #define DEBUG_STATIC static
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DEBUG_EXPORT
+
+ @abstract Macros to export variables.
+
+ @discussion
+
+ "__private_extern__" is a hack for IOKit to allow symbols to be exported from compilation units, but
+ // not exported outside a driver (IOKit uses a lame global namespace for symbols). This still does not
+ // solve the problem of multiple drivers in the same dependency chain since they share symbols.
+ */
+
+#if ( TARGET_API_MAC_OSX_KERNEL )
+ #define DEBUG_EXPORT __private_extern__
+#else
+ #define DEBUG_EXPORT extern
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined debug_add
+
+ @abstract Macro to add (or subtract if negative) a value when debugging is on. Does nothing if debugging is off.
+ */
+
+#if ( DEBUG )
+ #define debug_add( A, B ) ( A ) += ( B )
+#else
+ #define debug_add( A, B )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined debug_perform
+
+ @abstract Macro to perform something in debug-only builds.
+ */
+
+#if ( DEBUG )
+ #define debug_perform( X ) do { X; } while( 0 )
+#else
+ #define debug_perform( X )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function translate_errno
+
+ @abstract Returns 0 if the test success. If the test fails, returns errno if non-zero and othewise the alternate error.
+ */
+
+#define translate_errno( TEST, ERRNO, ALTERNATE_ERROR ) ( ( TEST ) ? 0 : ( ERRNO ) ? ( ERRNO ) : ( ALTERNATE_ERROR ) )
+
+#if 0
+#pragma mark == Compile Time macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined check_compile_time
+
+ @abstract Performs a compile-time check of something such as the size of an int.
+
+ @discussion
+
+ This declares an array with a size that is determined by a compile-time expression. If the expression evaluates
+ to 0, the array has a size of -1, which is illegal and generates a compile-time error.
+
+ For example:
+
+ check_compile_time( sizeof( int ) == 4 );
+
+ Note: This only works with compile-time expressions.
+ Note: This only works in places where extern declarations are allowed (e.g. global scope).
+
+ References:
+
+ <http://www.jaggersoft.com/pubs/CVu11_3.html>
+ <http://www.jaggersoft.com/pubs/CVu11_5.html>
+
+ Note: The following macros differ from the macros on the www.jaggersoft.com web site because those versions do not
+ work with GCC due to GCC allow a zero-length array. Using a -1 condition turned out to be more portable.
+ */
+
+#define check_compile_time( X ) extern int debug_compile_time_name[ ( X ) ? 1 : -1 ]
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined check_compile_time_code
+
+ @abstract Perform a compile-time check, suitable for placement in code, of something such as the size of an int.
+
+ @discussion
+
+ This creates a switch statement with an existing case for 0 and an additional case using the result of a
+ compile-time expression. A switch statement cannot have two case labels with the same constant so if the
+ compile-time expression evaluates to 0, it is illegal and generates a compile-time error. If the compile-time
+ expression does not evaluate to 0, the resulting value is used as the case label and it compiles without error.
+
+ For example:
+
+ check_compile_time_code( sizeof( int ) == 4 );
+
+ Note: This only works with compile-time expressions.
+ Note: This does not work in a global scope so it must be inside a function.
+
+ References:
+
+ <http://www.jaggersoft.com/pubs/CVu11_3.html>
+ <http://www.jaggersoft.com/pubs/CVu11_5.html>
+ */
+
+#define check_compile_time_code( X ) switch( 0 ) { case 0: case X:; }
+
+#if 0
+#pragma mark == check macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined check
+
+ @abstract Check that an expression is true (non-zero).
+
+ @discussion
+
+ If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
+ function name, etc.) using the default debugging output method.
+
+ Code inside check() statements is not compiled into production builds.
+ */
+
+#if ( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef check
+#endif
+#if ( !defined( check ) )
+ #if ( DEBUG )
+ #define check( X ) \
+ do \
+ { \
+ if( !( X ) ) \
+ { \
+ debug_print_assert( 0, # X, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
+ } \
+ } while( 0 )
+ #else
+ #define check( X )
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined check_string
+
+ @abstract Check that an expression is true (non-zero) with an explanation.
+
+ @discussion
+
+ If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
+ function name, etc.) and a custom explanation string using the default debugging output method.
+
+ Code inside check_string() statements is not compiled into production builds.
+ */
+
+#if ( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef check_string
+#endif
+#if ( !defined( check_string ) )
+ #if ( DEBUG )
+ #define check_string( X, STR ) \
+ do \
+ { \
+ if( !( X ) ) \
+ { \
+ debug_print_assert( 0, # X, STR, __FILE__, __LINE__, __ROUTINE__ ); \
+ } \
+ \
+ } while( 0 )
+ #else
+ #define check_string( X, STR )
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined check_noerr
+
+ @abstract Check that an error code is noErr (0).
+
+ @discussion
+
+ If the error code is non-0, this prints debugging information (actual expression string, file, line number,
+ function name, etc.) using the default debugging output method.
+
+ Code inside check_noerr() statements is not compiled into production builds.
+ */
+
+#if ( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef check_noerr
+#endif
+#if ( !defined( check_noerr ) )
+ #if ( DEBUG )
+ #define check_noerr( ERR ) \
+ do \
+ { \
+ int_least32_t localErr; \
+ \
+ localErr = (int_least32_t)( ERR ); \
+ if( localErr != 0 ) \
+ { \
+ debug_print_assert( localErr, NULL, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
+ } \
+ \
+ } while( 0 )
+ #else
+ #define check_noerr( ERR )
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined check_noerr_string
+
+ @abstract Check that an error code is noErr (0) with an explanation.
+
+ @discussion
+
+ If the error code is non-0, this prints debugging information (actual expression string, file, line number,
+ function name, etc.) and a custom explanation string using the default debugging output method.
+
+ Code inside check_noerr_string() statements is not compiled into production builds.
+ */
+
+#if ( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef check_noerr_string
+#endif
+#if ( !defined( check_noerr_string ) )
+ #if ( DEBUG )
+ #define check_noerr_string( ERR, STR ) \
+ do \
+ { \
+ int_least32_t localErr; \
+ \
+ localErr = (int_least32_t)( ERR ); \
+ if( localErr != 0 ) \
+ { \
+ debug_print_assert( localErr, NULL, STR, __FILE__, __LINE__, __ROUTINE__ ); \
+ } \
+ \
+ } while( 0 )
+ #else
+ #define check_noerr_string( ERR, STR )
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined check_translated_errno
+
+ @abstract Check a condition and prints errno (if non-zero) to the log.
+
+ @discussion
+
+ Code inside check_translated_errno() statements is not compiled into production builds.
+ */
+
+#if ( !defined( check_translated_errno ) )
+ #if ( DEBUG )
+ #define check_translated_errno( TEST, ERRNO, ALTERNATE_ERROR ) \
+ do \
+ { \
+ if( !( TEST ) ) \
+ { \
+ int_least32_t localErr; \
+ \
+ localErr = (int_least32_t)( ERRNO ); \
+ localErr = ( localErr != 0 ) ? localErr : (int_least32_t)( ALTERNATE_ERROR ); \
+ debug_print_assert( localErr, # TEST, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
+ } \
+ \
+ } while( 0 )
+ #else
+ #define check_translated_errno( TEST, ERRNO, ALTERNATE_ERROR )
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined check_ptr_overlap
+
+ @abstract Checks that two ptrs do not overlap.
+ */
+
+#define check_ptr_overlap( P1, P1_SIZE, P2, P2_SIZE ) \
+ do \
+ { \
+ check( !( ( (uintptr_t)( P1 ) >= (uintptr_t)( P2 ) ) && \
+ ( (uintptr_t)( P1 ) < ( ( (uintptr_t)( P2 ) ) + ( P2_SIZE ) ) ) ) ); \
+ check( !( ( (uintptr_t)( P2 ) >= (uintptr_t)( P1 ) ) && \
+ ( (uintptr_t)( P2 ) < ( ( (uintptr_t)( P1 ) ) + ( P1_SIZE ) ) ) ) ); \
+ \
+ } while( 0 )
+
+#if 0
+#pragma mark == require macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require
+
+ @abstract Requires that an expression evaluate to true.
+
+ @discussion
+
+ If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
+ function name, etc.) using the default debugging output method then jumps to a label.
+ */
+
+#if ( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require
+#endif
+#if ( !defined( require ) )
+ #define require( X, LABEL ) \
+ do \
+ { \
+ if( !( X ) ) \
+ { \
+ debug_print_assert( 0, # X, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_string
+
+ @abstract Requires that an expression evaluate to true with an explanation.
+
+ @discussion
+
+ If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
+ function name, etc.) and a custom explanation string using the default debugging output method then jumps to a label.
+ */
+
+#if ( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_string
+#endif
+#if ( !defined( require_string ) )
+ #define require_string( X, LABEL, STR ) \
+ do \
+ { \
+ if( !( X ) ) \
+ { \
+ debug_print_assert( 0, # X, STR, __FILE__, __LINE__, __ROUTINE__ ); \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_quiet
+
+ @abstract Requires that an expression evaluate to true.
+
+ @discussion
+
+ If expression evalulates to false, this jumps to a label. No debugging information is printed.
+ */
+
+#if ( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_quiet
+#endif
+#if ( !defined( require_quiet ) )
+ #define require_quiet( X, LABEL ) \
+ do \
+ { \
+ if( !( X ) ) \
+ { \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_noerr
+
+ @abstract Require that an error code is noErr (0).
+
+ @discussion
+
+ If the error code is non-0, this prints debugging information (actual expression string, file, line number,
+ function name, etc.) using the default debugging output method then jumps to a label.
+ */
+
+#if ( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_noerr
+#endif
+#if ( !defined( require_noerr ) )
+ #define require_noerr( ERR, LABEL ) \
+ do \
+ { \
+ int_least32_t localErr; \
+ \
+ localErr = (int_least32_t)( ERR ); \
+ if( localErr != 0 ) \
+ { \
+ debug_print_assert( localErr, NULL, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_noerr_string
+
+ @abstract Require that an error code is noErr (0).
+
+ @discussion
+
+ If the error code is non-0, this prints debugging information (actual expression string, file, line number,
+ function name, etc.), and a custom explanation string using the default debugging output method using the
+ default debugging output method then jumps to a label.
+ */
+
+#if ( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_noerr_string
+#endif
+#if ( !defined( require_noerr_string ) )
+ #define require_noerr_string( ERR, LABEL, STR ) \
+ do \
+ { \
+ int_least32_t localErr; \
+ \
+ localErr = (int_least32_t)( ERR ); \
+ if( localErr != 0 ) \
+ { \
+ debug_print_assert( localErr, NULL, STR, __FILE__, __LINE__, __ROUTINE__ ); \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_noerr_action_string
+
+ @abstract Require that an error code is noErr (0).
+
+ @discussion
+
+ If the error code is non-0, this prints debugging information (actual expression string, file, line number,
+ function name, etc.), and a custom explanation string using the default debugging output method using the
+ default debugging output method then executes an action and jumps to a label.
+ */
+
+#if ( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_noerr_action_string
+#endif
+#if ( !defined( require_noerr_action_string ) )
+ #define require_noerr_action_string( ERR, LABEL, ACTION, STR ) \
+ do \
+ { \
+ int_least32_t localErr; \
+ \
+ localErr = (int_least32_t)( ERR ); \
+ if( localErr != 0 ) \
+ { \
+ debug_print_assert( localErr, NULL, STR, __FILE__, __LINE__, __ROUTINE__ ); \
+ { ACTION; } \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_noerr_quiet
+
+ @abstract Require that an error code is noErr (0).
+
+ @discussion
+
+ If the error code is non-0, this jumps to a label. No debugging information is printed.
+ */
+
+#if ( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_noerr_quiet
+#endif
+#if ( !defined( require_noerr_quiet ) )
+ #define require_noerr_quiet( ERR, LABEL ) \
+ do \
+ { \
+ if( ( ERR ) != 0 ) \
+ { \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_noerr_action
+
+ @abstract Require that an error code is noErr (0) with an action to execute otherwise.
+
+ @discussion
+
+ If the error code is non-0, this prints debugging information (actual expression string, file, line number,
+ function name, etc.) using the default debugging output method then executes an action and jumps to a label.
+ */
+
+#if ( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_noerr_action
+#endif
+#if ( !defined( require_noerr_action ) )
+ #define require_noerr_action( ERR, LABEL, ACTION ) \
+ do \
+ { \
+ int_least32_t localErr; \
+ \
+ localErr = (int_least32_t)( ERR ); \
+ if( localErr != 0 ) \
+ { \
+ debug_print_assert( localErr, NULL, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
+ { ACTION; } \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_noerr_action_quiet
+
+ @abstract Require that an error code is noErr (0) with an action to execute otherwise.
+
+ @discussion
+
+ If the error code is non-0, this executes an action and jumps to a label. No debugging information is printed.
+ */
+
+#if ( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_noerr_action_quiet
+#endif
+#if ( !defined( require_noerr_action_quiet ) )
+ #define require_noerr_action_quiet( ERR, LABEL, ACTION ) \
+ do \
+ { \
+ if( ( ERR ) != 0 ) \
+ { \
+ { ACTION; } \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_action
+
+ @abstract Requires that an expression evaluate to true with an action to execute otherwise.
+
+ @discussion
+
+ If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
+ function name, etc.) using the default debugging output method then executes an action and jumps to a label.
+ */
+
+#if ( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_action
+#endif
+#if ( !defined( require_action ) )
+ #define require_action( X, LABEL, ACTION ) \
+ do \
+ { \
+ if( !( X ) ) \
+ { \
+ debug_print_assert( 0, # X, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
+ { ACTION; } \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_action_quiet
+
+ @abstract Requires that an expression evaluate to true with an action to execute otherwise.
+
+ @discussion
+
+ If expression evalulates to false, this executes an action and jumps to a label. No debugging information is printed.
+ */
+
+#if ( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_action_quiet
+#endif
+#if ( !defined( require_action_quiet ) )
+ #define require_action_quiet( X, LABEL, ACTION ) \
+ do \
+ { \
+ if( !( X ) ) \
+ { \
+ { ACTION; } \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_action_string
+
+ @abstract Requires that an expression evaluate to true with an explanation and action to execute otherwise.
+
+ @discussion
+
+ If expression evalulates to false, this prints debugging information (actual expression string, file, line number,
+ function name, etc.) and a custom explanation string using the default debugging output method then executes an
+ action and jumps to a label.
+ */
+
+#if ( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef require_action_string
+#endif
+#if ( !defined( require_action_string ) )
+ #define require_action_string( X, LABEL, ACTION, STR ) \
+ do \
+ { \
+ if( !( X ) ) \
+ { \
+ debug_print_assert( 0, # X, STR, __FILE__, __LINE__, __ROUTINE__ ); \
+ { ACTION; } \
+ goto LABEL; \
+ } \
+ \
+ } while( 0 )
+
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined require_throw
+
+ @abstract Requires that an expression evaluates to true or an exception is thrown.
+
+ @discussion
+
+ If the expression evaluates to false, this prints debugging information (actual expression string, file,
+ line number, function name, etc.) using the default debugging output method then throws an exception.
+ */
+
+#if ( defined( __cplusplus ) )
+ #define require_throw( X ) \
+ do \
+ { \
+ if( !( X ) ) \
+ { \
+ debug_print_assert( 0, # X, NULL, __FILE__, __LINE__, __ROUTINE__ ); \
+ throw kUnknownErr; \
+ } \
+ \
+ } while( 0 )
+#endif
+
+#if 0
+#pragma mark == Design-By-Contract macros ==
+#endif
+
+//===========================================================================================================================
+// Design-By-Contract macros
+//===========================================================================================================================
+
+#define ensure( X ) check( X )
+#define ensure_string( X, STR ) check_string( X, STR )
+#define ensure_noerr( ERR ) check_noerr( ERR )
+#define ensure_noerr_string( ERR, STR ) check_noerr_string( ERR, STR )
+#define ensure_translated_errno( TEST, ERRNO, ALTERNATE_ERROR ) check_translated_errno( TEST, ERRNO, ALTERNATE_ERROR )
+
+// Note: Design-By-Contract "require" macros are already defined elsewhere.
+
+#if 0
+#pragma mark == Expect macros ==
+#endif
+
+//===========================================================================================================================
+// Expect macros
+//===========================================================================================================================
+
+// Expect macros allow code to include runtime checking of things that should not happen in shipping code (e.g. internal
+// programmer errors, such as a NULL parameter where it is not allowed). Once the code has been verified to work correctly
+// without asserting, the DEBUG_EXPECT_VERIFIED conditional can be set to eliminate the error checking entirely. It can
+// also be useful to measure the cost of error checking code by profiling with it enable and with it disabled.
+
+#if ( DEBUG_EXPECT_VERIFIED )
+ #define require_expect
+ #define require_string_expect
+ #define require_quiet_expect
+ #define require_noerr_expect
+ #define require_noerr_string_expect
+ #define require_noerr_action_string_expect
+ #define require_noerr_quiet_expect
+ #define require_noerr_action_expect
+ #define require_noerr_action_quiet_expect
+ #define require_action_expect
+ #define require_action_quiet_expect
+ #define require_action_string_expect
+#else
+ #define require_expect require
+ #define require_string_expect require_string
+ #define require_quiet_expect require_quiet
+ #define require_noerr_expect require_noerr
+ #define require_noerr_string_expect require_noerr_string
+ #define require_noerr_action_string_expect require_noerr_action_string
+ #define require_noerr_quiet_expect require_noerr_quiet
+ #define require_noerr_action_expect require_noerr_action
+ #define require_noerr_action_quiet_expect require_noerr_action_quiet
+ #define require_action_expect require_action
+ #define require_action_quiet_expect require_action_quiet
+ #define require_action_string_expect require_action_string
+#endif
+
+#if 0
+#pragma mark == Output macros ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined debug_string
+
+ @abstract Prints a debugging C string.
+ */
+
+#if ( DEBUG_OVERRIDE_APPLE_MACROS )
+ #undef debug_string
+#endif
+#if ( !defined( debug_string ) )
+ #if ( DEBUG )
+ #define debug_string( STR ) \
+ do \
+ { \
+ debug_print_assert( 0, NULL, STR, __FILE__, __LINE__, __ROUTINE__ ); \
+ \
+ } while( 0 )
+ #else
+ #define debug_string( STR )
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined debug_print_assert
+
+ @abstract Prints an assertion.
+ */
+
+#if ( DEBUG )
+ #define debug_print_assert( ERROR_CODE, ASSERT_STRING, MESSAGE, FILENAME, LINE_NUMBER, FUNCTION ) \
+ DebugPrintAssert( ERROR_CODE, ASSERT_STRING, MESSAGE, FILENAME, LINE_NUMBER, FUNCTION )
+#else
+ #define debug_print_assert( ERROR_CODE, ASSERT_STRING, MESSAGE, FILENAME, LINE_NUMBER, FUNCTION )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined dlog
+
+ @abstract Prints a debug-only message.
+ */
+
+#if ( DEBUG )
+ #if ( DEBUG_C99_VA_ARGS )
+ #define dlog(... ) DebugPrintF( __VA_ARGS__ )
+ #elif ( DEBUG_GNU_VA_ARGS )
+ #define dlog( ARGS... ) DebugPrintF( ## ARGS )
+ #else
+ #define dlog DebugPrintF
+ #endif
+#else
+ #if ( DEBUG_C99_VA_ARGS )
+ #define dlog(... )
+ #elif ( DEBUG_GNU_VA_ARGS )
+ #define dlog( ARGS... )
+ #else
+ #define dlog while( 0 )
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined dlogv
+
+ @abstract Prints a debug-only message.
+ */
+
+#if ( DEBUG )
+ #define dlogv( LEVEL, FORMAT, LIST ) DebugPrintFVAList( ( LEVEL ), ( FORMAT ), ( LIST ) )
+#else
+ #define dlogv( LEVEL, FORMAT, LIST )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined dlogmem
+
+ @abstract Prints a debug-only dump of memory.
+ */
+
+#if ( DEBUG )
+ #define dlogmem( LEVEL, PTR, SIZE ) \
+ DebugHexDump( ( LEVEL ), 0, NULL, 0, 0, NULL, 0, ( PTR ), ( PTR ), ( SIZE ), kDebugFlagsNone, NULL, 0 )
+#else
+ #define dlogmem( LEVEL, PTR, SIZE )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DebugNSLog
+
+ @abstract Debug-only macro for the Cocoa NSLog function.
+ */
+
+#if ( DEBUG )
+ #if ( DEBUG_C99_VA_ARGS )
+ #define DebugNSLog(... ) NSLog( __VA_ARGS__ )
+ #elif ( DEBUG_GNU_VA_ARGS )
+ #define DebugNSLog( ARGS... ) NSLog( ## ARGS )
+ #else
+ #define DebugNSLog NSLog
+ #endif
+#else
+ #if ( DEBUG_C99_VA_ARGS )
+ #define DebugNSLog(... )
+ #elif ( DEBUG_GNU_VA_ARGS )
+ #define DebugNSLog( ARGS... )
+ #else
+ #define DebugNSLog while( 0 )
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @defined DebugLogMsg
+
+ @abstract Debug-only macro for the VxWorks logMsg function.
+ */
+
+#if ( TARGET_OS_VXWORKS )
+ #if ( DEBUG )
+ #define DebugLogMsg( LEVEL, FORMAT, P1, P2, P3, P4, P5, P6 ) \
+ do \
+ { \
+ if( ( inLevel >= gDebugPrintLevelMin ) || ( inLevel <= gDebugPrintLevelMax ) ) \
+ { \
+ logMsg( ( FORMAT ), ( P1 ), ( P2 ), ( P3 ), ( P4 ), ( P5 ), ( P6 ) ); \
+ } \
+ \
+ } while( 0 )
+ #else
+ #define DebugLogMsg( LEVEL, FORMAT, P1, P2, P3, P4, P5, P6 )
+ #endif
+#else
+ #define DebugLogMsg dlog
+#endif
+
+#if 0
+#pragma mark == Routines - General ==
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugInitialize
+
+ @abstract Initializes the debugging library for a specific kind of output.
+
+ @param inType
+ @param varArg Variable number parameters, controlled by the "inType" parameter.
+ */
+
+#if ( DEBUG )
+DEBUG_EXPORT OSStatus DebugInitialize( DebugOutputType inType, ... );
+#endif
+
+#if ( DEBUG )
+ #if ( DEBUG_C99_VA_ARGS )
+ #define debug_initialize(... ) DebugInitialize( __VA_ARGS__ )
+ #elif ( DEBUG_GNU_VA_ARGS )
+ #define debug_initialize( ARGS... ) DebugInitialize( ## ARGS )
+ #else
+ #define debug_initialize DebugInitialize
+ #endif
+#else
+ #if ( DEBUG_C99_VA_ARGS )
+ #define debug_initialize(... )
+ #elif ( DEBUG_GNU_VA_ARGS )
+ #define debug_initialize( ARGS... )
+ #else
+ #define debug_initialize while( 0 )
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugFinalize
+
+ @abstract Releases any resources used by the debugging library
+ */
+
+#if ( DEBUG )
+DEBUG_EXPORT void DebugFinalize( void );
+#endif
+
+#if ( DEBUG )
+ #define debug_terminate() DebugFinalize()
+#else
+ #define debug_terminate()
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugGetProperty
+
+ @abstract Gets the specified property from the debugging library.
+ */
+
+#if ( DEBUG )
+DEBUG_EXPORT OSStatus DebugGetProperty( DebugPropertyTag inTag, ... );
+#endif
+
+#if ( DEBUG )
+ #if ( DEBUG_C99_VA_ARGS )
+ #define debug_get_property(... ) DebugGetProperty( __VA_ARGS__ )
+ #elif ( DEBUG_GNU_VA_ARGS )
+ #define debug_get_property( ARGS... ) DebugGetProperty( ## ARGS )
+ #else
+ #define debug_get_property DebugGetProperty
+ #endif
+#else
+ #if ( DEBUG_C99_VA_ARGS )
+ #define debug_get_property(... )
+ #elif ( DEBUG_GNU_VA_ARGS )
+ #define debug_get_property( ARGS... )
+ #else
+ #define debug_get_property while( 0 )
+ #endif
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugSetProperty
+
+ @abstract Sets the specified property from the debugging library.
+ */
+
+#if ( DEBUG )
+DEBUG_EXPORT OSStatus DebugSetProperty( DebugPropertyTag inTag, ... );
+#endif
+
+#if ( DEBUG )
+ #if ( DEBUG_C99_VA_ARGS )
+ #define debug_set_property(... ) DebugSetProperty( __VA_ARGS__ )
+ #elif ( DEBUG_GNU_VA_ARGS )
+ #define debug_set_property( ARGS... ) DebugSetProperty( ## ARGS )
+ #else
+ #define debug_set_property DebugSetProperty
+ #endif
+#else
+ #if ( DEBUG_C99_VA_ARGS )
+ #define debug_set_property(... )
+ #elif ( DEBUG_GNU_VA_ARGS )
+ #define debug_set_property( ARGS... )
+ #else
+ #define debug_set_property while( 0 )
+ #endif
+#endif
+
+#if 0
+#pragma mark == Routines - Debugging Output ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugPrintF
+
+ @abstract Prints a debug message with printf-style formatting.
+
+ @param inLevel Error that generated this assert or noErr.
+
+ @param inFormatString
+ C string containing assertion text.
+
+ @param VAR_ARG
+ Variable number of arguments depending on the format string.
+
+ @result Number of bytes printed or -1 on error.
+ */
+
+#if ( DEBUG )
+DEBUG_EXPORT size_t DebugPrintF( DebugLevel inLevel, const char *inFormat, ... );
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugPrintFVAList
+
+ @abstract va_list version of DebugPrintF. See DebugPrintF for more info.
+ */
+
+#if ( DEBUG )
+DEBUG_EXPORT size_t DebugPrintFVAList( DebugLevel inLevel, const char *inFormat, va_list inArgs );
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugPrintAssert
+
+ @abstract Prints a message describing the reason the (e.g. an assert failed), an optional error message,
+ an optional source filename, an optional source line number.
+
+ @param inErrorCode Error that generated this assert or noErr.
+ @param inAssertString C string containing assertion text.
+ @param inMessage C string containing a message about the assert.
+ @param inFileName C string containing path of file where the error occurred.
+ @param inLineNumber Line number in source file where the error occurred.
+ @param inFunction C string containing name of function where assert occurred.
+
+ @discussion
+
+ Example output:
+
+ [ASSERT] assert: "dataPtr != NULL" allocate memory for object failed
+ [ASSERT] where: "MyFile.c", line 123, ("MyFunction")
+
+ OR
+
+ [ASSERT] error: -6728 (kNoMemoryErr)
+ [ASSERT] where: "MyFile.c", line 123, ("MyFunction")
+ */
+
+#if ( DEBUG )
+DEBUG_EXPORT void
+DebugPrintAssert(
+ int_least32_t inErrorCode,
+ const char * inAssertString,
+ const char * inMessage,
+ const char * inFilename,
+ int_least32_t inLineNumber,
+ const char * inFunction );
+#endif
+
+#if 0
+#pragma mark == Routines - Utilities ==
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugSNPrintF
+
+ @abstract Debugging versions of standard C snprintf with extra features.
+
+ @param sbuffer Buffer to receive result. Null terminated unless the buffer size is 0.
+ @param buflen Size of the buffer including space for the null terminator.
+ @param fmt printf-style format string.
+ @param VAR_ARG Variable number of arguments depending on the format string.
+
+ @result Number of characters written (minus the null terminator).
+
+ @discussion
+
+ Extra features over the standard C snprintf:
+ <pre>
+ 64-bit support for %d (%lld), %i (%lli), %u (%llu), %o (%llo), %x (%llx), and %b (%llb).
+ %@ - Cocoa/CoreFoundation object. Param is the object. Strings are used directly. Others use CFCopyDescription.
+ %a - Network Address: %.4a=IPv4, %.6a=Ethernet, %.8a Fibre Channel, %.16a=IPv6. Arg=ptr to network address.
+ %#a - IPv4 or IPv6 mDNSAddr. Arg=ptr to mDNSAddr.
+ %##a - IPv4 (if AF_INET defined) or IPv6 (if AF_INET6 defined) sockaddr. Arg=ptr to sockaddr.
+ %b - Binary representation of integer (e.g. 01101011). Modifiers and arg=the same as %d, %x, etc.
+ %C - Mac-style FourCharCode (e.g. 'APPL'). Arg=32-bit value to print as a Mac-style FourCharCode.
+ %H - Hex Dump (e.g. "\x6b\xa7" -> "6B A7"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
+ %#H - Hex Dump & ASCII (e.g. "\x41\x62" -> "6B A7 'Ab'"). 1st arg=ptr, 2nd arg=size, 3rd arg=max size.
+ %m - Error Message (e.g. 0 -> "kNoErr"). Modifiers and error code arg=the same as %d, %x, etc.
+ %#s - Pascal-style length-prefixed string. Arg=ptr to string.
+ %##s - DNS label-sequence name. Arg=ptr to name.
+ %S - UTF-16 string, 0x0000 terminated. Host order if no BOM. Precision is UTF-16 count. Precision includes BOM.
+ %#S - Big Endian UTF-16 string (unless BOM overrides). Otherwise, the same as %S.
+ %##S - Little Endian UTF-16 string (unless BOM overrides). Otherwise, the same as %S.
+ %U - Universally Unique Identifier (UUID) (e.g. 6ba7b810-9dad-11d1-80b4-00c04fd430c8). Arg=ptr to 16-byte UUID.
+ </pre>
+ */
+
+#if ( DEBUG )
+DEBUG_EXPORT size_t DebugSNPrintF(char *sbuffer, size_t buflen, const char *fmt, ...);
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugSNPrintFVAList
+
+ @abstract va_list version of DebugSNPrintF. See DebugSNPrintF for more info.
+ */
+
+#if ( DEBUG )
+DEBUG_EXPORT size_t DebugSNPrintFVAList(char *sbuffer, size_t buflen, const char *fmt, va_list arg);
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugGetErrorString
+
+ @abstract Gets an error string from an error code.
+
+ @param inStatus Error code to get the string for.
+ @param inBuffer Optional buffer to copy the string to for non-static strings. May be null.
+ @param inBufferSize Size of optional buffer. May be 0.
+
+ @result C string containing error string for the error code. Guaranteed to be a valid, static string. If a
+ buffer is supplied, the return value will always be a pointer to the supplied buffer, which will
+ contain the best available description of the error code. If a buffer is not supplied, the return
+ value will be the best available description of the error code that can be represented as a static
+ string. This allows code that cannot use a temporary buffer to hold the result to still get a useful
+ error string in most cases, but also allows code that can use a temporary buffer to get the best
+ available description.
+ */
+
+#if ( DEBUG )
+DEBUG_EXPORT const char * DebugGetErrorString( int_least32_t inErrorCode, char *inBuffer, size_t inBufferSize );
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugHexDump
+
+ @abstract Hex dumps data to a string or to the output device.
+ */
+
+#if ( DEBUG )
+DEBUG_EXPORT size_t
+DebugHexDump(
+ DebugLevel inLevel,
+ int inIndent,
+ const char * inLabel,
+ size_t inLabelSize,
+ int inLabelMinWidth,
+ const char * inType,
+ size_t inTypeSize,
+ const void * inDataStart,
+ const void * inData,
+ size_t inDataSize,
+ DebugFlags inFlags,
+ char * outBuffer,
+ size_t inBufferSize );
+#endif
+
+#if ( DEBUG )
+ #define dloghex( LEVEL, INDENT, LABEL, LABEL_SIZE, LABEL_MIN_SIZE, TYPE, TYPE_SIZE, DATA_START, DATA, DATA_SIZE, FLAGS, BUFFER, BUFFER_SIZE ) \
+ DebugHexDump( ( LEVEL ), (INDENT), ( LABEL ), ( LABEL_SIZE ), ( LABEL_MIN_SIZE ), ( TYPE ), ( TYPE_SIZE ), \
+ ( DATA_START ), ( DATA ), ( DATA_SIZE ), ( FLAGS ), ( BUFFER ), ( BUFFER_SIZE ) )
+#else
+ #define dloghex( LEVEL, INDENT, LABEL, LABEL_SIZE, LABEL_MIN_SIZE, TYPE, TYPE_SIZE, DATA_START, DATA, DATA_SIZE, FLAGS, BUFFER, BUFFER_SIZE )
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugTaskLevel
+
+ @abstract Returns the current task level.
+
+ @result Current task level
+
+ @discussion
+
+ Bit masks to isolate portions of the result (note that some masks may also need bit shifts to right justify):
+ <pre>
+ kDebugInterruptLevelMask - Indicates the current interrupt level (> 0 means interrupt time).
+ kDebugInVBLTaskMask - Indicates if a VBL task is currently being executed.
+ kDebugInDeferredTaskMask - Indicates if a Deferred Task is currently being executed.
+ kDebugInSecondaryInterruptHandlerMask - Indicates if a Secondary Interrupt Handler is currently being executed.
+ kDebugPageFaultFatalMask - Indicates if it is unsafe to cause a page fault (worse than interrupt time).
+ kDebugMPTaskLevelMask - Indicates if being called from an MP task.
+ kDebugInterruptDepthMask - 0 means task level, 1 means in interrupt, > 1 means in nested interrupt.
+ </pre>
+
+ Helpers:
+ <pre>
+ DebugExtractTaskLevelInterruptDepth() - Macro to extract interrupt depth from task level value.
+ </pre>
+ */
+
+#if ( DEBUG )
+DEBUG_EXPORT uint32_t DebugTaskLevel( void );
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @function DebugServicesTest
+
+ @abstract Unit test.
+ */
+
+#if ( DEBUG )
+DEBUG_EXPORT OSStatus DebugServicesTest( void );
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __DEBUG_SERVICES__
diff --git a/sd/source/ui/remotecontrol/mDNSResponder/GenLinkedList.c b/sd/source/ui/remotecontrol/mDNSResponder/GenLinkedList.c
new file mode 100755
index 000000000000..a36183d7a61e
--- /dev/null
+++ b/sd/source/ui/remotecontrol/mDNSResponder/GenLinkedList.c
@@ -0,0 +1,319 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ File: GenLinkedList.c
+
+ Contains: implementation of generic linked lists.
+
+ Version: 1.0
+ Tabs: 4 spaces
+ */
+
+#include "GenLinkedList.h"
+
+
+// Return the link pointer contained within element e at offset o.
+#define GETLINK( e, o) ( *(void**)((char*) (e) + (o)) )
+
+// Assign the link pointer l to element e at offset o.
+#define ASSIGNLINK( e, l, o) ( *((void**)((char*) (e) + (o))) = (l))
+
+
+// GenLinkedList /////////////////////////////////////////////////////////////
+
+void InitLinkedList( GenLinkedList *pList, size_t linkOffset)
+/* Initialize the block of memory pointed to by pList as a linked list. */
+{
+ pList->Head = NULL;
+ pList->Tail = NULL;
+ pList->LinkOffset = linkOffset;
+}
+
+
+void AddToTail( GenLinkedList *pList, void *elem)
+/* Add a linked list element to the tail of the list. */
+{
+ if ( pList->Tail) {
+ ASSIGNLINK( pList->Tail, elem, pList->LinkOffset);
+ } else
+ pList->Head = elem;
+ ASSIGNLINK( elem, NULL, pList->LinkOffset);
+
+ pList->Tail = elem;
+}
+
+
+void AddToHead( GenLinkedList *pList, void *elem)
+/* Add a linked list element to the head of the list. */
+{
+ ASSIGNLINK( elem, pList->Head, pList->LinkOffset);
+ if ( pList->Tail == NULL)
+ pList->Tail = elem;
+
+ pList->Head = elem;
+}
+
+
+int RemoveFromList( GenLinkedList *pList, void *elem)
+/* Remove a linked list element from the list. Return 0 if it was not found. */
+/* If the element is removed, its link will be set to NULL. */
+{
+ void *iElem, *lastElem;
+
+ for ( iElem = pList->Head, lastElem = NULL; iElem; iElem = GETLINK( iElem, pList->LinkOffset)) {
+ if ( iElem == elem) {
+ if ( lastElem) { // somewhere past the head
+ ASSIGNLINK( lastElem, GETLINK( elem, pList->LinkOffset), pList->LinkOffset);
+ } else { // at the head
+ pList->Head = GETLINK( elem, pList->LinkOffset);
+ }
+ if ( pList->Tail == elem)
+ pList->Tail = lastElem ? lastElem : NULL;
+ ASSIGNLINK( elem, NULL, pList->LinkOffset); // maybe catch a stale reference bug.
+ return 1;
+ }
+ lastElem = iElem;
+ }
+
+ return 0;
+}
+
+
+int ReplaceElem( GenLinkedList *pList, void *elemInList, void *newElem)
+/* Replace an element in the list with a new element, in the same position. */
+{
+ void *iElem, *lastElem;
+
+ if ( elemInList == NULL || newElem == NULL)
+ return 0;
+
+ for ( iElem = pList->Head, lastElem = NULL; iElem; iElem = GETLINK( iElem, pList->LinkOffset))
+ {
+ if ( iElem == elemInList)
+ {
+ ASSIGNLINK( newElem, GETLINK( elemInList, pList->LinkOffset), pList->LinkOffset);
+ if ( lastElem) // somewhere past the head
+ {
+ ASSIGNLINK( lastElem, newElem, pList->LinkOffset);
+ }
+ else // at the head
+ {
+ pList->Head = newElem;
+ }
+ if ( pList->Tail == elemInList)
+ pList->Tail = newElem;
+ return 1;
+ }
+ lastElem = iElem;
+ }
+
+ return 0;
+}
+
+
+// GenDoubleLinkedList /////////////////////////////////////////////////////////
+
+void InitDoubleLinkedList( GenDoubleLinkedList *pList, size_t fwdLinkOffset,
+ size_t backLinkOffset)
+/* Initialize the block of memory pointed to by pList as a double linked list. */
+{
+ pList->Head = NULL;
+ pList->Tail = NULL;
+ pList->FwdLinkOffset = fwdLinkOffset;
+ pList->BackLinkOffset = backLinkOffset;
+}
+
+
+void DLLAddToHead( GenDoubleLinkedList *pList, void *elem)
+/* Add a linked list element to the head of the list. */
+{
+ void *pNext;
+
+ pNext = pList->Head;
+
+ // fix up the forward links
+ ASSIGNLINK( elem, pList->Head, pList->FwdLinkOffset);
+ pList->Head = elem;
+
+ // fix up the backward links
+ if ( pNext) {
+ ASSIGNLINK( pNext, elem, pList->BackLinkOffset);
+ } else
+ pList->Tail = elem;
+ ASSIGNLINK( elem, NULL, pList->BackLinkOffset);
+}
+
+
+void DLLRemoveFromList( GenDoubleLinkedList *pList, void *elem)
+/* Remove a linked list element from the list. */
+/* When the element is removed, its link will be set to NULL. */
+{
+ void *pNext, *pPrev;
+
+ pNext = GETLINK( elem, pList->FwdLinkOffset);
+ pPrev = GETLINK( elem, pList->BackLinkOffset);
+
+ // fix up the forward links
+ if ( pPrev)
+ ASSIGNLINK( pPrev, pNext, pList->FwdLinkOffset);
+ else
+ pList->Head = pNext;
+
+ // fix up the backward links
+ if ( pNext)
+ ASSIGNLINK( pNext, pPrev, pList->BackLinkOffset);
+ else
+ pList->Tail = pPrev;
+
+ ASSIGNLINK( elem, NULL, pList->FwdLinkOffset);
+ ASSIGNLINK( elem, NULL, pList->BackLinkOffset);
+}
+
+
+// GenLinkedOffsetList /////////////////////////////////////////////////////
+
+// Extract the Next offset from element
+#define GETOFFSET( e, o) ( *(size_t*)((char*) (e) + (o)) )
+
+static void AssignOffsetLink( void *elem, void *link, size_t linkOffset);
+
+
+static void AssignOffsetLink( void *elem, void *link, size_t linkOffset)
+// Assign link to elem as an offset from elem. Assign 0 to elem if link is NULL.
+{
+ GETOFFSET( elem, linkOffset) = link ? (size_t) link - (size_t) elem : 0;
+}
+
+
+void *GetHeadPtr( GenLinkedOffsetList *pList)
+/* Return a pointer to the head element of a list, or NULL if none. */
+{
+ return pList->Head ? ( (char*) (pList) + pList->Head) : NULL;
+}
+
+
+void *GetTailPtr( GenLinkedOffsetList *pList)
+/* Return a pointer to the tail element of a list, or NULL if none. */
+{
+ return pList->Tail ? ( (char*) (pList) + pList->Tail) : NULL;
+}
+
+
+void *GetOffsetLink( GenLinkedOffsetList *pList, void *elem)
+/* Return the link pointer contained within element e for pList, or NULL if it is 0. */
+{
+ size_t nextOffset;
+
+ nextOffset = GETOFFSET( elem, pList->LinkOffset);
+
+ return nextOffset ? (char*) elem + nextOffset : NULL;
+}
+
+
+void InitLinkedOffsetList( GenLinkedOffsetList *pList, size_t linkOffset)
+/* Initialize the block of memory pointed to by pList as a linked list. */
+{
+ pList->Head = 0;
+ pList->Tail = 0;
+ pList->LinkOffset = linkOffset;
+}
+
+
+void OffsetAddToTail( GenLinkedOffsetList *pList, void *elem)
+/* Add a linked list element to the tail of the list. */
+{
+ if ( pList->Tail) {
+ AssignOffsetLink( GetTailPtr( pList), elem, pList->LinkOffset);
+ } else
+ pList->Head = (size_t) elem - (size_t) pList;
+ AssignOffsetLink( elem, NULL, pList->LinkOffset);
+
+ pList->Tail = (size_t) elem - (size_t) pList;
+}
+
+
+void OffsetAddToHead( GenLinkedOffsetList *pList, void *elem)
+/* Add a linked list element to the head of the list. */
+{
+ AssignOffsetLink( elem, GetHeadPtr( pList), pList->LinkOffset);
+ if ( pList->Tail == 0)
+ pList->Tail = (size_t) elem - (size_t) pList;
+
+ pList->Head = (size_t) elem - (size_t) pList;
+}
+
+
+int OffsetRemoveFromList( GenLinkedOffsetList *pList, void *elem)
+/* Remove a linked list element from the list. Return 0 if it was not found. */
+/* If the element is removed, its link will be set to NULL. */
+{
+ void *iElem, *lastElem;
+
+ for ( iElem = GetHeadPtr( pList), lastElem = NULL; iElem;
+ iElem = GetOffsetLink( pList, iElem))
+ {
+ if ( iElem == elem) {
+ if ( lastElem) { // somewhere past the head
+ AssignOffsetLink( lastElem, GetOffsetLink( pList, elem), pList->LinkOffset);
+ } else { // at the head
+ iElem = GetOffsetLink( pList, elem);
+ pList->Head = iElem ? (size_t) iElem - (size_t) pList : 0;
+ }
+ if ( GetTailPtr( pList) == elem)
+ pList->Tail = lastElem ? (size_t) lastElem - (size_t) pList : 0;
+ AssignOffsetLink( elem, NULL, pList->LinkOffset); // maybe catch a stale reference bug.
+ return 1;
+ }
+ lastElem = iElem;
+ }
+
+ return 0;
+}
+
+
+int OffsetReplaceElem( GenLinkedOffsetList *pList, void *elemInList, void *newElem)
+/* Replace an element in the list with a new element, in the same position. */
+{
+ void *iElem, *lastElem;
+
+ if ( elemInList == NULL || newElem == NULL)
+ return 0;
+
+ for ( iElem = GetHeadPtr( pList), lastElem = NULL; iElem;
+ iElem = GetOffsetLink( pList, iElem))
+ {
+ if ( iElem == elemInList)
+ {
+ AssignOffsetLink( newElem, GetOffsetLink( pList, elemInList), pList->LinkOffset);
+ if ( lastElem) // somewhere past the head
+ {
+ AssignOffsetLink( lastElem, newElem, pList->LinkOffset);
+ }
+ else // at the head
+ {
+ pList->Head = (size_t) newElem - (size_t) pList;
+ }
+ if ( GetTailPtr( pList) == elemInList)
+ pList->Tail = (size_t) newElem - (size_t) pList;
+ return 1;
+ }
+ lastElem = iElem;
+ }
+
+ return 0;
+}
+
+
diff --git a/sd/source/ui/remotecontrol/mDNSResponder/GenLinkedList.h b/sd/source/ui/remotecontrol/mDNSResponder/GenLinkedList.h
new file mode 100755
index 000000000000..71d5638c03b9
--- /dev/null
+++ b/sd/source/ui/remotecontrol/mDNSResponder/GenLinkedList.h
@@ -0,0 +1,90 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __GenLinkedList__
+#define __GenLinkedList__
+
+
+#include <stddef.h>
+
+
+struct GenLinkedList
+{
+ void *Head,
+ *Tail;
+ size_t LinkOffset;
+};
+typedef struct GenLinkedList GenLinkedList;
+
+
+void InitLinkedList( GenLinkedList *pList, size_t linkOffset);
+
+void AddToHead( GenLinkedList *pList, void *elem);
+void AddToTail( GenLinkedList *pList, void *elem);
+
+int RemoveFromList( GenLinkedList *pList, void *elem);
+
+int ReplaceElem( GenLinkedList *pList, void *elemInList, void *newElem);
+
+
+
+struct GenDoubleLinkedList
+{
+ void *Head,
+ *Tail;
+ size_t FwdLinkOffset,
+ BackLinkOffset;
+};
+typedef struct GenDoubleLinkedList GenDoubleLinkedList;
+
+
+void InitDoubleLinkedList( GenDoubleLinkedList *pList, size_t fwdLinkOffset,
+ size_t backLinkOffset);
+
+void DLLAddToHead( GenDoubleLinkedList *pList, void *elem);
+
+void DLLRemoveFromList( GenDoubleLinkedList *pList, void *elem);
+
+
+
+/* A GenLinkedOffsetList is like a GenLinkedList that stores the *Next field as a signed */
+/* offset from the address of the beginning of the element, rather than as a pointer. */
+
+struct GenLinkedOffsetList
+{
+ size_t Head,
+ Tail;
+ size_t LinkOffset;
+};
+typedef struct GenLinkedOffsetList GenLinkedOffsetList;
+
+
+void InitLinkedOffsetList( GenLinkedOffsetList *pList, size_t linkOffset);
+
+void *GetHeadPtr( GenLinkedOffsetList *pList);
+void *GetTailPtr( GenLinkedOffsetList *pList);
+void *GetOffsetLink( GenLinkedOffsetList *pList, void *elem);
+
+void OffsetAddToHead( GenLinkedOffsetList *pList, void *elem);
+void OffsetAddToTail( GenLinkedOffsetList *pList, void *elem);
+
+int OffsetRemoveFromList( GenLinkedOffsetList *pList, void *elem);
+
+int OffsetReplaceElem( GenLinkedOffsetList *pList, void *elemInList, void *newElem);
+
+
+#endif // __GenLinkedList__
diff --git a/sd/source/ui/remotecontrol/mDNSResponder/dllmain.c b/sd/source/ui/remotecontrol/mDNSResponder/dllmain.c
new file mode 100755
index 000000000000..ce3fce554037
--- /dev/null
+++ b/sd/source/ui/remotecontrol/mDNSResponder/dllmain.c
@@ -0,0 +1,113 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #include <windows.h>
+#include <DebugServices.h>
+#include <stdlib.h>
+
+BOOL APIENTRY DllMain( HANDLE inModule, DWORD inReason, LPVOID inReserved )
+{
+ (void) inModule;
+ (void) inReserved;
+
+ switch( inReason )
+ {
+ case DLL_PROCESS_ATTACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return( TRUE );
+}
+
+
+BOOL
+IsSystemServiceDisabled()
+{
+ ENUM_SERVICE_STATUS * lpService = NULL;
+ SC_HANDLE sc;
+ BOOL ret = FALSE;
+ BOOL ok;
+ DWORD bytesNeeded = 0;
+ DWORD srvCount;
+ DWORD resumeHandle = 0;
+ DWORD srvType;
+ DWORD srvState;
+ DWORD dwBytes = 0;
+ DWORD i;
+ OSStatus err;
+
+ sc = OpenSCManager( NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE );
+ err = translate_errno( sc, GetLastError(), kUnknownErr );
+ require_noerr( err, exit );
+
+ srvType = SERVICE_WIN32;
+ srvState = SERVICE_STATE_ALL;
+
+ for ( ;; )
+ {
+ // Call EnumServicesStatus using the handle returned by OpenSCManager
+
+ ok = EnumServicesStatus ( sc, srvType, srvState, lpService, dwBytes, &bytesNeeded, &srvCount, &resumeHandle );
+
+ if ( ok || ( GetLastError() != ERROR_MORE_DATA ) )
+ {
+ break;
+ }
+
+ if ( lpService )
+ {
+ free( lpService );
+ }
+
+ dwBytes = bytesNeeded;
+
+ lpService = ( ENUM_SERVICE_STATUS* ) malloc( dwBytes );
+ require_action( lpService, exit, ret = FALSE );
+ }
+
+ err = translate_errno( ok, GetLastError(), kUnknownErr );
+ require_noerr( err, exit );
+
+ for ( i = 0; i < srvCount; i++ )
+ {
+ if ( strcmp( lpService[i].lpServiceName, "Bonjour Service" ) == 0 )
+ {
+ if ( ( lpService[i].ServiceStatus.dwCurrentState == SERVICE_PAUSED ) || ( lpService[i].ServiceStatus.dwCurrentState == SERVICE_STOPPED ) )
+ {
+ ret = TRUE;
+ }
+
+ break;
+ }
+ }
+
+exit:
+
+ if ( lpService )
+ {
+ free( lpService );
+ }
+
+ if ( sc )
+ {
+ CloseServiceHandle ( sc );
+ }
+
+ return ret;
+}
diff --git a/sd/source/ui/remotecontrol/mDNSResponder/dns_sd.h b/sd/source/ui/remotecontrol/mDNSResponder/dns_sd.h
new file mode 100755
index 000000000000..eb65465a9132
--- /dev/null
+++ b/sd/source/ui/remotecontrol/mDNSResponder/dns_sd.h
@@ -0,0 +1,2492 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * 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.
+ */
+
+
+/*! @header DNS Service Discovery
+ *
+ * @discussion This section describes the functions, callbacks, and data structures
+ * that make up the DNS Service Discovery API.
+ *
+ * The DNS Service Discovery API is part of Bonjour, Apple's implementation
+ * of zero-configuration networking (ZEROCONF).
+ *
+ * Bonjour allows you to register a network service, such as a
+ * printer or file server, so that it can be found by name or browsed
+ * for by service type and domain. Using Bonjour, applications can
+ * discover what services are available on the network, along with
+ * all the information -- such as name, IP address, and port --
+ * necessary to access a particular service.
+ *
+ * In effect, Bonjour combines the functions of a local DNS server and
+ * AppleTalk. Bonjour allows applications to provide user-friendly printer
+ * and server browsing, among other things, over standard IP networks.
+ * This behavior is a result of combining protocols such as multicast and
+ * DNS to add new functionality to the network (such as multicast DNS).
+ *
+ * Bonjour gives applications easy access to services over local IP
+ * networks without requiring the service or the application to support
+ * an AppleTalk or a Netbeui stack, and without requiring a DNS server
+ * for the local network.
+ */
+
+
+/* _DNS_SD_H contains the mDNSResponder version number for this header file, formatted as follows:
+ * Major part of the build number * 10000 +
+ * minor part of the build number * 100
+ * For example, Mac OS X 10.4.9 has mDNSResponder-108.4, which would be represented as
+ * version 1080400. This allows C code to do simple greater-than and less-than comparisons:
+ * e.g. an application that requires the DNSServiceGetProperty() call (new in mDNSResponder-126) can check:
+ *
+ * #if _DNS_SD_H+0 >= 1260000
+ * ... some C code that calls DNSServiceGetProperty() ...
+ * #endif
+ *
+ * The version defined in this header file symbol allows for compile-time
+ * checking, so that C code building with earlier versions of the header file
+ * can avoid compile errors trying to use functions that aren't even defined
+ * in those earlier versions. Similar checks may also be performed at run-time:
+ * => weak linking -- to avoid link failures if run with an earlier
+ * version of the library that's missing some desired symbol, or
+ * => DNSServiceGetProperty(DaemonVersion) -- to verify whether the running daemon
+ * ("system service" on Windows) meets some required minimum functionality level.
+ */
+
+#ifndef _DNS_SD_H
+#define _DNS_SD_H 3793700
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef WIN32
+#define WIN32
+#endif
+#ifndef _DEBUG
+#define _DEBUG
+#endif
+#ifndef _WINDOWS
+#define _WINDOWS
+#endif
+#ifndef _USRDLL
+#define _USRDLL
+#endif
+#ifndef DEBUG
+#define DEBUG 1
+#endif
+#ifndef NOT_HAVE_SA_LEN
+#define NOT_HAVE_SA_LEN
+#endif
+#ifndef MDNS_DEBUGMSGS
+#define MDNS_DEBUGMSGS 0
+#endif
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#ifndef USE_TCP_LOOPBACK
+#define USE_TCP_LOOPBACK
+#endif
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+#ifndef _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
+#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
+#endif
+
+/* Set to 1 if libdispatch is supported
+ * Note: May also be set by project and/or Makefile
+ */
+#ifndef _DNS_SD_LIBDISPATCH
+#define _DNS_SD_LIBDISPATCH 0
+#endif /* ndef _DNS_SD_LIBDISPATCH */
+
+/* standard calling convention under Win32 is __stdcall */
+/* Note: When compiling Intel EFI (Extensible Firmware Interface) under MS Visual Studio, the */
+/* _WIN32 symbol is defined by the compiler even though it's NOT compiling code for Windows32 */
+#if defined(_WIN32) && !defined(EFI32) && !defined(EFI64)
+#define DNSSD_API __stdcall
+#else
+#define DNSSD_API
+#endif
+
+/* stdint.h does not exist on FreeBSD 4.x; its types are defined in sys/types.h instead */
+#if defined(__FreeBSD__) && (__FreeBSD__ < 5)
+#include <sys/types.h>
+
+/* Likewise, on Sun, standard integer types are in sys/types.h */
+#elif defined(__sun__)
+#include <sys/types.h>
+
+/* EFI does not have stdint.h, or anything else equivalent */
+#elif defined(EFI32) || defined(EFI64) || defined(EFIX64)
+#include "Tiano.h"
+#if !defined(_STDINT_H_)
+typedef UINT8 uint8_t;
+typedef INT8 int8_t;
+typedef UINT16 uint16_t;
+typedef INT16 int16_t;
+typedef UINT32 uint32_t;
+typedef INT32 int32_t;
+#endif
+/* Windows has its own differences */
+#elif defined(_WIN32)
+#include <windows.h>
+#define _UNUSED
+#ifndef _MSL_STDINT_H
+typedef UINT8 uint8_t;
+typedef INT8 int8_t;
+typedef UINT16 uint16_t;
+typedef INT16 int16_t;
+typedef UINT32 uint32_t;
+typedef INT32 int32_t;
+#endif
+
+/* All other Posix platforms use stdint.h */
+#else
+#include <stdint.h>
+#endif
+
+#if _DNS_SD_LIBDISPATCH
+#include <dispatch/dispatch.h>
+#endif
+
+/* DNSServiceRef, DNSRecordRef
+ *
+ * Opaque internal data types.
+ * Note: client is responsible for serializing access to these structures if
+ * they are shared between concurrent threads.
+ */
+
+typedef struct _DNSServiceRef_t *DNSServiceRef;
+typedef struct _DNSRecordRef_t *DNSRecordRef;
+
+struct sockaddr;
+
+/*! @enum General flags
+ * Most DNS-SD API functions and callbacks include a DNSServiceFlags parameter.
+ * As a general rule, any given bit in the 32-bit flags field has a specific fixed meaning,
+ * regardless of the function or callback being used. For any given function or callback,
+ * typically only a subset of the possible flags are meaningful, and all others should be zero.
+ * The discussion section for each API call describes which flags are valid for that call
+ * and callback. In some cases, for a particular call, it may be that no flags are currently
+ * defined, in which case the DNSServiceFlags parameter exists purely to allow future expansion.
+ * In all cases, developers should expect that in future releases, it is possible that new flag
+ * values will be defined, and write code with this in mind. For example, code that tests
+ * if (flags == kDNSServiceFlagsAdd) ...
+ * will fail if, in a future release, another bit in the 32-bit flags field is also set.
+ * The reliable way to test whether a particular bit is set is not with an equality test,
+ * but with a bitwise mask:
+ * if (flags & kDNSServiceFlagsAdd) ...
+ */
+enum
+{
+ kDNSServiceFlagsMoreComing = 0x1,
+ /* MoreComing indicates to a callback that at least one more result is
+ * queued and will be delivered following immediately after this one.
+ * When the MoreComing flag is set, applications should not immediately
+ * update their UI, because this can result in a great deal of ugly flickering
+ * on the screen, and can waste a great deal of CPU time repeatedly updating
+ * the screen with content that is then immediately erased, over and over.
+ * Applications should wait until MoreComing is not set, and then
+ * update their UI when no more changes are imminent.
+ * When MoreComing is not set, that doesn't mean there will be no more
+ * answers EVER, just that there are no more answers immediately
+ * available right now at this instant. If more answers become available
+ * in the future they will be delivered as usual.
+ */
+
+ kDNSServiceFlagsAdd = 0x2,
+ kDNSServiceFlagsDefault = 0x4,
+ /* Flags for domain enumeration and browse/query reply callbacks.
+ * "Default" applies only to enumeration and is only valid in
+ * conjunction with "Add". An enumeration callback with the "Add"
+ * flag NOT set indicates a "Remove", i.e. the domain is no longer
+ * valid.
+ */
+
+ kDNSServiceFlagsNoAutoRename = 0x8,
+ /* Flag for specifying renaming behavior on name conflict when registering
+ * non-shared records. By default, name conflicts are automatically handled
+ * by renaming the service. NoAutoRename overrides this behavior - with this
+ * flag set, name conflicts will result in a callback. The NoAutorename flag
+ * is only valid if a name is explicitly specified when registering a service
+ * (i.e. the default name is not used.)
+ */
+
+ kDNSServiceFlagsShared = 0x10,
+ kDNSServiceFlagsUnique = 0x20,
+ /* Flag for registering individual records on a connected
+ * DNSServiceRef. Shared indicates that there may be multiple records
+ * with this name on the network (e.g. PTR records). Unique indicates that the
+ * record's name is to be unique on the network (e.g. SRV records).
+ */
+
+ kDNSServiceFlagsBrowseDomains = 0x40,
+ kDNSServiceFlagsRegistrationDomains = 0x80,
+ /* Flags for specifying domain enumeration type in DNSServiceEnumerateDomains.
+ * BrowseDomains enumerates domains recommended for browsing, RegistrationDomains
+ * enumerates domains recommended for registration.
+ */
+
+ kDNSServiceFlagsLongLivedQuery = 0x100,
+ /* Flag for creating a long-lived unicast query for the DNSServiceQueryRecord call. */
+
+ kDNSServiceFlagsAllowRemoteQuery = 0x200,
+ /* Flag for creating a record for which we will answer remote queries
+ * (queries from hosts more than one hop away; hosts not directly connected to the local link).
+ */
+
+ kDNSServiceFlagsForceMulticast = 0x400,
+ /* Flag for signifying that a query or registration should be performed exclusively via multicast
+ * DNS, even for a name in a domain (e.g. foo.apple.com.) that would normally imply unicast DNS.
+ */
+
+ kDNSServiceFlagsForce = 0x800,
+ /* Flag for signifying a "stronger" variant of an operation.
+ * Currently defined only for DNSServiceReconfirmRecord(), where it forces a record to
+ * be removed from the cache immediately, instead of querying for a few seconds before
+ * concluding that the record is no longer valid and then removing it. This flag should
+ * be used with caution because if a service browsing PTR record is indeed still valid
+ * on the network, forcing its removal will result in a user-interface flap -- the
+ * discovered service instance will disappear, and then re-appear moments later.
+ */
+
+ kDNSServiceFlagsReturnIntermediates = 0x1000,
+ /* Flag for returning intermediate results.
+ * For example, if a query results in an authoritative NXDomain (name does not exist)
+ * then that result is returned to the client. However the query is not implicitly
+ * cancelled -- it remains active and if the answer subsequently changes
+ * (e.g. because a VPN tunnel is subsequently established) then that positive
+ * result will still be returned to the client.
+ * Similarly, if a query results in a CNAME record, then in addition to following
+ * the CNAME referral, the intermediate CNAME result is also returned to the client.
+ * When this flag is not set, NXDomain errors are not returned, and CNAME records
+ * are followed silently without informing the client of the intermediate steps.
+ * (In earlier builds this flag was briefly calledkDNSServiceFlagsReturnCNAME)
+ */
+
+ kDNSServiceFlagsNonBrowsable = 0x2000,
+ /* A service registered with the NonBrowsable flag set can be resolved using
+ * DNSServiceResolve(), but will not be discoverable using DNSServiceBrowse().
+ * This is for cases where the name is actually a GUID; it is found by other means;
+ * there is no end-user benefit to browsing to find a long list of opaque GUIDs.
+ * Using the NonBrowsable flag creates SRV+TXT without the cost of also advertising
+ * an associated PTR record.
+ */
+
+ kDNSServiceFlagsShareConnection = 0x4000,
+ /* For efficiency, clients that perform many concurrent operations may want to use a
+ * single Unix Domain Socket connection with the background daemon, instead of having a
+ * separate connection for each independent operation. To use this mode, clients first
+ * call DNSServiceCreateConnection(&MainRef) to initialize the main DNSServiceRef.
+ * For each subsequent operation that is to share that same connection, the client copies
+ * the MainRef, and then passes the address of that copy, setting the ShareConnection flag
+ * to tell the library that this DNSServiceRef is not a typical uninitialized DNSServiceRef;
+ * it's a copy of an existing DNSServiceRef whose connection information should be reused.
+ *
+ * For example:
+ *
+ * DNSServiceErrorType error;
+ * DNSServiceRef MainRef;
+ * error = DNSServiceCreateConnection(&MainRef);
+ * if (error) ...
+ * DNSServiceRef BrowseRef = MainRef; // Important: COPY the primary DNSServiceRef first...
+ * error = DNSServiceBrowse(&BrowseRef, kDNSServiceFlagsShareConnection, ...); // then use the copy
+ * if (error) ...
+ * ...
+ * DNSServiceRefDeallocate(BrowseRef); // Terminate the browse operation
+ * DNSServiceRefDeallocate(MainRef); // Terminate the shared connection
+ *
+ * Notes:
+ *
+ * 1. Collective kDNSServiceFlagsMoreComing flag
+ * When callbacks are invoked using a shared DNSServiceRef, the
+ * kDNSServiceFlagsMoreComing flag applies collectively to *all* active
+ * operations sharing the same parent DNSServiceRef. If the MoreComing flag is
+ * set it means that there are more results queued on this parent DNSServiceRef,
+ * but not necessarily more results for this particular callback function.
+ * The implication of this for client programmers is that when a callback
+ * is invoked with the MoreComing flag set, the code should update its
+ * internal data structures with the new result, and set a variable indicating
+ * that its UI needs to be updated. Then, later when a callback is eventually
+ * invoked with the MoreComing flag not set, the code should update *all*
+ * stale UI elements related to that shared parent DNSServiceRef that need
+ * updating, not just the UI elements related to the particular callback
+ * that happened to be the last one to be invoked.
+ *
+ * 2. Canceling operations and kDNSServiceFlagsMoreComing
+ * Whenever you cancel any operation for which you had deferred UI updates
+ * waiting because of a kDNSServiceFlagsMoreComing flag, you should perform
+ * those deferred UI updates. This is because, after cancelling the operation,
+ * you can no longer wait for a callback *without* MoreComing set, to tell
+ * you do perform your deferred UI updates (the operation has been canceled,
+ * so there will be no more callbacks). An implication of the collective
+ * kDNSServiceFlagsMoreComing flag for shared connections is that this
+ * guideline applies more broadly -- any time you cancel an operation on
+ * a shared connection, you should perform all deferred UI updates for all
+ * operations sharing that connection. This is because the MoreComing flag
+ * might have been referring to events coming for the operation you canceled,
+ * which will now not be coming because the operation has been canceled.
+ *
+ * 3. Only share DNSServiceRef's created with DNSServiceCreateConnection
+ * Calling DNSServiceCreateConnection(&ref) creates a special shareable DNSServiceRef.
+ * DNSServiceRef's created by other calls like DNSServiceBrowse() or DNSServiceResolve()
+ * cannot be shared by copying them and using kDNSServiceFlagsShareConnection.
+ *
+ * 4. Don't Double-Deallocate
+ * Calling DNSServiceRefDeallocate(ref) for a particular operation's DNSServiceRef terminates
+ * just that operation. Calling DNSServiceRefDeallocate(ref) for the main shared DNSServiceRef
+ * (the parent DNSServiceRef, originally created by DNSServiceCreateConnection(&ref))
+ * automatically terminates the shared connection and all operations that were still using it.
+ * After doing this, DO NOT then attempt to deallocate any remaining subordinate DNSServiceRef's.
+ * The memory used by those subordinate DNSServiceRef's has already been freed, so any attempt
+ * to do a DNSServiceRefDeallocate (or any other operation) on them will result in accesses
+ * to freed memory, leading to crashes or other equally undesirable results.
+ *
+ * 5. Thread Safety
+ * The dns_sd.h API does not presuppose any particular threading model, and consequently
+ * does no locking of its own (which would require linking some specific threading library).
+ * If client code calls API routines on the same DNSServiceRef concurrently
+ * from multiple threads, it is the client's responsibility to use a mutext
+ * lock or take similar appropriate precautions to serialize those calls.
+ */
+
+ kDNSServiceFlagsSuppressUnusable = 0x8000,
+ /*
+ * This flag is meaningful only in DNSServiceQueryRecord which suppresses unusable queries on the
+ * wire. If "hostname" is a wide-area unicast DNS hostname (i.e. not a ".local." name)
+ * but this host has no routable IPv6 address, then the call will not try to look up IPv6 addresses
+ * for "hostname", since any addresses it found would be unlikely to be of any use anyway. Similarly,
+ * if this host has no routable IPv4 address, the call will not try to look up IPv4 addresses for
+ * "hostname".
+ */
+
+ kDNSServiceFlagsTimeout = 0x10000,
+ /*
+ * When kDNServiceFlagsTimeout is passed to DNSServiceQueryRecord or DNSServiceGetAddrInfo, the query is
+ * stopped after a certain number of seconds have elapsed. The time at which the query will be stopped
+ * is determined by the system and cannot be configured by the user. The query will be stopped irrespective
+ * of whether a response was given earlier or not. When the query is stopped, the callback will be called
+ * with an error code of kDNSServiceErr_Timeout and a NULL sockaddr will be returned for DNSServiceGetAddrInfo
+ * and zero length rdata will be returned for DNSServiceQueryRecord.
+ */
+
+ kDNSServiceFlagsIncludeP2P = 0x20000,
+ /*
+ * Include P2P interfaces when kDNSServiceInterfaceIndexAny is specified.
+ * By default, specifying kDNSServiceInterfaceIndexAny does not include P2P interfaces.
+ */
+
+ kDNSServiceFlagsWakeOnResolve = 0x40000,
+ /*
+ * This flag is meaningful only in DNSServiceResolve. When set, it tries to send a magic packet
+ * to wake up the client.
+ */
+
+ kDNSServiceFlagsBackgroundTrafficClass = 0x80000,
+ /*
+ * This flag is meaningful in DNSServiceBrowse, DNSServiceGetAddrInfo, DNSServiceQueryRecord,
+ * and DNSServiceResolve. When set, it uses the background traffic
+ * class for packets that service the request.
+ */
+
+ kDNSServiceFlagsIncludeAWDL = 0x100000
+ /*
+ * Include AWDL interface when kDNSServiceInterfaceIndexAny is specified.
+ */
+};
+
+/* Possible protocols for DNSServiceNATPortMappingCreate(). */
+enum
+{
+ kDNSServiceProtocol_IPv4 = 0x01,
+ kDNSServiceProtocol_IPv6 = 0x02,
+ /* 0x04 and 0x08 reserved for future internetwork protocols */
+
+ kDNSServiceProtocol_UDP = 0x10,
+ kDNSServiceProtocol_TCP = 0x20
+ /* 0x40 and 0x80 reserved for future transport protocols, e.g. SCTP [RFC 2960]
+ * or DCCP [RFC 4340]. If future NAT gateways are created that support port
+ * mappings for these protocols, new constants will be defined here.
+ */
+};
+
+/*
+ * The values for DNS Classes and Types are listed in RFC 1035, and are available
+ * on every OS in its DNS header file. Unfortunately every OS does not have the
+ * same header file containing DNS Class and Type constants, and the names of
+ * the constants are not consistent. For example, BIND 8 uses "T_A",
+ * BIND 9 uses "ns_t_a", Windows uses "DNS_TYPE_A", etc.
+ * For this reason, these constants are also listed here, so that code using
+ * the DNS-SD programming APIs can use these constants, so that the same code
+ * can compile on all our supported platforms.
+ */
+
+enum
+{
+ kDNSServiceClass_IN = 1 /* Internet */
+};
+
+enum
+{
+ kDNSServiceType_A = 1, /* Host address. */
+ kDNSServiceType_NS = 2, /* Authoritative server. */
+ kDNSServiceType_MD = 3, /* Mail destination. */
+ kDNSServiceType_MF = 4, /* Mail forwarder. */
+ kDNSServiceType_CNAME = 5, /* Canonical name. */
+ kDNSServiceType_SOA = 6, /* Start of authority zone. */
+ kDNSServiceType_MB = 7, /* Mailbox domain name. */
+ kDNSServiceType_MG = 8, /* Mail group member. */
+ kDNSServiceType_MR = 9, /* Mail rename name. */
+ kDNSServiceType_NULL = 10, /* Null resource record. */
+ kDNSServiceType_WKS = 11, /* Well known service. */
+ kDNSServiceType_PTR = 12, /* Domain name pointer. */
+ kDNSServiceType_HINFO = 13, /* Host information. */
+ kDNSServiceType_MINFO = 14, /* Mailbox information. */
+ kDNSServiceType_MX = 15, /* Mail routing information. */
+ kDNSServiceType_TXT = 16, /* One or more text strings (NOT "zero or more..."). */
+ kDNSServiceType_RP = 17, /* Responsible person. */
+ kDNSServiceType_AFSDB = 18, /* AFS cell database. */
+ kDNSServiceType_X25 = 19, /* X_25 calling address. */
+ kDNSServiceType_ISDN = 20, /* ISDN calling address. */
+ kDNSServiceType_RT = 21, /* Router. */
+ kDNSServiceType_NSAP = 22, /* NSAP address. */
+ kDNSServiceType_NSAP_PTR = 23, /* Reverse NSAP lookup (deprecated). */
+ kDNSServiceType_SIG = 24, /* Security signature. */
+ kDNSServiceType_KEY = 25, /* Security key. */
+ kDNSServiceType_PX = 26, /* X.400 mail mapping. */
+ kDNSServiceType_GPOS = 27, /* Geographical position (withdrawn). */
+ kDNSServiceType_AAAA = 28, /* IPv6 Address. */
+ kDNSServiceType_LOC = 29, /* Location Information. */
+ kDNSServiceType_NXT = 30, /* Next domain (security). */
+ kDNSServiceType_EID = 31, /* Endpoint identifier. */
+ kDNSServiceType_NIMLOC = 32, /* Nimrod Locator. */
+ kDNSServiceType_SRV = 33, /* Server Selection. */
+ kDNSServiceType_ATMA = 34, /* ATM Address */
+ kDNSServiceType_NAPTR = 35, /* Naming Authority PoinTeR */
+ kDNSServiceType_KX = 36, /* Key Exchange */
+ kDNSServiceType_CERT = 37, /* Certification record */
+ kDNSServiceType_A6 = 38, /* IPv6 Address (deprecated) */
+ kDNSServiceType_DNAME = 39, /* Non-terminal DNAME (for IPv6) */
+ kDNSServiceType_SINK = 40, /* Kitchen sink (experimental) */
+ kDNSServiceType_OPT = 41, /* EDNS0 option (meta-RR) */
+ kDNSServiceType_APL = 42, /* Address Prefix List */
+ kDNSServiceType_DS = 43, /* Delegation Signer */
+ kDNSServiceType_SSHFP = 44, /* SSH Key Fingerprint */
+ kDNSServiceType_IPSECKEY = 45, /* IPSECKEY */
+ kDNSServiceType_RRSIG = 46, /* RRSIG */
+ kDNSServiceType_NSEC = 47, /* Denial of Existence */
+ kDNSServiceType_DNSKEY = 48, /* DNSKEY */
+ kDNSServiceType_DHCID = 49, /* DHCP Client Identifier */
+ kDNSServiceType_NSEC3 = 50, /* Hashed Authenticated Denial of Existence */
+ kDNSServiceType_NSEC3PARAM = 51, /* Hashed Authenticated Denial of Existence */
+
+ kDNSServiceType_HIP = 55, /* Host Identity Protocol */
+
+ kDNSServiceType_SPF = 99, /* Sender Policy Framework for E-Mail */
+ kDNSServiceType_UINFO = 100, /* IANA-Reserved */
+ kDNSServiceType_UID = 101, /* IANA-Reserved */
+ kDNSServiceType_GID = 102, /* IANA-Reserved */
+ kDNSServiceType_UNSPEC = 103, /* IANA-Reserved */
+
+ kDNSServiceType_TKEY = 249, /* Transaction key */
+ kDNSServiceType_TSIG = 250, /* Transaction signature. */
+ kDNSServiceType_IXFR = 251, /* Incremental zone transfer. */
+ kDNSServiceType_AXFR = 252, /* Transfer zone of authority. */
+ kDNSServiceType_MAILB = 253, /* Transfer mailbox records. */
+ kDNSServiceType_MAILA = 254, /* Transfer mail agent records. */
+ kDNSServiceType_ANY = 255 /* Wildcard match. */
+};
+
+/* possible error code values */
+enum
+{
+ kDNSServiceErr_NoError = 0,
+ kDNSServiceErr_Unknown = -65537, /* 0xFFFE FFFF */
+ kDNSServiceErr_NoSuchName = -65538,
+ kDNSServiceErr_NoMemory = -65539,
+ kDNSServiceErr_BadParam = -65540,
+ kDNSServiceErr_BadReference = -65541,
+ kDNSServiceErr_BadState = -65542,
+ kDNSServiceErr_BadFlags = -65543,
+ kDNSServiceErr_Unsupported = -65544,
+ kDNSServiceErr_NotInitialized = -65545,
+ kDNSServiceErr_AlreadyRegistered = -65547,
+ kDNSServiceErr_NameConflict = -65548,
+ kDNSServiceErr_Invalid = -65549,
+ kDNSServiceErr_Firewall = -65550,
+ kDNSServiceErr_Incompatible = -65551, /* client library incompatible with daemon */
+ kDNSServiceErr_BadInterfaceIndex = -65552,
+ kDNSServiceErr_Refused = -65553,
+ kDNSServiceErr_NoSuchRecord = -65554,
+ kDNSServiceErr_NoAuth = -65555,
+ kDNSServiceErr_NoSuchKey = -65556,
+ kDNSServiceErr_NATTraversal = -65557,
+ kDNSServiceErr_DoubleNAT = -65558,
+ kDNSServiceErr_BadTime = -65559, /* Codes up to here existed in Tiger */
+ kDNSServiceErr_BadSig = -65560,
+ kDNSServiceErr_BadKey = -65561,
+ kDNSServiceErr_Transient = -65562,
+ kDNSServiceErr_ServiceNotRunning = -65563, /* Background daemon not running */
+ kDNSServiceErr_NATPortMappingUnsupported = -65564, /* NAT doesn't support NAT-PMP or UPnP */
+ kDNSServiceErr_NATPortMappingDisabled = -65565, /* NAT supports NAT-PMP or UPnP but it's disabled by the administrator */
+ kDNSServiceErr_NoRouter = -65566, /* No router currently configured (probably no network connectivity) */
+ kDNSServiceErr_PollingMode = -65567,
+ kDNSServiceErr_Timeout = -65568
+
+ /* mDNS Error codes are in the range
+ * FFFE FF00 (-65792) to FFFE FFFF (-65537) */
+};
+
+/* Maximum length, in bytes, of a service name represented as a */
+/* literal C-String, including the terminating NULL at the end. */
+
+#define kDNSServiceMaxServiceName 64
+
+/* Maximum length, in bytes, of a domain name represented as an *escaped* C-String */
+/* including the final trailing dot, and the C-String terminating NULL at the end. */
+
+#define kDNSServiceMaxDomainName 1009
+
+/*
+ * Notes on DNS Name Escaping
+ * -- or --
+ * "Why is kDNSServiceMaxDomainName 1009, when the maximum legal domain name is 256 bytes?"
+ *
+ * All strings used in the DNS-SD APIs are UTF-8 strings. Apart from the exceptions noted below,
+ * the APIs expect the strings to be properly escaped, using the conventional DNS escaping rules:
+ *
+ * '\\' represents a single literal '\' in the name
+ * '\.' represents a single literal '.' in the name
+ * '\ddd', where ddd is a three-digit decimal value from 000 to 255,
+ * represents a single literal byte with that value.
+ * A bare unescaped '.' is a label separator, marking a boundary between domain and subdomain.
+ *
+ * The exceptions, that do not use escaping, are the routines where the full
+ * DNS name of a resource is broken, for convenience, into servicename/regtype/domain.
+ * In these routines, the "servicename" is NOT escaped. It does not need to be, since
+ * it is, by definition, just a single literal string. Any characters in that string
+ * represent exactly what they are. The "regtype" portion is, technically speaking,
+ * escaped, but since legal regtypes are only allowed to contain letters, digits,
+ * and hyphens, there is nothing to escape, so the issue is moot. The "domain"
+ * portion is also escaped, though most domains in use on the public Internet
+ * today, like regtypes, don't contain any characters that need to be escaped.
+ * As DNS-SD becomes more popular, rich-text domains for service discovery will
+ * become common, so software should be written to cope with domains with escaping.
+ *
+ * The servicename may be up to 63 bytes of UTF-8 text (not counting the C-String
+ * terminating NULL at the end). The regtype is of the form _service._tcp or
+ * _service._udp, where the "service" part is 1-15 characters, which may be
+ * letters, digits, or hyphens. The domain part of the three-part name may be
+ * any legal domain, providing that the resulting servicename+regtype+domain
+ * name does not exceed 256 bytes.
+ *
+ * For most software, these issues are transparent. When browsing, the discovered
+ * servicenames should simply be displayed as-is. When resolving, the discovered
+ * servicename/regtype/domain are simply passed unchanged to DNSServiceResolve().
+ * When a DNSServiceResolve() succeeds, the returned fullname is already in
+ * the correct format to pass to standard system DNS APIs such as res_query().
+ * For converting from servicename/regtype/domain to a single properly-escaped
+ * full DNS name, the helper function DNSServiceConstructFullName() is provided.
+ *
+ * The following (highly contrived) example illustrates the escaping process.
+ * Suppose you have an service called "Dr. Smith\Dr. Johnson", of type "_ftp._tcp"
+ * in subdomain "4th. Floor" of subdomain "Building 2" of domain "apple.com."
+ * The full (escaped) DNS name of this service's SRV record would be:
+ * Dr\.\032Smith\\Dr\.\032Johnson._ftp._tcp.4th\.\032Floor.Building\0322.apple.com.
+ */
+
+
+/*
+ * Constants for specifying an interface index
+ *
+ * Specific interface indexes are identified via a 32-bit unsigned integer returned
+ * by the if_nametoindex() family of calls.
+ *
+ * If the client passes 0 for interface index, that means "do the right thing",
+ * which (at present) means, "if the name is in an mDNS local multicast domain
+ * (e.g. 'local.', '254.169.in-addr.arpa.', '{8,9,A,B}.E.F.ip6.arpa.') then multicast
+ * on all applicable interfaces, otherwise send via unicast to the appropriate
+ * DNS server." Normally, most clients will use 0 for interface index to
+ * automatically get the default sensible behaviour.
+ *
+ * If the client passes a positive interface index, then for multicast names that
+ * indicates to do the operation only on that one interface. For unicast names the
+ * interface index is ignored unless kDNSServiceFlagsForceMulticast is also set.
+ *
+ * If the client passes kDNSServiceInterfaceIndexLocalOnly when registering
+ * a service, then that service will be found *only* by other local clients
+ * on the same machine that are browsing using kDNSServiceInterfaceIndexLocalOnly
+ * or kDNSServiceInterfaceIndexAny.
+ * If a client has a 'private' service, accessible only to other processes
+ * running on the same machine, this allows the client to advertise that service
+ * in a way such that it does not inadvertently appear in service lists on
+ * all the other machines on the network.
+ *
+ * If the client passes kDNSServiceInterfaceIndexLocalOnly when browsing
+ * then it will find *all* records registered on that same local machine.
+ * Clients explicitly wishing to discover *only* LocalOnly services can
+ * accomplish this by inspecting the interfaceIndex of each service reported
+ * to their DNSServiceBrowseReply() callback function, and discarding those
+ * where the interface index is not kDNSServiceInterfaceIndexLocalOnly.
+ *
+ * kDNSServiceInterfaceIndexP2P is meaningful only in Browse, QueryRecord,
+ * and Resolve operations. It should not be used in other DNSService APIs.
+ *
+ * - If kDNSServiceInterfaceIndexP2P is passed to DNSServiceBrowse or
+ * DNSServiceQueryRecord, it restricts the operation to P2P.
+ *
+ * - If kDNSServiceInterfaceIndexP2P is passed to DNSServiceResolve, it is
+ * mapped internally to kDNSServiceInterfaceIndexAny with the kDNSServiceFlagsIncludeP2P
+ * set, because resolving a P2P service may create and/or enable an interface whose
+ * index is not known a priori. The resolve callback will indicate the index of the
+ * interface via which the service can be accessed.
+ *
+ * If applications pass kDNSServiceInterfaceIndexAny to DNSServiceBrowse
+ * or DNSServiceQueryRecord, they must set the kDNSServiceFlagsIncludeP2P flag
+ * to include P2P. In this case, if a service instance or the record being queried
+ * is found over P2P, the resulting ADD event will indicate kDNSServiceInterfaceIndexP2P
+ * as the interface index.
+ */
+
+#define kDNSServiceInterfaceIndexAny 0
+#define kDNSServiceInterfaceIndexLocalOnly ((uint32_t)-1)
+#define kDNSServiceInterfaceIndexUnicast ((uint32_t)-2)
+#define kDNSServiceInterfaceIndexP2P ((uint32_t)-3)
+
+typedef uint32_t DNSServiceFlags;
+typedef uint32_t DNSServiceProtocol;
+typedef int32_t DNSServiceErrorType;
+
+
+/*********************************************************************************************
+*
+* Version checking
+*
+*********************************************************************************************/
+
+/* DNSServiceGetProperty() Parameters:
+ *
+ * property: The requested property.
+ * Currently the only property defined is kDNSServiceProperty_DaemonVersion.
+ *
+ * result: Place to store result.
+ * For retrieving DaemonVersion, this should be the address of a uint32_t.
+ *
+ * size: Pointer to uint32_t containing size of the result location.
+ * For retrieving DaemonVersion, this should be sizeof(uint32_t).
+ * On return the uint32_t is updated to the size of the data returned.
+ * For DaemonVersion, the returned size is always sizeof(uint32_t), but
+ * future properties could be defined which return variable-sized results.
+ *
+ * return value: Returns kDNSServiceErr_NoError on success, or kDNSServiceErr_ServiceNotRunning
+ * if the daemon (or "system service" on Windows) is not running.
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceGetProperty
+(
+ const char *property, /* Requested property (i.e. kDNSServiceProperty_DaemonVersion) */
+ void *result, /* Pointer to place to store result */
+ uint32_t *size /* size of result location */
+);
+
+/*
+ * When requesting kDNSServiceProperty_DaemonVersion, the result pointer must point
+ * to a 32-bit unsigned integer, and the size parameter must be set to sizeof(uint32_t).
+ *
+ * On return, the 32-bit unsigned integer contains the version number, formatted as follows:
+ * Major part of the build number * 10000 +
+ * minor part of the build number * 100
+ *
+ * For example, Mac OS X 10.4.9 has mDNSResponder-108.4, which would be represented as
+ * version 1080400. This allows applications to do simple greater-than and less-than comparisons:
+ * e.g. an application that requires at least mDNSResponder-108.4 can check:
+ *
+ * if (version >= 1080400) ...
+ *
+ * Example usage:
+ *
+ * uint32_t version;
+ * uint32_t size = sizeof(version);
+ * DNSServiceErrorType err = DNSServiceGetProperty(kDNSServiceProperty_DaemonVersion, &version, &size);
+ * if (!err) printf("Bonjour version is %d.%d\n", version / 10000, version / 100 % 100);
+ */
+
+#define kDNSServiceProperty_DaemonVersion "DaemonVersion"
+
+
+/*********************************************************************************************
+*
+* Unix Domain Socket access, DNSServiceRef deallocation, and data processing functions
+*
+*********************************************************************************************/
+
+/* DNSServiceRefSockFD()
+ *
+ * Access underlying Unix domain socket for an initialized DNSServiceRef.
+ * The DNS Service Discovery implementation uses this socket to communicate between the client and
+ * the mDNSResponder daemon. The application MUST NOT directly read from or write to this socket.
+ * Access to the socket is provided so that it can be used as a kqueue event source, a CFRunLoop
+ * event source, in a select() loop, etc. When the underlying event management subsystem (kqueue/
+ * select/CFRunLoop etc.) indicates to the client that data is available for reading on the
+ * socket, the client should call DNSServiceProcessResult(), which will extract the daemon's
+ * reply from the socket, and pass it to the appropriate application callback. By using a run
+ * loop or select(), results from the daemon can be processed asynchronously. Alternatively,
+ * a client can choose to fork a thread and have it loop calling "DNSServiceProcessResult(ref);"
+ * If DNSServiceProcessResult() is called when no data is available for reading on the socket, it
+ * will block until data does become available, and then process the data and return to the caller.
+ * When data arrives on the socket, the client is responsible for calling DNSServiceProcessResult(ref)
+ * in a timely fashion -- if the client allows a large backlog of data to build up the daemon
+ * may terminate the connection.
+ *
+ * sdRef: A DNSServiceRef initialized by any of the DNSService calls.
+ *
+ * return value: The DNSServiceRef's underlying socket descriptor, or -1 on
+ * error.
+ */
+
+int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef);
+
+
+/* DNSServiceProcessResult()
+ *
+ * Read a reply from the daemon, calling the appropriate application callback. This call will
+ * block until the daemon's response is received. Use DNSServiceRefSockFD() in
+ * conjunction with a run loop or select() to determine the presence of a response from the
+ * server before calling this function to process the reply without blocking. Call this function
+ * at any point if it is acceptable to block until the daemon's response arrives. Note that the
+ * client is responsible for ensuring that DNSServiceProcessResult() is called whenever there is
+ * a reply from the daemon - the daemon may terminate its connection with a client that does not
+ * process the daemon's responses.
+ *
+ * sdRef: A DNSServiceRef initialized by any of the DNSService calls
+ * that take a callback parameter.
+ *
+ * return value: Returns kDNSServiceErr_NoError on success, otherwise returns
+ * an error code indicating the specific failure that occurred.
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef);
+
+
+/* DNSServiceRefDeallocate()
+ *
+ * Terminate a connection with the daemon and free memory associated with the DNSServiceRef.
+ * Any services or records registered with this DNSServiceRef will be deregistered. Any
+ * Browse, Resolve, or Query operations called with this reference will be terminated.
+ *
+ * Note: If the reference's underlying socket is used in a run loop or select() call, it should
+ * be removed BEFORE DNSServiceRefDeallocate() is called, as this function closes the reference's
+ * socket.
+ *
+ * Note: If the reference was initialized with DNSServiceCreateConnection(), any DNSRecordRefs
+ * created via this reference will be invalidated by this call - the resource records are
+ * deregistered, and their DNSRecordRefs may not be used in subsequent functions. Similarly,
+ * if the reference was initialized with DNSServiceRegister, and an extra resource record was
+ * added to the service via DNSServiceAddRecord(), the DNSRecordRef created by the Add() call
+ * is invalidated when this function is called - the DNSRecordRef may not be used in subsequent
+ * functions.
+ *
+ * Note: This call is to be used only with the DNSServiceRef defined by this API. It is
+ * not compatible with dns_service_discovery_ref objects defined in the legacy Mach-based
+ * DNSServiceDiscovery.h API.
+ *
+ * sdRef: A DNSServiceRef initialized by any of the DNSService calls.
+ *
+ */
+
+void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef);
+
+
+/*********************************************************************************************
+*
+* Domain Enumeration
+*
+*********************************************************************************************/
+
+/* DNSServiceEnumerateDomains()
+ *
+ * Asynchronously enumerate domains available for browsing and registration.
+ *
+ * The enumeration MUST be cancelled via DNSServiceRefDeallocate() when no more domains
+ * are to be found.
+ *
+ * Note that the names returned are (like all of DNS-SD) UTF-8 strings,
+ * and are escaped using standard DNS escaping rules.
+ * (See "Notes on DNS Name Escaping" earlier in this file for more details.)
+ * A graphical browser displaying a hierarchical tree-structured view should cut
+ * the names at the bare dots to yield individual labels, then de-escape each
+ * label according to the escaping rules, and then display the resulting UTF-8 text.
+ *
+ * DNSServiceDomainEnumReply Callback Parameters:
+ *
+ * sdRef: The DNSServiceRef initialized by DNSServiceEnumerateDomains().
+ *
+ * flags: Possible values are:
+ * kDNSServiceFlagsMoreComing
+ * kDNSServiceFlagsAdd
+ * kDNSServiceFlagsDefault
+ *
+ * interfaceIndex: Specifies the interface on which the domain exists. (The index for a given
+ * interface is determined via the if_nametoindex() family of calls.)
+ *
+ * errorCode: Will be kDNSServiceErr_NoError (0) on success, otherwise indicates
+ * the failure that occurred (other parameters are undefined if errorCode is nonzero).
+ *
+ * replyDomain: The name of the domain.
+ *
+ * context: The context pointer passed to DNSServiceEnumerateDomains.
+ *
+ */
+
+typedef void (DNSSD_API *DNSServiceDomainEnumReply)
+(
+ DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char *replyDomain,
+ void *context
+);
+
+
+/* DNSServiceEnumerateDomains() Parameters:
+ *
+ * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
+ * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
+ * and the enumeration operation will run indefinitely until the client
+ * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ *
+ * flags: Possible values are:
+ * kDNSServiceFlagsBrowseDomains to enumerate domains recommended for browsing.
+ * kDNSServiceFlagsRegistrationDomains to enumerate domains recommended
+ * for registration.
+ *
+ * interfaceIndex: If non-zero, specifies the interface on which to look for domains.
+ * (the index for a given interface is determined via the if_nametoindex()
+ * family of calls.) Most applications will pass 0 to enumerate domains on
+ * all interfaces. See "Constants for specifying an interface index" for more details.
+ *
+ * callBack: The function to be called when a domain is found or the call asynchronously
+ * fails.
+ *
+ * context: An application context pointer which is passed to the callback function
+ * (may be NULL).
+ *
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ * errors are delivered to the callback), otherwise returns an error code indicating
+ * the error that occurred (the callback is not invoked and the DNSServiceRef
+ * is not initialized).
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceDomainEnumReply callBack,
+ void *context /* may be NULL */
+);
+
+
+/*********************************************************************************************
+*
+* Service Registration
+*
+*********************************************************************************************/
+
+/* Register a service that is discovered via Browse() and Resolve() calls.
+ *
+ * DNSServiceRegisterReply() Callback Parameters:
+ *
+ * sdRef: The DNSServiceRef initialized by DNSServiceRegister().
+ *
+ * flags: When a name is successfully registered, the callback will be
+ * invoked with the kDNSServiceFlagsAdd flag set. When Wide-Area
+ * DNS-SD is in use, it is possible for a single service to get
+ * more than one success callback (e.g. one in the "local" multicast
+ * DNS domain, and another in a wide-area unicast DNS domain).
+ * If a successfully-registered name later suffers a name conflict
+ * or similar problem and has to be deregistered, the callback will
+ * be invoked with the kDNSServiceFlagsAdd flag not set. The callback
+ * is *not* invoked in the case where the caller explicitly terminates
+ * the service registration by calling DNSServiceRefDeallocate(ref);
+ *
+ * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will
+ * indicate the failure that occurred (including name conflicts,
+ * if the kDNSServiceFlagsNoAutoRename flag was used when registering.)
+ * Other parameters are undefined if errorCode is nonzero.
+ *
+ * name: The service name registered (if the application did not specify a name in
+ * DNSServiceRegister(), this indicates what name was automatically chosen).
+ *
+ * regtype: The type of service registered, as it was passed to the callout.
+ *
+ * domain: The domain on which the service was registered (if the application did not
+ * specify a domain in DNSServiceRegister(), this indicates the default domain
+ * on which the service was registered).
+ *
+ * context: The context pointer that was passed to the callout.
+ *
+ */
+
+typedef void (DNSSD_API *DNSServiceRegisterReply)
+(
+ DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ DNSServiceErrorType errorCode,
+ const char *name,
+ const char *regtype,
+ const char *domain,
+ void *context
+);
+
+
+/* DNSServiceRegister() Parameters:
+ *
+ * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
+ * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
+ * and the registration will remain active indefinitely until the client
+ * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ *
+ * interfaceIndex: If non-zero, specifies the interface on which to register the service
+ * (the index for a given interface is determined via the if_nametoindex()
+ * family of calls.) Most applications will pass 0 to register on all
+ * available interfaces. See "Constants for specifying an interface index" for more details.
+ *
+ * flags: Indicates the renaming behavior on name conflict (most applications
+ * will pass 0). See flag definitions above for details.
+ *
+ * name: If non-NULL, specifies the service name to be registered.
+ * Most applications will not specify a name, in which case the computer
+ * name is used (this name is communicated to the client via the callback).
+ * If a name is specified, it must be 1-63 bytes of UTF-8 text.
+ * If the name is longer than 63 bytes it will be automatically truncated
+ * to a legal length, unless the NoAutoRename flag is set,
+ * in which case kDNSServiceErr_BadParam will be returned.
+ *
+ * regtype: The service type followed by the protocol, separated by a dot
+ * (e.g. "_ftp._tcp"). The service type must be an underscore, followed
+ * by 1-15 characters, which may be letters, digits, or hyphens.
+ * The transport protocol must be "_tcp" or "_udp". New service types
+ * should be registered at <http://www.dns-sd.org/ServiceTypes.html>.
+ *
+ * Additional subtypes of the primary service type (where a service
+ * type has defined subtypes) follow the primary service type in a
+ * comma-separated list, with no additional spaces, e.g.
+ * "_primarytype._tcp,_subtype1,_subtype2,_subtype3"
+ * Subtypes provide a mechanism for filtered browsing: A client browsing
+ * for "_primarytype._tcp" will discover all instances of this type;
+ * a client browsing for "_primarytype._tcp,_subtype2" will discover only
+ * those instances that were registered with "_subtype2" in their list of
+ * registered subtypes.
+ *
+ * The subtype mechanism can be illustrated with some examples using the
+ * dns-sd command-line tool:
+ *
+ * % dns-sd -R Simple _test._tcp "" 1001 &
+ * % dns-sd -R Better _test._tcp,HasFeatureA "" 1002 &
+ * % dns-sd -R Best _test._tcp,HasFeatureA,HasFeatureB "" 1003 &
+ *
+ * Now:
+ * % dns-sd -B _test._tcp # will find all three services
+ * % dns-sd -B _test._tcp,HasFeatureA # finds "Better" and "Best"
+ * % dns-sd -B _test._tcp,HasFeatureB # finds only "Best"
+ *
+ * Subtype labels may be up to 63 bytes long, and may contain any eight-
+ * bit byte values, including zero bytes. However, due to the nature of
+ * using a C-string-based API, conventional DNS escaping must be used for
+ * dots ('.'), commas (','), backslashes ('\') and zero bytes, as shown below:
+ *
+ * % dns-sd -R Test '_test._tcp,s\.one,s\,two,s\\three,s\000four' local 123
+ *
+ * domain: If non-NULL, specifies the domain on which to advertise the service.
+ * Most applications will not specify a domain, instead automatically
+ * registering in the default domain(s).
+ *
+ * host: If non-NULL, specifies the SRV target host name. Most applications
+ * will not specify a host, instead automatically using the machine's
+ * default host name(s). Note that specifying a non-NULL host does NOT
+ * create an address record for that host - the application is responsible
+ * for ensuring that the appropriate address record exists, or creating it
+ * via DNSServiceRegisterRecord().
+ *
+ * port: The port, in network byte order, on which the service accepts connections.
+ * Pass 0 for a "placeholder" service (i.e. a service that will not be discovered
+ * by browsing, but will cause a name conflict if another client tries to
+ * register that same name). Most clients will not use placeholder services.
+ *
+ * txtLen: The length of the txtRecord, in bytes. Must be zero if the txtRecord is NULL.
+ *
+ * txtRecord: The TXT record rdata. A non-NULL txtRecord MUST be a properly formatted DNS
+ * TXT record, i.e. <length byte> <data> <length byte> <data> ...
+ * Passing NULL for the txtRecord is allowed as a synonym for txtLen=1, txtRecord="",
+ * i.e. it creates a TXT record of length one containing a single empty string.
+ * RFC 1035 doesn't allow a TXT record to contain *zero* strings, so a single empty
+ * string is the smallest legal DNS TXT record.
+ * As with the other parameters, the DNSServiceRegister call copies the txtRecord
+ * data; e.g. if you allocated the storage for the txtRecord parameter with malloc()
+ * then you can safely free that memory right after the DNSServiceRegister call returns.
+ *
+ * callBack: The function to be called when the registration completes or asynchronously
+ * fails. The client MAY pass NULL for the callback - The client will NOT be notified
+ * of the default values picked on its behalf, and the client will NOT be notified of any
+ * asynchronous errors (e.g. out of memory errors, etc.) that may prevent the registration
+ * of the service. The client may NOT pass the NoAutoRename flag if the callback is NULL.
+ * The client may still deregister the service at any time via DNSServiceRefDeallocate().
+ *
+ * context: An application context pointer which is passed to the callback function
+ * (may be NULL).
+ *
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ * errors are delivered to the callback), otherwise returns an error code indicating
+ * the error that occurred (the callback is never invoked and the DNSServiceRef
+ * is not initialized).
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceRegister
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *name, /* may be NULL */
+ const char *regtype,
+ const char *domain, /* may be NULL */
+ const char *host, /* may be NULL */
+ uint16_t port, /* In network byte order */
+ uint16_t txtLen,
+ const void *txtRecord, /* may be NULL */
+ DNSServiceRegisterReply callBack, /* may be NULL */
+ void *context /* may be NULL */
+);
+
+
+/* DNSServiceAddRecord()
+ *
+ * Add a record to a registered service. The name of the record will be the same as the
+ * registered service's name.
+ * The record can later be updated or deregistered by passing the RecordRef initialized
+ * by this function to DNSServiceUpdateRecord() or DNSServiceRemoveRecord().
+ *
+ * Note that the DNSServiceAddRecord/UpdateRecord/RemoveRecord are *NOT* thread-safe
+ * with respect to a single DNSServiceRef. If you plan to have multiple threads
+ * in your program simultaneously add, update, or remove records from the same
+ * DNSServiceRef, then it's the caller's responsibility to use a mutext lock
+ * or take similar appropriate precautions to serialize those calls.
+ *
+ * Parameters;
+ *
+ * sdRef: A DNSServiceRef initialized by DNSServiceRegister().
+ *
+ * RecordRef: A pointer to an uninitialized DNSRecordRef. Upon succesfull completion of this
+ * call, this ref may be passed to DNSServiceUpdateRecord() or DNSServiceRemoveRecord().
+ * If the above DNSServiceRef is passed to DNSServiceRefDeallocate(), RecordRef is also
+ * invalidated and may not be used further.
+ *
+ * flags: Currently ignored, reserved for future use.
+ *
+ * rrtype: The type of the record (e.g. kDNSServiceType_TXT, kDNSServiceType_SRV, etc)
+ *
+ * rdlen: The length, in bytes, of the rdata.
+ *
+ * rdata: The raw rdata to be contained in the added resource record.
+ *
+ * ttl: The time to live of the resource record, in seconds.
+ * Most clients should pass 0 to indicate that the system should
+ * select a sensible default value.
+ *
+ * return value: Returns kDNSServiceErr_NoError on success, otherwise returns an
+ * error code indicating the error that occurred (the RecordRef is not initialized).
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceAddRecord
+(
+ DNSServiceRef sdRef,
+ DNSRecordRef *RecordRef,
+ DNSServiceFlags flags,
+ uint16_t rrtype,
+ uint16_t rdlen,
+ const void *rdata,
+ uint32_t ttl
+);
+
+
+/* DNSServiceUpdateRecord
+ *
+ * Update a registered resource record. The record must either be:
+ * - The primary txt record of a service registered via DNSServiceRegister()
+ * - A record added to a registered service via DNSServiceAddRecord()
+ * - An individual record registered by DNSServiceRegisterRecord()
+ *
+ * Parameters:
+ *
+ * sdRef: A DNSServiceRef that was initialized by DNSServiceRegister()
+ * or DNSServiceCreateConnection().
+ *
+ * RecordRef: A DNSRecordRef initialized by DNSServiceAddRecord, or NULL to update the
+ * service's primary txt record.
+ *
+ * flags: Currently ignored, reserved for future use.
+ *
+ * rdlen: The length, in bytes, of the new rdata.
+ *
+ * rdata: The new rdata to be contained in the updated resource record.
+ *
+ * ttl: The time to live of the updated resource record, in seconds.
+ * Most clients should pass 0 to indicate that the system should
+ * select a sensible default value.
+ *
+ * return value: Returns kDNSServiceErr_NoError on success, otherwise returns an
+ * error code indicating the error that occurred.
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
+(
+ DNSServiceRef sdRef,
+ DNSRecordRef RecordRef, /* may be NULL */
+ DNSServiceFlags flags,
+ uint16_t rdlen,
+ const void *rdata,
+ uint32_t ttl
+);
+
+
+/* DNSServiceRemoveRecord
+ *
+ * Remove a record previously added to a service record set via DNSServiceAddRecord(), or deregister
+ * an record registered individually via DNSServiceRegisterRecord().
+ *
+ * Parameters:
+ *
+ * sdRef: A DNSServiceRef initialized by DNSServiceRegister() (if the
+ * record being removed was registered via DNSServiceAddRecord()) or by
+ * DNSServiceCreateConnection() (if the record being removed was registered via
+ * DNSServiceRegisterRecord()).
+ *
+ * recordRef: A DNSRecordRef initialized by a successful call to DNSServiceAddRecord()
+ * or DNSServiceRegisterRecord().
+ *
+ * flags: Currently ignored, reserved for future use.
+ *
+ * return value: Returns kDNSServiceErr_NoError on success, otherwise returns an
+ * error code indicating the error that occurred.
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
+(
+ DNSServiceRef sdRef,
+ DNSRecordRef RecordRef,
+ DNSServiceFlags flags
+);
+
+
+/*********************************************************************************************
+*
+* Service Discovery
+*
+*********************************************************************************************/
+
+/* Browse for instances of a service.
+ *
+ * DNSServiceBrowseReply() Parameters:
+ *
+ * sdRef: The DNSServiceRef initialized by DNSServiceBrowse().
+ *
+ * flags: Possible values are kDNSServiceFlagsMoreComing and kDNSServiceFlagsAdd.
+ * See flag definitions for details.
+ *
+ * interfaceIndex: The interface on which the service is advertised. This index should
+ * be passed to DNSServiceResolve() when resolving the service.
+ *
+ * errorCode: Will be kDNSServiceErr_NoError (0) on success, otherwise will
+ * indicate the failure that occurred. Other parameters are undefined if
+ * the errorCode is nonzero.
+ *
+ * serviceName: The discovered service name. This name should be displayed to the user,
+ * and stored for subsequent use in the DNSServiceResolve() call.
+ *
+ * regtype: The service type, which is usually (but not always) the same as was passed
+ * to DNSServiceBrowse(). One case where the discovered service type may
+ * not be the same as the requested service type is when using subtypes:
+ * The client may want to browse for only those ftp servers that allow
+ * anonymous connections. The client will pass the string "_ftp._tcp,_anon"
+ * to DNSServiceBrowse(), but the type of the service that's discovered
+ * is simply "_ftp._tcp". The regtype for each discovered service instance
+ * should be stored along with the name, so that it can be passed to
+ * DNSServiceResolve() when the service is later resolved.
+ *
+ * domain: The domain of the discovered service instance. This may or may not be the
+ * same as the domain that was passed to DNSServiceBrowse(). The domain for each
+ * discovered service instance should be stored along with the name, so that
+ * it can be passed to DNSServiceResolve() when the service is later resolved.
+ *
+ * context: The context pointer that was passed to the callout.
+ *
+ */
+
+typedef void (DNSSD_API *DNSServiceBrowseReply)
+(
+ DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char *serviceName,
+ const char *regtype,
+ const char *replyDomain,
+ void *context
+);
+
+
+/* DNSServiceBrowse() Parameters:
+ *
+ * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
+ * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
+ * and the browse operation will run indefinitely until the client
+ * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ *
+ * flags: Currently ignored, reserved for future use.
+ *
+ * interfaceIndex: If non-zero, specifies the interface on which to browse for services
+ * (the index for a given interface is determined via the if_nametoindex()
+ * family of calls.) Most applications will pass 0 to browse on all available
+ * interfaces. See "Constants for specifying an interface index" for more details.
+ *
+ * regtype: The service type being browsed for followed by the protocol, separated by a
+ * dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
+ * A client may optionally specify a single subtype to perform filtered browsing:
+ * e.g. browsing for "_primarytype._tcp,_subtype" will discover only those
+ * instances of "_primarytype._tcp" that were registered specifying "_subtype"
+ * in their list of registered subtypes.
+ *
+ * domain: If non-NULL, specifies the domain on which to browse for services.
+ * Most applications will not specify a domain, instead browsing on the
+ * default domain(s).
+ *
+ * callBack: The function to be called when an instance of the service being browsed for
+ * is found, or if the call asynchronously fails.
+ *
+ * context: An application context pointer which is passed to the callback function
+ * (may be NULL).
+ *
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ * errors are delivered to the callback), otherwise returns an error code indicating
+ * the error that occurred (the callback is not invoked and the DNSServiceRef
+ * is not initialized).
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceBrowse
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *regtype,
+ const char *domain, /* may be NULL */
+ DNSServiceBrowseReply callBack,
+ void *context /* may be NULL */
+);
+
+
+/* DNSServiceResolve()
+ *
+ * Resolve a service name discovered via DNSServiceBrowse() to a target host name, port number, and
+ * txt record.
+ *
+ * Note: Applications should NOT use DNSServiceResolve() solely for txt record monitoring - use
+ * DNSServiceQueryRecord() instead, as it is more efficient for this task.
+ *
+ * Note: When the desired results have been returned, the client MUST terminate the resolve by calling
+ * DNSServiceRefDeallocate().
+ *
+ * Note: DNSServiceResolve() behaves correctly for typical services that have a single SRV record
+ * and a single TXT record. To resolve non-standard services with multiple SRV or TXT records,
+ * DNSServiceQueryRecord() should be used.
+ *
+ * DNSServiceResolveReply Callback Parameters:
+ *
+ * sdRef: The DNSServiceRef initialized by DNSServiceResolve().
+ *
+ * flags: Possible values: kDNSServiceFlagsMoreComing
+ *
+ * interfaceIndex: The interface on which the service was resolved.
+ *
+ * errorCode: Will be kDNSServiceErr_NoError (0) on success, otherwise will
+ * indicate the failure that occurred. Other parameters are undefined if
+ * the errorCode is nonzero.
+ *
+ * fullname: The full service domain name, in the form <servicename>.<protocol>.<domain>.
+ * (This name is escaped following standard DNS rules, making it suitable for
+ * passing to standard system DNS APIs such as res_query(), or to the
+ * special-purpose functions included in this API that take fullname parameters.
+ * See "Notes on DNS Name Escaping" earlier in this file for more details.)
+ *
+ * hosttarget: The target hostname of the machine providing the service. This name can
+ * be passed to functions like gethostbyname() to identify the host's IP address.
+ *
+ * port: The port, in network byte order, on which connections are accepted for this service.
+ *
+ * txtLen: The length of the txt record, in bytes.
+ *
+ * txtRecord: The service's primary txt record, in standard txt record format.
+ *
+ * context: The context pointer that was passed to the callout.
+ *
+ * NOTE: In earlier versions of this header file, the txtRecord parameter was declared "const char *"
+ * This is incorrect, since it contains length bytes which are values in the range 0 to 255, not -128 to +127.
+ * Depending on your compiler settings, this change may cause signed/unsigned mismatch warnings.
+ * These should be fixed by updating your own callback function definition to match the corrected
+ * function signature using "const unsigned char *txtRecord". Making this change may also fix inadvertent
+ * bugs in your callback function, where it could have incorrectly interpreted a length byte with value 250
+ * as being -6 instead, with various bad consequences ranging from incorrect operation to software crashes.
+ * If you need to maintain portable code that will compile cleanly with both the old and new versions of
+ * this header file, you should update your callback function definition to use the correct unsigned value,
+ * and then in the place where you pass your callback function to DNSServiceResolve(), use a cast to eliminate
+ * the compiler warning, e.g.:
+ * DNSServiceResolve(sd, flags, index, name, regtype, domain, (DNSServiceResolveReply)MyCallback, context);
+ * This will ensure that your code compiles cleanly without warnings (and more importantly, works correctly)
+ * with both the old header and with the new corrected version.
+ *
+ */
+
+typedef void (DNSSD_API *DNSServiceResolveReply)
+(
+ DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char *fullname,
+ const char *hosttarget,
+ uint16_t port, /* In network byte order */
+ uint16_t txtLen,
+ const unsigned char *txtRecord,
+ void *context
+);
+
+
+/* DNSServiceResolve() Parameters
+ *
+ * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
+ * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
+ * and the resolve operation will run indefinitely until the client
+ * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ *
+ * flags: Specifying kDNSServiceFlagsForceMulticast will cause query to be
+ * performed with a link-local mDNS query, even if the name is an
+ * apparently non-local name (i.e. a name not ending in ".local.")
+ *
+ * interfaceIndex: The interface on which to resolve the service. If this resolve call is
+ * as a result of a currently active DNSServiceBrowse() operation, then the
+ * interfaceIndex should be the index reported in the DNSServiceBrowseReply
+ * callback. If this resolve call is using information previously saved
+ * (e.g. in a preference file) for later use, then use interfaceIndex 0, because
+ * the desired service may now be reachable via a different physical interface.
+ * See "Constants for specifying an interface index" for more details.
+ *
+ * name: The name of the service instance to be resolved, as reported to the
+ * DNSServiceBrowseReply() callback.
+ *
+ * regtype: The type of the service instance to be resolved, as reported to the
+ * DNSServiceBrowseReply() callback.
+ *
+ * domain: The domain of the service instance to be resolved, as reported to the
+ * DNSServiceBrowseReply() callback.
+ *
+ * callBack: The function to be called when a result is found, or if the call
+ * asynchronously fails.
+ *
+ * context: An application context pointer which is passed to the callback function
+ * (may be NULL).
+ *
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ * errors are delivered to the callback), otherwise returns an error code indicating
+ * the error that occurred (the callback is never invoked and the DNSServiceRef
+ * is not initialized).
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceResolve
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *name,
+ const char *regtype,
+ const char *domain,
+ DNSServiceResolveReply callBack,
+ void *context /* may be NULL */
+);
+
+
+/*********************************************************************************************
+*
+* Querying Individual Specific Records
+*
+*********************************************************************************************/
+
+/* DNSServiceQueryRecord
+ *
+ * Query for an arbitrary DNS record.
+ *
+ * DNSServiceQueryRecordReply() Callback Parameters:
+ *
+ * sdRef: The DNSServiceRef initialized by DNSServiceQueryRecord().
+ *
+ * flags: Possible values are kDNSServiceFlagsMoreComing and
+ * kDNSServiceFlagsAdd. The Add flag is NOT set for PTR records
+ * with a ttl of 0, i.e. "Remove" events.
+ *
+ * interfaceIndex: The interface on which the query was resolved (the index for a given
+ * interface is determined via the if_nametoindex() family of calls).
+ * See "Constants for specifying an interface index" for more details.
+ *
+ * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will
+ * indicate the failure that occurred. Other parameters are undefined if
+ * errorCode is nonzero.
+ *
+ * fullname: The resource record's full domain name.
+ *
+ * rrtype: The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
+ *
+ * rrclass: The class of the resource record (usually kDNSServiceClass_IN).
+ *
+ * rdlen: The length, in bytes, of the resource record rdata.
+ *
+ * rdata: The raw rdata of the resource record.
+ *
+ * ttl: If the client wishes to cache the result for performance reasons,
+ * the TTL indicates how long the client may legitimately hold onto
+ * this result, in seconds. After the TTL expires, the client should
+ * consider the result no longer valid, and if it requires this data
+ * again, it should be re-fetched with a new query. Of course, this
+ * only applies to clients that cancel the asynchronous operation when
+ * they get a result. Clients that leave the asynchronous operation
+ * running can safely assume that the data remains valid until they
+ * get another callback telling them otherwise.
+ *
+ * context: The context pointer that was passed to the callout.
+ *
+ */
+
+typedef void (DNSSD_API *DNSServiceQueryRecordReply)
+(
+ DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char *fullname,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ uint16_t rdlen,
+ const void *rdata,
+ uint32_t ttl,
+ void *context
+);
+
+
+/* DNSServiceQueryRecord() Parameters:
+ *
+ * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
+ * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
+ * and the query operation will run indefinitely until the client
+ * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ *
+ * flags: kDNSServiceFlagsForceMulticast or kDNSServiceFlagsLongLivedQuery.
+ * Pass kDNSServiceFlagsLongLivedQuery to create a "long-lived" unicast
+ * query to a unicast DNS server that implements the protocol. This flag
+ * has no effect on link-local multicast queries.
+ *
+ * interfaceIndex: If non-zero, specifies the interface on which to issue the query
+ * (the index for a given interface is determined via the if_nametoindex()
+ * family of calls.) Passing 0 causes the name to be queried for on all
+ * interfaces. See "Constants for specifying an interface index" for more details.
+ *
+ * fullname: The full domain name of the resource record to be queried for.
+ *
+ * rrtype: The numerical type of the resource record to be queried for
+ * (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
+ *
+ * rrclass: The class of the resource record (usually kDNSServiceClass_IN).
+ *
+ * callBack: The function to be called when a result is found, or if the call
+ * asynchronously fails.
+ *
+ * context: An application context pointer which is passed to the callback function
+ * (may be NULL).
+ *
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ * errors are delivered to the callback), otherwise returns an error code indicating
+ * the error that occurred (the callback is never invoked and the DNSServiceRef
+ * is not initialized).
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *fullname,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ DNSServiceQueryRecordReply callBack,
+ void *context /* may be NULL */
+);
+
+
+/*********************************************************************************************
+*
+* Unified lookup of both IPv4 and IPv6 addresses for a fully qualified hostname
+*
+*********************************************************************************************/
+
+/* DNSServiceGetAddrInfo
+ *
+ * Queries for the IP address of a hostname by using either Multicast or Unicast DNS.
+ *
+ * DNSServiceGetAddrInfoReply() parameters:
+ *
+ * sdRef: The DNSServiceRef initialized by DNSServiceGetAddrInfo().
+ *
+ * flags: Possible values are kDNSServiceFlagsMoreComing and
+ * kDNSServiceFlagsAdd.
+ *
+ * interfaceIndex: The interface to which the answers pertain.
+ *
+ * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will
+ * indicate the failure that occurred. Other parameters are
+ * undefined if errorCode is nonzero.
+ *
+ * hostname: The fully qualified domain name of the host to be queried for.
+ *
+ * address: IPv4 or IPv6 address.
+ *
+ * ttl: If the client wishes to cache the result for performance reasons,
+ * the TTL indicates how long the client may legitimately hold onto
+ * this result, in seconds. After the TTL expires, the client should
+ * consider the result no longer valid, and if it requires this data
+ * again, it should be re-fetched with a new query. Of course, this
+ * only applies to clients that cancel the asynchronous operation when
+ * they get a result. Clients that leave the asynchronous operation
+ * running can safely assume that the data remains valid until they
+ * get another callback telling them otherwise.
+ *
+ * context: The context pointer that was passed to the callout.
+ *
+ */
+
+typedef void (DNSSD_API *DNSServiceGetAddrInfoReply)
+(
+ DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char *hostname,
+ const struct sockaddr *address,
+ uint32_t ttl,
+ void *context
+);
+
+
+/* DNSServiceGetAddrInfo() Parameters:
+ *
+ * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds then it
+ * initializes the DNSServiceRef, returns kDNSServiceErr_NoError, and the query
+ * begins and will last indefinitely until the client terminates the query
+ * by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ *
+ * flags: kDNSServiceFlagsForceMulticast or kDNSServiceFlagsLongLivedQuery.
+ * Pass kDNSServiceFlagsLongLivedQuery to create a "long-lived" unicast
+ * query to a unicast DNS server that implements the protocol. This flag
+ * has no effect on link-local multicast queries.
+ *
+ * interfaceIndex: The interface on which to issue the query. Passing 0 causes the query to be
+ * sent on all active interfaces via Multicast or the primary interface via Unicast.
+ *
+ * protocol: Pass in kDNSServiceProtocol_IPv4 to look up IPv4 addresses, or kDNSServiceProtocol_IPv6
+ * to look up IPv6 addresses, or both to look up both kinds. If neither flag is
+ * set, the system will apply an intelligent heuristic, which is (currently)
+ * that it will attempt to look up both, except:
+ *
+ * * If "hostname" is a wide-area unicast DNS hostname (i.e. not a ".local." name)
+ * but this host has no routable IPv6 address, then the call will not try to
+ * look up IPv6 addresses for "hostname", since any addresses it found would be
+ * unlikely to be of any use anyway. Similarly, if this host has no routable
+ * IPv4 address, the call will not try to look up IPv4 addresses for "hostname".
+ *
+ * hostname: The fully qualified domain name of the host to be queried for.
+ *
+ * callBack: The function to be called when the query succeeds or fails asynchronously.
+ *
+ * context: An application context pointer which is passed to the callback function
+ * (may be NULL).
+ *
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ * errors are delivered to the callback), otherwise returns an error code indicating
+ * the error that occurred.
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceProtocol protocol,
+ const char *hostname,
+ DNSServiceGetAddrInfoReply callBack,
+ void *context /* may be NULL */
+);
+
+
+/*********************************************************************************************
+*
+* Special Purpose Calls:
+* DNSServiceCreateConnection(), DNSServiceRegisterRecord(), DNSServiceReconfirmRecord()
+* (most applications will not use these)
+*
+*********************************************************************************************/
+
+/* DNSServiceCreateConnection()
+ *
+ * Create a connection to the daemon allowing efficient registration of
+ * multiple individual records.
+ *
+ * Parameters:
+ *
+ * sdRef: A pointer to an uninitialized DNSServiceRef. Deallocating
+ * the reference (via DNSServiceRefDeallocate()) severs the
+ * connection and deregisters all records registered on this connection.
+ *
+ * return value: Returns kDNSServiceErr_NoError on success, otherwise returns
+ * an error code indicating the specific failure that occurred (in which
+ * case the DNSServiceRef is not initialized).
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef);
+
+
+/* DNSServiceRegisterRecord
+ *
+ * Register an individual resource record on a connected DNSServiceRef.
+ *
+ * Note that name conflicts occurring for records registered via this call must be handled
+ * by the client in the callback.
+ *
+ * DNSServiceRegisterRecordReply() parameters:
+ *
+ * sdRef: The connected DNSServiceRef initialized by
+ * DNSServiceCreateConnection().
+ *
+ * RecordRef: The DNSRecordRef initialized by DNSServiceRegisterRecord(). If the above
+ * DNSServiceRef is passed to DNSServiceRefDeallocate(), this DNSRecordRef is
+ * invalidated, and may not be used further.
+ *
+ * flags: Currently unused, reserved for future use.
+ *
+ * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will
+ * indicate the failure that occurred (including name conflicts.)
+ * Other parameters are undefined if errorCode is nonzero.
+ *
+ * context: The context pointer that was passed to the callout.
+ *
+ */
+
+typedef void (DNSSD_API *DNSServiceRegisterRecordReply)
+(
+ DNSServiceRef sdRef,
+ DNSRecordRef RecordRef,
+ DNSServiceFlags flags,
+ DNSServiceErrorType errorCode,
+ void *context
+);
+
+
+/* DNSServiceRegisterRecord() Parameters:
+ *
+ * sdRef: A DNSServiceRef initialized by DNSServiceCreateConnection().
+ *
+ * RecordRef: A pointer to an uninitialized DNSRecordRef. Upon succesfull completion of this
+ * call, this ref may be passed to DNSServiceUpdateRecord() or DNSServiceRemoveRecord().
+ * (To deregister ALL records registered on a single connected DNSServiceRef
+ * and deallocate each of their corresponding DNSServiceRecordRefs, call
+ * DNSServiceRefDeallocate()).
+ *
+ * flags: Possible values are kDNSServiceFlagsShared or kDNSServiceFlagsUnique
+ * (see flag type definitions for details).
+ *
+ * interfaceIndex: If non-zero, specifies the interface on which to register the record
+ * (the index for a given interface is determined via the if_nametoindex()
+ * family of calls.) Passing 0 causes the record to be registered on all interfaces.
+ * See "Constants for specifying an interface index" for more details.
+ *
+ * fullname: The full domain name of the resource record.
+ *
+ * rrtype: The numerical type of the resource record (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
+ *
+ * rrclass: The class of the resource record (usually kDNSServiceClass_IN)
+ *
+ * rdlen: Length, in bytes, of the rdata.
+ *
+ * rdata: A pointer to the raw rdata, as it is to appear in the DNS record.
+ *
+ * ttl: The time to live of the resource record, in seconds.
+ * Most clients should pass 0 to indicate that the system should
+ * select a sensible default value.
+ *
+ * callBack: The function to be called when a result is found, or if the call
+ * asynchronously fails (e.g. because of a name conflict.)
+ *
+ * context: An application context pointer which is passed to the callback function
+ * (may be NULL).
+ *
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ * errors are delivered to the callback), otherwise returns an error code indicating
+ * the error that occurred (the callback is never invoked and the DNSRecordRef is
+ * not initialized).
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
+(
+ DNSServiceRef sdRef,
+ DNSRecordRef *RecordRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *fullname,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ uint16_t rdlen,
+ const void *rdata,
+ uint32_t ttl,
+ DNSServiceRegisterRecordReply callBack,
+ void *context /* may be NULL */
+);
+
+
+/* DNSServiceReconfirmRecord
+ *
+ * Instruct the daemon to verify the validity of a resource record that appears
+ * to be out of date (e.g. because TCP connection to a service's target failed.)
+ * Causes the record to be flushed from the daemon's cache (as well as all other
+ * daemons' caches on the network) if the record is determined to be invalid.
+ * Use this routine conservatively. Reconfirming a record necessarily consumes
+ * network bandwidth, so this should not be done indiscriminately.
+ *
+ * Parameters:
+ *
+ * flags: Pass kDNSServiceFlagsForce to force immediate deletion of record,
+ * instead of after some number of reconfirmation queries have gone unanswered.
+ *
+ * interfaceIndex: Specifies the interface of the record in question.
+ * The caller must specify the interface.
+ * This API (by design) causes increased network traffic, so it requires
+ * the caller to be precise about which record should be reconfirmed.
+ * It is not possible to pass zero for the interface index to perform
+ * a "wildcard" reconfirmation, where *all* matching records are reconfirmed.
+ *
+ * fullname: The resource record's full domain name.
+ *
+ * rrtype: The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
+ *
+ * rrclass: The class of the resource record (usually kDNSServiceClass_IN).
+ *
+ * rdlen: The length, in bytes, of the resource record rdata.
+ *
+ * rdata: The raw rdata of the resource record.
+ *
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
+(
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *fullname,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ uint16_t rdlen,
+ const void *rdata
+);
+
+/*********************************************************************************************
+*
+* NAT Port Mapping
+*
+*********************************************************************************************/
+
+/* DNSServiceNATPortMappingCreate
+ *
+ * Request a port mapping in the NAT gateway, which maps a port on the local machine
+ * to an external port on the NAT. The NAT should support either the NAT-PMP or the UPnP IGD
+ * protocol for this API to create a successful mapping.
+ *
+ * The port mapping will be renewed indefinitely until the client process exits, or
+ * explicitly terminates the port mapping request by calling DNSServiceRefDeallocate().
+ * The client callback will be invoked, informing the client of the NAT gateway's
+ * external IP address and the external port that has been allocated for this client.
+ * The client should then record this external IP address and port using whatever
+ * directory service mechanism it is using to enable peers to connect to it.
+ * (Clients advertising services using Wide-Area DNS-SD DO NOT need to use this API
+ * -- when a client calls DNSServiceRegister() NAT mappings are automatically created
+ * and the external IP address and port for the service are recorded in the global DNS.
+ * Only clients using some directory mechanism other than Wide-Area DNS-SD need to use
+ * this API to explicitly map their own ports.)
+ *
+ * It's possible that the client callback could be called multiple times, for example
+ * if the NAT gateway's IP address changes, or if a configuration change results in a
+ * different external port being mapped for this client. Over the lifetime of any long-lived
+ * port mapping, the client should be prepared to handle these notifications of changes
+ * in the environment, and should update its recorded address and/or port as appropriate.
+ *
+ * NOTE: There are two unusual aspects of how the DNSServiceNATPortMappingCreate API works,
+ * which were intentionally designed to help simplify client code:
+ *
+ * 1. It's not an error to request a NAT mapping when the machine is not behind a NAT gateway.
+ * In other NAT mapping APIs, if you request a NAT mapping and the machine is not behind a NAT
+ * gateway, then the API returns an error code -- it can't get you a NAT mapping if there's no
+ * NAT gateway. The DNSServiceNATPortMappingCreate API takes a different view. Working out
+ * whether or not you need a NAT mapping can be tricky and non-obvious, particularly on
+ * a machine with multiple active network interfaces. Rather than make every client recreate
+ * this logic for deciding whether a NAT mapping is required, the PortMapping API does that
+ * work for you. If the client calls the PortMapping API when the machine already has a
+ * routable public IP address, then instead of complaining about it and giving an error,
+ * the PortMapping API just invokes your callback, giving the machine's public address
+ * and your own port number. This means you don't need to write code to work out whether
+ * your client needs to call the PortMapping API -- just call it anyway, and if it wasn't
+ * necessary, no harm is done:
+ *
+ * - If the machine already has a routable public IP address, then your callback
+ * will just be invoked giving your own address and port.
+ * - If a NAT mapping is required and obtained, then your callback will be invoked
+ * giving you the external address and port.
+ * - If a NAT mapping is required but not obtained from the local NAT gateway,
+ * or the machine has no network connectivity, then your callback will be
+ * invoked giving zero address and port.
+ *
+ * 2. In other NAT mapping APIs, if a laptop computer is put to sleep and woken up on a new
+ * network, it's the client's job to notice this, and work out whether a NAT mapping
+ * is required on the new network, and make a new NAT mapping request if necessary.
+ * The DNSServiceNATPortMappingCreate API does this for you, automatically.
+ * The client just needs to make one call to the PortMapping API, and its callback will
+ * be invoked any time the mapping state changes. This property complements point (1) above.
+ * If the client didn't make a NAT mapping request just because it determined that one was
+ * not required at that particular moment in time, the client would then have to monitor
+ * for network state changes to determine if a NAT port mapping later became necessary.
+ * By unconditionally making a NAT mapping request, even when a NAT mapping not to be
+ * necessary, the PortMapping API will then begin monitoring network state changes on behalf of
+ * the client, and if a NAT mapping later becomes necessary, it will automatically create a NAT
+ * mapping and inform the client with a new callback giving the new address and port information.
+ *
+ * DNSServiceNATPortMappingReply() parameters:
+ *
+ * sdRef: The DNSServiceRef initialized by DNSServiceNATPortMappingCreate().
+ *
+ * flags: Currently unused, reserved for future use.
+ *
+ * interfaceIndex: The interface through which the NAT gateway is reached.
+ *
+ * errorCode: Will be kDNSServiceErr_NoError on success.
+ * Will be kDNSServiceErr_DoubleNAT when the NAT gateway is itself behind one or
+ * more layers of NAT, in which case the other parameters have the defined values.
+ * For other failures, will indicate the failure that occurred, and the other
+ * parameters are undefined.
+ *
+ * externalAddress: Four byte IPv4 address in network byte order.
+ *
+ * protocol: Will be kDNSServiceProtocol_UDP or kDNSServiceProtocol_TCP or both.
+ *
+ * internalPort: The port on the local machine that was mapped.
+ *
+ * externalPort: The actual external port in the NAT gateway that was mapped.
+ * This is likely to be different than the requested external port.
+ *
+ * ttl: The lifetime of the NAT port mapping created on the gateway.
+ * This controls how quickly stale mappings will be garbage-collected
+ * if the client machine crashes, suffers a power failure, is disconnected
+ * from the network, or suffers some other unfortunate demise which
+ * causes it to vanish without explicitly removing its NAT port mapping.
+ * It's possible that the ttl value will differ from the requested ttl value.
+ *
+ * context: The context pointer that was passed to the callout.
+ *
+ */
+
+typedef void (DNSSD_API *DNSServiceNATPortMappingReply)
+(
+ DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ uint32_t externalAddress, /* four byte IPv4 address in network byte order */
+ DNSServiceProtocol protocol,
+ uint16_t internalPort, /* In network byte order */
+ uint16_t externalPort, /* In network byte order and may be different than the requested port */
+ uint32_t ttl, /* may be different than the requested ttl */
+ void *context
+);
+
+
+/* DNSServiceNATPortMappingCreate() Parameters:
+ *
+ * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds then it
+ * initializes the DNSServiceRef, returns kDNSServiceErr_NoError, and the nat
+ * port mapping will last indefinitely until the client terminates the port
+ * mapping request by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ *
+ * flags: Currently ignored, reserved for future use.
+ *
+ * interfaceIndex: The interface on which to create port mappings in a NAT gateway. Passing 0 causes
+ * the port mapping request to be sent on the primary interface.
+ *
+ * protocol: To request a port mapping, pass in kDNSServiceProtocol_UDP, or kDNSServiceProtocol_TCP,
+ * or (kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP) to map both.
+ * The local listening port number must also be specified in the internalPort parameter.
+ * To just discover the NAT gateway's external IP address, pass zero for protocol,
+ * internalPort, externalPort and ttl.
+ *
+ * internalPort: The port number in network byte order on the local machine which is listening for packets.
+ *
+ * externalPort: The requested external port in network byte order in the NAT gateway that you would
+ * like to map to the internal port. Pass 0 if you don't care which external port is chosen for you.
+ *
+ * ttl: The requested renewal period of the NAT port mapping, in seconds.
+ * If the client machine crashes, suffers a power failure, is disconnected from
+ * the network, or suffers some other unfortunate demise which causes it to vanish
+ * unexpectedly without explicitly removing its NAT port mappings, then the NAT gateway
+ * will garbage-collect old stale NAT port mappings when their lifetime expires.
+ * Requesting a short TTL causes such orphaned mappings to be garbage-collected
+ * more promptly, but consumes system resources and network bandwidth with
+ * frequent renewal packets to keep the mapping from expiring.
+ * Requesting a long TTL is more efficient on the network, but in the event of the
+ * client vanishing, stale NAT port mappings will not be garbage-collected as quickly.
+ * Most clients should pass 0 to use a system-wide default value.
+ *
+ * callBack: The function to be called when the port mapping request succeeds or fails asynchronously.
+ *
+ * context: An application context pointer which is passed to the callback function
+ * (may be NULL).
+ *
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ * errors are delivered to the callback), otherwise returns an error code indicating
+ * the error that occurred.
+ *
+ * If you don't actually want a port mapped, and are just calling the API
+ * because you want to find out the NAT's external IP address (e.g. for UI
+ * display) then pass zero for protocol, internalPort, externalPort and ttl.
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceProtocol protocol, /* TCP and/or UDP */
+ uint16_t internalPort, /* network byte order */
+ uint16_t externalPort, /* network byte order */
+ uint32_t ttl, /* time to live in seconds */
+ DNSServiceNATPortMappingReply callBack,
+ void *context /* may be NULL */
+);
+
+
+/*********************************************************************************************
+*
+* General Utility Functions
+*
+*********************************************************************************************/
+
+/* DNSServiceConstructFullName()
+ *
+ * Concatenate a three-part domain name (as returned by the above callbacks) into a
+ * properly-escaped full domain name. Note that callbacks in the above functions ALREADY ESCAPE
+ * strings where necessary.
+ *
+ * Parameters:
+ *
+ * fullName: A pointer to a buffer that where the resulting full domain name is to be written.
+ * The buffer must be kDNSServiceMaxDomainName (1009) bytes in length to
+ * accommodate the longest legal domain name without buffer overrun.
+ *
+ * service: The service name - any dots or backslashes must NOT be escaped.
+ * May be NULL (to construct a PTR record name, e.g.
+ * "_ftp._tcp.apple.com.").
+ *
+ * regtype: The service type followed by the protocol, separated by a dot
+ * (e.g. "_ftp._tcp").
+ *
+ * domain: The domain name, e.g. "apple.com.". Literal dots or backslashes,
+ * if any, must be escaped, e.g. "1st\. Floor.apple.com."
+ *
+ * return value: Returns kDNSServiceErr_NoError (0) on success, kDNSServiceErr_BadParam on error.
+ *
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceConstructFullName
+(
+ char * const fullName,
+ const char * const service, /* may be NULL */
+ const char * const regtype,
+ const char * const domain
+);
+
+
+/*********************************************************************************************
+*
+* TXT Record Construction Functions
+*
+*********************************************************************************************/
+
+/*
+ * A typical calling sequence for TXT record construction is something like:
+ *
+ * Client allocates storage for TXTRecord data (e.g. declare buffer on the stack)
+ * TXTRecordCreate();
+ * TXTRecordSetValue();
+ * TXTRecordSetValue();
+ * TXTRecordSetValue();
+ * ...
+ * DNSServiceRegister( ... TXTRecordGetLength(), TXTRecordGetBytesPtr() ... );
+ * TXTRecordDeallocate();
+ * Explicitly deallocate storage for TXTRecord data (if not allocated on the stack)
+ */
+
+
+/* TXTRecordRef
+ *
+ * Opaque internal data type.
+ * Note: Represents a DNS-SD TXT record.
+ */
+
+typedef union _TXTRecordRef_t { char PrivateData[16]; char *ForceNaturalAlignment; } TXTRecordRef;
+
+
+/* TXTRecordCreate()
+ *
+ * Creates a new empty TXTRecordRef referencing the specified storage.
+ *
+ * If the buffer parameter is NULL, or the specified storage size is not
+ * large enough to hold a key subsequently added using TXTRecordSetValue(),
+ * then additional memory will be added as needed using malloc().
+ *
+ * On some platforms, when memory is low, malloc() may fail. In this
+ * case, TXTRecordSetValue() will return kDNSServiceErr_NoMemory, and this
+ * error condition will need to be handled as appropriate by the caller.
+ *
+ * You can avoid the need to handle this error condition if you ensure
+ * that the storage you initially provide is large enough to hold all
+ * the key/value pairs that are to be added to the record.
+ * The caller can precompute the exact length required for all of the
+ * key/value pairs to be added, or simply provide a fixed-sized buffer
+ * known in advance to be large enough.
+ * A no-value (key-only) key requires (1 + key length) bytes.
+ * A key with empty value requires (1 + key length + 1) bytes.
+ * A key with non-empty value requires (1 + key length + 1 + value length).
+ * For most applications, DNS-SD TXT records are generally
+ * less than 100 bytes, so in most cases a simple fixed-sized
+ * 256-byte buffer will be more than sufficient.
+ * Recommended size limits for DNS-SD TXT Records are discussed in
+ * <http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt>
+ *
+ * Note: When passing parameters to and from these TXT record APIs,
+ * the key name does not include the '=' character. The '=' character
+ * is the separator between the key and value in the on-the-wire
+ * packet format; it is not part of either the key or the value.
+ *
+ * txtRecord: A pointer to an uninitialized TXTRecordRef.
+ *
+ * bufferLen: The size of the storage provided in the "buffer" parameter.
+ *
+ * buffer: Optional caller-supplied storage used to hold the TXTRecord data.
+ * This storage must remain valid for as long as
+ * the TXTRecordRef.
+ */
+
+void DNSSD_API TXTRecordCreate
+(
+ TXTRecordRef *txtRecord,
+ uint16_t bufferLen,
+ void *buffer
+);
+
+
+/* TXTRecordDeallocate()
+ *
+ * Releases any resources allocated in the course of preparing a TXT Record
+ * using TXTRecordCreate()/TXTRecordSetValue()/TXTRecordRemoveValue().
+ * Ownership of the buffer provided in TXTRecordCreate() returns to the client.
+ *
+ * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate().
+ *
+ */
+
+void DNSSD_API TXTRecordDeallocate
+(
+ TXTRecordRef *txtRecord
+);
+
+
+/* TXTRecordSetValue()
+ *
+ * Adds a key (optionally with value) to a TXTRecordRef. If the "key" already
+ * exists in the TXTRecordRef, then the current value will be replaced with
+ * the new value.
+ * Keys may exist in four states with respect to a given TXT record:
+ * - Absent (key does not appear at all)
+ * - Present with no value ("key" appears alone)
+ * - Present with empty value ("key=" appears in TXT record)
+ * - Present with non-empty value ("key=value" appears in TXT record)
+ * For more details refer to "Data Syntax for DNS-SD TXT Records" in
+ * <http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt>
+ *
+ * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate().
+ *
+ * key: A null-terminated string which only contains printable ASCII
+ * values (0x20-0x7E), excluding '=' (0x3D). Keys should be
+ * 9 characters or fewer (not counting the terminating null).
+ *
+ * valueSize: The size of the value.
+ *
+ * value: Any binary value. For values that represent
+ * textual data, UTF-8 is STRONGLY recommended.
+ * For values that represent textual data, valueSize
+ * should NOT include the terminating null (if any)
+ * at the end of the string.
+ * If NULL, then "key" will be added with no value.
+ * If non-NULL but valueSize is zero, then "key=" will be
+ * added with empty value.
+ *
+ * return value: Returns kDNSServiceErr_NoError on success.
+ * Returns kDNSServiceErr_Invalid if the "key" string contains
+ * illegal characters.
+ * Returns kDNSServiceErr_NoMemory if adding this key would
+ * exceed the available storage.
+ */
+
+DNSServiceErrorType DNSSD_API TXTRecordSetValue
+(
+ TXTRecordRef *txtRecord,
+ const char *key,
+ uint8_t valueSize, /* may be zero */
+ const void *value /* may be NULL */
+);
+
+
+/* TXTRecordRemoveValue()
+ *
+ * Removes a key from a TXTRecordRef. The "key" must be an
+ * ASCII string which exists in the TXTRecordRef.
+ *
+ * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate().
+ *
+ * key: A key name which exists in the TXTRecordRef.
+ *
+ * return value: Returns kDNSServiceErr_NoError on success.
+ * Returns kDNSServiceErr_NoSuchKey if the "key" does not
+ * exist in the TXTRecordRef.
+ */
+
+DNSServiceErrorType DNSSD_API TXTRecordRemoveValue
+(
+ TXTRecordRef *txtRecord,
+ const char *key
+);
+
+
+/* TXTRecordGetLength()
+ *
+ * Allows you to determine the length of the raw bytes within a TXTRecordRef.
+ *
+ * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate().
+ *
+ * return value: Returns the size of the raw bytes inside a TXTRecordRef
+ * which you can pass directly to DNSServiceRegister() or
+ * to DNSServiceUpdateRecord().
+ * Returns 0 if the TXTRecordRef is empty.
+ */
+
+uint16_t DNSSD_API TXTRecordGetLength
+(
+ const TXTRecordRef *txtRecord
+);
+
+
+/* TXTRecordGetBytesPtr()
+ *
+ * Allows you to retrieve a pointer to the raw bytes within a TXTRecordRef.
+ *
+ * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate().
+ *
+ * return value: Returns a pointer to the raw bytes inside the TXTRecordRef
+ * which you can pass directly to DNSServiceRegister() or
+ * to DNSServiceUpdateRecord().
+ */
+
+const void * DNSSD_API TXTRecordGetBytesPtr
+(
+ const TXTRecordRef *txtRecord
+);
+
+
+/*********************************************************************************************
+*
+* TXT Record Parsing Functions
+*
+*********************************************************************************************/
+
+/*
+ * A typical calling sequence for TXT record parsing is something like:
+ *
+ * Receive TXT record data in DNSServiceResolve() callback
+ * if (TXTRecordContainsKey(txtLen, txtRecord, "key")) then do something
+ * val1ptr = TXTRecordGetValuePtr(txtLen, txtRecord, "key1", &len1);
+ * val2ptr = TXTRecordGetValuePtr(txtLen, txtRecord, "key2", &len2);
+ * ...
+ * memcpy(myval1, val1ptr, len1);
+ * memcpy(myval2, val2ptr, len2);
+ * ...
+ * return;
+ *
+ * If you wish to retain the values after return from the DNSServiceResolve()
+ * callback, then you need to copy the data to your own storage using memcpy()
+ * or similar, as shown in the example above.
+ *
+ * If for some reason you need to parse a TXT record you built yourself
+ * using the TXT record construction functions above, then you can do
+ * that using TXTRecordGetLength and TXTRecordGetBytesPtr calls:
+ * TXTRecordGetValue(TXTRecordGetLength(x), TXTRecordGetBytesPtr(x), key, &len);
+ *
+ * Most applications only fetch keys they know about from a TXT record and
+ * ignore the rest.
+ * However, some debugging tools wish to fetch and display all keys.
+ * To do that, use the TXTRecordGetCount() and TXTRecordGetItemAtIndex() calls.
+ */
+
+/* TXTRecordContainsKey()
+ *
+ * Allows you to determine if a given TXT Record contains a specified key.
+ *
+ * txtLen: The size of the received TXT Record.
+ *
+ * txtRecord: Pointer to the received TXT Record bytes.
+ *
+ * key: A null-terminated ASCII string containing the key name.
+ *
+ * return value: Returns 1 if the TXT Record contains the specified key.
+ * Otherwise, it returns 0.
+ */
+
+int DNSSD_API TXTRecordContainsKey
+(
+ uint16_t txtLen,
+ const void *txtRecord,
+ const char *key
+);
+
+
+/* TXTRecordGetValuePtr()
+ *
+ * Allows you to retrieve the value for a given key from a TXT Record.
+ *
+ * txtLen: The size of the received TXT Record
+ *
+ * txtRecord: Pointer to the received TXT Record bytes.
+ *
+ * key: A null-terminated ASCII string containing the key name.
+ *
+ * valueLen: On output, will be set to the size of the "value" data.
+ *
+ * return value: Returns NULL if the key does not exist in this TXT record,
+ * or exists with no value (to differentiate between
+ * these two cases use TXTRecordContainsKey()).
+ * Returns pointer to location within TXT Record bytes
+ * if the key exists with empty or non-empty value.
+ * For empty value, valueLen will be zero.
+ * For non-empty value, valueLen will be length of value data.
+ */
+
+const void * DNSSD_API TXTRecordGetValuePtr
+(
+ uint16_t txtLen,
+ const void *txtRecord,
+ const char *key,
+ uint8_t *valueLen
+);
+
+
+/* TXTRecordGetCount()
+ *
+ * Returns the number of keys stored in the TXT Record. The count
+ * can be used with TXTRecordGetItemAtIndex() to iterate through the keys.
+ *
+ * txtLen: The size of the received TXT Record.
+ *
+ * txtRecord: Pointer to the received TXT Record bytes.
+ *
+ * return value: Returns the total number of keys in the TXT Record.
+ *
+ */
+
+uint16_t DNSSD_API TXTRecordGetCount
+(
+ uint16_t txtLen,
+ const void *txtRecord
+);
+
+
+/* TXTRecordGetItemAtIndex()
+ *
+ * Allows you to retrieve a key name and value pointer, given an index into
+ * a TXT Record. Legal index values range from zero to TXTRecordGetCount()-1.
+ * It's also possible to iterate through keys in a TXT record by simply
+ * calling TXTRecordGetItemAtIndex() repeatedly, beginning with index zero
+ * and increasing until TXTRecordGetItemAtIndex() returns kDNSServiceErr_Invalid.
+ *
+ * On return:
+ * For keys with no value, *value is set to NULL and *valueLen is zero.
+ * For keys with empty value, *value is non-NULL and *valueLen is zero.
+ * For keys with non-empty value, *value is non-NULL and *valueLen is non-zero.
+ *
+ * txtLen: The size of the received TXT Record.
+ *
+ * txtRecord: Pointer to the received TXT Record bytes.
+ *
+ * itemIndex: An index into the TXT Record.
+ *
+ * keyBufLen: The size of the string buffer being supplied.
+ *
+ * key: A string buffer used to store the key name.
+ * On return, the buffer contains a null-terminated C string
+ * giving the key name. DNS-SD TXT keys are usually
+ * 9 characters or fewer. To hold the maximum possible
+ * key name, the buffer should be 256 bytes long.
+ *
+ * valueLen: On output, will be set to the size of the "value" data.
+ *
+ * value: On output, *value is set to point to location within TXT
+ * Record bytes that holds the value data.
+ *
+ * return value: Returns kDNSServiceErr_NoError on success.
+ * Returns kDNSServiceErr_NoMemory if keyBufLen is too short.
+ * Returns kDNSServiceErr_Invalid if index is greater than
+ * TXTRecordGetCount()-1.
+ */
+
+DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex
+(
+ uint16_t txtLen,
+ const void *txtRecord,
+ uint16_t itemIndex,
+ uint16_t keyBufLen,
+ char *key,
+ uint8_t *valueLen,
+ const void **value
+);
+
+#if _DNS_SD_LIBDISPATCH
+/*
+ * DNSServiceSetDispatchQueue
+ *
+ * Allows you to schedule a DNSServiceRef on a serial dispatch queue for receiving asynchronous
+ * callbacks. It's the clients responsibility to ensure that the provided dispatch queue is running.
+ *
+ * A typical application that uses CFRunLoopRun or dispatch_main on its main thread will
+ * usually schedule DNSServiceRefs on its main queue (which is always a serial queue)
+ * using "DNSServiceSetDispatchQueue(sdref, dispatch_get_main_queue());"
+ *
+ * If there is any error during the processing of events, the application callback will
+ * be called with an error code. For shared connections, each subordinate DNSServiceRef
+ * will get its own error callback. Currently these error callbacks only happen
+ * if the mDNSResponder daemon is manually terminated or crashes, and the error
+ * code in this case is kDNSServiceErr_ServiceNotRunning. The application must call
+ * DNSServiceRefDeallocate to free the DNSServiceRef when it gets such an error code.
+ * These error callbacks are rare and should not normally happen on customer machines,
+ * but application code should be written defensively to handle such error callbacks
+ * gracefully if they occur.
+ *
+ * After using DNSServiceSetDispatchQueue on a DNSServiceRef, calling DNSServiceProcessResult
+ * on the same DNSServiceRef will result in undefined behavior and should be avoided.
+ *
+ * Once the application successfully schedules a DNSServiceRef on a serial dispatch queue using
+ * DNSServiceSetDispatchQueue, it cannot remove the DNSServiceRef from the dispatch queue, or use
+ * DNSServiceSetDispatchQueue a second time to schedule the DNSServiceRef onto a different serial dispatch
+ * queue. Once scheduled onto a dispatch queue a DNSServiceRef will deliver events to that queue until
+ * the application no longer requires that operation and terminates it using DNSServiceRefDeallocate.
+ *
+ * service: DNSServiceRef that was allocated and returned to the application, when the
+ * application calls one of the DNSService API.
+ *
+ * queue: dispatch queue where the application callback will be scheduled
+ *
+ * return value: Returns kDNSServiceErr_NoError on success.
+ * Returns kDNSServiceErr_NoMemory if it cannot create a dispatch source
+ * Returns kDNSServiceErr_BadParam if the service param is invalid or the
+ * queue param is invalid
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue
+(
+ DNSServiceRef service,
+ dispatch_queue_t queue
+);
+#endif //_DNS_SD_LIBDISPATCH
+
+#if !defined(_WIN32)
+typedef void (DNSSD_API *DNSServiceSleepKeepaliveReply)
+(
+ DNSServiceRef sdRef,
+ DNSServiceErrorType errorCode,
+ void *context
+);
+DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ int fd,
+ unsigned int timeout,
+ DNSServiceSleepKeepaliveReply callBack,
+ void *context
+);
+#endif
+
+#ifdef __APPLE_API_PRIVATE
+
+#define kDNSServiceCompPrivateDNS "PrivateDNS"
+#define kDNSServiceCompMulticastDNS "MulticastDNS"
+
+#endif //__APPLE_API_PRIVATE
+
+/* Some C compiler cleverness. We can make the compiler check certain things for us,
+ * and report errors at compile-time if anything is wrong. The usual way to do this would
+ * be to use a run-time "if" statement or the conventional run-time "assert" mechanism, but
+ * then you don't find out what's wrong until you run the software. This way, if the assertion
+ * condition is false, the array size is negative, and the complier complains immediately.
+ */
+
+struct CompileTimeAssertionChecks_DNS_SD
+{
+ char assert0[(sizeof(union _TXTRecordRef_t) == 16) ? 1 : -1];
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DNS_SD_H */
diff --git a/sd/source/ui/remotecontrol/mDNSResponder/dnssd_clientlib.c b/sd/source/ui/remotecontrol/mDNSResponder/dnssd_clientlib.c
new file mode 100755
index 000000000000..cca58853338c
--- /dev/null
+++ b/sd/source/ui/remotecontrol/mDNSResponder/dnssd_clientlib.c
@@ -0,0 +1,366 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "dns_sd.h"
+
+#if MDNS_BUILDINGSHAREDLIBRARY || MDNS_BUILDINGSTUBLIBRARY
+#pragma export on
+#endif
+
+#if defined(_WIN32)
+// disable warning "conversion from <data> to uint16_t"
+#pragma warning(disable:4244)
+#define strncasecmp _strnicmp
+#define strcasecmp _stricmp
+#endif
+
+/*********************************************************************************************
+*
+* Supporting Functions
+*
+*********************************************************************************************/
+
+#define mDNSIsDigit(X) ((X) >= '0' && (X) <= '9')
+
+// DomainEndsInDot returns 1 if name ends with a dot, 0 otherwise
+// (DNSServiceConstructFullName depends this returning 1 for true, rather than any non-zero value meaning true)
+
+static int DomainEndsInDot(const char *dom)
+{
+ while (dom[0] && dom[1])
+ {
+ if (dom[0] == '\\') // advance past escaped byte sequence
+ {
+ if (mDNSIsDigit(dom[1]) && mDNSIsDigit(dom[2]) && mDNSIsDigit(dom[3]))
+ dom += 4; // If "\ddd" then skip four
+ else dom += 2; // else if "\x" then skip two
+ }
+ else dom++; // else goto next character
+ }
+ return (dom[0] == '.');
+}
+
+static uint8_t *InternalTXTRecordSearch
+(
+ uint16_t txtLen,
+ const void *txtRecord,
+ const char *key,
+ unsigned long *keylen
+)
+{
+ uint8_t *p = (uint8_t*)txtRecord;
+ uint8_t *e = p + txtLen;
+ *keylen = (unsigned long) strlen(key);
+ while (p<e)
+ {
+ uint8_t *x = p;
+ p += 1 + p[0];
+ if (p <= e && *keylen <= x[0] && !strncasecmp(key, (char*)x+1, *keylen))
+ if (*keylen == x[0] || x[1+*keylen] == '=') return(x);
+ }
+ return(NULL);
+}
+
+/*********************************************************************************************
+*
+* General Utility Functions
+*
+*********************************************************************************************/
+
+// Note: Need to make sure we don't write more than kDNSServiceMaxDomainName (1009) bytes to fullName
+// In earlier builds this constant was defined to be 1005, so to avoid buffer overruns on clients
+// compiled with that constant we'll actually limit the output to 1005 bytes.
+
+DNSServiceErrorType DNSSD_API DNSServiceConstructFullName
+(
+ char *const fullName,
+ const char *const service, // May be NULL
+ const char *const regtype,
+ const char *const domain
+)
+{
+ const size_t len = !regtype ? 0 : strlen(regtype) - DomainEndsInDot(regtype);
+ char *fn = fullName;
+ char *const lim = fullName + 1005;
+ const char *s = service;
+ const char *r = regtype;
+ const char *d = domain;
+
+ // regtype must be at least "x._udp" or "x._tcp"
+ if (len < 6 || !domain || !domain[0]) return kDNSServiceErr_BadParam;
+ if (strncasecmp((regtype + len - 4), "_tcp", 4) && strncasecmp((regtype + len - 4), "_udp", 4)) return kDNSServiceErr_BadParam;
+
+ if (service && *service)
+ {
+ while (*s)
+ {
+ unsigned char c = *s++; // Needs to be unsigned, or values like 0xFF will be interpreted as < 32
+ if (c <= ' ') // Escape non-printable characters
+ {
+ if (fn+4 >= lim) goto fail;
+ *fn++ = '\\';
+ *fn++ = '0' + (c / 100);
+ *fn++ = '0' + (c / 10) % 10;
+ c = '0' + (c ) % 10;
+ }
+ else if (c == '.' || (c == '\\')) // Escape dot and backslash literals
+ {
+ if (fn+2 >= lim) goto fail;
+ *fn++ = '\\';
+ }
+ else
+ if (fn+1 >= lim) goto fail;
+ *fn++ = (char)c;
+ }
+ *fn++ = '.';
+ }
+
+ while (*r) if (fn+1 >= lim) goto fail;else *fn++ = *r++;
+ if (!DomainEndsInDot(regtype)) { if (fn+1 >= lim) goto fail;else *fn++ = '.';}
+
+ while (*d) if (fn+1 >= lim) goto fail;else *fn++ = *d++;
+ if (!DomainEndsInDot(domain)) { if (fn+1 >= lim) goto fail;else *fn++ = '.';}
+
+ *fn = '\0';
+ return kDNSServiceErr_NoError;
+
+fail:
+ *fn = '\0';
+ return kDNSServiceErr_BadParam;
+}
+
+/*********************************************************************************************
+*
+* TXT Record Construction Functions
+*
+*********************************************************************************************/
+
+typedef struct _TXTRecordRefRealType
+{
+ uint8_t *buffer; // Pointer to data
+ uint16_t buflen; // Length of buffer
+ uint16_t datalen; // Length currently in use
+ uint16_t malloced; // Non-zero if buffer was allocated via malloc()
+} TXTRecordRefRealType;
+
+#define txtRec ((TXTRecordRefRealType*)txtRecord)
+
+// The opaque storage defined in the public dns_sd.h header is 16 bytes;
+// make sure we don't exceed that.
+struct CompileTimeAssertionCheck_dnssd_clientlib
+{
+ char assert0[(sizeof(TXTRecordRefRealType) <= 16) ? 1 : -1];
+};
+
+void DNSSD_API TXTRecordCreate
+(
+ TXTRecordRef *txtRecord,
+ uint16_t bufferLen,
+ void *buffer
+)
+{
+ txtRec->buffer = buffer;
+ txtRec->buflen = buffer ? bufferLen : (uint16_t)0;
+ txtRec->datalen = 0;
+ txtRec->malloced = 0;
+}
+
+void DNSSD_API TXTRecordDeallocate(TXTRecordRef *txtRecord)
+{
+ if (txtRec->malloced) free(txtRec->buffer);
+}
+
+DNSServiceErrorType DNSSD_API TXTRecordSetValue
+(
+ TXTRecordRef *txtRecord,
+ const char *key,
+ uint8_t valueSize,
+ const void *value
+)
+{
+ uint8_t *start, *p;
+ const char *k;
+ unsigned long keysize, keyvalsize;
+
+ for (k = key; *k; k++) if (*k < 0x20 || *k > 0x7E || *k == '=') return(kDNSServiceErr_Invalid);
+ keysize = (unsigned long)(k - key);
+ keyvalsize = 1 + keysize + (value ? (1 + valueSize) : 0);
+ if (keysize < 1 || keyvalsize > 255) return(kDNSServiceErr_Invalid);
+ (void)TXTRecordRemoveValue(txtRecord, key);
+ if (txtRec->datalen + keyvalsize > txtRec->buflen)
+ {
+ unsigned char *newbuf;
+ unsigned long newlen = txtRec->datalen + keyvalsize;
+ if (newlen > 0xFFFF) return(kDNSServiceErr_Invalid);
+ newbuf = malloc((size_t)newlen);
+ if (!newbuf) return(kDNSServiceErr_NoMemory);
+ memcpy(newbuf, txtRec->buffer, txtRec->datalen);
+ if (txtRec->malloced) free(txtRec->buffer);
+ txtRec->buffer = newbuf;
+ txtRec->buflen = (uint16_t)(newlen);
+ txtRec->malloced = 1;
+ }
+ start = txtRec->buffer + txtRec->datalen;
+ p = start + 1;
+ memcpy(p, key, keysize);
+ p += keysize;
+ if (value)
+ {
+ *p++ = '=';
+ memcpy(p, value, valueSize);
+ p += valueSize;
+ }
+ *start = (uint8_t)(p - start - 1);
+ txtRec->datalen += p - start;
+ return(kDNSServiceErr_NoError);
+}
+
+DNSServiceErrorType DNSSD_API TXTRecordRemoveValue
+(
+ TXTRecordRef *txtRecord,
+ const char *key
+)
+{
+ unsigned long keylen, itemlen, remainder;
+ uint8_t *item = InternalTXTRecordSearch(txtRec->datalen, txtRec->buffer, key, &keylen);
+ if (!item) return(kDNSServiceErr_NoSuchKey);
+ itemlen = (unsigned long)(1 + item[0]);
+ remainder = (unsigned long)((txtRec->buffer + txtRec->datalen) - (item + itemlen));
+ // Use memmove because memcpy behaviour is undefined for overlapping regions
+ memmove(item, item + itemlen, remainder);
+ txtRec->datalen -= itemlen;
+ return(kDNSServiceErr_NoError);
+}
+
+uint16_t DNSSD_API TXTRecordGetLength (const TXTRecordRef *txtRecord) { return(txtRec->datalen); }
+const void * DNSSD_API TXTRecordGetBytesPtr(const TXTRecordRef *txtRecord) { return(txtRec->buffer); }
+
+/*********************************************************************************************
+*
+* TXT Record Parsing Functions
+*
+*********************************************************************************************/
+
+int DNSSD_API TXTRecordContainsKey
+(
+ uint16_t txtLen,
+ const void *txtRecord,
+ const char *key
+)
+{
+ unsigned long keylen;
+ return (InternalTXTRecordSearch(txtLen, txtRecord, key, &keylen) ? 1 : 0);
+}
+
+const void * DNSSD_API TXTRecordGetValuePtr
+(
+ uint16_t txtLen,
+ const void *txtRecord,
+ const char *key,
+ uint8_t *valueLen
+)
+{
+ unsigned long keylen;
+ uint8_t *item = InternalTXTRecordSearch(txtLen, txtRecord, key, &keylen);
+ if (!item || item[0] <= keylen) return(NULL); // If key not found, or found with no value, return NULL
+ *valueLen = (uint8_t)(item[0] - (keylen + 1));
+ return (item + 1 + keylen + 1);
+}
+
+uint16_t DNSSD_API TXTRecordGetCount
+(
+ uint16_t txtLen,
+ const void *txtRecord
+)
+{
+ uint16_t count = 0;
+ uint8_t *p = (uint8_t*)txtRecord;
+ uint8_t *e = p + txtLen;
+ while (p<e) { p += 1 + p[0]; count++; }
+ return((p>e) ? (uint16_t)0 : count);
+}
+
+DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex
+(
+ uint16_t txtLen,
+ const void *txtRecord,
+ uint16_t itemIndex,
+ uint16_t keyBufLen,
+ char *key,
+ uint8_t *valueLen,
+ const void **value
+)
+{
+ uint16_t count = 0;
+ uint8_t *p = (uint8_t*)txtRecord;
+ uint8_t *e = p + txtLen;
+ while (p<e && count<itemIndex) { p += 1 + p[0]; count++; } // Find requested item
+ if (p<e && p + 1 + p[0] <= e) // If valid
+ {
+ uint8_t *x = p+1;
+ unsigned long len = 0;
+ e = p + 1 + p[0];
+ while (x+len<e && x[len] != '=') len++;
+ if (len >= keyBufLen) return(kDNSServiceErr_NoMemory);
+ memcpy(key, x, len);
+ key[len] = 0;
+ if (x+len<e) // If we found '='
+ {
+ *value = x + len + 1;
+ *valueLen = (uint8_t)(p[0] - (len + 1));
+ }
+ else
+ {
+ *value = NULL;
+ *valueLen = 0;
+ }
+ return(kDNSServiceErr_NoError);
+ }
+ return(kDNSServiceErr_Invalid);
+}
+
+/*********************************************************************************************
+*
+* SCCS-compatible version string
+*
+*********************************************************************************************/
+
+// For convenience when using the "strings" command, this is the last thing in the file
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) # s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// NOT static -- otherwise the compiler may optimize it out
+// The "@(#) " pattern is a special prefix the "what" command looks for
+const char VersionString_SCCS_libdnssd[] = "@(#) libdns_sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
diff --git a/sd/source/ui/remotecontrol/mDNSResponder/dnssd_clientstub.c b/sd/source/ui/remotecontrol/mDNSResponder/dnssd_clientstub.c
new file mode 100755
index 000000000000..fb4ae9532e59
--- /dev/null
+++ b/sd/source/ui/remotecontrol/mDNSResponder/dnssd_clientstub.c
@@ -0,0 +1,2206 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * 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.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#if APPLE_OSX_mDNSResponder
+#include <mach-o/dyld.h>
+#endif
+
+#include "dnssd_ipc.h"
+
+static int gDaemonErr = kDNSServiceErr_NoError;
+
+#if defined(_WIN32)
+
+ #define _SSIZE_T
+ #include <CommonServices.h>
+ #include <DebugServices.h>
+ #include <winsock2.h>
+ #include <ws2tcpip.h>
+ #include <windows.h>
+ #include <stdarg.h>
+ #include <stdio.h>
+
+ #define sockaddr_mdns sockaddr_in
+ #define AF_MDNS AF_INET
+
+// 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)
+
+extern BOOL IsSystemServiceDisabled();
+
+ #define sleep(X) Sleep((X) * 1000)
+
+static int g_initWinsock = 0;
+ #define LOG_WARNING kDebugLevelWarning
+ #define LOG_INFO kDebugLevelInfo
+static void syslog( int priority, const char * message, ...)
+{
+ va_list args;
+ int len;
+ char * buffer;
+ DWORD err = WSAGetLastError();
+ (void) priority;
+ va_start( args, message );
+ len = _vscprintf( message, args ) + 1;
+ buffer = malloc( len * sizeof(char) );
+ if ( buffer ) { vsprintf( buffer, message, args ); OutputDebugString( buffer ); free( buffer ); }
+ WSASetLastError( err );
+}
+#else
+
+ #include <sys/fcntl.h> // For O_RDWR etc.
+ #include <sys/time.h>
+ #include <sys/socket.h>
+ #include <syslog.h>
+
+ #define sockaddr_mdns sockaddr_un
+ #define AF_MDNS AF_LOCAL
+
+#endif
+
+// <rdar://problem/4096913> Specifies how many times we'll try and connect to the server.
+
+#define DNSSD_CLIENT_MAXTRIES 4
+
+// Uncomment the line below to use the old error return mechanism of creating a temporary named socket (e.g. in /var/tmp)
+//#define USE_NAMED_ERROR_RETURN_SOCKET 1
+
+#define DNSSD_CLIENT_TIMEOUT 10 // In seconds
+
+#ifndef CTL_PATH_PREFIX
+#define CTL_PATH_PREFIX "/var/tmp/dnssd_result_socket."
+#endif
+
+typedef struct
+{
+ ipc_msg_hdr ipc_hdr;
+ DNSServiceFlags cb_flags;
+ uint32_t cb_interface;
+ DNSServiceErrorType cb_err;
+} CallbackHeader;
+
+typedef struct _DNSServiceRef_t DNSServiceOp;
+typedef struct _DNSRecordRef_t DNSRecord;
+
+#if !defined(_WIN32)
+typedef struct
+{
+ void *AppCallback; // Client callback function and context
+ void *AppContext;
+} SleepKAContext;
+#endif
+
+// client stub callback to process message from server and deliver results to client application
+typedef void (*ProcessReplyFn)(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *msg, const char *const end);
+
+#define ValidatorBits 0x12345678
+#define DNSServiceRefValid(X) (dnssd_SocketValid((X)->sockfd) && (((X)->sockfd ^ (X)->validator) == ValidatorBits))
+
+// When using kDNSServiceFlagsShareConnection, there is one primary _DNSServiceOp_t, and zero or more subordinates
+// For the primary, the 'next' field points to the first subordinate, and its 'next' field points to the next, and so on.
+// For the primary, the 'primary' field is NULL; for subordinates the 'primary' field points back to the associated primary
+//
+// _DNS_SD_LIBDISPATCH is defined where libdispatch/GCD is available. This does not mean that the application will use the
+// DNSServiceSetDispatchQueue API. Hence any new code guarded with _DNS_SD_LIBDISPATCH should still be backwards compatible.
+struct _DNSServiceRef_t
+{
+ DNSServiceOp *next; // For shared connection
+ DNSServiceOp *primary; // For shared connection
+ dnssd_sock_t sockfd; // Connected socket between client and daemon
+ dnssd_sock_t validator; // Used to detect memory corruption, double disposals, etc.
+ client_context_t uid; // For shared connection requests, each subordinate DNSServiceRef has its own ID,
+ // unique within the scope of the same shared parent DNSServiceRef
+ uint32_t op; // request_op_t or reply_op_t
+ uint32_t max_index; // Largest assigned record index - 0 if no additional records registered
+ uint32_t logcounter; // Counter used to control number of syslog messages we write
+ int *moreptr; // Set while DNSServiceProcessResult working on this particular DNSServiceRef
+ ProcessReplyFn ProcessReply; // Function pointer to the code to handle received messages
+ void *AppCallback; // Client callback function and context
+ void *AppContext;
+ DNSRecord *rec;
+#if _DNS_SD_LIBDISPATCH
+ dispatch_source_t disp_source;
+ dispatch_queue_t disp_queue;
+#endif
+ void *kacontext;
+};
+
+struct _DNSRecordRef_t
+{
+ DNSRecord *recnext;
+ void *AppContext;
+ DNSServiceRegisterRecordReply AppCallback;
+ DNSRecordRef recref;
+ uint32_t record_index; // index is unique to the ServiceDiscoveryRef
+ client_context_t uid; // For demultiplexing multiple DNSServiceRegisterRecord calls
+ DNSServiceOp *sdr;
+};
+
+// Write len bytes. Return 0 on success, -1 on error
+static int write_all(dnssd_sock_t sd, char *buf, size_t 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, (long)len, 0);
+ if (num_written < 0 || (size_t)num_written > len)
+ {
+ // Should never happen. If it does, it indicates some OS bug,
+ // or that the mDNSResponder daemon crashed (which should never happen).
+ #if !defined(__ppc__) && defined(SO_ISDEFUNCT)
+ int defunct;
+ socklen_t dlen = sizeof (defunct);
+ if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0)
+ syslog(LOG_WARNING, "dnssd_clientstub write_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+ if (!defunct)
+ syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
+ (long)num_written, (long)len,
+ (num_written < 0) ? dnssd_errno : 0,
+ (num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
+ else
+ syslog(LOG_INFO, "dnssd_clientstub write_all(%d) DEFUNCT", sd);
+ #else
+ syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
+ (long)num_written, (long)len,
+ (num_written < 0) ? dnssd_errno : 0,
+ (num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
+ #endif
+ return -1;
+ }
+ buf += num_written;
+ len -= num_written;
+ }
+ return 0;
+}
+
+enum { read_all_success = 0, read_all_fail = -1, read_all_wouldblock = -2 };
+
+// Read len bytes. Return 0 on success, read_all_fail on error, or read_all_wouldblock for
+static int read_all(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);
+ // It is valid to get an interrupted system call error e.g., somebody attaching
+ // in a debugger, retry without failing
+ if ((num_read < 0) && (errno == EINTR)) { syslog(LOG_INFO, "dnssd_clientstub read_all: EINTR continue"); continue; }
+ if ((num_read == 0) || (num_read < 0) || (num_read > len))
+ {
+ int printWarn = 0;
+ int defunct = 0;
+ // Should never happen. If it does, it indicates some OS bug,
+ // or that the mDNSResponder daemon crashed (which should never happen).
+#if defined(WIN32)
+ // <rdar://problem/7481776> Suppress logs for "A non-blocking socket operation
+ // could not be completed immediately"
+ if (WSAGetLastError() != WSAEWOULDBLOCK)
+ printWarn = 1;
+#endif
+#if !defined(__ppc__) && defined(SO_ISDEFUNCT)
+ {
+ socklen_t dlen = sizeof (defunct);
+ if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0)
+ syslog(LOG_WARNING, "dnssd_clientstub read_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+ }
+ if (!defunct)
+ printWarn = 1;
+#endif
+ if (printWarn)
+ syslog(LOG_WARNING, "dnssd_clientstub read_all(%d) failed %ld/%ld %d %s", sd,
+ (long)num_read, (long)len,
+ (num_read < 0) ? dnssd_errno : 0,
+ (num_read < 0) ? dnssd_strerror(dnssd_errno) : "");
+ else if (defunct)
+ syslog(LOG_INFO, "dnssd_clientstub read_all(%d) DEFUNCT", sd);
+ return (num_read < 0 && dnssd_errno == dnssd_EWOULDBLOCK) ? read_all_wouldblock : read_all_fail;
+ }
+ buf += num_read;
+ len -= num_read;
+ }
+ return read_all_success;
+}
+
+// Returns 1 if more bytes remain to be read on socket descriptor sd, 0 otherwise
+static int more_bytes(dnssd_sock_t sd)
+{
+ struct timeval tv = { 0, 0 };
+ fd_set readfds;
+ fd_set *fs;
+ int ret;
+
+ if (sd < FD_SETSIZE)
+ {
+ fs = &readfds;
+ FD_ZERO(fs);
+ }
+ else
+ {
+ // Compute the number of integers needed for storing "sd". Internally fd_set is stored
+ // as an array of ints with one bit for each fd and hence we need to compute
+ // the number of ints needed rather than the number of bytes. If "sd" is 32, we need
+ // two ints and not just one.
+ int nfdbits = sizeof (int) * 8;
+ int nints = (sd/nfdbits) + 1;
+ fs = (fd_set *)calloc(nints, sizeof(int));
+ if (fs == NULL) { syslog(LOG_WARNING, "dnssd_clientstub more_bytes: malloc failed"); return 0; }
+ }
+ FD_SET(sd, fs);
+ ret = select((int)sd+1, fs, (fd_set*)NULL, (fd_set*)NULL, &tv);
+ if (fs != &readfds) free(fs);
+ return (ret > 0);
+}
+
+// Wait for daemon to write to socket
+static int wait_for_daemon(dnssd_sock_t sock, int timeout)
+{
+#ifndef WIN32
+ // At this point the next operation (accept() or read()) on this socket may block for a few milliseconds waiting
+ // for the daemon to respond, but that's okay -- the daemon is a trusted service and we know if won't take more
+ // than a few milliseconds to respond. So we'll forego checking for readability of the socket.
+ (void) sock;
+ (void) timeout;
+#else
+ // Windows on the other hand suffers from 3rd party software (primarily 3rd party firewall software) that
+ // interferes with proper functioning of the TCP protocol stack. Because of this and because we depend on TCP
+ // to communicate with the system service, we want to make sure that the next operation on this socket (accept() or
+ // read()) doesn't block indefinitely.
+ if (!gDaemonErr)
+ {
+ struct timeval tv;
+ fd_set set;
+
+ FD_ZERO(&set);
+ FD_SET(sock, &set);
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+ if (!select((int)(sock + 1), &set, NULL, NULL, &tv))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub wait_for_daemon timed out");
+ gDaemonErr = kDNSServiceErr_Timeout;
+ }
+ }
+#endif
+ return gDaemonErr;
+}
+
+/* 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. SeparateReturnSocket should be
+ * non-zero for calls that can't receive an immediate error return value on their primary
+ * socket, and therefore require a separate return path for the error code result.
+ * 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 SeparateReturnSocket, DNSServiceOp *ref)
+{
+ char *msg = NULL;
+ ipc_msg_hdr *hdr;
+ int datalen;
+#if !defined(USE_TCP_LOOPBACK)
+ char ctrl_path[64] = ""; // "/var/tmp/dnssd_result_socket.xxxxxxxxxx-xxx-xxxxxx"
+#endif
+
+ if (SeparateReturnSocket)
+ {
+#if defined(USE_TCP_LOOPBACK)
+ *len += 2; // Allocate space for two-byte port number
+#elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
+ struct timeval tv;
+ if (gettimeofday(&tv, NULL) < 0)
+ { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: gettimeofday failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); return NULL; }
+ sprintf(ctrl_path, "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(),
+ (unsigned long)(tv.tv_sec & 0xFFF), (unsigned long)(tv.tv_usec));
+ *len += strlen(ctrl_path) + 1;
+#else
+ *len += 1; // Allocate space for single zero byte (empty C string)
+#endif
+ }
+
+ datalen = (int) *len;
+ *len += sizeof(ipc_msg_hdr);
+
+ // Write message to buffer
+ msg = malloc(*len);
+ if (!msg) { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: malloc failed"); return NULL; }
+
+ memset(msg, 0, *len);
+ hdr = (ipc_msg_hdr *)msg;
+ hdr->version = VERSION;
+ hdr->datalen = datalen;
+ hdr->ipc_flags = 0;
+ hdr->op = op;
+ hdr->client_context = ref->uid;
+ hdr->reg_index = 0;
+ *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 (SeparateReturnSocket) put_uint16(0, data_start);
+#else
+ if (SeparateReturnSocket) put_string(ctrl_path, data_start);
+#endif
+ return hdr;
+}
+
+static void FreeDNSRecords(DNSServiceOp *sdRef)
+{
+ DNSRecord *rec = sdRef->rec;
+ while (rec)
+ {
+ DNSRecord *next = rec->recnext;
+ free(rec);
+ rec = next;
+ }
+}
+
+static void FreeDNSServiceOp(DNSServiceOp *x)
+{
+ // We don't use our DNSServiceRefValid macro here because if we're cleaning up after a socket() call failed
+ // then sockfd could legitimately contain a failing value (e.g. dnssd_InvalidSocket)
+ if ((x->sockfd ^ x->validator) != ValidatorBits)
+ syslog(LOG_WARNING, "dnssd_clientstub attempt to dispose invalid DNSServiceRef %p %08X %08X", x, x->sockfd, x->validator);
+ else
+ {
+ x->next = NULL;
+ x->primary = NULL;
+ x->sockfd = dnssd_InvalidSocket;
+ x->validator = 0xDDDDDDDD;
+ x->op = request_op_none;
+ x->max_index = 0;
+ x->logcounter = 0;
+ x->moreptr = NULL;
+ x->ProcessReply = NULL;
+ x->AppCallback = NULL;
+ x->AppContext = NULL;
+#if _DNS_SD_LIBDISPATCH
+ if (x->disp_source) dispatch_release(x->disp_source);
+ x->disp_source = NULL;
+ x->disp_queue = NULL;
+#endif
+ // DNSRecords may have been added to subordinate sdRef e.g., DNSServiceRegister/DNSServiceAddRecord
+ // or on the main sdRef e.g., DNSServiceCreateConnection/DNSServiveRegisterRecord. DNSRecords may have
+ // been freed if the application called DNSRemoveRecord
+ FreeDNSRecords(x);
+ if (x->kacontext)
+ {
+ free(x->kacontext);
+ x->kacontext = NULL;
+ }
+ free(x);
+ }
+}
+
+// Return a connected service ref (deallocate with DNSServiceRefDeallocate)
+static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags flags, uint32_t op, ProcessReplyFn ProcessReply, void *AppCallback, void *AppContext)
+{
+ #if APPLE_OSX_mDNSResponder
+ int NumTries = DNSSD_CLIENT_MAXTRIES;
+ #else
+ int NumTries = 0;
+ #endif
+
+ dnssd_sockaddr_t saddr;
+ DNSServiceOp *sdr;
+
+ if (!ref) { syslog(LOG_WARNING, "dnssd_clientstub DNSService operation with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
+
+ if (flags & kDNSServiceFlagsShareConnection)
+ {
+ if (!*ref)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with NULL DNSServiceRef");
+ return kDNSServiceErr_BadParam;
+ }
+ if (!DNSServiceRefValid(*ref) || (*ref)->op != connection_request || (*ref)->primary)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with invalid DNSServiceRef %p %08X %08X",
+ (*ref), (*ref)->sockfd, (*ref)->validator);
+ *ref = NULL;
+ return kDNSServiceErr_BadReference;
+ }
+ }
+
+ #if defined(_WIN32)
+ if (!g_initWinsock)
+ {
+ WSADATA wsaData;
+ g_initWinsock = 1;
+ if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { *ref = NULL; return kDNSServiceErr_ServiceNotRunning; }
+ }
+ // <rdar://problem/4096913> If the system service is disabled, we only want to try to connect once
+ if (IsSystemServiceDisabled()) NumTries = DNSSD_CLIENT_MAXTRIES;
+ #endif
+
+ sdr = malloc(sizeof(DNSServiceOp));
+ if (!sdr) { syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: malloc failed"); *ref = NULL; return kDNSServiceErr_NoMemory; }
+ sdr->next = NULL;
+ sdr->primary = NULL;
+ sdr->sockfd = dnssd_InvalidSocket;
+ sdr->validator = sdr->sockfd ^ ValidatorBits;
+ sdr->op = op;
+ sdr->max_index = 0;
+ sdr->logcounter = 0;
+ sdr->moreptr = NULL;
+ sdr->uid.u32[0] = 0;
+ sdr->uid.u32[1] = 0;
+ sdr->ProcessReply = ProcessReply;
+ sdr->AppCallback = AppCallback;
+ sdr->AppContext = AppContext;
+ sdr->rec = NULL;
+#if _DNS_SD_LIBDISPATCH
+ sdr->disp_source = NULL;
+ sdr->disp_queue = NULL;
+#endif
+ sdr->kacontext = NULL;
+
+ if (flags & kDNSServiceFlagsShareConnection)
+ {
+ DNSServiceOp **p = &(*ref)->next; // Append ourselves to end of primary's list
+ while (*p) p = &(*p)->next;
+ *p = sdr;
+ // Preincrement counter before we use it -- it helps with debugging if we know the all-zeroes ID should never appear
+ if (++(*ref)->uid.u32[0] == 0) ++(*ref)->uid.u32[1]; // In parent DNSServiceOp increment UID counter
+ sdr->primary = *ref; // Set our primary pointer
+ sdr->sockfd = (*ref)->sockfd; // Inherit primary's socket
+ sdr->validator = (*ref)->validator;
+ sdr->uid = (*ref)->uid;
+ //printf("ConnectToServer sharing socket %d\n", sdr->sockfd);
+ }
+ else
+ {
+ #ifdef SO_NOSIGPIPE
+ const unsigned long optval = 1;
+ #endif
+ *ref = NULL;
+ sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0);
+ sdr->validator = sdr->sockfd ^ ValidatorBits;
+ if (!dnssd_SocketValid(sdr->sockfd))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: socket failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+ FreeDNSServiceOp(sdr);
+ return kDNSServiceErr_NoMemory;
+ }
+ #ifdef SO_NOSIGPIPE
+ // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
+ if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_NOSIGPIPE failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+ #endif
+ #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);
+ #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
+ {
+ int defunct = 1;
+ if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+ }
+ #endif
+ #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 four seconds, we still can't connect to the daemon,
+ // then we give up and return a failure code.
+ if (++NumTries < DNSSD_CLIENT_MAXTRIES) sleep(1); // Sleep a bit, then try again
+ else { dnssd_close(sdr->sockfd); FreeDNSServiceOp(sdr); return kDNSServiceErr_ServiceNotRunning; }
+ }
+ //printf("ConnectToServer opened socket %d\n", sdr->sockfd);
+ }
+
+ *ref = sdr;
+ return kDNSServiceErr_NoError;
+}
+
+#define deliver_request_bailout(MSG) \
+ do { syslog(LOG_WARNING, "dnssd_clientstub deliver_request: %s failed %d (%s)", (MSG), dnssd_errno, dnssd_strerror(dnssd_errno)); goto cleanup; } while(0)
+
+static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
+{
+ uint32_t datalen = hdr->datalen; // We take a copy here because we're going to convert hdr->datalen to network byte order
+ #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
+ char *const data = (char *)hdr + sizeof(ipc_msg_hdr);
+ #endif
+ dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
+ DNSServiceErrorType err = kDNSServiceErr_Unknown; // Default for the "goto cleanup" cases
+ int MakeSeparateReturnSocket = 0;
+
+ // Note: need to check hdr->op, not sdr->op.
+ // hdr->op contains the code for the specific operation we're currently doing, whereas sdr->op
+ // contains the original parent DNSServiceOp (e.g. for an add_record_request, hdr->op will be
+ // add_record_request but the parent sdr->op will be connection_request or reg_service_request)
+ if (sdr->primary ||
+ hdr->op == reg_record_request || hdr->op == add_record_request || hdr->op == update_record_request || hdr->op == remove_record_request)
+ MakeSeparateReturnSocket = 1;
+
+ if (!DNSServiceRefValid(sdr))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub deliver_request: invalid DNSServiceRef %p %08X %08X", sdr, sdr->sockfd, sdr->validator);
+ return kDNSServiceErr_BadReference;
+ }
+
+ if (!hdr) { syslog(LOG_WARNING, "dnssd_clientstub deliver_request: !hdr"); return kDNSServiceErr_Unknown; }
+
+ if (MakeSeparateReturnSocket)
+ {
+ #if defined(USE_TCP_LOOPBACK)
+ {
+ union { uint16_t s; u_char b[2]; } port;
+ dnssd_sockaddr_t caddr;
+ dnssd_socklen_t len = (dnssd_socklen_t) sizeof(caddr);
+ listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
+ if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("TCP socket");
+
+ caddr.sin_family = AF_INET;
+ caddr.sin_port = 0;
+ caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
+ if (bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr)) < 0) deliver_request_bailout("TCP bind");
+ if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) deliver_request_bailout("TCP getsockname");
+ if (listen(listenfd, 1) < 0) deliver_request_bailout("TCP listen");
+ 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
+ }
+ #elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
+ {
+ mode_t mask;
+ int bindresult;
+ dnssd_sockaddr_t caddr;
+ listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
+ if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET socket");
+
+ caddr.sun_family = AF_LOCAL;
+ // According to Stevens (section 3.2), there is no portable way to
+ // determine whether sa_len is defined on a particular platform.
+ #ifndef NOT_HAVE_SA_LEN
+ caddr.sun_len = sizeof(struct sockaddr_un);
+ #endif
+ strcpy(caddr.sun_path, data);
+ mask = umask(0);
+ bindresult = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr));
+ umask(mask);
+ if (bindresult < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET bind");
+ if (listen(listenfd, 1) < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET listen");
+ }
+ #else
+ {
+ dnssd_sock_t sp[2];
+ if (socketpair(AF_DNSSD, SOCK_STREAM, 0, sp) < 0) deliver_request_bailout("socketpair");
+ else
+ {
+ errsd = sp[0]; // We'll read our four-byte error code from sp[0]
+ listenfd = sp[1]; // We'll send sp[1] to the daemon
+ #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
+ {
+ int defunct = 1;
+ if (setsockopt(errsd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+ }
+ #endif
+ }
+ }
+ #endif
+ }
+
+#if !defined(USE_TCP_LOOPBACK) && !defined(USE_NAMED_ERROR_RETURN_SOCKET)
+ // If we're going to make a separate error return socket, and pass it to the daemon
+ // using sendmsg, then we'll hold back one data byte to go with it.
+ // On some versions of Unix (including Leopard) sending a control message without
+ // any associated data does not work reliably -- e.g. one particular issue we ran
+ // into is that if the receiving program is in a kqueue loop waiting to be notified
+ // of the received message, it doesn't get woken up when the control message arrives.
+ if (MakeSeparateReturnSocket || sdr->op == send_bpf) datalen--; // Okay to use sdr->op when checking for op == send_bpf
+#endif
+
+ // At this point, our listening socket is set up and waiting, if necessary, for the daemon to connect back to
+ ConvertHeaderBytes(hdr);
+ //syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %lu bytes", (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
+ //if (MakeSeparateReturnSocket) syslog(LOG_WARNING, "dnssd_clientstub deliver_request name is %s", data);
+#if TEST_SENDING_ONE_BYTE_AT_A_TIME
+ unsigned int i;
+ for (i=0; i<datalen + sizeof(ipc_msg_hdr); i++)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %d", i);
+ if (write_all(sdr->sockfd, ((char *)hdr)+i, 1) < 0)
+ { syslog(LOG_WARNING, "write_all (byte %u) failed", i); goto cleanup; }
+ usleep(10000);
+ }
+#else
+ if (write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr)) < 0)
+ {
+ // write_all already prints an error message if there is an error writing to
+ // the socket except for DEFUNCT. Logging here is unnecessary and also wrong
+ // in the case of DEFUNCT sockets
+ syslog(LOG_INFO, "dnssd_clientstub deliver_request ERROR: write_all(%d, %lu bytes) failed",
+ sdr->sockfd, (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
+ goto cleanup;
+ }
+#endif
+
+ if (!MakeSeparateReturnSocket) errsd = sdr->sockfd;
+ if (MakeSeparateReturnSocket || sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
+ {
+#if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
+ // At this point we may block in accept for a few milliseconds waiting for the daemon to connect back to us,
+ // but that's okay -- the daemon is a trusted service and we know if won't take more than a few milliseconds to respond.
+ dnssd_sockaddr_t daddr;
+ dnssd_socklen_t len = sizeof(daddr);
+ if ((err = wait_for_daemon(listenfd, DNSSD_CLIENT_TIMEOUT)) != kDNSServiceErr_NoError) goto cleanup;
+ errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
+ if (!dnssd_SocketValid(errsd)) deliver_request_bailout("accept");
+#else
+
+ struct iovec vec = { ((char *)hdr) + sizeof(ipc_msg_hdr) + datalen, 1 }; // Send the last byte along with the SCM_RIGHTS
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ char cbuf[CMSG_SPACE(sizeof(dnssd_sock_t))];
+
+ if (sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
+ {
+ int i;
+ char p[12]; // Room for "/dev/bpf999" with terminating null
+ for (i=0; i<100; i++)
+ {
+ snprintf(p, sizeof(p), "/dev/bpf%d", i);
+ listenfd = open(p, O_RDWR, 0);
+ //if (dnssd_SocketValid(listenfd)) syslog(LOG_WARNING, "Sending fd %d for %s", listenfd, p);
+ if (!dnssd_SocketValid(listenfd) && dnssd_errno != EBUSY)
+ syslog(LOG_WARNING, "Error opening %s %d (%s)", p, dnssd_errno, dnssd_strerror(dnssd_errno));
+ if (dnssd_SocketValid(listenfd) || dnssd_errno != EBUSY) break;
+ }
+ }
+
+ msg.msg_name = 0;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &vec;
+ msg.msg_iovlen = 1;
+ msg.msg_control = cbuf;
+ msg.msg_controllen = CMSG_LEN(sizeof(dnssd_sock_t));
+ msg.msg_flags = 0;
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(dnssd_sock_t));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ *((dnssd_sock_t *)CMSG_DATA(cmsg)) = listenfd;
+
+#if TEST_KQUEUE_CONTROL_MESSAGE_BUG
+ sleep(1);
+#endif
+
+#if DEBUG_64BIT_SCM_RIGHTS
+ syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d %ld %ld %ld/%ld/%ld/%ld",
+ errsd, listenfd, sizeof(dnssd_sock_t), sizeof(void*),
+ sizeof(struct cmsghdr) + sizeof(dnssd_sock_t),
+ CMSG_LEN(sizeof(dnssd_sock_t)), (long)CMSG_SPACE(sizeof(dnssd_sock_t)),
+ (long)((char*)CMSG_DATA(cmsg) + 4 - cbuf));
+#endif // DEBUG_64BIT_SCM_RIGHTS
+
+ if (sendmsg(sdr->sockfd, &msg, 0) < 0)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub deliver_request ERROR: sendmsg failed read sd=%d write sd=%d errno %d (%s)",
+ errsd, listenfd, dnssd_errno, dnssd_strerror(dnssd_errno));
+ err = kDNSServiceErr_Incompatible;
+ goto cleanup;
+ }
+
+#if DEBUG_64BIT_SCM_RIGHTS
+ syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d okay", errsd, listenfd);
+#endif // DEBUG_64BIT_SCM_RIGHTS
+
+#endif
+ // Close our end of the socketpair *before* blocking in read_all to get the four-byte error code.
+ // Otherwise, if the daemon closes our socket (or crashes), we block in read_all() forever
+ // because the socket is not closed (we still have an open reference to it ourselves).
+ dnssd_close(listenfd);
+ listenfd = dnssd_InvalidSocket; // Make sure we don't close it a second time in the cleanup handling below
+ }
+
+ // At this point we may block in read_all for a few milliseconds waiting for the daemon to send us the error code,
+ // but that's okay -- the daemon is a trusted service and we know if won't take more than a few milliseconds to respond.
+ if (sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
+ err = kDNSServiceErr_NoError;
+ else if ((err = wait_for_daemon(errsd, DNSSD_CLIENT_TIMEOUT)) == kDNSServiceErr_NoError)
+ {
+ if (read_all(errsd, (char*)&err, (int)sizeof(err)) < 0)
+ err = kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us
+ else
+ err = ntohl(err);
+ }
+
+ //syslog(LOG_WARNING, "dnssd_clientstub deliver_request: retrieved error code %d", err);
+
+cleanup:
+ if (MakeSeparateReturnSocket)
+ {
+ if (dnssd_SocketValid(listenfd)) dnssd_close(listenfd);
+ if (dnssd_SocketValid(errsd)) dnssd_close(errsd);
+#if defined(USE_NAMED_ERROR_RETURN_SOCKET)
+ // syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removing UDS: %s", data);
+ if (unlink(data) != 0)
+ syslog(LOG_WARNING, "dnssd_clientstub WARNING: unlink(\"%s\") failed errno %d (%s)", data, dnssd_errno, dnssd_strerror(dnssd_errno));
+ // else syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removed UDS: %s", data);
+#endif
+ }
+
+ free(hdr);
+ return err;
+}
+
+int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef)
+{
+ if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with NULL DNSServiceRef"); return dnssd_InvalidSocket; }
+
+ if (!DNSServiceRefValid(sdRef))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with invalid DNSServiceRef %p %08X %08X",
+ sdRef, sdRef->sockfd, sdRef->validator);
+ return dnssd_InvalidSocket;
+ }
+
+ if (sdRef->primary)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
+ return dnssd_InvalidSocket;
+ }
+
+ return (int) sdRef->sockfd;
+}
+
+#if _DNS_SD_LIBDISPATCH
+static void CallbackWithError(DNSServiceRef sdRef, DNSServiceErrorType error)
+{
+ DNSServiceOp *sdr = sdRef;
+ DNSServiceOp *sdrNext;
+ DNSRecord *rec;
+ DNSRecord *recnext;
+ int morebytes;
+
+ while (sdr)
+ {
+ // We can't touch the sdr after the callback as it can be deallocated in the callback
+ sdrNext = sdr->next;
+ morebytes = 1;
+ sdr->moreptr = &morebytes;
+ switch (sdr->op)
+ {
+ case resolve_request:
+ if (sdr->AppCallback) ((DNSServiceResolveReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, sdr->AppContext);
+ break;
+ case query_request:
+ if (sdr->AppCallback) ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, 0, sdr->AppContext);
+ break;
+ case addrinfo_request:
+ if (sdr->AppCallback) ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, NULL, 0, sdr->AppContext);
+ break;
+ case browse_request:
+ if (sdr->AppCallback) ((DNSServiceBrowseReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, NULL, sdr->AppContext);
+ break;
+ case reg_service_request:
+ if (sdr->AppCallback) ((DNSServiceRegisterReply) sdr->AppCallback)(sdr, 0, error, NULL, 0, NULL, sdr->AppContext);
+ break;
+ case enumeration_request:
+ if (sdr->AppCallback) ((DNSServiceDomainEnumReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, sdr->AppContext);
+ break;
+ case connection_request:
+ // This means Register Record, walk the list of DNSRecords to do the callback
+ rec = sdr->rec;
+ while (rec)
+ {
+ recnext = rec->recnext;
+ if (rec->AppCallback) ((DNSServiceRegisterRecordReply)rec->AppCallback)(sdr, 0, 0, error, rec->AppContext);
+ // The Callback can call DNSServiceRefDeallocate which in turn frees sdr and all the records.
+ // Detect that and return early
+ if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:Record: CallbackwithError morebytes zero"); return;}
+ rec = recnext;
+ }
+ break;
+ case port_mapping_request:
+ if (sdr->AppCallback) ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, 0, 0, error, 0, 0, 0, 0, 0, sdr->AppContext);
+ break;
+ default:
+ syslog(LOG_WARNING, "dnssd_clientstub CallbackWithError called with bad op %d", sdr->op);
+ }
+ // If DNSServiceRefDeallocate was called in the callback, morebytes will be zero. As the sdRef
+ // (and its subordinates) have been freed, we should not proceed further. Note that when we
+ // call the callback with a subordinate sdRef the application can call DNSServiceRefDeallocate
+ // on the main sdRef and DNSServiceRefDeallocate handles this case by walking all the sdRefs and
+ // clears the moreptr so that we can terminate here.
+ //
+ // If DNSServiceRefDeallocate was not called in the callback, then set moreptr to NULL so that
+ // we don't access the stack variable after we return from this function.
+ if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:sdRef: CallbackwithError morebytes zero sdr %p", sdr); return;}
+ else {sdr->moreptr = NULL;}
+ sdr = sdrNext;
+ }
+}
+#endif // _DNS_SD_LIBDISPATCH
+
+// 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 DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
+{
+ int morebytes = 0;
+
+ if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
+
+ if (!DNSServiceRefValid(sdRef))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+ return kDNSServiceErr_BadReference;
+ }
+
+ if (sdRef->primary)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
+ return kDNSServiceErr_BadReference;
+ }
+
+ if (!sdRef->ProcessReply)
+ {
+ static int num_logs = 0;
+ if (num_logs < 10) syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function");
+ if (num_logs < 1000) num_logs++;else sleep(1);
+ return kDNSServiceErr_BadReference;
+ }
+
+ do
+ {
+ CallbackHeader cbh;
+ char *data;
+
+ // 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.
+ // On error, read_all will write a message to syslog for us, so don't need to duplicate that here
+ // Note: If we want to properly support using non-blocking sockets in the future
+ int result = read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr));
+ if (result == read_all_fail)
+ {
+ // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
+ // in the callback.
+ sdRef->ProcessReply = NULL;
+#if _DNS_SD_LIBDISPATCH
+ // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
+ // is not called by the application and hence need to communicate the error. Cancel the
+ // source so that we don't get any more events
+ // Note: read_all fails if we could not read from the daemon which can happen if the
+ // daemon dies or the file descriptor is disconnected (defunct).
+ if (sdRef->disp_source)
+ {
+ dispatch_source_cancel(sdRef->disp_source);
+ dispatch_release(sdRef->disp_source);
+ sdRef->disp_source = NULL;
+ CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
+ }
+#endif
+ // Don't touch sdRef anymore as it might have been deallocated
+ return kDNSServiceErr_ServiceNotRunning;
+ }
+ else if (result == read_all_wouldblock)
+ {
+ if (morebytes && sdRef->logcounter < 100)
+ {
+ sdRef->logcounter++;
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult error: select indicated data was waiting but read_all returned EWOULDBLOCK");
+ }
+ return kDNSServiceErr_NoError;
+ }
+
+ ConvertHeaderBytes(&cbh.ipc_hdr);
+ if (cbh.ipc_hdr.version != VERSION)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult daemon version %d does not match client version %d", cbh.ipc_hdr.version, VERSION);
+ sdRef->ProcessReply = NULL;
+ return kDNSServiceErr_Incompatible;
+ }
+
+ data = malloc(cbh.ipc_hdr.datalen);
+ if (!data) return kDNSServiceErr_NoMemory;
+ if (read_all(sdRef->sockfd, data, cbh.ipc_hdr.datalen) < 0) // On error, read_all will write a message to syslog for us
+ {
+ // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
+ // in the callback.
+ sdRef->ProcessReply = NULL;
+#if _DNS_SD_LIBDISPATCH
+ // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
+ // is not called by the application and hence need to communicate the error. Cancel the
+ // source so that we don't get any more events
+ if (sdRef->disp_source)
+ {
+ dispatch_source_cancel(sdRef->disp_source);
+ dispatch_release(sdRef->disp_source);
+ sdRef->disp_source = NULL;
+ CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
+ }
+#endif
+ // Don't touch sdRef anymore as it might have been deallocated
+ free(data);
+ return kDNSServiceErr_ServiceNotRunning;
+ }
+ else
+ {
+ const char *ptr = data;
+ cbh.cb_flags = get_flags (&ptr, data + cbh.ipc_hdr.datalen);
+ cbh.cb_interface = get_uint32 (&ptr, data + cbh.ipc_hdr.datalen);
+ cbh.cb_err = get_error_code(&ptr, data + cbh.ipc_hdr.datalen);
+
+ // CAUTION: We have to handle the case where the client calls DNSServiceRefDeallocate from within the callback function.
+ // To do this we set moreptr to point to morebytes. If the client does call DNSServiceRefDeallocate(),
+ // then that routine will clear morebytes for us, and cause us to exit our loop.
+ morebytes = more_bytes(sdRef->sockfd);
+ if (morebytes)
+ {
+ cbh.cb_flags |= kDNSServiceFlagsMoreComing;
+ sdRef->moreptr = &morebytes;
+ }
+ if (ptr) sdRef->ProcessReply(sdRef, &cbh, ptr, data + cbh.ipc_hdr.datalen);
+ // Careful code here:
+ // If morebytes is non-zero, that means we set sdRef->moreptr above, and the operation was not
+ // cancelled out from under us, so now we need to clear sdRef->moreptr so we don't leave a stray
+ // dangling pointer pointing to a long-gone stack variable.
+ // If morebytes is zero, then one of two thing happened:
+ // (a) morebytes was 0 above, so we didn't set sdRef->moreptr, so we don't need to clear it
+ // (b) morebytes was 1 above, and we set sdRef->moreptr, but the operation was cancelled (with DNSServiceRefDeallocate()),
+ // so we MUST NOT try to dereference our stale sdRef pointer.
+ if (morebytes) sdRef->moreptr = NULL;
+ }
+ free(data);
+ } while (morebytes);
+
+ return kDNSServiceErr_NoError;
+}
+
+void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef)
+{
+ if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with NULL DNSServiceRef"); return; }
+
+ if (!DNSServiceRefValid(sdRef)) // Also verifies dnssd_SocketValid(sdRef->sockfd) for us too
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+ return;
+ }
+
+ // If we're in the middle of a DNSServiceProcessResult() invocation for this DNSServiceRef, clear its morebytes flag to break it out of its while loop
+ if (sdRef->moreptr) *(sdRef->moreptr) = 0;
+
+ if (sdRef->primary) // If this is a subordinate DNSServiceOp, just send a 'stop' command
+ {
+ DNSServiceOp **p = &sdRef->primary->next;
+ while (*p && *p != sdRef) p = &(*p)->next;
+ if (*p)
+ {
+ char *ptr;
+ size_t len = 0;
+ ipc_msg_hdr *hdr = create_hdr(cancel_request, &len, &ptr, 0, sdRef);
+ if (hdr)
+ {
+ ConvertHeaderBytes(hdr);
+ write_all(sdRef->sockfd, (char *)hdr, len);
+ free(hdr);
+ }
+ *p = sdRef->next;
+ FreeDNSServiceOp(sdRef);
+ }
+ }
+ else // else, make sure to terminate all subordinates as well
+ {
+#if _DNS_SD_LIBDISPATCH
+ // The cancel handler will close the fd if a dispatch source has been set
+ if (sdRef->disp_source)
+ {
+ // By setting the ProcessReply to NULL, we make sure that we never call
+ // the application callbacks ever, after returning from this function. We
+ // assume that DNSServiceRefDeallocate is called from the serial queue
+ // that was passed to DNSServiceSetDispatchQueue. Hence, dispatch_source_cancel
+ // should cancel all the blocks on the queue and hence there should be no more
+ // callbacks when we return from this function. Setting ProcessReply to NULL
+ // provides extra protection.
+ sdRef->ProcessReply = NULL;
+ dispatch_source_cancel(sdRef->disp_source);
+ dispatch_release(sdRef->disp_source);
+ sdRef->disp_source = NULL;
+ }
+ // if disp_queue is set, it means it used the DNSServiceSetDispatchQueue API. In that case,
+ // when the source was cancelled, the fd was closed in the handler. Currently the source
+ // is cancelled only when the mDNSResponder daemon dies
+ else if (!sdRef->disp_queue) dnssd_close(sdRef->sockfd);
+#else
+ dnssd_close(sdRef->sockfd);
+#endif
+ // Free DNSRecords added in DNSRegisterRecord if they have not
+ // been freed in DNSRemoveRecord
+ while (sdRef)
+ {
+ DNSServiceOp *p = sdRef;
+ sdRef = sdRef->next;
+ // When there is an error reading from the daemon e.g., bad fd, CallbackWithError
+ // is called which sets moreptr. It might set the moreptr on a subordinate sdRef
+ // but the application might call DNSServiceRefDeallocate with the main sdRef from
+ // the callback. Hence, when we loop through the subordinate sdRefs, we need
+ // to clear the moreptr so that CallbackWithError can terminate itself instead of
+ // walking through the freed sdRefs.
+ if (p->moreptr) *(p->moreptr) = 0;
+ FreeDNSServiceOp(p);
+ }
+ }
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceGetProperty(const char *property, void *result, uint32_t *size)
+{
+ char *ptr;
+ size_t len = strlen(property) + 1;
+ ipc_msg_hdr *hdr;
+ DNSServiceOp *tmp;
+ uint32_t actualsize;
+
+ DNSServiceErrorType err = ConnectToServer(&tmp, 0, getproperty_request, NULL, NULL, NULL);
+ if (err) return err;
+
+ hdr = create_hdr(getproperty_request, &len, &ptr, 0, tmp);
+ if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
+
+ put_string(property, &ptr);
+ err = deliver_request(hdr, tmp); // Will free hdr for us
+ if (read_all(tmp->sockfd, (char*)&actualsize, (int)sizeof(actualsize)) < 0)
+ { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
+
+ actualsize = ntohl(actualsize);
+ if (read_all(tmp->sockfd, (char*)result, actualsize < *size ? actualsize : *size) < 0)
+ { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
+ DNSServiceRefDeallocate(tmp);
+
+ // Swap version result back to local process byte order
+ if (!strcmp(property, kDNSServiceProperty_DaemonVersion) && *size >= 4)
+ *(uint32_t*)result = ntohl(*(uint32_t*)result);
+
+ *size = actualsize;
+ return kDNSServiceErr_NoError;
+}
+
+static void handle_resolve_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *end)
+{
+ char fullname[kDNSServiceMaxDomainName];
+ char target[kDNSServiceMaxDomainName];
+ uint16_t txtlen;
+ union { uint16_t s; u_char b[2]; } port;
+ unsigned char *txtrecord;
+
+ get_string(&data, end, fullname, kDNSServiceMaxDomainName);
+ get_string(&data, end, target, kDNSServiceMaxDomainName);
+ if (!data || data + 2 > end) goto fail;
+
+ port.b[0] = *data++;
+ port.b[1] = *data++;
+ txtlen = get_uint16(&data, end);
+ txtrecord = (unsigned char *)get_rdata(&data, end, txtlen);
+
+ if (!data) goto fail;
+ ((DNSServiceResolveReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, fullname, target, port.s, txtlen, txtrecord, sdr->AppContext);
+ return;
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+fail:
+ syslog(LOG_WARNING, "dnssd_clientstub handle_resolve_response: error reading result from daemon");
+}
+
+#if APPLE_OSX_mDNSResponder
+
+static int32_t libSystemVersion = 0;
+
+// Return true if the application linked against a version of libsystem where P2P
+// interfaces were included by default when using kDNSServiceInterfaceIndexAny.
+// Using 160.0.0 == 0xa00000 as the version threshold.
+static int includeP2PWithIndexAny()
+{
+ if (libSystemVersion == 0)
+ libSystemVersion = NSVersionOfLinkTimeLibrary("System");
+
+ if (libSystemVersion < 0xa00000)
+ return 1;
+ else
+ return 0;
+}
+
+#else // APPLE_OSX_mDNSResponder
+
+// always return false for non Apple platforms
+static int includeP2PWithIndexAny()
+{
+ return 0;
+}
+
+#endif // APPLE_OSX_mDNSResponder
+
+DNSServiceErrorType DNSSD_API DNSServiceResolve
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *name,
+ const char *regtype,
+ const char *domain,
+ DNSServiceResolveReply callBack,
+ void *context
+)
+{
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err;
+
+ if (!name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam;
+
+ // Need a real InterfaceID for WakeOnResolve
+ if ((flags & kDNSServiceFlagsWakeOnResolve) != 0 &&
+ ((interfaceIndex == kDNSServiceInterfaceIndexAny) ||
+ (interfaceIndex == kDNSServiceInterfaceIndexLocalOnly) ||
+ (interfaceIndex == kDNSServiceInterfaceIndexUnicast) ||
+ (interfaceIndex == kDNSServiceInterfaceIndexP2P)))
+ {
+ return kDNSServiceErr_BadParam;
+ }
+
+ if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
+ flags |= kDNSServiceFlagsIncludeP2P;
+
+ err = ConnectToServer(sdRef, flags, resolve_request, handle_resolve_response, callBack, context);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ // Calculate total message length
+ len = sizeof(flags);
+ len += sizeof(interfaceIndex);
+ len += strlen(name) + 1;
+ len += strlen(regtype) + 1;
+ len += strlen(domain) + 1;
+
+ hdr = create_hdr(resolve_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_string(name, &ptr);
+ put_string(regtype, &ptr);
+ put_string(domain, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+}
+
+static void handle_query_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
+{
+ uint32_t ttl;
+ char name[kDNSServiceMaxDomainName];
+ uint16_t rrtype, rrclass, rdlen;
+ const char *rdata;
+
+ get_string(&data, end, name, kDNSServiceMaxDomainName);
+ rrtype = get_uint16(&data, end);
+ rrclass = get_uint16(&data, end);
+ rdlen = get_uint16(&data, end);
+ rdata = get_rdata(&data, end, rdlen);
+ ttl = get_uint32(&data, end);
+
+ if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_query_response: error reading result from daemon");
+ else ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, name, rrtype, rrclass, rdlen, rdata, ttl, sdr->AppContext);
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *name,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ DNSServiceQueryRecordReply callBack,
+ void *context
+)
+{
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err;
+
+ if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
+ flags |= kDNSServiceFlagsIncludeP2P;
+
+ err = ConnectToServer(sdRef, flags, query_request, handle_query_response, callBack, context);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ if (!name) name = "\0";
+
+ // Calculate total message length
+ len = sizeof(flags);
+ len += sizeof(uint32_t); // interfaceIndex
+ len += strlen(name) + 1;
+ len += 2 * sizeof(uint16_t); // rrtype, rrclass
+
+ hdr = create_hdr(query_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_string(name, &ptr);
+ put_uint16(rrtype, &ptr);
+ put_uint16(rrclass, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+}
+
+static void handle_addrinfo_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
+{
+ char hostname[kDNSServiceMaxDomainName];
+ uint16_t rrtype, rrclass, rdlen;
+ const char *rdata;
+ uint32_t ttl;
+
+ get_string(&data, end, hostname, kDNSServiceMaxDomainName);
+ rrtype = get_uint16(&data, end);
+ rrclass = get_uint16(&data, end);
+ rdlen = get_uint16(&data, end);
+ rdata = get_rdata (&data, end, rdlen);
+ ttl = get_uint32(&data, end);
+
+ // We only generate client callbacks for A and AAAA results (including NXDOMAIN results for
+ // those types, if the client has requested those with the kDNSServiceFlagsReturnIntermediates).
+ // Other result types, specifically CNAME referrals, are not communicated to the client, because
+ // the DNSServiceGetAddrInfoReply interface doesn't have any meaningful way to communiate CNAME referrals.
+ if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_addrinfo_response: error reading result from daemon");
+ else if (rrtype == kDNSServiceType_A || rrtype == kDNSServiceType_AAAA)
+ {
+ struct sockaddr_in sa4;
+ struct sockaddr_in6 sa6;
+ const struct sockaddr *const sa = (rrtype == kDNSServiceType_A) ? (struct sockaddr*)&sa4 : (struct sockaddr*)&sa6;
+ if (rrtype == kDNSServiceType_A)
+ {
+ memset(&sa4, 0, sizeof(sa4));
+ #ifndef NOT_HAVE_SA_LEN
+ sa4.sin_len = sizeof(struct sockaddr_in);
+ #endif
+ sa4.sin_family = AF_INET;
+ // sin_port = 0;
+ if (!cbh->cb_err) memcpy(&sa4.sin_addr, rdata, rdlen);
+ }
+ else
+ {
+ memset(&sa6, 0, sizeof(sa6));
+ #ifndef NOT_HAVE_SA_LEN
+ sa6.sin6_len = sizeof(struct sockaddr_in6);
+ #endif
+ sa6.sin6_family = AF_INET6;
+ // sin6_port = 0;
+ // sin6_flowinfo = 0;
+ // sin6_scope_id = 0;
+ if (!cbh->cb_err)
+ {
+ memcpy(&sa6.sin6_addr, rdata, rdlen);
+ if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr)) sa6.sin6_scope_id = cbh->cb_interface;
+ }
+ }
+ ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, sa, ttl, sdr->AppContext);
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+ }
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ uint32_t protocol,
+ const char *hostname,
+ DNSServiceGetAddrInfoReply callBack,
+ void *context /* may be NULL */
+)
+{
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err;
+
+ if (!hostname) return kDNSServiceErr_BadParam;
+
+ err = ConnectToServer(sdRef, flags, addrinfo_request, handle_addrinfo_response, callBack, context);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ // Calculate total message length
+ len = sizeof(flags);
+ len += sizeof(uint32_t); // interfaceIndex
+ len += sizeof(uint32_t); // protocol
+ len += strlen(hostname) + 1;
+
+ hdr = create_hdr(addrinfo_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_uint32(protocol, &ptr);
+ put_string(hostname, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+}
+
+static void handle_browse_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
+{
+ char replyName[256], replyType[kDNSServiceMaxDomainName], replyDomain[kDNSServiceMaxDomainName];
+ get_string(&data, end, replyName, 256);
+ get_string(&data, end, replyType, kDNSServiceMaxDomainName);
+ get_string(&data, end, replyDomain, kDNSServiceMaxDomainName);
+ if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_browse_response: error reading result from daemon");
+ else ((DNSServiceBrowseReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, replyName, replyType, replyDomain, sdr->AppContext);
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceBrowse
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *regtype,
+ const char *domain,
+ DNSServiceBrowseReply callBack,
+ void *context
+)
+{
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err;
+
+ if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
+ flags |= kDNSServiceFlagsIncludeP2P;
+
+ err = ConnectToServer(sdRef, flags, browse_request, handle_browse_response, callBack, context);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ if (!domain) domain = "";
+ len = sizeof(flags);
+ len += sizeof(interfaceIndex);
+ len += strlen(regtype) + 1;
+ len += strlen(domain) + 1;
+
+ hdr = create_hdr(browse_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_string(regtype, &ptr);
+ put_string(domain, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain);
+DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain)
+{
+ DNSServiceOp *tmp;
+ char *ptr;
+ size_t len = sizeof(flags) + strlen(domain) + 1;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err = ConnectToServer(&tmp, 0, setdomain_request, NULL, NULL, NULL);
+ if (err) return err;
+
+ hdr = create_hdr(setdomain_request, &len, &ptr, 0, tmp);
+ if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_string(domain, &ptr);
+ err = deliver_request(hdr, tmp); // Will free hdr for us
+ DNSServiceRefDeallocate(tmp);
+ return err;
+}
+
+static void handle_regservice_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
+{
+ char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
+ get_string(&data, end, name, 256);
+ get_string(&data, end, regtype, kDNSServiceMaxDomainName);
+ get_string(&data, end, domain, kDNSServiceMaxDomainName);
+ if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_regservice_response: error reading result from daemon");
+ else ((DNSServiceRegisterReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_err, name, regtype, domain, sdr->AppContext);
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceRegister
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *name,
+ const char *regtype,
+ const char *domain,
+ const char *host,
+ uint16_t PortInNetworkByteOrder,
+ uint16_t txtLen,
+ const void *txtRecord,
+ DNSServiceRegisterReply callBack,
+ void *context
+)
+{
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err;
+ union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder };
+
+ if (!name) name = "";
+ if (!regtype) return kDNSServiceErr_BadParam;
+ if (!domain) domain = "";
+ if (!host) host = "";
+ if (!txtRecord) txtRecord = (void*)"";
+
+ // No callback must have auto-rename
+ if (!callBack && (flags & kDNSServiceFlagsNoAutoRename)) return kDNSServiceErr_BadParam;
+
+ if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
+ flags |= kDNSServiceFlagsIncludeP2P;
+
+ err = ConnectToServer(sdRef, flags, reg_service_request, callBack ? handle_regservice_response : NULL, callBack, context);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ len = sizeof(DNSServiceFlags);
+ len += sizeof(uint32_t); // interfaceIndex
+ len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4;
+ len += 2 * sizeof(uint16_t); // port, txtLen
+ len += txtLen;
+
+ hdr = create_hdr(reg_service_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ // If it is going over a shared connection, then don't set the IPC_FLAGS_NOREPLY
+ // as it affects all the operations over the shared connection. This is not
+ // a normal case and hence receiving the response back from the daemon and
+ // discarding it in ConnectionResponse is okay.
+
+ if (!(flags & kDNSServiceFlagsShareConnection) && !callBack) hdr->ipc_flags |= IPC_FLAGS_NOREPLY;
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_string(name, &ptr);
+ put_string(regtype, &ptr);
+ put_string(domain, &ptr);
+ put_string(host, &ptr);
+ *ptr++ = port.b[0];
+ *ptr++ = port.b[1];
+ put_uint16(txtLen, &ptr);
+ put_rdata(txtLen, txtRecord, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+}
+
+static void handle_enumeration_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
+{
+ char domain[kDNSServiceMaxDomainName];
+ get_string(&data, end, domain, kDNSServiceMaxDomainName);
+ if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_enumeration_response: error reading result from daemon");
+ else ((DNSServiceDomainEnumReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, domain, sdr->AppContext);
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceDomainEnumReply callBack,
+ void *context
+)
+{
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err;
+
+ int f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0;
+ int f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0;
+ if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
+
+ err = ConnectToServer(sdRef, flags, enumeration_request, handle_enumeration_response, callBack, context);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ len = sizeof(DNSServiceFlags);
+ len += sizeof(uint32_t);
+
+ hdr = create_hdr(enumeration_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+}
+
+static void ConnectionResponse(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *const data, const char *const end)
+{
+ (void)data; // Unused
+
+ //printf("ConnectionResponse got %d\n", cbh->ipc_hdr.op);
+ if (cbh->ipc_hdr.op != reg_record_reply_op)
+ {
+ // When using kDNSServiceFlagsShareConnection, need to search the list of associated DNSServiceOps
+ // to find the one this response is intended for, and then call through to its ProcessReply handler.
+ // We start with our first subordinate DNSServiceRef -- don't want to accidentally match the parent DNSServiceRef.
+ DNSServiceOp *op = sdr->next;
+ while (op && (op->uid.u32[0] != cbh->ipc_hdr.client_context.u32[0] || op->uid.u32[1] != cbh->ipc_hdr.client_context.u32[1]))
+ op = op->next;
+ // Note: We may sometimes not find a matching DNSServiceOp, in the case where the client has
+ // cancelled the subordinate DNSServiceOp, but there are still messages in the pipeline from the daemon
+ if (op && op->ProcessReply) op->ProcessReply(op, cbh, data, end);
+ // WARNING: Don't touch op or sdr after this -- client may have called DNSServiceRefDeallocate
+ return;
+ }
+ else
+ {
+ DNSRecordRef rec;
+ for (rec = sdr->rec; rec; rec = rec->recnext)
+ {
+ if (rec->uid.u32[0] == cbh->ipc_hdr.client_context.u32[0] && rec->uid.u32[1] == cbh->ipc_hdr.client_context.u32[1])
+ break;
+ }
+ // The record might have been freed already and hence not an
+ // error if the record is not found.
+ if (!rec)
+ {
+ syslog(LOG_INFO, "ConnectionResponse: Record not found");
+ return;
+ }
+ if (rec->sdr != sdr)
+ {
+ syslog(LOG_WARNING, "ConnectionResponse: Record sdr mismatch: rec %p sdr %p", rec->sdr, sdr);
+ return;
+ }
+
+ if (sdr->op == connection_request)
+ {
+ rec->AppCallback(rec->sdr, rec, cbh->cb_flags, cbh->cb_err, rec->AppContext);
+ }
+ else
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectionResponse: sdr->op != connection_request");
+ rec->AppCallback(rec->sdr, rec, 0, kDNSServiceErr_Unknown, rec->AppContext);
+ }
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+ }
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef)
+{
+ char *ptr;
+ size_t len = 0;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err = ConnectToServer(sdRef, 0, connection_request, ConnectionResponse, NULL, NULL);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ hdr = create_hdr(connection_request, &len, &ptr, 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
+(
+ DNSServiceRef sdRef,
+ DNSRecordRef *RecordRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *fullname,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ uint16_t rdlen,
+ const void *rdata,
+ uint32_t ttl,
+ DNSServiceRegisterRecordReply callBack,
+ void *context
+)
+{
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr = NULL;
+ DNSRecordRef rref = NULL;
+ DNSRecord **p;
+ int f1 = (flags & kDNSServiceFlagsShared) != 0;
+ int f2 = (flags & kDNSServiceFlagsUnique) != 0;
+ if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
+
+ if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
+ flags |= kDNSServiceFlagsIncludeP2P;
+
+ if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
+
+ if (!DNSServiceRefValid(sdRef))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+ return kDNSServiceErr_BadReference;
+ }
+
+ if (sdRef->op != connection_request)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with non-DNSServiceCreateConnection DNSServiceRef %p %d", sdRef, sdRef->op);
+ return kDNSServiceErr_BadReference;
+ }
+
+ *RecordRef = NULL;
+
+ len = sizeof(DNSServiceFlags);
+ len += 2 * sizeof(uint32_t); // interfaceIndex, ttl
+ len += 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen
+ len += strlen(fullname) + 1;
+ len += rdlen;
+
+ // Bump up the uid. Normally for shared operations (kDNSServiceFlagsShareConnection), this
+ // is done in ConnectToServer. For DNSServiceRegisterRecord, ConnectToServer has already
+ // been called. As multiple DNSServiceRegisterRecords can be multiplexed over a single
+ // connection, we need a way to demultiplex the response so that the callback corresponding
+ // to the right DNSServiceRegisterRecord instance can be called. Use the same mechanism that
+ // is used by kDNSServiceFlagsShareConnection. create_hdr copies the uid value to ipc
+ // hdr->client_context which will be returned in the ipc response.
+ if (++sdRef->uid.u32[0] == 0)
+ ++sdRef->uid.u32[1];
+ hdr = create_hdr(reg_record_request, &len, &ptr, 1, sdRef);
+ if (!hdr) return kDNSServiceErr_NoMemory;
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_string(fullname, &ptr);
+ put_uint16(rrtype, &ptr);
+ put_uint16(rrclass, &ptr);
+ put_uint16(rdlen, &ptr);
+ put_rdata(rdlen, rdata, &ptr);
+ put_uint32(ttl, &ptr);
+
+ rref = malloc(sizeof(DNSRecord));
+ if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; }
+ rref->AppContext = context;
+ rref->AppCallback = callBack;
+ rref->record_index = sdRef->max_index++;
+ rref->sdr = sdRef;
+ rref->recnext = NULL;
+ *RecordRef = rref;
+ // Remember the uid that we are sending across so that we can match
+ // when the response comes back.
+ rref->uid = sdRef->uid;
+ hdr->reg_index = rref->record_index;
+
+ p = &(sdRef)->rec;
+ while (*p) p = &(*p)->recnext;
+ *p = rref;
+
+ return deliver_request(hdr, sdRef); // Will free hdr for us
+}
+
+// sdRef returned by DNSServiceRegister()
+DNSServiceErrorType DNSSD_API DNSServiceAddRecord
+(
+ DNSServiceRef sdRef,
+ DNSRecordRef *RecordRef,
+ DNSServiceFlags flags,
+ uint16_t rrtype,
+ uint16_t rdlen,
+ const void *rdata,
+ uint32_t ttl
+)
+{
+ ipc_msg_hdr *hdr;
+ size_t len = 0;
+ char *ptr;
+ DNSRecordRef rref;
+ DNSRecord **p;
+
+ if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
+ if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSRecordRef pointer"); return kDNSServiceErr_BadParam; }
+ if (sdRef->op != reg_service_request)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with non-DNSServiceRegister DNSServiceRef %p %d", sdRef, sdRef->op);
+ return kDNSServiceErr_BadReference;
+ }
+
+ if (!DNSServiceRefValid(sdRef))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+ return kDNSServiceErr_BadReference;
+ }
+
+ *RecordRef = NULL;
+
+ len += 2 * sizeof(uint16_t); // rrtype, rdlen
+ len += rdlen;
+ len += sizeof(uint32_t);
+ len += sizeof(DNSServiceFlags);
+
+ hdr = create_hdr(add_record_request, &len, &ptr, 1, sdRef);
+ if (!hdr) return kDNSServiceErr_NoMemory;
+ put_flags(flags, &ptr);
+ put_uint16(rrtype, &ptr);
+ put_uint16(rdlen, &ptr);
+ put_rdata(rdlen, rdata, &ptr);
+ put_uint32(ttl, &ptr);
+
+ rref = malloc(sizeof(DNSRecord));
+ if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; }
+ rref->AppContext = NULL;
+ rref->AppCallback = NULL;
+ rref->record_index = sdRef->max_index++;
+ rref->sdr = sdRef;
+ rref->recnext = NULL;
+ *RecordRef = rref;
+ hdr->reg_index = rref->record_index;
+
+ p = &(sdRef)->rec;
+ while (*p) p = &(*p)->recnext;
+ *p = rref;
+
+ return deliver_request(hdr, sdRef); // Will free hdr for us
+}
+
+// DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
+DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
+(
+ DNSServiceRef sdRef,
+ DNSRecordRef RecordRef,
+ DNSServiceFlags flags,
+ uint16_t rdlen,
+ const void *rdata,
+ uint32_t ttl
+)
+{
+ ipc_msg_hdr *hdr;
+ size_t len = 0;
+ char *ptr;
+
+ if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
+
+ if (!DNSServiceRefValid(sdRef))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+ return kDNSServiceErr_BadReference;
+ }
+
+ // Note: RecordRef is allowed to be NULL
+
+ len += sizeof(uint16_t);
+ len += rdlen;
+ len += sizeof(uint32_t);
+ len += sizeof(DNSServiceFlags);
+
+ hdr = create_hdr(update_record_request, &len, &ptr, 1, sdRef);
+ if (!hdr) return kDNSServiceErr_NoMemory;
+ hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX;
+ put_flags(flags, &ptr);
+ put_uint16(rdlen, &ptr);
+ put_rdata(rdlen, rdata, &ptr);
+ put_uint32(ttl, &ptr);
+ return deliver_request(hdr, sdRef); // Will free hdr for us
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
+(
+ DNSServiceRef sdRef,
+ DNSRecordRef RecordRef,
+ DNSServiceFlags flags
+)
+{
+ ipc_msg_hdr *hdr;
+ size_t len = 0;
+ char *ptr;
+ DNSServiceErrorType err;
+
+ if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
+ if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSRecordRef"); return kDNSServiceErr_BadParam; }
+ if (!sdRef->max_index) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with bad DNSServiceRef"); return kDNSServiceErr_BadReference; }
+
+ if (!DNSServiceRefValid(sdRef))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+ return kDNSServiceErr_BadReference;
+ }
+
+ len += sizeof(flags);
+ hdr = create_hdr(remove_record_request, &len, &ptr, 1, sdRef);
+ if (!hdr) return kDNSServiceErr_NoMemory;
+ hdr->reg_index = RecordRef->record_index;
+ put_flags(flags, &ptr);
+ err = deliver_request(hdr, sdRef); // Will free hdr for us
+ if (!err)
+ {
+ // This RecordRef could have been allocated in DNSServiceRegisterRecord or DNSServiceAddRecord.
+ // If so, delink from the list before freeing
+ DNSRecord **p = &sdRef->rec;
+ while (*p && *p != RecordRef) p = &(*p)->recnext;
+ if (*p) *p = RecordRef->recnext;
+ free(RecordRef);
+ }
+ return err;
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
+(
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *fullname,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ uint16_t rdlen,
+ const void *rdata
+)
+{
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ DNSServiceOp *tmp;
+
+ DNSServiceErrorType err = ConnectToServer(&tmp, flags, reconfirm_record_request, NULL, NULL, NULL);
+ if (err) return err;
+
+ len = sizeof(DNSServiceFlags);
+ len += sizeof(uint32_t);
+ len += strlen(fullname) + 1;
+ len += 3 * sizeof(uint16_t);
+ len += rdlen;
+ hdr = create_hdr(reconfirm_record_request, &len, &ptr, 0, tmp);
+ if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_string(fullname, &ptr);
+ put_uint16(rrtype, &ptr);
+ put_uint16(rrclass, &ptr);
+ put_uint16(rdlen, &ptr);
+ put_rdata(rdlen, rdata, &ptr);
+
+ err = deliver_request(hdr, tmp); // Will free hdr for us
+ DNSServiceRefDeallocate(tmp);
+ return err;
+}
+
+static void handle_port_mapping_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
+{
+ union { uint32_t l; u_char b[4]; } addr;
+ uint8_t protocol;
+ union { uint16_t s; u_char b[2]; } internalPort;
+ union { uint16_t s; u_char b[2]; } externalPort;
+ uint32_t ttl;
+
+ if (!data || data + 13 > end) goto fail;
+
+ addr.b[0] = *data++;
+ addr.b[1] = *data++;
+ addr.b[2] = *data++;
+ addr.b[3] = *data++;
+ protocol = *data++;
+ internalPort.b[0] = *data++;
+ internalPort.b[1] = *data++;
+ externalPort.b[0] = *data++;
+ externalPort.b[1] = *data++;
+ ttl = get_uint32(&data, end);
+ if (!data) goto fail;
+
+ ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, addr.l, protocol, internalPort.s, externalPort.s, ttl, sdr->AppContext);
+ return;
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+
+ fail :
+ syslog(LOG_WARNING, "dnssd_clientstub handle_port_mapping_response: error reading result from daemon");
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ uint32_t protocol, /* TCP and/or UDP */
+ uint16_t internalPortInNetworkByteOrder,
+ uint16_t externalPortInNetworkByteOrder,
+ uint32_t ttl, /* time to live in seconds */
+ DNSServiceNATPortMappingReply callBack,
+ void *context /* may be NULL */
+)
+{
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ union { uint16_t s; u_char b[2]; } internalPort = { internalPortInNetworkByteOrder };
+ union { uint16_t s; u_char b[2]; } externalPort = { externalPortInNetworkByteOrder };
+
+ DNSServiceErrorType err = ConnectToServer(sdRef, flags, port_mapping_request, handle_port_mapping_response, callBack, context);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ len = sizeof(flags);
+ len += sizeof(interfaceIndex);
+ len += sizeof(protocol);
+ len += sizeof(internalPort);
+ len += sizeof(externalPort);
+ len += sizeof(ttl);
+
+ hdr = create_hdr(port_mapping_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_uint32(protocol, &ptr);
+ *ptr++ = internalPort.b[0];
+ *ptr++ = internalPort.b[1];
+ *ptr++ = externalPort.b[0];
+ *ptr++ = externalPort.b[1];
+ put_uint32(ttl, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+}
+
+#if _DNS_SD_LIBDISPATCH
+DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue
+(
+ DNSServiceRef service,
+ dispatch_queue_t queue
+)
+{
+ int dnssd_fd = DNSServiceRefSockFD(service);
+ if (dnssd_fd == dnssd_InvalidSocket) return kDNSServiceErr_BadParam;
+ if (!queue)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub: DNSServiceSetDispatchQueue dispatch queue NULL");
+ return kDNSServiceErr_BadParam;
+ }
+ if (service->disp_queue)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch queue set already");
+ return kDNSServiceErr_BadParam;
+ }
+ if (service->disp_source)
+ {
+ syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch source set already");
+ return kDNSServiceErr_BadParam;
+ }
+ service->disp_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, dnssd_fd, 0, queue);
+ if (!service->disp_source)
+ {
+ syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch_source_create failed");
+ return kDNSServiceErr_NoMemory;
+ }
+ service->disp_queue = queue;
+ dispatch_source_set_event_handler(service->disp_source, ^{DNSServiceProcessResult(service);});
+ dispatch_source_set_cancel_handler(service->disp_source, ^{dnssd_close(dnssd_fd);});
+ dispatch_resume(service->disp_source);
+ return kDNSServiceErr_NoError;
+}
+#endif // _DNS_SD_LIBDISPATCH
+
+#if !defined(_WIN32)
+
+static void DNSSD_API SleepKeepaliveCallback(DNSServiceRef sdRef, DNSRecordRef rec, const DNSServiceFlags flags,
+ DNSServiceErrorType errorCode, void *context)
+{
+ SleepKAContext *ka = (SleepKAContext *)context;
+ (void)rec; // Unused
+ (void)flags; // Unused
+
+ if (sdRef->kacontext != context)
+ syslog(LOG_WARNING, "SleepKeepaliveCallback context mismatch");
+
+ if (ka->AppCallback)
+ ((DNSServiceSleepKeepaliveReply)ka->AppCallback)(sdRef, errorCode, ka->AppContext);
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ int fd,
+ unsigned int timeout,
+ DNSServiceSleepKeepaliveReply callBack,
+ void *context
+)
+{
+ char source_str[INET6_ADDRSTRLEN];
+ char target_str[INET6_ADDRSTRLEN];
+ struct sockaddr_storage lss;
+ struct sockaddr_storage rss;
+ socklen_t len1, len2;
+ unsigned int len, proxyreclen;
+ char buf[256];
+ DNSServiceErrorType err;
+ DNSRecordRef record = NULL;
+ char name[10];
+ char recname[128];
+ SleepKAContext *ka;
+ unsigned int i, unique;
+
+
+ (void) flags; //unused
+ if (!timeout) return kDNSServiceErr_BadParam;
+
+
+ len1 = sizeof(lss);
+ if (getsockname(fd, (struct sockaddr *)&lss, &len1) < 0)
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getsockname %d\n", errno);
+ return kDNSServiceErr_BadParam;
+ }
+
+ len2 = sizeof(rss);
+ if (getpeername(fd, (struct sockaddr *)&rss, &len2) < 0)
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getpeername %d\n", errno);
+ return kDNSServiceErr_BadParam;
+ }
+
+ if (len1 != len2)
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive local/remote info not same");
+ return kDNSServiceErr_Unknown;
+ }
+
+ unique = 0;
+ if (lss.ss_family == AF_INET)
+ {
+ struct sockaddr_in *sl = (struct sockaddr_in *)&lss;
+ struct sockaddr_in *sr = (struct sockaddr_in *)&rss;
+ unsigned char *ptr = (unsigned char *)&sl->sin_addr;
+
+ if (!inet_ntop(AF_INET, (const void *)&sr->sin_addr, target_str, sizeof (target_str)))
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote info failed %d", errno);
+ return kDNSServiceErr_Unknown;
+ }
+ if (!inet_ntop(AF_INET, (const void *)&sl->sin_addr, source_str, sizeof (source_str)))
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive local info failed %d", errno);
+ return kDNSServiceErr_Unknown;
+ }
+ // Sum of all bytes in the local address and port should result in a unique
+ // number in the local network
+ for (i = 0; i < sizeof(struct in_addr); i++)
+ unique += ptr[i];
+ unique += sl->sin_port;
+ len = snprintf(buf+1, sizeof(buf) - 1, "t=%u h=%s d=%s l=%u r=%u", timeout, source_str, target_str, ntohs(sl->sin_port), ntohs(sr->sin_port));
+ }
+ else
+ {
+ struct sockaddr_in6 *sl6 = (struct sockaddr_in6 *)&lss;
+ struct sockaddr_in6 *sr6 = (struct sockaddr_in6 *)&rss;
+ unsigned char *ptr = (unsigned char *)&sl6->sin6_addr;
+
+ if (!inet_ntop(AF_INET6, (const void *)&sr6->sin6_addr, target_str, sizeof (target_str)))
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote6 info failed %d", errno);
+ return kDNSServiceErr_Unknown;
+ }
+ if (!inet_ntop(AF_INET6, (const void *)&sl6->sin6_addr, source_str, sizeof (source_str)))
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive local6 info failed %d", errno);
+ return kDNSServiceErr_Unknown;
+ }
+ for (i = 0; i < sizeof(struct in6_addr); i++)
+ unique += ptr[i];
+ unique += sl6->sin6_port;
+ len = snprintf(buf+1, sizeof(buf) - 1, "t=%u H=%s D=%s l=%u r=%u", timeout, source_str, target_str, ntohs(sl6->sin6_port), ntohs(sr6->sin6_port));
+ }
+
+ if (len >= (sizeof(buf) - 1))
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit local/remote info");
+ return kDNSServiceErr_Unknown;
+ }
+ // Include the NULL byte also in the first byte. The total length of the record includes the
+ // first byte also.
+ buf[0] = len + 1;
+ proxyreclen = len + 2;
+
+ len = snprintf(name, sizeof(name), "%u", unique);
+ if (len >= sizeof(name))
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit unique");
+ return kDNSServiceErr_Unknown;
+ }
+
+ len = snprintf(recname, sizeof(recname), "%s.%s", name, "_keepalive._dns-sd._udp.local");
+ if (len >= sizeof(recname))
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit name");
+ return kDNSServiceErr_Unknown;
+ }
+
+ ka = malloc(sizeof(SleepKAContext));
+ if (!ka) return kDNSServiceErr_NoMemory;
+ ka->AppCallback = callBack;
+ ka->AppContext = context;
+
+ err = DNSServiceCreateConnection(sdRef);
+ if (err)
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection");
+ free(ka);
+ return err;
+ }
+
+ // we don't care about the "record". When sdRef gets deallocated later, it will be freed too
+ err = DNSServiceRegisterRecord(*sdRef, &record, kDNSServiceFlagsUnique, 0, recname,
+ kDNSServiceType_NULL, kDNSServiceClass_IN, proxyreclen, buf, kDNSServiceInterfaceIndexAny, SleepKeepaliveCallback, ka);
+ if (err)
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection");
+ free(ka);
+ return err;
+ }
+ (*sdRef)->kacontext = ka;
+ return kDNSServiceErr_NoError;
+}
+#endif
diff --git a/sd/source/ui/remotecontrol/mDNSResponder/dnssd_ipc.c b/sd/source/ui/remotecontrol/mDNSResponder/dnssd_ipc.c
new file mode 100755
index 000000000000..6059eb392c73
--- /dev/null
+++ b/sd/source/ui/remotecontrol/mDNSResponder/dnssd_ipc.c
@@ -0,0 +1,161 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * 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.
+ */
+
+#include "dnssd_ipc.h"
+
+#if defined(_WIN32)
+
+char *win32_strerror(int inErrorCode)
+{
+ static char buffer[1024];
+ DWORD n;
+ memset(buffer, 0, sizeof(buffer));
+ n = FormatMessageA(
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ (DWORD) inErrorCode,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ buffer,
+ sizeof(buffer),
+ NULL);
+ if (n > 0)
+ {
+ // Remove any trailing CR's or LF's since some messages have them.
+ while ((n > 0) && isspace(((unsigned char *) buffer)[n - 1]))
+ buffer[--n] = '\0';
+ }
+ return buffer;
+}
+
+#endif
+
+void put_uint32(const uint32_t l, char **ptr)
+{
+ (*ptr)[0] = (char)((l >> 24) & 0xFF);
+ (*ptr)[1] = (char)((l >> 16) & 0xFF);
+ (*ptr)[2] = (char)((l >> 8) & 0xFF);
+ (*ptr)[3] = (char)((l ) & 0xFF);
+ *ptr += sizeof(uint32_t);
+}
+
+uint32_t get_uint32(const char **ptr, const char *end)
+{
+ if (!*ptr || *ptr + sizeof(uint32_t) > end)
+ {
+ *ptr = NULL;
+ return(0);
+ }
+ else
+ {
+ uint8_t *p = (uint8_t*) *ptr;
+ *ptr += sizeof(uint32_t);
+ return((uint32_t) ((uint32_t)p[0] << 24 | (uint32_t)p[1] << 16 | (uint32_t)p[2] << 8 | p[3]));
+ }
+}
+
+void put_uint16(uint16_t s, char **ptr)
+{
+ (*ptr)[0] = (char)((s >> 8) & 0xFF);
+ (*ptr)[1] = (char)((s ) & 0xFF);
+ *ptr += sizeof(uint16_t);
+}
+
+uint16_t get_uint16(const char **ptr, const char *end)
+{
+ if (!*ptr || *ptr + sizeof(uint16_t) > end)
+ {
+ *ptr = NULL;
+ return(0);
+ }
+ else
+ {
+ uint8_t *p = (uint8_t*) *ptr;
+ *ptr += sizeof(uint16_t);
+ return((uint16_t) ((uint16_t)p[0] << 8 | p[1]));
+ }
+}
+
+int put_string(const char *str, char **ptr)
+{
+ if (!str) str = "";
+ strcpy(*ptr, str);
+ *ptr += strlen(str) + 1;
+ return 0;
+}
+
+int get_string(const char **ptr, const char *const end, char *buffer, int buflen)
+{
+ if (!*ptr)
+ {
+ *buffer = 0;
+ return(-1);
+ }
+ else
+ {
+ char *lim = buffer + buflen; // Calculate limit
+ while (*ptr < end && buffer < lim)
+ {
+ char c = *buffer++ = *(*ptr)++;
+ if (c == 0) return(0); // Success
+ }
+ if (buffer == lim) buffer--;
+ *buffer = 0; // Failed, so terminate string,
+ *ptr = NULL; // clear pointer,
+ return(-1); // and return failure indication
+ }
+}
+
+void put_rdata(const int rdlen, const unsigned char *rdata, char **ptr)
+{
+ memcpy(*ptr, rdata, rdlen);
+ *ptr += rdlen;
+}
+
+const char *get_rdata(const char **ptr, const char *end, int rdlen)
+{
+ if (!*ptr || *ptr + rdlen > end)
+ {
+ *ptr = NULL;
+ return(0);
+ }
+ else
+ {
+ const char *rd = *ptr;
+ *ptr += rdlen;
+ return rd;
+ }
+}
+
+void ConvertHeaderBytes(ipc_msg_hdr *hdr)
+{
+ hdr->version = htonl(hdr->version);
+ hdr->datalen = htonl(hdr->datalen);
+ hdr->ipc_flags = htonl(hdr->ipc_flags);
+ hdr->op = htonl(hdr->op );
+ hdr->reg_index = htonl(hdr->reg_index);
+}
diff --git a/sd/source/ui/remotecontrol/mDNSResponder/dnssd_ipc.h b/sd/source/ui/remotecontrol/mDNSResponder/dnssd_ipc.h
new file mode 100755
index 000000000000..30ce0f96cff2
--- /dev/null
+++ b/sd/source/ui/remotecontrol/mDNSResponder/dnssd_ipc.h
@@ -0,0 +1,223 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * 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.
+ */
+
+#ifndef DNSSD_IPC_H
+#define DNSSD_IPC_H
+
+
+//
+// Common cross platform services
+//
+#if defined(WIN32)
+# include <winsock2.h>
+#endif
+
+#include "dns_sd.h"
+
+#if defined(WIN32)
+# define dnssd_InvalidSocket INVALID_SOCKET
+# define dnssd_SocketValid(s) ((s) != INVALID_SOCKET)
+# define dnssd_EWOULDBLOCK WSAEWOULDBLOCK
+# define dnssd_EINTR WSAEINTR
+# define dnssd_ECONNRESET WSAECONNRESET
+# define dnssd_sock_t SOCKET
+# define dnssd_socklen_t int
+# define dnssd_close(sock) closesocket(sock)
+# define dnssd_errno WSAGetLastError()
+# define dnssd_strerror(X) win32_strerror(X)
+# define ssize_t int
+# define getpid _getpid
+# define unlink _unlink
+extern char *win32_strerror(int inErrorCode);
+#else
+# include <sys/types.h>
+# include <unistd.h>
+# include <sys/un.h>
+# include <string.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <sys/stat.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# define dnssd_InvalidSocket -1
+# define dnssd_SocketValid(s) ((s) >= 0)
+# define dnssd_EWOULDBLOCK EWOULDBLOCK
+# define dnssd_EINTR EINTR
+# define dnssd_ECONNRESET ECONNRESET
+# define dnssd_EPIPE EPIPE
+# define dnssd_sock_t int
+# define dnssd_socklen_t unsigned int
+# define dnssd_close(sock) close(sock)
+# define dnssd_errno errno
+# define dnssd_strerror(X) strerror(X)
+#endif
+
+#if defined(USE_TCP_LOOPBACK)
+# define AF_DNSSD AF_INET
+# define MDNS_TCP_SERVERADDR "127.0.0.1"
+# define MDNS_TCP_SERVERPORT 5354
+# define LISTENQ 5
+# define dnssd_sockaddr_t struct sockaddr_in
+#else
+# define AF_DNSSD AF_LOCAL
+# ifndef MDNS_UDS_SERVERPATH
+# define MDNS_UDS_SERVERPATH "/var/run/mDNSResponder"
+# endif
+# define LISTENQ 100
+// longest legal control path length
+# define MAX_CTLPATH 256
+# define dnssd_sockaddr_t struct sockaddr_un
+#endif
+
+// Compatibility workaround
+#ifndef AF_LOCAL
+#define AF_LOCAL AF_UNIX
+#endif
+
+// General UDS constants
+#define TXT_RECORD_INDEX ((uint32_t)(-1)) // record index for default text record
+
+// IPC data encoding constants and types
+#define VERSION 1
+#define IPC_FLAGS_NOREPLY 1 // set flag if no asynchronous replies are to be sent to client
+
+// Structure packing macro. If we're not using GNUC, it's not fatal. Most compilers naturally pack the on-the-wire
+// structures correctly anyway, so a plain "struct" is usually fine. In the event that structures are not packed
+// correctly, our compile-time assertion checks will catch it and prevent inadvertent generation of non-working code.
+#ifndef packedstruct
+ #if ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 9)))
+ #define packedstruct struct __attribute__((__packed__))
+ #define packedunion union __attribute__((__packed__))
+ #else
+ #define packedstruct struct
+ #define packedunion union
+ #endif
+#endif
+
+typedef enum
+{
+ request_op_none = 0, // No request yet received on this connection
+ connection_request = 1, // connected socket via DNSServiceConnect()
+ reg_record_request, // reg/remove record only valid for connected sockets
+ remove_record_request,
+ enumeration_request,
+ reg_service_request,
+ browse_request,
+ resolve_request,
+ query_request,
+ reconfirm_record_request,
+ add_record_request,
+ update_record_request,
+ setdomain_request, // Up to here is in Tiger and B4W 1.0.3
+ getproperty_request, // New in B4W 1.0.4
+ port_mapping_request, // New in Leopard and B4W 2.0
+ addrinfo_request,
+ send_bpf, // New in SL
+ release_request,
+
+ cancel_request = 63
+} request_op_t;
+
+typedef enum
+{
+ enumeration_reply_op = 64,
+ reg_service_reply_op,
+ browse_reply_op,
+ resolve_reply_op,
+ query_reply_op,
+ reg_record_reply_op, // Up to here is in Tiger and B4W 1.0.3
+ getproperty_reply_op, // New in B4W 1.0.4
+ port_mapping_reply_op, // New in Leopard and B4W 2.0
+ addrinfo_reply_op
+} reply_op_t;
+
+#if defined(_WIN64)
+# pragma pack(push,4)
+#endif
+
+// Define context object big enough to hold a 64-bit pointer,
+// to accomodate 64-bit clients communicating with 32-bit daemon.
+// There's no reason for the daemon to ever be a 64-bit process, but its clients might be
+typedef packedunion
+{
+ void *context;
+ uint32_t u32[2];
+} client_context_t;
+
+typedef packedstruct
+{
+ uint32_t version;
+ uint32_t datalen;
+ uint32_t ipc_flags;
+ uint32_t op; // request_op_t or reply_op_t
+ client_context_t client_context; // context passed from client, returned by server in corresponding reply
+ uint32_t reg_index; // identifier for a record registered via DNSServiceRegisterRecord() on a
+ // socket connected by DNSServiceCreateConnection(). Must be unique in the scope of the connection, such that and
+ // index/socket pair uniquely identifies a record. (Used to select records for removal by DNSServiceRemoveRecord())
+} ipc_msg_hdr;
+
+#if defined(_WIN64)
+# pragma pack(pop)
+#endif
+
+// routines to write to and extract data from message buffers.
+// caller responsible for bounds checking.
+// ptr is the address of the pointer to the start of the field.
+// it is advanced to point to the next field, or the end of the message
+
+void put_uint32(const uint32_t l, char **ptr);
+uint32_t get_uint32(const char **ptr, const char *end);
+
+void put_uint16(uint16_t s, char **ptr);
+uint16_t get_uint16(const char **ptr, const char *end);
+
+#define put_flags put_uint32
+#define get_flags get_uint32
+
+#define put_error_code put_uint32
+#define get_error_code get_uint32
+
+int put_string(const char *str, char **ptr);
+int get_string(const char **ptr, const char *const end, char *buffer, int buflen);
+
+void put_rdata(const int rdlen, const unsigned char *rdata, char **ptr);
+const char *get_rdata(const char **ptr, const char *end, int rdlen); // return value is rdata pointed to by *ptr -
+// rdata is not copied from buffer.
+
+void ConvertHeaderBytes(ipc_msg_hdr *hdr);
+
+struct CompileTimeAssertionChecks_dnssd_ipc
+{
+ // Check that the compiler generated our on-the-wire packet format structure definitions
+ // properly packed, without adding padding bytes to align fields on 32-bit or 64-bit boundaries.
+ char assert0[(sizeof(client_context_t) == 8) ? 1 : -1];
+ char assert1[(sizeof(ipc_msg_hdr) == 28) ? 1 : -1];
+};
+
+#endif // DNSSD_IPC_H