Skip to content

Commit ed13e01

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 fa71faf commit ed13e01

File tree

3 files changed

+57
-25
lines changed

3 files changed

+57
-25
lines changed

CoreFoundation/Base.subproj/CoreFoundation_Prefix.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ typedef char * Class;
130130
#endif
131131

132132
// The order of these includes is important
133-
#define FD_SETSIZE 1024
133+
#define FD_SETSIZE 128
134134
#include <winsock2.h>
135135
#include <windows.h>
136136

CoreFoundation/RunLoop.subproj/CFSocket.c

+55-23
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,6 @@
5151
#include <process.h>
5252
#endif
5353

54-
#ifndef NBBY
55-
#define NBBY 8
56-
#endif
57-
5854
#if TARGET_OS_WIN32
5955

6056
// redefine this to the winsock error in this file
@@ -65,9 +61,6 @@
6561
#undef EBADF
6662
#define EBADF WSAENOTSOCK
6763

68-
#define NFDBITS (sizeof(int32_t) * NBBY)
69-
70-
typedef int32_t fd_mask;
7164
typedef int socklen_t;
7265

7366
#define gettimeofday _NS_gettimeofday
@@ -94,6 +87,12 @@ static void timeradd(struct timeval *a, struct timeval *b, struct timeval *res)
9487
}
9588
}
9689

90+
#else
91+
92+
#ifndef NBBY
93+
#define NBBY 8
94+
#endif
95+
9796
#endif // TARGET_OS_WIN32
9897

9998

@@ -214,10 +213,15 @@ CF_INLINE int __CFSocketLastError(void) {
214213

215214
CF_INLINE CFIndex __CFSocketFdGetSize(CFDataRef fdSet) {
216215
#if TARGET_OS_WIN32
217-
if (CFDataGetLength(fdSet) == 0) {
216+
CFIndex dataLength = CFDataGetLength(fdSet);
217+
if (dataLength == 0) {
218218
return 0;
219219
}
220-
return FD_SETSIZE;
220+
// The minimal possible capacity we could possibly have
221+
// equals to FD_SETSIZE (as part of fd_set structure).
222+
// All additional data length is the space for SOCKETs
223+
// over fd_set static buffer limit.
224+
return (dataLength - sizeof(fd_set)) / sizeof(SOCKET) + FD_SETSIZE;
221225
#else
222226
return NBBY * CFDataGetLength(fdSet);
223227
#endif
@@ -229,13 +233,27 @@ CF_INLINE Boolean __CFSocketFdSet(CFSocketNativeHandle sock, CFMutableDataRef fd
229233
if (INVALID_SOCKET != sock && 0 <= sock) {
230234
fd_set *fds;
231235
#if TARGET_OS_WIN32
236+
// Allocate initial fd_set if there is none
232237
if (CFDataGetLength(fdSet) == 0) {
233238
CFDataIncreaseLength(fdSet, sizeof(fd_set));
234239
fds = (fd_set *)CFDataGetMutableBytePtr(fdSet);
235240
FD_ZERO(fds);
236241
} else {
237242
fds = (fd_set *)CFDataGetMutableBytePtr(fdSet);
238243
}
244+
245+
// FD_SET macro replacement with growable storage
246+
if (!FD_ISSET(sock, fds)) {
247+
retval = true;
248+
u_int count = fds->fd_count;
249+
if (count >= __CFSocketFdGetSize(fdSet)) {
250+
CFDataIncreaseLength(fdSet, FD_SETSIZE * sizeof(SOCKET));
251+
fds = (fd_set *)CFDataGetMutableBytePtr(fdSet);
252+
}
253+
254+
fds->fd_array[count] = sock;
255+
fds->fd_count++;
256+
}
239257
#else
240258
CFIndex numFds = NBBY * CFDataGetLength(fdSet);
241259
fd_mask *fds_bits;
@@ -248,11 +266,11 @@ CF_INLINE Boolean __CFSocketFdSet(CFSocketNativeHandle sock, CFMutableDataRef fd
248266
fds_bits = (fd_mask *)CFDataGetMutableBytePtr(fdSet);
249267
}
250268
fds = (fd_set *)fds_bits;
251-
#endif
252269
if (!FD_ISSET(sock, fds)) {
253270
retval = true;
254271
FD_SET(sock, fds);
255272
}
273+
#endif
256274
}
257275
return retval;
258276
}
@@ -1223,20 +1241,20 @@ clearInvalidFileDescriptors(CFMutableDataRef d)
12231241
}
12241242

12251243
fd_set *fds = (fd_set *)CFDataGetMutableBytePtr(d);
1226-
fd_set invalidFds;
1227-
FD_ZERO(&invalidFds);
1228-
// Gather all invalid sockets into invalidFds set
1244+
u_int count = 0;
1245+
SOCKET *invalidFds = malloc(sizeof(SOCKET) * fds->fd_count);
1246+
// Gather all invalid sockets
12291247
for (u_int idx = 0; idx < fds->fd_count; idx++) {
12301248
SOCKET socket = fds->fd_array[idx];
12311249
if (! __CFNativeSocketIsValid(socket)) {
1232-
FD_SET(socket, &invalidFds);
1250+
invalidFds[count++] = socket;
12331251
}
12341252
}
12351253
// Remove invalid sockets from source set
1236-
for (u_int idx = 0; idx < invalidFds.fd_count; idx++) {
1237-
SOCKET socket = invalidFds.fd_array[idx];
1238-
FD_CLR(socket, fds);
1254+
for (u_int idx = 0; idx < count; idx++) {
1255+
FD_CLR(invalidFds[idx], fds);
12391256
}
1257+
free(invalidFds);
12401258
#else
12411259
SInt32 count = __CFSocketFdGetSize(d);
12421260
fd_set* s = (fd_set*) CFDataGetMutableBytePtr(d);
@@ -1309,15 +1327,19 @@ static void *__CFSocketManager(void * arg)
13091327
#elif !TARGET_OS_CYGWIN && !TARGET_OS_BSD
13101328
pthread_setname_np("com.apple.CFSocket.private");
13111329
#endif
1312-
SInt32 nrfds, maxnrfds, fdentries = 1;
1313-
SInt32 rfds, wfds;
1330+
SInt32 nrfds, maxnrfds;
13141331
fd_set *exceptfds = NULL;
13151332
#if TARGET_OS_WIN32
1316-
fd_set *writefds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(fd_set), 0);
1317-
fd_set *readfds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(fd_set), 0);
1333+
CFMutableDataRef writeFdsData = CFDataCreateMutable(kCFAllocatorSystemDefault, 0);
1334+
CFMutableDataRef readFdsData = CFDataCreateMutable(kCFAllocatorSystemDefault, 0);
1335+
CFDataSetLength(writeFdsData, sizeof(fd_set));
1336+
CFDataSetLength(readFdsData, sizeof(fd_set));
1337+
fd_set *writefds = (fd_set *)CFDataGetMutableBytePtr(writeFdsData);
1338+
fd_set *readfds = (fd_set *)CFDataGetMutableBytePtr(readFdsData);
13181339
FD_ZERO(writefds);
13191340
FD_ZERO(readfds);
13201341
#else
1342+
SInt32 rfds, wfds, fdentries = 1;
13211343
fd_set *writefds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, fdentries * sizeof(fd_mask), 0);
13221344
fd_set *readfds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, fdentries * sizeof(fd_mask), 0);
13231345
#endif
@@ -1347,9 +1369,19 @@ static void *__CFSocketManager(void * arg)
13471369
free(writeBuffer);
13481370
#endif
13491371

