Skip to content

Commit 3c244f7

Browse files
committed
Port: Windows fixes
- WinSock doesn’t define the sa_* and in_* types. - in_addr is a union on Windows instead of a scalar. Remove the reliance on that and copy the bytes over instead. - IPPROTO_TCP is imported typed. Shim it as a scalar. - Native socket handles are not the same size as SocketNativeHandle; cast explicitly between the two.
1 parent f2d055c commit 3c244f7

File tree

1 file changed

+30
-12
lines changed

1 file changed

+30
-12
lines changed

Foundation/Port.swift

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,21 @@ fileprivate let INADDR_ANY: in_addr_t = 0
9999
#endif
100100

101101

102-
#if canImport(WinSock)
103-
import WinSock
102+
#if canImport(WinSDK)
103+
import WinSDK
104+
/*
105+
// https://docs.microsoft.com/en-us/windows/win32/api/winsock/ns-winsock-sockaddr_in
106+
typedef struct sockaddr_in {
107+
short sin_family;
108+
u_short sin_port;
109+
struct in_addr sin_addr;
110+
char sin_zero[8];
111+
} SOCKADDR_IN, *PSOCKADDR_IN, *LPSOCKADDR_IN;
112+
*/
113+
fileprivate typealias sa_family_t = ADDRESS_FAMILY
114+
fileprivate typealias in_port_t = USHORT
115+
fileprivate typealias in_addr_t = UInt32
116+
fileprivate let IPPROTO_TCP = Int32(WinSDK.IPPROTO_TCP.rawValue)
104117
#endif
105118

106119
// MARK: Darwin representation of socket addresses
@@ -116,7 +129,7 @@ import WinSock
116129
- swift-corelibs-foundation clients across all platforms can interoperate between themselves and with Darwin as long as all the ports that are sent through SocketPort are AF_INET or AF_INET6;
117130
- otherwise, it is the implementor and deployer's responsibility to make sure all the clients are on the same platform. For sockets that do not leave the machine, like AF_UNIX, this is trivial.
118131

119-
This allows us to special-case sockaddr_in and sockaddr_in6; when we transmit them, we will transmit them in a way that's binary-compatible with Darwin's version of those structure, and then we translate them into whatever version your platform uses, with the one exception that we assume that in6_addr is always representable as 16 contiguous bytes.
132+
This allows us to special-case sockaddr_in and sockaddr_in6; when we transmit them, we will transmit them in a way that's binary-compatible with Darwin's version of those structure, and then we translate them into whatever version your platform uses, with the one exception that we assume that in_addr is always representable as 4 contiguous bytes, and similarly in6_addr as 16 contiguous bytes.
120133

121134
Addresses are internally represented as LocalAddress enum cases; we use DarwinAddress as a type to denote a block of bytes that we type as being a sockaddr produced by Darwin or a Darwin-mimicking source; and the extensions on sockaddr_in and sockaddr_in6 paper over some platform differences and provide translations back and forth into DarwinAddresses for their specific types.
122135

@@ -164,15 +177,17 @@ fileprivate extension sockaddr_in {
164177
self.init(settingLength: ())
165178
self.sin_family = sa_family_t(AF_INET)
166179
self.sin_port = in_port_t(port)
167-
self.sin_addr.s_addr = in_addr_t(inAddr)
180+
withUnsafeMutableBytes(of: &self.sin_addr) { (buffer) in
181+
withUnsafeBytes(of: inAddr) { buffer.copyMemory(from: $0) }
182+
}
168183
}
169184

