Skip to content

Commit fbbe6fa

Browse files
authored
Merge pull request #4977 from parkera/package
Merge the main branch into package
2 parents 9a8e5ae + 697cb9e commit fbbe6fa

16 files changed

+909
-102
lines changed

Sources/CoreFoundation/CFSocket.c

+74-6
Original file line numberDiff line numberDiff line change
@@ -215,13 +215,30 @@ CF_INLINE int __CFSocketLastError(void) {
215215
}
216216

217217
CF_INLINE CFIndex __CFSocketFdGetSize(CFDataRef fdSet) {
218+
#if TARGET_OS_WIN32
219+
if (CFDataGetLength(fdSet) == 0) {
220+
return 0;
221+
}
222+
return FD_SETSIZE;
223+
#else
218224
return NBBY * CFDataGetLength(fdSet);
225+
#endif
219226
}
220227

221228
CF_INLINE Boolean __CFSocketFdSet(CFSocketNativeHandle sock, CFMutableDataRef fdSet) {
222229
/* returns true if a change occurred, false otherwise */
223230
Boolean retval = false;
224231
if (INVALID_SOCKET != sock && 0 <= sock) {
232+
fd_set *fds;
233+
#if TARGET_OS_WIN32
234+
if (CFDataGetLength(fdSet) == 0) {
235+
CFDataIncreaseLength(fdSet, sizeof(fd_set));
236+
fds = (fd_set *)CFDataGetMutableBytePtr(fdSet);
237+
FD_ZERO(fds);
238+
} else {
239+
fds = (fd_set *)CFDataGetMutableBytePtr(fdSet);
240+
}
241+
#else
225242
CFIndex numFds = NBBY * CFDataGetLength(fdSet);
226243
fd_mask *fds_bits;
227244
if (sock >= numFds) {
@@ -232,9 +249,11 @@ CF_INLINE Boolean __CFSocketFdSet(CFSocketNativeHandle sock, CFMutableDataRef fd
232249
} else {
233250
fds_bits = (fd_mask *)CFDataGetMutableBytePtr(fdSet);
234251
}
235-
if (!FD_ISSET(sock, (fd_set *)fds_bits)) {
252+
fds = (fd_set *)fds_bits;
253+
#endif
254+
if (!FD_ISSET(sock, fds)) {
236255
retval = true;
237-
FD_SET(sock, (fd_set *)fds_bits);
256+
FD_SET(sock, fds);
238257
}
239258
}
240259
return retval;
@@ -418,6 +437,15 @@ CF_INLINE Boolean __CFSocketFdClr(CFSocketNativeHandle sock, CFMutableDataRef fd
418437
/* returns true if a change occurred, false otherwise */
419438
Boolean retval = false;
420439
if (INVALID_SOCKET != sock && 0 <= sock) {
440+
#if TARGET_OS_WIN32
441+
if (CFDataGetLength(fdSet) > 0) {
442+
fd_set *fds = (fd_set *)CFDataGetMutableBytePtr(fdSet);
443+
if (FD_ISSET(sock, fds)) {
444+
retval = true;
445+
FD_CLR(sock, fds);
446+
}
447+
}
448+
#else
421449
CFIndex numFds = NBBY * CFDataGetLength(fdSet);
422450
fd_mask *fds_bits;
423451
if (sock < numFds) {
@@ -427,6 +455,7 @@ CF_INLINE Boolean __CFSocketFdClr(CFSocketNativeHandle sock, CFMutableDataRef fd
427455
FD_CLR(sock, (fd_set *)fds_bits);
428456
}
429457
}
458+
#endif
430459
}
431460
return retval;
432461
}
@@ -1190,6 +1219,27 @@ static void
11901219
clearInvalidFileDescriptors(CFMutableDataRef d)
11911220
{
11921221
if (d) {
1222+
#if TARGET_OS_WIN32
1223+
if (CFDataGetLength(d) == 0) {
1224+
return;
1225+
}
1226+
1227+
fd_set *fds = (fd_set *)CFDataGetMutableBytePtr(d);
1228+
fd_set invalidFds;
1229+
FD_ZERO(&invalidFds);
1230+
// Gather all invalid sockets into invalidFds set
1231+
for (u_int idx = 0; idx < fds->fd_count; idx++) {
1232+
SOCKET socket = fds->fd_array[idx];
1233+
if (! __CFNativeSocketIsValid(socket)) {
1234+
FD_SET(socket, &invalidFds);
1235+
}
1236+
}
1237+
// 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);
1241+
}
1242+
#else
11931243
SInt32 count = __CFSocketFdGetSize(d);
11941244
fd_set* s = (fd_set*) CFDataGetMutableBytePtr(d);
11951245
for (SInt32 idx = 0; idx < count; idx++) {
@@ -1198,14 +1248,13 @@ clearInvalidFileDescriptors(CFMutableDataRef d)
11981248
FD_CLR(idx, s);
11991249
}
12001250
}
1251+
#endif
12011252
}
12021253
}
12031254

12041255
static void
1205-
manageSelectError()
1256+
manageSelectError(SInt32 selectError)
12061257
{
1207-
SInt32 selectError = __CFSocketLastError();
1208-
12091258
__CFSOCKETLOG("socket manager received error %ld from select", (long)selectError);
12101259

12111260
if (EBADF == selectError) {
@@ -1265,8 +1314,15 @@ static void *__CFSocketManager(void * arg)
12651314
SInt32 nrfds, maxnrfds, fdentries = 1;
12661315
SInt32 rfds, wfds;
12671316
fd_set *exceptfds = NULL;
1317+
#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);
1320+
FD_ZERO(writefds);
1321+
FD_ZERO(readfds);
1322+
#else
12681323
fd_set *writefds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, fdentries * sizeof(fd_mask), 0);
12691324
fd_set *readfds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, fdentries * sizeof(fd_mask), 0);
1325+
#endif
12701326
fd_set *tempfds;
12711327
SInt32 idx, cnt;
12721328
uint8_t buffer[256];
@@ -1292,6 +1348,11 @@ static void *__CFSocketManager(void * arg)
12921348
free(readBuffer);
12931349
free(writeBuffer);
12941350
#endif
1351+
1352+
#if TARGET_OS_WIN32
1353+
// This parameter is ignored by `select` from Winsock2 API
1354+
maxnrfds = INT_MAX;
1355+
#else
12951356
rfds = __CFSocketFdGetSize(__CFReadSocketsFds);
12961357
wfds = __CFSocketFdGetSize(__CFWriteSocketsFds);
12971358
maxnrfds = __CFMax(rfds, wfds);
@@ -1302,6 +1363,7 @@ static void *__CFSocketManager(void * arg)
13021363
}
13031364
memset(writefds, 0, fdentries * sizeof(fd_mask));
13041365
memset(readfds, 0, fdentries * sizeof(fd_mask));
1366+
#endif
13051367
CFDataGetBytes(__CFWriteSocketsFds, CFRangeMake(0, CFDataGetLength(__CFWriteSocketsFds)), (UInt8 *)writefds);
13061368
CFDataGetBytes(__CFReadSocketsFds, CFRangeMake(0, CFDataGetLength(__CFReadSocketsFds)), (UInt8 *)readfds);
13071369

