Skip to content

Commit d68e344

Browse files
committed
[Windows] Dynamic fd_set in CFSocket
This makes `fd_set` on Windows growable by adding additional space to the storing buffer, which effectively extends `fd_set.fd_array` capacity.
1 parent b55ac8f commit d68e344

File tree

3 files changed

+57
-25
lines changed

3 files changed

+57
-25
lines changed

Sources/CoreFoundation/CFSocket.c

+55-23
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,6 @@
5353
#include <process.h>
5454
#endif
5555

56-
#ifndef NBBY
57-
#define NBBY 8
58-
#endif
59-
6056
#if TARGET_OS_WIN32
6157

6258
// redefine this to the winsock error in this file
@@ -67,9 +63,6 @@
6763
#undef EBADF
6864
#define EBADF WSAENOTSOCK
6965

70-
#define NFDBITS (sizeof(int32_t) * NBBY)
71-
72-
typedef int32_t fd_mask;
7366
typedef int socklen_t;
7467

7568
#define gettimeofday _NS_gettimeofday
@@ -96,6 +89,12 @@ static void timeradd(struct timeval *a, struct timeval *b, struct timeval *res)
9689
}
9790
}
9891

92+
#else
93+
94+
#ifndef NBBY
95+
#define NBBY 8
96+
#endif
97+
9998
#endif // TARGET_OS_WIN32
10099

101100

@@ -216,10 +215,15 @@ CF_INLINE int __CFSocketLastError(void) {
216215

217216
CF_INLINE CFIndex __CFSocketFdGetSize(CFDataRef fdSet) {
218217
#if TARGET_OS_WIN32
219-
if (CFDataGetLength(fdSet) == 0) {
218+
CFIndex dataLength = CFDataGetLength(fdSet);
219+
if (dataLength == 0) {
220220
return 0;
221221
}
222-
return FD_SETSIZE;
222+
// The minimal possible capacity we could possibly have
223+
// equals to FD_SETSIZE (as part of fd_set structure).
224+
// All additional data length is the space for SOCKETs
225+
// over fd_set static buffer limit.
226+
return (dataLength - sizeof(fd_set)) / sizeof(SOCKET) + FD_SETSIZE;
223227
#else
224228
return NBBY * CFDataGetLength(fdSet);
225229
#endif
@@ -231,13 +235,27 @@ CF_INLINE Boolean __CFSocketFdSet(CFSocketNativeHandle sock, CFMutableDataRef fd
231235
if (INVALID_SOCKET != sock && 0 <= sock) {
232236
fd_set *fds;
233237
#if TARGET_OS_WIN32
238+
// Allocate initial fd_set if there is none
234239
if (CFDataGetLength(fdSet) == 0) {
235240
CFDataIncreaseLength(fdSet, sizeof(fd_set));
236241
fds = (fd_set *)CFDataGetMutableBytePtr(fdSet);
237242
FD_ZERO(fds);
238243
} else {
239244
fds = (fd_set *)CFDataGetMutableBytePtr(fdSet);
240245
}
246+
247+
// FD_SET macro replacement with growable storage
248+
if (!FD_ISSET(sock, fds)) {
249+
retval = true;
250+
u_int count = fds->fd_count;
251+
if (count >= __CFSocketFdGetSize(fdSet)) {
252+
CFDataIncreaseLength(fdSet, FD_SETSIZE * sizeof(SOCKET));
253+
fds = (fd_set *)CFDataGetMutableBytePtr(fdSet);
254+
}
255+
256+
fds->fd_array[count] = sock;
257+
fds->fd_count++;
258+
}
241259
#else
242260
CFIndex numFds = NBBY * CFDataGetLength(fdSet);
243261
fd_mask *fds_bits;
@@ -250,11 +268,11 @@ CF_INLINE Boolean __CFSocketFdSet(CFSocketNativeHandle sock, CFMutableDataRef fd
250268
fds_bits = (fd_mask *)CFDataGetMutableBytePtr(fdSet);
251269
}
252270
fds = (fd_set *)fds_bits;
253-
#endif
254271
if (!FD_ISSET(sock, fds)) {
255272
retval = true;
256273
FD_SET(sock, fds);
257274
}
275+
#endif
258276
}
259277
return retval;
260278
}
@@ -1225,20 +1243,20 @@ clearInvalidFileDescriptors(CFMutableDataRef d)
12251243
}
12261244

12271245
fd_set *fds = (fd_set *)CFDataGetMutableBytePtr(d);
1228-
fd_set invalidFds;
1229-
FD_ZERO(&invalidFds);
1230-
// Gather all invalid sockets into invalidFds set
1246+
u_int count = 0;
1247+
SOCKET *invalidFds = malloc(sizeof(SOCKET) * fds->fd_count);
1248+
// Gather all invalid sockets
12311249
for (u_int idx = 0; idx < fds->fd_count; idx++) {
12321250
SOCKET socket = fds->fd_array[idx];
12331251
if (! __CFNativeSocketIsValid(socket)) {
1234-
FD_SET(socket, &invalidFds);
1252+
invalidFds[count++] = socket;
12351253
}
12361254
}
12371255
// Remove invalid sockets from source set
1238-
for (u_int idx = 0; idx < invalidFds.fd_count; idx++) {
1239-
SOCKET socket = invalidFds.fd_array[idx];
1240-
FD_CLR(socket, fds);
1256+
for (u_int idx = 0; idx < count; idx++) {
1257+
FD_CLR(invalidFds[idx], fds);
12411258
}
1259+
free(invalidFds);
12421260
#else
12431261
SInt32 count = __CFSocketFdGetSize(d);
12441262
fd_set* s = (fd_set*) CFDataGetMutableBytePtr(d);
@@ -1311,15 +1329,19 @@ static void *__CFSocketManager(void * arg)
13111329
#elif !TARGET_OS_CYGWIN && !TARGET_OS_BSD
13121330
pthread_setname_np("com.apple.CFSocket.private");
13131331
#endif
1314-
SInt32 nrfds, maxnrfds, fdentries = 1;
1315-
SInt32 rfds, wfds;
1332+
SInt32 nrfds, maxnrfds;
13161333
fd_set *exceptfds = NULL;
13171334
#if TARGET_OS_WIN32
1318-
fd_set *writefds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(fd_set), 0);
1319-
fd_set *readfds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(fd_set), 0);
1335+
CFMutableDataRef writeFdsData = CFDataCreateMutable(kCFAllocatorSystemDefault, 0);
1336+
CFMutableDataRef readFdsData = CFDataCreateMutable(kCFAllocatorSystemDefault, 0);
1337+
CFDataSetLength(writeFdsData, sizeof(fd_set));
1338+
CFDataSetLength(readFdsData, sizeof(fd_set));
1339+
fd_set *writefds = (fd_set *)CFDataGetMutableBytePtr(writeFdsData);
1340+
fd_set *readfds = (fd_set *)CFDataGetMutableBytePtr(readFdsData);
13201341
FD_ZERO(writefds);
13211342
FD_ZERO(readfds);
13221343
#else
1344+
SInt32 rfds, wfds, fdentries = 1;
13231345
fd_set *writefds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, fdentries * sizeof(fd_mask), 0);
13241346
fd_set *readfds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, fdentries * sizeof(fd_mask), 0);
13251347
#endif
@@ -1349,9 +1371,19 @@ static void *__CFSocketManager(void * arg)
13491371
free(writeBuffer);
13501372
#endif
13511373