1372+
CFIndex rfdsDataLendth = CFDataGetLength(__CFReadSocketsFds);
1373+
CFIndex wfdsDataLength = CFDataGetLength(__CFWriteSocketsFds);
13501374
#if TARGET_OS_WIN32
13511375
// This parameter is ignored by `select` from Winsock2 API
13521376
maxnrfds = INT_MAX;
1377+
// Note that writeFdsData and rfdsDataLendth lengths are equal
1378+
CFIndex dataLengthDiff = __CFMax(rfdsDataLendth, wfdsDataLength) - CFDataGetLength(writeFdsData);
1379+
if (dataLengthDiff > 0) {
1380+
CFDataIncreaseLength(writeFdsData, dataLengthDiff);
1381+
CFDataIncreaseLength(readFdsData, dataLengthDiff);
1382+
writefds = (fd_set *)CFDataGetMutableBytePtr(writeFdsData);
1383+
readfds = (fd_set *)CFDataGetMutableBytePtr(readFdsData);
1384+
}
13531385
#else
13541386
rfds = __CFSocketFdGetSize(__CFReadSocketsFds);
13551387
wfds = __CFSocketFdGetSize(__CFWriteSocketsFds);
@@ -1362,8 +1394,8 @@ static void *__CFSocketManager(void * arg)
13621394
memset(writefds, 0, fdentries * sizeof(fd_mask));
13631395
memset(readfds, 0, fdentries * sizeof(fd_mask));
13641396
#endif
1365-
CFDataGetBytes(__CFWriteSocketsFds, CFRangeMake(0, CFDataGetLength(__CFWriteSocketsFds)), (UInt8 *)writefds);
1366-
CFDataGetBytes(__CFReadSocketsFds, CFRangeMake(0, CFDataGetLength(__CFReadSocketsFds)), (UInt8 *)readfds);
1397+
CFDataGetBytes(__CFWriteSocketsFds, CFRangeMake(0, wfdsDataLength), (UInt8 *)writefds);
1398+
CFDataGetBytes(__CFReadSocketsFds, CFRangeMake(0, rfdsDataLendth), (UInt8 *)readfds);
13671399

13681400
if (__CFReadSocketsTimeoutInvalid) {
13691401
struct timeval* minTimeout = NULL;

Tests/Foundation/Tests/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)