@@ -1347,7 +1409,13 @@ static void *__CFSocketManager(void * arg)
13471409
}
13481410
#endif
13491411

1412+
SInt32 error = 0;
13501413
nrfds = select(maxnrfds, readfds, writefds, exceptfds, pTimeout);
1414+
if (nrfds < 0) {
1415+
// Store error as early as possible, as the code below could
1416+
// reset it and make late check unreliable.
1417+
error = __CFSocketLastError();
1418+
}
13511419

13521420
#if defined(LOG_CFSOCKET) && defined(DEBUG_POLLING_SELECT)
13531421
__CFSOCKETLOG("socket manager woke from select, ret=%ld", (long)nrfds);
@@ -1436,7 +1504,7 @@ static void *__CFSocketManager(void * arg)
14361504
}
14371505

14381506
if (0 > nrfds) {
1439-
manageSelectError();
1507+
manageSelectError(error);
14401508
continue;
14411509
}
14421510
if (FD_ISSET(__CFWakeupSocketPair[1], readfds)) {

Sources/Foundation/NSData.swift

+5-1
Original file line numberDiff line numberDiff line change
@@ -421,8 +421,12 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
421421
}
422422

423423
let fm = FileManager.default
424+
#if os(WASI)
425+
// WASI does not have permission concept
426+
let permissions: Int? = nil
427+
#else
424428
let permissions = try? fm.attributesOfItem(atPath: path)[.posixPermissions] as? Int
425-
429+
#endif
426430
if writeOptionsMask.contains(.atomic) {
427431
let (newFD, auxFilePath) = try _NSCreateTemporaryFile(path)
428432
let fh = FileHandle(fileDescriptor: newFD, closeOnDealloc: true)

Sources/FoundationNetworking/DataURLProtocol.swift

+1-2
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,7 @@ internal class _DataURLProtocol: URLProtocol {
9191
urlClient.urlProtocolDidFinishLoading(self)
9292
} else {
9393
let error = NSError(domain: NSURLErrorDomain, code: NSURLErrorBadURL)
94-
if let session = self.task?.session as? URLSession, let delegate = session.delegate as? URLSessionTaskDelegate,
95-
let task = self.task {
94+
if let task = self.task, let session = task.actualSession, let delegate = task.delegate {
9695
delegate.urlSession(session, task: task, didCompleteWithError: error)
9796
}
9897
}

Sources/FoundationNetworking/URLSession/FTP/FTPURLProtocol.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ internal extension _FTPURLProtocol {
119119
switch session.behaviour(for: self.task!) {
120120
case .noDelegate:
121121
break
122-
case .taskDelegate:
122+
case .taskDelegate, .dataCompletionHandlerWithTaskDelegate, .downloadCompletionHandlerWithTaskDelegate:
123123
self.client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
124124
case .dataCompletionHandler:
125125
break

Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift

+4-2
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ internal class _HTTPURLProtocol: _NativeProtocol {
475475

476476
guard let session = task?.session as? URLSession else { fatalError() }
477477

478-
if let delegate = session.delegate as? URLSessionTaskDelegate {
478+
if let delegate = task?.delegate {
479479
// At this point we need to change the internal state to note
480480
// that we're waiting for the delegate to call the completion
481481
// handler. Then we'll call the delegate callback
@@ -524,7 +524,9 @@ internal class _HTTPURLProtocol: _NativeProtocol {
524524
switch session.behaviour(for: self.task!) {
525525
case .noDelegate:
526526
break
527-
case .taskDelegate:
527+
case .taskDelegate,
528+
.dataCompletionHandlerWithTaskDelegate,
529+
.downloadCompletionHandlerWithTaskDelegate:
528530
//TODO: There's a problem with libcurl / with how we're using it.
529531
// We're currently unable to pause the transfer / the easy handle:
530532
// https://curl.haxx.se/mail/lib-2016-03/0222.html

Sources/FoundationNetworking/URLSession/NativeProtocol.swift

+51-33
Original file line numberDiff line numberDiff line change
@@ -129,43 +129,59 @@ internal class _NativeProtocol: URLProtocol, _EasyHandleDelegate {
129129
}
130130

131131
fileprivate func notifyDelegate(aboutReceivedData data: Data) {
132-
guard let t = self.task else {
132+
guard let task = self.task, let session = task.session as? URLSession else {
133133
fatalError("Cannot notify")
134134
}
135-
if case .taskDelegate(let delegate) = t.session.behaviour(for: self.task!),
136-
let dataDelegate = delegate as? URLSessionDataDelegate,
137-
let task = self.task as? URLSessionDataTask {
138-
// Forward to the delegate:
139-
guard let s = self.task?.session as? URLSession else {
140-
fatalError()
141-
}
142-
s.delegateQueue.addOperation {
143-
dataDelegate.urlSession(s, dataTask: task, didReceive: data)
144-
}
145-
} else if case .taskDelegate(let delegate) = t.session.behaviour(for: self.task!),
146-
let downloadDelegate = delegate as? URLSessionDownloadDelegate,
147-
let task = self.task as? URLSessionDownloadTask {
148-
guard let s = self.task?.session as? URLSession else {
149-
fatalError()
150-
}
151-
let fileHandle = try! FileHandle(forWritingTo: self.tempFileURL)
152-
_ = fileHandle.seekToEndOfFile()
153-
fileHandle.write(data)
154-
task.countOfBytesReceived += Int64(data.count)
155-
s.delegateQueue.addOperation {
156-
downloadDelegate.urlSession(s, downloadTask: task, didWriteData: Int64(data.count), totalBytesWritten: task.countOfBytesReceived,
157-
totalBytesExpectedToWrite: task.countOfBytesExpectedToReceive)
135+
switch task.session.behaviour(for: task) {
136+
case .taskDelegate(let delegate),
137+
.dataCompletionHandlerWithTaskDelegate(_, let delegate),
138+
.downloadCompletionHandlerWithTaskDelegate(_, let delegate):
139+
if let dataDelegate = delegate as? URLSessionDataDelegate,
140+
let dataTask = task as? URLSessionDataTask {
141+
session.delegateQueue.addOperation {
142+
dataDelegate.urlSession(session, dataTask: dataTask, didReceive: data)
143+
}
144+
} else if let downloadDelegate = delegate as? URLSessionDownloadDelegate,
145+
let downloadTask = task as? URLSessionDownloadTask {
146+
let fileHandle = try! FileHandle(forWritingTo: self.tempFileURL)
147+
_ = fileHandle.seekToEndOfFile()
148+
fileHandle.write(data)
149+
task.countOfBytesReceived += Int64(data.count)
150+
session.delegateQueue.addOperation {
151+
downloadDelegate.urlSession(
152+
session,
153+
downloadTask: downloadTask,
154+
didWriteData: Int64(data.count),
155+
totalBytesWritten: task.countOfBytesReceived,
156+
totalBytesExpectedToWrite: task.countOfBytesExpectedToReceive
157+
)
158+
}
158159
}
160+
default:
161+
break
159162
}
160163
}
161164

162165
fileprivate func notifyDelegate(aboutUploadedData count: Int64) {
163-
guard let task = self.task, let session = task.session as? URLSession,
164-
case .taskDelegate(let delegate) = session.behaviour(for: task) else { return }
165-
task.countOfBytesSent += count
166-
session.delegateQueue.addOperation {
167-
delegate.urlSession(session, task: task, didSendBodyData: count,
168-
totalBytesSent: task.countOfBytesSent, totalBytesExpectedToSend: task.countOfBytesExpectedToSend)
166+
guard let task = self.task, let session = task.session as? URLSession else {
167+
return
168+
}
169+
switch session.behaviour(for: task) {
170+
case .taskDelegate(let delegate),
171+
.dataCompletionHandlerWithTaskDelegate(_, let delegate),
172+
.downloadCompletionHandlerWithTaskDelegate(_, let delegate):
173+
task.countOfBytesSent += count
174+
session.delegateQueue.addOperation {
175+
delegate.urlSession(
176+
session,
177+
task: task,
178+
didSendBodyData: count,
179+
totalBytesSent: task.countOfBytesSent,
180+
totalBytesExpectedToSend: task.countOfBytesExpectedToSend
181+
)
182+
}
183+
default:
184+
break
169185
}
170186
}
171187

@@ -284,7 +300,7 @@ internal class _NativeProtocol: URLProtocol, _EasyHandleDelegate {
284300

285301
var currentInputStream: InputStream?
286302

287-
if let delegate = session.delegate as? URLSessionTaskDelegate {
303+
if let delegate = task?.delegate {
288304
let dispatchGroup = DispatchGroup()
289305
dispatchGroup.enter()
290306

@@ -338,11 +354,13 @@ internal class _NativeProtocol: URLProtocol, _EasyHandleDelegate {
338354
// Data will be forwarded to the delegate as we receive it, we don't
339355
// need to do anything about it.
340356
return .ignore
341-
case .dataCompletionHandler:
357+
case .dataCompletionHandler,
358+
.dataCompletionHandlerWithTaskDelegate:
342359
// Data needs to be concatenated in-memory such that we can pass it
343360
// to the completion handler upon completion.
344361
return .inMemory(nil)
345-
case .downloadCompletionHandler:
362+
case .downloadCompletionHandler,
363+
.downloadCompletionHandlerWithTaskDelegate:
346364
// Data needs to be written to a file (i.e. a download task).
347365
let fileHandle = try! FileHandle(forWritingTo: self.tempFileURL)
348366
return .toFile(self.tempFileURL, fileHandle)

Sources/FoundationNetworking/URLSession/TaskRegistry.swift

+4
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,12 @@ extension URLSession {
4545
case callDelegate
4646
/// Default action for all events, except for completion.
4747
case dataCompletionHandler(DataTaskCompletion)
48+
/// Default action for all asynchronous events.
49+
case dataCompletionHandlerWithTaskDelegate(DataTaskCompletion, URLSessionTaskDelegate?)
4850
/// Default action for all events, except for completion.
4951
case downloadCompletionHandler(DownloadTaskCompletion)
52+
/// Default action for all asynchronous events.
53+
case downloadCompletionHandlerWithTaskDelegate(DownloadTaskCompletion, URLSessionTaskDelegate?)
5054
}
5155

5256
fileprivate var tasks: [Int: URLSessionTask] = [:]

0 commit comments

Comments
 (0)