170185
var darwinAddress: DarwinAddress {
171186
var data = Data()
172187
withUnsafeBytes(of: darwinSockaddrInSize) { data.append(contentsOf: $0) }
173188
withUnsafeBytes(of: darwinAfInet) { data.append(contentsOf: $0) }
174189
withUnsafeBytes(of: UInt16(sin_port)) { data.append(contentsOf: $0) }
175-
withUnsafeBytes(of: UInt32(sin_addr.s_addr)) { data.append(contentsOf: $0) }
190+
withUnsafeBytes(of: sin_addr) { data.append(contentsOf: $0) }
176191

177192
let padding: (Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8) =
178193
(0, 0, 0, 0, 0, 0, 0, 0)
@@ -449,7 +464,9 @@ open class SocketPort : Port {
449464
var address = sockaddr_in(settingLength: ())
450465
address.sin_family = sa_family_t(AF_INET)
451466
address.sin_port = in_port_t(port).bigEndian
452-
address.sin_addr.s_addr = in_addr_t(INADDR_ANY).bigEndian
467+
withUnsafeMutableBytes(of: &address.sin_addr) { (buffer) in
468+
withUnsafeBytes(of: in_addr_t(INADDR_ANY).bigEndian) { buffer.copyMemory(from: $0) }
469+
}
453470

454471
let data = withUnsafeBytes(of: address) { Data($0) }
455472

@@ -489,9 +506,9 @@ open class SocketPort : Port {
489506
context.info = Unmanaged.passUnretained(self).toOpaque()
490507
var s: CFSocket
491508
if type == SOCK_STREAM {
492-
s = CFSocketCreateWithNative(nil, sock, CFOptionFlags(kCFSocketAcceptCallBack), __NSFireSocketAccept, &context)
509+
s = CFSocketCreateWithNative(nil, CFSocketNativeHandle(sock), CFOptionFlags(kCFSocketAcceptCallBack), __NSFireSocketAccept, &context)
493510
} else {
494-
s = CFSocketCreateWithNative(nil, sock, CFOptionFlags(kCFSocketDataCallBack), __NSFireSocketDatagram, &context)
511+
s = CFSocketCreateWithNative(nil, CFSocketNativeHandle(sock), CFOptionFlags(kCFSocketDataCallBack), __NSFireSocketDatagram, &context)
495512
}
496513

497514
createNonuniquedCore(from: s, protocolFamily: family, socketType: type, protocol: `protocol`)
@@ -538,8 +555,9 @@ open class SocketPort : Port {
538555
var sinAddr = sockaddr_in(settingLength: ())
539556
sinAddr.sin_family = sa_family_t(AF_INET)
540557
sinAddr.sin_port = port.bigEndian
541-
sinAddr.sin_addr.s_addr = in_addr_t(INADDR_LOOPBACK).bigEndian
542-
558+
withUnsafeMutableBytes(of: &sinAddr.sin_addr) { (buffer) in
559+
withUnsafeBytes(of: in_addr_t(INADDR_LOOPBACK).bigEndian) { buffer.copyMemory(from: $0) }
560+
}
543561
let data = withUnsafeBytes(of: sinAddr) { Data($0) }
544562
self.init(remoteWithProtocolFamily: PF_INET, socketType: SOCK_STREAM, protocol: IPPROTO_TCP, address: data)
545563
}
@@ -637,7 +655,7 @@ open class SocketPort : Port {
637655
}
638656

639657
open var socket: SocketNativeHandle {
640-
return CFSocketGetNative(core.receiver)
658+
return SocketNativeHandle(CFSocketGetNative(core.receiver))
641659
}
642660

643661
open override func schedule(in runLoop: RunLoop, forMode mode: RunLoop.Mode) {
@@ -720,7 +738,7 @@ open class SocketPort : Port {
720738
var context = CFSocketContext()
721739
context.info = Unmanaged.passUnretained(self).toOpaque()
722740

723-
guard let child = CFSocketCreateWithNative(nil, handle.pointee, CFOptionFlags(kCFSocketDataCallBack), __NSFireSocketData, &context) else {
741+
guard let child = CFSocketCreateWithNative(nil, CFSocketNativeHandle(handle.pointee), CFOptionFlags(kCFSocketDataCallBack), __NSFireSocketData, &context) else {
724742
return
725743
}
726744

0 commit comments

Comments
 (0)