X-Git-Url: https://git.saurik.com/apple/cf.git/blobdiff_plain/47a9ab1f151d80a00a045f81937ddac81c51a463..bd5b749cf7786ae858ab372fc8f64179736c6515:/RunLoop.subproj/CFSocket.c?ds=inline diff --git a/RunLoop.subproj/CFSocket.c b/RunLoop.subproj/CFSocket.c deleted file mode 100644 index 8635d88..0000000 --- a/RunLoop.subproj/CFSocket.c +++ /dev/null @@ -1,2124 +0,0 @@ -/* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* CFSocket.c - Copyright 1999-2002, Apple, Inc. All rights reserved. - Responsibility: Doug Davidson -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "CFInternal.h" -#if defined(__WIN32__) -#include -#include -// Careful with remapping these - different WinSock routines return different errors than -// on BSD, so if these are used many places they won't work. -#define EINPROGRESS WSAEINPROGRESS -#ifdef EBADF -#undef EBADF -#endif -#define EBADF WSAENOTSOCK -#elif defined(__MACH__) -#include -#else -#include -#include -#include -#include -#include -#endif - -// On Mach we use a v0 RunLoopSource to make client callbacks. That source is signalled by a -// separate SocketManager thread who uses select() to watch the sockets' fds. -// -// On Win32 we (primarily) use a v1 RunLoopSource. Code protected by USE_V1_RUN_LOOP_SOURCE currently -// assumes __WIN32__ is defined. The Win32 v1 RunLoopSource uses a Windows event object to be notified -// of socket events like FD_READ, FD_CONNECT, etc, at which point it can immediately make client -// callbacks instead of doing any inter-thread signaling. -// -// Because of the peculiar way that FD_WRITE is signalled (see WSAEventSelect doc in MSDN), we -// could not implement the current CFSocket client write callback semantics on top of the FD_WRITE -// events received by the v1 source. However, because the performance gains on the read side -// were so great with the v1 source, we use a hybrid approach to implement the write side. Read -// callbacks are triggered straightforwardly by FD_READ events. Write callbacks are triggered in -// two ways. Most commonly, as we return to the core run loop we poll a socket's writability -// using select(). If it can accept bytes, we signal our v1 RunLoopSource such that it will be -// immediately fired, and we can make the write callback. Alternatively, if the socket is full, -// we then use the old v0-style approach of notifying the SocketManager thread to listen for -// notification that the socket can accept bytes using select(). Of course these two modes also -// must respect the various write callback settings and autoenabling flags setup by the client. -// The net effect is that we rarely must interact with the SocketMgr thread, which leads to a -// performance win. -// -// Because of this hybrid, we end up needing both a v1 RunLoopSource (to watch the Windows FD_* -// events) and a v0 RunLoopSource (to be signaled from the socket manager). Since our API exports -// a single RunLoopSource that clients may schedule, we hand out the v0 RunLoopSource, and as it -// is scheduled and canceled we install the v1 RunLoopSource in the same modes. -#if defined(__WIN32__) -#define USE_V1_RUN_LOOP_SOURCE -#endif - -//#define LOG_CFSOCKET - -#if !defined(__WIN32__) -#define INVALID_SOCKET (CFSocketNativeHandle)(-1) -#endif /* __WIN32__ */ - -#define MAX_SOCKADDR_LEN 256 -#define MAX_DATA_SIZE 32768 - -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") - -/* locks are to be acquired in the following order: - (1) __CFAllSocketsLock - (2) an individual CFSocket's lock - (3) __CFActiveSocketsLock -*/ -static CFSpinLock_t __CFAllSocketsLock = 0; /* controls __CFAllSockets */ -static CFMutableDictionaryRef __CFAllSockets = NULL; -static CFSpinLock_t __CFActiveSocketsLock = 0; /* controls __CFRead/WriteSockets, __CFRead/WriteSocketsFds, __CFSocketManagerThread, and __CFSocketManagerIteration */ -static volatile UInt32 __CFSocketManagerIteration = 0; -static CFMutableArrayRef __CFWriteSockets = NULL; -static CFMutableArrayRef __CFReadSockets = NULL; -static CFMutableDataRef __CFWriteSocketsFds = NULL; -static CFMutableDataRef __CFReadSocketsFds = NULL; -#if defined(__WIN32__) -// We need to select on exceptFDs on Win32 to hear of connect failures -static CFMutableDataRef __CFExceptSocketsFds = NULL; -#endif -static CFDataRef zeroLengthData = NULL; - -static CFSocketNativeHandle __CFWakeupSocketPair[2] = {INVALID_SOCKET, INVALID_SOCKET}; -static void *__CFSocketManagerThread = NULL; - -#if !defined(__WIN32__) -#define CFSOCKET_USE_SOCKETPAIR -#define closesocket(a) close((a)) -#define ioctlsocket(a,b,c) ioctl((a),(b),(c)) -#endif - -static CFTypeID __kCFSocketTypeID = _kCFRuntimeNotATypeID; -static void __CFSocketDoCallback(CFSocketRef s, CFDataRef data, CFDataRef address, CFSocketNativeHandle sock); -static void __CFSocketInvalidate(CFSocketRef s, Boolean wakeup); - -struct __CFSocket { - CFRuntimeBase _base; - struct { - unsigned client:8; // flags set by client (reenable, CloseOnInvalidate) - unsigned disabled:8; // flags marking disabled callbacks - unsigned connected:1; // Are we connected yet? (also true for connectionless sockets) - unsigned writableHint:1; // Did the polling the socket show it to be writable? - unsigned closeSignaled:1; // Have we seen FD_CLOSE? (only used on Win32) - unsigned unused:13; - } _f; - CFSpinLock_t _lock; - CFSpinLock_t _writeLock; - CFSocketNativeHandle _socket; /* immutable */ - SInt32 _socketType; - SInt32 _errorCode; - CFDataRef _address; - CFDataRef _peerAddress; - SInt32 _socketSetCount; - CFRunLoopSourceRef _source0; // v0 RLS, messaged from SocketMgr - CFMutableArrayRef _runLoops; - CFSocketCallBack _callout; /* immutable */ - CFSocketContext _context; /* immutable */ -#if !defined(USE_V1_RUN_LOOP_SOURCE) - CFIndex _maxQueueLen; // queues to pass data from SocketMgr thread - CFMutableArrayRef _dataQueue; - CFMutableArrayRef _addressQueue; -#else - CFRunLoopSourceRef _source1; // v1 RLS, triggered by _event happenings - HANDLE _event; // used to hear about socket events - long _oldEventMask; // last event mask value set with WSAEventSelect -#endif -}; - -/* Bit 6 in the base reserved bits is used for write-signalled state (mutable) */ -/* Bit 5 in the base reserved bits is used for read-signalled state (mutable) */ -/* Bit 4 in the base reserved bits is used for invalid state (mutable) */ -/* Bits 0-3 in the base reserved bits are used for callback types (immutable) */ -/* Of this, bits 0-1 are used for the read callback type. */ - -CF_INLINE Boolean __CFSocketIsWriteSignalled(CFSocketRef s) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_info, 6, 6); -} - -CF_INLINE void __CFSocketSetWriteSignalled(CFSocketRef s) { - __CFBitfieldSetValue(((CFRuntimeBase *)s)->_info, 6, 6, 1); -} - -CF_INLINE void __CFSocketUnsetWriteSignalled(CFSocketRef s) { - __CFBitfieldSetValue(((CFRuntimeBase *)s)->_info, 6, 6, 0); -} - -CF_INLINE Boolean __CFSocketIsReadSignalled(CFSocketRef s) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_info, 5, 5); -} - -CF_INLINE void __CFSocketSetReadSignalled(CFSocketRef s) { - __CFBitfieldSetValue(((CFRuntimeBase *)s)->_info, 5, 5, 1); -} - -CF_INLINE void __CFSocketUnsetReadSignalled(CFSocketRef s) { - __CFBitfieldSetValue(((CFRuntimeBase *)s)->_info, 5, 5, 0); -} - -CF_INLINE Boolean __CFSocketIsValid(CFSocketRef s) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_info, 4, 4); -} - -CF_INLINE void __CFSocketSetValid(CFSocketRef s) { - __CFBitfieldSetValue(((CFRuntimeBase *)s)->_info, 4, 4, 1); -} - -CF_INLINE void __CFSocketUnsetValid(CFSocketRef s) { - __CFBitfieldSetValue(((CFRuntimeBase *)s)->_info, 4, 4, 0); -} - -CF_INLINE uint8_t __CFSocketCallBackTypes(CFSocketRef s) { - return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_info, 3, 0); -} - -CF_INLINE uint8_t __CFSocketReadCallBackType(CFSocketRef s) { - return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_info, 1, 0); -} - -CF_INLINE void __CFSocketSetCallBackTypes(CFSocketRef s, uint8_t types) { - __CFBitfieldSetValue(((CFRuntimeBase *)s)->_info, 3, 0, types & 0xF); -} - -CF_INLINE void __CFSocketLock(CFSocketRef s) { - __CFSpinLock(&(s->_lock)); -} - -CF_INLINE void __CFSocketUnlock(CFSocketRef s) { - __CFSpinUnlock(&(s->_lock)); -} - -CF_INLINE void __CFSocketWriteLock(CFSocketRef s) { - __CFSpinLock(&(s->_writeLock)); -} - -CF_INLINE void __CFSocketWriteUnlock(CFSocketRef s) { - __CFSpinUnlock(&(s->_writeLock)); -} - -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) { - /* socket should already be locked */ - 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, &namelen) && NULL != name && 0 < namelen) { - s->_address = CFDataCreate(CFGetAllocator(s), name, namelen); - } -} - -CF_INLINE void __CFSocketEstablishPeerAddress(CFSocketRef s) { - /* socket should already be locked */ - 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, &namelen) && NULL != name && 0 < namelen) { - s->_peerAddress = CFDataCreate(CFGetAllocator(s), name, namelen); - } -} - -CF_INLINE CFIndex __CFSocketFdGetSize(CFDataRef fdSet) { -#if defined(__WIN32__) - fd_set* set = (fd_set*)CFDataGetBytePtr(fdSet); - return set ? set->fd_count : 0; -#else - return NBBY * CFDataGetLength(fdSet); -#endif -} - -CF_INLINE int __CFSocketLastError(void) { -#if defined(__WIN32__) - return WSAGetLastError(); -#else - return thread_errno(); -#endif -} - -static Boolean __CFNativeSocketIsValid(CFSocketNativeHandle sock) { -#if defined(__WIN32__) - SInt32 errorCode = 0; - int errorSize = sizeof(errorCode); - return !(0 != getsockopt(sock, SOL_SOCKET, SO_ERROR, (void *)&errorCode, &errorSize) && WSAGetLastError() == WSAENOTSOCK); -#else - SInt32 flags = fcntl(sock, F_GETFL, 0); - return !(0 > flags && EBADF == thread_errno()); -#endif -} - -CF_INLINE Boolean __CFSocketFdSet(CFSocketNativeHandle sock, CFMutableDataRef fdSet) { - /* returns true if a change occurred, false otherwise */ - Boolean retval = false; - if (INVALID_SOCKET != sock && 0 <= sock) { -#if defined(__WIN32__) - fd_set* set = (fd_set*)CFDataGetMutableBytePtr(fdSet); - if ((set->fd_count * sizeof(SOCKET) + sizeof(u_int)) >= CFDataGetLength(fdSet)) { - CFDataIncreaseLength(fdSet, sizeof(SOCKET)); - set = (fd_set*)CFDataGetMutableBytePtr(fdSet); - } - if (!FD_ISSET(sock, set)) { - retval = true; - FD_SET(sock, set); - } -#else - 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); - } -#endif - } - return retval; -} - -CF_INLINE Boolean __CFSocketFdClr(CFSocketNativeHandle sock, CFMutableDataRef fdSet) { - /* returns true if a change occurred, false otherwise */ - Boolean retval = false; - if (INVALID_SOCKET != sock && 0 <= sock) { -#if defined(__WIN32__) - fd_set* set = (fd_set*)CFDataGetMutableBytePtr(fdSet); - if (FD_ISSET(sock, set)) { - retval = true; - FD_CLR(sock, set); - } -#else - 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); - } - } -#endif - } - return retval; -} - -static SInt32 __CFSocketCreateWakeupSocketPair(void) { -#if defined(CFSOCKET_USE_SOCKETPAIR) - return socketpair(PF_LOCAL, SOCK_DGRAM, 0, __CFWakeupSocketPair); -#else - //??? should really use native Win32 facilities - 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; - } - return error; -#endif -} - -#if defined(USE_V1_RUN_LOOP_SOURCE) -// Version 1 RunLoopSources set a mask in a Windows System Event to control what socket activity we -// hear about. Because you can only set the mask as a whole, we must remember the previous value so -// set can make relative changes to it. The way we enable/disable precludes calculating the whole -// mask from scratch from the current state we keep. - -static Boolean __CFSocketSetWholeEventMask(CFSocketRef s, long newMask) { - if (s->_oldEventMask != newMask) { - int err; -#if defined(LOG_CFSOCKET) - fprintf(stdout, "calling WSAEventSelect for socket/event %d/%d with event flags 0x%lx\n", s->_socket, (int)s->_event, newMask); -#endif - err = WSAEventSelect(s->_socket, s->_event, newMask); - CFAssert2(0 == err, __kCFLogAssertion, "%s(): WSAEventSelect failed: %d", __PRETTY_FUNCTION__, WSAGetLastError()); - s->_oldEventMask = newMask; - return TRUE; - } else - return FALSE; -} - -CF_INLINE Boolean __CFSocketSetFDForRead(CFSocketRef s) { - long bitToSet; - // we assume that some read bits are set - all callers have checked this - CFAssert1(0 != __CFSocketReadCallBackType(s), __kCFLogAssertion, "%s(): __CFSocketReadCallBackType is zero", __PRETTY_FUNCTION__); - bitToSet = (__CFSocketReadCallBackType(s) == kCFSocketAcceptCallBack) ? FD_ACCEPT : FD_READ; - return __CFSocketSetWholeEventMask(s, s->_oldEventMask | bitToSet); -} - -CF_INLINE Boolean __CFSocketClearFDForRead(CFSocketRef s) { - long bitToClear; - // we assume that some read bits are set - all callers have checked this - CFAssert1(0 != __CFSocketReadCallBackType(s), __kCFLogAssertion, "%s(): __CFSocketReadCallBackType is zero", __PRETTY_FUNCTION__); - bitToClear = (__CFSocketReadCallBackType(s) == kCFSocketAcceptCallBack) ? FD_ACCEPT : FD_READ; - return __CFSocketSetWholeEventMask(s, s->_oldEventMask & ~bitToClear); -} - -#else // !USE_V1_RUN_LOOP_SOURCE -// Version 0 RunLoopSources set a mask in an FD set to control what socket activity we hear about. -CF_INLINE Boolean __CFSocketSetFDForRead(CFSocketRef s) { - return __CFSocketFdSet(s->_socket, __CFReadSocketsFds); -} - -CF_INLINE Boolean __CFSocketClearFDForRead(CFSocketRef s) { - return __CFSocketFdClr(s->_socket, __CFReadSocketsFds); -} -#endif - -CF_INLINE Boolean __CFSocketSetFDForWrite(CFSocketRef s) { - return __CFSocketFdSet(s->_socket, __CFWriteSocketsFds); -} - -CF_INLINE Boolean __CFSocketClearFDForWrite(CFSocketRef s) { - return __CFSocketFdClr(s->_socket, __CFWriteSocketsFds); -} - -#if defined(USE_V1_RUN_LOOP_SOURCE) -static Boolean __CFSocketCanAcceptBytes(CFSocketRef s) { - struct timeval timeout = {0, 0}; - fd_set set; - int result; - FD_ZERO(&set); - FD_SET(s->_socket, &set); - result = select(s->_socket + 1, NULL, &set, NULL, &timeout); -#if defined(LOG_CFSOCKET) - fprintf(stdout, "polling writability of %d yields %d\n", s->_socket, result); -#endif - return result == 1; -} - -static Boolean __CFSocketHasBytesToRead(CFSocketRef s) { - unsigned long avail; - int err = ioctlsocket(s->_socket, FIONREAD, &avail); - CFAssert3(0 == err, __kCFLogAssertion, "%s(): unexpected error from ioctlsocket(%d, FIONREAD,...): %d", __PRETTY_FUNCTION__, s->_socket, WSAGetLastError()); -#if defined(LOG_CFSOCKET) - fprintf(stdout, "polling readability of %d yields %ld\n", s->_socket, avail); -#endif - return (0 == err) && avail > 0; -} -#endif - -#if defined(__WIN32__) -static Boolean WinSockUsed = FALSE; - -static void __CFSocketInitializeWinSock_Guts(void) { - if (!WinSockUsed) { - WinSockUsed = TRUE; - WORD versionRequested = MAKEWORD(2, 0); - WSADATA wsaData; - int errorStatus = WSAStartup(versionRequested, &wsaData); - if (errorStatus != 0 || LOBYTE(wsaData.wVersion) != LOBYTE(versionRequested) || HIBYTE(wsaData.wVersion) != HIBYTE(versionRequested)) { - WSACleanup(); - CFLog(0, CFSTR("*** Could not initialize WinSock subsystem!!!")); - } - } -} - -CF_EXPORT void __CFSocketInitializeWinSock(void) { - __CFSpinLock(&__CFActiveSocketsLock); - __CFSocketInitializeWinSock_Guts(); - __CFSpinUnlock(&__CFActiveSocketsLock); -} - -__private_extern__ void __CFSocketCleanup(void) { - __CFSpinLock(&__CFActiveSocketsLock); - if (NULL != __CFReadSockets) { - CFRelease(__CFWriteSockets); - __CFWriteSockets = NULL; - CFRelease(__CFReadSockets); - __CFReadSockets = NULL; - CFRelease(__CFWriteSocketsFds); - __CFWriteSocketsFds = NULL; - CFRelease(__CFReadSocketsFds); - __CFReadSocketsFds = NULL; - CFRelease(__CFExceptSocketsFds); - __CFExceptSocketsFds = NULL; - CFRelease(zeroLengthData); - zeroLengthData = NULL; - } - if (NULL != __CFAllSockets) { - CFRelease(__CFAllSockets); - __CFAllSockets = NULL; - } - 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(); - } - __CFSpinUnlock(&__CFActiveSocketsLock); -} -#endif - -// CFNetwork needs to call this, especially for Win32 to get WSAStartup -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 defined(__WIN32__) - __CFSocketInitializeWinSock_Guts(); - // make sure we have space for the count field and the first socket - CFDataIncreaseLength(__CFWriteSocketsFds, sizeof(u_int) + sizeof(SOCKET)); - CFDataIncreaseLength(__CFReadSocketsFds, sizeof(u_int) + sizeof(SOCKET)); - __CFExceptSocketsFds = CFDataCreateMutable(kCFAllocatorSystemDefault, 0); - CFDataIncreaseLength(__CFExceptSocketsFds, sizeof(u_int) + sizeof(SOCKET)); -#endif - if (0 > __CFSocketCreateWakeupSocketPair()) { - CFLog(0, CFSTR("*** Could not create wakeup socket pair for CFSocket!!!")); - } else { - UInt32 yes = 1; - /* wakeup sockets must be non-blocking */ - ioctlsocket(__CFWakeupSocketPair[0], FIONBIO, &yes); - ioctlsocket(__CFWakeupSocketPair[1], FIONBIO, &yes); - __CFSocketFdSet(__CFWakeupSocketPair[1], __CFReadSocketsFds); - } -} - -static CFRunLoopRef __CFSocketCopyRunLoopToWakeUp(CFSocketRef s) { - CFRunLoopRef rl = NULL; - SInt32 idx, cnt = CFArrayGetCount(s->_runLoops); - if (0 < cnt) { - rl = (CFRunLoopRef)CFArrayGetValueAtIndex(s->_runLoops, 0); - for (idx = 1; NULL != rl && idx < cnt; idx++) { - CFRunLoopRef value = (CFRunLoopRef)CFArrayGetValueAtIndex(s->_runLoops, idx); - if (value != rl) rl = NULL; - } - if (NULL == rl) { /* more than one different rl, so we must pick one */ - /* ideally, this would be a run loop which isn't also in a - * signaled state for this or another source, but that's tricky; - * we pick one that is running in an appropriate mode for this - * source, and from those if possible one that is waiting; then - * we move this run loop to the end of the list to scramble them - * a bit, and always search from the front */ - Boolean foundIt = false, foundBackup = false; - SInt32 foundIdx = 0; - for (idx = 0; !foundIt && idx < cnt; idx++) { - CFRunLoopRef value = (CFRunLoopRef)CFArrayGetValueAtIndex(s->_runLoops, idx); - CFStringRef currentMode = CFRunLoopCopyCurrentMode(value); - if (NULL != currentMode) { - if (CFRunLoopContainsSource(value, s->_source0, currentMode)) { - if (CFRunLoopIsWaiting(value)) { - foundIdx = idx; - foundIt = true; - } else if (!foundBackup) { - foundIdx = idx; - foundBackup = true; - } - } - CFRelease(currentMode); - } - } - rl = (CFRunLoopRef)CFArrayGetValueAtIndex(s->_runLoops, foundIdx); - CFRetain(rl); - CFArrayRemoveValueAtIndex(s->_runLoops, foundIdx); - CFArrayAppendValue(s->_runLoops, rl); - } else { - CFRetain(rl); - } - } - return rl; -} - -// If callBackNow, we immediately do client callbacks, else we have to signal a v0 RunLoopSource so the -// callbacks can happen in another thread. -static void __CFSocketHandleWrite(CFSocketRef s, Boolean callBackNow) { - SInt32 errorCode = 0; - int errorSize = sizeof(errorCode); - CFOptionFlags writeCallBacksAvailable; - - if (!CFSocketIsValid(s)) return; - if (0 != getsockopt(s->_socket, SOL_SOCKET, SO_ERROR, (void *)&errorCode, &errorSize)) errorCode = 0; // cast for WinSock bad API -#if defined(LOG_CFSOCKET) - if (errorCode) fprintf(stdout, "error %ld on socket %d\n", 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 { - CFRunLoopRef rl; - CFRunLoopSourceSignal(s->_source0); - rl = __CFSocketCopyRunLoopToWakeUp(s); - __CFSocketUnlock(s); - if (NULL != rl) { - CFRunLoopWakeUp(rl); - CFRelease(rl); - } - } -} - -static void __CFSocketHandleRead(CFSocketRef s) { - CFDataRef data = NULL, address = NULL; - CFSocketNativeHandle sock = INVALID_SOCKET; - if (!CFSocketIsValid(s)) return; - if (__CFSocketReadCallBackType(s) == kCFSocketDataCallBack) { - uint8_t buffer[MAX_DATA_SIZE]; - uint8_t name[MAX_SOCKADDR_LEN]; - int namelen = sizeof(name); - SInt32 recvlen = recvfrom(s->_socket, buffer, sizeof(buffer), 0, (struct sockaddr *)name, &namelen); -#if defined(LOG_CFSOCKET) - fprintf(stdout, "read %ld bytes on socket %d\n", recvlen, s->_socket); -#endif - if (0 >= recvlen) { - //??? should return error if <0 - /* zero-length data is the signal for perform to invalidate */ - data = CFRetain(zeroLengthData); - } else { - data = CFDataCreate(CFGetAllocator(s), buffer, recvlen); - } - __CFSocketLock(s); - if (!__CFSocketIsValid(s)) { - CFRelease(data); - __CFSocketUnlock(s); - return; - } - __CFSocketSetReadSignalled(s); - if (NULL != name && 0 < namelen) { - //??? possible optimizations: uniquing; storing last value - address = CFDataCreate(CFGetAllocator(s), name, namelen); - } else if (__CFSocketIsConnectionOriented(s)) { - if (NULL == s->_peerAddress) __CFSocketEstablishPeerAddress(s); - if (NULL != s->_peerAddress) address = CFRetain(s->_peerAddress); - } - if (NULL == address) { - address = CFRetain(zeroLengthData); - } -#if !defined(USE_V1_RUN_LOOP_SOURCE) - 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); -#endif // !USE_V1_RUN_LOOP_SOURCE - if (0 < recvlen - && (s->_f.client & kCFSocketDataCallBack) != 0 && (s->_f.disabled & kCFSocketDataCallBack) == 0 - && __CFSocketIsScheduled(s) -#if !defined(USE_V1_RUN_LOOP_SOURCE) - && (0 == s->_maxQueueLen || CFArrayGetCount(s->_dataQueue) < s->_maxQueueLen) -#endif // !USE_V1_RUN_LOOP_SOURCE - ) { - __CFSpinLock(&__CFActiveSocketsLock); - /* restore socket to fds */ - __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, &namelen); - if (INVALID_SOCKET == sock) { - //??? should return error - return; - } - if (NULL != name && 0 < namelen) { - address = CFDataCreate(CFGetAllocator(s), name, namelen); - } else { - address = CFRetain(zeroLengthData); - } - __CFSocketLock(s); - if (!__CFSocketIsValid(s)) { - closesocket(sock); - CFRelease(address); - __CFSocketUnlock(s); - return; - } - __CFSocketSetReadSignalled(s); -#if !defined(USE_V1_RUN_LOOP_SOURCE) - 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 *)sock); - CFArrayAppendValue(s->_addressQueue, address); - CFRelease(address); -#endif // !USE_V1_RUN_LOOP_SOURCE - if ((s->_f.client & kCFSocketAcceptCallBack) != 0 && (s->_f.disabled & kCFSocketAcceptCallBack) == 0 - && __CFSocketIsScheduled(s) -#if !defined(USE_V1_RUN_LOOP_SOURCE) - && (0 == s->_maxQueueLen || CFArrayGetCount(s->_dataQueue) < s->_maxQueueLen) -#endif // !USE_V1_RUN_LOOP_SOURCE - ) { - __CFSpinLock(&__CFActiveSocketsLock); - /* restore socket to fds */ - __CFSocketSetFDForRead(s); - __CFSpinUnlock(&__CFActiveSocketsLock); - } - } else { - __CFSocketLock(s); - if (!__CFSocketIsValid(s) || (s->_f.disabled & kCFSocketReadCallBack) != 0) { - __CFSocketUnlock(s); - return; - } - __CFSocketSetReadSignalled(s); - } -#if defined(LOG_CFSOCKET) - fprintf(stdout, "read signaling source for socket %d\n", s->_socket); -#endif -#if defined(USE_V1_RUN_LOOP_SOURCE) - // since in the v0 case data and sock come from the same queue, only one could be set - CFAssert1(NULL == data || 0 == sock, __kCFLogAssertion, "%s(): both data and sock are set", __PRETTY_FUNCTION__); - __CFSocketDoCallback(s, data, address, sock); // does __CFSocketUnlock(s) - if (NULL != data) CFRelease(data); - if (NULL != address) CFRelease(address); -#else - CFRunLoopSourceSignal(s->_source0); - CFRunLoopRef rl = __CFSocketCopyRunLoopToWakeUp(s); - __CFSocketUnlock(s); - if (NULL != rl) { - CFRunLoopWakeUp(rl); - CFRelease(rl); - } -#endif // !USE_V1_RUN_LOOP_SOURCE -} - -#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)) // mostly interesting for shutting up a warning -#endif -static void __CFSocketManager(void * arg) -{ - SInt32 nrfds, maxnrfds, fdentries = 1; - SInt32 rfds, wfds; -#if defined(__WIN32__) - fd_set *exceptfds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, fdentries * sizeof(SOCKET) + sizeof(u_int), 0); - fd_set *writefds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, fdentries * sizeof(SOCKET) + sizeof(u_int), 0); - fd_set *readfds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, fdentries * sizeof(SOCKET) + sizeof(u_int), 0); -#else - 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); -#endif - fd_set *tempfds; - SInt32 idx, cnt; - uint8_t buffer[256]; - CFMutableArrayRef selectedWriteSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); - CFMutableArrayRef selectedReadSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); - - for (;;) { - __CFSpinLock(&__CFActiveSocketsLock); - __CFSocketManagerIteration++; -#if defined(LOG_CFSOCKET) - fprintf(stdout, "socket manager iteration %lu looking at read sockets ", __CFSocketManagerIteration); - __CFSocketWriteSocketList(__CFReadSockets, __CFReadSocketsFds, FALSE); - if (0 < CFArrayGetCount(__CFWriteSockets)) { - fprintf(stdout, " and write sockets "); - __CFSocketWriteSocketList(__CFWriteSockets, __CFWriteSocketsFds, FALSE); -#if defined(__WIN32__) - fprintf(stdout, " and except sockets "); - __CFSocketWriteSocketList(__CFWriteSockets, __CFExceptSocketsFds, TRUE); -#endif - } - fprintf(stdout, "\n"); -#endif - rfds = __CFSocketFdGetSize(__CFReadSocketsFds); - wfds = __CFSocketFdGetSize(__CFWriteSocketsFds); - maxnrfds = __CFMax(rfds, wfds); -#if defined(__WIN32__) - if (maxnrfds > fdentries) { - fdentries = maxnrfds; - exceptfds = (fd_set *)CFAllocatorReallocate(kCFAllocatorSystemDefault, exceptfds, fdentries * sizeof(SOCKET) + sizeof(u_int), 0); - writefds = (fd_set *)CFAllocatorReallocate(kCFAllocatorSystemDefault, writefds, fdentries * sizeof(SOCKET) + sizeof(u_int), 0); - readfds = (fd_set *)CFAllocatorReallocate(kCFAllocatorSystemDefault, readfds, fdentries * sizeof(SOCKET) + sizeof(u_int), 0); - } - memset(exceptfds, 0, fdentries * sizeof(SOCKET) + sizeof(u_int)); - memset(writefds, 0, fdentries * sizeof(SOCKET) + sizeof(u_int)); - memset(readfds, 0, fdentries * sizeof(SOCKET) + sizeof(u_int)); - CFDataGetBytes(__CFExceptSocketsFds, CFRangeMake(0, __CFSocketFdGetSize(__CFExceptSocketsFds) * sizeof(SOCKET) + sizeof(u_int)), (UInt8 *)exceptfds); - CFDataGetBytes(__CFWriteSocketsFds, CFRangeMake(0, wfds * sizeof(SOCKET) + sizeof(u_int)), (UInt8 *)writefds); - CFDataGetBytes(__CFReadSocketsFds, CFRangeMake(0, rfds * sizeof(SOCKET) + sizeof(u_int)), (UInt8 *)readfds); -#else - 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); -#endif - __CFSpinUnlock(&__CFActiveSocketsLock); - - nrfds = select(maxnrfds, readfds, writefds, exceptfds, NULL); -#if defined(LOG_CFSOCKET) - fprintf(stdout, "socket manager woke from select, ret=%ld\n", nrfds); -#endif - if (0 == nrfds) continue; - if (0 > nrfds) { - SInt32 selectError = __CFSocketLastError(); -#if defined(LOG_CFSOCKET) - fprintf(stdout, "socket manager received error %ld from select\n", 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)), false); - } - CFRelease(invalidSockets); - } - continue; - } - if (FD_ISSET(__CFWakeupSocketPair[1], readfds)) { - recv(__CFWakeupSocketPair[1], 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; -#if !defined(__WIN32__) - // We might have an new element in __CFWriteSockets that we weren't listening to, - // in which case we must be sure not to test a bit in the fdset that is - // outside our mask size. - Boolean sockInBounds = (0 <= sock && sock < maxnrfds); -#else - // fdset's are arrays, so we don't have that issue above - Boolean sockInBounds = true; -#endif - if (INVALID_SOCKET != sock && sockInBounds) { - if (FD_ISSET(sock, writefds)) { - CFArrayAppendValue(selectedWriteSockets, s); - /* socket is removed from fds here, restored by CFSocketReschedule */ - if (!tempfds) tempfds = (fd_set *)CFDataGetMutableBytePtr(__CFWriteSocketsFds); - FD_CLR(sock, tempfds); -#if defined(__WIN32__) - fd_set *exfds = (fd_set *)CFDataGetMutableBytePtr(__CFExceptSocketsFds); - FD_CLR(sock, exfds); -#endif - } -#if defined(__WIN32__) - else if (FD_ISSET(sock, exceptfds)) { - // On Win32 connect errors come in on exceptFDs. We treat these as if - // they had come on writeFDs, since the rest of our Unix-based code - // expects that. - CFArrayAppendValue(selectedWriteSockets, s); - fd_set *exfds = (fd_set *)CFDataGetMutableBytePtr(__CFExceptSocketsFds); - FD_CLR(sock, exfds); - } -#endif - } - } - tempfds = NULL; - cnt = CFArrayGetCount(__CFReadSockets); - for (idx = 0; idx < cnt; idx++) { - CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFReadSockets, idx); - CFSocketNativeHandle sock = s->_socket; -#if !defined(__WIN32__) - // We might have an new element in __CFReadSockets that we weren't listening to, - // in which case we must be sure not to test a bit in the fdset that is - // outside our mask size. - Boolean sockInBounds = (0 <= sock && sock < maxnrfds); -#else - // fdset's are arrays, so we don't have that issue above - Boolean sockInBounds = true; -#endif - if (INVALID_SOCKET != sock && sockInBounds && FD_ISSET(sock, readfds)) { - CFArrayAppendValue(selectedReadSockets, s); - /* socket is removed from fds here, will be restored in read handling or in perform function */ - if (!tempfds) tempfds = (fd_set *)CFDataGetMutableBytePtr(__CFReadSocketsFds); - FD_CLR(sock, tempfds); - } - } - __CFSpinUnlock(&__CFActiveSocketsLock); - - cnt = CFArrayGetCount(selectedWriteSockets); - for (idx = 0; idx < cnt; idx++) { - CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(selectedWriteSockets, idx); -#if defined(LOG_CFSOCKET) - fprintf(stdout, "socket manager signaling socket %d for write\n", s->_socket); -#endif - __CFSocketHandleWrite(s, FALSE); - } - if (0 < cnt) CFArrayRemoveAllValues(selectedWriteSockets); - cnt = CFArrayGetCount(selectedReadSockets); - for (idx = 0; idx < cnt; idx++) { - CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(selectedReadSockets, idx); -#if defined(LOG_CFSOCKET) - fprintf(stdout, "socket manager signaling socket %d for read\n", s->_socket); -#endif - __CFSocketHandleRead(s); - } - if (0 < cnt) CFArrayRemoveAllValues(selectedReadSockets); - } -} - -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); - CFStringAppendFormat(result, NULL, CFSTR("{valid = %s, type = %d, socket = %d, socket set count = %ld\n callback types = 0x%x, callout = %x, source = %p,\n run loops = %@,\n context = "), cf, CFGetAllocator(s), (__CFSocketIsValid(s) ? "Yes" : "No"), s->_socketType, s->_socket, s->_socketSetCount, __CFSocketCallBackTypes(s), s->_callout, 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(""), contextInfo); - } - CFStringAppend(result, contextDesc); - CFRelease(contextDesc); - return result; -} - -static void __CFSocketDeallocate(CFTypeRef cf) { - /* Since CFSockets are cached, we can only get here sometime after being invalidated */ - CFSocketRef s = (CFSocketRef)cf; - if (NULL != s->_address) { - CFRelease(s->_address); - s->_address = NULL; - } -} - -static const CFRuntimeClass __CFSocketClass = { - 0, - "CFSocket", - NULL, // init - NULL, // copy - __CFSocketDeallocate, - NULL, // equal - NULL, // hash - NULL, // - __CFSocketCopyDescription -}; - -__private_extern__ void __CFSocketInitialize(void) { - __kCFSocketTypeID = _CFRuntimeRegisterClass(&__CFSocketClass); -} - -CFTypeID CFSocketGetTypeID(void) { - return __kCFSocketTypeID; -} - -CFSocketError CFSocketSetAddress(CFSocketRef s, CFDataRef address) { - const uint8_t *name; - SInt32 namelen, result = 0; - __CFGenericValidateType(s, __kCFSocketTypeID); - if (NULL == address) return -1; - name = CFDataGetBytePtr(address); - namelen = CFDataGetLength(address); - __CFSocketLock(s); - if (__CFSocketIsValid(s) && INVALID_SOCKET != s->_socket && NULL != name && 0 < namelen) { - result = bind(s->_socket, (struct sockaddr *)name, namelen); - if (0 == result) { - __CFSocketEstablishAddress(s); - listen(s->_socket, 256); - } - } - if (NULL == s->_address && NULL != name && 0 < namelen && 0 == result) { - s->_address = CFDataCreateCopy(CFGetAllocator(s), address); - } - __CFSocketUnlock(s); - //??? should return errno - return result; -} - -__private_extern__ void CFSocketSetAcceptBacklog(CFSocketRef s, CFIndex limit) { - __CFGenericValidateType(s, __kCFSocketTypeID); - __CFSocketLock(s); - if (__CFSocketIsValid(s) && INVALID_SOCKET != s->_socket) { - listen(s->_socket, limit); - } - __CFSocketUnlock(s); -} - -__private_extern__ void CFSocketSetMaximumQueueLength(CFSocketRef s, CFIndex length) { - __CFGenericValidateType(s, __kCFSocketTypeID); -#if !defined(USE_V1_RUN_LOOP_SOURCE) - __CFSocketLock(s); - if (__CFSocketIsValid(s)) { - s->_maxQueueLen = length; - } - __CFSocketUnlock(s); -#endif -} - -CFSocketError CFSocketConnectToAddress(CFSocketRef s, CFDataRef address, CFTimeInterval timeout) { - //??? need error handling, retries - const uint8_t *name; - SInt32 namelen, result = -1, connect_err = 0, select_err = 0; - UInt32 yes = 1, no = 0; - Boolean wasBlocking = true; - - __CFGenericValidateType(s, __kCFSocketTypeID); - name = CFDataGetBytePtr(address); - namelen = CFDataGetLength(address); - __CFSocketLock(s); - if (__CFSocketIsValid(s) && INVALID_SOCKET != s->_socket && NULL != name && 0 < namelen) { -#if !defined(__WIN32__) - SInt32 flags = fcntl(s->_socket, F_GETFL, 0); - if (flags >= 0) wasBlocking = ((flags & O_NONBLOCK) == 0); - if (wasBlocking && (timeout > 0.0 || timeout < 0.0)) ioctlsocket(s->_socket, FIONBIO, &yes); -#else - // You can set but not get this flag in WIN32, so assume it was in non-blocking mode. - // The downside is that when we leave this routine we'll leave it non-blocking, - // whether it started that way or not. - if (timeout > 0.0 || timeout < 0.0) ioctlsocket(s->_socket, FIONBIO, &yes); - wasBlocking = false; -#endif - result = connect(s->_socket, (struct sockaddr *)name, namelen); - if (result != 0) { - connect_err = __CFSocketLastError(); -#if defined(__WIN32__) - if (connect_err == WSAEWOULDBLOCK) connect_err = EINPROGRESS; -#endif - } -#if defined(LOG_CFSOCKET) -#if !defined(__WIN32__) - fprintf(stdout, "connection attempt returns %ld error %ld on socket %d (flags 0x%lx blocking %d)\n", result, connect_err, s->_socket, flags, wasBlocking); -#else - fprintf(stdout, "connection attempt returns %ld error %ld on socket %d\n", result, connect_err, s->_socket); -#endif -#endif - if (EINPROGRESS == connect_err && timeout >= 0.0) { - /* select on socket */ - SInt32 nrfds; - int error_size = sizeof(select_err); - struct timeval tv; - CFMutableDataRef fds = CFDataCreateMutable(kCFAllocatorSystemDefault, 0); -#if defined(__WIN32__) - CFDataIncreaseLength(fds , sizeof(u_int) + sizeof(SOCKET)); -#endif - __CFSocketFdSet(s->_socket, fds); - tv.tv_sec = (0 >= timeout || INT_MAX <= timeout) ? INT_MAX : (int)(float)floor(timeout); - tv.tv_usec = (int)((timeout - floor(timeout)) * 1.0E6); - 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(s->_socket, SOL_SOCKET, SO_ERROR, (void *)&select_err, &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 %ld, select returns %ld error %ld\n", (result == 0) ? "succeeds" : "fails", s->_socket, result, nrfds, select_err); -#endif - } - if (wasBlocking && (timeout > 0.0 || timeout < 0.0)) ioctlsocket(s->_socket, FIONBIO, &no); - if (0 == result) { - __CFSocketEstablishPeerAddress(s); - if (NULL == s->_peerAddress && NULL != name && 0 < namelen && __CFSocketIsConnectionOriented(s)) { - s->_peerAddress = CFDataCreateCopy(CFGetAllocator(s), address); - } - } - if (EINPROGRESS == connect_err && timeout < 0.0) { - result = 0; -#if defined(LOG_CFSOCKET) - fprintf(stdout, "connection attempt continues in background on socket %d\n", s->_socket); -#endif - } - } - __CFSocketUnlock(s); - //??? should return errno - return result; -} - -CFSocketRef CFSocketCreate(CFAllocatorRef allocator, SInt32 protocolFamily, SInt32 socketType, SInt32 protocol, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context) { - 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 !defined(__WIN32__) - if (PF_LOCAL == protocolFamily && 0 >= socketType) socketType = SOCK_STREAM; -#else - /* WinSock needs to be initialized at this point for Windows, before socket() */ - __CFSocketInitializeWinSock(); -#endif - sock = socket(protocolFamily, socketType, protocol); - if (INVALID_SOCKET != sock) { - s = CFSocketCreateWithNative(allocator, sock, callBackTypes, callout, context); - } - return s; -} - -CFSocketRef CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketNativeHandle sock, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context) { - 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 *)sock, (const void **)&memory)) { - __CFSpinUnlock(&__CFAllSocketsLock); - CFRetain(memory); - return memory; - } - memory = (CFSocketRef)_CFRuntimeCreateInstance(allocator, __kCFSocketTypeID, 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 = 0; - memory->_writeLock = 0; - memory->_socket = sock; - if (INVALID_SOCKET == sock || 0 != getsockopt(sock, SOL_SOCKET, SO_TYPE, (void *)&(memory->_socketType), &typeSize)) memory->_socketType = 0; // cast for WinSock bad API - memory->_errorCode = 0; - memory->_address = NULL; - memory->_peerAddress = NULL; - memory->_socketSetCount = 0; - memory->_source0 = NULL; - if (INVALID_SOCKET != sock) { - memory->_runLoops = CFArrayCreateMutable(allocator, 0, NULL); - } else { - memory->_runLoops = NULL; - } - memory->_callout = callout; -#if defined(USE_V1_RUN_LOOP_SOURCE) - memory->_event = CreateEvent(NULL, true, false, NULL); - CFAssert1(NULL != memory->_event, __kCFLogAssertion, "%s(): could not create event", __PRETTY_FUNCTION__); - memory->_oldEventMask = 0; - __CFSocketSetWholeEventMask(memory, FD_CLOSE|FD_CONNECT); // always listen for closes, connects - memory->_source1 = NULL; -#else // !USE_V1_RUN_LOOP_SOURCE - memory->_dataQueue = NULL; - memory->_addressQueue = NULL; - memory->_maxQueueLen = 0; -#endif // !USE_V1_RUN_LOOP_SOURCE - memory->_context.info = 0; - memory->_context.retain = 0; - memory->_context.release = 0; - memory->_context.copyDescription = 0; - if (INVALID_SOCKET != sock) CFDictionaryAddValue(__CFAllSockets, (void *)sock, memory); - __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); - } - return memory; -} - -CFSocketRef CFSocketCreateWithSocketSignature(CFAllocatorRef allocator, const CFSocketSignature *signature, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context) { - 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) { - 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; -} - -static void __CFSocketInvalidate(CFSocketRef s, Boolean wakeup) { - UInt32 previousSocketManagerIteration; - __CFGenericValidateType(s, __kCFSocketTypeID); -#if defined(LOG_CFSOCKET) - fprintf(stdout, "invalidating socket %d with flags 0x%x disabled 0x%x connected 0x%x wakeup %d\n", s->_socket, s->_f.client, s->_f.disabled, s->_f.connected, wakeup); -#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); -#if defined(__WIN32__) - __CFSocketFdClr(s->_socket, __CFExceptSocketsFds); -#endif - } -#if !defined(USE_V1_RUN_LOOP_SOURCE) - // No need to clear FD's for V1 sources, since we'll just throw the whole event away - idx = CFArrayGetFirstIndexOfValue(__CFReadSockets, CFRangeMake(0, CFArrayGetCount(__CFReadSockets)), s); - if (0 <= idx) { - CFArrayRemoveValueAtIndex(__CFReadSockets, idx); - __CFSocketClearFDForRead(s); - } -#endif // !USE_V1_RUN_LOOP_SOURCE - previousSocketManagerIteration = __CFSocketManagerIteration; - __CFSpinUnlock(&__CFActiveSocketsLock); -#if 0 - if (wakeup && __CFSocketManagerThread) { - Boolean doneWaiting = false; - uint8_t c = 'i'; -#if defined(LOG_CFSOCKET) - fprintf(stdout, "invalidation wants socket iteration to change from %lu\n", previousSocketManagerIteration); -#endif - send(__CFWakeupSocketPair[0], &c, sizeof(c), 0); -#if !defined(__WIN32__) - while (!doneWaiting) { - __CFSpinLock(&__CFActiveSocketsLock); - if (previousSocketManagerIteration != __CFSocketManagerIteration) doneWaiting = true; -#if defined(LOG_CFSOCKET) - fprintf(stdout, "invalidation comparing socket iteration %lu to previous %lu\n", __CFSocketManagerIteration, previousSocketManagerIteration); -#endif - __CFSpinUnlock(&__CFActiveSocketsLock); - if (!doneWaiting) { - struct timespec ts = {0, 1}; - // ??? depress priority - nanosleep(&ts, NULL); - } - } -#endif - } -#endif - CFDictionaryRemoveValue(__CFAllSockets, (void *)(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 !defined(USE_V1_RUN_LOOP_SOURCE) - if (NULL != s->_dataQueue) { - CFRelease(s->_dataQueue); - s->_dataQueue = NULL; - } - if (NULL != s->_addressQueue) { - CFRelease(s->_addressQueue); - s->_addressQueue = NULL; - } - s->_socketSetCount = 0; -#endif // !USE_V1_RUN_LOOP_SOURCE - for (idx = CFArrayGetCount(s->_runLoops); idx--;) { - CFRunLoopWakeUp((CFRunLoopRef)CFArrayGetValueAtIndex(s->_runLoops, idx)); - } - 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); - if (NULL != contextRelease) { - contextRelease(contextInfo); - } - if (NULL != source0) { - CFRunLoopSourceInvalidate(source0); - CFRelease(source0); - } -#if defined(USE_V1_RUN_LOOP_SOURCE) - // Important to do the v1 source after the v0 source, since cancelling the v0 source - // references the v1 source (since the v1 source is added/removed from RunLoops as a - // side-effect of the v0 source being added/removed). - if (NULL != s->_source1) { - CFRunLoopSourceInvalidate(s->_source1); - CFRelease(s->_source1); - s->_source1 = NULL; - } - CloseHandle(s->_event); -#endif - } else { - __CFSocketUnlock(s); - } - __CFSpinUnlock(&__CFAllSocketsLock); - CFRelease(s); -} - -void CFSocketInvalidate(CFSocketRef s) {__CFSocketInvalidate(s, true);} - -Boolean CFSocketIsValid(CFSocketRef s) { - __CFGenericValidateType(s, __kCFSocketTypeID); - return __CFSocketIsValid(s); -} - -CFSocketNativeHandle CFSocketGetNative(CFSocketRef s) { - __CFGenericValidateType(s, __kCFSocketTypeID); - return s->_socket; -} - -CFDataRef CFSocketCopyAddress(CFSocketRef s) { - CFDataRef result = NULL; - __CFGenericValidateType(s, __kCFSocketTypeID); - __CFSocketLock(s); - __CFSocketEstablishAddress(s); - if (NULL != s->_address) { - result = CFRetain(s->_address); - } - __CFSocketUnlock(s); - return result; -} - -CFDataRef CFSocketCopyPeerAddress(CFSocketRef s) { - CFDataRef result = NULL; - __CFGenericValidateType(s, __kCFSocketTypeID); - __CFSocketLock(s); - __CFSocketEstablishPeerAddress(s); - if (NULL != s->_peerAddress) { - result = CFRetain(s->_peerAddress); - } - __CFSocketUnlock(s); - return result; -} - -void CFSocketGetContext(CFSocketRef s, CFSocketContext *context) { - __CFGenericValidateType(s, __kCFSocketTypeID); - CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__); - *context = s->_context; -} - -__private_extern__ void CFSocketReschedule(CFSocketRef s) { - CFSocketEnableCallBacks(s, __CFSocketCallBackTypes(s)); -} - -CFOptionFlags CFSocketGetSocketFlags(CFSocketRef s) { - __CFGenericValidateType(s, __kCFSocketTypeID); - return s->_f.client; -} - -void CFSocketSetSocketFlags(CFSocketRef s, CFOptionFlags flags) { - __CFGenericValidateType(s, __kCFSocketTypeID); - __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) { - Boolean wakeup = false; - uint8_t readCallBackType; - __CFGenericValidateType(s, __kCFSocketTypeID); - __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)) { - // do not wake up the socket manager thread if all relevant write callbacks are disabled - CFOptionFlags writeCallBacksAvailable = __CFSocketCallBackTypes(s) & (kCFSocketWriteCallBack | kCFSocketConnectCallBack); - if (s->_f.connected) writeCallBacksAvailable &= ~kCFSocketConnectCallBack; - if ((s->_f.disabled & writeCallBacksAvailable) != writeCallBacksAvailable) wakeup = true; -#if defined(__WIN32__) - __CFSocketFdClr(s->_socket, __CFExceptSocketsFds); -#endif - } - } - if (readCallBackType != kCFSocketNoCallBack && (callBackTypes & readCallBackType) != 0) { - if (__CFSocketClearFDForRead(s)) { -#if !defined(USE_V1_RUN_LOOP_SOURCE) - // do not wake up the socket manager thread if callback type is read - if (readCallBackType != kCFSocketReadCallBack) wakeup = true; -#endif - } - } - __CFSpinUnlock(&__CFActiveSocketsLock); - } - __CFSocketUnlock(s); - if (wakeup && __CFSocketManagerThread) { - uint8_t c = 'u'; - send(__CFWakeupSocketPair[0], &c, sizeof(c), 0); - } -} - -// "force" means to clear the disabled bits set by DisableCallBacks and always reenable. -// if (!force) we respect those bits, meaning they may stop us from enabling. -// In addition, if !force we assume that the sockets have already been added to the -// __CFReadSockets and __CFWriteSockets arrays. This is true because the callbacks start -// enabled when the CFSocket is created (at which time we enable with force). -// Called with SocketLock held, returns with it released! -void __CFSocketEnableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes, Boolean force, uint8_t wakeupChar) { - 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 - /* We will wait for connection only for connection-oriented, non-rendezvous sockets that are not already connected. Mark others as already connected. */ - if ((readCallBackType == kCFSocketAcceptCallBack) || !__CFSocketIsConnectionOriented(s)) s->_f.connected = TRUE; - - // First figure out what to turn on - if (s->_f.connected || (callBackTypes & kCFSocketConnectCallBack) == 0) { - // if we want write callbacks and they're not disabled... - if ((callBackTypes & kCFSocketWriteCallBack) != 0 && (s->_f.disabled & kCFSocketWriteCallBack) == 0) turnOnWrite = TRUE; - } else { - // if we want connect callbacks and they're not disabled... - if ((callBackTypes & kCFSocketConnectCallBack) != 0 && (s->_f.disabled & kCFSocketConnectCallBack) == 0) turnOnConnect = TRUE; - } - // if we want read callbacks and they're not disabled... - if (readCallBackType != kCFSocketNoCallBack && (callBackTypes & readCallBackType) != 0 && (s->_f.disabled & kCFSocketReadCallBack) == 0) turnOnRead = TRUE; - - // Now turn on the callbacks we've determined that we want on - if (turnOnRead || turnOnWrite || turnOnConnect) { - __CFSpinLock(&__CFActiveSocketsLock); -#if defined(USE_V1_RUN_LOOP_SOURCE) - if (turnOnWrite) { - if (force) { - SInt32 idx = CFArrayGetFirstIndexOfValue(__CFWriteSockets, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets)), s); - if (kCFNotFound == idx) CFArrayAppendValue(__CFWriteSockets, s); - } - // If we can tell the socket is writable, just reschedule the v1 source. Else we need - // a real notification from the OS, so enable the SocketManager's listening. - if (__CFSocketCanAcceptBytes(s)) { - SetEvent(s->_event); - s->_f.writableHint = TRUE; - } else { - if (__CFSocketSetFDForWrite(s)) wakeup = true; - } - } - if (turnOnConnect) __CFSocketSetWholeEventMask(s, s->_oldEventMask | FD_CONNECT); - if (turnOnRead) __CFSocketSetFDForRead(s); -#else // !USE_V1_RUN_LOOP_SOURCE - 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 defined(__WIN32__) - if ((callBackTypes & kCFSocketConnectCallBack) != 0 && !s->_f.connected) __CFSocketFdSet(s->_socket, __CFExceptSocketsFds); -#endif - } - if (turnOnRead) { - if (force) { - SInt32 idx = CFArrayGetFirstIndexOfValue(__CFReadSockets, CFRangeMake(0, CFArrayGetCount(__CFReadSockets)), s); - if (kCFNotFound == idx) CFArrayAppendValue(__CFReadSockets, s); - } - if (__CFSocketSetFDForRead(s)) wakeup = true; - } -#endif - if (wakeup && NULL == __CFSocketManagerThread) __CFSocketManagerThread = __CFStartSimpleThread(__CFSocketManager, 0); - __CFSpinUnlock(&__CFActiveSocketsLock); - } - } - __CFSocketUnlock(s); - if (wakeup) send(__CFWakeupSocketPair[0], &wakeupChar, sizeof(wakeupChar), 0); -} - -void CFSocketEnableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes) { - __CFGenericValidateType(s, __kCFSocketTypeID); - __CFSocketLock(s); - __CFSocketEnableCallBacks(s, callBackTypes, TRUE, 'r'); -} - -static void __CFSocketSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) { - CFSocketRef s = info; - __CFSocketLock(s); - //??? also need to arrange delivery of all pending data - if (__CFSocketIsValid(s)) { - CFArrayAppendValue(s->_runLoops, rl); - s->_socketSetCount++; - // Since the v0 source is listened to on the SocketMgr thread, no matter how many modes it - // is added to we just need to enable it there once (and _socketSetCount gives us a refCount - // to know when we can finally disable it). - if (1 == s->_socketSetCount) { -#if defined(LOG_CFSOCKET) - fprintf(stdout, "scheduling socket %d\n", s->_socket); -#endif - __CFSocketEnableCallBacks(s, __CFSocketCallBackTypes(s), TRUE, 's'); // unlocks s - } else - __CFSocketUnlock(s); -#if defined(USE_V1_RUN_LOOP_SOURCE) - // Since the v1 source is listened to in rl on this thread, we need to add it to all modes - // the v0 source is added to. - CFRunLoopAddSource(rl, s->_source1, mode); - CFRunLoopWakeUp(rl); -#endif - } else - __CFSocketUnlock(s); -} - -static void __CFSocketCancel(void *info, CFRunLoopRef rl, CFStringRef mode) { - CFSocketRef s = 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); -#if defined(__WIN32__) - __CFSocketFdClr(s->_socket, __CFExceptSocketsFds); -#endif - } -#if !defined(USE_V1_RUN_LOOP_SOURCE) - idx = CFArrayGetFirstIndexOfValue(__CFReadSockets, CFRangeMake(0, CFArrayGetCount(__CFReadSockets)), s); - if (0 <= idx) { - CFArrayRemoveValueAtIndex(__CFReadSockets, idx); - __CFSocketClearFDForRead(s); - } -#endif - __CFSpinUnlock(&__CFActiveSocketsLock); - } -#if defined(USE_V1_RUN_LOOP_SOURCE) - CFRunLoopRemoveSource(rl, s->_source1, mode); - CFRunLoopWakeUp(rl); - if (0 == s->_socketSetCount && s->_socket != INVALID_SOCKET) { - __CFSocketSetWholeEventMask(s, FD_CLOSE|FD_CONNECT); - } -#endif - if (NULL != s->_runLoops) { - idx = CFArrayGetFirstIndexOfValue(s->_runLoops, CFRangeMake(0, CFArrayGetCount(s->_runLoops)), rl); - if (0 <= idx) CFArrayRemoveValueAtIndex(s->_runLoops, idx); - } - __CFSocketUnlock(s); -} - -// Note: must be called with socket lock held, then returns with it released -// Used by both the v0 and v1 RunLoopSource perform routines -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", 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", datalen, s->_socket); -#endif - if (callout) callout(s, kCFSocketDataCallBack, address, data, contextInfo); - calledOut = true; - if (0 == datalen) __CFSocketInvalidate(s, true); - } - } 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; - } - } -} - -#if defined(USE_V1_RUN_LOOP_SOURCE) -static HANDLE __CFSocketGetPort(void *info) { - CFSocketRef s = info; - return s->_event; -} - -static void __CFSocketPerformV1(void *info) { - CFSocketRef s = info; - WSANETWORKEVENTS eventsTranspired; - uint8_t readCallBackType = __CFSocketReadCallBackType(s); - CFOptionFlags callBacksSignalled = 0; - - int err = WSAEnumNetworkEvents(s->_socket, s->_event, &eventsTranspired); - CFAssert2(0 == err, __kCFLogAssertion, "%s(): WSAEnumNetworkEvents failed: %d", __PRETTY_FUNCTION__, WSAGetLastError()); -#if defined(LOG_CFSOCKET) - fprintf(stdout, "socket %d with flags 0x%x disabled 0x%x connected 0x%x received NetworkEvents 0x%lx\n", s->_socket, s->_f.client, s->_f.disabled, s->_f.connected, eventsTranspired.lNetworkEvents); -#endif - // Get these bits cleared before any callouts, just as the SocketMgr thread used to - if (eventsTranspired.lNetworkEvents & FD_READ) { - __CFSpinLock(&__CFActiveSocketsLock); - __CFSocketClearFDForRead(s); - __CFSpinUnlock(&__CFActiveSocketsLock); - } - - if (eventsTranspired.lNetworkEvents & FD_READ || eventsTranspired.lNetworkEvents & FD_ACCEPT) callBacksSignalled |= readCallBackType; - if (eventsTranspired.lNetworkEvents & FD_CONNECT || s->_f.writableHint) callBacksSignalled |= kCFSocketWriteCallBack; - s->_f.writableHint = FALSE; - CFAssert2(0 == (eventsTranspired.lNetworkEvents & FD_WRITE), __kCFLogAssertion, "%s(): WSAEnumNetworkEvents returned unexpected events: %lx", __PRETTY_FUNCTION__, eventsTranspired.lNetworkEvents); - -#if defined(LOG_CFSOCKET) - // I believe all these errors will be re-found in __CFSocketHandleRead and __CFSocketHandleWrite - // so we don't need to check for them here. - if (eventsTranspired.lNetworkEvents & FD_READ && eventsTranspired.iErrorCode[FD_READ_BIT] != 0) - fprintf(stdout, "socket %d has error %d for FD_READ\n", s->_socket, eventsTranspired.iErrorCode[FD_READ_BIT]); - if (eventsTranspired.lNetworkEvents & FD_WRITE && eventsTranspired.iErrorCode[FD_WRITE_BIT] != 0) - fprintf(stdout, "socket %d has error %d for FD_WRITE\n", s->_socket, eventsTranspired.iErrorCode[FD_WRITE_BIT]); - if (eventsTranspired.lNetworkEvents & FD_CLOSE && eventsTranspired.iErrorCode[FD_CLOSE_BIT] != 0) - fprintf(stdout, "socket %d has error %d for FD_CLOSE\n", s->_socket, eventsTranspired.iErrorCode[FD_CLOSE_BIT]); - if (eventsTranspired.lNetworkEvents & FD_CONNECT && eventsTranspired.iErrorCode[FD_CONNECT_BIT] != 0) - fprintf(stdout, "socket %d has error %d for FD_CONNECT\n", s->_socket, eventsTranspired.iErrorCode[FD_CONNECT_BIT]); -#endif - - if (0 != (eventsTranspired.lNetworkEvents & FD_CLOSE)) s->_f.closeSignaled = TRUE; - if (0 != (callBacksSignalled & readCallBackType)) __CFSocketHandleRead(s); - if (0 != (callBacksSignalled & kCFSocketWriteCallBack)) __CFSocketHandleWrite(s, TRUE); - // FD_CLOSE is edge triggered (sent once). FD_READ is level triggered (sent as long as there are - // bytes). Event after we get FD_CLOSE, if there are still bytes to be read we'll keep getting - // FD_READ until the pipe is drained. However, an EOF condition on the socket will -not- - // trigger an FD_READ, so we must be careful not to stall out after the last bytes are read. - // Finally, a client may have already noticed the EOF in the Read callout just done, so we don't - // call him again if the socket has been invalidated. - // All this implies that once we have seen FD_CLOSE, we need to keep checking for EOF on the read - // side to give the client one last callback for that case. - if (__CFSocketIsValid(s) && (eventsTranspired.lNetworkEvents == FD_CLOSE || (s->_f.closeSignaled && !__CFSocketHasBytesToRead(s)))) { - if (readCallBackType != kCFSocketNoCallBack) { - __CFSocketHandleRead(s); - } else if ((__CFSocketCallBackTypes(s) & kCFSocketWriteCallBack) != 0) { - __CFSocketHandleWrite(s, TRUE); - } - } - - // Only reenable callbacks that are auto-reenabled - __CFSocketLock(s); - __CFSocketEnableCallBacks(s, callBacksSignalled & s->_f.client, FALSE, 'P'); // unlocks s -} -#endif // USE_V1_RUN_LOOP_SOURCE - -static void __CFSocketPerformV0(void *info) { - CFSocketRef s = 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 !defined(USE_V1_RUN_LOOP_SOURCE) - if (kCFSocketDataCallBack == readCallBackType) { - if (NULL != s->_dataQueue && 0 < CFArrayGetCount(s->_dataQueue)) { - data = CFArrayGetValueAtIndex(s->_dataQueue, 0); - CFRetain(data); - CFArrayRemoveValueAtIndex(s->_dataQueue, 0); - address = CFArrayGetValueAtIndex(s->_addressQueue, 0); - CFRetain(address); - CFArrayRemoveValueAtIndex(s->_addressQueue, 0); - } - } else if (kCFSocketAcceptCallBack == readCallBackType) { - if (NULL != s->_dataQueue && 0 < CFArrayGetCount(s->_dataQueue)) { - sock = (CFSocketNativeHandle)CFArrayGetValueAtIndex(s->_dataQueue, 0); - CFArrayRemoveValueAtIndex(s->_dataQueue, 0); - address = CFArrayGetValueAtIndex(s->_addressQueue, 0); - CFRetain(address); - CFArrayRemoveValueAtIndex(s->_addressQueue, 0); - } - } -#endif - - __CFSocketDoCallback(s, data, address, sock); // does __CFSocketUnlock(s) - if (NULL != data) CFRelease(data); - if (NULL != address) CFRelease(address); - - __CFSocketLock(s); -#if !defined(USE_V1_RUN_LOOP_SOURCE) - if (__CFSocketIsValid(s) && kCFSocketNoCallBack != readCallBackType) { - // if there's still more data, we want to wake back up right away - if ((kCFSocketDataCallBack == readCallBackType || kCFSocketAcceptCallBack == readCallBackType) && NULL != s->_dataQueue && 0 < CFArrayGetCount(s->_dataQueue)) { - CFRunLoopSourceSignal(s->_source0); -#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 - rl = __CFSocketCopyRunLoopToWakeUp(s); - } - } -#endif - // Only reenable callbacks that are auto-reenabled - __CFSocketEnableCallBacks(s, callBacksSignalled & s->_f.client, FALSE, 'p'); // unlocks s - - if (NULL != rl) { - CFRunLoopWakeUp(rl); - CFRelease(rl); - } -} - -CFRunLoopSourceRef CFSocketCreateRunLoopSource(CFAllocatorRef allocator, CFSocketRef s, CFIndex order) { - CFRunLoopSourceRef result = NULL; - __CFGenericValidateType(s, __kCFSocketTypeID); - __CFSocketLock(s); - if (__CFSocketIsValid(s)) { - if (NULL == s->_source0) { - CFRunLoopSourceContext context; -#if defined(USE_V1_RUN_LOOP_SOURCE) - CFRunLoopSourceContext1 context1; - context1.version = 1; - context1.info = s; - context1.retain = CFRetain; - context1.release = CFRelease; - context1.copyDescription = CFCopyDescription; - context1.equal = CFEqual; - context1.hash = CFHash; - context1.getPort = __CFSocketGetPort; - context1.perform = __CFSocketPerformV1; - s->_source1 = CFRunLoopSourceCreate(allocator, order, (CFRunLoopSourceContext*)&context1); -#endif - 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); /* This retain is for the receiver */ - result = s->_source0; - } - __CFSocketUnlock(s); - return result; -} - -//??? need timeout, error handling, retries -CFSocketError CFSocketSendData(CFSocketRef s, CFDataRef address, CFDataRef data, CFTimeInterval timeout) { - const uint8_t *dataptr, *addrptr = NULL; - SInt32 datalen, addrlen = 0, size = 0; - CFSocketNativeHandle sock = INVALID_SOCKET; - struct timeval tv; - __CFGenericValidateType(s, __kCFSocketTypeID); - if (address) { - addrptr = CFDataGetBytePtr(address); - addrlen = CFDataGetLength(address); - } - dataptr = CFDataGetBytePtr(data); - datalen = CFDataGetLength(data); - __CFSocketLock(s); - if (__CFSocketIsValid(s)) sock = s->_socket; - __CFSocketUnlock(s); - if (INVALID_SOCKET != sock) { - CFRetain(s); - __CFSocketWriteLock(s); - tv.tv_sec = (0 >= timeout || INT_MAX <= timeout) ? INT_MAX : (int)(float)floor(timeout); - tv.tv_usec = (int)((timeout - floor(timeout)) * 1.0E6); - setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (void *)&tv, sizeof(tv)); // cast for WinSock bad API - if (NULL != addrptr && 0 < addrlen) { - size = sendto(sock, dataptr, datalen, 0, (struct sockaddr *)addrptr, addrlen); - } else { - size = send(sock, dataptr, datalen, 0); - } -#if defined(LOG_CFSOCKET) - fprintf(stdout, "wrote %ld bytes to socket %d\n", size, s->_socket); -#endif - __CFSocketWriteUnlock(s); - CFRelease(s); - } - return (size > 0) ? kCFSocketSuccess : kCFSocketError; -} - -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 = CFPropertyListCreateFromXMLData(NULL, 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(NULL, 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(NULL, requestDictionary); - if (NULL != requestData) { - if (NULL != response->error) *(response->error) = kCFSocketTimeout; - s = CFSocketCreateConnectedToSocketSignature(NULL, signature, kCFSocketDataCallBack, __CFSocketHandleNameRegistryReply, &context, timeout); - if (NULL != s) { - if (kCFSocketSuccess == CFSocketSendData(s, NULL, requestData, timeout)) { - source = CFSocketCreateRunLoopSource(NULL, 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 !defined(__WIN32__) - 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(NULL, (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(NULL, (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 !defined(__WIN32__) - 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(NULL, (uint8_t *)&sain, sizeof(sain)); - } else { - signature->address = CFRetain(providedSignature->address); - } - } - } -} - -CFSocketError CFSocketRegisterValue(const CFSocketSignature *nameServerSignature, CFTimeInterval timeout, CFStringRef name, CFPropertyListRef value) { - CFSocketSignature signature; - CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(NULL, 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(NULL, 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(NULL, 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(NULL, 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(NULL, 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 ? 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; -}