diff --git a/CoreFoundation/Base.subproj/CoreFoundation_Prefix.h b/CoreFoundation/Base.subproj/CoreFoundation_Prefix.h index c1176c765c..a683f50bfe 100644 --- a/CoreFoundation/Base.subproj/CoreFoundation_Prefix.h +++ b/CoreFoundation/Base.subproj/CoreFoundation_Prefix.h @@ -130,7 +130,7 @@ typedef char * Class; #endif // The order of these includes is important -#define FD_SETSIZE 1024 +#define FD_SETSIZE 128 #include #include diff --git a/CoreFoundation/RunLoop.subproj/CFSocket.c b/CoreFoundation/RunLoop.subproj/CFSocket.c index 475d99c574..649823ec04 100644 --- a/CoreFoundation/RunLoop.subproj/CFSocket.c +++ b/CoreFoundation/RunLoop.subproj/CFSocket.c @@ -51,10 +51,6 @@ #include #endif -#ifndef NBBY -#define NBBY 8 -#endif - #if TARGET_OS_WIN32 // redefine this to the winsock error in this file @@ -65,9 +61,6 @@ #undef EBADF #define EBADF WSAENOTSOCK -#define NFDBITS (sizeof(int32_t) * NBBY) - -typedef int32_t fd_mask; typedef int socklen_t; #define gettimeofday _NS_gettimeofday @@ -94,6 +87,12 @@ static void timeradd(struct timeval *a, struct timeval *b, struct timeval *res) } } +#else + +#ifndef NBBY +#define NBBY 8 +#endif + #endif // TARGET_OS_WIN32 @@ -214,10 +213,15 @@ CF_INLINE int __CFSocketLastError(void) { CF_INLINE CFIndex __CFSocketFdGetSize(CFDataRef fdSet) { #if TARGET_OS_WIN32 - if (CFDataGetLength(fdSet) == 0) { + CFIndex dataLength = CFDataGetLength(fdSet); + if (dataLength == 0) { return 0; } - return FD_SETSIZE; + // The minimal possible capacity we could possibly have + // equals to FD_SETSIZE (as part of fd_set structure). + // All additional data length is the space for SOCKETs + // over fd_set static buffer limit. + return (dataLength - sizeof(fd_set)) / sizeof(SOCKET) + FD_SETSIZE; #else return NBBY * CFDataGetLength(fdSet); #endif @@ -229,6 +233,7 @@ CF_INLINE Boolean __CFSocketFdSet(CFSocketNativeHandle sock, CFMutableDataRef fd if (INVALID_SOCKET != sock && 0 <= sock) { fd_set *fds; #if TARGET_OS_WIN32 + // Allocate initial fd_set if there is none if (CFDataGetLength(fdSet) == 0) { CFDataIncreaseLength(fdSet, sizeof(fd_set)); fds = (fd_set *)CFDataGetMutableBytePtr(fdSet); @@ -236,6 +241,19 @@ CF_INLINE Boolean __CFSocketFdSet(CFSocketNativeHandle sock, CFMutableDataRef fd } else { fds = (fd_set *)CFDataGetMutableBytePtr(fdSet); } + + // FD_SET macro replacement with growable storage + if (!FD_ISSET(sock, fds)) { + retval = true; + u_int count = fds->fd_count; + if (count >= __CFSocketFdGetSize(fdSet)) { + CFDataIncreaseLength(fdSet, FD_SETSIZE * sizeof(SOCKET)); + fds = (fd_set *)CFDataGetMutableBytePtr(fdSet); + } + + fds->fd_array[count] = sock; + fds->fd_count++; + } #else CFIndex numFds = NBBY * CFDataGetLength(fdSet); fd_mask *fds_bits; @@ -248,11 +266,11 @@ CF_INLINE Boolean __CFSocketFdSet(CFSocketNativeHandle sock, CFMutableDataRef fd fds_bits = (fd_mask *)CFDataGetMutableBytePtr(fdSet); } fds = (fd_set *)fds_bits; -#endif if (!FD_ISSET(sock, fds)) { retval = true; FD_SET(sock, fds); } +#endif } return retval; } @@ -1223,20 +1241,20 @@ clearInvalidFileDescriptors(CFMutableDataRef d) } fd_set *fds = (fd_set *)CFDataGetMutableBytePtr(d); - fd_set invalidFds; - FD_ZERO(&invalidFds); - // Gather all invalid sockets into invalidFds set + u_int count = 0; + SOCKET *invalidFds = malloc(sizeof(SOCKET) * fds->fd_count); + // Gather all invalid sockets for (u_int idx = 0; idx < fds->fd_count; idx++) { SOCKET socket = fds->fd_array[idx]; if (! __CFNativeSocketIsValid(socket)) { - FD_SET(socket, &invalidFds); + invalidFds[count++] = socket; } } // Remove invalid sockets from source set - for (u_int idx = 0; idx < invalidFds.fd_count; idx++) { - SOCKET socket = invalidFds.fd_array[idx]; - FD_CLR(socket, fds); + for (u_int idx = 0; idx < count; idx++) { + FD_CLR(invalidFds[idx], fds); } + free(invalidFds); #else SInt32 count = __CFSocketFdGetSize(d); fd_set* s = (fd_set*) CFDataGetMutableBytePtr(d); @@ -1309,15 +1327,19 @@ static void *__CFSocketManager(void * arg) #elif !TARGET_OS_CYGWIN && !TARGET_OS_BSD pthread_setname_np("com.apple.CFSocket.private"); #endif - SInt32 nrfds, maxnrfds, fdentries = 1; - SInt32 rfds, wfds; + SInt32 nrfds, maxnrfds; fd_set *exceptfds = NULL; #if TARGET_OS_WIN32 - fd_set *writefds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(fd_set), 0); - fd_set *readfds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(fd_set), 0); + CFMutableDataRef writeFdsData = CFDataCreateMutable(kCFAllocatorSystemDefault, 0); + CFMutableDataRef readFdsData = CFDataCreateMutable(kCFAllocatorSystemDefault, 0); + CFDataSetLength(writeFdsData, sizeof(fd_set)); + CFDataSetLength(readFdsData, sizeof(fd_set)); + fd_set *writefds = (fd_set *)CFDataGetMutableBytePtr(writeFdsData); + fd_set *readfds = (fd_set *)CFDataGetMutableBytePtr(readFdsData); FD_ZERO(writefds); FD_ZERO(readfds); #else + SInt32 rfds, wfds, fdentries = 1; 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 @@ -1347,9 +1369,19 @@ static void *__CFSocketManager(void * arg) free(writeBuffer); #endif + CFIndex rfdsDataLendth = CFDataGetLength(__CFReadSocketsFds); + CFIndex wfdsDataLength = CFDataGetLength(__CFWriteSocketsFds); #if TARGET_OS_WIN32 // This parameter is ignored by `select` from Winsock2 API maxnrfds = INT_MAX; + // Note that writeFdsData and rfdsDataLendth lengths are equal + CFIndex dataLengthDiff = __CFMax(rfdsDataLendth, wfdsDataLength) - CFDataGetLength(writeFdsData); + if (dataLengthDiff > 0) { + CFDataIncreaseLength(writeFdsData, dataLengthDiff); + CFDataIncreaseLength(readFdsData, dataLengthDiff); + writefds = (fd_set *)CFDataGetMutableBytePtr(writeFdsData); + readfds = (fd_set *)CFDataGetMutableBytePtr(readFdsData); + } #else rfds = __CFSocketFdGetSize(__CFReadSocketsFds); wfds = __CFSocketFdGetSize(__CFWriteSocketsFds); @@ -1362,8 +1394,8 @@ static void *__CFSocketManager(void * arg) memset(writefds, 0, fdentries * sizeof(fd_mask)); memset(readfds, 0, fdentries * sizeof(fd_mask)); #endif - CFDataGetBytes(__CFWriteSocketsFds, CFRangeMake(0, CFDataGetLength(__CFWriteSocketsFds)), (UInt8 *)writefds); - CFDataGetBytes(__CFReadSocketsFds, CFRangeMake(0, CFDataGetLength(__CFReadSocketsFds)), (UInt8 *)readfds); + CFDataGetBytes(__CFWriteSocketsFds, CFRangeMake(0, wfdsDataLength), (UInt8 *)writefds); + CFDataGetBytes(__CFReadSocketsFds, CFRangeMake(0, rfdsDataLendth), (UInt8 *)readfds); if (__CFReadSocketsTimeoutInvalid) { struct timeval* minTimeout = NULL; diff --git a/Tests/Foundation/Tests/TestSocketPort.swift b/Tests/Foundation/Tests/TestSocketPort.swift index b620e5e4aa..9926812f66 100644 --- a/Tests/Foundation/Tests/TestSocketPort.swift +++ b/Tests/Foundation/Tests/TestSocketPort.swift @@ -113,7 +113,7 @@ class TestSocketPort : XCTestCase { let data = Data("I cannot weave".utf8) - for _ in 0..<128 { + for _ in 0..<136 { let local = try XCTUnwrap(SocketPort(tcpPort: 0)) let tcpPort = try UInt16(XCTUnwrap(tcpOrUdpPort(of: local))) let remote = try XCTUnwrap(SocketPort(remoteWithTCPPort: tcpPort, host: "localhost"))