14
14
15
15
import Dispatch
16
16
17
- #if canImport(Darwin)
17
+ #if canImport(MSVCRT)
18
+ import MSVCRT
19
+ import WinSDK
20
+ #elseif canImport(Darwin)
18
21
import Darwin
19
22
#elseif canImport(Glibc)
20
23
import Glibc
21
24
#endif
22
25
26
+ #if !os(Windows)
27
+ typealias SOCKET = Int32
28
+ #endif
29
+
23
30
24
31
public let globalDispatchQueue = DispatchQueue . global ( )
25
32
public let dispatchQueueMake : ( String ) -> DispatchQueue = { DispatchQueue . init ( label: $0) }
@@ -40,11 +47,12 @@ extension UInt16 {
40
47
}
41
48
42
49
class _TCPSocket {
43
-
50
+ #if !os(Windows)
44
51
private let sendFlags : CInt
45
- private var listenSocket : Int32 !
52
+ #endif
53
+ private var listenSocket : SOCKET !
46
54
private var socketAddress = UnsafeMutablePointer< sockaddr_in> . allocate( capacity: 1 )
47
- private var connectionSocket : Int32 !
55
+ private var connectionSocket : SOCKET !
48
56
49
57
private func isNotNegative( r: CInt ) -> Bool {
50
58
return r != - 1
@@ -54,7 +62,7 @@ class _TCPSocket {
54
62
return r == 0
55
63
}
56
64
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 {
58
66
let r = b ( )
59
67
guard valid ( r) else {
60
68
throw ServerError ( operation: name, errno: errno, file: file, line: line)
@@ -65,21 +73,31 @@ class _TCPSocket {
65
73
public private( set) var port : UInt16
66
74
67
75
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)
71
78
sendFlags = CInt ( MSG_NOSIGNAL)
79
+ #else
80
+ sendFlags = 0
81
+ #endif
72
82
#endif
73
83
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
74
92
#if os(Linux) && !os(Android)
75
- let SOCKSTREAM = Int32 ( SOCK_STREAM . rawValue)
93
+ let SOCKSTREAM = Int32 ( SOCK_STREAM . rawValue)
76
94
#else
77
- let SOCKSTREAM = SOCK_STREAM
95
+ let SOCKSTREAM = SOCK_STREAM
78
96
#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) ) )
81
98
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
83
101
84
102
let sa = createSockaddr ( port)
85
103
socketAddress. initialize ( to: sa)
@@ -109,6 +127,8 @@ class _TCPSocket {
109
127
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 ) )
110
128
#elseif os(Linux)
111
129
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 ) ) )
112
132
#else
113
133
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 ) )
114
134
#endif
@@ -118,7 +138,11 @@ class _TCPSocket {
118
138
try socketAddress. withMemoryRebound ( to: sockaddr. self, capacity: MemoryLayout< sockaddr> . size, {
119
139
let addr = UnsafeMutablePointer < sockaddr > ( $0)
120
140
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
122
146
#if canImport(Dawin)
123
147
// Disable SIGPIPEs when writing to closed sockets
124
148
var on : CInt = 1
@@ -128,8 +152,16 @@ class _TCPSocket {
128
152
}
129
153
130
154
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
133
165
return String ( cString: & buffer)
134
166
}
135
167
@@ -142,41 +174,69 @@ class _TCPSocket {
142
174
}
143
175
144
176
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
145
184
_ = try data. withUnsafeBytes { ptr in
146
185
try attempt ( " send " , valid: isNotNegative, CInt ( send ( connectionSocket, ptr, data. count, sendFlags) ) )
147
186
}
187
+ #endif
148
188
}
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
+
150
204
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) )
153
206
154
207
if let sendDelay = sendDelay, let bodyChunks = bodyChunks {
155
208
let count = max ( 1 , Int ( Double ( body. utf8. count) / Double( bodyChunks) ) )
156
209
let texts = split ( body, count)
157
210
158
211
for item in texts {
159
212
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) )
162
214
}
163
215
} 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) )
166
217
}
167
218
}
168
219
169
220
func closeClient( ) {
170
221
if let connectionSocket = self . connectionSocket {
222
+ #if os(Windows)
223
+ closesocket ( connectionSocket)
224
+ #else
171
225
close ( connectionSocket)
226
+ #endif
172
227
self . connectionSocket = nil
173
228
}
174
229
}
175
230
176
231
func shutdownListener( ) {
177
232
closeClient ( )
233
+ #if os(Windows)
234
+ shutdown ( listenSocket, SD_BOTH)
235
+ closesocket ( listenSocket)
236
+ #else
178
237
shutdown ( listenSocket, CInt ( SHUT_RDWR) )
179
238
close ( listenSocket)
239
+ #endif
180
240
}
181
241
}
182
242
0 commit comments