#define NEW_SOCKET 0
#if NEW_SOCKET
#else
#include <CoreFoundation/CFSocket.h>
#include <sys/types.h>
#include <math.h>
#include <limits.h>
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
#include <sys/sysctl.h>
#include <sys/un.h>
#include <libc.h>
#include <dlfcn.h>
#endif
#include <CoreFoundation/CFArray.h>
#include <CoreFoundation/CFData.h>
#include <CoreFoundation/CFDictionary.h>
#include <CoreFoundation/CFRunLoop.h>
#include <CoreFoundation/CFString.h>
#include <CoreFoundation/CFPropertyList.h>
#include "CFInternal.h"
#if DEPLOYMENT_TARGET_WINDOWS
#define EINPROGRESS WSAEINPROGRESS
#undef EBADF
#define EBADF WSAENOTSOCK
#define NBBY 8
#define NFDBITS (sizeof(int32_t) * NBBY)
typedef int32_t fd_mask;
typedef int socklen_t;
#define gettimeofday _NS_gettimeofday
__private_extern__ int _NS_gettimeofday(struct timeval *tv, struct timezone *tz);
#define timersub(tvp, uvp, vvp) \
do { \
(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
if ((vvp)->tv_usec < 0) { \
(vvp)->tv_sec--; \
(vvp)->tv_usec += 1000000; \
} \
} while (0)
#endif // DEPLOYMENT_TARGET_WINDOWS
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
#define INVALID_SOCKET (CFSocketNativeHandle)(-1)
#define closesocket(a) close((a))
#define ioctlsocket(a,b,c) ioctl((a),(b),(c))
#endif
CF_INLINE int __CFSocketLastError(void) {
#if DEPLOYMENT_TARGET_WINDOWS
return WSAGetLastError();
#else
return thread_errno();
#endif
}
CF_INLINE CFIndex __CFSocketFdGetSize(CFDataRef fdSet) {
return NBBY * CFDataGetLength(fdSet);
}
CF_INLINE Boolean __CFSocketFdSet(CFSocketNativeHandle sock, CFMutableDataRef fdSet) {
Boolean retval = false;
if (INVALID_SOCKET != sock && 0 <= sock) {
CFIndex numFds = NBBY * CFDataGetLength(fdSet);
fd_mask *fds_bits;
if (sock >= numFds) {
CFIndex oldSize = numFds / NFDBITS, newSize = (sock + NFDBITS) / NFDBITS, changeInBytes = (newSize - oldSize) * sizeof(fd_mask);
CFDataIncreaseLength(fdSet, changeInBytes);
fds_bits = (fd_mask *)CFDataGetMutableBytePtr(fdSet);
memset(fds_bits + oldSize, 0, changeInBytes);
} else {
fds_bits = (fd_mask *)CFDataGetMutableBytePtr(fdSet);
}
if (!FD_ISSET(sock, (fd_set *)fds_bits)) {
retval = true;
FD_SET(sock, (fd_set *)fds_bits);
}
}
return retval;
}
#define MAX_SOCKADDR_LEN 256
#define MAX_DATA_SIZE 65535
#define MAX_CONNECTION_ORIENTED_DATA_SIZE 32768
static CFSpinLock_t __CFAllSocketsLock = CFSpinLockInit;
static CFMutableDictionaryRef __CFAllSockets = NULL;
static CFSpinLock_t __CFActiveSocketsLock = CFSpinLockInit;
static volatile UInt32 __CFSocketManagerIteration = 0;
static CFMutableArrayRef __CFWriteSockets = NULL;
static CFMutableArrayRef __CFReadSockets = NULL;
static CFMutableDataRef __CFWriteSocketsFds = NULL;
static CFMutableDataRef __CFReadSocketsFds = NULL;
static CFDataRef zeroLengthData = NULL;
static Boolean __CFReadSocketsTimeoutInvalid = true;
static CFSocketNativeHandle __CFWakeupSocketPair[2] = {INVALID_SOCKET, INVALID_SOCKET};
static void *__CFSocketManagerThread = NULL;
static void __CFSocketDoCallback(CFSocketRef s, CFDataRef data, CFDataRef address, CFSocketNativeHandle sock);
struct __CFSocket {
CFRuntimeBase _base;
struct {
unsigned client:8; unsigned disabled:8; unsigned connected:1; unsigned writableHint:1; unsigned closeSignaled:1; unsigned unused:13;
} _f;
CFSpinLock_t _lock;
CFSpinLock_t _writeLock;
CFSocketNativeHandle _socket;
SInt32 _socketType;
SInt32 _errorCode;
CFDataRef _address;
CFDataRef _peerAddress;
SInt32 _socketSetCount;
CFRunLoopSourceRef _source0; CFMutableArrayRef _runLoops;
CFSocketCallBack _callout;
CFSocketContext _context;
CFMutableArrayRef _dataQueue; CFMutableArrayRef _addressQueue;
struct timeval _readBufferTimeout;
CFMutableDataRef _readBuffer;
CFIndex _bytesToBuffer;
CFIndex _bytesToBufferPos;
CFIndex _bytesToBufferReadPos;
Boolean _atEOF;
int _bufferedReadError;
CFMutableDataRef _leftoverBytes;
};
CF_INLINE Boolean __CFSocketIsWriteSignalled(CFSocketRef s) {
return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 6, 6);
}
CF_INLINE void __CFSocketSetWriteSignalled(CFSocketRef s) {
__CFBitfieldSetValue(((CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 6, 6, 1);
}
CF_INLINE void __CFSocketUnsetWriteSignalled(CFSocketRef s) {
__CFBitfieldSetValue(((CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 6, 6, 0);
}
CF_INLINE Boolean __CFSocketIsReadSignalled(CFSocketRef s) {
return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 5, 5);
}
CF_INLINE void __CFSocketSetReadSignalled(CFSocketRef s) {
__CFBitfieldSetValue(((CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 5, 5, 1);
}
CF_INLINE void __CFSocketUnsetReadSignalled(CFSocketRef s) {
__CFBitfieldSetValue(((CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 5, 5, 0);
}
CF_INLINE Boolean __CFSocketIsValid(CFSocketRef s) {
return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 4, 4);
}
CF_INLINE void __CFSocketSetValid(CFSocketRef s) {
__CFBitfieldSetValue(((CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 4, 4, 1);
}
CF_INLINE void __CFSocketUnsetValid(CFSocketRef s) {
__CFBitfieldSetValue(((CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 4, 4, 0);
}
CF_INLINE uint8_t __CFSocketCallBackTypes(CFSocketRef s) {
return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 3, 0);
}
CF_INLINE uint8_t __CFSocketReadCallBackType(CFSocketRef s) {
return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 1, 0);
}
CF_INLINE void __CFSocketSetCallBackTypes(CFSocketRef s, uint8_t types) {
__CFBitfieldSetValue(((CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 3, 0, types & 0xF);
}
CF_INLINE void __CFSocketLock(CFSocketRef s) {
__CFSpinLock(&(s->_lock));
}
CF_INLINE void __CFSocketUnlock(CFSocketRef s) {
__CFSpinUnlock(&(s->_lock));
}
CF_INLINE Boolean __CFSocketIsConnectionOriented(CFSocketRef s) {
return (SOCK_STREAM == s->_socketType || SOCK_SEQPACKET == s->_socketType);
}
CF_INLINE Boolean __CFSocketIsScheduled(CFSocketRef s) {
return (s->_socketSetCount > 0);
}
CF_INLINE void __CFSocketEstablishAddress(CFSocketRef s) {
uint8_t name[MAX_SOCKADDR_LEN];
int namelen = sizeof(name);
if (__CFSocketIsValid(s) && NULL == s->_address && INVALID_SOCKET != s->_socket && 0 == getsockname(s->_socket, (struct sockaddr *)name, (socklen_t *)&namelen) && NULL != name && 0 < namelen) {
s->_address = CFDataCreate(CFGetAllocator(s), name, namelen);
}
}
CF_INLINE void __CFSocketEstablishPeerAddress(CFSocketRef s) {
uint8_t name[MAX_SOCKADDR_LEN];
int namelen = sizeof(name);
if (__CFSocketIsValid(s) && NULL == s->_peerAddress && INVALID_SOCKET != s->_socket && 0 == getpeername(s->_socket, (struct sockaddr *)name, (socklen_t *)&namelen) && NULL != name && 0 < namelen) {
s->_peerAddress = CFDataCreate(CFGetAllocator(s), name, namelen);
}
}
static Boolean __CFNativeSocketIsValid(CFSocketNativeHandle sock) {
#if DEPLOYMENT_TARGET_WINDOWS
SInt32 errorCode = 0;
int errorSize = sizeof(errorCode);
return !(0 != getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&errorCode, &errorSize) && __CFSocketLastError() == WSAENOTSOCK);
#else
SInt32 flags = fcntl(sock, F_GETFL, 0);
return !(0 > flags && EBADF == __CFSocketLastError());
#endif
}
CF_INLINE Boolean __CFSocketFdClr(CFSocketNativeHandle sock, CFMutableDataRef fdSet) {
Boolean retval = false;
if (INVALID_SOCKET != sock && 0 <= sock) {
CFIndex numFds = NBBY * CFDataGetLength(fdSet);
fd_mask *fds_bits;
if (sock < numFds) {
fds_bits = (fd_mask *)CFDataGetMutableBytePtr(fdSet);
if (FD_ISSET(sock, (fd_set *)fds_bits)) {
retval = true;
FD_CLR(sock, (fd_set *)fds_bits);
}
}
}
return retval;
}
static SInt32 __CFSocketCreateWakeupSocketPair(void) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
SInt32 error;
error = socketpair(PF_LOCAL, SOCK_DGRAM, 0, __CFWakeupSocketPair);
if (0 <= error) error = fcntl(__CFWakeupSocketPair[0], F_SETFD, FD_CLOEXEC);
if (0 <= error) error = fcntl(__CFWakeupSocketPair[1], F_SETFD, FD_CLOEXEC);
if (0 > error) {
closesocket(__CFWakeupSocketPair[0]);
closesocket(__CFWakeupSocketPair[1]);
__CFWakeupSocketPair[0] = INVALID_SOCKET;
__CFWakeupSocketPair[1] = INVALID_SOCKET;
}
#else
UInt32 i;
SInt32 error = 0;
struct sockaddr_in address[2];
int namelen = sizeof(struct sockaddr_in);
for (i = 0; i < 2; i++) {
__CFWakeupSocketPair[i] = socket(PF_INET, SOCK_DGRAM, 0);
memset(&(address[i]), 0, sizeof(struct sockaddr_in));
address[i].sin_family = AF_INET;
address[i].sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (0 <= error) error = bind(__CFWakeupSocketPair[i], (struct sockaddr *)&(address[i]), sizeof(struct sockaddr_in));
if (0 <= error) error = getsockname(__CFWakeupSocketPair[i], (struct sockaddr *)&(address[i]), &namelen);
if (sizeof(struct sockaddr_in) != namelen) error = -1;
}
if (0 <= error) error = connect(__CFWakeupSocketPair[0], (struct sockaddr *)&(address[1]), sizeof(struct sockaddr_in));
if (0 <= error) error = connect(__CFWakeupSocketPair[1], (struct sockaddr *)&(address[0]), sizeof(struct sockaddr_in));
if (0 > error) {
closesocket(__CFWakeupSocketPair[0]);
closesocket(__CFWakeupSocketPair[1]);
__CFWakeupSocketPair[0] = INVALID_SOCKET;
__CFWakeupSocketPair[1] = INVALID_SOCKET;
}
#endif
#if defined(LOG_CFSOCKET)
fprintf(stdout, "wakeup socket pair is %d / %d\n", __CFWakeupSocketPair[0], __CFWakeupSocketPair[1]);
#endif
return error;
}
CF_INLINE Boolean __CFSocketSetFDForRead(CFSocketRef s) {
__CFReadSocketsTimeoutInvalid = true;
Boolean b = __CFSocketFdSet(s->_socket, __CFReadSocketsFds);
if (b && INVALID_SOCKET != __CFWakeupSocketPair[0]) {
uint8_t c = 'r';
send(__CFWakeupSocketPair[0], (const char *)&c, sizeof(c), 0);
}
return b;
}
CF_INLINE Boolean __CFSocketClearFDForRead(CFSocketRef s) {
__CFReadSocketsTimeoutInvalid = true;
Boolean b = __CFSocketFdClr(s->_socket, __CFReadSocketsFds);
if (b && INVALID_SOCKET != __CFWakeupSocketPair[0]) {
uint8_t c = 's';
send(__CFWakeupSocketPair[0], (const char *)&c, sizeof(c), 0);
}
return b;
}
CF_INLINE Boolean __CFSocketSetFDForWrite(CFSocketRef s) {
Boolean b = __CFSocketFdSet(s->_socket, __CFWriteSocketsFds);
if (b && INVALID_SOCKET != __CFWakeupSocketPair[0]) {
uint8_t c = 'w';
send(__CFWakeupSocketPair[0], (const char *)&c, sizeof(c), 0);
}
return b;
}
CF_INLINE Boolean __CFSocketClearFDForWrite(CFSocketRef s) {
Boolean b = __CFSocketFdClr(s->_socket, __CFWriteSocketsFds);
if (b && INVALID_SOCKET != __CFWakeupSocketPair[0]) {
uint8_t c = 'x';
send(__CFWakeupSocketPair[0], (const char *)&c, sizeof(c), 0);
}
return b;
}
#if DEPLOYMENT_TARGET_WINDOWS
static Boolean WinSockUsed = FALSE;
static void __CFSocketInitializeWinSock_Guts(void) {
if (!WinSockUsed) {
WinSockUsed = TRUE;
WORD versionRequested = MAKEWORD(2, 2);
WSADATA wsaData;
int errorStatus = WSAStartup(versionRequested, &wsaData);
if (errorStatus != 0 || LOBYTE(wsaData.wVersion) != LOBYTE(versionRequested) || HIBYTE(wsaData.wVersion) != HIBYTE(versionRequested)) {
WSACleanup();
CFLog(kCFLogLevelWarning, CFSTR("*** Could not initialize WinSock subsystem!!!"));
}
}
}
CF_EXPORT void __CFSocketInitializeWinSock(void) {
__CFSpinLock(&__CFActiveSocketsLock);
__CFSocketInitializeWinSock_Guts();
__CFSpinUnlock(&__CFActiveSocketsLock);
}
__private_extern__ void __CFSocketCleanup(void) {
if (INVALID_SOCKET != __CFWakeupSocketPair[0]) {
closesocket(__CFWakeupSocketPair[0]);
__CFWakeupSocketPair[0] = INVALID_SOCKET;
}
if (INVALID_SOCKET != __CFWakeupSocketPair[1]) {
closesocket(__CFWakeupSocketPair[1]);
__CFWakeupSocketPair[1] = INVALID_SOCKET;
}
if (WinSockUsed) {
WSACleanup();
}
}
#endif
static void __CFSocketInitializeSockets(void) {
__CFWriteSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, NULL);
__CFReadSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, NULL);
__CFWriteSocketsFds = CFDataCreateMutable(kCFAllocatorSystemDefault, 0);
__CFReadSocketsFds = CFDataCreateMutable(kCFAllocatorSystemDefault, 0);
zeroLengthData = CFDataCreateMutable(kCFAllocatorSystemDefault, 0);
#if DEPLOYMENT_TARGET_WINDOWS
__CFSocketInitializeWinSock_Guts();
#endif
if (0 > __CFSocketCreateWakeupSocketPair()) {
CFLog(kCFLogLevelWarning, CFSTR("*** Could not create wakeup socket pair for CFSocket!!!"));
} else {
UInt32 yes = 1;
ioctlsocket(__CFWakeupSocketPair[0], FIONBIO, (u_long *)&yes);
ioctlsocket(__CFWakeupSocketPair[1], FIONBIO, (u_long *)&yes);
__CFSocketFdSet(__CFWakeupSocketPair[1], __CFReadSocketsFds);
}
}
static CFRunLoopRef __CFSocketCopyRunLoopToWakeUp(CFRunLoopSourceRef src, CFMutableArrayRef runLoops) {
if (!src) return NULL;
CFRunLoopRef rl = NULL;
SInt32 idx, cnt = CFArrayGetCount(runLoops);
if (0 < cnt) {
rl = (CFRunLoopRef)CFArrayGetValueAtIndex(runLoops, 0);
for (idx = 1; NULL != rl && idx < cnt; idx++) {
CFRunLoopRef value = (CFRunLoopRef)CFArrayGetValueAtIndex(runLoops, idx);
if (value != rl) rl = NULL;
}
if (NULL == rl) {
Boolean foundIt = false, foundBackup = false;
SInt32 foundIdx = 0;
for (idx = 0; !foundIt && idx < cnt; idx++) {
CFRunLoopRef value = (CFRunLoopRef)CFArrayGetValueAtIndex(runLoops, idx);
CFStringRef currentMode = CFRunLoopCopyCurrentMode(value);
if (NULL != currentMode) {
if (CFRunLoopContainsSource(value, src, currentMode)) {
if (CFRunLoopIsWaiting(value)) {
foundIdx = idx;
foundIt = true;
} else if (!foundBackup) {
foundIdx = idx;
foundBackup = true;
}
}
CFRelease(currentMode);
}
}
rl = (CFRunLoopRef)CFArrayGetValueAtIndex(runLoops, foundIdx);
CFRetain(rl);
CFArrayRemoveValueAtIndex(runLoops, foundIdx);
CFArrayAppendValue(runLoops, rl);
} else {
CFRetain(rl);
}
}
return rl;
}
static void __CFSocketHandleWrite(CFSocketRef s, Boolean callBackNow) {
SInt32 errorCode = 0;
int errorSize = sizeof(errorCode);
CFOptionFlags writeCallBacksAvailable;
if (!CFSocketIsValid(s)) return;
if (0 != (s->_f.client & kCFSocketLeaveErrors) || 0 != getsockopt(s->_socket, SOL_SOCKET, SO_ERROR, (char *)&errorCode, (socklen_t *)&errorSize)) errorCode = 0;
#if defined(LOG_CFSOCKET)
if (errorCode) fprintf(stdout, "error %ld on socket %d\n", (long)errorCode, s->_socket);
#endif
__CFSocketLock(s);
writeCallBacksAvailable = __CFSocketCallBackTypes(s) & (kCFSocketWriteCallBack | kCFSocketConnectCallBack);
if ((s->_f.client & kCFSocketConnectCallBack) != 0) writeCallBacksAvailable &= ~kCFSocketConnectCallBack;
if (!__CFSocketIsValid(s) || ((s->_f.disabled & writeCallBacksAvailable) == writeCallBacksAvailable)) {
__CFSocketUnlock(s);
return;
}
s->_errorCode = errorCode;
__CFSocketSetWriteSignalled(s);
#if defined(LOG_CFSOCKET)
fprintf(stdout, "write signaling source for socket %d\n", s->_socket);
#endif
if (callBackNow) {
__CFSocketDoCallback(s, NULL, NULL, 0);
} else {
CFRunLoopSourceSignal(s->_source0);
CFMutableArrayRef runLoopsOrig = (CFMutableArrayRef)CFRetain(s->_runLoops);
CFMutableArrayRef runLoopsCopy = CFArrayCreateMutableCopy(kCFAllocatorSystemDefault, 0, s->_runLoops);
CFRunLoopSourceRef source0 = s->_source0;
if (NULL != source0 && !CFRunLoopSourceIsValid(source0)) {
source0 = NULL;
}
if (source0) CFRetain(source0);
__CFSocketUnlock(s);
CFRunLoopRef rl = __CFSocketCopyRunLoopToWakeUp(source0, runLoopsCopy);
if (source0) CFRelease(source0);
if (NULL != rl) {
CFRunLoopWakeUp(rl);
CFRelease(rl);
}
__CFSocketLock(s);
if (runLoopsOrig == s->_runLoops) {
s->_runLoops = runLoopsCopy;
runLoopsCopy = NULL;
CFRelease(runLoopsOrig);
}
__CFSocketUnlock(s);
CFRelease(runLoopsOrig);
if (runLoopsCopy) CFRelease(runLoopsCopy);
}
}
static void __CFSocketHandleRead(CFSocketRef s, Boolean causedByTimeout)
{
CFDataRef data = NULL, address = NULL;
CFSocketNativeHandle sock = INVALID_SOCKET;
if (!CFSocketIsValid(s)) return;
if (__CFSocketReadCallBackType(s) == kCFSocketDataCallBack) {
uint8_t bufferArray[MAX_CONNECTION_ORIENTED_DATA_SIZE], *buffer;
uint8_t name[MAX_SOCKADDR_LEN];
int namelen = sizeof(name);
SInt32 recvlen = 0;
if (__CFSocketIsConnectionOriented(s)) {
buffer = bufferArray;
recvlen = recvfrom(s->_socket, (char *)buffer, MAX_CONNECTION_ORIENTED_DATA_SIZE, 0, (struct sockaddr *)name, (socklen_t *)&namelen);
} else {
buffer = (uint8_t *)malloc(MAX_DATA_SIZE);
if (buffer) recvlen = recvfrom(s->_socket, (char *)buffer, MAX_DATA_SIZE, 0, (struct sockaddr *)name, (socklen_t *)&namelen);
}
#if defined(LOG_CFSOCKET)
fprintf(stdout, "read %ld bytes on socket %d\n", (long)recvlen, s->_socket);
#endif
if (0 >= recvlen) {
data = (CFDataRef)CFRetain(zeroLengthData);
} else {
data = CFDataCreate(CFGetAllocator(s), buffer, recvlen);
}
if (buffer && buffer != bufferArray) free(buffer);
__CFSocketLock(s);
if (!__CFSocketIsValid(s)) {
CFRelease(data);
__CFSocketUnlock(s);
return;
}
__CFSocketSetReadSignalled(s);
if (NULL != name && 0 < namelen) {
address = CFDataCreate(CFGetAllocator(s), name, namelen);
} else if (__CFSocketIsConnectionOriented(s)) {
if (NULL == s->_peerAddress) __CFSocketEstablishPeerAddress(s);
if (NULL != s->_peerAddress) address = (CFDataRef)CFRetain(s->_peerAddress);
}
if (NULL == address) {
address = (CFDataRef)CFRetain(zeroLengthData);
}
if (NULL == s->_dataQueue) {
s->_dataQueue = CFArrayCreateMutable(CFGetAllocator(s), 0, &kCFTypeArrayCallBacks);
}
if (NULL == s->_addressQueue) {
s->_addressQueue = CFArrayCreateMutable(CFGetAllocator(s), 0, &kCFTypeArrayCallBacks);
}
CFArrayAppendValue(s->_dataQueue, data);
CFRelease(data);
CFArrayAppendValue(s->_addressQueue, address);
CFRelease(address);
if (0 < recvlen
&& (s->_f.client & kCFSocketDataCallBack) != 0 && (s->_f.disabled & kCFSocketDataCallBack) == 0
&& __CFSocketIsScheduled(s)
) {
__CFSpinLock(&__CFActiveSocketsLock);
__CFSocketSetFDForRead(s);
__CFSpinUnlock(&__CFActiveSocketsLock);
}
} else if (__CFSocketReadCallBackType(s) == kCFSocketAcceptCallBack) {
uint8_t name[MAX_SOCKADDR_LEN];
int namelen = sizeof(name);
sock = accept(s->_socket, (struct sockaddr *)name, (socklen_t *)&namelen);
if (INVALID_SOCKET == sock) {
return;
}
if (NULL != name && 0 < namelen) {
address = CFDataCreate(CFGetAllocator(s), name, namelen);
} else {
address = (CFDataRef)CFRetain(zeroLengthData);
}
__CFSocketLock(s);
if (!__CFSocketIsValid(s)) {
closesocket(sock);
CFRelease(address);
__CFSocketUnlock(s);
return;
}
__CFSocketSetReadSignalled(s);
if (NULL == s->_dataQueue) {
s->_dataQueue = CFArrayCreateMutable(CFGetAllocator(s), 0, NULL);
}
if (NULL == s->_addressQueue) {
s->_addressQueue = CFArrayCreateMutable(CFGetAllocator(s), 0, &kCFTypeArrayCallBacks);
}
CFArrayAppendValue(s->_dataQueue, (void *)(uintptr_t)sock);
CFArrayAppendValue(s->_addressQueue, address);
CFRelease(address);
if ((s->_f.client & kCFSocketAcceptCallBack) != 0 && (s->_f.disabled & kCFSocketAcceptCallBack) == 0
&& __CFSocketIsScheduled(s)
) {
__CFSpinLock(&__CFActiveSocketsLock);
__CFSocketSetFDForRead(s);
__CFSpinUnlock(&__CFActiveSocketsLock);
}
} else {
__CFSocketLock(s);
if (!__CFSocketIsValid(s) || (s->_f.disabled & kCFSocketReadCallBack) != 0) {
__CFSocketUnlock(s);
return;
}
if (causedByTimeout) {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "TIMEOUT RECEIVED - WILL SIGNAL IMMEDIATELY TO FLUSH (%ld buffered)\n", s->_bytesToBufferPos);
#endif
if (s->_bytesToBufferPos == 0) {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "TIMEOUT - but no bytes, restoring to active set\n");
fflush(stdout);
#endif
__CFSpinLock(&__CFActiveSocketsLock);
__CFSocketSetFDForRead(s);
__CFSpinUnlock(&__CFActiveSocketsLock);
__CFSocketUnlock(s);
return;
}
} else if (s->_bytesToBuffer != 0 && ! s->_atEOF) {
UInt8* base;
CFIndex ctRead;
CFIndex ctRemaining = s->_bytesToBuffer - s->_bytesToBufferPos;
if (ctRemaining > 0) {
base = CFDataGetMutableBytePtr(s->_readBuffer);
do {
ctRead = read(CFSocketGetNative(s), &base[s->_bytesToBufferPos], ctRemaining);
} while (ctRead == -1 && errno == EAGAIN);
switch (ctRead) {
case -1:
s->_bufferedReadError = errno;
s->_atEOF = true;
#if defined(LOG_CFSOCKET)
fprintf(stderr, "BUFFERED READ GOT ERROR %d\n", errno);
#endif
break;
case 0:
#if defined(LOG_CFSOCKET)
fprintf(stdout, "DONE READING (EOF) - GOING TO SIGNAL\n");
#endif
s->_atEOF = true;
break;
default:
s->_bytesToBufferPos += ctRead;
if (s->_bytesToBuffer != s->_bytesToBufferPos) {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "READ %ld - need %ld MORE - GOING BACK FOR MORE\n", ctRead, s->_bytesToBuffer - s->_bytesToBufferPos);
#endif
__CFSpinLock(&__CFActiveSocketsLock);
__CFSocketSetFDForRead(s);
__CFSpinUnlock(&__CFActiveSocketsLock);
__CFSocketUnlock(s);
return;
} else {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "DONE READING (read %ld bytes) - GOING TO SIGNAL\n", ctRead);
#endif
}
}
}
}
__CFSocketSetReadSignalled(s);
}
#if defined(LOG_CFSOCKET)
fprintf(stdout, "read signaling source for socket %d\n", s->_socket);
#endif
CFRunLoopSourceSignal(s->_source0);
CFMutableArrayRef runLoopsOrig = (CFMutableArrayRef)CFRetain(s->_runLoops);
CFMutableArrayRef runLoopsCopy = CFArrayCreateMutableCopy(kCFAllocatorSystemDefault, 0, s->_runLoops);
CFRunLoopSourceRef source0 = s->_source0;
if (NULL != source0 && !CFRunLoopSourceIsValid(source0)) {
source0 = NULL;
}
if (source0) CFRetain(source0);
__CFSocketUnlock(s);
CFRunLoopRef rl = __CFSocketCopyRunLoopToWakeUp(source0, runLoopsCopy);
if (source0) CFRelease(source0);
if (NULL != rl) {
CFRunLoopWakeUp(rl);
CFRelease(rl);
}
__CFSocketLock(s);
if (runLoopsOrig == s->_runLoops) {
s->_runLoops = runLoopsCopy;
runLoopsCopy = NULL;
CFRelease(runLoopsOrig);
}
__CFSocketUnlock(s);
CFRelease(runLoopsOrig);
if (runLoopsCopy) CFRelease(runLoopsCopy);
}
static struct timeval* intervalToTimeval(CFTimeInterval timeout, struct timeval* tv)
{
if (timeout == 0.0)
timerclear(tv);
else {
tv->tv_sec = (0 >= timeout || INT_MAX <= timeout) ? INT_MAX : (int)(float)floor(timeout);
tv->tv_usec = (int)((timeout - floor(timeout)) * 1.0E6);
}
return tv;
}
static void _calcMinTimeout_locked(const void* val, void* ctxt)
{
CFSocketRef s = (CFSocketRef) val;
struct timeval** minTime = (struct timeval**) ctxt;
if (timerisset(&s->_readBufferTimeout) && (*minTime == NULL || timercmp(&s->_readBufferTimeout, *minTime, <)))
*minTime = &s->_readBufferTimeout;
else if (s->_leftoverBytes) {
static struct timeval sKickerTime = { 0, 0 };
*minTime = &sKickerTime;
}
}
void __CFSocketSetSocketReadBufferAttrs(CFSocketRef s, CFTimeInterval timeout, CFIndex length)
{
struct timeval timeoutVal;
intervalToTimeval(timeout, &timeoutVal);
__CFSocketLock(s);
__CFSpinLock(&__CFActiveSocketsLock);
if (s->_bytesToBuffer != length) {
CFIndex ctBuffer = s->_bytesToBufferPos - s->_bytesToBufferReadPos;
if (ctBuffer) {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "%s(%d): WARNING: shouldn't set read buffer length while data (%ld bytes) is still in the read buffer (leftover total %ld)", __FUNCTION__, __LINE__, ctBuffer, s->_leftoverBytes? CFDataGetLength(s->_leftoverBytes) : 0);
#endif
if (s->_leftoverBytes == NULL)
s->_leftoverBytes = CFDataCreateMutable(CFGetAllocator(s), 0);
CFDataAppendBytes(s->_leftoverBytes, CFDataGetBytePtr(s->_readBuffer) + s->_bytesToBufferReadPos, ctBuffer);
CFRelease(s->_readBuffer);
s->_readBuffer = NULL;
s->_bytesToBuffer = 0;
s->_bytesToBufferPos = 0;
s->_bytesToBufferReadPos = 0;
}
if (length == 0) {
s->_bytesToBuffer = 0;
s->_bytesToBufferPos = 0;
s->_bytesToBufferReadPos = 0;
if (s->_readBuffer) {
CFRelease(s->_readBuffer);
s->_readBuffer = NULL;
}
timeoutVal.tv_sec = 0;
timeoutVal.tv_usec = 0;
} else {
if (length > s->_bytesToBuffer) {
if (s->_readBuffer) {
CFRelease(s->_readBuffer);
s->_readBuffer = NULL;
}
}
s->_bytesToBuffer = length;
s->_bytesToBufferPos = 0;
s->_bytesToBufferReadPos = 0;
if (s->_readBuffer == NULL) {
s->_readBuffer = CFDataCreateMutable(kCFAllocatorSystemDefault, length);
CFDataSetLength(s->_readBuffer, length);
}
}
}
if (timercmp(&s->_readBufferTimeout, &timeoutVal, !=)) {
s->_readBufferTimeout = timeoutVal;
__CFReadSocketsTimeoutInvalid = true;
}
__CFSpinUnlock(&__CFActiveSocketsLock);
__CFSocketUnlock(s);
}
CFIndex __CFSocketRead(CFSocketRef s, UInt8* buffer, CFIndex length, int* error)
{
#if defined(LOG_CFSOCKET)
fprintf(stdout, "READING BYTES FOR SOCKET %d (%ld buffered, out of %ld desired, eof = %d, err = %d)\n", s->_socket, s->_bytesToBufferPos, s->_bytesToBuffer, s->_atEOF, s->_bufferedReadError);
#endif
CFIndex result = -1;
__CFSocketLock(s);
*error = 0;
if (s->_leftoverBytes) {
CFIndex ctBuffer = CFDataGetLength(s->_leftoverBytes);
#if defined(DEBUG)
fprintf(stderr, "%s(%ld): WARNING: Draining %ld leftover bytes first\n\n", __FUNCTION__, (long)__LINE__, (long)ctBuffer);
#endif
if (ctBuffer > length)
ctBuffer = length;
memcpy(buffer, CFDataGetBytePtr(s->_leftoverBytes), ctBuffer);
if (ctBuffer < CFDataGetLength(s->_leftoverBytes))
CFDataReplaceBytes(s->_leftoverBytes, CFRangeMake(0, ctBuffer), NULL, 0);
else {
CFRelease(s->_leftoverBytes);
s->_leftoverBytes = NULL;
}
result = ctBuffer;
goto unlock;
}
if (s->_bytesToBuffer != 0) {
CFIndex ctBuffer = s->_bytesToBufferPos - s->_bytesToBufferReadPos;
if (ctBuffer > 0) {
if (ctBuffer > length)
ctBuffer = length;
memcpy(buffer, CFDataGetBytePtr(s->_readBuffer) + s->_bytesToBufferReadPos, ctBuffer);
s->_bytesToBufferReadPos += ctBuffer;
if (s->_bytesToBufferReadPos == s->_bytesToBufferPos) {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "DRAINED BUFFER - SHOULD START BUFFERING AGAIN!\n");
#endif
s->_bytesToBufferPos = 0;
s->_bytesToBufferReadPos = 0;
}
#if defined(LOG_CFSOCKET)
fprintf(stdout, "SLURPED %ld BYTES FROM BUFFER %ld LEFT TO READ!\n", ctBuffer, length);
#endif
result = ctBuffer;
goto unlock;
}
}
if (s->_bufferedReadError != 0) {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "RETURNING ERROR %d\n", s->_bufferedReadError);
#endif
*error = s->_bufferedReadError;
result = -1;
goto unlock;
}
if (s->_atEOF) {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "RETURNING EOF\n");
#endif
result = 0;
goto unlock;
}
result = read(CFSocketGetNative(s), buffer, length);
#if defined(LOG_CFSOCKET)
fprintf(stdout, "READ %ld bytes", result);
#endif
if (result == 0) {
s->_atEOF = true;
} else if (result < 0) {
*error = errno;
if (*error != EAGAIN) {
s->_bufferedReadError = *error;
}
}
unlock:
__CFSocketUnlock(s);
return result;
}
Boolean __CFSocketGetBytesAvailable(CFSocketRef s, CFIndex* ctBytesAvailable)
{
CFIndex ctBuffer = s->_bytesToBufferPos - s->_bytesToBufferReadPos;
if (ctBuffer != 0) {
*ctBytesAvailable = ctBuffer;
return true;
} else {
int result;
unsigned long bytesAvailable;
result = ioctlsocket(CFSocketGetNative(s), FIONREAD, &bytesAvailable);
if (result < 0)
return false;
*ctBytesAvailable = (CFIndex) bytesAvailable;
return true;
}
}
#if defined(LOG_CFSOCKET)
static void __CFSocketWriteSocketList(CFArrayRef sockets, CFDataRef fdSet, Boolean onlyIfSet) {
fd_set *tempfds = (fd_set *)CFDataGetBytePtr(fdSet);
SInt32 idx, cnt;
for (idx = 0, cnt = CFArrayGetCount(sockets); idx < cnt; idx++) {
CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(sockets, idx);
if (FD_ISSET(s->_socket, tempfds)) {
fprintf(stdout, "%d ", s->_socket);
} else if (!onlyIfSet) {
fprintf(stdout, "(%d) ", s->_socket);
}
}
}
#endif
#ifdef __GNUC__
__attribute__ ((noreturn)) #endif
static void __CFSocketManager(void * arg)
{
pthread_setname_np("com.apple.CFSocket.private");
if (objc_collectingEnabled()) objc_registerThreadWithCollector();
SInt32 nrfds, maxnrfds, fdentries = 1;
SInt32 rfds, wfds;
fd_set *exceptfds = NULL;
fd_set *writefds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, fdentries * sizeof(fd_mask), 0);
fd_set *readfds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, fdentries * sizeof(fd_mask), 0);
fd_set *tempfds;
SInt32 idx, cnt;
uint8_t buffer[256];
CFMutableArrayRef selectedWriteSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
CFMutableArrayRef selectedReadSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
CFIndex selectedWriteSocketsIndex = 0, selectedReadSocketsIndex = 0;
struct timeval tv;
struct timeval* pTimeout = NULL;
struct timeval timeBeforeSelect;
for (;;) {
__CFSpinLock(&__CFActiveSocketsLock);
__CFSocketManagerIteration++;
#if defined(LOG_CFSOCKET)
fprintf(stdout, "socket manager iteration %lu looking at read sockets ", (unsigned long)__CFSocketManagerIteration);
__CFSocketWriteSocketList(__CFReadSockets, __CFReadSocketsFds, FALSE);
if (0 < CFArrayGetCount(__CFWriteSockets)) {
fprintf(stdout, " and write sockets ");
__CFSocketWriteSocketList(__CFWriteSockets, __CFWriteSocketsFds, FALSE);
}
fprintf(stdout, "\n");
#endif
rfds = __CFSocketFdGetSize(__CFReadSocketsFds);
wfds = __CFSocketFdGetSize(__CFWriteSocketsFds);
maxnrfds = __CFMax(rfds, wfds);
if (maxnrfds > fdentries * (int)NFDBITS) {
fdentries = (maxnrfds + NFDBITS - 1) / NFDBITS;
writefds = (fd_set *)CFAllocatorReallocate(kCFAllocatorSystemDefault, writefds, fdentries * sizeof(fd_mask), 0);
readfds = (fd_set *)CFAllocatorReallocate(kCFAllocatorSystemDefault, readfds, fdentries * sizeof(fd_mask), 0);
}
memset(writefds, 0, fdentries * sizeof(fd_mask));
memset(readfds, 0, fdentries * sizeof(fd_mask));
CFDataGetBytes(__CFWriteSocketsFds, CFRangeMake(0, CFDataGetLength(__CFWriteSocketsFds)), (UInt8 *)writefds);
CFDataGetBytes(__CFReadSocketsFds, CFRangeMake(0, CFDataGetLength(__CFReadSocketsFds)), (UInt8 *)readfds);
if (__CFReadSocketsTimeoutInvalid) {
struct timeval* minTimeout = NULL;
__CFReadSocketsTimeoutInvalid = false;
#if defined(LOG_CFSOCKET)
fprintf(stdout, "Figuring out which sockets have timeouts...\n");
#endif
CFArrayApplyFunction(__CFReadSockets, CFRangeMake(0, CFArrayGetCount(__CFReadSockets)), _calcMinTimeout_locked, (void*) &minTimeout);
if (minTimeout == NULL) {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "No one wants a timeout!\n");
#endif
pTimeout = NULL;
} else {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "timeout will be %ld, %d!\n", minTimeout->tv_sec, minTimeout->tv_usec);
#endif
tv = *minTimeout;
pTimeout = &tv;
}
}
if (pTimeout) {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "select will have a %ld, %d timeout\n", pTimeout->tv_sec, pTimeout->tv_usec);
#endif
gettimeofday(&timeBeforeSelect, NULL);
}
__CFSpinUnlock(&__CFActiveSocketsLock);
#if DEPLOYMENT_TARGET_WINDOWS
exceptfds = writefds;
#endif
nrfds = select(maxnrfds, readfds, writefds, exceptfds, pTimeout);
#if defined(LOG_CFSOCKET)
fprintf(stdout, "socket manager woke from select, ret=%ld\n", (long)nrfds);
#endif
if (0 == nrfds) {
struct timeval timeAfterSelect;
struct timeval deltaTime;
gettimeofday(&timeAfterSelect, NULL);
timersub(&timeAfterSelect, &timeBeforeSelect, &deltaTime);
#if defined(LOG_CFSOCKET)
fprintf(stdout, "Socket manager received timeout - kicking off expired reads (expired delta %ld, %d)\n", deltaTime.tv_sec, deltaTime.tv_usec);
#endif
__CFSpinLock(&__CFActiveSocketsLock);
tempfds = NULL;
cnt = CFArrayGetCount(__CFReadSockets);
for (idx = 0; idx < cnt; idx++) {
CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFReadSockets, idx);
if (timerisset(&s->_readBufferTimeout) || s->_leftoverBytes) {
CFSocketNativeHandle sock = s->_socket;
Boolean sockInBounds = (0 <= sock && sock < maxnrfds);
if (INVALID_SOCKET != sock && sockInBounds) {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "Expiring socket %d (delta %ld, %d)\n", sock, s->_readBufferTimeout.tv_sec, s->_readBufferTimeout.tv_usec);
#endif
CFArraySetValueAtIndex(selectedReadSockets, selectedReadSocketsIndex, s);
selectedReadSocketsIndex++;
if (!tempfds) tempfds = (fd_set *)CFDataGetMutableBytePtr(__CFReadSocketsFds);
FD_CLR(sock, tempfds);
}
}
}
__CFSpinUnlock(&__CFActiveSocketsLock);
}
if (0 > nrfds) {
SInt32 selectError = __CFSocketLastError();
#if defined(LOG_CFSOCKET)
fprintf(stdout, "socket manager received error %ld from select\n", (long)selectError);
#endif
if (EBADF == selectError) {
CFMutableArrayRef invalidSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
__CFSpinLock(&__CFActiveSocketsLock);
cnt = CFArrayGetCount(__CFWriteSockets);
for (idx = 0; idx < cnt; idx++) {
CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFWriteSockets, idx);
if (!__CFNativeSocketIsValid(s->_socket)) {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "socket manager found write socket %d invalid\n", s->_socket);
#endif
CFArrayAppendValue(invalidSockets, s);
}
}
cnt = CFArrayGetCount(__CFReadSockets);
for (idx = 0; idx < cnt; idx++) {
CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFReadSockets, idx);
if (!__CFNativeSocketIsValid(s->_socket)) {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "socket manager found read socket %d invalid\n", s->_socket);
#endif
CFArrayAppendValue(invalidSockets, s);
}
}
__CFSpinUnlock(&__CFActiveSocketsLock);
cnt = CFArrayGetCount(invalidSockets);
for (idx = 0; idx < cnt; idx++) {
CFSocketInvalidate(((CFSocketRef)CFArrayGetValueAtIndex(invalidSockets, idx)));
}
CFRelease(invalidSockets);
}
continue;
}
if (FD_ISSET(__CFWakeupSocketPair[1], readfds)) {
recv(__CFWakeupSocketPair[1], (char *)buffer, sizeof(buffer), 0);
#if defined(LOG_CFSOCKET)
fprintf(stdout, "socket manager received %c on wakeup socket\n", buffer[0]);
#endif
}
__CFSpinLock(&__CFActiveSocketsLock);
tempfds = NULL;
cnt = CFArrayGetCount(__CFWriteSockets);
for (idx = 0; idx < cnt; idx++) {
CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFWriteSockets, idx);
CFSocketNativeHandle sock = s->_socket;
Boolean sockInBounds = (0 <= sock && sock < maxnrfds);
if (INVALID_SOCKET != sock && sockInBounds) {
if (FD_ISSET(sock, writefds)) {
CFArraySetValueAtIndex(selectedWriteSockets, selectedWriteSocketsIndex, s);
selectedWriteSocketsIndex++;
if (!tempfds) tempfds = (fd_set *)CFDataGetMutableBytePtr(__CFWriteSocketsFds);
FD_CLR(sock, tempfds);
}
}
}
tempfds = NULL;
cnt = CFArrayGetCount(__CFReadSockets);
for (idx = 0; idx < cnt; idx++) {
CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFReadSockets, idx);
CFSocketNativeHandle sock = s->_socket;
Boolean sockInBounds = (0 <= sock && sock < maxnrfds);
if (INVALID_SOCKET != sock && sockInBounds && FD_ISSET(sock, readfds)) {
CFArraySetValueAtIndex(selectedReadSockets, selectedReadSocketsIndex, s);
selectedReadSocketsIndex++;
if (!tempfds) tempfds = (fd_set *)CFDataGetMutableBytePtr(__CFReadSocketsFds);
FD_CLR(sock, tempfds);
}
}
__CFSpinUnlock(&__CFActiveSocketsLock);
for (idx = 0; idx < selectedWriteSocketsIndex; idx++) {
CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(selectedWriteSockets, idx);
if (kCFNull == (CFNullRef)s) continue;
#if defined(LOG_CFSOCKET)
fprintf(stdout, "socket manager signaling socket %d for write\n", s->_socket);
#endif
__CFSocketHandleWrite(s, FALSE);
CFArraySetValueAtIndex(selectedWriteSockets, idx, kCFNull);
}
selectedWriteSocketsIndex = 0;
for (idx = 0; idx < selectedReadSocketsIndex; idx++) {
CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(selectedReadSockets, idx);
if (kCFNull == (CFNullRef)s) continue;
#if defined(LOG_CFSOCKET)
fprintf(stdout, "socket manager signaling socket %d for read\n", s->_socket);
#endif
__CFSocketHandleRead(s, nrfds == 0);
CFArraySetValueAtIndex(selectedReadSockets, idx, kCFNull);
}
selectedReadSocketsIndex = 0;
}
}
static CFStringRef __CFSocketCopyDescription(CFTypeRef cf) {
CFSocketRef s = (CFSocketRef)cf;
CFMutableStringRef result;
CFStringRef contextDesc = NULL;
void *contextInfo = NULL;
CFStringRef (*contextCopyDescription)(const void *info) = NULL;
result = CFStringCreateMutable(CFGetAllocator(s), 0);
__CFSocketLock(s);
void *addr = s->_callout;
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
Dl_info info;
const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???";
#else
const char *name = "<unknown>";
#endif
CFStringAppendFormat(result, NULL, CFSTR("<CFSocket %p [%p]>{valid = %s, type = %d, socket = %d, socket set count = %ld,\n callback types = 0x%x, callout = %s (%p), source = %p,\n run loops = %@,\n context = "), cf, CFGetAllocator(s), (__CFSocketIsValid(s) ? "Yes" : "No"), s->_socketType, s->_socket, s->_socketSetCount, __CFSocketCallBackTypes(s), name, addr, s->_source0, s->_runLoops);
contextInfo = s->_context.info;
contextCopyDescription = s->_context.copyDescription;
__CFSocketUnlock(s);
if (NULL != contextInfo && NULL != contextCopyDescription) {
contextDesc = (CFStringRef)contextCopyDescription(contextInfo);
}
if (NULL == contextDesc) {
contextDesc = CFStringCreateWithFormat(CFGetAllocator(s), NULL, CFSTR("<CFSocket context %p>"), contextInfo);
}
CFStringAppend(result, contextDesc);
CFStringAppend(result, CFSTR("}"));
CFRelease(contextDesc);
return result;
}
static void __CFSocketDeallocate(CFTypeRef cf) {
CFSocketRef s = (CFSocketRef)cf;
if (NULL != s->_address) {
CFRelease(s->_address);
s->_address = NULL;
}
if (NULL != s->_readBuffer) {
CFRelease(s->_readBuffer);
s->_readBuffer = NULL;
}
if (NULL != s->_leftoverBytes) {
CFRelease(s->_leftoverBytes);
s->_leftoverBytes = NULL;
}
timerclear(&s->_readBufferTimeout);
s->_bytesToBuffer = 0;
s->_bytesToBufferPos = 0;
s->_bytesToBufferReadPos = 0;
s->_atEOF = true;
s->_bufferedReadError = 0;
}
static CFTypeID __kCFSocketTypeID = _kCFRuntimeNotATypeID;
static const CFRuntimeClass __CFSocketClass = {
0,
"CFSocket",
NULL, NULL, __CFSocketDeallocate,
NULL, NULL, NULL, __CFSocketCopyDescription
};
CFTypeID CFSocketGetTypeID(void) {
if (_kCFRuntimeNotATypeID == __kCFSocketTypeID) {
__kCFSocketTypeID = _CFRuntimeRegisterClass(&__CFSocketClass);
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
struct rlimit lim1;
int ret1 = getrlimit(RLIMIT_NOFILE, &lim1);
int mib[] = {CTL_KERN, KERN_MAXFILESPERPROC};
int maxfd = 0;
size_t len = sizeof(int);
int ret0 = sysctl(mib, 2, &maxfd, &len, NULL, 0);
if (0 == ret0 && 0 == ret1 && lim1.rlim_max < maxfd) maxfd = lim1.rlim_max;
if (0 == ret1 && lim1.rlim_cur < maxfd) {
struct rlimit lim2 = lim1;
lim2.rlim_cur += 2304;
if (maxfd < lim2.rlim_cur) lim2.rlim_cur = maxfd;
setrlimit(RLIMIT_NOFILE, &lim2);
}
#endif
}
return __kCFSocketTypeID;
}
static CFSocketRef _CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketNativeHandle sock, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context, Boolean useExistingInstance) {
CHECK_FOR_FORK();
CFSocketRef memory;
int typeSize = sizeof(memory->_socketType);
__CFSpinLock(&__CFActiveSocketsLock);
if (NULL == __CFReadSockets) __CFSocketInitializeSockets();
__CFSpinUnlock(&__CFActiveSocketsLock);
__CFSpinLock(&__CFAllSocketsLock);
if (NULL == __CFAllSockets) {
__CFAllSockets = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
}
if (INVALID_SOCKET != sock && CFDictionaryGetValueIfPresent(__CFAllSockets, (void *)(uintptr_t)sock, (const void **)&memory)) {
if (useExistingInstance) {
__CFSpinUnlock(&__CFAllSocketsLock);
CFRetain(memory);
return memory;
} else {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "useExistingInstance is FALSE, removing existing instance %p from __CFAllSockets\n", memory);
#endif
__CFSpinUnlock(&__CFAllSocketsLock);
CFSocketInvalidate(memory);
__CFSpinLock(&__CFAllSocketsLock);
}
}
memory = (CFSocketRef)_CFRuntimeCreateInstance(allocator, CFSocketGetTypeID(), sizeof(struct __CFSocket) - sizeof(CFRuntimeBase), NULL);
if (NULL == memory) {
__CFSpinUnlock(&__CFAllSocketsLock);
return NULL;
}
__CFSocketSetCallBackTypes(memory, callBackTypes);
if (INVALID_SOCKET != sock) __CFSocketSetValid(memory);
__CFSocketUnsetWriteSignalled(memory);
__CFSocketUnsetReadSignalled(memory);
memory->_f.client = ((callBackTypes & (~kCFSocketConnectCallBack)) & (~kCFSocketWriteCallBack)) | kCFSocketCloseOnInvalidate;
memory->_f.disabled = 0;
memory->_f.connected = FALSE;
memory->_f.writableHint = FALSE;
memory->_f.closeSignaled = FALSE;
memory->_lock = CFSpinLockInit;
memory->_writeLock = CFSpinLockInit;
memory->_socket = sock;
if (INVALID_SOCKET == sock || 0 != getsockopt(sock, SOL_SOCKET, SO_TYPE, (char *)&(memory->_socketType), (socklen_t *)&typeSize)) memory->_socketType = 0; memory->_errorCode = 0;
memory->_address = NULL;
memory->_peerAddress = NULL;
memory->_socketSetCount = 0;
memory->_source0 = NULL;
if (INVALID_SOCKET != sock) {
memory->_runLoops = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, NULL);
} else {
memory->_runLoops = NULL;
}
memory->_callout = callout;
memory->_dataQueue = NULL;
memory->_addressQueue = NULL;
memory->_context.info = 0;
memory->_context.retain = 0;
memory->_context.release = 0;
memory->_context.copyDescription = 0;
timerclear(&memory->_readBufferTimeout);
memory->_readBuffer = NULL;
memory->_bytesToBuffer = 0;
memory->_bytesToBufferPos = 0;
memory->_bytesToBufferReadPos = 0;
memory->_atEOF = false;
memory->_bufferedReadError = 0;
memory->_leftoverBytes = NULL;
if (INVALID_SOCKET != sock) CFDictionaryAddValue(__CFAllSockets, (void *)(uintptr_t)sock, memory);
if (NULL == __CFSocketManagerThread) __CFSocketManagerThread = __CFStartSimpleThread(__CFSocketManager, 0);
__CFSpinUnlock(&__CFAllSocketsLock);
if (NULL != context) {
void *contextInfo = context->retain ? (void *)context->retain(context->info) : context->info;
__CFSocketLock(memory);
memory->_context.retain = context->retain;
memory->_context.release = context->release;
memory->_context.copyDescription = context->copyDescription;
memory->_context.info = contextInfo;
__CFSocketUnlock(memory);
}
#if defined(LOG_CFSOCKET)
CFLog(5, CFSTR("CFSocketCreateWithNative(): created socket %p (%d) with callbacks 0x%x"), memory, memory->_socket, callBackTypes);
#endif
return memory;
}
CFSocketRef CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketNativeHandle sock, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context) {
return _CFSocketCreateWithNative(allocator, sock, callBackTypes, callout, context, TRUE);
}
void CFSocketInvalidate(CFSocketRef s) {
CHECK_FOR_FORK();
UInt32 previousSocketManagerIteration;
__CFGenericValidateType(s, CFSocketGetTypeID());
#if defined(LOG_CFSOCKET)
fprintf(stdout, "invalidating socket %d with flags 0x%x disabled 0x%x connected 0x%x\n", s->_socket, s->_f.client, s->_f.disabled, s->_f.connected);
#endif
CFRetain(s);
__CFSpinLock(&__CFAllSocketsLock);
__CFSocketLock(s);
if (__CFSocketIsValid(s)) {
SInt32 idx;
CFRunLoopSourceRef source0;
void *contextInfo = NULL;
void (*contextRelease)(const void *info) = NULL;
__CFSocketUnsetValid(s);
__CFSocketUnsetWriteSignalled(s);
__CFSocketUnsetReadSignalled(s);
__CFSpinLock(&__CFActiveSocketsLock);
idx = CFArrayGetFirstIndexOfValue(__CFWriteSockets, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets)), s);
if (0 <= idx) {
CFArrayRemoveValueAtIndex(__CFWriteSockets, idx);
__CFSocketClearFDForWrite(s);
}
idx = CFArrayGetFirstIndexOfValue(__CFReadSockets, CFRangeMake(0, CFArrayGetCount(__CFReadSockets)), s);
if (0 <= idx) {
CFArrayRemoveValueAtIndex(__CFReadSockets, idx);
__CFSocketClearFDForRead(s);
}
previousSocketManagerIteration = __CFSocketManagerIteration;
__CFSpinUnlock(&__CFActiveSocketsLock);
CFDictionaryRemoveValue(__CFAllSockets, (void *)(uintptr_t)(s->_socket));
if ((s->_f.client & kCFSocketCloseOnInvalidate) != 0) closesocket(s->_socket);
s->_socket = INVALID_SOCKET;
if (NULL != s->_peerAddress) {
CFRelease(s->_peerAddress);
s->_peerAddress = NULL;
}
if (NULL != s->_dataQueue) {
CFRelease(s->_dataQueue);
s->_dataQueue = NULL;
}
if (NULL != s->_addressQueue) {
CFRelease(s->_addressQueue);
s->_addressQueue = NULL;
}
s->_socketSetCount = 0;
CFArrayRef runLoops = (CFArrayRef)CFRetain(s->_runLoops);
CFRelease(s->_runLoops);
s->_runLoops = NULL;
source0 = s->_source0;
s->_source0 = NULL;
contextInfo = s->_context.info;
contextRelease = s->_context.release;
s->_context.info = 0;
s->_context.retain = 0;
s->_context.release = 0;
s->_context.copyDescription = 0;
__CFSocketUnlock(s);
for (idx = CFArrayGetCount(runLoops); idx--;) {
CFRunLoopWakeUp((CFRunLoopRef)CFArrayGetValueAtIndex(runLoops, idx));
}
CFRelease(runLoops);
if (NULL != contextRelease) {
contextRelease(contextInfo);
}
if (NULL != source0) {
CFRunLoopSourceInvalidate(source0);
CFRelease(source0);
}
} else {
__CFSocketUnlock(s);
}
__CFSpinUnlock(&__CFAllSocketsLock);
CFRelease(s);
#if defined(LOG_CFSOCKET)
CFLog(5, CFSTR("CFSocketInvalidate(%p) done"), s);
#endif
}
Boolean CFSocketIsValid(CFSocketRef s) {
CHECK_FOR_FORK();
__CFGenericValidateType(s, CFSocketGetTypeID());
return __CFSocketIsValid(s);
}
CFSocketNativeHandle CFSocketGetNative(CFSocketRef s) {
CHECK_FOR_FORK();
__CFGenericValidateType(s, CFSocketGetTypeID());
return s->_socket;
}
CFDataRef CFSocketCopyAddress(CFSocketRef s) {
CHECK_FOR_FORK();
CFDataRef result = NULL;
__CFGenericValidateType(s, CFSocketGetTypeID());
__CFSocketLock(s);
__CFSocketEstablishAddress(s);
if (NULL != s->_address) {
result = (CFDataRef)CFRetain(s->_address);
}
__CFSocketUnlock(s);
#if defined(LOG_CFSOCKET)
CFLog(5, CFSTR("CFSocketCopyAddress(): created socket %p address %@"), s, result);
#endif
return result;
}
CFDataRef CFSocketCopyPeerAddress(CFSocketRef s) {
CHECK_FOR_FORK();
CFDataRef result = NULL;
__CFGenericValidateType(s, CFSocketGetTypeID());
__CFSocketLock(s);
__CFSocketEstablishPeerAddress(s);
if (NULL != s->_peerAddress) {
result = (CFDataRef)CFRetain(s->_peerAddress);
}
__CFSocketUnlock(s);
#if defined(LOG_CFSOCKET)
CFLog(5, CFSTR("CFSocketCopyAddress(): created socket %p peer address %@"), s, result);
#endif
return result;
}
void CFSocketGetContext(CFSocketRef s, CFSocketContext *context) {
CHECK_FOR_FORK();
__CFGenericValidateType(s, CFSocketGetTypeID());
CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
*context = s->_context;
}
CFOptionFlags CFSocketGetSocketFlags(CFSocketRef s) {
CHECK_FOR_FORK();
__CFGenericValidateType(s, CFSocketGetTypeID());
return s->_f.client;
}
void CFSocketSetSocketFlags(CFSocketRef s, CFOptionFlags flags) {
CHECK_FOR_FORK();
__CFGenericValidateType(s, CFSocketGetTypeID());
__CFSocketLock(s);
#if defined(LOG_CFSOCKET)
fprintf(stdout, "setting flags for socket %d, from 0x%x to 0x%lx\n", s->_socket, s->_f.client, flags);
#endif
s->_f.client = flags;
__CFSocketUnlock(s);
}
void CFSocketDisableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes) {
CHECK_FOR_FORK();
Boolean wakeup = false;
uint8_t readCallBackType;
__CFGenericValidateType(s, CFSocketGetTypeID());
__CFSocketLock(s);
if (__CFSocketIsValid(s) && __CFSocketIsScheduled(s)) {
callBackTypes &= __CFSocketCallBackTypes(s);
readCallBackType = __CFSocketReadCallBackType(s);
s->_f.disabled |= callBackTypes;
#if defined(LOG_CFSOCKET)
fprintf(stdout, "unscheduling socket %d with flags 0x%x disabled 0x%x connected 0x%x for types 0x%lx\n", s->_socket, s->_f.client, s->_f.disabled, s->_f.connected, callBackTypes);
#endif
__CFSpinLock(&__CFActiveSocketsLock);
if ((readCallBackType == kCFSocketAcceptCallBack) || !__CFSocketIsConnectionOriented(s)) s->_f.connected = TRUE;
if (((callBackTypes & kCFSocketWriteCallBack) != 0) || (((callBackTypes & kCFSocketConnectCallBack) != 0) && !s->_f.connected)) {
if (__CFSocketClearFDForWrite(s)) {
CFOptionFlags writeCallBacksAvailable = __CFSocketCallBackTypes(s) & (kCFSocketWriteCallBack | kCFSocketConnectCallBack);
if (s->_f.connected) writeCallBacksAvailable &= ~kCFSocketConnectCallBack;
if ((s->_f.disabled & writeCallBacksAvailable) != writeCallBacksAvailable) wakeup = true;
}
}
if (readCallBackType != kCFSocketNoCallBack && (callBackTypes & readCallBackType) != 0) {
if (__CFSocketClearFDForRead(s)) {
if (readCallBackType != kCFSocketReadCallBack) wakeup = true;
}
}
__CFSpinUnlock(&__CFActiveSocketsLock);
}
__CFSocketUnlock(s);
}
void __CFSocketEnableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes, Boolean force, uint8_t wakeupChar) {
CHECK_FOR_FORK();
Boolean wakeup = FALSE;
if (!callBackTypes) {
__CFSocketUnlock(s);
return;
}
if (__CFSocketIsValid(s) && __CFSocketIsScheduled(s)) {
Boolean turnOnWrite = FALSE, turnOnConnect = FALSE, turnOnRead = FALSE;
uint8_t readCallBackType = __CFSocketReadCallBackType(s);
callBackTypes &= __CFSocketCallBackTypes(s);
if (force) s->_f.disabled &= ~callBackTypes;
#if defined(LOG_CFSOCKET)
fprintf(stdout, "rescheduling socket %d with flags 0x%x disabled 0x%x connected 0x%x for types 0x%lx\n", s->_socket, s->_f.client, s->_f.disabled, s->_f.connected, callBackTypes);
#endif
if ((readCallBackType == kCFSocketAcceptCallBack) || !__CFSocketIsConnectionOriented(s)) s->_f.connected = TRUE;
if (s->_f.connected || (callBackTypes & kCFSocketConnectCallBack) == 0) {
if ((callBackTypes & kCFSocketWriteCallBack) != 0 && (s->_f.disabled & kCFSocketWriteCallBack) == 0) turnOnWrite = TRUE;
} else {
if ((callBackTypes & kCFSocketConnectCallBack) != 0 && (s->_f.disabled & kCFSocketConnectCallBack) == 0) turnOnConnect = TRUE;
}
if (readCallBackType != kCFSocketNoCallBack && (callBackTypes & readCallBackType) != 0 && (s->_f.disabled & kCFSocketReadCallBack) == 0) turnOnRead = TRUE;
if (turnOnRead || turnOnWrite || turnOnConnect) {
__CFSpinLock(&__CFActiveSocketsLock);
if (turnOnWrite || turnOnConnect) {
if (force) {
SInt32 idx = CFArrayGetFirstIndexOfValue(__CFWriteSockets, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets)), s);
if (kCFNotFound == idx) CFArrayAppendValue(__CFWriteSockets, s);
}
if (__CFSocketSetFDForWrite(s)) wakeup = true;
}
if (turnOnRead) {
if (force) {
SInt32 idx = CFArrayGetFirstIndexOfValue(__CFReadSockets, CFRangeMake(0, CFArrayGetCount(__CFReadSockets)), s);
if (kCFNotFound == idx) CFArrayAppendValue(__CFReadSockets, s);
}
if (__CFSocketSetFDForRead(s)) wakeup = true;
}
__CFSpinUnlock(&__CFActiveSocketsLock);
}
}
__CFSocketUnlock(s);
}
void CFSocketEnableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes) {
CHECK_FOR_FORK();
__CFGenericValidateType(s, CFSocketGetTypeID());
__CFSocketLock(s);
__CFSocketEnableCallBacks(s, callBackTypes, TRUE, 'r');
}
static void __CFSocketSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) {
CFSocketRef s = (CFSocketRef)info;
__CFSocketLock(s);
if (__CFSocketIsValid(s)) {
CFMutableArrayRef runLoopsOrig = s->_runLoops;
CFMutableArrayRef runLoopsCopy = CFArrayCreateMutableCopy(kCFAllocatorSystemDefault, 0, s->_runLoops);
CFArrayAppendValue(runLoopsCopy, rl);
s->_runLoops = runLoopsCopy;
CFRelease(runLoopsOrig);
s->_socketSetCount++;
if (1 == s->_socketSetCount) {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "scheduling socket %d\n", s->_socket);
#endif
__CFSocketEnableCallBacks(s, __CFSocketCallBackTypes(s), TRUE, 's'); } else
__CFSocketUnlock(s);
} else
__CFSocketUnlock(s);
}
static void __CFSocketCancel(void *info, CFRunLoopRef rl, CFStringRef mode) {
CFSocketRef s = (CFSocketRef)info;
SInt32 idx;
__CFSocketLock(s);
s->_socketSetCount--;
if (0 == s->_socketSetCount) {
__CFSpinLock(&__CFActiveSocketsLock);
idx = CFArrayGetFirstIndexOfValue(__CFWriteSockets, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets)), s);
if (0 <= idx) {
CFArrayRemoveValueAtIndex(__CFWriteSockets, idx);
__CFSocketClearFDForWrite(s);
}
idx = CFArrayGetFirstIndexOfValue(__CFReadSockets, CFRangeMake(0, CFArrayGetCount(__CFReadSockets)), s);
if (0 <= idx) {
CFArrayRemoveValueAtIndex(__CFReadSockets, idx);
__CFSocketClearFDForRead(s);
}
__CFSpinUnlock(&__CFActiveSocketsLock);
}
if (NULL != s->_runLoops) {
CFMutableArrayRef runLoopsOrig = s->_runLoops;
CFMutableArrayRef runLoopsCopy = CFArrayCreateMutableCopy(kCFAllocatorSystemDefault, 0, s->_runLoops);
idx = CFArrayGetFirstIndexOfValue(runLoopsCopy, CFRangeMake(0, CFArrayGetCount(runLoopsCopy)), rl);
if (0 <= idx) CFArrayRemoveValueAtIndex(runLoopsCopy, idx);
s->_runLoops = runLoopsCopy;
CFRelease(runLoopsOrig);
}
__CFSocketUnlock(s);
}
static void __CFSocketDoCallback(CFSocketRef s, CFDataRef data, CFDataRef address, CFSocketNativeHandle sock) {
CFSocketCallBack callout = NULL;
void *contextInfo = NULL;
SInt32 errorCode = 0;
Boolean readSignalled = false, writeSignalled = false, connectSignalled = false, calledOut = false;
uint8_t readCallBackType, callBackTypes;
callBackTypes = __CFSocketCallBackTypes(s);
readCallBackType = __CFSocketReadCallBackType(s);
readSignalled = __CFSocketIsReadSignalled(s);
writeSignalled = __CFSocketIsWriteSignalled(s);
connectSignalled = writeSignalled && !s->_f.connected;
__CFSocketUnsetReadSignalled(s);
__CFSocketUnsetWriteSignalled(s);
callout = s->_callout;
contextInfo = s->_context.info;
#if defined(LOG_CFSOCKET)
fprintf(stdout, "entering perform for socket %d with read signalled %d write signalled %d connect signalled %d callback types %d\n", s->_socket, readSignalled, writeSignalled, connectSignalled, callBackTypes);
#endif
if (writeSignalled) {
errorCode = s->_errorCode;
s->_f.connected = TRUE;
}
__CFSocketUnlock(s);
if ((callBackTypes & kCFSocketConnectCallBack) != 0) {
if (connectSignalled && (!calledOut || CFSocketIsValid(s))) {
if (errorCode) {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "perform calling out error %ld to socket %d\n", (long)errorCode, s->_socket);
#endif
if (callout) callout(s, kCFSocketConnectCallBack, NULL, &errorCode, contextInfo);
calledOut = true;
} else {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "perform calling out connect to socket %d\n", s->_socket);
#endif
if (callout) callout(s, kCFSocketConnectCallBack, NULL, NULL, contextInfo);
calledOut = true;
}
}
}
if (kCFSocketDataCallBack == readCallBackType) {
if (NULL != data && (!calledOut || CFSocketIsValid(s))) {
SInt32 datalen = CFDataGetLength(data);
#if defined(LOG_CFSOCKET)
fprintf(stdout, "perform calling out data of length %ld to socket %d\n", (long)datalen, s->_socket);
#endif
if (callout) callout(s, kCFSocketDataCallBack, address, data, contextInfo);
calledOut = true;
if (0 == datalen) CFSocketInvalidate(s);
}
} else if (kCFSocketAcceptCallBack == readCallBackType) {
if (INVALID_SOCKET != sock && (!calledOut || CFSocketIsValid(s))) {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "perform calling out accept of socket %d to socket %d\n", sock, s->_socket);
#endif
if (callout) callout(s, kCFSocketAcceptCallBack, address, &sock, contextInfo);
calledOut = true;
}
} else if (kCFSocketReadCallBack == readCallBackType) {
if (readSignalled && (!calledOut || CFSocketIsValid(s))) {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "perform calling out read to socket %d\n", s->_socket);
#endif
if (callout) callout(s, kCFSocketReadCallBack, NULL, NULL, contextInfo);
calledOut = true;
}
}
if ((callBackTypes & kCFSocketWriteCallBack) != 0) {
if (writeSignalled && !errorCode && (!calledOut || CFSocketIsValid(s))) {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "perform calling out write to socket %d\n", s->_socket);
#endif
if (callout) callout(s, kCFSocketWriteCallBack, NULL, NULL, contextInfo);
calledOut = true;
}
}
}
static void __CFSocketPerformV0(void *info) {
CFSocketRef s = (CFSocketRef)info;
CFDataRef data = NULL;
CFDataRef address = NULL;
CFSocketNativeHandle sock = INVALID_SOCKET;
uint8_t readCallBackType, callBackTypes;
CFRunLoopRef rl = NULL;
__CFSocketLock(s);
if (!__CFSocketIsValid(s)) {
__CFSocketUnlock(s);
return;
}
callBackTypes = __CFSocketCallBackTypes(s);
readCallBackType = __CFSocketReadCallBackType(s);
CFOptionFlags callBacksSignalled = 0;
if (__CFSocketIsReadSignalled(s)) callBacksSignalled |= readCallBackType;
if (__CFSocketIsWriteSignalled(s)) callBacksSignalled |= kCFSocketWriteCallBack;
if (kCFSocketDataCallBack == readCallBackType) {
if (NULL != s->_dataQueue && 0 < CFArrayGetCount(s->_dataQueue)) {
data = (CFDataRef)CFArrayGetValueAtIndex(s->_dataQueue, 0);
CFRetain(data);
CFArrayRemoveValueAtIndex(s->_dataQueue, 0);
address = (CFDataRef)CFArrayGetValueAtIndex(s->_addressQueue, 0);
CFRetain(address);
CFArrayRemoveValueAtIndex(s->_addressQueue, 0);
}
} else if (kCFSocketAcceptCallBack == readCallBackType) {
if (NULL != s->_dataQueue && 0 < CFArrayGetCount(s->_dataQueue)) {
sock = (CFSocketNativeHandle)(uintptr_t)CFArrayGetValueAtIndex(s->_dataQueue, 0);
CFArrayRemoveValueAtIndex(s->_dataQueue, 0);
address = (CFDataRef)CFArrayGetValueAtIndex(s->_addressQueue, 0);
CFRetain(address);
CFArrayRemoveValueAtIndex(s->_addressQueue, 0);
}
}
__CFSocketDoCallback(s, data, address, sock); if (NULL != data) CFRelease(data);
if (NULL != address) CFRelease(address);
__CFSocketLock(s);
if (__CFSocketIsValid(s) && kCFSocketNoCallBack != readCallBackType) {
if ((kCFSocketDataCallBack == readCallBackType || kCFSocketAcceptCallBack == readCallBackType) && NULL != s->_dataQueue && 0 < CFArrayGetCount(s->_dataQueue)) {
#if defined(LOG_CFSOCKET)
fprintf(stdout, "perform short-circuit signaling source for socket %d with flags 0x%x disabled 0x%x connected 0x%x\n", s->_socket, s->_f.client, s->_f.disabled, s->_f.connected);
#endif
CFRunLoopSourceSignal(s->_source0);
CFMutableArrayRef runLoopsOrig = (CFMutableArrayRef)CFRetain(s->_runLoops);
CFMutableArrayRef runLoopsCopy = CFArrayCreateMutableCopy(kCFAllocatorSystemDefault, 0, s->_runLoops);
CFRunLoopSourceRef source0 = s->_source0;
if (NULL != source0 && !CFRunLoopSourceIsValid(source0)) {
source0 = NULL;
}
if (source0) CFRetain(source0);
__CFSocketUnlock(s);
rl = __CFSocketCopyRunLoopToWakeUp(source0, runLoopsCopy);
if (source0) CFRelease(source0);
__CFSocketLock(s);
if (runLoopsOrig == s->_runLoops) {
s->_runLoops = runLoopsCopy;
runLoopsCopy = NULL;
CFRelease(runLoopsOrig);
}
CFRelease(runLoopsOrig);
if (runLoopsCopy) CFRelease(runLoopsCopy);
}
}
__CFSocketEnableCallBacks(s, callBacksSignalled & s->_f.client, FALSE, 'p');
if (NULL != rl) {
CFRunLoopWakeUp(rl);
CFRelease(rl);
}
}
CFRunLoopSourceRef CFSocketCreateRunLoopSource(CFAllocatorRef allocator, CFSocketRef s, CFIndex order) {
CHECK_FOR_FORK();
CFRunLoopSourceRef result = NULL;
__CFGenericValidateType(s, CFSocketGetTypeID());
__CFSocketLock(s);
if (__CFSocketIsValid(s)) {
if (NULL != s->_source0 && !CFRunLoopSourceIsValid(s->_source0)) {
CFRelease(s->_source0);
s->_source0 = NULL;
}
if (NULL == s->_source0) {
CFRunLoopSourceContext context;
context.version = 0;
context.info = s;
context.retain = CFRetain;
context.release = CFRelease;
context.copyDescription = CFCopyDescription;
context.equal = CFEqual;
context.hash = CFHash;
context.schedule = __CFSocketSchedule;
context.cancel = __CFSocketCancel;
context.perform = __CFSocketPerformV0;
s->_source0 = CFRunLoopSourceCreate(allocator, order, &context);
}
CFRetain(s->_source0);
result = s->_source0;
}
__CFSocketUnlock(s);
return result;
}
#endif
static uint16_t __CFSocketDefaultNameRegistryPortNumber = 2454;
CONST_STRING_DECL(kCFSocketCommandKey, "Command")
CONST_STRING_DECL(kCFSocketNameKey, "Name")
CONST_STRING_DECL(kCFSocketValueKey, "Value")
CONST_STRING_DECL(kCFSocketResultKey, "Result")
CONST_STRING_DECL(kCFSocketErrorKey, "Error")
CONST_STRING_DECL(kCFSocketRegisterCommand, "Register")
CONST_STRING_DECL(kCFSocketRetrieveCommand, "Retrieve")
CONST_STRING_DECL(__kCFSocketRegistryRequestRunLoopMode, "CFSocketRegistryRequest")
static CFSpinLock_t __CFSocketWriteLock_ = CFSpinLockInit;
CF_INLINE void __CFSocketWriteLock(CFSocketRef s) {
__CFSpinLock(& __CFSocketWriteLock_);
}
CF_INLINE void __CFSocketWriteUnlock(CFSocketRef s) {
__CFSpinUnlock(& __CFSocketWriteLock_);
}
#if NEW_SOCKET
CF_INLINE CFIndex __CFSocketFdGetSize(CFDataRef fdSet) {
return NBBY * CFDataGetLength(fdSet);
}
CF_INLINE Boolean __CFSocketFdSet(CFSocketNativeHandle sock, CFMutableDataRef fdSet) {
Boolean retval = false;
if (INVALID_SOCKET != sock && 0 <= sock) {
CFIndex numFds = NBBY * CFDataGetLength(fdSet);
fd_mask *fds_bits;
if (sock >= numFds) {
CFIndex oldSize = numFds / NFDBITS, newSize = (sock + NFDBITS) / NFDBITS, changeInBytes = (newSize - oldSize) * sizeof(fd_mask);
CFDataIncreaseLength(fdSet, changeInBytes);
fds_bits = (fd_mask *)CFDataGetMutableBytePtr(fdSet);
memset(fds_bits + oldSize, 0, changeInBytes);
} else {
fds_bits = (fd_mask *)CFDataGetMutableBytePtr(fdSet);
}
if (!FD_ISSET(sock, (fd_set *)fds_bits)) {
retval = true;
FD_SET(sock, (fd_set *)fds_bits);
}
}
return retval;
}
#endif
CFSocketError CFSocketSendData(CFSocketRef s, CFDataRef address, CFDataRef data, CFTimeInterval timeout) {
CHECK_FOR_FORK();
const uint8_t *dataptr, *addrptr = NULL;
SInt32 datalen, addrlen = 0, size = 0;
CFSocketNativeHandle sock = INVALID_SOCKET;
struct timeval tv;
__CFGenericValidateType(s, CFSocketGetTypeID());
if (address) {
addrptr = CFDataGetBytePtr(address);
addrlen = CFDataGetLength(address);
}
dataptr = CFDataGetBytePtr(data);
datalen = CFDataGetLength(data);
if (CFSocketIsValid(s)) sock = CFSocketGetNative(s);
if (INVALID_SOCKET != sock) {
CFRetain(s);
__CFSocketWriteLock(s);
tv.tv_sec = (timeout <= 0.0 || (CFTimeInterval)INT_MAX <= timeout) ? INT_MAX : (int)floor(timeout);
tv.tv_usec = (int)floor(1.0e+6 * (timeout - floor(timeout)));
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv)); if (NULL != addrptr && 0 < addrlen) {
size = sendto(sock, (char *)dataptr, datalen, 0, (struct sockaddr *)addrptr, addrlen);
} else {
size = send(sock, (char *)dataptr, datalen, 0);
}
#if defined(LOG_CFSOCKET)
fprintf(stdout, "wrote %ld bytes to socket %d\n", (long)size, sock);
#endif
__CFSocketWriteUnlock(s);
CFRelease(s);
}
return (size > 0) ? kCFSocketSuccess : kCFSocketError;
}
CFSocketError CFSocketSetAddress(CFSocketRef s, CFDataRef address) {
CHECK_FOR_FORK();
struct sockaddr *name;
socklen_t namelen;
__CFGenericValidateType(s, CFSocketGetTypeID());
if (NULL == address) return kCFSocketError;
if (!CFSocketIsValid(s)) return kCFSocketError;
name = (struct sockaddr *)CFDataGetBytePtr(address);
namelen = (socklen_t)CFDataGetLength(address);
if (!name || namelen <= 0) return kCFSocketError;
CFSocketNativeHandle sock = CFSocketGetNative(s);
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
char newName[255];
if (namelen > 2 && name->sa_family == AF_UNIX) {
socklen_t realLength = (sizeof(*((struct sockaddr_un *)name)) - sizeof(((struct sockaddr_un *)name)->sun_path) + strnlen(((struct sockaddr_un *)name)->sun_path, namelen - 2));
if (realLength > 255) return kCFSocketError;
namelen = (socklen_t)(((struct sockaddr_un *)name)->sun_len);
if (realLength != namelen) {
CFLog(kCFLogLevelWarning, CFSTR("WARNING: The sun_len field of a sockaddr_un structure passed to CFSocketSetAddress was not set correctly using the SUN_LEN macro."));
memcpy(newName, name, realLength);
namelen = realLength;
((struct sockaddr_un *)newName)->sun_len = realLength;
name = (struct sockaddr *)newName;
}
}
#endif
int result = bind(sock, name, namelen);
if (0 == result) {
listen(sock, 256);
}
return (CFIndex)result;
}
CFSocketError CFSocketConnectToAddress(CFSocketRef s, CFDataRef address, CFTimeInterval timeout) {
CHECK_FOR_FORK();
const uint8_t *name;
SInt32 namelen, result = -1, connect_err = 0, select_err = 0;
UInt32 yes = 1, no = 0;
Boolean wasBlocking = true;
__CFGenericValidateType(s, CFSocketGetTypeID());
if (!CFSocketIsValid(s)) return kCFSocketError;
name = CFDataGetBytePtr(address);
namelen = CFDataGetLength(address);
if (!name || namelen <= 0) return kCFSocketError;
CFSocketNativeHandle sock = CFSocketGetNative(s);
{
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
SInt32 flags = fcntl(sock, F_GETFL, 0);
if (flags >= 0) wasBlocking = ((flags & O_NONBLOCK) == 0);
if (wasBlocking && (timeout > 0.0 || timeout < 0.0)) ioctlsocket(sock, FIONBIO, (u_long *)&yes);
#else
SInt32 flags = 0;
if (timeout > 0.0 || timeout < 0.0) ioctlsocket(sock, FIONBIO, (u_long *)&yes);
wasBlocking = false;
#endif
result = connect(sock, (struct sockaddr *)name, namelen);
if (result != 0) {
connect_err = __CFSocketLastError();
#if DEPLOYMENT_TARGET_WINDOWS
if (connect_err == WSAEWOULDBLOCK) connect_err = EINPROGRESS;
#endif
}
#if defined(LOG_CFSOCKET)
fprintf(stdout, "connection attempt returns %d error %d on socket %d (flags 0x%x blocking %d)\n", result, connect_err, sock, flags, wasBlocking);
#endif
if (EINPROGRESS == connect_err && timeout >= 0.0) {
SInt32 nrfds;
int error_size = sizeof(select_err);
struct timeval tv;
CFMutableDataRef fds = CFDataCreateMutable(kCFAllocatorSystemDefault, 0);
__CFSocketFdSet(sock, fds);
tv.tv_sec = (timeout <= 0.0 || (CFTimeInterval)INT_MAX <= timeout) ? INT_MAX : (int)floor(timeout);
tv.tv_usec = (int)floor(1.0e+6 * (timeout - floor(timeout)));
nrfds = select(__CFSocketFdGetSize(fds), NULL, (fd_set *)CFDataGetMutableBytePtr(fds), NULL, &tv);
if (nrfds < 0) {
select_err = __CFSocketLastError();
result = -1;
} else if (nrfds == 0) {
result = -2;
} else {
if (0 != getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&select_err, (socklen_t *)&error_size)) select_err = 0;
result = (select_err == 0) ? 0 : -1;
}
CFRelease(fds);
#if defined(LOG_CFSOCKET)
fprintf(stdout, "timed connection attempt %s on socket %d, result %d, select returns %d error %d\n", (result == 0) ? "succeeds" : "fails", sock, result, nrfds, select_err);
#endif
}
if (wasBlocking && (timeout > 0.0 || timeout < 0.0)) ioctlsocket(sock, FIONBIO, (u_long *)&no);
if (EINPROGRESS == connect_err && timeout < 0.0) {
result = 0;
#if defined(LOG_CFSOCKET)
fprintf(stdout, "connection attempt continues in background on socket %d\n", sock);
#endif
}
}
return result;
}
CFSocketRef CFSocketCreate(CFAllocatorRef allocator, SInt32 protocolFamily, SInt32 socketType, SInt32 protocol, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context) {
CHECK_FOR_FORK();
CFSocketNativeHandle sock = INVALID_SOCKET;
CFSocketRef s = NULL;
if (0 >= protocolFamily) protocolFamily = PF_INET;
if (PF_INET == protocolFamily) {
if (0 >= socketType) socketType = SOCK_STREAM;
if (0 >= protocol && SOCK_STREAM == socketType) protocol = IPPROTO_TCP;
if (0 >= protocol && SOCK_DGRAM == socketType) protocol = IPPROTO_UDP;
}
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
if (PF_LOCAL == protocolFamily && 0 >= socketType) socketType = SOCK_STREAM;
#endif
#if DEPLOYMENT_TARGET_WINDOWS
__CFSocketInitializeWinSock();
#endif
sock = socket(protocolFamily, socketType, protocol);
if (INVALID_SOCKET != sock) {
s = CFSocketCreateWithNative(allocator, sock, callBackTypes, callout, context);
}
return s;
}
CFSocketRef CFSocketCreateWithSocketSignature(CFAllocatorRef allocator, const CFSocketSignature *signature, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context) {
CHECK_FOR_FORK();
CFSocketRef s = CFSocketCreate(allocator, signature->protocolFamily, signature->socketType, signature->protocol, callBackTypes, callout, context);
if (NULL != s && (!CFSocketIsValid(s) || kCFSocketSuccess != CFSocketSetAddress(s, signature->address))) {
CFSocketInvalidate(s);
CFRelease(s);
s = NULL;
}
return s;
}
CFSocketRef CFSocketCreateConnectedToSocketSignature(CFAllocatorRef allocator, const CFSocketSignature *signature, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context, CFTimeInterval timeout) {
CHECK_FOR_FORK();
CFSocketRef s = CFSocketCreate(allocator, signature->protocolFamily, signature->socketType, signature->protocol, callBackTypes, callout, context);
if (NULL != s && (!CFSocketIsValid(s) || kCFSocketSuccess != CFSocketConnectToAddress(s, signature->address, timeout))) {
CFSocketInvalidate(s);
CFRelease(s);
s = NULL;
}
return s;
}
typedef struct {
CFSocketError *error;
CFPropertyListRef *value;
CFDataRef *address;
} __CFSocketNameRegistryResponse;
static void __CFSocketHandleNameRegistryReply(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) {
CFDataRef replyData = (CFDataRef)data;
__CFSocketNameRegistryResponse *response = (__CFSocketNameRegistryResponse *)info;
CFDictionaryRef replyDictionary = NULL;
CFPropertyListRef value;
replyDictionary = (CFDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, replyData, kCFPropertyListImmutable, NULL);
if (NULL != response->error) *(response->error) = kCFSocketError;
if (NULL != replyDictionary) {
if (CFGetTypeID((CFTypeRef)replyDictionary) == CFDictionaryGetTypeID() && NULL != (value = CFDictionaryGetValue(replyDictionary, kCFSocketResultKey))) {
if (NULL != response->error) *(response->error) = kCFSocketSuccess;
if (NULL != response->value) *(response->value) = CFRetain(value);
if (NULL != response->address) *(response->address) = address ? CFDataCreateCopy(kCFAllocatorSystemDefault, address) : NULL;
}
CFRelease(replyDictionary);
}
CFSocketInvalidate(s);
}
static void __CFSocketSendNameRegistryRequest(CFSocketSignature *signature, CFDictionaryRef requestDictionary, __CFSocketNameRegistryResponse *response, CFTimeInterval timeout) {
CFDataRef requestData = NULL;
CFSocketContext context = {0, response, NULL, NULL, NULL};
CFSocketRef s = NULL;
CFRunLoopSourceRef source = NULL;
if (NULL != response->error) *(response->error) = kCFSocketError;
requestData = CFPropertyListCreateXMLData(kCFAllocatorSystemDefault, requestDictionary);
if (NULL != requestData) {
if (NULL != response->error) *(response->error) = kCFSocketTimeout;
s = CFSocketCreateConnectedToSocketSignature(kCFAllocatorSystemDefault, signature, kCFSocketDataCallBack, __CFSocketHandleNameRegistryReply, &context, timeout);
if (NULL != s) {
if (kCFSocketSuccess == CFSocketSendData(s, NULL, requestData, timeout)) {
source = CFSocketCreateRunLoopSource(kCFAllocatorSystemDefault, s, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, __kCFSocketRegistryRequestRunLoopMode);
CFRunLoopRunInMode(__kCFSocketRegistryRequestRunLoopMode, timeout, false);
CFRelease(source);
}
CFSocketInvalidate(s);
CFRelease(s);
}
CFRelease(requestData);
}
}
static void __CFSocketValidateSignature(const CFSocketSignature *providedSignature, CFSocketSignature *signature, uint16_t defaultPortNumber) {
struct sockaddr_in sain, *sainp;
memset(&sain, 0, sizeof(sain));
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
sain.sin_len = sizeof(sain);
#endif
sain.sin_family = AF_INET;
sain.sin_port = htons(__CFSocketDefaultNameRegistryPortNumber);
sain.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (NULL == providedSignature) {
signature->protocolFamily = PF_INET;
signature->socketType = SOCK_STREAM;
signature->protocol = IPPROTO_TCP;
signature->address = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)&sain, sizeof(sain));
} else {
signature->protocolFamily = providedSignature->protocolFamily;
signature->socketType = providedSignature->socketType;
signature->protocol = providedSignature->protocol;
if (0 >= signature->protocolFamily) signature->protocolFamily = PF_INET;
if (PF_INET == signature->protocolFamily) {
if (0 >= signature->socketType) signature->socketType = SOCK_STREAM;
if (0 >= signature->protocol && SOCK_STREAM == signature->socketType) signature->protocol = IPPROTO_TCP;
if (0 >= signature->protocol && SOCK_DGRAM == signature->socketType) signature->protocol = IPPROTO_UDP;
}
if (NULL == providedSignature->address) {
signature->address = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)&sain, sizeof(sain));
} else {
sainp = (struct sockaddr_in *)CFDataGetBytePtr(providedSignature->address);
if ((int)sizeof(struct sockaddr_in) <= CFDataGetLength(providedSignature->address) && (AF_INET == sainp->sin_family || 0 == sainp->sin_family)) {
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
sain.sin_len = sizeof(sain);
#endif
sain.sin_family = AF_INET;
sain.sin_port = sainp->sin_port;
if (0 == sain.sin_port) sain.sin_port = htons(defaultPortNumber);
sain.sin_addr.s_addr = sainp->sin_addr.s_addr;
if (htonl(INADDR_ANY) == sain.sin_addr.s_addr) sain.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
signature->address = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)&sain, sizeof(sain));
} else {
signature->address = (CFDataRef)CFRetain(providedSignature->address);
}
}
}
}
CFSocketError CFSocketRegisterValue(const CFSocketSignature *nameServerSignature, CFTimeInterval timeout, CFStringRef name, CFPropertyListRef value) {
CFSocketSignature signature;
CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFSocketError retval = kCFSocketError;
__CFSocketNameRegistryResponse response = {&retval, NULL, NULL};
CFDictionaryAddValue(dictionary, kCFSocketCommandKey, kCFSocketRegisterCommand);
CFDictionaryAddValue(dictionary, kCFSocketNameKey, name);
if (NULL != value) CFDictionaryAddValue(dictionary, kCFSocketValueKey, value);
__CFSocketValidateSignature(nameServerSignature, &signature, __CFSocketDefaultNameRegistryPortNumber);
__CFSocketSendNameRegistryRequest(&signature, dictionary, &response, timeout);
CFRelease(dictionary);
CFRelease(signature.address);
return retval;
}
CFSocketError CFSocketCopyRegisteredValue(const CFSocketSignature *nameServerSignature, CFTimeInterval timeout, CFStringRef name, CFPropertyListRef *value, CFDataRef *serverAddress) {
CFSocketSignature signature;
CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFSocketError retval = kCFSocketError;
__CFSocketNameRegistryResponse response = {&retval, value, serverAddress};
CFDictionaryAddValue(dictionary, kCFSocketCommandKey, kCFSocketRetrieveCommand);
CFDictionaryAddValue(dictionary, kCFSocketNameKey, name);
__CFSocketValidateSignature(nameServerSignature, &signature, __CFSocketDefaultNameRegistryPortNumber);
__CFSocketSendNameRegistryRequest(&signature, dictionary, &response, timeout);
CFRelease(dictionary);
CFRelease(signature.address);
return retval;
}
CFSocketError CFSocketRegisterSocketSignature(const CFSocketSignature *nameServerSignature, CFTimeInterval timeout, CFStringRef name, const CFSocketSignature *signature) {
CFSocketSignature validatedSignature;
CFMutableDataRef data = NULL;
CFSocketError retval;
CFIndex length;
uint8_t bytes[4];
if (NULL == signature) {
retval = CFSocketUnregister(nameServerSignature, timeout, name);
} else {
__CFSocketValidateSignature(signature, &validatedSignature, 0);
if (NULL == validatedSignature.address || 0 > validatedSignature.protocolFamily || 255 < validatedSignature.protocolFamily || 0 > validatedSignature.socketType || 255 < validatedSignature.socketType || 0 > validatedSignature.protocol || 255 < validatedSignature.protocol || 0 >= (length = CFDataGetLength(validatedSignature.address)) || 255 < length) {
retval = kCFSocketError;
} else {
data = CFDataCreateMutable(kCFAllocatorSystemDefault, sizeof(bytes) + length);
bytes[0] = validatedSignature.protocolFamily;
bytes[1] = validatedSignature.socketType;
bytes[2] = validatedSignature.protocol;
bytes[3] = length;
CFDataAppendBytes(data, bytes, sizeof(bytes));
CFDataAppendBytes(data, CFDataGetBytePtr(validatedSignature.address), length);
retval = CFSocketRegisterValue(nameServerSignature, timeout, name, data);
CFRelease(data);
}
CFRelease(validatedSignature.address);
}
return retval;
}
CFSocketError CFSocketCopyRegisteredSocketSignature(const CFSocketSignature *nameServerSignature, CFTimeInterval timeout, CFStringRef name, CFSocketSignature *signature, CFDataRef *nameServerAddress) {
CFDataRef data = NULL;
CFSocketSignature returnedSignature;
const uint8_t *ptr = NULL, *aptr = NULL;
uint8_t *mptr;
CFIndex length = 0;
CFDataRef serverAddress = NULL;
CFSocketError retval = CFSocketCopyRegisteredValue(nameServerSignature, timeout, name, (CFPropertyListRef *)&data, &serverAddress);
if (NULL == data || CFGetTypeID(data) != CFDataGetTypeID() || NULL == (ptr = CFDataGetBytePtr(data)) || (length = CFDataGetLength(data)) < 4) retval = kCFSocketError;
if (kCFSocketSuccess == retval && NULL != signature) {
returnedSignature.protocolFamily = (SInt32)*ptr++;
returnedSignature.socketType = (SInt32)*ptr++;
returnedSignature.protocol = (SInt32)*ptr++;
ptr++;
returnedSignature.address = CFDataCreate(kCFAllocatorSystemDefault, ptr, length - 4);
__CFSocketValidateSignature(&returnedSignature, signature, 0);
CFRelease(returnedSignature.address);
ptr = CFDataGetBytePtr(signature->address);
if (CFDataGetLength(signature->address) >= (int)sizeof(struct sockaddr_in) && AF_INET == ((struct sockaddr *)ptr)->sa_family && NULL != serverAddress && CFDataGetLength(serverAddress) >= (int)sizeof(struct sockaddr_in) && NULL != (aptr = CFDataGetBytePtr(serverAddress)) && AF_INET == ((struct sockaddr *)aptr)->sa_family) {
CFMutableDataRef address = CFDataCreateMutableCopy(kCFAllocatorSystemDefault, CFDataGetLength(signature->address), signature->address);
mptr = CFDataGetMutableBytePtr(address);
((struct sockaddr_in *)mptr)->sin_addr = ((struct sockaddr_in *)aptr)->sin_addr;
CFRelease(signature->address);
signature->address = address;
}
if (NULL != nameServerAddress) *nameServerAddress = serverAddress ? (CFDataRef)CFRetain(serverAddress) : NULL;
}
if (NULL != data) CFRelease(data);
if (NULL != serverAddress) CFRelease(serverAddress);
return retval;
}
CFSocketError CFSocketUnregister(const CFSocketSignature *nameServerSignature, CFTimeInterval timeout, CFStringRef name) {
return CFSocketRegisterValue(nameServerSignature, timeout, name, NULL);
}
CF_EXPORT void CFSocketSetDefaultNameRegistryPortNumber(uint16_t port) {
__CFSocketDefaultNameRegistryPortNumber = port;
}
CF_EXPORT uint16_t CFSocketGetDefaultNameRegistryPortNumber(void) {
return __CFSocketDefaultNameRegistryPortNumber;
}