From a9e7e07b452f2f17a17077fd6a99c16a7e8c8ee7 Mon Sep 17 00:00:00 2001 From: Fawzi Mohamed Date: Thu, 8 Mar 2012 20:06:52 +0100 Subject: [PATCH] zeroconf: windows support, avahi improvements, less messages * support windows without apple bonjour installed * avahi with autorefresh * less spurious updates (messages when nothing actually changes) * quickly give up on connecting to daemon the first time * added startedBrowsing signal Change-Id: I8a29d94040fa6ffae318c98782120123093d6616 Reviewed-by: Jarek Kobus --- src/libs/zeroconf/avahiLib.cpp | 32 +- src/libs/zeroconf/dnsSdLib.cpp | 7 +- src/libs/zeroconf/embed/CommonServices.h | 1518 ++++++++++ src/libs/zeroconf/embed/DebugServices.c | 3075 ++++++++++++++++++++ src/libs/zeroconf/embed/DebugServices.h | 1607 ++++++++++ src/libs/zeroconf/embed/dnssd_clientstub.c | 20 +- src/libs/zeroconf/embeddedLib.cpp | 6 +- src/libs/zeroconf/servicebrowser.cpp | 251 +- src/libs/zeroconf/servicebrowser.h | 10 +- src/libs/zeroconf/servicebrowser_p.h | 13 +- 10 files changed, 6451 insertions(+), 88 deletions(-) create mode 100644 src/libs/zeroconf/embed/CommonServices.h create mode 100644 src/libs/zeroconf/embed/DebugServices.c create mode 100644 src/libs/zeroconf/embed/DebugServices.h diff --git a/src/libs/zeroconf/avahiLib.cpp b/src/libs/zeroconf/avahiLib.cpp index 6aeff59c584..0a8912d0fae 100644 --- a/src/libs/zeroconf/avahiLib.cpp +++ b/src/libs/zeroconf/avahiLib.cpp @@ -52,6 +52,7 @@ #include #include +#include namespace ZeroConf { namespace Internal { @@ -70,6 +71,7 @@ extern "C" void cAvahiBrowseReply( AvahiServiceBrowser * /*b*/, AvahiIfIndex interface, AvahiProtocol /*protocol*/, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags /*flags*/, void* context); +extern "C" int cAvahiPollFunction(struct pollfd *ufds, unsigned int nfds, int timeout, void *userdata); extern "C" { typedef const AvahiPoll* (*AvahiSimplePollGet)(AvahiSimplePoll *s); @@ -77,6 +79,7 @@ typedef AvahiSimplePoll *(*AvahiSimplePollNewPtr)(void); typedef int (*AvahiSimplePollIteratePtr)(AvahiSimplePoll *s, int sleep_time); typedef void (*AvahiSimplePollQuitPtr)(AvahiSimplePoll *s); typedef void (*AvahiSimplePollFreePtr)(AvahiSimplePoll *s); +typedef void (*AvahiSimplePollSetFuncPtr)(AvahiSimplePoll *s, AvahiPollFunc func, void *userdata); typedef AvahiClient* (*AvahiClientNewPtr)( const AvahiPoll *poll_api, AvahiClientFlags flags, AvahiClientCallback callback, void *userdata, int *error); @@ -113,6 +116,7 @@ private: AvahiSimplePollIteratePtr m_simplePollIterate; AvahiSimplePollQuitPtr m_simplePollQuit; AvahiSimplePollFreePtr m_simplePollFree; + AvahiSimplePollSetFuncPtr m_simplePollSetFunc; AvahiClientNewPtr m_clientNew; AvahiClientFreePtr m_clientFree; AvahiServiceBrowserNewPtr m_serviceBrowserNew; @@ -137,6 +141,7 @@ public: m_simplePollIterate = reinterpret_cast(nativeLib.resolve("avahi_simple_poll_iterate")); m_simplePollQuit = reinterpret_cast(nativeLib.resolve("avahi_simple_poll_quit")); m_simplePollFree = reinterpret_cast(nativeLib.resolve("avahi_simple_poll_free")); + m_simplePollSetFunc = reinterpret_cast(nativeLib.resolve("avahi_simple_poll_set_func")); m_clientNew = reinterpret_cast(nativeLib.resolve("avahi_client_new")); m_clientFree = reinterpret_cast(nativeLib.resolve("avahi_client_free")); m_serviceBrowserNew = reinterpret_cast(nativeLib.resolve("avahi_service_browser_new")); @@ -149,6 +154,7 @@ public: m_simplePollIterate = reinterpret_cast(&avahi_simple_poll_iterate); m_simplePollQuit = reinterpret_cast(&avahi_simple_poll_quit); m_simplePollFree = reinterpret_cast(&avahi_simple_poll_free); + m_simplePollSetFunc = reinterpret_cast(&avahi_simple_poll_set_func); m_clientNew = reinterpret_cast(&avahi_client_new); m_clientFree = reinterpret_cast(&avahi_client_free); m_serviceBrowserNew = reinterpret_cast(&avahi_service_browser_new); @@ -162,6 +168,7 @@ public: if (!m_simplePollIterate) qDebug() << name() << " has null m_simplePollIterate"; if (!m_simplePollQuit) qDebug() << name() << " has null m_simplePollQuit"; if (!m_simplePollFree) qDebug() << name() << " has null m_simplePollFree"; + if (!m_simplePollSetFunc) qDebug() << name() << " has null m_simplePollSetFunc"; if (!m_clientNew) qDebug() << name() << " has null m_clientNew"; if (!m_clientFree) qDebug() << name() << " has null m_clientFree"; if (!m_serviceBrowserNew) qDebug() << name() << " has null m_serviceBrowserNew"; @@ -286,6 +293,7 @@ public: return kDNSServiceErr_Unknown; //avahi_strerror(avahi_client_errno(client)); } + browser->activateAutoRefresh(); return kDNSServiceErr_NoError; } @@ -297,7 +305,7 @@ public: return 0; } - RunLoopStatus processOneEvent(ConnectionRef cRef, qint64 maxLockMs) { + RunLoopStatus processOneEvent(MainConnection *, ConnectionRef cRef, qint64 maxLockMs) { if (!m_simplePollIterate) return ProcessedFailure; MyAvahiConnection *connection = reinterpret_cast(cRef); @@ -309,11 +317,11 @@ public: } RunLoopStatus processOneEventBlock(ConnectionRef cRef) { - return processOneEvent(cRef,-1); + return processOneEvent(NULL,cRef,-1); } - DNSServiceErrorType createConnection(ConnectionRef *sdRef) { - if (!m_simplePollNew || !m_clientNew) + DNSServiceErrorType createConnection(MainConnection *mainConnection, ConnectionRef *sdRef) { + if (!m_simplePollNew || !m_clientNew || !m_simplePollSetFunc) return kDNSServiceErr_Unknown; MyAvahiConnection *connection = new MyAvahiConnection; connection->lib = this; @@ -327,6 +335,8 @@ public: delete connection; return kDNSServiceErr_Unknown; } + typedef void (*AvahiSimplePollSetFuncPtr)(AvahiSimplePoll *s, AvahiPollFunc func, void *userdata); + m_simplePollSetFunc(connection->simple_poll, &cAvahiPollFunction, mainConnection); /* Allocate a new client */ int error; connection->client = m_clientNew(m_simplePollGet(connection->simple_poll), @@ -525,6 +535,20 @@ extern "C" void cAvahiBrowseReply( } } +extern "C" int cAvahiPollFunction(struct pollfd *ufds, unsigned int nfds, int timeout, void *userdata) +{ + MainConnection *mainConnection = static_cast(userdata); + QMutex *lock = 0; + if (mainConnection) + lock = mainConnection->mainThreadLock(); + if (lock) + lock->unlock(); + int res=poll(ufds,nfds,timeout); + if (lock) + lock->lock(); + return res; +} + } // namespace Internal } // namespace ZeroConf diff --git a/src/libs/zeroconf/dnsSdLib.cpp b/src/libs/zeroconf/dnsSdLib.cpp index 603e2917400..eb579d6010e 100644 --- a/src/libs/zeroconf/dnsSdLib.cpp +++ b/src/libs/zeroconf/dnsSdLib.cpp @@ -138,6 +138,10 @@ public: m_createConnection = reinterpret_cast(&DNSServiceCreateConnection); m_refSockFD = reinterpret_cast(&DNSServiceRefSockFD); #endif + if (m_isOk && m_getAddrInfo == 0) { + m_isOk = false; + m_errorMsg = tr("*WARNING* DnsSdZConfLib detected an obsolete version of Apple Bonjour, either disable/uninstall it or upgrade it. Otherwise zeroconf will fail."); + } if (DEBUG_ZEROCONF){ if (m_refDeallocate == 0) qDebug() << QLatin1String("DnsSdZConfLib.m_refDeallocate == 0"); if (m_resolve == 0) qDebug() << QLatin1String("DnsSdZConfLib.m_resolve == 0"); @@ -284,7 +288,7 @@ public: return ProcessedOk; } - DNSServiceErrorType createConnection(ConnectionRef *sdRef) + DNSServiceErrorType createConnection(MainConnection *, ConnectionRef *sdRef) { if (m_createConnection == 0) return kDNSServiceErr_Unsupported; return m_createConnection(reinterpret_cast(sdRef)); @@ -299,7 +303,6 @@ public: ZConfLib::Ptr ZConfLib::createDnsSdLib(const QString &libName, ZConfLib::Ptr fallback) { return ZConfLib::Ptr(new DnsSdZConfLib(libName, fallback)); - return fallback; } } // namespace Internal } // namespace ZeroConf diff --git a/src/libs/zeroconf/embed/CommonServices.h b/src/libs/zeroconf/embed/CommonServices.h new file mode 100644 index 00000000000..1261f1d5ab3 --- /dev/null +++ b/src/libs/zeroconf/embed/CommonServices.h @@ -0,0 +1,1518 @@ +/* -*- 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 + +// 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( __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 +#endif + +#if( ( macintosh || __MACH__ ) && !KERNEL ) + + #if( defined( __MWERKS__ ) ) + #if( __option( c9x ) ) + #include + #endif + #else + #include + #endif + + #include + + #if( __MACH__ ) + + // Mac OS X + + #include + #include + #include + #include + #include + #include + #include + #include + + #else + + // Classic Mac OS + + #include + #include + + #endif + +#elif( KERNEL ) + + // Mac OS X Kernel + + #include + + #include + #include + +#elif( TARGET_OS_LINUX ) + + // Linux + + #include + #include + +#elif( TARGET_OS_SOLARIS ) + + // Solaris + + #include + + #include + #include + + #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 + #endif + + #include + + #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 + #include + #include + + #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_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 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/src/libs/zeroconf/embed/DebugServices.c b/src/libs/zeroconf/embed/DebugServices.c new file mode 100644 index 00000000000..647329628ce --- /dev/null +++ b/src/libs/zeroconf/embed/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 + #include + #include +#endif + +#include "CommonServices.h" + +#include "DebugServices.h" + +#if( DEBUG ) + +#if( TARGET_OS_VXWORKS ) + #include "intLib.h" +#endif + +#if( TARGET_OS_WIN32 ) + #include + + #if( !TARGET_OS_WINDOWS_CE ) + #include + #include + #endif +#endif + +#if( DEBUG_IDEBUG_ENABLED && TARGET_API_MAC_OSX_KERNEL ) + #include +#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[] = "<>"; 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[] = "<>"; 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[] = "<>"; 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), "<>", *a); break; } + if (s + *a >= &mDNS_VACB[254]) { s += DebugSNPrintF(s, mDNS_VACB_Remain(s), "<>"); 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[] = "<>"; 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: " ); + } + } + 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), "<>", 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= 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 = ""; + } + } + 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/src/libs/zeroconf/embed/DebugServices.h b/src/libs/zeroconf/embed/DebugServices.h new file mode 100644 index 00000000000..d4e5c7203df --- /dev/null +++ b/src/libs/zeroconf/embed/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 + +#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: + + + + + 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: + + + +*/ + +#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: +
+		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.
+	
+*/ + +#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): +
+		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.
+	
+ + Helpers: +
+		DebugExtractTaskLevelInterruptDepth()   - Macro to extract interrupt depth from task level value.
+	
+*/ + +#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/src/libs/zeroconf/embed/dnssd_clientstub.c b/src/libs/zeroconf/embed/dnssd_clientstub.c index 06a64a8bc24..7c94862be8f 100644 --- a/src/libs/zeroconf/embed/dnssd_clientstub.c +++ b/src/libs/zeroconf/embed/dnssd_clientstub.c @@ -40,17 +40,16 @@ namespace ZeroConf { namespace embeddedLib { static int gDaemonErr = kDNSServiceErr_NoError; }} -extern "C" { #if defined(_WIN32) #define _SSIZE_T - #include - #include + #include "embed/CommonServices.h" + #include "embed/DebugServices.h" #include #include #include #include - #include + #include #define sockaddr_mdns sockaddr_in #define AF_MDNS AF_INET @@ -61,7 +60,7 @@ extern "C" { // Disable warning: "nonstandard extension, function/data pointer conversion in expression" #pragma warning(disable:4152) - extern BOOL IsSystemServiceDisabled(); + //extern BOOL IsSystemServiceDisabled(); #define sleep(X) Sleep((X) * 1000) #define NOT_HAVE_SA_LEN @@ -83,6 +82,7 @@ namespace ZeroConf { namespace embeddedLib { if ( buffer ) { vsprintf( buffer, message, args ); OutputDebugStringA( buffer ); free( buffer ); } WSASetLastError( err ); } +}} #else #include // For O_RDWR etc. @@ -112,6 +112,7 @@ namespace ZeroConf { namespace embeddedLib { #define CTL_PATH_PREFIX "/var/tmp/dnssd_result_socket." #endif +extern "C" { typedef struct { ipc_msg_hdr ipc_hdr; @@ -427,6 +428,7 @@ static void FreeDNSServiceOp(DNSServiceOp *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) { + static int quickCheck = 1; #if APPLE_OSX_mDNSResponder int NumTries = DNSSD_CLIENT_MAXTRIES; #else @@ -462,7 +464,7 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { *ref = NULL; return kDNSServiceErr_ServiceNotRunning; } } // If the system service is disabled, we only want to try to connect once - if (IsSystemServiceDisabled()) NumTries = DNSSD_CLIENT_MAXTRIES; + //if (IsSystemServiceDisabled()) NumTries = DNSSD_CLIENT_MAXTRIES; #endif sdr = static_cast(malloc(sizeof(DNSServiceOp))); @@ -543,8 +545,10 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f // 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; } + if (++NumTries < DNSSD_CLIENT_MAXTRIES && !quickCheck) sleep(1); // Sleep a bit, then try again + else { + quickCheck = 0; + dnssd_close(sdr->sockfd); FreeDNSServiceOp(sdr); return kDNSServiceErr_ServiceNotRunning; } } //printf("ConnectToServer opened socket %d\n", sdr->sockfd); } diff --git a/src/libs/zeroconf/embeddedLib.cpp b/src/libs/zeroconf/embeddedLib.cpp index 8ce4be55dfb..38fc765f0fa 100644 --- a/src/libs/zeroconf/embeddedLib.cpp +++ b/src/libs/zeroconf/embeddedLib.cpp @@ -44,6 +44,10 @@ #define EMBEDDED_LIB #endif +#ifdef Q_OS_WIN32 +#define EMBEDDED_LIB +#endif + #ifdef EMBEDDED_LIB #include "embed/dnssd_ipc.c" #include "embed/dnssd_clientlib.c" @@ -204,7 +208,7 @@ public: return ProcessedOk; } - DNSServiceErrorType createConnection(ConnectionRef *sdRef) + DNSServiceErrorType createConnection(MainConnection *, ConnectionRef *sdRef) { return embeddedLib::DNSServiceCreateConnection(reinterpret_cast(sdRef)); } diff --git a/src/libs/zeroconf/servicebrowser.cpp b/src/libs/zeroconf/servicebrowser.cpp index e7ce8fa9f76..2eda25d2734 100644 --- a/src/libs/zeroconf/servicebrowser.cpp +++ b/src/libs/zeroconf/servicebrowser.cpp @@ -135,16 +135,26 @@ public: const QString &dnsSdDaemonPath); private: + static const char *defaultmDnsSdLibName; + static const char *defaultmDNSDaemonName; QMutex m_lock; ZConfLib::Ptr m_defaultLib; }; Q_GLOBAL_STATIC(ZeroConfLib, zeroConfLibInstance) +#ifdef Q_OS_WIN + const char *ZeroConfLib::defaultmDnsSdLibName = "dnssd"; + const char *ZeroConfLib::defaultmDNSDaemonName = "mdnssd.exe"; +#else + const char *ZeroConfLib::defaultmDnsSdLibName = "dns_sd"; + const char *ZeroConfLib::defaultmDNSDaemonName = "mdnssd"; +#endif + ZeroConfLib::ZeroConfLib(): m_lock(QMutex::Recursive), m_defaultLib(ZConfLib::createAvahiLib(QLatin1String("avahi-client"), - ZConfLib::createDnsSdLib(QLatin1String("dns_sd"), - ZConfLib::createEmbeddedLib(QLatin1String("mdnssd"))))) + ZConfLib::createDnsSdLib(QLatin1String(defaultmDnsSdLibName), + ZConfLib::createEmbeddedLib(QLatin1String(defaultmDNSDaemonName))))) { qRegisterMetaType("ZeroConf::Service::ConstPtr"); qRegisterMetaType("ZeroConf::ErrorMessage::SeverityLevel"); @@ -259,7 +269,24 @@ Service::~Service() delete m_host; } -ZEROCONFSHARED_EXPORT QDebug operator<<(QDebug dbg, const Service &service) +bool Service::operator==(const Service &o) const { + bool eq = m_fullName == o.m_fullName + && m_name == o.m_name && m_type == o.m_type + && m_domain == o.m_domain && m_port == o.m_port + && m_txtRecord == o.m_txtRecord && m_interfaceNr == o.m_interfaceNr + && m_outdated == m_outdated; + if (eq) { + if (m_host != o.m_host) { + if (m_host == 0 || o.m_host == 0) + return false; + return m_host->hostName() == o.m_host->hostName() + && m_host->addresses() == o.m_host->addresses(); + } + } + return eq; +} + +QDebug operator<<(QDebug dbg, const Service &service) { dbg.maybeSpace() << "Service{ name:" << service.name() << ", " << "type:" << service.type() << ", domain:" << service.domain() << ", " @@ -293,6 +320,16 @@ ZEROCONFSHARED_EXPORT QDebug operator<<(QDebug dbg, const Service &service) dbg << " interfaceNr:" << service.interfaceNr() << ", outdated:" << service.outdated() << " }"; return dbg.space(); } + +QDebug operator<<(QDebug dbg, const Service::ConstPtr &service){ + if (service.data() == 0){ + dbg << "Service{*NULL*}"; + } else { + dbg << *service.data(); + } + return dbg; +} + // inline methods /*! \fn bool Service::outdated() const @@ -369,16 +406,17 @@ void ServiceBrowser::startBrowsing(qint32 interfaceIndex) /// create a new brower for the given service type ServiceBrowser::ServiceBrowser(const QString &serviceType, const QString &domain, AddressesSetting addressesSetting, QObject *parent) - : QObject(parent), + : QObject(parent), timer(0), d(new ServiceBrowserPrivate(serviceType, domain, addressesSetting == RequireAddresses, MainConnectionPtr())) { + connect(this,SIGNAL(activateAutoRefresh()),this,SLOT(autoRefresh())); d->q = this; } ServiceBrowser::ServiceBrowser(const MainConnectionPtr &mainConnection, const QString &serviceType, const QString &domain, AddressesSetting addressesSetting, QObject *parent) - : QObject(parent), + : QObject(parent), timer(0), d(new ServiceBrowserPrivate(serviceType, domain, addressesSetting == RequireAddresses, mainConnection)) { @@ -399,6 +437,11 @@ MainConnectionPtr ServiceBrowser::mainConnection() const /// stops browsing, but does not delete all services found void ServiceBrowser::stopBrowsing() { + if (timer) { + timer->stop(); + delete timer; + timer = 0; + } d->stopBrowsing(); } @@ -452,6 +495,16 @@ void ServiceBrowser::reconfirmService(Service::ConstPtr service) d->reconfirmService(service); } +void ServiceBrowser::autoRefresh() +{ + QMutexLocker l(d->mainConnection->lock()); + if (!timer) { + timer = new QTimer(this); + connect(timer,SIGNAL(timeout()),this,SLOT(triggerRefresh())); + timer->start(5000); + } +} + // signals /*! \fn void ServiceBrowser::serviceChanged( @@ -485,6 +538,24 @@ void ServiceBrowser::reconfirmService(Service::ConstPtr service) services(), use this signal, not serviceChanged(), serviceAdded() or serviceRemoved() to know about changes to the list. */ +/*! + \fn void errorMessage(ZeroConf::ErrorMessage::SeverityLevel severity, const QString &msg, ZeroConf::ServiceBrowser *browser) + + This signal is called every time a warning or error is emitted (for example when a library + cannot be used and another one has to be used). Zeroconf will still work if severity < FailureLevel. +*/ +/*! + \fn void hadFailure(const QList &messages, ZeroConf::ServiceBrowser *browser) + + This signal is emitted only when a full failure has happened, and all the previous errors/attempts to set up zeroconf + are passed in messages. +*/ +/*! + \fn void startedBrowsing(ZeroConf::ServiceBrowser *browser) + + This signal is emitted when browsing has actually started. + One can rely on either startedBrowsing or hadFailure to be emitted. +*/ // ----------------- library initialization impl ----------------- /*! @@ -631,25 +702,32 @@ QString ServiceGatherer::fullName(){ return currentService->fullName(); } -void ServiceGatherer::enactServiceChange() +bool ServiceGatherer::enactServiceChange() { if (DEBUG_ZEROCONF) qDebug() << "ServiceGatherer::enactServiceChange() for service " << currentService->fullName(); if (currentServiceCanBePublished()) { + if ((publishedService.data() == 0 && currentService == 0) + || (publishedService.data() != 0 && currentService != 0 + && *publishedService == *currentService)) + return false; Service::Ptr nService = Service::Ptr(currentService); - serviceBrowser->serviceChanged(publishedService, nService, serviceBrowser->q); if (publishedService) { + publishedService->invalidate(); serviceBrowser->nextActiveServices.removeOne(publishedService); serviceBrowser->serviceRemoved(publishedService, serviceBrowser->q); } + serviceBrowser->serviceChanged(publishedService, nService, serviceBrowser->q); publishedService = nService; if (nService) { serviceBrowser->nextActiveServices.append(nService); serviceBrowser->serviceAdded(nService, serviceBrowser->q); currentService = new Service(*currentService); } + return true; } + return false; } void ServiceGatherer::retireService() @@ -660,8 +738,9 @@ void ServiceGatherer::retireService() << currentService->fullName(); Service::Ptr nService; serviceBrowser->nextActiveServices.removeOne(publishedService); - serviceBrowser->serviceChanged(publishedService, nService, serviceBrowser->q); + publishedService->invalidate(); serviceBrowser->serviceRemoved(publishedService, serviceBrowser->q); + serviceBrowser->serviceChanged(publishedService, nService, serviceBrowser->q); publishedService = nService; } else if (DEBUG_ZEROCONF){ qDebug() << "ServiceGatherer::retireService() for non published service " @@ -897,7 +976,6 @@ void ServiceGatherer::serviceResolveReply(DNSServiceFlags fl } return; } - if (publishedService) publishedService->invalidate(); // delay this to enactServiceChange? serviceBrowser->updateFlowStatusForFlags(flags); uint16_t nKeys = txtRecordGetCount(txtLen, rawTxtRecord); for (uint16_t i = 0; i < nKeys; ++i){ @@ -1041,7 +1119,7 @@ void ServiceGatherer::addrReply(DNSServiceFlags flags, const struct sockaddr *address, uint32_t /*ttl*/) // should we use this??? { - if (errorCode != kDNSServiceErr_NoError){ + if (errorCode != kDNSServiceErr_NoError) { if (errorCode == kDNSServiceErr_Timeout){ if ((status & AddrConnectionSuccess) == 0){ qDebug() << "ServiceBrowser " << serviceBrowser->serviceType @@ -1088,8 +1166,12 @@ void ServiceGatherer::addrReply(DNSServiceFlags flags, } else { if (!addrNow.contains(newAddr)){ switch (newAddr.protocol()){ - case QAbstractSocket::IPv6Protocol: - addrNow.insert(0, newAddr); // prefers IPv6 addresses +#ifdef Q_OS_WIN + case QAbstractSocket::IPv4Protocol: // prefers IPv4 addresses +#else + case QAbstractSocket::IPv6Protocol: // prefers IPv6 addresses +#endif + addrNow.insert(0, newAddr); break; default: addrNow.append(newAddr); @@ -1239,6 +1321,7 @@ void ServiceBrowserPrivate::maybeUpdateLists() qint64 now = QDateTime::currentMSecsSinceEpoch(); QList::iterator i = knownServices.begin(), endi = knownServices.end(); QMap::iterator j = gatherers.begin(); + bool hasServicesChanges = false; while (i != endi && j != gatherers.end()) { const QString vi = *i; QString vj = j.value()->fullName(); @@ -1253,6 +1336,7 @@ void ServiceBrowserPrivate::maybeUpdateLists() pendingGatherers.removeAll(j.value()); j.value()->retireService(); j = gatherers.erase(j); + hasServicesChanges = true; } else { ++j; } @@ -1266,17 +1350,20 @@ void ServiceBrowserPrivate::maybeUpdateLists() pendingGatherers.removeAll(j.value()); j.value()->retireService(); j = gatherers.erase(j); + hasServicesChanges = true; } else { ++j; } } foreach (const ServiceGatherer::Ptr &g, pendingGatherers) - g->enactServiceChange(); - { - QMutexLocker l(mainConnection->lock()); - activeServices = nextActiveServices; + hasServicesChanges = hasServicesChanges || g->enactServiceChange(); + if (hasServicesChanges) { + { + QMutexLocker l(mainConnection->lock()); + activeServices = nextActiveServices; + } + emit q->servicesUpdated(q); } - emit q->servicesUpdated(q); } if (shouldRefresh) refresh(); @@ -1333,6 +1420,11 @@ void ServiceBrowserPrivate::browseReply(DNSServiceFlags flag maybeUpdateLists(); // avoid? } +void ServiceBrowserPrivate::activateAutoRefresh() +{ + emit q->activateAutoRefresh(); +} + void ServiceBrowserPrivate::startBrowsing(quint32 interfaceIndex) { this->interfaceIndex = interfaceIndex; @@ -1364,11 +1456,18 @@ bool ServiceBrowserPrivate::internalStartBrowsing() void ServiceBrowserPrivate::triggerRefresh() { - QMutexLocker l(mainConnection->lock()); - const qint64 msecDelay = 5100; - delayDeletesUntil = QDateTime::currentMSecsSinceEpoch() + msecDelay; - stopBrowsing(); - shouldRefresh = true; + { + QMutexLocker l(mainConnection->lock()); + const qint64 msecDelay = 5100; + delayDeletesUntil = QDateTime::currentMSecsSinceEpoch() + msecDelay; + stopBrowsing(); + shouldRefresh = true; + } + { + QMutexLocker l(mainConnection->mainThreadLock()); + if (!browsing) + refresh(); + } } void ServiceBrowserPrivate::refresh() @@ -1444,6 +1543,11 @@ void ServiceBrowserPrivate::hadFailure(const QList &messages) emit q->hadFailure(messages, q); } +void ServiceBrowserPrivate::startedBrowsing() +{ + emit q->startedBrowsing(q); +} + // ----------------- MainConnection impl ----------------- void MainConnection::stop(bool wait) @@ -1463,8 +1567,8 @@ void MainConnection::stop(bool wait) } MainConnection::MainConnection(): - lib(zeroConfLibInstance()->defaultLib()), m_lock(QMutex::Recursive), m_mainRef(0), - m_failed(false), m_status(Starting), m_nErrs(0) + lib(zeroConfLibInstance()->defaultLib()), m_lock(QMutex::Recursive), + m_mainThreadLock(QMutex::Recursive), m_mainRef(0), m_failed(false), m_status(Starting), m_nErrs(0) { if (lib.isNull()){ qDebug() << "could not load a valid library for ZeroConf::MainConnection, failing"; @@ -1505,6 +1609,11 @@ QMutex *MainConnection::lock() return &m_lock; } +QMutex *MainConnection::mainThreadLock() +{ + return &m_mainThreadLock; +} + void MainConnection::waitStartup() { int sAtt; @@ -1537,9 +1646,8 @@ void MainConnection::addBrowser(ServiceBrowserPrivate *browser) m_browsers.append(browser); errs = m_errors; } - if (actualStatus == Running) { - browser->internalStartBrowsing(); - } + if (actualStatus == Running && browser->internalStartBrowsing()) + browser->startedBrowsing(); bool didFail = false; foreach (const ErrorMessage &msg, errs) { browser->errorMessage(msg.severity, msg.msg); @@ -1620,7 +1728,7 @@ void MainConnection::createConnection() uint32_t size = (uint32_t)sizeof(uint32_t); DNSServiceErrorType err = lib->getProperty(kDNSServiceProperty_DaemonVersion, &version, &size); if (err == kDNSServiceErr_NoError){ - DNSServiceErrorType error = lib->createConnection(&m_mainRef); + DNSServiceErrorType error = lib->createConnection(this, &m_mainRef); if (error != kDNSServiceErr_NoError){ appendError(ErrorMessage::WarningLevel, tr("MainConnection using lib %1 failed the initialization of mainRef with error %2") .arg(lib->name()).arg(error)); @@ -1636,8 +1744,9 @@ void MainConnection::createConnection() } for (int i = waitingBrowsers.count(); i-- != 0; ){ ServiceBrowserPrivate *actualBrowser = waitingBrowsers[i]; - if (actualBrowser && !actualBrowser->browsing) - actualBrowser->internalStartBrowsing(); + if (actualBrowser && !actualBrowser->browsing + && actualBrowser->internalStartBrowsing()) + actualBrowser->startedBrowsing(); } break; } @@ -1672,11 +1781,11 @@ ZConfLib::RunLoopStatus MainConnection::handleEvent() nextEvent = bAtt->delayDeletesUntil; } if (nextEvent <= now) - nextEvent = 5000; + nextEvent = -1; else nextEvent -= now; maybeUpdateLists(); - ZConfLib::RunLoopStatus err = lib->processOneEvent(m_mainRef, nextEvent); + ZConfLib::RunLoopStatus err = lib->processOneEvent(this, m_mainRef, nextEvent); if (err != ZConfLib::ProcessedOk && err != ZConfLib::ProcessedIdle) { qDebug() << "processOneEvent returned " << err; ++m_nErrs; @@ -1715,6 +1824,7 @@ void MainConnection::handleEvents() #else while (m_status < Stopping) { #endif + QMutexLocker l(mainThreadLock()); if (m_nErrs > 10) increaseStatusTo(Stopping); switch (handleEvent()) { @@ -1821,45 +1931,50 @@ void ZConfLib::setError(bool failure, const QString &eMsg) m_isOk = !failure; } -ZConfLib::RunLoopStatus ZConfLib::processOneEvent(ConnectionRef cRef, qint64 maxMsBlock) +ZConfLib::RunLoopStatus ZConfLib::processOneEvent(MainConnection *mainConnection, + ConnectionRef cRef, qint64 maxMsBlock) { if (maxMsBlock < 0) { // just block - return processOneEventBlock(cRef); - } else { - // some stuff could be extracted for maximal performance - int dns_sd_fd = (cRef ? refSockFD(cRef) : -1); - int nfds = dns_sd_fd + 1; - fd_set readfds; - struct timeval tv; - int result; - dns_sd_fd = (cRef ? refSockFD(cRef) : -1); - if (dns_sd_fd < 0) - return ProcessedError; - nfds = dns_sd_fd + 1; - FD_ZERO(&readfds); - FD_SET(dns_sd_fd, &readfds); - - if (maxMsBlock > MAX_SEC_FOR_READ * static_cast(1000)) { - tv.tv_sec = MAX_SEC_FOR_READ; - tv.tv_usec = 0; - } else { - tv.tv_sec = static_cast(maxMsBlock / 1000); - tv.tv_usec = static_cast((maxMsBlock % 1000) * 1000); - } - result = select(nfds, &readfds, (fd_set *)NULL, (fd_set *)NULL, &tv); - if (result > 0) { - if (FD_ISSET(dns_sd_fd, &readfds)) - return processOneEventBlock(cRef); - } else if (result == 0) { - return ProcessedIdle; - } else if (errno != EINTR) { - if (DEBUG_ZEROCONF) - qDebug() << "select() returned " << result << " errno " << errno - << strerror(errno); - return ProcessedError; - } - return ProcessedIdle; // change? should never happen anyway + maxMsBlock = MAX_SEC_FOR_READ * static_cast(1000); } + // some stuff could be extracted for maximal performance + int dns_sd_fd = (cRef ? refSockFD(cRef) : -1); + int nfds = dns_sd_fd + 1; + fd_set readfds; + struct timeval tv; + int result; + dns_sd_fd = (cRef ? refSockFD(cRef) : -1); + if (dns_sd_fd < 0) + return ProcessedError; + nfds = dns_sd_fd + 1; + FD_ZERO(&readfds); + FD_SET(dns_sd_fd, &readfds); + + if (maxMsBlock > MAX_SEC_FOR_READ * static_cast(1000)) { + tv.tv_sec = MAX_SEC_FOR_READ; + tv.tv_usec = 0; + } else { + tv.tv_sec = static_cast(maxMsBlock / 1000); + tv.tv_usec = static_cast((maxMsBlock % 1000) * 1000); + } + QMutex *lock = (mainConnection ? mainConnection->mainThreadLock() : 0); + if (lock) + lock->unlock(); + result = select(nfds, &readfds, (fd_set *)NULL, (fd_set *)NULL, &tv); + if (lock) + lock->lock(); + if (result > 0) { + if (FD_ISSET(dns_sd_fd, &readfds)) + return processOneEventBlock(cRef); + } else if (result == 0) { + return ProcessedIdle; + } else if (errno != EINTR) { + if (DEBUG_ZEROCONF) + qDebug() << "select() returned " << result << " errno " << errno + << strerror(errno); + return ProcessedError; + } + return ProcessedIdle; // change? should never happen anyway } } // namespace Internal diff --git a/src/libs/zeroconf/servicebrowser.h b/src/libs/zeroconf/servicebrowser.h index 88f01ab4b2a..a3dfd338f91 100644 --- a/src/libs/zeroconf/servicebrowser.h +++ b/src/libs/zeroconf/servicebrowser.h @@ -39,6 +39,7 @@ #include #include #include +#include QT_FORWARD_DECLARE_CLASS(QHostInfo) @@ -99,6 +100,7 @@ public: const ServiceTxtRecord &txtRecord() const { return m_txtRecord; } const QHostInfo *host() const { return m_host; } int interfaceNr() const { return m_interfaceNr; } + bool operator==(const Service &o) const; bool invalidate() { bool res = m_outdated; m_outdated = true; return res; } private: @@ -114,6 +116,7 @@ private: }; ZEROCONFSHARED_EXPORT QDebug operator<<(QDebug dbg, const Service &service); +ZEROCONFSHARED_EXPORT QDebug operator<<(QDebug dbg, const Service::ConstPtr &service); class ZEROCONFSHARED_EXPORT ServiceBrowser : public QObject { @@ -133,7 +136,6 @@ public: void startBrowsing(qint32 interfaceIndex = 0); void stopBrowsing(); - void triggerRefresh(); bool isBrowsing() const; bool didFail() const; @@ -145,7 +147,11 @@ public: QList services() const; void reconfirmService(Service::ConstPtr service); +public slots: + void triggerRefresh(); + void autoRefresh(); signals: + void activateAutoRefresh(); void serviceChanged(const ZeroConf::Service::ConstPtr &oldService, const ZeroConf::Service::ConstPtr &newService, ZeroConf::ServiceBrowser *browser); void serviceAdded(const ZeroConf::Service::ConstPtr &service, @@ -155,7 +161,9 @@ signals: void servicesUpdated(ZeroConf::ServiceBrowser *browser); void errorMessage(ZeroConf::ErrorMessage::SeverityLevel severity, const QString &msg, ZeroConf::ServiceBrowser *browser); void hadFailure(const QList &messages, ZeroConf::ServiceBrowser *browser); + void startedBrowsing(ZeroConf::ServiceBrowser *browser); private: + QTimer *timer; Internal::ServiceBrowserPrivate *d; }; diff --git a/src/libs/zeroconf/servicebrowser_p.h b/src/libs/zeroconf/servicebrowser_p.h index 8cd880d18a1..1c1966df1be 100644 --- a/src/libs/zeroconf/servicebrowser_p.h +++ b/src/libs/zeroconf/servicebrowser_p.h @@ -109,8 +109,10 @@ public: ServiceBrowserPrivate *browser) = 0; virtual DNSServiceErrorType getProperty(const char *property, void *result, uint32_t *size) = 0; virtual RunLoopStatus processOneEventBlock(ConnectionRef sdRef) = 0; - virtual RunLoopStatus processOneEvent(ConnectionRef sdRef, qint64 maxMsBlock); - virtual DNSServiceErrorType createConnection(ConnectionRef *sdRef) = 0; + virtual RunLoopStatus processOneEvent(MainConnection *mainConnection, + ConnectionRef sdRef, qint64 maxMsBlock); + virtual DNSServiceErrorType createConnection(MainConnection *mainConnection, + ConnectionRef *sdRef) = 0; virtual void stopConnection(ConnectionRef cRef) = 0; virtual void destroyConnection(ConnectionRef *sdRef) = 0; virtual int refSockFD(ConnectionRef sdRef) = 0; @@ -154,7 +156,7 @@ public: }; QString fullName(); - void enactServiceChange(); + bool enactServiceChange(); void retireService(); Ptr gatherer(); @@ -232,6 +234,7 @@ public: MainConnection(); ~MainConnection(); QMutex *lock(); + QMutex *mainThreadLock(); void waitStartup(); void stop(bool wait = true); void addBrowser(ServiceBrowserPrivate *browser); @@ -253,7 +256,7 @@ public: private: void appendError(ErrorMessage::SeverityLevel severity, const QString &msg); - mutable QMutex m_lock; + mutable QMutex m_lock, m_mainThreadLock; QList m_browsers; ZConfLib::ConnectionRef m_mainRef; bool m_failed; @@ -309,6 +312,7 @@ public: uint32_t interfaceIndex, ZK_IP_Protocol proto, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain); + void activateAutoRefresh(); void serviceChanged(const Service::ConstPtr &oldService, const Service::ConstPtr &newService, ServiceBrowser *browser); void serviceAdded(const Service::ConstPtr &service, ServiceBrowser *browser); @@ -316,6 +320,7 @@ public: void servicesUpdated(ServiceBrowser *browser); void errorMessage(ErrorMessage::SeverityLevel severity, const QString &msg); void hadFailure(const QList &msgs); + void startedBrowsing(); }; class ConnectionThread: public QThread {