Skip to content

Commit cf74be7

Browse files
committed
Initial port of Swifter to Windows
1 parent 1e4f51c commit cf74be7

File tree

6 files changed

+94
-21
lines changed

6 files changed

+94
-21
lines changed

Xcode/Sources/HttpServerIO.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88
import Foundation
99
import Dispatch
1010

11+
#if os(Windows)
12+
import WinSDK
13+
public typealias in_port_t = UInt16
14+
#endif
15+
1116
public protocol HttpServerIODelegate: AnyObject {
1217
func socketConnectionReceived(_ socket: Socket)
1318
}
@@ -16,7 +21,7 @@ open class HttpServerIO {
1621

1722
public weak var delegate: HttpServerIODelegate?
1823

19-
private var socket = Socket(socketFileDescriptor: -1)
24+
private var socket = Socket(socketFileDescriptor: invalidPlatformSocketFD)
2025
private var sockets = Set<Socket>()
2126

2227
public enum HttpServerIOState: Int32 {
@@ -33,7 +38,7 @@ open class HttpServerIO {
3338
return HttpServerIOState(rawValue: stateValue)!
3439
}
3540
set(state) {
36-
#if !os(Linux)
41+
#if !os(Linux) && !os(Windows)
3742
OSAtomicCompareAndSwapInt(self.state.rawValue, state.rawValue, &stateValue)
3843
#else
3944
self.stateValue = state.rawValue

Xcode/Sources/Process.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77

88
import Foundation
99

10+
#if os(Windows)
11+
import WinSDK
12+
#endif
13+
1014
public class Process {
1115

1216
public static var pid: Int {
@@ -16,6 +20,8 @@ public class Process {
1620
public static var tid: UInt64 {
1721
#if os(Linux)
1822
return UInt64(pthread_self())
23+
#elseif os(Windows)
24+
return UInt64(GetCurrentThreadId())
1925
#else
2026
var tid: __uint64_t = 0
2127
pthread_threadid_np(nil, &tid)
@@ -28,7 +34,12 @@ public class Process {
2834

2935
public static func watchSignals(_ callback: @escaping (Int32) -> Void) {
3036
if !signalsObserved {
31-
[SIGTERM, SIGHUP, SIGSTOP, SIGINT].forEach { item in
37+
#if os(Windows)
38+
let signals = [SIGTERM, SIGINT]
39+
#else
40+
let signals = [SIGTERM, SIGHUP, SIGSTOP, SIGINT]
41+
#endif
42+
signals.forEach { item in
3243
signal(item) { signum in
3344
Process.signalsWatchers.forEach { $0(signum) }
3445
}

Xcode/Sources/Socket+File.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,15 @@
77

88
import Foundation
99

10-
#if os(iOS) || os(tvOS) || os (Linux)
10+
#if os(Windows)
11+
import WinSDK
12+
#endif
13+
14+
#if os(iOS) || os(tvOS) || os (Linux) || os(Windows)
1115
// swiftlint:disable type_name function_parameter_count
1216
struct sf_hdtr { }
1317

14-
private func sendfileImpl(_ source: UnsafeMutablePointer<FILE>, _ target: Int32, _: off_t, _: UnsafeMutablePointer<off_t>, _: UnsafeMutablePointer<sf_hdtr>, _: Int32) -> Int32 {
18+
private func sendfileImpl(_ source: UnsafeMutablePointer<FILE>, _ target: PlatformSocketFD, _: off_t, _: UnsafeMutablePointer<off_t>, _: UnsafeMutablePointer<sf_hdtr>, _: Int32) -> Int32 {
1519
var buffer = [UInt8](repeating: 0, count: 1024)
1620
while true {
1721
let readResult = fread(&buffer, 1, buffer.count, source)
@@ -25,6 +29,8 @@ import Foundation
2529
let len = readResult - writeCounter
2630
#if os(Linux)
2731
return send(target, start, len, Int32(MSG_NOSIGNAL))
32+
#elseif os(Windows)
33+
return Int(send(target, start, Int32(len), 0))
2834
#else
2935
return write(target, start, len)
3036
#endif
@@ -44,7 +50,7 @@ extension Socket {
4450
var offset: off_t = 0
4551
var sf: sf_hdtr = sf_hdtr()
4652

47-
#if os(iOS) || os(tvOS) || os (Linux)
53+
#if os(iOS) || os(tvOS) || os (Linux) || os(Windows)
4854
let result = sendfileImpl(file.pointer, self.socketFileDescriptor, 0, &offset, &sf, 0)
4955
#else
5056
let result = sendfile(fileno(file.pointer), self.socketFileDescriptor, 0, &offset, &sf, 0)

Xcode/Sources/Socket+Server.swift

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77

88
import Foundation
99

10+
#if os(Windows)
11+
import WinSDK
12+
#endif
13+
1014
extension Socket {
1115

1216
// swiftlint:disable function_body_length
@@ -15,14 +19,13 @@ extension Socket {
1519
/// connections from. It should be in IPv4 format if forceIPv4 == true,
1620
/// otherwise - in IPv6.
1721
public class func tcpSocketForListen(_ port: in_port_t, _ forceIPv4: Bool = false, _ maxPendingConnection: Int32 = SOMAXCONN, _ listenAddress: String? = nil) throws -> Socket {
18-
1922
#if os(Linux)
2023
let socketFileDescriptor = socket(forceIPv4 ? AF_INET : AF_INET6, Int32(SOCK_STREAM.rawValue), 0)
2124
#else
2225
let socketFileDescriptor = socket(forceIPv4 ? AF_INET : AF_INET6, SOCK_STREAM, 0)
2326
#endif
2427

25-
if socketFileDescriptor == -1 {
28+
if socketFileDescriptor == invalidPlatformSocketFD {
2629
throw SocketError.socketCreationFailed(Errno.description())
2730
}
2831

@@ -42,6 +45,12 @@ extension Socket {
4245
sin_port: port.bigEndian,
4346
sin_addr: in_addr(s_addr: in_addr_t(0)),
4447
sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
48+
#elseif os(Windows)
49+
var addr = sockaddr_in(
50+
sin_family: ADDRESS_FAMILY(AF_INET),
51+
sin_port: port.bigEndian,
52+
sin_addr: .init(),
53+
sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
4554
#else
4655
var addr = sockaddr_in(
4756
sin_len: UInt8(MemoryLayout<sockaddr_in>.stride),
@@ -68,6 +77,13 @@ extension Socket {
6877
sin6_flowinfo: 0,
6978
sin6_addr: in6addr_any,
7079
sin6_scope_id: 0)
80+
#elseif os(Windows)
81+
var addr = sockaddr_in6(
82+
sin6_family: ADDRESS_FAMILY(AF_INET6),
83+
sin6_port: port.bigEndian,
84+
sin6_flowinfo: 0,
85+
sin6_addr: in6addr_any,
86+
sockaddr_in6.__Unnamed_union___Anonymous_field4())
7187
#else
7288
var addr = sockaddr_in6(
7389
sin6_len: UInt8(MemoryLayout<sockaddr_in6>.stride),
@@ -104,10 +120,8 @@ extension Socket {
104120
}
105121

106122
public func acceptClientSocket() throws -> Socket {
107-
var addr = sockaddr()
108-
var len: socklen_t = 0
109-
let clientSocket = accept(self.socketFileDescriptor, &addr, &len)
110-
if clientSocket == -1 {
123+
let clientSocket = accept(self.socketFileDescriptor, nil, nil)
124+
if clientSocket == invalidPlatformSocketFD {
111125
throw SocketError.acceptFailed(Errno.description())
112126
}
113127
Socket.setNoSigPipe(clientSocket)

Xcode/Sources/Socket.swift

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,18 @@
77

88
import Foundation
99

10+
#if os(Windows)
11+
import WinSDK
12+
#endif
13+
14+
#if os(Windows)
15+
public typealias PlatformSocketFD = SOCKET
16+
public let invalidPlatformSocketFD = INVALID_SOCKET
17+
#else
18+
public typealias PlatformSocketFD = Int32
19+
public let invalidPlatformSocketFD = Int32(-1)
20+
#endif
21+
1022
public enum SocketError: Error {
1123
case socketCreationFailed(String)
1224
case socketSettingReUseAddrFailed(String)
@@ -23,11 +35,10 @@ public enum SocketError: Error {
2335

2436
// swiftlint: disable identifier_name
2537
open class Socket: Hashable, Equatable {
26-
27-
let socketFileDescriptor: Int32
38+
let socketFileDescriptor: PlatformSocketFD
2839
private var shutdown = false
2940

30-
public init(socketFileDescriptor: Int32) {
41+
public init(socketFileDescriptor: PlatformSocketFD) {
3142
self.socketFileDescriptor = socketFileDescriptor
3243
}
3344

@@ -55,7 +66,7 @@ open class Socket: Hashable, Equatable {
5566
throw SocketError.getSockNameFailed(Errno.description())
5667
}
5768
let sin_port = pointer.pointee.sin_port
58-
#if os(Linux)
69+
#if os(Linux) || os(Windows)
5970
return ntohs(sin_port)
6071
#else
6172
return Int(OSHostByteOrder()) != OSLittleEndian ? sin_port.littleEndian : sin_port.bigEndian
@@ -112,6 +123,8 @@ open class Socket: Hashable, Equatable {
112123
while sent < length {
113124
#if os(Linux)
114125
let result = send(self.socketFileDescriptor, pointer + sent, Int(length - sent), Int32(MSG_NOSIGNAL))
126+
#elseif os(Windows)
127+
let result = Int(send(self.socketFileDescriptor, pointer + sent, Int32(length - sent), 0))
115128
#else
116129
let result = write(self.socketFileDescriptor, pointer + sent, Int(length - sent))
117130
#endif
@@ -133,6 +146,8 @@ open class Socket: Hashable, Equatable {
133146

134147
#if os(Linux)
135148
let count = Glibc.read(self.socketFileDescriptor as Int32, &byte, 1)
149+
#elseif os(Windows)
150+
let count = recv(self.socketFileDescriptor, &byte, 1, 0)
136151
#else
137152
let count = Darwin.read(self.socketFileDescriptor as Int32, &byte, 1)
138153
#endif
@@ -172,6 +187,8 @@ open class Socket: Hashable, Equatable {
172187

173188
#if os(Linux)
174189
let bytesRead = Glibc.read(self.socketFileDescriptor as Int32, baseAddress + offset, readLength)
190+
#elseif os(Windows)
191+
let bytesRead = Int(recv(self.socketFileDescriptor, baseAddress + offset, Int32(readLength), 0))
175192
#else
176193
let bytesRead = Darwin.read(self.socketFileDescriptor as Int32, baseAddress + offset, readLength)
177194
#endif
@@ -205,14 +222,19 @@ open class Socket: Hashable, Equatable {
205222
throw SocketError.getPeerNameFailed(Errno.description())
206223
}
207224
var hostBuffer = [CChar](repeating: 0, count: Int(NI_MAXHOST))
208-
if getnameinfo(&addr, len, &hostBuffer, socklen_t(hostBuffer.count), nil, 0, NI_NUMERICHOST) != 0 {
225+
#if os(Windows)
226+
let hostBufferSize = DWORD(hostBuffer.count)
227+
#else
228+
let hostBufferSize = socklen_t(hostBuffer.count)
229+
#endif
230+
if getnameinfo(&addr, len, &hostBuffer, hostBufferSize, nil, 0, NI_NUMERICHOST) != 0 {
209231
throw SocketError.getNameInfoFailed(Errno.description())
210232
}
211233
return String(cString: hostBuffer)
212234
}
213235

214-
public class func setNoSigPipe(_ socket: Int32) {
215-
#if os(Linux)
236+
public class func setNoSigPipe(_ socket: PlatformSocketFD) {
237+
#if os(Linux) || os(Windows)
216238
// There is no SO_NOSIGPIPE in Linux (nor some other systems). You can instead use the MSG_NOSIGNAL flag when calling send(),
217239
// or use signal(SIGPIPE, SIG_IGN) to make your entire application ignore SIGPIPE.
218240
#else
@@ -222,9 +244,11 @@ open class Socket: Hashable, Equatable {
222244
#endif
223245
}
224246

225-
public class func close(_ socket: Int32) {
247+
public class func close(_ socket: PlatformSocketFD) {
226248
#if os(Linux)
227249
_ = Glibc.close(socket)
250+
#elseif os(Windows)
251+
_ = closesocket(socket)
228252
#else
229253
_ = Darwin.close(socket)
230254
#endif

Xcode/Sources/String+File.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77

88
import Foundation
99

10+
#if os(Windows)
11+
import WinSDK
12+
#endif
13+
1014
extension String {
1115

1216
public enum FileError: Error {
@@ -25,7 +29,7 @@ extension String {
2529
fclose(pointer)
2630
}
2731

28-
public func seek(_ offset: Int) -> Bool {
32+
public func seek(_ offset: Int32) -> Bool {
2933
return (fseek(pointer, offset, SEEK_SET) == 0)
3034
}
3135

@@ -98,13 +102,21 @@ extension String {
98102
public func directory() throws -> Bool {
99103
return try self.withStat {
100104
if let stat = $0 {
105+
#if os(Windows)
106+
// Need to disambiguate here.
107+
return Int32(stat.st_mode) & ucrt.S_IFMT == ucrt.S_IFDIR
108+
#else
101109
return stat.st_mode & S_IFMT == S_IFDIR
110+
#endif
102111
}
103112
return false
104113
}
105114
}
106115

107116
public func files() throws -> [String] {
117+
#if os(Windows)
118+
fatalError("Not implemented")
119+
#else
108120
guard let dir = self.withCString({ opendir($0) }) else {
109121
throw FileError.error(errno)
110122
}
@@ -130,6 +142,7 @@ extension String {
130142
}
131143
}
132144
return results
145+
#endif
133146
}
134147

135148
private func withStat<T>(_ closure: ((stat?) throws -> T)) throws -> T {

0 commit comments

Comments
 (0)