NIO: Implement BSD sockets APIs for Windows (#1471)
Motivation: Split out the internal implied BSD socket API code to allow alternative implementations of these interfaces on other platforms. Modifications: - Split the code apart. - Provide POSIX and Windows implementations of the BSD socket API. Result: Should be easier to run NIO unmodified on Windows.
This commit is contained in:
parent
8aae654645
commit
5de1e41310
|
@ -40,6 +40,7 @@ let package = Package(
|
|||
EOF
|
||||
cp "$here/../../Tests/NIOTests/SystemCallWrapperHelpers.swift" \
|
||||
"$here/../../Sources/NIO/BSDSocketAPI.swift" \
|
||||
"$here/../../Sources/NIO/BSDSocketAPIPosix.swift" \
|
||||
"$here/../../Sources/NIO/System.swift" \
|
||||
"$here/../../Sources/NIO/IO.swift" \
|
||||
"$tmpdir/syscallwrapper/Sources/syscallwrapper"
|
||||
|
|
|
@ -26,6 +26,39 @@ typedef struct {
|
|||
unsigned int msg_len;
|
||||
} NIO(mmsghdr);
|
||||
|
||||
static inline __attribute__((__always_inline__)) int
|
||||
NIO(getsockopt)(SOCKET s, int level, int optname, void *optval, int *optlen) {
|
||||
return getsockopt(s, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
static inline __attribute__((__always_inline__)) int
|
||||
NIO(recv)(SOCKET s, void *buf, int len, int flags) {
|
||||
return recv(s, buf, len, flags);
|
||||
}
|
||||
|
||||
static inline __attribute__((__always_inline__)) int
|
||||
NIO(recvfrom)(SOCKET s, void *buf, int len, int flags, SOCKADDR *from,
|
||||
int *fromlen) {
|
||||
return recvfrom(s, buf, len, flags, from, fromlen);
|
||||
}
|
||||
|
||||
static inline __attribute__((__always_inline__)) int
|
||||
NIO(send)(SOCKET s, const void *buf, int len, int flags) {
|
||||
return send(s, buf, len, flags);
|
||||
}
|
||||
|
||||
static inline __attribute__((__always_inline__)) int
|
||||
NIO(setsockopt)(SOCKET s, int level, int optname, const void *optval,
|
||||
int optlen) {
|
||||
return setsockopt(s, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
static inline __attribute__((__always_inline__)) int
|
||||
NIO(sendto)(SOCKET s, const void *buf, int len, int flags, const SOCKADDR *to,
|
||||
int tolen) {
|
||||
return sendto(s, buf, len, flags, to, tolen);
|
||||
}
|
||||
|
||||
#undef NIO
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//
|
||||
// This source file is part of the SwiftNIO open source project
|
||||
//
|
||||
// Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors
|
||||
// Copyright (c) 2020 Apple Inc. and the SwiftNIO project authors
|
||||
// Licensed under Apache License v2.0
|
||||
//
|
||||
// See LICENSE.txt for license information
|
||||
|
@ -12,53 +12,22 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if os(Windows)
|
||||
import let WinSDK.AF_INET
|
||||
import let WinSDK.AF_INET6
|
||||
import let WinSDK.AF_UNIX
|
||||
protocol _SocketShutdownProtocol {
|
||||
var cValue: CInt { get }
|
||||
}
|
||||
|
||||
import let WinSDK.IPPROTO_IP
|
||||
import let WinSDK.IPPROTO_IPV6
|
||||
import let WinSDK.IPPROTO_TCP
|
||||
|
||||
import let WinSDK.IP_ADD_MEMBERSHIP
|
||||
import let WinSDK.IP_DROP_MEMBERSHIP
|
||||
import let WinSDK.IP_MULTICAST_IF
|
||||
import let WinSDK.IP_MULTICAST_LOOP
|
||||
import let WinSDK.IP_MULTICAST_TTL
|
||||
|
||||
import let WinSDK.IPV6_JOIN_GROUP
|
||||
import let WinSDK.IPV6_LEAVE_GROUP
|
||||
import let WinSDK.IPV6_MULTICAST_HOPS
|
||||
import let WinSDK.IPV6_MULTICAST_IF
|
||||
import let WinSDK.IPV6_MULTICAST_LOOP
|
||||
import let WinSDK.IPV6_V6ONLY
|
||||
|
||||
import let WinSDK.PF_INET
|
||||
import let WinSDK.PF_INET6
|
||||
import let WinSDK.PF_UNIX
|
||||
|
||||
import let WinSDK.TCP_NODELAY
|
||||
|
||||
import let WinSDK.SO_ERROR
|
||||
import let WinSDK.SO_KEEPALIVE
|
||||
import let WinSDK.SO_LINGER
|
||||
import let WinSDK.SO_RCVBUF
|
||||
import let WinSDK.SO_RCVTIMEO
|
||||
import let WinSDK.SO_REUSEADDR
|
||||
import let WinSDK.SO_REUSE_UNICASTPORT
|
||||
|
||||
import let WinSDK.SOL_SOCKET
|
||||
|
||||
import let WinSDK.SOCK_DGRAM
|
||||
import let WinSDK.SOCK_STREAM
|
||||
#elseif os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
|
||||
import Darwin
|
||||
#else
|
||||
import Glibc
|
||||
#endif
|
||||
internal enum Shutdown: _SocketShutdownProtocol {
|
||||
case RD
|
||||
case WR
|
||||
case RDWR
|
||||
}
|
||||
|
||||
public enum NIOBSDSocket {
|
||||
#if os(Windows)
|
||||
public typealias Handle = SOCKET
|
||||
#else
|
||||
public typealias Handle = CInt
|
||||
#endif
|
||||
}
|
||||
|
||||
extension NIOBSDSocket {
|
||||
|
@ -367,3 +336,124 @@ extension NIOBSDSocket.Option {
|
|||
NIOBSDSocket.Option(rawValue: SO_TIMESTAMP)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/// This protocol defines the methods that are expected to be found on `NIOBSDSocket`. While defined as a protocol
|
||||
/// there is no expectation that any object other than `NIOBSDSocket` will implement this protocol: instead, this protocol
|
||||
/// acts as a reference for what new supported operating systems must implement.
|
||||
protocol _BSDSocketProtocol {
|
||||
static func accept(socket s: NIOBSDSocket.Handle,
|
||||
address addr: UnsafeMutablePointer<sockaddr>?,
|
||||
address_len addrlen: UnsafeMutablePointer<socklen_t>?) throws -> NIOBSDSocket.Handle?
|
||||
|
||||
static func bind(socket s: NIOBSDSocket.Handle,
|
||||
address addr: UnsafePointer<sockaddr>,
|
||||
address_len namelen: socklen_t) throws
|
||||
|
||||
static func close(socket s: NIOBSDSocket.Handle) throws
|
||||
|
||||
static func connect(socket s: NIOBSDSocket.Handle,
|
||||
address name: UnsafePointer<sockaddr>,
|
||||
address_len namelen: socklen_t) throws -> Bool
|
||||
|
||||
static func getpeername(socket s: NIOBSDSocket.Handle,
|
||||
address name: UnsafeMutablePointer<sockaddr>,
|
||||
address_len namelen: UnsafeMutablePointer<socklen_t>) throws
|
||||
|
||||
static func getsockname(socket s: NIOBSDSocket.Handle,
|
||||
address name: UnsafeMutablePointer<sockaddr>,
|
||||
address_len namelen: UnsafeMutablePointer<socklen_t>) throws
|
||||
|
||||
static func getsockopt(socket: NIOBSDSocket.Handle,
|
||||
level: NIOBSDSocket.OptionLevel,
|
||||
option_name optname: NIOBSDSocket.Option,
|
||||
option_value optval: UnsafeMutableRawPointer,
|
||||
option_len optlen: UnsafeMutablePointer<socklen_t>) throws
|
||||
|
||||
static func listen(socket s: NIOBSDSocket.Handle, backlog: CInt) throws
|
||||
|
||||
static func recv(socket s: NIOBSDSocket.Handle,
|
||||
buffer buf: UnsafeMutableRawPointer,
|
||||
length len: size_t) throws -> IOResult<size_t>
|
||||
|
||||
static func recvfrom(socket s: NIOBSDSocket.Handle,
|
||||
buffer buf: UnsafeMutableRawPointer,
|
||||
length len: size_t,
|
||||
address from: UnsafeMutablePointer<sockaddr>,
|
||||
address_len fromlen: UnsafeMutablePointer<socklen_t>) throws -> IOResult<size_t>
|
||||
|
||||
static func send(socket s: NIOBSDSocket.Handle,
|
||||
buffer buf: UnsafeRawPointer,
|
||||
length len: size_t) throws -> IOResult<size_t>
|
||||
|
||||
static func setsockopt(socket: NIOBSDSocket.Handle,
|
||||
level: NIOBSDSocket.OptionLevel,
|
||||
option_name optname: NIOBSDSocket.Option,
|
||||
option_value optval: UnsafeRawPointer,
|
||||
option_len optlen: socklen_t) throws
|
||||
|
||||
// NOTE: this should return a `ssize_t`, however, that is not a standard
|
||||
// type, and defining that type is difficult. Opt to return a `size_t`
|
||||
// which is the same size, but is unsigned.
|
||||
static func sendto(socket s: NIOBSDSocket.Handle,
|
||||
buffer buf: UnsafeRawPointer,
|
||||
length len: size_t,
|
||||
dest_addr to: UnsafePointer<sockaddr>,
|
||||
dest_len tolen: socklen_t) throws -> IOResult<size_t>
|
||||
|
||||
static func shutdown(socket: NIOBSDSocket.Handle, how: Shutdown) throws
|
||||
|
||||
static func socket(domain af: NIOBSDSocket.ProtocolFamily,
|
||||
type: NIOBSDSocket.SocketType,
|
||||
`protocol`: CInt) throws -> NIOBSDSocket.Handle
|
||||
|
||||
static func recvmmsg(socket: NIOBSDSocket.Handle,
|
||||
msgvec: UnsafeMutablePointer<MMsgHdr>,
|
||||
vlen: CUnsignedInt,
|
||||
flags: CInt,
|
||||
timeout: UnsafeMutablePointer<timespec>?) throws -> IOResult<Int>
|
||||
|
||||
static func sendmmsg(socket: NIOBSDSocket.Handle,
|
||||
msgvec: UnsafeMutablePointer<MMsgHdr>,
|
||||
vlen: CUnsignedInt,
|
||||
flags: CInt) throws -> IOResult<Int>
|
||||
|
||||
// NOTE: this should return a `ssize_t`, however, that is not a standard
|
||||
// type, and defining that type is difficult. Opt to return a `size_t`
|
||||
// which is the same size, but is unsigned.
|
||||
static func pread(socket: NIOBSDSocket.Handle,
|
||||
pointer: UnsafeMutableRawPointer,
|
||||
size: size_t,
|
||||
offset: off_t) throws -> IOResult<size_t>
|
||||
|
||||
// NOTE: this should return a `ssize_t`, however, that is not a standard
|
||||
// type, and defining that type is difficult. Opt to return a `size_t`
|
||||
// which is the same size, but is unsigned.
|
||||
static func pwrite(socket: NIOBSDSocket.Handle,
|
||||
pointer: UnsafeRawPointer,
|
||||
size: size_t,
|
||||
offset: off_t) throws -> IOResult<size_t>
|
||||
|
||||
static func poll(fds: UnsafeMutablePointer<pollfd>,
|
||||
nfds: nfds_t,
|
||||
timeout: CInt) throws -> CInt
|
||||
|
||||
static func inet_ntop(af family: NIOBSDSocket.AddressFamily,
|
||||
src addr: UnsafeRawPointer,
|
||||
dst dstBuf: UnsafeMutablePointer<CChar>,
|
||||
size dstSize: socklen_t) throws -> UnsafePointer<CChar>?
|
||||
|
||||
static func inet_pton(af family: NIOBSDSocket.AddressFamily,
|
||||
src description: UnsafePointer<CChar>,
|
||||
dst address: UnsafeMutableRawPointer) throws
|
||||
|
||||
static func sendfile(socket s: NIOBSDSocket.Handle,
|
||||
fd: CInt,
|
||||
offset: off_t,
|
||||
len: off_t) throws -> IOResult<Int>
|
||||
|
||||
static func setNonBlocking(socket: NIOBSDSocket.Handle) throws
|
||||
}
|
||||
|
||||
/// If this extension is hitting a compile error, your platform is missing one of the functions defined above!
|
||||
extension NIOBSDSocket: _BSDSocketProtocol { }
|
||||
|
|
|
@ -0,0 +1,224 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the SwiftNIO open source project
|
||||
//
|
||||
// Copyright (c) 2020 Apple Inc. and the SwiftNIO project authors
|
||||
// Licensed under Apache License v2.0
|
||||
//
|
||||
// See LICENSE.txt for license information
|
||||
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#if os(Linux) || os(Android) || os(FreeBSD) || os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
|
||||
|
||||
extension Shutdown {
|
||||
internal var cValue: CInt {
|
||||
switch self {
|
||||
case .RD:
|
||||
return CInt(Posix.SHUT_RD)
|
||||
case .WR:
|
||||
return CInt(Posix.SHUT_WR)
|
||||
case .RDWR:
|
||||
return CInt(Posix.SHUT_RDWR)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Implementation of _BSDSocketProtocol for POSIX systems
|
||||
extension NIOBSDSocket {
|
||||
static func accept(socket s: NIOBSDSocket.Handle,
|
||||
address addr: UnsafeMutablePointer<sockaddr>?,
|
||||
address_len addrlen: UnsafeMutablePointer<socklen_t>?) throws -> NIOBSDSocket.Handle? {
|
||||
return try Posix.accept(descriptor: s, addr: addr, len: addrlen)
|
||||
}
|
||||
|
||||
static func bind(socket s: NIOBSDSocket.Handle,
|
||||
address addr: UnsafePointer<sockaddr>,
|
||||
address_len namelen: socklen_t) throws {
|
||||
return try Posix.bind(descriptor: s, ptr: addr, bytes: Int(namelen))
|
||||
}
|
||||
|
||||
static func close(socket s: NIOBSDSocket.Handle) throws {
|
||||
return try Posix.close(descriptor: s)
|
||||
}
|
||||
|
||||
static func connect(socket s: NIOBSDSocket.Handle,
|
||||
address name: UnsafePointer<sockaddr>,
|
||||
address_len namelen: socklen_t) throws -> Bool {
|
||||
return try Posix.connect(descriptor: s, addr: name, size: namelen)
|
||||
}
|
||||
|
||||
static func getpeername(socket s: NIOBSDSocket.Handle,
|
||||
address name: UnsafeMutablePointer<sockaddr>,
|
||||
address_len namelen: UnsafeMutablePointer<socklen_t>) throws {
|
||||
return try Posix.getpeername(socket: s, address: name, addressLength: namelen)
|
||||
}
|
||||
|
||||
static func getsockname(socket s: NIOBSDSocket.Handle,
|
||||
address name: UnsafeMutablePointer<sockaddr>,
|
||||
address_len namelen: UnsafeMutablePointer<socklen_t>) throws {
|
||||
return try Posix.getsockname(socket: s, address: name, addressLength: namelen)
|
||||
}
|
||||
|
||||
static func getsockopt(socket: NIOBSDSocket.Handle,
|
||||
level: NIOBSDSocket.OptionLevel,
|
||||
option_name optname: NIOBSDSocket.Option,
|
||||
option_value optval: UnsafeMutableRawPointer,
|
||||
option_len optlen: UnsafeMutablePointer<socklen_t>) throws {
|
||||
return try Posix.getsockopt(socket: socket,
|
||||
level: level.rawValue,
|
||||
optionName: optname.rawValue,
|
||||
optionValue: optval,
|
||||
optionLen: optlen)
|
||||
}
|
||||
|
||||
static func listen(socket s: NIOBSDSocket.Handle, backlog: CInt) throws {
|
||||
return try Posix.listen(descriptor: s, backlog: backlog)
|
||||
}
|
||||
|
||||
static func recv(socket s: NIOBSDSocket.Handle,
|
||||
buffer buf: UnsafeMutableRawPointer,
|
||||
length len: size_t) throws -> IOResult<size_t> {
|
||||
return try Posix.read(descriptor: s, pointer: buf, size: len)
|
||||
}
|
||||
|
||||
static func recvfrom(socket s: NIOBSDSocket.Handle,
|
||||
buffer buf: UnsafeMutableRawPointer,
|
||||
length len: size_t,
|
||||
address from: UnsafeMutablePointer<sockaddr>,
|
||||
address_len fromlen: UnsafeMutablePointer<socklen_t>) throws -> IOResult<size_t> {
|
||||
return try Posix.recvfrom(descriptor: s,
|
||||
pointer: buf,
|
||||
len: len,
|
||||
addr: from,
|
||||
addrlen: fromlen)
|
||||
}
|
||||
|
||||
static func send(socket s: NIOBSDSocket.Handle,
|
||||
buffer buf: UnsafeRawPointer,
|
||||
length len: size_t) throws -> IOResult<size_t> {
|
||||
return try Posix.write(descriptor: s, pointer: buf, size: len)
|
||||
}
|
||||
|
||||
static func setsockopt(socket: NIOBSDSocket.Handle,
|
||||
level: NIOBSDSocket.OptionLevel,
|
||||
option_name optname: NIOBSDSocket.Option,
|
||||
option_value optval: UnsafeRawPointer,
|
||||
option_len optlen: socklen_t) throws {
|
||||
return try Posix.setsockopt(socket: socket,
|
||||
level: level.rawValue,
|
||||
optionName: optname.rawValue,
|
||||
optionValue: optval,
|
||||
optionLen: optlen)
|
||||
}
|
||||
|
||||
// NOTE: this should return a `ssize_t`, however, that is not a standard
|
||||
// type, and defining that type is difficult. Opt to return a `size_t`
|
||||
// which is the same size, but is unsigned.
|
||||
static func sendto(socket s: NIOBSDSocket.Handle,
|
||||
buffer buf: UnsafeRawPointer,
|
||||
length len: size_t,
|
||||
dest_addr to: UnsafePointer<sockaddr>,
|
||||
dest_len tolen: socklen_t) throws -> IOResult<size_t> {
|
||||
return try Posix.sendto(descriptor: s,
|
||||
pointer: buf,
|
||||
size: len,
|
||||
destinationPtr: to,
|
||||
destinationSize: tolen)
|
||||
}
|
||||
|
||||
static func shutdown(socket: NIOBSDSocket.Handle, how: Shutdown) throws {
|
||||
return try Posix.shutdown(descriptor: socket, how: how)
|
||||
}
|
||||
|
||||
static func socket(domain af: NIOBSDSocket.ProtocolFamily,
|
||||
type: NIOBSDSocket.SocketType,
|
||||
`protocol`: CInt) throws -> NIOBSDSocket.Handle {
|
||||
return try Posix.socket(domain: af, type: type, protocol: `protocol`)
|
||||
}
|
||||
|
||||
static func recvmmsg(socket: NIOBSDSocket.Handle,
|
||||
msgvec: UnsafeMutablePointer<MMsgHdr>,
|
||||
vlen: CUnsignedInt,
|
||||
flags: CInt,
|
||||
timeout: UnsafeMutablePointer<timespec>?) throws -> IOResult<Int> {
|
||||
return try Posix.recvmmsg(sockfd: socket,
|
||||
msgvec: msgvec,
|
||||
vlen: vlen,
|
||||
flags: flags,
|
||||
timeout: timeout)
|
||||
}
|
||||
|
||||
static func sendmmsg(socket: NIOBSDSocket.Handle,
|
||||
msgvec: UnsafeMutablePointer<MMsgHdr>,
|
||||
vlen: CUnsignedInt,
|
||||
flags: CInt) throws -> IOResult<Int> {
|
||||
return try Posix.sendmmsg(sockfd: socket,
|
||||
msgvec: msgvec,
|
||||
vlen: vlen,
|
||||
flags: flags)
|
||||
}
|
||||
|
||||
// NOTE: this should return a `ssize_t`, however, that is not a standard
|
||||
// type, and defining that type is difficult. Opt to return a `size_t`
|
||||
// which is the same size, but is unsigned.
|
||||
static func pread(socket: NIOBSDSocket.Handle,
|
||||
pointer: UnsafeMutableRawPointer,
|
||||
size: size_t,
|
||||
offset: off_t) throws -> IOResult<size_t> {
|
||||
return try Posix.pread(descriptor: socket,
|
||||
pointer: pointer,
|
||||
size: size,
|
||||
offset: offset)
|
||||
}
|
||||
|
||||
// NOTE: this should return a `ssize_t`, however, that is not a standard
|
||||
// type, and defining that type is difficult. Opt to return a `size_t`
|
||||
// which is the same size, but is unsigned.
|
||||
static func pwrite(socket: NIOBSDSocket.Handle,
|
||||
pointer: UnsafeRawPointer,
|
||||
size: size_t,
|
||||
offset: off_t) throws -> IOResult<size_t> {
|
||||
return try Posix.pwrite(descriptor: socket, pointer: pointer, size: size, offset: offset)
|
||||
}
|
||||
|
||||
static func poll(fds: UnsafeMutablePointer<pollfd>,
|
||||
nfds: nfds_t,
|
||||
timeout: CInt) throws -> CInt {
|
||||
return try Posix.poll(fds: fds, nfds: nfds, timeout: timeout)
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
static func inet_ntop(af family: NIOBSDSocket.AddressFamily,
|
||||
src addr: UnsafeRawPointer,
|
||||
dst dstBuf: UnsafeMutablePointer<CChar>,
|
||||
size dstSize: socklen_t) throws -> UnsafePointer<CChar>? {
|
||||
return try Posix.inet_ntop(addressFamily: sa_family_t(family.rawValue),
|
||||
addressBytes: addr,
|
||||
addressDescription: dstBuf,
|
||||
addressDescriptionLength: dstSize)
|
||||
}
|
||||
|
||||
static func inet_pton(af family: NIOBSDSocket.AddressFamily,
|
||||
src description: UnsafePointer<CChar>,
|
||||
dst address: UnsafeMutableRawPointer) throws {
|
||||
return try Posix.inet_pton(addressFamily: sa_family_t(family.rawValue),
|
||||
addressDescription: description,
|
||||
address: address)
|
||||
}
|
||||
|
||||
static func sendfile(socket s: NIOBSDSocket.Handle,
|
||||
fd: CInt,
|
||||
offset: off_t,
|
||||
len: off_t) throws -> IOResult<Int> {
|
||||
return try Posix.sendfile(descriptor: s, fd: fd, offset: offset, count: size_t(len))
|
||||
}
|
||||
|
||||
static func setNonBlocking(socket: NIOBSDSocket.Handle) throws {
|
||||
return try Posix.setNonBlocking(socket: socket)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,360 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the SwiftNIO open source project
|
||||
//
|
||||
// Copyright (c) 2020 Apple Inc. and the SwiftNIO project authors
|
||||
// Licensed under Apache License v2.0
|
||||
//
|
||||
// See LICENSE.txt for license information
|
||||
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#if os(Windows)
|
||||
import ucrt
|
||||
|
||||
import let WinSDK.AF_INET
|
||||
import let WinSDK.AF_INET6
|
||||
import let WinSDK.AF_UNIX
|
||||
|
||||
import let WinSDK.IPPROTO_IP
|
||||
import let WinSDK.IPPROTO_IPV6
|
||||
import let WinSDK.IPPROTO_TCP
|
||||
|
||||
import let WinSDK.IP_ADD_MEMBERSHIP
|
||||
import let WinSDK.IP_DROP_MEMBERSHIP
|
||||
import let WinSDK.IP_MULTICAST_IF
|
||||
import let WinSDK.IP_MULTICAST_LOOP
|
||||
import let WinSDK.IP_MULTICAST_TTL
|
||||
|
||||
import let WinSDK.IPV6_JOIN_GROUP
|
||||
import let WinSDK.IPV6_LEAVE_GROUP
|
||||
import let WinSDK.IPV6_MULTICAST_HOPS
|
||||
import let WinSDK.IPV6_MULTICAST_IF
|
||||
import let WinSDK.IPV6_MULTICAST_LOOP
|
||||
import let WinSDK.IPV6_V6ONLY
|
||||
|
||||
import let WinSDK.PF_INET
|
||||
import let WinSDK.PF_INET6
|
||||
import let WinSDK.PF_UNIX
|
||||
|
||||
import let WinSDK.TCP_NODELAY
|
||||
|
||||
import let WinSDK.SO_ERROR
|
||||
import let WinSDK.SO_KEEPALIVE
|
||||
import let WinSDK.SO_LINGER
|
||||
import let WinSDK.SO_RCVBUF
|
||||
import let WinSDK.SO_RCVTIMEO
|
||||
import let WinSDK.SO_REUSEADDR
|
||||
import let WinSDK.SO_REUSE_UNICASTPORT
|
||||
|
||||
import let WinSDK.SOL_SOCKET
|
||||
|
||||
import let WinSDK.SOCK_DGRAM
|
||||
import let WinSDK.SOCK_STREAM
|
||||
|
||||
import let WinSDK.SOCKET_ERROR
|
||||
|
||||
import func WinSDK.WSAGetLastError
|
||||
|
||||
import struct WinSDK.socklen_t
|
||||
import struct WinSDK.SOCKADDR
|
||||
|
||||
|
||||
extension Shutdown {
|
||||
internal var cValue: CInt {
|
||||
switch self {
|
||||
case .RD:
|
||||
return WinSDK.SD_RECEIVE
|
||||
case .WR:
|
||||
return WinSDK.SD_SEND
|
||||
case .RDWR:
|
||||
return WinSDK.SD_BOTH
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: _BSDSocketProtocol implementation
|
||||
extension NIOBSDSocket {
|
||||
@inline(never)
|
||||
static func accept(socket s: NIOBSDSocket.Handle,
|
||||
address addr: UnsafeMutablePointer<sockaddr>?,
|
||||
address_len addrlen: UnsafeMutablePointer<socklen_t>?) throws -> NIOBSDSocket.Handle? {
|
||||
let socket: NIOBSDSocket.Handle = WinSDK.accept(s, addr, addrlen)
|
||||
if socket == WinSDK.INVALID_SOCKET {
|
||||
throw IOError(winsock: WSAGetLastError(), reason: "accept")
|
||||
}
|
||||
return socket
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
static func bind(socket s: NIOBSDSocket.Handle,
|
||||
address addr: UnsafePointer<sockaddr>,
|
||||
address_len namelen: socklen_t) throws {
|
||||
if WinSDK.bind(s, addr, namelen) == SOCKET_ERROR {
|
||||
throw IOError(winsock: WSAGetLastError(), reason: "bind")
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
static func close(socket s: NIOBSDSocket.Handle) throws {
|
||||
try Posix.close(descriptor: s)
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
static func connect(socket s: NIOBSDSocket.Handle,
|
||||
address name: UnsafePointer<sockaddr>,
|
||||
address_len namelen: socklen_t) throws -> Bool {
|
||||
if WinSDK.connect(s, name, namelen) == SOCKET_ERROR {
|
||||
throw IOError(winsock: WSAGetLastError(), reason: "connect")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
static func getpeername(socket s: NIOBSDSocket.Handle,
|
||||
address name: UnsafeMutablePointer<sockaddr>,
|
||||
address_len namelen: UnsafeMutablePointer<socklen_t>) throws {
|
||||
if WinSDK.getpeername(s, name, namelen) == SOCKET_ERROR {
|
||||
throw IOError(winsock: WSAGetLastError(), reason: "getpeername")
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
static func getsockname(socket s: NIOBSDSocket.Handle,
|
||||
address name: UnsafeMutablePointer<sockaddr>,
|
||||
address_len namelen: UnsafeMutablePointer<socklen_t>) throws {
|
||||
if WinSDK.getsockname(s, name, namelen) == SOCKET_ERROR {
|
||||
throw IOError(winsock: WSAGetLastError(), reason: "getsockname")
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
static func getsockopt(socket: NIOBSDSocket.Handle,
|
||||
level: NIOBSDSocket.OptionLevel,
|
||||
option_name optname: NIOBSDSocket.Option,
|
||||
option_value optval: UnsafeMutableRawPointer,
|
||||
option_len optlen: UnsafeMutablePointer<socklen_t>) throws {
|
||||
if CNIOWindows_getsockopt(socket, level.rawValue, optname.rawValue,
|
||||
optval, optlen) == SOCKET_ERROR {
|
||||
throw IOError(winsock: WSAGetLastError(), reason: "getsockopt")
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
static func listen(socket s: NIOBSDSocket.Handle, backlog: CInt) throws {
|
||||
if WinSDK.listen(s, backlog) == SOCKET_ERROR {
|
||||
throw IOError(winsock: WSAGetLastError(), reason: "listen")
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
static func recv(socket s: NIOBSDSocket.Handle,
|
||||
buffer buf: UnsafeMutableRawPointer,
|
||||
length len: size_t) throws -> IOResult<size_t> {
|
||||
let iResult: CInt = CNIOWindows_recv(s, buf, CInt(len), 0)
|
||||
if iResult == SOCKET_ERROR {
|
||||
throw IOError(winsock: WSAGetLastError(), reason: "recv")
|
||||
}
|
||||
return .processed(size_t(iResult))
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
static func recvfrom(socket s: NIOBSDSocket.Handle,
|
||||
buffer buf: UnsafeMutableRawPointer,
|
||||
length len: size_t,
|
||||
address from: UnsafeMutablePointer<sockaddr>,
|
||||
address_len fromlen: UnsafeMutablePointer<socklen_t>) throws -> IOResult<size_t> {
|
||||
let iResult: CInt = CNIOWindows_recvfrom(s, buf, CInt(len), 0, from, fromlen)
|
||||
if iResult == SOCKET_ERROR {
|
||||
throw IOError(winsock: WSAGetLastError(), reason: "recvfrom")
|
||||
}
|
||||
return .processed(size_t(iResult))
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
static func send(socket s: NIOBSDSocket.Handle,
|
||||
buffer buf: UnsafeRawPointer,
|
||||
length len: size_t) throws -> IOResult<size_t> {
|
||||
let iResult: CInt = CNIOWindows_send(s, buf, CInt(len), 0)
|
||||
if iResult == SOCKET_ERROR {
|
||||
throw IOError(winsock: WSAGetLastError(), reason: "send")
|
||||
}
|
||||
return .processed(size_t(iResult))
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
static func setsockopt(socket: NIOBSDSocket.Handle,
|
||||
level: NIOBSDSocket.OptionLevel,
|
||||
option_name optname: NIOBSDSocket.Option,
|
||||
option_value optval: UnsafeRawPointer,
|
||||
option_len optlen: socklen_t) throws {
|
||||
if CNIOWindows_setsockopt(socket, level.rawValue, optname.rawValue,
|
||||
optval, optlen) == SOCKET_ERROR {
|
||||
throw IOError(winsock: WSAGetLastError(), reason: "setsockopt")
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this should return a `ssize_t`, however, that is not a standard
|
||||
// type, and defining that type is difficult. Opt to return a `size_t`
|
||||
// which is the same size, but is unsigned.
|
||||
@inline(never)
|
||||
static func sendto(socket s: NIOBSDSocket.Handle,
|
||||
buffer buf: UnsafeRawPointer,
|
||||
length len: size_t,
|
||||
dest_addr to: UnsafePointer<sockaddr>,
|
||||
dest_len tolen: socklen_t) throws -> IOResult<size_t> {
|
||||
let iResult: CInt = CNIOWindows_sendto(s, buf, CInt(len), 0, to, tolen)
|
||||
if iResult == SOCKET_ERROR {
|
||||
throw IOError(winsock: WSAGetLastError(), reason: "sendto")
|
||||
}
|
||||
return .processed(size_t(iResult))
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
static func shutdown(socket: NIOBSDSocket.Handle, how: Shutdown) throws {
|
||||
if WinSDK.shutdown(socket, how.cValue) == SOCKET_ERROR {
|
||||
throw IOError(winsock: WSAGetLastError(), reason: "shutdown")
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
static func socket(domain af: NIOBSDSocket.ProtocolFamily,
|
||||
type: NIOBSDSocket.SocketType,
|
||||
`protocol`: CInt) throws -> NIOBSDSocket.Handle {
|
||||
let socket: NIOBSDSocket.Handle = WinSDK.socket(af.rawValue, type.rawValue, `protocol`)
|
||||
if socket == WinSDK.INVALID_SOCKET {
|
||||
throw IOError(winsock: WSAGetLastError(), reason: "socket")
|
||||
}
|
||||
return socket
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
static func recvmmsg(socket: NIOBSDSocket.Handle,
|
||||
msgvec: UnsafeMutablePointer<MMsgHdr>,
|
||||
vlen: CUnsignedInt,
|
||||
flags: CInt,
|
||||
timeout: UnsafeMutablePointer<timespec>?) throws -> IOResult<Int> {
|
||||
return try Posix.recvmmsg(sockfd: socket,
|
||||
msgvec: msgvec,
|
||||
vlen: vlen,
|
||||
flags: flags,
|
||||
timeout: timeout)
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
static func sendmmsg(socket: NIOBSDSocket.Handle,
|
||||
msgvec: UnsafeMutablePointer<MMsgHdr>,
|
||||
vlen: CUnsignedInt,
|
||||
flags: CInt) throws -> IOResult<Int> {
|
||||
return try Posix.sendmmsg(sockfd: socket,
|
||||
msgvec: msgvec,
|
||||
vlen: vlen,
|
||||
flags: flags)
|
||||
}
|
||||
|
||||
// NOTE: this should return a `ssize_t`, however, that is not a standard
|
||||
// type, and defining that type is difficult. Opt to return a `size_t`
|
||||
// which is the same size, but is unsigned.
|
||||
@inline(never)
|
||||
static func pread(socket: NIOBSDSocket.Handle,
|
||||
pointer: UnsafeMutableRawPointer,
|
||||
size: size_t,
|
||||
offset: off_t) throws -> IOResult<size_t> {
|
||||
var ovlOverlapped: OVERLAPPED = OVERLAPPED()
|
||||
ovlOverlapped.OffsetHigh = DWORD(UInt32(offset >> 32) & 0xffffffff)
|
||||
ovlOverlapped.Offset = DWORD(UInt32(offset >> 0) & 0xffffffff)
|
||||
var nNumberOfBytesRead: DWORD = 0
|
||||
if !ReadFile(HANDLE(bitPattern: UInt(socket)), pointer, DWORD(size),
|
||||
&nNumberOfBytesRead, &ovlOverlapped) {
|
||||
throw IOError(windows: GetLastError(), reason: "ReadFile")
|
||||
}
|
||||
return .processed(CInt(nNumberOfBytesRead))
|
||||
}
|
||||
|
||||
// NOTE: this should return a `ssize_t`, however, that is not a standard
|
||||
// type, and defining that type is difficult. Opt to return a `size_t`
|
||||
// which is the same size, but is unsigned.
|
||||
@inline(never)
|
||||
static func pwrite(socket: NIOBSDSocket.Handle,
|
||||
pointer: UnsafeRawPointer,
|
||||
size: size_t,
|
||||
offset: off_t) throws -> IOResult<size_t> {
|
||||
var ovlOverlapped: OVERLAPPED = OVERLAPPED()
|
||||
ovlOverlapped.OffsetHigh = DWORD(UInt32(offset >> 32) & 0xffffffff)
|
||||
ovlOverlapped.Offset = DWORD(UInt32(offset >> 0) & 0xffffffff)
|
||||
var nNumberOfBytesWritten: DWORD = 0
|
||||
if !WriteFile(HANDLE(bitPattern: UInt(socket)), pointer, DWORD(size),
|
||||
&nNumberOfBytesWritten, &ovlOverlapped) {
|
||||
throw IOError(windows: GetLastError(), reason: "WriteFile")
|
||||
}
|
||||
return .processed(CInt(nNumberOfBytesWritten))
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
static func poll(fds: UnsafeMutablePointer<pollfd>,
|
||||
nfds: nfds_t,
|
||||
timeout: CInt) throws -> CInt {
|
||||
fatalError("Poll unsupported on Windows")
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
@inline(never)
|
||||
static func inet_ntop(af family: NIOBSDSocket.AddressFamily,
|
||||
src addr: UnsafeRawPointer,
|
||||
dst dstBuf: UnsafeMutablePointer<CChar>,
|
||||
size dstSize: socklen_t) throws -> UnsafePointer<CChar>? {
|
||||
// TODO(compnerd) use `InetNtopW` to ensure that we handle unicode properly
|
||||
guard let result = WinSDK.inet_ntop(family.rawValue, addr, dstBuf,
|
||||
Int(dstSize)) else {
|
||||
throw IOError(windows: GetLastError(), reason: "inet_ntop")
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
@inline(never)
|
||||
static func inet_pton(af family: NIOBSDSocket.AddressFamily,
|
||||
src description: UnsafePointer<CChar>,
|
||||
dst address: UnsafeMutableRawPointer) throws {
|
||||
// TODO(compnerd) use `InetPtonW` to ensure that we handle unicode properly
|
||||
switch WinSDK.inet_pton(family.rawValue, description, address) {
|
||||
case 0: throw IOError(errnoCode: EINVAL, reason: "inet_pton")
|
||||
case 1: return
|
||||
default: throw IOError(winsock: WSAGetLastError(), reason: "inet_pton")
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
static func sendfile(socket s: NIOBSDSocket.Handle,
|
||||
fd: CInt,
|
||||
offset: off_t,
|
||||
len: off_t) throws -> IOResult<Int> {
|
||||
let hFile: HANDLE = HANDLE(bitPattern: ucrt._get_osfhandle(fd))!
|
||||
if hFile == INVALID_HANDLE_VALUE {
|
||||
throw IOError(errnoCode: EBADF, reason: "_get_osfhandle")
|
||||
}
|
||||
|
||||
var ovlOverlapped: OVERLAPPED = OVERLAPPED()
|
||||
ovlOverlapped.Offset = DWORD(UInt32(offset >> 0) & 0xffffffff)
|
||||
ovlOverlapped.OffsetHigh = DWORD(UInt32(offset >> 32) & 0xffffffff)
|
||||
if !TransmitFile(s, hFile, DWORD(nNumberOfBytesToWrite), 0,
|
||||
&ovlOverlapped, nil, DWORD(TF_USE_KERNEL_APC)) {
|
||||
throw IOError(winsock: WSAGetLastError(), reason: "TransmitFile")
|
||||
}
|
||||
|
||||
return .processed(Int(nNumberOfBytesToWrite))
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
static func setNonBlocking(socket: NIOBSDSocket.Handle) throws {
|
||||
var ulMode: u_long = 1
|
||||
if WinSDK.ioctlsocket(socket, FIONBIO, &ulMode) == SOCKET_ERROR {
|
||||
throw IOError(winsock: WSAGetLastError(), reason: "ioctlsocket")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -14,6 +14,10 @@
|
|||
|
||||
import NIOConcurrencyHelpers
|
||||
|
||||
#if os(Windows)
|
||||
import let WinSDK.INVALID_SOCKET
|
||||
#endif
|
||||
|
||||
/// A Registration on a `Selector`, which is interested in an `SelectorEventSet`.
|
||||
protocol Registration {
|
||||
/// The `SelectorEventSet` in which the `Registration` is interested.
|
||||
|
@ -29,10 +33,9 @@ protocol SockAddrProtocol {
|
|||
internal func descriptionForAddress(family: NIOBSDSocket.AddressFamily, bytes: UnsafeRawPointer, length byteCount: Int) throws -> String {
|
||||
var addressBytes: [Int8] = Array(repeating: 0, count: byteCount)
|
||||
return try addressBytes.withUnsafeMutableBufferPointer { (addressBytesPtr: inout UnsafeMutableBufferPointer<Int8>) -> String in
|
||||
try Posix.inet_ntop(addressFamily: sa_family_t(family.rawValue),
|
||||
addressBytes: bytes,
|
||||
addressDescription: addressBytesPtr.baseAddress!,
|
||||
addressDescriptionLength: socklen_t(byteCount))
|
||||
try NIOBSDSocket.inet_ntop(af: family, src: bytes,
|
||||
dst: addressBytesPtr.baseAddress!,
|
||||
size: socklen_t(byteCount))
|
||||
return addressBytesPtr.baseAddress!.withMemoryRebound(to: UInt8.self, capacity: byteCount) { addressBytesPtr -> String in
|
||||
String(cString: addressBytesPtr)
|
||||
}
|
||||
|
@ -209,9 +212,13 @@ extension sockaddr_storage {
|
|||
class BaseSocket: BaseSocketProtocol {
|
||||
typealias SelectableType = BaseSocket
|
||||
|
||||
private var descriptor: CInt
|
||||
private var descriptor: NIOBSDSocket.Handle
|
||||
public var isOpen: Bool {
|
||||
return descriptor >= 0
|
||||
#if os(Windows)
|
||||
return descriptor != WinSDK.INVALID_SOCKET
|
||||
#else
|
||||
return descriptor >= 0
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Returns the local bound `SocketAddress` of the socket.
|
||||
|
@ -219,7 +226,9 @@ class BaseSocket: BaseSocketProtocol {
|
|||
/// - returns: The local bound address.
|
||||
/// - throws: An `IOError` if the retrieval of the address failed.
|
||||
func localAddress() throws -> SocketAddress {
|
||||
return try get_addr { try Posix.getsockname(socket: $0, address: $1, addressLength: $2) }
|
||||
return try get_addr {
|
||||
try NIOBSDSocket.getsockname(socket: $0, address: $1, address_len: $2)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the connected `SocketAddress` of the socket.
|
||||
|
@ -227,11 +236,13 @@ class BaseSocket: BaseSocketProtocol {
|
|||
/// - returns: The connected address.
|
||||
/// - throws: An `IOError` if the retrieval of the address failed.
|
||||
func remoteAddress() throws -> SocketAddress {
|
||||
return try get_addr { try Posix.getpeername(socket: $0, address: $1, addressLength: $2) }
|
||||
return try get_addr {
|
||||
try NIOBSDSocket.getpeername(socket: $0, address: $1, address_len: $2)
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal helper function for retrieval of a `SocketAddress`.
|
||||
private func get_addr(_ body: (Int32, UnsafeMutablePointer<sockaddr>, UnsafeMutablePointer<socklen_t>) throws -> Void) throws -> SocketAddress {
|
||||
private func get_addr(_ body: (NIOBSDSocket.Handle, UnsafeMutablePointer<sockaddr>, UnsafeMutablePointer<socklen_t>) throws -> Void) throws -> SocketAddress {
|
||||
var addr = sockaddr_storage()
|
||||
|
||||
try addr.withMutableSockAddr { addressPtr, size in
|
||||
|
@ -252,23 +263,23 @@ class BaseSocket: BaseSocketProtocol {
|
|||
/// - setNonBlocking: Set non-blocking mode on the socket.
|
||||
/// - returns: the file descriptor of the socket that was created.
|
||||
/// - throws: An `IOError` if creation of the socket failed.
|
||||
static func makeSocket(protocolFamily: NIOBSDSocket.ProtocolFamily, type: NIOBSDSocket.SocketType, setNonBlocking: Bool = false) throws -> CInt {
|
||||
static func makeSocket(protocolFamily: NIOBSDSocket.ProtocolFamily, type: NIOBSDSocket.SocketType, setNonBlocking: Bool = false) throws -> NIOBSDSocket.Handle {
|
||||
var sockType: CInt = type.rawValue
|
||||
#if os(Linux)
|
||||
if setNonBlocking {
|
||||
sockType = type.rawValue | Linux.SOCK_NONBLOCK
|
||||
}
|
||||
#endif
|
||||
let sock = try Posix.socket(domain: protocolFamily,
|
||||
type: NIOBSDSocket.SocketType(rawValue: sockType),
|
||||
protocol: 0)
|
||||
let sock = try NIOBSDSocket.socket(domain: protocolFamily,
|
||||
type: NIOBSDSocket.SocketType(rawValue: sockType),
|
||||
protocol: 0)
|
||||
#if !os(Linux)
|
||||
if setNonBlocking {
|
||||
do {
|
||||
try Posix.setNonBlocking(socket: sock)
|
||||
try NIOBSDSocket.setNonBlocking(socket: sock)
|
||||
} catch {
|
||||
// best effort close
|
||||
try? Posix.close(descriptor: sock)
|
||||
try? NIOBSDSocket.close(socket: sock)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
@ -276,11 +287,11 @@ class BaseSocket: BaseSocketProtocol {
|
|||
if protocolFamily == .inet6 {
|
||||
var zero: Int32 = 0
|
||||
do {
|
||||
try Posix.setsockopt(socket: sock, level: NIOBSDSocket.OptionLevel.ipv6.rawValue, optionName: NIOBSDSocket.Option.ipv6_v6only.rawValue, optionValue: &zero, optionLen: socklen_t(MemoryLayout.size(ofValue: zero)))
|
||||
try NIOBSDSocket.setsockopt(socket: sock, level: .ipv6, option_name: .ipv6_v6only, option_value: &zero, option_len: socklen_t(MemoryLayout.size(ofValue: zero)))
|
||||
} catch let e as IOError {
|
||||
if e.errnoCode != EAFNOSUPPORT {
|
||||
// Ignore error that may be thrown by close.
|
||||
_ = try? Posix.close(descriptor: sock)
|
||||
_ = try? NIOBSDSocket.close(socket: sock)
|
||||
throw e
|
||||
}
|
||||
/* we couldn't enable dual IP4/6 support, that's okay too. */
|
||||
|
@ -298,8 +309,12 @@ class BaseSocket: BaseSocketProtocol {
|
|||
///
|
||||
/// - parameters:
|
||||
/// - descriptor: The file descriptor to wrap.
|
||||
init(descriptor: CInt) throws {
|
||||
precondition(descriptor >= 0, "invalid file descriptor")
|
||||
init(socket descriptor: NIOBSDSocket.Handle) throws {
|
||||
#if os(Windows)
|
||||
precondition(descriptor != WinSDK.INVALID_SOCKET, "invalid socket")
|
||||
#else
|
||||
precondition(descriptor >= 0, "invalid socket")
|
||||
#endif
|
||||
self.descriptor = descriptor
|
||||
do {
|
||||
try self.ignoreSIGPIPE()
|
||||
|
@ -324,7 +339,7 @@ class BaseSocket: BaseSocketProtocol {
|
|||
/// throws: An `IOError` if the operation failed.
|
||||
final func setNonBlocking() throws {
|
||||
return try self.withUnsafeHandle {
|
||||
try Posix.setNonBlocking(socket: $0)
|
||||
try NIOBSDSocket.setNonBlocking(socket: $0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -346,12 +361,12 @@ class BaseSocket: BaseSocketProtocol {
|
|||
return try self.withUnsafeHandle {
|
||||
var val = value
|
||||
|
||||
try Posix.setsockopt(
|
||||
try NIOBSDSocket.setsockopt(
|
||||
socket: $0,
|
||||
level: level.rawValue,
|
||||
optionName: name.rawValue,
|
||||
optionValue: &val,
|
||||
optionLen: socklen_t(MemoryLayout.size(ofValue: val)))
|
||||
level: level,
|
||||
option_name: name,
|
||||
option_value: &val,
|
||||
option_len: socklen_t(MemoryLayout.size(ofValue: val)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -377,7 +392,7 @@ class BaseSocket: BaseSocketProtocol {
|
|||
storage.deallocate()
|
||||
}
|
||||
|
||||
try Posix.getsockopt(socket: fd, level: level.rawValue, optionName: name.rawValue, optionValue: val, optionLen: &length)
|
||||
try NIOBSDSocket.getsockopt(socket: fd, level: level, option_name: name, option_value: val, option_len: &length)
|
||||
return val.pointee
|
||||
}
|
||||
}
|
||||
|
@ -390,7 +405,7 @@ class BaseSocket: BaseSocketProtocol {
|
|||
func bind(to address: SocketAddress) throws {
|
||||
try self.withUnsafeHandle { fd in
|
||||
func doBind(ptr: UnsafePointer<sockaddr>, bytes: Int) throws {
|
||||
try Posix.bind(descriptor: fd, ptr: ptr, bytes: bytes)
|
||||
try NIOBSDSocket.bind(socket: fd, address: ptr, address_len: socklen_t(bytes))
|
||||
}
|
||||
|
||||
switch address {
|
||||
|
@ -413,7 +428,7 @@ class BaseSocket: BaseSocketProtocol {
|
|||
///
|
||||
/// - throws: An `IOError` if the operation failed.
|
||||
func close() throws {
|
||||
try Posix.close(descriptor: try self.takeDescriptorOwnership())
|
||||
try NIOBSDSocket.close(socket: try self.takeDescriptorOwnership())
|
||||
}
|
||||
|
||||
/// Takes the file descriptor's ownership.
|
||||
|
@ -422,7 +437,7 @@ class BaseSocket: BaseSocketProtocol {
|
|||
/// the underlying file descriptor.
|
||||
///
|
||||
/// - throws: An `IOError` if the operation failed.
|
||||
final func takeDescriptorOwnership() throws -> CInt {
|
||||
final func takeDescriptorOwnership() throws -> NIOBSDSocket.Handle {
|
||||
return try self.withUnsafeHandle {
|
||||
self.descriptor = -1
|
||||
return $0
|
||||
|
@ -431,7 +446,7 @@ class BaseSocket: BaseSocketProtocol {
|
|||
}
|
||||
|
||||
extension BaseSocket: Selectable {
|
||||
func withUnsafeHandle<T>(_ body: (CInt) throws -> T) throws -> T {
|
||||
func withUnsafeHandle<T>(_ body: (NIOBSDSocket.Handle) throws -> T) throws -> T {
|
||||
guard self.isOpen else {
|
||||
throw IOError(errnoCode: EBADF, reason: "file descriptor already closed!")
|
||||
}
|
||||
|
|
|
@ -225,13 +225,24 @@ public final class ServerBootstrap {
|
|||
}
|
||||
}
|
||||
|
||||
#if !os(Windows)
|
||||
/// Use the existing bound socket file descriptor.
|
||||
///
|
||||
/// - parameters:
|
||||
/// - descriptor: The _Unix file descriptor_ representing the bound stream socket.
|
||||
@available(*, deprecated, renamed: "ServerBootstrap.withBoundSocket(_:)")
|
||||
public func withBoundSocket(descriptor: CInt) -> EventLoopFuture<Channel> {
|
||||
return withBoundSocket(descriptor)
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Use the existing bound socket file descriptor.
|
||||
///
|
||||
/// - parameters:
|
||||
/// - descriptor: The _Unix file descriptor_ representing the bound stream socket.
|
||||
public func withBoundSocket(descriptor: CInt) -> EventLoopFuture<Channel> {
|
||||
public func withBoundSocket(_ socket: NIOBSDSocket.Handle) -> EventLoopFuture<Channel> {
|
||||
func makeChannel(_ eventLoop: SelectableEventLoop, _ childEventLoopGroup: EventLoopGroup) throws -> ServerSocketChannel {
|
||||
return try ServerSocketChannel(descriptor: descriptor, eventLoop: eventLoop, group: childEventLoopGroup)
|
||||
return try ServerSocketChannel(socket: socket, eventLoop: eventLoop, group: childEventLoopGroup)
|
||||
}
|
||||
return bind0(makeServerChannel: makeChannel) { (eventLoop, serverChannel) in
|
||||
let promise = eventLoop.makePromise(of: Void.self)
|
||||
|
@ -613,17 +624,29 @@ public final class ClientBootstrap: NIOClientTCPBootstrapProtocol {
|
|||
}
|
||||
}
|
||||
|
||||
#if !os(Windows)
|
||||
/// Use the existing connected socket file descriptor.
|
||||
///
|
||||
/// - parameters:
|
||||
/// - descriptor: The _Unix file descriptor_ representing the connected stream socket.
|
||||
/// - returns: an `EventLoopFuture<Channel>` to deliver the `Channel`.
|
||||
@available(*, deprecated, renamed: "ClientBoostrap.withConnectedSocket(_:)")
|
||||
public func withConnectedSocket(descriptor: CInt) -> EventLoopFuture<Channel> {
|
||||
return self.withConnectedSocket(descriptor)
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Use the existing connected socket file descriptor.
|
||||
///
|
||||
/// - parameters:
|
||||
/// - descriptor: The _Unix file descriptor_ representing the connected stream socket.
|
||||
/// - returns: an `EventLoopFuture<Channel>` to deliver the `Channel`.
|
||||
public func withConnectedSocket(descriptor: CInt) -> EventLoopFuture<Channel> {
|
||||
public func withConnectedSocket(_ socket: NIOBSDSocket.Handle) -> EventLoopFuture<Channel> {
|
||||
let eventLoop = group.next()
|
||||
let channelInitializer = self.channelInitializer
|
||||
let channel: SocketChannel
|
||||
do {
|
||||
channel = try SocketChannel(eventLoop: eventLoop as! SelectableEventLoop, descriptor: descriptor)
|
||||
channel = try SocketChannel(eventLoop: eventLoop as! SelectableEventLoop, socket: socket)
|
||||
} catch {
|
||||
return eventLoop.makeFailedFuture(error)
|
||||
}
|
||||
|
@ -783,13 +806,24 @@ public final class DatagramBootstrap {
|
|||
return self
|
||||
}
|
||||
|
||||
#if !os(Windows)
|
||||
/// Use the existing bound socket file descriptor.
|
||||
///
|
||||
/// - parameters:
|
||||
/// - descriptor: The _Unix file descriptor_ representing the bound datagram socket.
|
||||
@available(*, deprecated, renamed: "DatagramBootstrap.withBoundSocket(_:)")
|
||||
public func withBoundSocket(descriptor: CInt) -> EventLoopFuture<Channel> {
|
||||
return self.withBoundSocket(descriptor)
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Use the existing bound socket file descriptor.
|
||||
///
|
||||
/// - parameters:
|
||||
/// - descriptor: The _Unix file descriptor_ representing the bound datagram socket.
|
||||
public func withBoundSocket(descriptor: CInt) -> EventLoopFuture<Channel> {
|
||||
public func withBoundSocket(_ socket: NIOBSDSocket.Handle) -> EventLoopFuture<Channel> {
|
||||
func makeChannel(_ eventLoop: SelectableEventLoop) throws -> DatagramChannel {
|
||||
return try DatagramChannel(eventLoop: eventLoop, descriptor: descriptor)
|
||||
return try DatagramChannel(eventLoop: eventLoop, socket: socket)
|
||||
}
|
||||
return bind0(makeChannel: makeChannel) { (eventLoop, channel) in
|
||||
let promise = eventLoop.makePromise(of: Void.self)
|
||||
|
|
|
@ -19,5 +19,5 @@
|
|||
/// `Selectable`s are not thread-safe, only to be used on the appropriate
|
||||
/// `EventLoop`.
|
||||
protocol Selectable {
|
||||
func withUnsafeHandle<T>(_: (CInt) throws -> T) throws -> T
|
||||
func withUnsafeHandle<T>(_: (NIOBSDSocket.Handle) throws -> T) throws -> T
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
/// - throws: An `IOError` if creation of the socket failed.
|
||||
init(protocolFamily: NIOBSDSocket.ProtocolFamily, setNonBlocking: Bool = false) throws {
|
||||
let sock = try BaseSocket.makeSocket(protocolFamily: protocolFamily, type: .stream, setNonBlocking: setNonBlocking)
|
||||
try super.init(descriptor: sock)
|
||||
try super.init(socket: sock)
|
||||
}
|
||||
|
||||
/// Create a new instance.
|
||||
|
@ -40,8 +40,21 @@
|
|||
/// - descriptor: The _Unix file descriptor_ representing the bound socket.
|
||||
/// - setNonBlocking: Set non-blocking mode on the socket.
|
||||
/// - throws: An `IOError` if socket is invalid.
|
||||
init(descriptor: CInt, setNonBlocking: Bool = false) throws {
|
||||
try super.init(descriptor: descriptor)
|
||||
#if !os(Windows)
|
||||
@available(*, deprecated, renamed: "init(socket:setNonBlocking:)")
|
||||
convenience init(descriptor: CInt, setNonBlocking: Bool = false) throws {
|
||||
try self.init(socket: descriptor, setNonBlocking: setNonBlocking)
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Create a new instance.
|
||||
///
|
||||
/// - parameters:
|
||||
/// - descriptor: The _Unix file descriptor_ representing the bound socket.
|
||||
/// - setNonBlocking: Set non-blocking mode on the socket.
|
||||
/// - throws: An `IOError` if socket is invalid.
|
||||
init(socket: NIOBSDSocket.Handle, setNonBlocking: Bool = false) throws {
|
||||
try super.init(socket: socket)
|
||||
if setNonBlocking {
|
||||
try self.setNonBlocking()
|
||||
}
|
||||
|
@ -54,7 +67,7 @@
|
|||
/// - throws: An `IOError` if creation of the socket failed.
|
||||
func listen(backlog: Int32 = 128) throws {
|
||||
try withUnsafeHandle {
|
||||
_ = try Posix.listen(descriptor: $0, backlog: backlog)
|
||||
_ = try NIOBSDSocket.listen(socket: $0, backlog: backlog)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,13 +88,13 @@
|
|||
}
|
||||
let result = try Linux.accept4(descriptor: fd, addr: nil, len: nil, flags: flags)
|
||||
#else
|
||||
let result = try Posix.accept(descriptor: fd, addr: nil, len: nil)
|
||||
let result = try NIOBSDSocket.accept(socket: fd, address: nil, address_len: nil)
|
||||
#endif
|
||||
|
||||
guard let fd = result else {
|
||||
return nil
|
||||
}
|
||||
let sock = try Socket(descriptor: fd)
|
||||
let sock = try Socket(socket: fd)
|
||||
#if !os(Linux)
|
||||
if setNonBlocking {
|
||||
do {
|
||||
|
|
|
@ -34,7 +34,7 @@ typealias IOVector = iovec
|
|||
/// - throws: An `IOError` if creation of the socket failed.
|
||||
init(protocolFamily: NIOBSDSocket.ProtocolFamily, type: NIOBSDSocket.SocketType, setNonBlocking: Bool = false) throws {
|
||||
let sock = try BaseSocket.makeSocket(protocolFamily: protocolFamily, type: type, setNonBlocking: setNonBlocking)
|
||||
try super.init(descriptor: sock)
|
||||
try super.init(socket: sock)
|
||||
}
|
||||
|
||||
/// Create a new instance out of an already established socket.
|
||||
|
@ -43,8 +43,21 @@ typealias IOVector = iovec
|
|||
/// - descriptor: The existing socket descriptor.
|
||||
/// - setNonBlocking: Set non-blocking mode on the socket.
|
||||
/// - throws: An `IOError` if could not change the socket into non-blocking
|
||||
init(descriptor: CInt, setNonBlocking: Bool) throws {
|
||||
try super.init(descriptor: descriptor)
|
||||
#if !os(Windows)
|
||||
@available(*, deprecated, renamed: "init(socket:setNonBlocking:)")
|
||||
convenience init(descriptor: CInt, setNonBlocking: Bool) throws {
|
||||
try self.init(socket: descriptor, setNonBlocking: setNonBlocking)
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Create a new instance out of an already established socket.
|
||||
///
|
||||
/// - parameters:
|
||||
/// - descriptor: The existing socket descriptor.
|
||||
/// - setNonBlocking: Set non-blocking mode on the socket.
|
||||
/// - throws: An `IOError` if could not change the socket into non-blocking
|
||||
init(socket: NIOBSDSocket.Handle, setNonBlocking: Bool) throws {
|
||||
try super.init(socket: socket)
|
||||
if setNonBlocking {
|
||||
try self.setNonBlocking()
|
||||
}
|
||||
|
@ -57,8 +70,22 @@ typealias IOVector = iovec
|
|||
///
|
||||
/// - parameters:
|
||||
/// - descriptor: The file descriptor to wrap.
|
||||
override init(descriptor: CInt) throws {
|
||||
try super.init(descriptor: descriptor)
|
||||
#if !os(Windows)
|
||||
@available(*, deprecated, renamed: "init(socket:)")
|
||||
convenience init(descriptor: CInt) throws {
|
||||
try self.init(socket: descriptor)
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Create a new instance.
|
||||
///
|
||||
/// The ownership of the passed in descriptor is transferred to this class. A user must call `close` to close the underlying
|
||||
/// file descriptor once it's not needed / used anymore.
|
||||
///
|
||||
/// - parameters:
|
||||
/// - descriptor: The file descriptor to wrap.
|
||||
override init(socket: NIOBSDSocket.Handle) throws {
|
||||
try super.init(socket: socket)
|
||||
}
|
||||
|
||||
/// Connect to the `SocketAddress`.
|
||||
|
@ -84,7 +111,8 @@ typealias IOVector = iovec
|
|||
var addr = addr
|
||||
return try withUnsafePointer(to: &addr) { ptr in
|
||||
try ptr.withMemoryRebound(to: sockaddr.self, capacity: 1) { ptr in
|
||||
try Posix.connect(descriptor: fd, addr: ptr, size: socklen_t(MemoryLayout<T>.size))
|
||||
try NIOBSDSocket.connect(socket: fd, address: ptr,
|
||||
address_len: socklen_t(MemoryLayout<T>.size))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -108,7 +136,8 @@ typealias IOVector = iovec
|
|||
/// - throws: An `IOError` if the operation failed.
|
||||
func write(pointer: UnsafeRawBufferPointer) throws -> IOResult<Int> {
|
||||
return try withUnsafeHandle {
|
||||
try Posix.write(descriptor: $0, pointer: pointer.baseAddress!, size: pointer.count)
|
||||
try NIOBSDSocket.send(socket: $0, buffer: pointer.baseAddress!,
|
||||
length: pointer.count)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,9 +162,11 @@ typealias IOVector = iovec
|
|||
/// - throws: An `IOError` if the operation failed.
|
||||
func sendto(pointer: UnsafeRawBufferPointer, destinationPtr: UnsafePointer<sockaddr>, destinationSize: socklen_t) throws -> IOResult<Int> {
|
||||
return try withUnsafeHandle {
|
||||
try Posix.sendto(descriptor: $0, pointer: UnsafeMutableRawPointer(mutating: pointer.baseAddress!),
|
||||
size: pointer.count, destinationPtr: destinationPtr,
|
||||
destinationSize: destinationSize)
|
||||
try NIOBSDSocket.sendto(socket: $0,
|
||||
buffer: UnsafeMutableRawPointer(mutating: pointer.baseAddress!),
|
||||
length: pointer.count,
|
||||
dest_addr: destinationPtr,
|
||||
dest_len: destinationSize)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,10 +193,10 @@ typealias IOVector = iovec
|
|||
func recvfrom(pointer: UnsafeMutableRawBufferPointer, storage: inout sockaddr_storage, storageLen: inout socklen_t) throws -> IOResult<(Int)> {
|
||||
return try withUnsafeHandle { fd in
|
||||
try storage.withMutableSockAddr { (storagePtr, _) in
|
||||
try Posix.recvfrom(descriptor: fd, pointer: pointer.baseAddress!,
|
||||
len: pointer.count,
|
||||
addr: storagePtr,
|
||||
addrlen: &storageLen)
|
||||
try NIOBSDSocket.recvfrom(socket: fd, buffer: pointer.baseAddress!,
|
||||
length: pointer.count,
|
||||
address: storagePtr,
|
||||
address_len: &storageLen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -180,7 +211,8 @@ typealias IOVector = iovec
|
|||
/// - throws: An `IOError` if the operation failed.
|
||||
func sendFile(fd: Int32, offset: Int, count: Int) throws -> IOResult<Int> {
|
||||
return try withUnsafeHandle {
|
||||
try Posix.sendfile(descriptor: $0, fd: fd, offset: off_t(offset), count: count)
|
||||
try NIOBSDSocket.sendfile(socket: $0, fd: fd, offset: off_t(offset),
|
||||
len: off_t(count))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,7 +224,9 @@ typealias IOVector = iovec
|
|||
/// - throws: An `IOError` if the operation failed.
|
||||
func recvmmsg(msgs: UnsafeMutableBufferPointer<MMsgHdr>) throws -> IOResult<Int> {
|
||||
return try withUnsafeHandle {
|
||||
try Posix.recvmmsg(sockfd: $0, msgvec: msgs.baseAddress!, vlen: CUnsignedInt(msgs.count), flags: 0, timeout: nil)
|
||||
try NIOBSDSocket.recvmmsg(socket: $0, msgvec: msgs.baseAddress!,
|
||||
vlen: CUnsignedInt(msgs.count), flags: 0,
|
||||
timeout: nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,7 +238,8 @@ typealias IOVector = iovec
|
|||
/// - throws: An `IOError` if the operation failed.
|
||||
func sendmmsg(msgs: UnsafeMutableBufferPointer<MMsgHdr>) throws -> IOResult<Int> {
|
||||
return try withUnsafeHandle {
|
||||
try Posix.sendmmsg(sockfd: $0, msgvec: msgs.baseAddress!, vlen: CUnsignedInt(msgs.count), flags: 0)
|
||||
try NIOBSDSocket.sendmmsg(socket: $0, msgvec: msgs.baseAddress!,
|
||||
vlen: CUnsignedInt(msgs.count), flags: 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,7 +250,7 @@ typealias IOVector = iovec
|
|||
/// - throws: An `IOError` if the operation failed.
|
||||
func shutdown(how: Shutdown) throws {
|
||||
return try withUnsafeHandle {
|
||||
try Posix.shutdown(descriptor: $0, how: how)
|
||||
try NIOBSDSocket.shutdown(socket: $0, how: how)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -264,17 +264,26 @@ public enum SocketAddress: CustomStringConvertible {
|
|||
/// - returns: the `SocketAddress` corresponding to this string and port combination.
|
||||
/// - throws: may throw `SocketAddressError.failedToParseIPString` if the IP address cannot be parsed.
|
||||
public init(ipAddress: String, port: Int) throws {
|
||||
var ipv4Addr = in_addr()
|
||||
var ipv6Addr = in6_addr()
|
||||
|
||||
self = try ipAddress.withCString {
|
||||
if inet_pton(NIOBSDSocket.AddressFamily.inet.rawValue, $0, &ipv4Addr) == 1 {
|
||||
do {
|
||||
var ipv4Addr = in_addr()
|
||||
try NIOBSDSocket.inet_pton(af: .inet, src: $0, dst: &ipv4Addr)
|
||||
|
||||
var addr = sockaddr_in()
|
||||
addr.sin_family = sa_family_t(NIOBSDSocket.AddressFamily.inet.rawValue)
|
||||
addr.sin_port = in_port_t(port).bigEndian
|
||||
addr.sin_addr = ipv4Addr
|
||||
|
||||
return .v4(.init(address: addr, host: ""))
|
||||
} else if inet_pton(NIOBSDSocket.AddressFamily.inet6.rawValue, $0, &ipv6Addr) == 1 {
|
||||
} catch {
|
||||
// If `inet_pton` fails as an IPv4 address, we will try as an
|
||||
// IPv6 address.
|
||||
}
|
||||
|
||||
do {
|
||||
var ipv6Addr = in6_addr()
|
||||
try NIOBSDSocket.inet_pton(af: .inet6, src: $0, dst: &ipv6Addr)
|
||||
|
||||
var addr = sockaddr_in6()
|
||||
addr.sin6_family = sa_family_t(NIOBSDSocket.AddressFamily.inet6.rawValue)
|
||||
addr.sin6_port = in_port_t(port).bigEndian
|
||||
|
@ -282,9 +291,12 @@ public enum SocketAddress: CustomStringConvertible {
|
|||
addr.sin6_addr = ipv6Addr
|
||||
addr.sin6_scope_id = 0
|
||||
return .v6(.init(address: addr, host: ""))
|
||||
} else {
|
||||
throw SocketAddressError.failedToParseIPString(ipAddress)
|
||||
} catch {
|
||||
// If `inet_pton` fails as an IPv6 address (and has failed as an
|
||||
// IPv4 address above), we will throw an error below.
|
||||
}
|
||||
|
||||
throw SocketAddressError.failedToParseIPString(ipAddress)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,9 +40,9 @@ final class SocketChannel: BaseStreamSocketChannel<Socket> {
|
|||
try super.init(socket: socket, parent: nil, eventLoop: eventLoop, recvAllocator: AdaptiveRecvByteBufferAllocator())
|
||||
}
|
||||
|
||||
init(eventLoop: SelectableEventLoop, descriptor: CInt) throws {
|
||||
let socket = try Socket(descriptor: descriptor, setNonBlocking: true)
|
||||
try super.init(socket: socket, parent: nil, eventLoop: eventLoop, recvAllocator: AdaptiveRecvByteBufferAllocator())
|
||||
init(eventLoop: SelectableEventLoop, socket: NIOBSDSocket.Handle) throws {
|
||||
let sock = try Socket(socket: socket, setNonBlocking: true)
|
||||
try super.init(socket: sock, parent: nil, eventLoop: eventLoop, recvAllocator: AdaptiveRecvByteBufferAllocator())
|
||||
}
|
||||
|
||||
init(socket: Socket, parent: Channel? = nil, eventLoop: SelectableEventLoop) throws {
|
||||
|
@ -147,9 +147,9 @@ final class ServerSocketChannel: BaseSocketChannel<ServerSocket> {
|
|||
recvAllocator: AdaptiveRecvByteBufferAllocator())
|
||||
}
|
||||
|
||||
convenience init(descriptor: CInt, eventLoop: SelectableEventLoop, group: EventLoopGroup) throws {
|
||||
let socket = try ServerSocket(descriptor: descriptor, setNonBlocking: true)
|
||||
try self.init(serverSocket: socket, eventLoop: eventLoop, group: group)
|
||||
convenience init(socket: NIOBSDSocket.Handle, eventLoop: SelectableEventLoop, group: EventLoopGroup) throws {
|
||||
let sock = try ServerSocket(socket: socket, setNonBlocking: true)
|
||||
try self.init(serverSocket: sock, eventLoop: eventLoop, group: group)
|
||||
try self.socket.listen(backlog: backlog)
|
||||
}
|
||||
|
||||
|
@ -342,8 +342,8 @@ final class DatagramChannel: BaseSocketChannel<Socket> {
|
|||
return super.isOpen
|
||||
}
|
||||
|
||||
convenience init(eventLoop: SelectableEventLoop, descriptor: CInt) throws {
|
||||
let socket = try Socket(descriptor: descriptor)
|
||||
convenience init(eventLoop: SelectableEventLoop, socket: NIOBSDSocket.Handle) throws {
|
||||
let socket = try Socket(socket: socket)
|
||||
|
||||
do {
|
||||
try self.init(socket: socket, eventLoop: eventLoop)
|
||||
|
|
|
@ -26,6 +26,10 @@ internal typealias MMsgHdr = CNIODarwin_mmsghdr
|
|||
@_exported import Glibc
|
||||
import CNIOLinux
|
||||
internal typealias MMsgHdr = CNIOLinux_mmsghdr
|
||||
#elseif os(Windows)
|
||||
import CNIOWindows
|
||||
internal typealias sockaddr = WinSDK.SOCKADDR
|
||||
internal typealias MMsgHdr = CNIOWindows_mmsghdr
|
||||
#else
|
||||
let badOS = { fatalError("unsupported OS") }()
|
||||
#endif
|
||||
|
@ -85,17 +89,21 @@ private let sysGetifaddrs: @convention(c) (UnsafeMutablePointer<UnsafeMutablePoi
|
|||
private let sysFreeifaddrs: @convention(c) (UnsafeMutablePointer<ifaddrs>?) -> Void = freeifaddrs
|
||||
private let sysIfNameToIndex: @convention(c) (UnsafePointer<CChar>?) -> CUnsignedInt = if_nametoindex
|
||||
private let sysInet_ntop: @convention(c) (CInt, UnsafeRawPointer?, UnsafeMutablePointer<CChar>?, socklen_t) -> UnsafePointer<CChar>? = inet_ntop
|
||||
private let sysInet_pton: @convention(c) (CInt, UnsafePointer<CChar>?, UnsafeMutableRawPointer?) -> CInt = inet_pton
|
||||
private let sysSocketpair: @convention(c) (CInt, CInt, CInt, UnsafeMutablePointer<CInt>?) -> CInt = socketpair
|
||||
|
||||
#if os(Linux)
|
||||
private let sysFstat: @convention(c) (CInt, UnsafeMutablePointer<stat>) -> CInt = fstat
|
||||
private let sysSendMmsg: @convention(c) (CInt, UnsafeMutablePointer<CNIOLinux_mmsghdr>?, CUnsignedInt, CInt) -> CInt = CNIOLinux_sendmmsg
|
||||
private let sysRecvMmsg: @convention(c) (CInt, UnsafeMutablePointer<CNIOLinux_mmsghdr>?, CUnsignedInt, CInt, UnsafeMutablePointer<timespec>?) -> CInt = CNIOLinux_recvmmsg
|
||||
#else
|
||||
#elseif os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
|
||||
private let sysFstat: @convention(c) (CInt, UnsafeMutablePointer<stat>?) -> CInt = fstat
|
||||
private let sysKevent = kevent
|
||||
private let sysSendMmsg: @convention(c) (CInt, UnsafeMutablePointer<CNIODarwin_mmsghdr>?, CUnsignedInt, CInt) -> CInt = CNIODarwin_sendmmsg
|
||||
private let sysRecvMmsg: @convention(c) (CInt, UnsafeMutablePointer<CNIODarwin_mmsghdr>?, CUnsignedInt, CInt, UnsafeMutablePointer<timespec>?) -> CInt = CNIODarwin_recvmmsg
|
||||
#elseif os(Windows)
|
||||
private let sysSendMmsg: @convention(c) (NIOBSDSocket.Handle, UnsafeMutablePointer<CNIOWindows_mmsghdr>?, CUnsignedInt, CInt) -> CInt = CNIOWindows_sendmmsg
|
||||
private let sysRecvMmsg: @convention(c) (NIOBSDSocket.Handle, UnsafeMutablePointer<CNIOWindows_mmsghdr>?, CUnsignedInt, CInt, UnsafeMutablePointer<timespec>?) -> CInt = CNIOWindows_recvmmsg
|
||||
#endif
|
||||
|
||||
private func isUnacceptableErrno(_ code: Int32) -> Bool {
|
||||
|
@ -157,23 +165,6 @@ internal func wrapErrorIsNullReturnCall<T>(where function: String = #function, _
|
|||
}
|
||||
}
|
||||
|
||||
enum Shutdown {
|
||||
case RD
|
||||
case WR
|
||||
case RDWR
|
||||
|
||||
fileprivate var cValue: CInt {
|
||||
switch self {
|
||||
case .RD:
|
||||
return CInt(Posix.SHUT_RD)
|
||||
case .WR:
|
||||
return CInt(Posix.SHUT_WR)
|
||||
case .RDWR:
|
||||
return CInt(Posix.SHUT_RDWR)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal enum Posix {
|
||||
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
|
||||
static let UIO_MAXIOV: Int = 1024
|
||||
|
@ -190,6 +181,15 @@ internal enum Posix {
|
|||
static var UIO_MAXIOV: Int {
|
||||
fatalError("unsupported OS")
|
||||
}
|
||||
static var SHUT_RD: Int {
|
||||
fatalError("unsupported OS")
|
||||
}
|
||||
static var SHUT_WR: Int {
|
||||
fatalError("unsupported OS")
|
||||
}
|
||||
static var SHUT_RDWR: Int {
|
||||
fatalError("unsupported OS")
|
||||
}
|
||||
#endif
|
||||
|
||||
@inline(never)
|
||||
|
@ -403,6 +403,15 @@ internal enum Posix {
|
|||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public static func inet_pton(addressFamily: sa_family_t, addressDescription: UnsafePointer<CChar>, address: UnsafeMutableRawPointer) throws {
|
||||
switch sysInet_pton(CInt(addressFamily), addressDescription, address) {
|
||||
case 0: throw IOError(errnoCode: EINVAL, reason: #function)
|
||||
case 1: return
|
||||
default: throw IOError(errnoCode: errno, reason: #function)
|
||||
}
|
||||
}
|
||||
|
||||
// It's not really posix but exists on Linux and MacOS / BSD so just put it here for now to keep it simple
|
||||
@inline(never)
|
||||
public static func sendfile(descriptor: CInt, fd: CInt, offset: off_t, count: size_t) throws -> IOResult<Int> {
|
||||
|
|
|
@ -155,7 +155,7 @@ class BootstrapTest: XCTestCase {
|
|||
socketVector: &socketFDs))
|
||||
defer {
|
||||
// 0 is closed together with the Channel below.
|
||||
XCTAssertNoThrow(try Posix.close(descriptor: socketFDs[1]))
|
||||
XCTAssertNoThrow(try NIOBSDSocket.close(socket: socketFDs[1]))
|
||||
}
|
||||
|
||||
XCTAssertNoThrow(try ClientBootstrap(group: self.freshEventLoop())
|
||||
|
@ -163,19 +163,20 @@ class BootstrapTest: XCTestCase {
|
|||
XCTAssert(channel.eventLoop.inEventLoop)
|
||||
return self.freshEventLoop().makeSucceededFuture(())
|
||||
}
|
||||
.withConnectedSocket(descriptor: socketFDs[0])
|
||||
.withConnectedSocket(socketFDs[0])
|
||||
.wait()
|
||||
.close()
|
||||
.wait())
|
||||
}
|
||||
|
||||
func testPreConnectedServerSocketToleratesFuturesFromDifferentEventLoopsReturnedInInitializers() throws {
|
||||
let socket = try Posix.socket(domain: .inet, type: .stream, protocol: 0)
|
||||
let socket =
|
||||
try NIOBSDSocket.socket(domain: .inet, type: .stream, protocol: 0)
|
||||
|
||||
let serverAddress = try assertNoThrowWithValue(SocketAddress.makeAddressResolvingHost("127.0.0.1", port: 0))
|
||||
try serverAddress.withSockAddr { serverAddressPtr, size in
|
||||
try Posix.bind(descriptor: socket, ptr: serverAddressPtr,
|
||||
bytes: size)
|
||||
try serverAddress.withSockAddr { address, len in
|
||||
try NIOBSDSocket.bind(socket: socket, address: address,
|
||||
address_len: socklen_t(len))
|
||||
}
|
||||
|
||||
let childChannelDone = self.freshEventLoop().next().makePromise(of: Void.self)
|
||||
|
@ -196,7 +197,7 @@ class BootstrapTest: XCTestCase {
|
|||
}
|
||||
return self.freshEventLoop().makeSucceededFuture(())
|
||||
}
|
||||
.withBoundSocket(descriptor: socket)
|
||||
.withBoundSocket(socket)
|
||||
.wait())
|
||||
let client = try assertNoThrowWithValue(ClientBootstrap(group: self.freshEventLoop())
|
||||
.channelInitializer { channel in
|
||||
|
@ -330,7 +331,7 @@ class BootstrapTest: XCTestCase {
|
|||
}
|
||||
return channel.pipeline.addHandler(MakeSureAutoReadIsOffInChannelInitializer())
|
||||
}
|
||||
.withConnectedSocket(descriptor: fd)
|
||||
.withConnectedSocket(fd)
|
||||
.wait())
|
||||
XCTAssertNotNil(channel)
|
||||
XCTAssertNoThrow(try channel?.close().wait())
|
||||
|
|
|
@ -2471,7 +2471,8 @@ public final class ChannelTests: XCTestCase {
|
|||
}
|
||||
try channel.socket.withUnsafeHandle { fd in
|
||||
var pollFd: pollfd = .init(fd: fd, events: Int16(POLLIN), revents: 0)
|
||||
let nfds = try Posix.poll(fds: &pollFd, nfds: 1, timeout: -1)
|
||||
let nfds =
|
||||
try NIOBSDSocket.poll(fds: &pollFd, nfds: 1, timeout: -1)
|
||||
XCTAssertEqual(1, nfds)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,25 +126,30 @@ private extension Channel {
|
|||
|
||||
private extension SocketAddress {
|
||||
init(host: String, ipAddress: String, port: Int) {
|
||||
var v4addr = in_addr()
|
||||
var v6addr = in6_addr()
|
||||
do {
|
||||
var v4addr = in_addr()
|
||||
try NIOBSDSocket.inet_pton(af: .inet, src: ipAddress, dst: &v4addr)
|
||||
|
||||
if inet_pton(NIOBSDSocket.AddressFamily.inet.rawValue, ipAddress, &v4addr) == 1 {
|
||||
var sockaddr = sockaddr_in()
|
||||
sockaddr.sin_family = sa_family_t(NIOBSDSocket.AddressFamily.inet.rawValue)
|
||||
sockaddr.sin_port = in_port_t(port).bigEndian
|
||||
sockaddr.sin_addr = v4addr
|
||||
self = .init(sockaddr, host: host)
|
||||
} else if inet_pton(NIOBSDSocket.AddressFamily.inet6.rawValue, ipAddress, &v6addr) == 1 {
|
||||
var sockaddr = sockaddr_in6()
|
||||
sockaddr.sin6_family = sa_family_t(NIOBSDSocket.AddressFamily.inet6.rawValue)
|
||||
sockaddr.sin6_port = in_port_t(port).bigEndian
|
||||
sockaddr.sin6_flowinfo = 0
|
||||
sockaddr.sin6_scope_id = 0
|
||||
sockaddr.sin6_addr = v6addr
|
||||
self = .init(sockaddr, host: host)
|
||||
} else {
|
||||
fatalError("Unable to convert to IP")
|
||||
} catch {
|
||||
do {
|
||||
var v6addr = in6_addr()
|
||||
try NIOBSDSocket.inet_pton(af: .inet6, src: ipAddress, dst: &v6addr)
|
||||
|
||||
var sockaddr = sockaddr_in6()
|
||||
sockaddr.sin6_family = sa_family_t(NIOBSDSocket.AddressFamily.inet6.rawValue)
|
||||
sockaddr.sin6_port = in_port_t(port).bigEndian
|
||||
sockaddr.sin6_flowinfo = 0
|
||||
sockaddr.sin6_scope_id = 0
|
||||
sockaddr.sin6_addr = v6addr
|
||||
self = .init(sockaddr, host: host)
|
||||
} catch {
|
||||
fatalError("Unable to convert to IP")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,10 +158,10 @@ private extension SocketAddress {
|
|||
switch self {
|
||||
case .v4(let address):
|
||||
var baseAddress = address.address
|
||||
precondition(inet_ntop(NIOBSDSocket.AddressFamily.inet.rawValue, &baseAddress.sin_addr, ptr, 256) != nil)
|
||||
precondition(try! NIOBSDSocket.inet_ntop(af: .inet, src: &baseAddress.sin_addr, dst: ptr, size: 256) != nil)
|
||||
case .v6(let address):
|
||||
var baseAddress = address.address
|
||||
precondition(inet_ntop(NIOBSDSocket.AddressFamily.inet6.rawValue, &baseAddress.sin6_addr, ptr, 256) != nil)
|
||||
precondition(try! NIOBSDSocket.inet_ntop(af: .inet6, src: &baseAddress.sin6_addr, dst: ptr, size: 256) != nil)
|
||||
case .unixDomainSocket:
|
||||
fatalError("No UDS support in happy eyeballs.")
|
||||
}
|
||||
|
|
|
@ -191,7 +191,8 @@ class NonBlockingFileIOTest: XCTestCase {
|
|||
|
||||
func testFailedIO() throws {
|
||||
enum DummyError: Error { case dummy }
|
||||
let unconnectedSockFH = NIOFileHandle(descriptor: try! Posix.socket(domain: .unix, type: .stream, protocol: 0))
|
||||
let unconnectedSockFH =
|
||||
NIOFileHandle(descriptor: try! NIOBSDSocket.socket(domain: .unix, type: .stream, protocol: 0))
|
||||
defer {
|
||||
XCTAssertNoThrow(try unconnectedSockFH.close())
|
||||
}
|
||||
|
|
|
@ -376,9 +376,9 @@ class SelectorTest: XCTestCase {
|
|||
}
|
||||
class FakeSocket: Socket {
|
||||
private let hasBeenClosedPromise: EventLoopPromise<Void>
|
||||
init(hasBeenClosedPromise: EventLoopPromise<Void>, descriptor: CInt) throws {
|
||||
init(hasBeenClosedPromise: EventLoopPromise<Void>, socket: NIOBSDSocket.Handle) throws {
|
||||
self.hasBeenClosedPromise = hasBeenClosedPromise
|
||||
try super.init(descriptor: descriptor)
|
||||
try super.init(socket: socket)
|
||||
}
|
||||
override func close() throws {
|
||||
self.hasBeenClosedPromise.succeed(())
|
||||
|
@ -395,7 +395,7 @@ class SelectorTest: XCTestCase {
|
|||
let el = group.next() as! SelectableEventLoop
|
||||
let channelHasBeenClosedPromise = el.makePromise(of: Void.self)
|
||||
let channel = try SocketChannel(socket: FakeSocket(hasBeenClosedPromise: channelHasBeenClosedPromise,
|
||||
descriptor: socketFDs[0]), eventLoop: el)
|
||||
socket: socketFDs[0]), eventLoop: el)
|
||||
let sched = el.scheduleRepeatedTask(initialDelay: .microseconds(delayToUseInMicroSeconds),
|
||||
delay: .microseconds(delayToUseInMicroSeconds)) { (_: RepeatedTask) in
|
||||
_ = numberFires.add(1)
|
||||
|
|
|
@ -330,7 +330,7 @@ public final class SocketChannelTest : XCTestCase {
|
|||
let serverSock = try Socket(protocolFamily: .inet, type: .stream)
|
||||
try serverSock.bind(to: SocketAddress(ipAddress: "127.0.0.1", port: 0))
|
||||
let serverChannelFuture = try serverSock.withUnsafeHandle {
|
||||
ServerBootstrap(group: group).withBoundSocket(descriptor: dup($0))
|
||||
ServerBootstrap(group: group).withBoundSocket(dup($0))
|
||||
}
|
||||
try serverSock.close()
|
||||
let serverChannel = try serverChannelFuture.wait()
|
||||
|
@ -339,7 +339,7 @@ public final class SocketChannelTest : XCTestCase {
|
|||
let connected = try clientSock.connect(to: serverChannel.localAddress!)
|
||||
XCTAssertEqual(connected, true)
|
||||
let clientChannelFuture = try clientSock.withUnsafeHandle {
|
||||
ClientBootstrap(group: group).withConnectedSocket(descriptor: dup($0))
|
||||
ClientBootstrap(group: group).withConnectedSocket(dup($0))
|
||||
}
|
||||
try clientSock.close()
|
||||
let clientChannel = try clientChannelFuture.wait()
|
||||
|
@ -357,7 +357,7 @@ public final class SocketChannelTest : XCTestCase {
|
|||
let serverSock = try Socket(protocolFamily: .inet, type: .datagram)
|
||||
try serverSock.bind(to: SocketAddress(ipAddress: "127.0.0.1", port: 0))
|
||||
let serverChannelFuture = try serverSock.withUnsafeHandle {
|
||||
DatagramBootstrap(group: group).withBoundSocket(descriptor: dup($0))
|
||||
DatagramBootstrap(group: group).withBoundSocket(dup($0))
|
||||
}
|
||||
try serverSock.close()
|
||||
let serverChannel = try serverChannelFuture.wait()
|
||||
|
|
|
@ -253,10 +253,10 @@ class HookedSocket: Socket, UserKernelInterface {
|
|||
fileprivate let userToKernel: LockedBox<UserToKernel>
|
||||
fileprivate let kernelToUser: LockedBox<KernelToUser>
|
||||
|
||||
init(userToKernel: LockedBox<UserToKernel>, kernelToUser: LockedBox<KernelToUser>, descriptor: CInt) throws {
|
||||
init(userToKernel: LockedBox<UserToKernel>, kernelToUser: LockedBox<KernelToUser>, socket: NIOBSDSocket.Handle) throws {
|
||||
self.userToKernel = userToKernel
|
||||
self.kernelToUser = kernelToUser
|
||||
try super.init(descriptor: descriptor)
|
||||
try super.init(socket: socket)
|
||||
}
|
||||
|
||||
override func ignoreSIGPIPE() throws {
|
||||
|
@ -505,7 +505,7 @@ extension SALTest {
|
|||
}) {
|
||||
try SocketChannel(socket: HookedSocket(userToKernel: self.userToKernelBox,
|
||||
kernelToUser: self.kernelToUserBox,
|
||||
descriptor: .max),
|
||||
socket: .max),
|
||||
eventLoop: eventLoop)
|
||||
}
|
||||
try self.assertParkedRightNow()
|
||||
|
@ -527,7 +527,7 @@ extension SALTest {
|
|||
}) {
|
||||
try SocketChannel(socket: HookedSocket(userToKernel: self.userToKernelBox,
|
||||
kernelToUser: self.kernelToUserBox,
|
||||
descriptor: .max),
|
||||
socket: .max),
|
||||
eventLoop: self.loop)
|
||||
}
|
||||
try self.assertParkedRightNow()
|
||||
|
|
|
@ -27,7 +27,11 @@ class SystemTest: XCTestCase {
|
|||
do {
|
||||
_ = try withUnsafePointer(to: &randomBytes) { ptr in
|
||||
try readFD.withUnsafeFileDescriptor { readFD in
|
||||
try Posix.setsockopt(socket: readFD, level: -1, optionName: -1, optionValue: ptr, optionLen: 0)
|
||||
try NIOBSDSocket.setsockopt(socket: readFD,
|
||||
level: NIOBSDSocket.OptionLevel(rawValue: -1),
|
||||
option_name: NIOBSDSocket.Option(rawValue: -1),
|
||||
option_value: ptr,
|
||||
option_len: 0)
|
||||
}
|
||||
}
|
||||
XCTFail("success even though the call was invalid")
|
||||
|
|
Loading…
Reference in New Issue