#if 0
#pragma mark Description
#endif
#if 0
#pragma mark -
#pragma mark Includes
#endif
#include <CFNetwork/CFNetwork.h>
#include <CFNetwork/CFNetworkPriv.h>
#include "CFNetworkInternal.h"
#include "CFNetworkSchedule.h"
#include <math.h>
#include <sys/socket.h>
#include <netdb_async.h>
#include <SystemConfiguration/SystemConfiguration.h>
#if 0
#pragma mark -
#pragma mark Constants
#endif
const SInt32 kCFStreamErrorDomainNetDB = 12;
const SInt32 kCFStreamErrorDomainSystemConfiguration = 13;
#define _kCFNullHostInfoType ((CFHostInfoType)0xFFFFFFFF)
#define _kCFHostIPv4Addresses ((CFHostInfoType)0x0000FFFE)
#define _kCFHostIPv6Addresses ((CFHostInfoType)0x0000FFFD)
#define _kCFHostMasterAddressLookup ((CFHostInfoType)0x0000FFFC)
#define _kCFHostByPassMasterAddressLookup ((CFHostInfoType)0x0000FFFB)
#define _kCFHostCacheMaxEntries 25
#define _kCFHostCacheTimeout ((CFTimeInterval)1.0)
#if 0
#pragma mark -
#pragma mark Constant Strings
#endif
#ifdef __CONSTANT_CFSTRINGS__
#define _kCFHostBlockingMode CFSTR("_kCFHostBlockingMode")
#define _kCFHostDescribeFormat CFSTR("<CFHost 0x%x>{info=%@}")
#else
static CONST_STRING_DECL(_kCFHostBlockingMode, "_kCFHostBlockingMode")
static CONST_STRING_DECL(_kCFHostDescribeFormat, "<CFHost 0x%x>{info=%@}")
#endif
#if 0
#pragma mark -
#pragma mark CFHost struct
#endif
typedef struct {
CFRuntimeBase _base;
CFSpinLock_t _lock;
CFStreamError _error;
CFMutableDictionaryRef _info;
CFTypeRef _lookup;
CFHostInfoType _type;
CFMutableArrayRef _schedules; CFHostClientCallBack _callback;
CFHostClientContext _client;
} _CFHost;
#if 0
#pragma mark -
#pragma mark Static Function Declarations
#endif
static void _CFHostRegisterClass(void);
static _CFHost* _HostCreate(CFAllocatorRef allocator);
static void _HostDestroy(_CFHost* host);
static CFStringRef _HostDescribe(_CFHost* host);
static void _HostCancel(_CFHost* host);
static Boolean _HostBlockUntilComplete(_CFHost* host);
static Boolean _CreateLookup_NoLock(_CFHost* host, CFHostInfoType info, Boolean* _Radar4012176);
static CFMachPortRef _CreateMasterAddressLookup(CFStringRef name, CFHostInfoType info, CFTypeRef context, CFStreamError* error);
static CFTypeRef _CreateAddressLookup(CFStringRef name, CFHostInfoType info, void* context, CFStreamError* error);
static CFMachPortRef _CreateNameLookup(CFDataRef address, void* context, CFStreamError* error);
static SCNetworkReachabilityRef _CreateReachabilityLookup(CFTypeRef thing, void* context, CFStreamError* error);
static CFMachPortRef _CreateDNSLookup(CFTypeRef thing, CFHostInfoType type, void* context, CFStreamError* error);
static void _GetAddrInfoCallBack(int32_t status, struct addrinfo* res, void* ctxt);
static void _GetAddrInfoMachPortCallBack(CFMachPortRef port, void* msg, CFIndex size, void* info);
static void _GetNameInfoCallBack(int32_t status, char *hostname, char *serv, void* ctxt);
static void _GetNameInfoMachPortCallBack(CFMachPortRef port, void* msg, CFIndex size, void* info);
static void _NetworkReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkConnectionFlags flags, void* ctxt);
static void _NetworkReachabilityByIPCallBack(_CFHost* host);
static void _DNSCallBack(int32_t status, char *buf, uint32_t len, struct sockaddr *from, int fromlen, void *context);
static void _DNSMachPortCallBack(CFMachPortRef port, void* msg, CFIndex size, void* info);
static void _MasterCallBack(CFHostRef theHost, CFHostInfoType typeInfo, const CFStreamError *error, CFStringRef name);
static void _AddressLookupSchedule_NoLock(_CFHost* host, CFRunLoopRef rl, CFStringRef mode);
static void _AddressLookupPerform(_CFHost* host);
static void _ExpireCacheEntries(void);
static CFArrayRef _CFArrayCreateDeepCopy(CFAllocatorRef alloc, CFArrayRef array);
static Boolean _IsDottedIp(CFStringRef name);
#if 0
#pragma mark -
#pragma mark Globals
#endif
static _CFOnceLock _kCFHostRegisterClass = _CFOnceInitializer;
static CFTypeID _kCFHostTypeID = _kCFRuntimeNotATypeID;
static _CFMutex* _HostLock;
static CFMutableDictionaryRef _HostLookups;
static CFMutableDictionaryRef _HostCache;
#if 0
#pragma mark -
#pragma mark Static Function Definitions
#endif
void
_CFHostRegisterClass(void) {
static const CFRuntimeClass _kCFHostClass = {
0, "CFHost", NULL, NULL, (void(*)(CFTypeRef))_HostDestroy, NULL, NULL, NULL, (CFStringRef(*)(CFTypeRef cf))_HostDescribe };
_kCFHostTypeID = _CFRuntimeRegisterClass(&_kCFHostClass);
_HostLock = (_CFMutex*)CFAllocatorAllocate(kCFAllocatorDefault, sizeof(_HostLock[0]), 0);
if (_HostLock) _CFMutexInit(_HostLock, FALSE);
_HostLookups = CFDictionaryCreateMutable(kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
_HostCache = CFDictionaryCreateMutable(kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
_CFHost*
_HostCreate(CFAllocatorRef allocator) {
CFDictionaryKeyCallBacks keys = {0, NULL, NULL, NULL, NULL, NULL};
_CFHost* result = (_CFHost*)_CFRuntimeCreateInstance(allocator,
CFHostGetTypeID(),
sizeof(result[0]) - sizeof(CFRuntimeBase),
NULL);
if (result) {
CFRuntimeBase copy = result->_base;
memset(result, 0, sizeof(result[0]));
memmove(&(result->_base), ©, sizeof(result->_base));
result->_type = _kCFNullHostInfoType;
result->_info = CFDictionaryCreateMutable(allocator, 0, &keys, &kCFTypeDictionaryValueCallBacks);
result->_schedules = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
if (!result->_info || !result->_schedules) {
CFRelease((CFTypeRef)result);
result = NULL;
}
}
return result;
}
void
_HostDestroy(_CFHost* host) {
__CFSpinLock(&(host->_lock));
if (host->_client.info && host->_client.release)
host->_client.release(host->_client.info);
if (host->_lookup) {
_CFTypeUnscheduleFromMultipleRunLoops(host->_lookup, host->_schedules);
_CFTypeInvalidate(host->_lookup);
CFRelease(host->_lookup);
}
if (host->_info)
CFRelease(host->_info);
if (host->_schedules)
CFRelease(host->_schedules);
}
CFStringRef
_HostDescribe(_CFHost* host) {
CFStringRef result;
__CFSpinLock(&host->_lock);
result = CFStringCreateWithFormat(CFGetAllocator((CFHostRef)host),
NULL,
_kCFHostDescribeFormat,
host,
host->_info);
__CFSpinUnlock(&host->_lock);
return result;
}
void
_HostCancel(_CFHost* host) {
CFHostClientCallBack cb = NULL;
CFStreamError error;
void* info = NULL;
CFHostInfoType type = _kCFNullHostInfoType;
CFRetain((CFHostRef)host);
__CFSpinLock(&host->_lock);
if (host->_lookup) {
cb = host->_callback;
type = host->_type;
memmove(&error, &(host->_error), sizeof(error));
info = host->_client.info;
_CFTypeUnscheduleFromMultipleRunLoops(host->_lookup, host->_schedules);
CFRunLoopSourceInvalidate((CFRunLoopSourceRef)(host->_lookup));
CFRelease(host->_lookup);
host->_lookup = NULL;
host->_type = _kCFNullHostInfoType;
}
__CFSpinUnlock(&host->_lock);
if (cb)
cb((CFHostRef)host, type, &error, info);
CFRelease((CFHostRef)host);
}
Boolean
_HostBlockUntilComplete(_CFHost* host) {
Boolean result = TRUE;
CFRunLoopRef rl = CFRunLoopGetCurrent();
CFHostScheduleWithRunLoop((CFHostRef)host, rl, _kCFHostBlockingMode);
__CFSpinLock(&(host->_lock));
while (host->_lookup) {
__CFSpinUnlock(&(host->_lock));
CFRunLoopRunInMode(_kCFHostBlockingMode, DBL_MAX, TRUE);
__CFSpinLock(&(host->_lock));
}
if (host->_error.error)
result = FALSE;
__CFSpinUnlock(&(host->_lock));
CFHostUnscheduleFromRunLoop((CFHostRef)host, rl, _kCFHostBlockingMode);
return result;
}
Boolean
_CreateLookup_NoLock(_CFHost* host, CFHostInfoType info, Boolean* _Radar4012176) {
Boolean result = FALSE;
CFArrayRef names = (CFArrayRef)CFDictionaryGetValue(host->_info, (const void*)kCFHostNames);
CFArrayRef addrs = (CFArrayRef)CFDictionaryGetValue(host->_info, (const void*)kCFHostAddresses);
CFStringRef name = names && ((CFTypeRef)names != kCFNull) && CFArrayGetCount(names) ? (CFStringRef)CFArrayGetValueAtIndex(names, 0) : NULL;
CFDataRef addr = addrs && ((CFTypeRef)addrs != kCFNull) && CFArrayGetCount(addrs) ? (CFDataRef)CFArrayGetValueAtIndex(addrs, 0) : NULL;
*_Radar4012176 = FALSE;
if (host->_lookup)
return result;
switch (info) {
case kCFHostAddresses:
if (name) {
CFArrayRef cached = NULL;
_ExpireCacheEntries();
_CFMutexLock(_HostLock);
if (_HostCache)
cached = (CFArrayRef)CFDictionaryGetValue(_HostCache, name);
if (cached)
CFRetain(cached);
_CFMutexUnlock(_HostLock);
if (!cached)
host->_lookup = _CreateAddressLookup(name, info, host, &(host->_error));
else {
CFAllocatorRef alloc = CFGetAllocator(name);
CFArrayRef cp = _CFArrayCreateDeepCopy(alloc,
CFHostGetInfo((CFHostRef)CFArrayGetValueAtIndex(cached, 0), _kCFHostMasterAddressLookup, NULL));
CFRunLoopSourceContext ctxt = {
0,
host,
CFRetain,
CFRelease,
CFCopyDescription,
NULL,
NULL,
NULL,
NULL,
(void (*)(void*))_AddressLookupPerform
};
host->_lookup = CFRunLoopSourceCreate(alloc, 0, &ctxt);
if (host->_lookup && cp) {
CFDictionaryAddValue(host->_info, (const void*)info, cp);
CFRunLoopSourceSignal((CFRunLoopSourceRef)host->_lookup);
*_Radar4012176 = TRUE;
}
else {
host->_error.error = ENOMEM;
host->_error.domain = kCFStreamErrorDomainPOSIX;
}
if (cp)
CFRelease(cp);
else if (host->_lookup) {
CFRelease(host->_lookup);
host->_lookup = NULL;
}
CFRelease(cached);
}
}
break;
case kCFHostNames:
if (addr) host->_lookup = _CreateNameLookup(addr, host, &(host->_error));
break;
case kCFHostReachability:
{
CFTypeRef use = (addr != NULL) ? (CFTypeRef)addr : (CFTypeRef)name;
host->_lookup = _CreateReachabilityLookup(use, host, &(host->_error));
if (host->_lookup && ((use == addr) || _IsDottedIp(use))) {
CFRunLoopSourceContext ctxt = {
0, host, NULL, NULL, NULL, NULL, NULL, NULL, NULL, (void(*)(void*))(&_NetworkReachabilityByIPCallBack) };
SCNetworkConnectionFlags flags = 0;
CFAllocatorRef alloc = CFGetAllocator(host);
SCNetworkReachabilityGetFlags((SCNetworkReachabilityRef)(host->_lookup), &flags);
SCNetworkReachabilitySetCallback((SCNetworkReachabilityRef)(host->_lookup), NULL, NULL);
CFRelease(host->_lookup);
host->_lookup = NULL;
host->_lookup = CFRunLoopSourceCreate(alloc, 0, &ctxt);
if (!host->_lookup) {
host->_error.error = ENOMEM;
host->_error.domain = kCFStreamErrorDomainPOSIX;
}
else {
CFDataRef reachability = CFDataCreate(alloc, (const UInt8*)&flags, sizeof(flags));
CFDictionaryRemoveValue(host->_info, (const void*)kCFHostReachability);
if (!reachability) {
CFRelease(host->_lookup);
host->_lookup = NULL;
host->_error.error = ENOMEM;
host->_error.domain = kCFStreamErrorDomainPOSIX;
}
else {
CFDictionaryAddValue(host->_info, (const void*)kCFHostReachability, reachability);
CFRelease(reachability);
CFRunLoopSourceSignal((CFRunLoopSourceRef)(host->_lookup));
}
}
}
}
break;
case 0x0000FFFC :
host->_lookup = _CreateMasterAddressLookup(name, info, host, &(host->_error));
break;
default:
if (name) {
if ((info == _kCFHostIPv4Addresses) || (info == _kCFHostIPv6Addresses) || (info == _kCFHostByPassMasterAddressLookup))
host->_lookup = _CreateMasterAddressLookup(name, info, host, &(host->_error));
else
host->_lookup = _CreateDNSLookup(name, info, host, &(host->_error));
}
else if (addr) {
name = _CFNetworkCFStringCreateWithCFDataAddress(CFGetAllocator(addr), addr);
if (name) {
host->_lookup = _CreateDNSLookup(name, info, host, &(host->_error));
CFRelease(name);
}
else {
host->_error.error = ENOMEM;
host->_error.domain = kCFStreamErrorDomainPOSIX;
}
}
break;
}
if (host->_lookup) {
host->_type = info;
result = TRUE;
}
return result;
}
CFMachPortRef
_CreateMasterAddressLookup(CFStringRef name, CFHostInfoType info, CFTypeRef context, CFStreamError* error) {
UInt8* buffer;
CFAllocatorRef allocator = CFGetAllocator(name);
CFIndex converted, length = CFStringGetLength(name);
CFMachPortRef result = NULL;
buffer = _CFStringGetOrCreateCString(allocator, name, NULL, &converted, kCFStringEncodingUTF8);
if (!buffer) {
error->error = ENOMEM;
error->domain = kCFStreamErrorDomainPOSIX;
return result;
}
if (converted != length) {
error->error = HOST_NOT_FOUND;
error->domain = (CFStreamErrorDomain)kCFStreamErrorDomainNetDB;
}
else {
struct addrinfo hints;
mach_port_t prt = MACH_PORT_NULL;
CFMachPortContext ctxt = {0, (void*)context, CFRetain, CFRelease, CFCopyDescription};
memset(&hints, 0, sizeof(hints));
#ifdef AI_PARALLEL
hints.ai_flags = AI_ADDRCONFIG | AI_PARALLEL;
#else
hints.ai_flags = AI_ADDRCONFIG;
#endif
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = (info == _kCFHostIPv4Addresses) ? AF_INET :
(info == _kCFHostIPv6Addresses) ? AF_INET6 : AF_UNSPEC;
error->error = getaddrinfo_async_start(&prt, (const char*)buffer, NULL, &hints, _GetAddrInfoCallBack, (void*)context);
if (!prt ||
!(result = CFMachPortCreateWithPort(allocator, prt, _GetAddrInfoMachPortCallBack, &ctxt, NULL)))
{
if (error->error) {
if (EAI_SYSTEM != error->error)
error->domain = (CFStreamErrorDomain)kCFStreamErrorDomainNetDB;
else {
error->error = errno;
error->domain = kCFStreamErrorDomainPOSIX;
}
}
else if (error->error = errno)
error->domain = (CFStreamErrorDomain)kCFStreamErrorDomainPOSIX;
else {
error->error = NETDB_INTERNAL;
error->domain = (CFStreamErrorDomain)kCFStreamErrorDomainNetDB;
}
}
}
CFAllocatorDeallocate(allocator, buffer);
return result;
}
CFTypeRef
_CreateAddressLookup(CFStringRef name, CFHostInfoType info, void* context, CFStreamError* error) {
CFTypeRef result = NULL;
memset(error, 0, sizeof(error[0]));
if (info == _kCFHostMasterAddressLookup)
result = _CreateMasterAddressLookup(name, info, context, error);
else {
CFHostRef host = NULL;
CFMutableArrayRef list = NULL;
_CFMutexLock(_HostLock);
list = (CFMutableArrayRef)CFDictionaryGetValue(_HostLookups, name);
if (list)
host = (CFHostRef)CFArrayGetValueAtIndex(list, 0);
else {
list = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
if (!list) {
error->error = ENOMEM;
error->domain = kCFStreamErrorDomainPOSIX;
}
else {
name = CFStringCreateCopy(kCFAllocatorDefault, name);
CFDictionaryAddValue(_HostLookups, name, list);
CFRelease(name);
CFRelease(list);
host = CFHostCreateWithName(kCFAllocatorDefault, name);
if (!host) {
error->error = ENOMEM;
error->domain = kCFStreamErrorDomainPOSIX;
}
else {
CFHostClientContext ctxt = {0, (void*)name, CFRetain, CFRelease, CFCopyDescription};
CFArrayAppendValue(list, host);
CFRelease(host);
CFHostSetClient(host, (CFHostClientCallBack)_MasterCallBack, &ctxt);
if (!CFHostStartInfoResolution(host, _kCFHostMasterAddressLookup, error)) {
CFHostSetClient(host, NULL, NULL);
CFDictionaryRemoveValue(_HostLookups, name);
}
}
}
}
if (!error->error) {
CFRunLoopSourceContext ctxt = {
0,
context,
CFRetain,
CFRelease,
CFCopyDescription,
NULL,
NULL,
(void (*)(void*, CFRunLoopRef, CFStringRef))_AddressLookupSchedule_NoLock,
NULL,
(void (*)(void*))_AddressLookupPerform
};
result = CFRunLoopSourceCreate(CFGetAllocator(name), 0, &ctxt);
if (result) {
CFArrayAppendValue(list, result);
}
else {
error->error = ENOMEM;
error->domain = kCFStreamErrorDomainPOSIX;
if (host && CFArrayGetCount(list) == 1) {
CFHostSetClient(host, NULL, NULL);
CFHostCancelInfoResolution(host, _kCFHostMasterAddressLookup);
CFDictionaryRemoveValue(_HostLookups, name);
}
}
}
_CFMutexUnlock(_HostLock);
}
return result;
}
CFMachPortRef
_CreateNameLookup(CFDataRef address, void* context, CFStreamError* error) {
mach_port_t prt = MACH_PORT_NULL;
CFMachPortRef result = NULL;
CFMachPortContext ctxt = {0, (void*)context, CFRetain, CFRelease, CFCopyDescription};
struct sockaddr* sa = (struct sockaddr*)CFDataGetBytePtr(address);
error->error = getnameinfo_async_start(&prt, sa, sa->sa_len, 0, _GetNameInfoCallBack, (void*)context);
if (!prt ||
!(result = CFMachPortCreateWithPort(CFGetAllocator(address), prt, _GetNameInfoMachPortCallBack, &ctxt, NULL)))
{
if (error->error) {
if (EAI_SYSTEM != error->error)
error->domain = (CFStreamErrorDomain)kCFStreamErrorDomainNetDB;
else {
error->error = errno;
error->domain = kCFStreamErrorDomainPOSIX;
}
}
else if (error->error = errno)
error->domain = (CFStreamErrorDomain)kCFStreamErrorDomainPOSIX;
else {
error->error = NETDB_INTERNAL;
error->domain = (CFStreamErrorDomain)kCFStreamErrorDomainNetDB;
}
}
return result;
}
SCNetworkReachabilityRef
_CreateReachabilityLookup(CFTypeRef thing, void* context, CFStreamError* error) {
SCNetworkReachabilityRef result = NULL;
if (CFGetTypeID(thing) == CFDataGetTypeID()) {
result = SCNetworkReachabilityCreateWithAddress(CFGetAllocator(thing),
(struct sockaddr*)CFDataGetBytePtr((CFDataRef)thing));
}
else {
UInt8* buffer;
CFAllocatorRef allocator = CFGetAllocator(thing);
CFIndex converted, length = CFStringGetLength((CFStringRef)thing);
buffer = _CFStringGetOrCreateCString(allocator, (CFStringRef)thing, NULL, &converted, kCFStringEncodingUTF8);
if (!buffer) {
error->error = ENOMEM;
error->domain = kCFStreamErrorDomainPOSIX;
return result;
}
if (converted != length) {
error->error = HOST_NOT_FOUND;
error->domain = (CFStreamErrorDomain)kCFStreamErrorDomainNetDB;
}
else {
result = SCNetworkReachabilityCreateWithName(allocator, (const char*)buffer);
}
CFAllocatorDeallocate(allocator, buffer);
}
if (result) {
SCNetworkReachabilityContext ctxt = {0, (void*)context, CFRetain, CFRelease, CFCopyDescription};
SCNetworkReachabilitySetCallback(result, _NetworkReachabilityCallBack, &ctxt);
}
else if (!error->error) {
error->error = errno;
if (error->error)
error->domain = (CFStreamErrorDomain)kCFStreamErrorDomainPOSIX;
}
return result;
}
CFMachPortRef
_CreateDNSLookup(CFTypeRef thing, CFHostInfoType type, void* context, CFStreamError* error) {
UInt8* buffer;
CFAllocatorRef allocator = CFGetAllocator(thing);
CFIndex converted, length = CFStringGetLength((CFStringRef)thing);
CFMachPortRef result = NULL;
buffer = _CFStringGetOrCreateCString(allocator, (CFStringRef)thing, NULL, &converted, kCFStringEncodingUTF8);
if (!buffer) {
error->error = ENOMEM;
error->domain = kCFStreamErrorDomainPOSIX;
return result;
}
if (converted != length) {
error->error = HOST_NOT_FOUND;
error->domain = (CFStreamErrorDomain)kCFStreamErrorDomainNetDB;
}
else {
mach_port_t prt = MACH_PORT_NULL;
CFMachPortContext ctxt = {0, (void*)context, CFRetain, CFRelease, CFCopyDescription};
error->error = dns_async_start(&prt, (const char*)buffer, ((type & 0xFFFF0000) >> 16), (type & 0x0000FFFF), 1, _DNSCallBack, (void*)context);
if (!prt ||
!(result = CFMachPortCreateWithPort(allocator, prt, _DNSMachPortCallBack, &ctxt, NULL)))
{
if (error->error) {
if (EAI_SYSTEM != error->error)
error->domain = (CFStreamErrorDomain)kCFStreamErrorDomainNetDB;
else {
error->error = errno;
error->domain = kCFStreamErrorDomainPOSIX;
}
}
else if (error->error = errno)
error->domain = (CFStreamErrorDomain)kCFStreamErrorDomainPOSIX;
else {
error->error = NETDB_INTERNAL;
error->domain = (CFStreamErrorDomain)kCFStreamErrorDomainNetDB;
}
}
}
CFAllocatorDeallocate(allocator, buffer);
return result;
}
void
_GetAddrInfoCallBack(int32_t status, struct addrinfo* res, void* ctxt) {
_CFHost* host = (_CFHost*)ctxt;
CFHostClientCallBack cb = NULL;
CFStreamError error;
void* info = NULL;
CFHostInfoType type = _kCFNullHostInfoType;
CFRetain((CFHostRef)host);
__CFSpinLock(&host->_lock);
if (host->_lookup) {
CFDictionaryRemoveValue(host->_info, (const void*)(host->_type));
if (status) {
if (EAI_SYSTEM == status) {
host->_error.error = errno;
host->_error.domain = kCFStreamErrorDomainPOSIX;
}
else {
host->_error.error = status;
host->_error.domain = (CFStreamErrorDomain)kCFStreamErrorDomainNetDB;
}
CFDictionaryAddValue(host->_info, (const void*)(host->_type), kCFNull);
}
else {
CFMutableArrayRef addrs;
CFAllocatorRef allocator = CFGetAllocator((CFHostRef)host);
addrs = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
if (!addrs) {
host->_error.error = ENOMEM;
host->_error.domain = kCFStreamErrorDomainPOSIX;
CFDictionaryAddValue(host->_info, (const void*)(host->_type), kCFNull);
}
else {
struct addrinfo* i;
for (i = res; i; i = i->ai_next) {
CFDataRef data;
if (i->ai_addr->sa_family != AF_INET && i->ai_addr->sa_family != AF_INET6)
continue;
data = CFDataCreate(allocator, (UInt8*)(i->ai_addr), i->ai_addr->sa_len);
if (!data) {
host->_error.error = ENOMEM;
host->_error.domain = kCFStreamErrorDomainPOSIX;
CFRelease(addrs);
addrs = NULL;
break;
}
CFArrayAppendValue(addrs, data);
CFRelease(data);
}
if (addrs) {
CFDictionaryAddValue(host->_info, (const void*)(host->_type), addrs);
CFRelease(addrs);
}
}
}
cb = host->_callback;
type = host->_type;
memmove(&error, &(host->_error), sizeof(error));
info = host->_client.info;
_CFTypeUnscheduleFromMultipleRunLoops(host->_lookup, host->_schedules);
CFMachPortInvalidate((CFMachPortRef)(host->_lookup));
CFRelease(host->_lookup);
host->_lookup = NULL;
host->_type = _kCFNullHostInfoType;
}
__CFSpinUnlock(&host->_lock);
if (res)
freeaddrinfo(res);
if (cb)
cb((CFHostRef)host, type, &error, info);
CFRelease((CFHostRef)host);
}
void
_GetAddrInfoMachPortCallBack(CFMachPortRef port, void* msg, CFIndex size, void* info) {
getaddrinfo_async_handle_reply(msg);
}
void
_GetNameInfoCallBack(int32_t status, char *hostname, char *serv, void* ctxt) {
_CFHost* host = (_CFHost*)ctxt;
CFHostClientCallBack cb = NULL;
CFStreamError error;
void* info = NULL;
CFRetain((CFHostRef)host);
__CFSpinLock(&host->_lock);
if (host->_lookup) {
CFDictionaryRemoveValue(host->_info, (const void*)kCFHostNames);
if (status) {
if (EAI_SYSTEM == status) {
host->_error.error = errno;
host->_error.error = kCFStreamErrorDomainPOSIX;
}
else {
host->_error.error = status;
host->_error.domain = (CFStreamErrorDomain)kCFStreamErrorDomainNetDB;
}
CFDictionaryAddValue(host->_info, (const void*)kCFHostNames, kCFNull);
}
else {
CFAllocatorRef allocator = CFGetAllocator((CFHostRef)host);
CFStringRef name = CFStringCreateWithCString(allocator, hostname, kCFStringEncodingUTF8);
if (!name) {
host->_error.error = ENOMEM;
host->_error.domain = kCFStreamErrorDomainPOSIX;
}
else {
CFArrayRef names = CFArrayCreate(allocator, (const void**)(&name), 1, &kCFTypeArrayCallBacks);
CFRelease(name);
if (!names) {
host->_error.error = ENOMEM;
host->_error.domain = kCFStreamErrorDomainPOSIX;
}
else {
CFDictionaryAddValue(host->_info, (const void*)kCFHostNames, names);
CFRelease(names);
}
}
}
cb = host->_callback;
memmove(&error, &(host->_error), sizeof(error));
info = host->_client.info;
_CFTypeUnscheduleFromMultipleRunLoops(host->_lookup, host->_schedules);
CFMachPortInvalidate((CFMachPortRef)(host->_lookup));
CFRelease(host->_lookup);
host->_lookup = NULL;
host->_type = _kCFNullHostInfoType;
}
__CFSpinUnlock(&host->_lock);
if (serv) free(serv);
if (hostname) free(hostname);
if (cb)
cb((CFHostRef)host, kCFHostNames, &error, info);
CFRelease((CFHostRef)host);
}
void
_GetNameInfoMachPortCallBack(CFMachPortRef port, void* msg, CFIndex size, void* info) {
getnameinfo_async_handle_reply(msg);
}
void
_NetworkReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkConnectionFlags flags, void* ctxt) {
_CFHost* host = (_CFHost*)ctxt;
CFHostClientCallBack cb = NULL;
CFStreamError error;
void* info = NULL;
CFRetain((CFHostRef)host);
__CFSpinLock(&host->_lock);
if (host->_lookup) {
CFDataRef reachability = CFDataCreate(CFGetAllocator(target), (const UInt8*)&flags, sizeof(flags));
CFDictionaryRemoveValue(host->_info, (const void*)kCFHostReachability);
if (!reachability) {
host->_error.error = ENOMEM;
host->_error.domain = kCFStreamErrorDomainPOSIX;
}
else {
CFDictionaryAddValue(host->_info, (const void*)kCFHostReachability, reachability);
CFRelease(reachability);
}
cb = host->_callback;
memmove(&error, &(host->_error), sizeof(error));
info = host->_client.info;
_CFTypeUnscheduleFromMultipleRunLoops(host->_lookup, host->_schedules);
SCNetworkReachabilitySetCallback((SCNetworkReachabilityRef)(host->_lookup), NULL, NULL);
CFRelease(host->_lookup);
host->_lookup = NULL;
host->_type = _kCFNullHostInfoType;
}
__CFSpinUnlock(&host->_lock);
if (cb)
cb((CFHostRef)host, kCFHostReachability, &error, info);
CFRelease((CFHostRef)host);
}
void
_NetworkReachabilityByIPCallBack(_CFHost* host) {
CFHostClientCallBack cb = NULL;
CFStreamError error;
void* info = NULL;
CFRetain((CFHostRef)host);
__CFSpinLock(&host->_lock);
if (host->_lookup) {
cb = host->_callback;
memmove(&error, &(host->_error), sizeof(error));
info = host->_client.info;
_CFTypeUnscheduleFromMultipleRunLoops(host->_lookup, host->_schedules);
CFRunLoopSourceInvalidate((CFRunLoopSourceRef)(host->_lookup));
CFRelease(host->_lookup);
host->_lookup = NULL;
host->_type = _kCFNullHostInfoType;
}
__CFSpinUnlock(&host->_lock);
if (cb)
cb((CFHostRef)host, kCFHostReachability, &error, info);
CFRelease((CFHostRef)host);
}
void
_DNSCallBack(int32_t status, char *buf, uint32_t len, struct sockaddr *from, int fromlen, void *context) {
_CFHost* host = (_CFHost*)context;
CFHostClientCallBack cb = NULL;
CFStreamError error;
void* info = NULL;
CFHostInfoType type = _kCFNullHostInfoType;
CFRetain((CFHostRef)context);
__CFSpinLock(&host->_lock);
if (host->_lookup) {
CFDictionaryRemoveValue(host->_info, (const void*)(host->_type));
if (status) {
if (EAI_SYSTEM == status) {
host->_error.error = errno;
host->_error.domain = kCFStreamErrorDomainPOSIX;
}
else {
host->_error.error = status;
host->_error.domain = (CFStreamErrorDomain)kCFStreamErrorDomainNetDB;
}
CFDictionaryAddValue(host->_info, (const void*)(host->_type), kCFNull);
}
else {
CFAllocatorRef allocator = CFGetAllocator((CFHostRef)context);
CFDataRef rr = CFDataCreate(allocator, (const UInt8*)buf, len);
CFDataRef sa = CFDataCreate(allocator, (const UInt8*)from, fromlen);
if (!rr || !sa) {
host->_error.error = ENOMEM;
host->_error.domain = kCFStreamErrorDomainPOSIX;
}
else {
CFTypeRef list[2] = {rr, sa};
CFArrayRef array = CFArrayCreate(allocator, list, sizeof(list) / sizeof(list[0]), &kCFTypeArrayCallBacks);
if (array) {
CFDictionaryAddValue(host->_info, (const void*)(host->_type), array);
CFRelease(array);
}
else {
host->_error.error = ENOMEM;
host->_error.domain = kCFStreamErrorDomainPOSIX;
}
}
if (rr)
CFRelease(rr);
if (sa)
CFRelease(sa);
}
cb = host->_callback;
type = host->_type;
memmove(&error, &(host->_error), sizeof(error));
info = host->_client.info;
_CFTypeUnscheduleFromMultipleRunLoops(host->_lookup, host->_schedules);
CFMachPortInvalidate((CFMachPortRef)(host->_lookup));
CFRelease(host->_lookup);
host->_lookup = NULL;
host->_type = _kCFNullHostInfoType;
}
__CFSpinUnlock(&host->_lock);
if (cb)
cb((CFHostRef)context, type, &error, info);
CFRelease((CFHostRef)context);
}
void
_DNSMachPortCallBack(CFMachPortRef port, void* msg, CFIndex size, void* info) {
dns_async_handle_reply(msg);
}
void
_MasterCallBack(CFHostRef theHost, CFHostInfoType typeInfo, const CFStreamError *error, CFStringRef name) {
CFArrayRef list;
CFHostSetClient(theHost, NULL, NULL);
_CFMutexLock(_HostLock);
list = CFDictionaryGetValue(_HostLookups, name);
if (list) {
CFRetain(list);
CFDictionaryRemoveValue(_HostLookups, name);
}
_CFMutexUnlock(_HostLock);
if (list) {
CFIndex i, count;
CFArrayRef addrs = CFHostGetInfo(theHost, _kCFHostMasterAddressLookup, NULL);
if (!error->error) {
CFArrayRef names = CFHostGetInfo(theHost, kCFHostNames, NULL);
if (names && ((CFTypeRef)names != kCFNull)) {
CFTypeRef orig[2] = {theHost, CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent())};
if (orig[1]) {
CFArrayRef items = CFArrayCreate(kCFAllocatorDefault, orig, sizeof(orig) / sizeof(orig[0]), &kCFTypeArrayCallBacks);
CFRelease(orig[1]);
if (items) {
count = CFArrayGetCount(names);
for (i = 0; i < count; i++)
CFDictionaryAddValue(_HostCache, CFArrayGetValueAtIndex(names, i), items);
CFRelease(items);
}
}
}
}
count = CFArrayGetCount(list);
for (i = 1; i < count; i++) {
_CFHost* client;
CFRunLoopSourceContext ctxt = {0};
CFRunLoopSourceRef src = (CFRunLoopSourceRef)CFArrayGetValueAtIndex(list, i);
CFRunLoopSourceGetContext(src, &ctxt);
client = (_CFHost*)ctxt.info;
__CFSpinLock(&client->_lock);
CFDictionaryRemoveValue(client->_info, (const void*)(client->_type));
if (error->error) {
memmove(&client->_error, error, sizeof(error[0]));
CFDictionaryAddValue(client->_info, (const void*)(client->_type), kCFNull);
}
else {
CFArrayRef cp = _CFArrayCreateDeepCopy(CFGetAllocator((CFHostRef)client), addrs);
if (cp) {
CFDictionaryAddValue(client->_info, (const void*)(client->_type), addrs);
CFRelease(cp);
}
else {
client->_error.error = ENOMEM;
client->_error.domain = kCFStreamErrorDomainPOSIX;
CFDictionaryAddValue(client->_info, (const void*)(client->_type), kCFNull);
}
}
CFRunLoopSourceSignal((CFRunLoopSourceRef)(client->_lookup));
CFArrayRef schedules = client->_schedules;
CFIndex j, c = CFArrayGetCount(schedules);
for (j = 0; j < c; j += 2) {
CFRunLoopRef runloop = (CFRunLoopRef)CFArrayGetValueAtIndex(schedules, j);
if (CFRunLoopIsWaiting(runloop)) {
CFStringRef mode = CFRunLoopCopyCurrentMode(runloop);
if (mode) {
if (CFRunLoopContainsSource(runloop, (CFRunLoopSourceRef)(client->_lookup), mode)) {
CFRunLoopWakeUp(runloop);
}
CFRelease(mode);
}
}
}
__CFSpinUnlock(&client->_lock);
}
CFRelease(list);
}
}
void
_AddressLookupSchedule_NoLock(_CFHost* host, CFRunLoopRef rl, CFStringRef mode) {
CFArrayRef list;
CFArrayRef names = (CFArrayRef)CFDictionaryGetValue(host->_info, (const void*)kCFHostNames);
CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, 0);
_CFMutexLock(_HostLock);
list = CFDictionaryGetValue(_HostLookups, name);
if (list)
CFHostScheduleWithRunLoop((CFHostRef)CFArrayGetValueAtIndex(list, 0), rl, mode);
_CFMutexUnlock(_HostLock);
}
void
_AddressLookupPerform(_CFHost* host) {
CFHostClientCallBack cb = NULL;
CFStreamError error;
void* info = NULL;
CFRetain((CFHostRef)host);
__CFSpinLock(&host->_lock);
cb = host->_callback;
memmove(&error, &(host->_error), sizeof(error));
info = host->_client.info;
_CFTypeUnscheduleFromMultipleRunLoops(host->_lookup, host->_schedules);
CFRunLoopSourceInvalidate((CFRunLoopSourceRef)(host->_lookup));
CFRelease(host->_lookup);
host->_lookup = NULL;
host->_type = _kCFNullHostInfoType;
__CFSpinUnlock(&host->_lock);
if (cb)
cb((CFHostRef)host, kCFHostAddresses, &error, info);
CFRelease((CFHostRef)host);
}
void
_ExpireCacheEntries(void) {
CFIndex count;
CFStringRef keys_buffer[_kCFHostCacheMaxEntries];
CFArrayRef values_buffer[_kCFHostCacheMaxEntries];
CFStringRef* keys = &keys_buffer[0];
CFArrayRef* values = &values_buffer[0];
_CFMutexLock(_HostLock);
if (_HostCache) {
count = CFDictionaryGetCount(_HostCache);
if (count > _kCFHostCacheMaxEntries) {
keys = (CFStringRef*)CFAllocatorAllocate(kCFAllocatorDefault, sizeof(keys[0]) * count, 0);
values = (CFArrayRef*)CFAllocatorAllocate(kCFAllocatorDefault, sizeof(values[0]) * count, 0);
}
if (keys && values) {
CFIndex i, j = 0;
CFTimeInterval oldest = 0.0;
CFDateRef now = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent());
CFDictionaryGetKeysAndValues(_HostCache, (const void **)keys, (const void **)values);
for (i = 0; i < count; i++) {
CFTimeInterval since = fabs(CFDateGetTimeIntervalSinceDate(now, (CFDateRef)CFArrayGetValueAtIndex(values[i], 1)));
if (since >= _kCFHostCacheTimeout)
CFDictionaryRemoveValue(_HostCache, keys[i]);
else if (since > oldest) {
j = i;
oldest = since;
}
}
CFRelease(now);
if (CFDictionaryGetCount(_HostCache) >= _kCFHostCacheMaxEntries)
CFDictionaryRemoveValue(_HostCache, keys[j]);
}
if (keys && (keys != &keys_buffer[0]))
CFAllocatorDeallocate(kCFAllocatorDefault, keys);
if (values && (values != &values_buffer[0]))
CFAllocatorDeallocate(kCFAllocatorDefault, values);
}
_CFMutexUnlock(_HostLock);
}
CFArrayRef
_CFArrayCreateDeepCopy(CFAllocatorRef alloc, CFArrayRef array) {
CFArrayRef result = NULL;
CFIndex i, c = CFArrayGetCount(array);
CFTypeRef *values;
if (c == 0) {
result = CFArrayCreate(alloc, NULL, 0, &kCFTypeArrayCallBacks);
} else if ((values = (CFTypeRef*)CFAllocatorAllocate(alloc, c*sizeof(CFTypeRef), 0)) != NULL) {
CFArrayGetValues(array, CFRangeMake(0, c), values);
if (CFGetTypeID(values[0]) == CFStringGetTypeID()) {
for (i = 0; i < c; i ++) {
values[i] = CFStringCreateCopy(alloc, (CFStringRef)values[i]);
if (values[i] == NULL) {
break;
}
}
}
else if (CFGetTypeID(values[0]) == CFDataGetTypeID()) {
for (i = 0; i < c; i ++) {
values[i] = CFDataCreateCopy(alloc, (CFDataRef)values[i]);
if (values[i] == NULL) {
break;
}
}
}
else {
for (i = 0; i < c; i ++) {
values[i] = CFPropertyListCreateDeepCopy(alloc, values[i], kCFPropertyListImmutable);
if (values[i] == NULL) {
break;
}
}
}
result = (i == c) ? CFArrayCreate(alloc, values, c, &kCFTypeArrayCallBacks) : NULL;
c = i;
for (i = 0; i < c; i ++) {
CFRelease(values[i]);
}
CFAllocatorDeallocate(alloc, values);
}
return result;
}
Boolean
_IsDottedIp(CFStringRef name) {
Boolean result = FALSE;
UInt8 stack_buffer[1024];
UInt8* buffer = stack_buffer;
CFIndex length = sizeof(stack_buffer);
CFAllocatorRef alloc = CFGetAllocator(name);
buffer = _CFStringGetOrCreateCString(alloc, name, buffer, &length, kCFStringEncodingASCII);
if (buffer) {
struct addrinfo hints;
struct addrinfo* results = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_NUMERICHOST;
if (!getaddrinfo((const char*)buffer, NULL, &hints, &results)) {
if (results) {
if (results->ai_addr)
result = TRUE;
freeaddrinfo(results);
}
}
}
if (buffer != stack_buffer)
CFAllocatorDeallocate(alloc, buffer);
return result;
}
#if 0
#pragma mark -
#pragma mark Extern Function Definitions (API)
#endif
CFTypeID
CFHostGetTypeID(void) {
_CFDoOnce(&_kCFHostRegisterClass, _CFHostRegisterClass);
return _kCFHostTypeID;
}
CFHostRef
CFHostCreateWithName(CFAllocatorRef allocator, CFStringRef hostname) {
_CFHost* result = _HostCreate(allocator);
if (result) {
CFArrayRef names = CFArrayCreate(allocator, (const void**)(&hostname), 1, &kCFTypeArrayCallBacks);
if (names) {
CFDictionaryAddValue(result->_info, (const void*)kCFHostNames, names);
CFRelease(names);
}
else {
CFRelease((CFTypeRef)result);
result = NULL;
}
}
return (CFHostRef)result;
}
CFHostRef
CFHostCreateWithAddress(CFAllocatorRef allocator, CFDataRef addr) {
_CFHost* result = _HostCreate(allocator);
if (result) {
CFArrayRef addrs = CFArrayCreate(allocator, (const void**)(&addr), 1, &kCFTypeArrayCallBacks);
if (addrs) {
CFDictionaryAddValue(result->_info, (const void*)kCFHostAddresses, addrs);
CFRelease(addrs);
}
else {
CFRelease((CFTypeRef)result);
result = NULL;
}
}
return (CFHostRef)result;
}
CFHostRef
CFHostCreateCopy(CFAllocatorRef allocator, CFHostRef h) {
_CFHost* host = (_CFHost*)h;
_CFHost* result = _HostCreate(allocator);
if (result) {
CFRelease(result->_info);
__CFSpinLock(&(host->_lock));
result->_info = CFDictionaryCreateMutableCopy(allocator, 0, host->_info);
__CFSpinUnlock(&(host->_lock));
if (!result->_info) {
CFRelease((CFTypeRef)result);
result = NULL;
}
}
return (CFHostRef)result;
}
Boolean
CFHostStartInfoResolution(CFHostRef theHost, CFHostInfoType info, CFStreamError* error) {
_CFHost* host = (_CFHost*)theHost;
CFStreamError extra;
Boolean result = FALSE;
if (!error)
error = &extra;
memset(error, 0, sizeof(error[0]));
CFRetain(theHost);
__CFSpinLock(&(host->_lock));
do {
Boolean wakeup = FALSE;
if (!_CreateLookup_NoLock(host, info, &wakeup))
break;
if (host->_callback) {
_CFTypeScheduleOnMultipleRunLoops(host->_lookup, host->_schedules);
if (wakeup) {
CFArrayRef schedules = host->_schedules;
CFIndex i, count = CFArrayGetCount(schedules);
for (i = 0; i < count; i += 2) {
CFRunLoopWakeUp((CFRunLoopRef)CFArrayGetValueAtIndex(schedules, i));
}
}
result = TRUE;
}
else {
__CFSpinUnlock(&(host->_lock));
result = _HostBlockUntilComplete(host);
__CFSpinLock(&(host->_lock));
}
} while (0);
memmove(error, &host->_error, sizeof(error[0]));
__CFSpinUnlock(&(host->_lock));
CFRelease(theHost);
return result;
}
CFTypeRef
CFHostGetInfo(CFHostRef theHost, CFHostInfoType info, Boolean* hasBeenResolved) {
_CFHost* host = (_CFHost*)theHost;
Boolean extra;
CFTypeRef result = NULL;
if (!hasBeenResolved)
hasBeenResolved = &extra;
*hasBeenResolved = FALSE;
__CFSpinLock(&(host->_lock));
result = (CFTypeRef)CFDictionaryGetValue(host->_info, (const void*)info);
if (result) {
if (CFEqual(result, kCFNull))
result = NULL;
*hasBeenResolved = TRUE;
}
__CFSpinUnlock(&(host->_lock));
return result;
}
CFArrayRef
CFHostGetAddressing(CFHostRef theHost, Boolean* hasBeenResolved) {
return (CFArrayRef)CFHostGetInfo(theHost, kCFHostAddresses, hasBeenResolved);
}
CFArrayRef
CFHostGetNames(CFHostRef theHost, Boolean* hasBeenResolved) {
return (CFArrayRef)CFHostGetInfo(theHost, kCFHostNames, hasBeenResolved);
}
#if defined(__MACH__)
CFDataRef
CFHostGetReachability(CFHostRef theHost, Boolean* hasBeenResolved) {
return (CFDataRef)CFHostGetInfo(theHost, kCFHostReachability, hasBeenResolved);
}
#endif
void
CFHostCancelInfoResolution(CFHostRef theHost, CFHostInfoType info) {
_CFHost* host = (_CFHost*)theHost;
__CFSpinLock(&(host->_lock));
if (host->_lookup) {
CFRunLoopSourceContext ctxt = {
0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, (void(*)(void*))(&_HostCancel) };
_CFTypeUnscheduleFromMultipleRunLoops(host->_lookup, host->_schedules);
_CFTypeInvalidate(host->_lookup);
if (host->_type == kCFHostAddresses) {
CFMutableArrayRef list;
CFArrayRef names = (CFArrayRef)CFDictionaryGetValue(host->_info, (const void*)kCFHostNames);
CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, 0);
_CFMutexLock(_HostLock);
list = (CFMutableArrayRef)CFDictionaryGetValue(_HostLookups, name);
if (list) {
CFIndex count = CFArrayGetCount(list);
CFIndex idx = CFArrayGetFirstIndexOfValue(list, CFRangeMake(0, count), host->_lookup);
if (idx != kCFNotFound) {
CFArrayRemoveValueAtIndex(list, idx);
if (count == 2) {
CFHostRef lookup = (CFHostRef)CFArrayGetValueAtIndex(list, 0);
CFHostSetClient(lookup, NULL, NULL);
CFHostCancelInfoResolution(lookup, _kCFHostMasterAddressLookup);
CFDictionaryRemoveValue(_HostLookups, name);
}
}
}
_CFMutexUnlock(_HostLock);
}
CFRelease(host->_lookup);
host->_lookup = CFRunLoopSourceCreate(CFGetAllocator(theHost), 0, &ctxt);
if (host->_lookup) {
CFArrayRef schedules = host->_schedules;
CFIndex i, count = CFArrayGetCount(schedules);
_CFTypeScheduleOnMultipleRunLoops(host->_lookup, schedules);
CFRunLoopSourceSignal((CFRunLoopSourceRef)(host->_lookup));
for (i = 0; i < count; i += 2) {
CFRunLoopRef runloop = (CFRunLoopRef)CFArrayGetValueAtIndex(schedules, i);
if (CFRunLoopIsWaiting(runloop)) {
CFStringRef mode = CFRunLoopCopyCurrentMode(runloop);
if (mode) {
if (CFRunLoopContainsSource(runloop, (CFRunLoopSourceRef)(host->_lookup), mode)) {
CFRunLoopWakeUp(runloop);
}
CFRelease(mode);
}
}
}
}
}
__CFSpinUnlock(&(host->_lock));
}
Boolean
CFHostSetClient(CFHostRef theHost, CFHostClientCallBack clientCB, CFHostClientContext* clientContext) {
_CFHost* host = (_CFHost*)theHost;
__CFSpinLock(&(host->_lock));
if (host->_client.info && host->_client.release)
host->_client.release(host->_client.info);
if (!clientCB || !clientContext) {
if (host->_lookup) {
_CFTypeUnscheduleFromMultipleRunLoops(host->_lookup, host->_schedules);
_CFTypeInvalidate(host->_lookup);
if (host->_type == kCFHostAddresses) {
CFMutableArrayRef list;
CFArrayRef names = (CFArrayRef)CFDictionaryGetValue(host->_info, (const void*)kCFHostNames);
CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, 0);
_CFMutexLock(_HostLock);
list = (CFMutableArrayRef)CFDictionaryGetValue(_HostLookups, name);
if (list) {
CFIndex count = CFArrayGetCount(list);
CFIndex idx = CFArrayGetFirstIndexOfValue(list, CFRangeMake(0, count), host->_lookup);
if (idx != kCFNotFound) {
CFArrayRemoveValueAtIndex(list, idx);
if (count == 2) {
CFHostRef lookup = (CFHostRef)CFArrayGetValueAtIndex(list, 0);
CFHostSetClient(lookup, NULL, NULL);
CFHostCancelInfoResolution(lookup, _kCFHostMasterAddressLookup);
CFDictionaryRemoveValue(_HostLookups, name);
}
}
}
_CFMutexUnlock(_HostLock);
}
CFRelease(host->_lookup);
host->_lookup = NULL;
host->_type = _kCFNullHostInfoType;
}
host->_callback = NULL;
memset(&(host->_client), 0, sizeof(host->_client));
}
else {
if (!host->_callback && host->_lookup)
_CFTypeScheduleOnMultipleRunLoops(host->_lookup, host->_schedules);
host->_callback = clientCB;
memmove(&(host->_client), clientContext, sizeof(host->_client));
if (host->_client.info && host->_client.retain)
host->_client.info = (void*)(host->_client.retain(host->_client.info));
}
__CFSpinUnlock(&(host->_lock));
return TRUE;
}
void
CFHostScheduleWithRunLoop(CFHostRef theHost, CFRunLoopRef runLoop, CFStringRef runLoopMode) {
_CFHost* host = (_CFHost*)theHost;
__CFSpinLock(&(host->_lock));
if (_SchedulesAddRunLoopAndMode(host->_schedules, runLoop, runLoopMode)) {
if (host->_lookup) {
_CFTypeScheduleOnRunLoop(host->_lookup, runLoop, runLoopMode);
}
}
__CFSpinUnlock(&(host->_lock));
}
void
CFHostUnscheduleFromRunLoop(CFHostRef theHost, CFRunLoopRef runLoop, CFStringRef runLoopMode) {
_CFHost* host = (_CFHost*)theHost;
__CFSpinLock(&(host->_lock));
if (_SchedulesRemoveRunLoopAndMode(host->_schedules, runLoop, runLoopMode)) {
if (host->_lookup) {
_CFTypeUnscheduleFromRunLoop(host->_lookup, runLoop, runLoopMode);
}
}
__CFSpinUnlock(&(host->_lock));
}