Skip to content

Commit d7e0488

Browse files
authored
Merge pull request #2013 from compnerd/open-all-the-ports
TestFoundation: port HTTPServer to Windows
2 parents a06922a + 6188a26 commit d7e0488

File tree

1 file changed

+83
-23
lines changed

1 file changed

+83
-23
lines changed

TestFoundation/HTTPServer.swift

Lines changed: 83 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,19 @@
1414

1515
import Dispatch
1616

17-
#if canImport(Darwin)
17+
#if canImport(MSVCRT)
18+
import MSVCRT
19+
import WinSDK
20+
#elseif canImport(Darwin)
1821
import Darwin
1922
#elseif canImport(Glibc)
2023
import Glibc
2124
#endif
2225

26+
#if !os(Windows)
27+
typealias SOCKET = Int32
28+
#endif
29+
2330

2431
public let globalDispatchQueue = DispatchQueue.global()
2532
public let dispatchQueueMake: (String) -> DispatchQueue = { DispatchQueue.init(label: $0) }
@@ -40,11 +47,12 @@ extension UInt16 {
4047
}
4148

4249
class _TCPSocket {
43-
50+
#if !os(Windows)
4451
private let sendFlags: CInt
45-
private var listenSocket: Int32!
52+
#endif
53+
private var listenSocket: SOCKET!
4654
private var socketAddress = UnsafeMutablePointer<sockaddr_in>.allocate(capacity: 1)
47-
private var connectionSocket: Int32!
55+
private var connectionSocket: SOCKET!
4856

4957
private func isNotNegative(r: CInt) -> Bool {
5058
return r != -1
@@ -54,7 +62,7 @@ class _TCPSocket {
5462
return r == 0
5563
}
5664

57-
private func attempt(_ name: String, file: String = #file, line: UInt = #line, valid: (CInt) -> Bool, _ b: @autoclosure () -> CInt) throws -> CInt {
65+
private func attempt<T>(_ name: String, file: String = #file, line: UInt = #line, valid: (T) -> Bool, _ b: @autoclosure () -> T) throws -> T {
5866
let r = b()
5967
guard valid(r) else {
6068
throw ServerError(operation: name, errno: errno, file: file, line: line)
@@ -65,21 +73,31 @@ class _TCPSocket {
6573
public private(set) var port: UInt16
6674

6775
init(port: UInt16?) throws {
68-
#if canImport(Darwin)
69-
sendFlags = 0
70-
#else
76+
#if !os(Windows)
77+
#if os(Linux) || os(Android) || os(FreeBSD)
7178
sendFlags = CInt(MSG_NOSIGNAL)
79+
#else
80+
sendFlags = 0
81+
#endif
7282
#endif
7383

84+
self.port = port ?? 0
85+
86+
#if os(Windows)
87+
listenSocket = try attempt("WSASocketW", valid: { $0 != INVALID_SOCKET }, WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP.rawValue, nil, 0, 0))
88+
89+
var value: Int8 = Int8(TRUE)
90+
_ = try attempt("setsockopt", valid: { $0 == 0 }, setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &value, Int32(MemoryLayout.size(ofValue: value))))
91+
#else
7492
#if os(Linux) && !os(Android)
75-
let SOCKSTREAM = Int32(SOCK_STREAM.rawValue)
93+
let SOCKSTREAM = Int32(SOCK_STREAM.rawValue)
7694
#else
77-
let SOCKSTREAM = SOCK_STREAM
95+
let SOCKSTREAM = SOCK_STREAM
7896
#endif
79-
self.port = port ?? 0
80-
listenSocket = try attempt("socket", valid: isNotNegative, socket(AF_INET, SOCKSTREAM, Int32(IPPROTO_TCP)))
97+
listenSocket = try attempt("socket", valid: { $0 >= 0 }, socket(AF_INET, SOCKSTREAM, Int32(IPPROTO_TCP)))
8198
var on: CInt = 1
82-
_ = try attempt("setsockopt", valid: isZero, setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &on, socklen_t(MemoryLayout<CInt>.size)))
99+
_ = try attempt("setsockopt", valid: { $0 == 0 }, setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &on, socklen_t(MemoryLayout<CInt>.size)))
100+
#endif
83101

84102
let sa = createSockaddr(port)
85103
socketAddress.initialize(to: sa)
@@ -109,6 +127,8 @@ class _TCPSocket {
109127
return sockaddr_in(sin_family: sa_family_t(AF_INET), sin_port: netPort, sin_addr: in_addr(s_addr: addr), __pad: (0,0,0,0,0,0,0,0))
110128
#elseif os(Linux)
111129
return sockaddr_in(sin_family: sa_family_t(AF_INET), sin_port: netPort, sin_addr: in_addr(s_addr: addr), sin_zero: (0,0,0,0,0,0,0,0))
130+
#elseif os(Windows)
131+
return sockaddr_in(sin_family: ADDRESS_FAMILY(AF_INET), sin_port: USHORT(netPort), sin_addr: IN_ADDR(S_un: in_addr.__Unnamed_union_S_un(S_addr: addr)), sin_zero: (CHAR(0), CHAR(0), CHAR(0), CHAR(0), CHAR(0), CHAR(0), CHAR(0), CHAR(0)))
112132
#else
113133
return sockaddr_in(sin_len: 0, sin_family: sa_family_t(AF_INET), sin_port: netPort, sin_addr: in_addr(s_addr: addr), sin_zero: (0,0,0,0,0,0,0,0))
114134
#endif
@@ -118,7 +138,11 @@ class _TCPSocket {
118138
try socketAddress.withMemoryRebound(to: sockaddr.self, capacity: MemoryLayout<sockaddr>.size, {
119139
let addr = UnsafeMutablePointer<sockaddr>($0)
120140
var sockLen = socklen_t(MemoryLayout<sockaddr>.size)
121-
connectionSocket = try attempt("accept", valid: isNotNegative, accept(listenSocket, addr, &sockLen))
141+
#if os(Windows)
142+
connectionSocket = try attempt("WSAAccept", valid: { $0 != INVALID_SOCKET }, WSAAccept(listenSocket, addr, &sockLen, nil, 0))
143+
#else
144+
connectionSocket = try attempt("accept", valid: { $0 >= 0 }, accept(listenSocket, addr, &sockLen))
145+
#endif
122146
#if canImport(Dawin)
123147
// Disable SIGPIPEs when writing to closed sockets
124148
var on: CInt = 1
@@ -128,8 +152,16 @@ class _TCPSocket {
128152
}
129153

130154
func readData() throws -> String {
131-
var buffer = [UInt8](repeating: 0, count: 4096)
132-
_ = try attempt("read", valid: isNotNegative, CInt(read(connectionSocket, &buffer, buffer.count)))
155+
var buffer = [CChar](repeating: 0, count: 4096)
156+
#if os(Windows)
157+
var dwNumberOfBytesRecieved: DWORD = 0;
158+
try buffer.withUnsafeMutableBufferPointer {
159+
var wsaBuffer: WSABUF = WSABUF(len: ULONG($0.count), buf: $0.baseAddress)
160+
_ = try attempt("WSARecv", valid: { $0 != SOCKET_ERROR }, WSARecv(connectionSocket, &wsaBuffer, 1, &dwNumberOfBytesRecieved, nil, nil, nil))
161+
}
162+
#else
163+
_ = try attempt("read", valid: { $0 >= 0 }, read(connectionSocket, &buffer, buffer.count))
164+
#endif
133165
return String(cString: &buffer)
134166
}
135167

@@ -142,41 +174,69 @@ class _TCPSocket {
142174
}
143175

144176
func writeRawData(_ data: Data) throws {
177+
#if os(Windows)
178+
_ = try data.withUnsafeBytes {
179+
var dwNumberOfBytesSent: DWORD = 0
180+
var wsaBuffer: WSABUF = WSABUF(len: ULONG(data.count), buf: UnsafeMutablePointer<CHAR>(mutating: $0.bindMemory(to: CHAR.self).baseAddress))
181+
_ = try attempt("WSASend", valid: { $0 != SOCKET_ERROR }, WSASend(connectionSocket, &wsaBuffer, 1, &dwNumberOfBytesSent, 0, nil, nil))
182+
}
183+
#else
145184
_ = try data.withUnsafeBytes { ptr in
146185
try attempt("send", valid: isNotNegative, CInt(send(connectionSocket, ptr, data.count, sendFlags)))
147186
}
187+
#endif
148188
}
149-
189+
190+
private func _send(_ bytes: [UInt8]) throws -> Int {
191+
#if os(Windows)
192+
return try bytes.withUnsafeBytes {
193+
var dwNumberOfBytesSent: DWORD = 0
194+
var wsaBuffer: WSABUF = WSABUF(len: ULONG(bytes.count), buf: UnsafeMutablePointer<CHAR>(mutating: $0.bindMemory(to: CHAR.self).baseAddress))
195+
return try Int(attempt("WSASend", valid: { $0 != SOCKET_ERROR }, WSASend(connectionSocket, &wsaBuffer, 1, &dwNumberOfBytesSent, 0, nil, nil)))
196+
}
197+
#else
198+
return try bytes.withUnsafeBufferPointer {
199+
try attempt("send", valid: { $0 >= 0 }, send(connectionSocket, $0.baseAddress, $0.count, sendFlags))
200+
}
201+
#endif
202+
}
203+
150204
func writeData(header: String, body: String, sendDelay: TimeInterval? = nil, bodyChunks: Int? = nil) throws {
151-
var _header = Array(header.utf8)
152-
_ = try attempt("send", valid: isNotNegative, CInt(send(connectionSocket, &_header, _header.count, sendFlags)))
205+
_ = try _send(Array(header.utf8))
153206

154207
if let sendDelay = sendDelay, let bodyChunks = bodyChunks {
155208
let count = max(1, Int(Double(body.utf8.count) / Double(bodyChunks)))
156209
let texts = split(body, count)
157210

158211
for item in texts {
159212
Thread.sleep(forTimeInterval: sendDelay)
160-
var bytes = Array(item.utf8)
161-
_ = try attempt("send", valid: isNotNegative, CInt(send(connectionSocket, &bytes, bytes.count, sendFlags)))
213+
_ = try _send(Array(item.utf8))
162214
}
163215
} else {
164-
var bytes = Array(body.utf8)
165-
_ = try attempt("send", valid: isNotNegative, CInt(send(connectionSocket, &bytes, bytes.count, sendFlags)))
216+
_ = try _send(Array(body.utf8))
166217
}
167218
}
168219

169220
func closeClient() {
170221
if let connectionSocket = self.connectionSocket {
222+
#if os(Windows)
223+
closesocket(connectionSocket)
224+
#else
171225
close(connectionSocket)
226+
#endif
172227
self.connectionSocket = nil
173228
}
174229
}
175230

176231
func shutdownListener() {
177232
closeClient()
233+
#if os(Windows)
234+
shutdown(listenSocket, SD_BOTH)
235+
closesocket(listenSocket)
236+
#else
178237
shutdown(listenSocket, CInt(SHUT_RDWR))
179238
close(listenSocket)
239+
#endif
180240
}
181241
}
182242

0 commit comments

Comments
 (0)