1374+
CFIndex rfdsDataLendth = CFDataGetLength(__CFReadSocketsFds);
1375+
CFIndex wfdsDataLength = CFDataGetLength(__CFWriteSocketsFds);
13521376
#if TARGET_OS_WIN32
13531377
// This parameter is ignored by `select` from Winsock2 API
13541378
maxnrfds = INT_MAX;
1379+
// Note that writeFdsData and rfdsDataLendth lengths are equal
1380+
CFIndex dataLengthDiff = __CFMax(rfdsDataLendth, wfdsDataLength) - CFDataGetLength(writeFdsData);
1381+
if (dataLengthDiff > 0) {
1382+
CFDataIncreaseLength(writeFdsData, dataLengthDiff);
1383+
CFDataIncreaseLength(readFdsData, dataLengthDiff);
1384+
writefds = (fd_set *)CFDataGetMutableBytePtr(writeFdsData);
1385+
readfds = (fd_set *)CFDataGetMutableBytePtr(readFdsData);
1386+
}
13551387
#else
13561388
rfds = __CFSocketFdGetSize(__CFReadSocketsFds);
13571389
wfds = __CFSocketFdGetSize(__CFWriteSocketsFds);
@@ -1364,8 +1396,8 @@ static void *__CFSocketManager(void * arg)
13641396
memset(writefds, 0, fdentries * sizeof(fd_mask));
13651397
memset(readfds, 0, fdentries * sizeof(fd_mask));
13661398
#endif
1367-
CFDataGetBytes(__CFWriteSocketsFds, CFRangeMake(0, CFDataGetLength(__CFWriteSocketsFds)), (UInt8 *)writefds);
1368-
CFDataGetBytes(__CFReadSocketsFds, CFRangeMake(0, CFDataGetLength(__CFReadSocketsFds)), (UInt8 *)readfds);
1399+
CFDataGetBytes(__CFWriteSocketsFds, CFRangeMake(0, wfdsDataLength), (UInt8 *)writefds);
1400+
CFDataGetBytes(__CFReadSocketsFds, CFRangeMake(0, rfdsDataLendth), (UInt8 *)readfds);
13691401

13701402
if (__CFReadSocketsTimeoutInvalid) {
13711403
struct timeval* minTimeout = NULL;

Sources/CoreFoundation/internalInclude/CoreFoundation_Prefix.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ typedef char * Class;
127127
#endif
128128

129129
// The order of these includes is important
130-
#define FD_SETSIZE 1024
130+
#define FD_SETSIZE 128
131131
#include <winsock2.h>
132132
#include <windows.h>
133133

Tests/Foundation/TestSocketPort.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ class TestSocketPort : XCTestCase {
113113

114114
let data = Data("I cannot weave".utf8)
115115

116-
for _ in 0..<128 {
116+
for _ in 0..<136 {
117117
let local = try XCTUnwrap(SocketPort(tcpPort: 0))
118118
let tcpPort = try UInt16(XCTUnwrap(tcpOrUdpPort(of: local)))
119119
let remote = try XCTUnwrap(SocketPort(remoteWithTCPPort: tcpPort, host: "localhost"))

0 commit comments

Comments
 (0)