Add `BSDSocket.SocketType` to represent the socket type (#1467)

This adds a new enumeration which encapsulates the socket type values.
This enables ports to provide the same surface with a different name as
necessary.
This commit is contained in:
Saleem Abdulrasool 2020-04-03 09:16:48 -07:00 committed by GitHub
parent bcc180dab6
commit 37b48094ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 87 additions and 58 deletions

View File

@ -39,6 +39,7 @@ let package = Package(
)
EOF
cp "$here/../../Tests/NIOTests/SystemCallWrapperHelpers.swift" \
"$here/../../Sources/NIO/BSDSocketAPI.swift" \
"$here/../../Sources/NIO/System.swift" \
"$here/../../Sources/NIO/IO.swift" \
"$tmpdir/syscallwrapper/Sources/syscallwrapper"

View File

@ -40,6 +40,9 @@ import let WinSDK.SO_RCVBUF
import let WinSDK.SO_RCVTIMEO
import let WinSDK.SO_REUSEADDR
import let WinSDK.SO_REUSE_UNICASTPORT
import let WinSDK.SOCK_DGRAM
import let WinSDK.SOCK_STREAM
#elseif os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
import Darwin
#else
@ -49,6 +52,23 @@ import Glibc
public enum NIOBSDSocket {
}
extension NIOBSDSocket {
/// Specifies the type of socket.
internal struct SocketType: RawRepresentable {
public typealias RawValue = CInt
public var rawValue: RawValue
public init(rawValue: RawValue) {
self.rawValue = rawValue
}
}
}
extension NIOBSDSocket.SocketType: Equatable {
}
extension NIOBSDSocket.SocketType: Hashable {
}
extension NIOBSDSocket {
/// Defines socket option levels.
public struct OptionLevel: RawRepresentable {
@ -83,6 +103,29 @@ extension NIOBSDSocket.Option: Equatable {
extension NIOBSDSocket.Option: Hashable {
}
// Socket Types
extension NIOBSDSocket.SocketType {
/// Supports datagrams, which are connectionless, unreliable messages of a
/// fixed (typically small) maximum length.
#if os(Linux)
internal static let dgram: NIOBSDSocket.SocketType =
NIOBSDSocket.SocketType(rawValue: CInt(SOCK_DGRAM.rawValue))
#else
internal static let dgram: NIOBSDSocket.SocketType =
NIOBSDSocket.SocketType(rawValue: SOCK_DGRAM)
#endif
/// Supports reliable, two-way, connection-based byte streams without
/// duplication of data and without preservation of boundaries.
#if os(Linux)
internal static let stream: NIOBSDSocket.SocketType =
NIOBSDSocket.SocketType(rawValue: CInt(SOCK_STREAM.rawValue))
#else
internal static let stream: NIOBSDSocket.SocketType =
NIOBSDSocket.SocketType(rawValue: SOCK_STREAM)
#endif
}
// Option Level
extension NIOBSDSocket.OptionLevel {
/// Socket options that apply only to IP sockets.

View File

@ -252,15 +252,15 @@ 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: Int32, type: CInt, setNonBlocking: Bool = false) throws -> CInt {
var sockType = type
static func makeSocket(protocolFamily: Int32, type: NIOBSDSocket.SocketType, setNonBlocking: Bool = false) throws -> CInt {
var sockType: CInt = type.rawValue
#if os(Linux)
if setNonBlocking {
sockType = type | Linux.SOCK_NONBLOCK
sockType = type.rawValue | Linux.SOCK_NONBLOCK
}
#endif
let sock = try Posix.socket(domain: protocolFamily,
type: sockType,
type: NIOBSDSocket.SocketType(rawValue: sockType),
protocol: 0)
#if !os(Linux)
if setNonBlocking {

View File

@ -530,7 +530,7 @@ public final class ClientBootstrap: NIOClientTCPBootstrapProtocol {
/// - returns: An `EventLoopFuture<Channel>` to deliver the `Channel` when connected.
public func connect(host: String, port: Int) -> EventLoopFuture<Channel> {
let loop = self.group.next()
let connector = HappyEyeballsConnector(resolver: resolver ?? GetaddrinfoResolver(loop: loop, aiSocktype: Posix.SOCK_STREAM, aiProtocol: CInt(IPPROTO_TCP)),
let connector = HappyEyeballsConnector(resolver: resolver ?? GetaddrinfoResolver(loop: loop, aiSocktype: .stream, aiProtocol: CInt(IPPROTO_TCP)),
loop: loop,
host: host,
port: port,

View File

@ -26,7 +26,7 @@ import CNIOLinux
internal class GetaddrinfoResolver: Resolver {
private let v4Future: EventLoopPromise<[SocketAddress]>
private let v6Future: EventLoopPromise<[SocketAddress]>
private let aiSocktype: CInt
private let aiSocktype: NIOBSDSocket.SocketType
private let aiProtocol: CInt
/// Create a new resolver.
@ -35,7 +35,7 @@ internal class GetaddrinfoResolver: Resolver {
/// - loop: The `EventLoop` whose thread this resolver will block.
/// - aiSocktype: The sock type to use as hint when calling getaddrinfo.
/// - aiProtocol: the protocol to use as hint when calling getaddrinfo.
init(loop: EventLoop, aiSocktype: CInt, aiProtocol: CInt) {
init(loop: EventLoop, aiSocktype: NIOBSDSocket.SocketType, aiProtocol: CInt) {
self.v4Future = loop.makePromise()
self.v6Future = loop.makePromise()
self.aiSocktype = aiSocktype
@ -88,7 +88,7 @@ internal class GetaddrinfoResolver: Resolver {
var info: UnsafeMutablePointer<addrinfo>?
var hint = addrinfo()
hint.ai_socktype = self.aiSocktype
hint.ai_socktype = self.aiSocktype.rawValue
hint.ai_protocol = self.aiProtocol
guard getaddrinfo(host, String(port), &hint, &info) == 0 else {
self.fail(SocketAddressError.unknown(host: host, port: port))

View File

@ -30,7 +30,7 @@
/// - setNonBlocking: Set non-blocking mode on the socket.
/// - throws: An `IOError` if creation of the socket failed.
init(protocolFamily: Int32, setNonBlocking: Bool = false) throws {
let sock = try BaseSocket.makeSocket(protocolFamily: protocolFamily, type: Posix.SOCK_STREAM, setNonBlocking: setNonBlocking)
let sock = try BaseSocket.makeSocket(protocolFamily: protocolFamily, type: .stream, setNonBlocking: setNonBlocking)
try super.init(descriptor: sock)
}

View File

@ -32,7 +32,7 @@ typealias IOVector = iovec
/// - type: The type of the socket to create.
/// - setNonBlocking: Set non-blocking mode on the socket.
/// - throws: An `IOError` if creation of the socket failed.
init(protocolFamily: CInt, type: CInt, setNonBlocking: Bool = false) throws {
init(protocolFamily: CInt, type: NIOBSDSocket.SocketType, setNonBlocking: Bool = false) throws {
let sock = try BaseSocket.makeSocket(protocolFamily: protocolFamily, type: type, setNonBlocking: setNonBlocking)
try super.init(descriptor: sock)
}

View File

@ -36,7 +36,7 @@ final class SocketChannel: BaseStreamSocketChannel<Socket> {
private var connectTimeout: TimeAmount? = nil
init(eventLoop: SelectableEventLoop, protocolFamily: Int32) throws {
let socket = try Socket(protocolFamily: protocolFamily, type: Posix.SOCK_STREAM, setNonBlocking: true)
let socket = try Socket(protocolFamily: protocolFamily, type: .stream, setNonBlocking: true)
try super.init(socket: socket, parent: nil, eventLoop: eventLoop, recvAllocator: AdaptiveRecvByteBufferAllocator())
}
@ -362,7 +362,7 @@ final class DatagramChannel: BaseSocketChannel<Socket> {
init(eventLoop: SelectableEventLoop, protocolFamily: Int32) throws {
self.vectorReadManager = nil
let socket = try Socket(protocolFamily: protocolFamily, type: Posix.SOCK_DGRAM)
let socket = try Socket(protocolFamily: protocolFamily, type: .dgram)
do {
try socket.setNonBlocking()
} catch let err {

View File

@ -179,32 +179,17 @@ enum Shutdown {
internal enum Posix {
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
static let SOCK_STREAM: CInt = CInt(Darwin.SOCK_STREAM)
static let SOCK_DGRAM: CInt = CInt(Darwin.SOCK_DGRAM)
static let UIO_MAXIOV: Int = 1024
static let SHUT_RD: CInt = CInt(Darwin.SHUT_RD)
static let SHUT_WR: CInt = CInt(Darwin.SHUT_WR)
static let SHUT_RDWR: CInt = CInt(Darwin.SHUT_RDWR)
#elseif os(Linux) || os(FreeBSD) || os(Android)
#if os(Android)
static let SOCK_STREAM: CInt = CInt(Glibc.SOCK_STREAM)
static let SOCK_DGRAM: CInt = CInt(Glibc.SOCK_DGRAM)
#else
static let SOCK_STREAM: CInt = CInt(Glibc.SOCK_STREAM.rawValue)
static let SOCK_DGRAM: CInt = CInt(Glibc.SOCK_DGRAM.rawValue)
#endif
static let UIO_MAXIOV: Int = Int(Glibc.UIO_MAXIOV)
static let SHUT_RD: CInt = CInt(Glibc.SHUT_RD)
static let SHUT_WR: CInt = CInt(Glibc.SHUT_WR)
static let SHUT_RDWR: CInt = CInt(Glibc.SHUT_RDWR)
#else
static var SOCK_STREAM: CInt {
fatalError("unsupported OS")
}
static var SOCK_DGRAM: CInt {
fatalError("unsupported OS")
}
static var UIO_MAXIOV: Int {
fatalError("unsupported OS")
}
@ -257,9 +242,9 @@ internal enum Posix {
}
@inline(never)
public static func socket(domain: CInt, type: CInt, `protocol`: CInt) throws -> CInt {
public static func socket(domain: CInt, type: NIOBSDSocket.SocketType, `protocol`: CInt) throws -> CInt {
return try syscall(blocking: false) {
return sysSocket(domain, type, `protocol`)
return sysSocket(domain, type.rawValue, `protocol`)
}.result
}
@ -516,11 +501,11 @@ internal enum Posix {
@inline(never)
public static func socketpair(domain: CInt,
type: CInt,
type: NIOBSDSocket.SocketType,
protocol: CInt,
socketVector: UnsafeMutablePointer<CInt>?) throws {
_ = try syscall(blocking: false) {
sysSocketpair(domain, type, `protocol`, socketVector)
sysSocketpair(domain, type.rawValue, `protocol`, socketVector)
}
}
}

View File

@ -150,7 +150,7 @@ class BootstrapTest: XCTestCase {
func testPreConnectedClientSocketToleratesFuturesFromDifferentEventLoopsReturnedInInitializers() throws {
var socketFDs: [CInt] = [-1, -1]
XCTAssertNoThrow(try Posix.socketpair(domain: PF_LOCAL,
type: Posix.SOCK_STREAM,
type: .stream,
protocol: 0,
socketVector: &socketFDs))
defer {
@ -170,7 +170,7 @@ class BootstrapTest: XCTestCase {
}
func testPreConnectedServerSocketToleratesFuturesFromDifferentEventLoopsReturnedInInitializers() throws {
let socket = try Posix.socket(domain: AF_INET, type: Posix.SOCK_STREAM, protocol: 0)
let socket = try Posix.socket(domain: AF_INET, type: .stream, protocol: 0)
let serverAddress = try assertNoThrowWithValue(SocketAddress.makeAddressResolvingHost("127.0.0.1", port: 0))
try serverAddress.withSockAddr { serverAddressPtr, size in
@ -309,7 +309,7 @@ class BootstrapTest: XCTestCase {
func testPreConnectedSocketSetsChannelOptionsBeforeChannelInitializer() {
XCTAssertNoThrow(try withTCPServerChannel(group: self.group) { server in
var maybeSocket: Socket? = nil
XCTAssertNoThrow(maybeSocket = try Socket(protocolFamily: AF_INET, type: Posix.SOCK_STREAM))
XCTAssertNoThrow(maybeSocket = try Socket(protocolFamily: AF_INET, type: .stream))
XCTAssertNoThrow(XCTAssertEqual(true, try maybeSocket?.connect(to: server.localAddress!)))
var maybeFD: CInt? = nil
XCTAssertNoThrow(maybeFD = try maybeSocket?.takeDescriptorOwnership())

View File

@ -1852,7 +1852,7 @@ public final class ChannelTests: XCTestCase {
func testChannelReadsDoesNotHappenAfterRegistration() throws {
class SocketThatSucceedsOnSecondConnectForPort123: Socket {
init(protocolFamily: CInt) throws {
try super.init(protocolFamily: protocolFamily, type: Posix.SOCK_STREAM, setNonBlocking: true)
try super.init(protocolFamily: protocolFamily, type: .stream, setNonBlocking: true)
}
override func connect(to address: SocketAddress) throws -> Bool {
if address.port == 123 {
@ -2025,7 +2025,7 @@ public final class ChannelTests: XCTestCase {
class SocketThatHasTheFirstReadSucceedButFailsTheNextWithECONNRESET: Socket {
private var firstReadHappened = false
init(protocolFamily: CInt) throws {
try super.init(protocolFamily: protocolFamily, type: Posix.SOCK_STREAM, setNonBlocking: true)
try super.init(protocolFamily: protocolFamily, type: .stream, setNonBlocking: true)
}
override func read(pointer: UnsafeMutableRawBufferPointer) throws -> IOResult<Int> {
defer {
@ -2131,7 +2131,7 @@ public final class ChannelTests: XCTestCase {
enum DummyError: Error { case dummy }
class SocketFailingAsyncConnect: Socket {
init() throws {
try super.init(protocolFamily: PF_INET, type: Posix.SOCK_STREAM, setNonBlocking: true)
try super.init(protocolFamily: PF_INET, type: .stream, setNonBlocking: true)
}
override func connect(to address: SocketAddress) throws -> Bool {
@ -2177,7 +2177,7 @@ public final class ChannelTests: XCTestCase {
enum DummyError: Error { case dummy }
class SocketFailingConnect: Socket {
init() throws {
try super.init(protocolFamily: PF_INET, type: Posix.SOCK_STREAM, setNonBlocking: true)
try super.init(protocolFamily: PF_INET, type: .stream, setNonBlocking: true)
}
override func connect(to address: SocketAddress) throws -> Bool {
@ -2225,7 +2225,7 @@ public final class ChannelTests: XCTestCase {
defer {
XCTAssertNoThrow(try group.syncShutdownGracefully())
}
let serverSock = try Socket(protocolFamily: PF_INET, type: Posix.SOCK_STREAM)
let serverSock = try Socket(protocolFamily: PF_INET, type: .stream)
// we deliberately don't set SO_REUSEADDR
XCTAssertNoThrow(try serverSock.bind(to: SocketAddress(ipAddress: "127.0.0.1", port: 0)))
let serverSockAddress = try! serverSock.localAddress()
@ -2244,7 +2244,7 @@ public final class ChannelTests: XCTestCase {
enum DummyError: Error { case dummy }
class SocketFailingClose: Socket {
init() throws {
try super.init(protocolFamily: PF_INET, type: Posix.SOCK_STREAM, setNonBlocking: true)
try super.init(protocolFamily: PF_INET, type: .stream, setNonBlocking: true)
}
override func close() throws {
@ -2439,7 +2439,7 @@ public final class ChannelTests: XCTestCase {
final class WriteAlwaysFailingSocket: Socket {
init() throws {
try super.init(protocolFamily: AF_INET, type: Posix.SOCK_STREAM, setNonBlocking: true)
try super.init(protocolFamily: AF_INET, type: .stream, setNonBlocking: true)
}
override func write(pointer: UnsafeRawBufferPointer) throws -> IOResult<Int> {

View File

@ -386,7 +386,7 @@ final class DatagramChannelTests: XCTestCase {
init(error: Int32) throws {
self.error = error
try super.init(protocolFamily: AF_INET, type: Posix.SOCK_DGRAM)
try super.init(protocolFamily: AF_INET, type: .dgram)
}
override func recvfrom(pointer: UnsafeMutableRawBufferPointer, storage: inout sockaddr_storage, storageLen: inout socklen_t) throws -> IOResult<(Int)> {
@ -462,7 +462,7 @@ final class DatagramChannelTests: XCTestCase {
init(error: Int32) throws {
self.error = error
try super.init(protocolFamily: AF_INET, type: Posix.SOCK_DGRAM)
try super.init(protocolFamily: AF_INET, type: .dgram)
}
override func recvmmsg(msgs: UnsafeMutableBufferPointer<MMsgHdr>) throws -> IOResult<Int> {

View File

@ -23,7 +23,7 @@ class GetaddrinfoResolverTest: XCTestCase {
XCTAssertNoThrow(try group.syncShutdownGracefully())
}
let resolver = GetaddrinfoResolver(loop: group.next(), aiSocktype: Posix.SOCK_STREAM, aiProtocol: CInt(IPPROTO_TCP))
let resolver = GetaddrinfoResolver(loop: group.next(), aiSocktype: .stream, aiProtocol: CInt(IPPROTO_TCP))
let v4Future = resolver.initiateAQuery(host: "127.0.0.1", port: 12345)
let v6Future = resolver.initiateAAAAQuery(host: "127.0.0.1", port: 12345)
@ -40,7 +40,7 @@ class GetaddrinfoResolverTest: XCTestCase {
XCTAssertNoThrow(try group.syncShutdownGracefully())
}
let resolver = GetaddrinfoResolver(loop: group.next(), aiSocktype: Posix.SOCK_STREAM, aiProtocol: CInt(IPPROTO_TCP))
let resolver = GetaddrinfoResolver(loop: group.next(), aiSocktype: .stream, aiProtocol: CInt(IPPROTO_TCP))
let v4Future = resolver.initiateAQuery(host: "::1", port: 12345)
let v6Future = resolver.initiateAAAAQuery(host: "::1", port: 12345)

View File

@ -191,7 +191,7 @@ class NonBlockingFileIOTest: XCTestCase {
func testFailedIO() throws {
enum DummyError: Error { case dummy }
let unconnectedSockFH = NIOFileHandle(descriptor: socket(AF_UNIX, Posix.SOCK_STREAM, 0))
let unconnectedSockFH = NIOFileHandle(descriptor: try! Posix.socket(domain: AF_UNIX, type: .stream, protocol: 0))
defer {
XCTAssertNoThrow(try unconnectedSockFH.close())
}

View File

@ -37,7 +37,7 @@ class SelectorTest: XCTestCase {
XCTAssertNoThrow(try selector.close())
}
let socket1 = try Socket(protocolFamily: PF_INET, type: Posix.SOCK_STREAM)
let socket1 = try Socket(protocolFamily: PF_INET, type: .stream)
defer {
if socket1.isOpen {
XCTAssertNoThrow(try socket1.close())
@ -45,7 +45,7 @@ class SelectorTest: XCTestCase {
}
try socket1.setNonBlocking()
let socket2 = try Socket(protocolFamily: PF_INET, type: Posix.SOCK_STREAM)
let socket2 = try Socket(protocolFamily: PF_INET, type: .stream)
defer {
if socket2.isOpen {
XCTAssertNoThrow(try socket2.close())
@ -387,7 +387,7 @@ class SelectorTest: XCTestCase {
}
var socketFDs: [CInt] = [-1, -1]
XCTAssertNoThrow(try Posix.socketpair(domain: PF_LOCAL,
type: Posix.SOCK_STREAM,
type: .stream,
protocol: 0,
socketVector: &socketFDs))

View File

@ -220,7 +220,7 @@ public final class SocketChannelTest : XCTestCase {
private let promise: EventLoopPromise<Void>
init(promise: EventLoopPromise<Void>) throws {
self.promise = promise
try super.init(protocolFamily: PF_INET, type: Posix.SOCK_STREAM)
try super.init(protocolFamily: PF_INET, type: .stream)
}
override func connect(to address: SocketAddress) throws -> Bool {
@ -327,7 +327,7 @@ public final class SocketChannelTest : XCTestCase {
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
defer { XCTAssertNoThrow(try group.syncShutdownGracefully()) }
let serverSock = try Socket(protocolFamily: AF_INET, type: Posix.SOCK_STREAM)
let serverSock = try Socket(protocolFamily: AF_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))
@ -335,7 +335,7 @@ public final class SocketChannelTest : XCTestCase {
try serverSock.close()
let serverChannel = try serverChannelFuture.wait()
let clientSock = try Socket(protocolFamily: AF_INET, type: Posix.SOCK_STREAM)
let clientSock = try Socket(protocolFamily: AF_INET, type: .stream)
let connected = try clientSock.connect(to: serverChannel.localAddress!)
XCTAssertEqual(connected, true)
let clientChannelFuture = try clientSock.withUnsafeHandle {
@ -354,7 +354,7 @@ public final class SocketChannelTest : XCTestCase {
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
defer { XCTAssertNoThrow(try group.syncShutdownGracefully()) }
let serverSock = try Socket(protocolFamily: AF_INET, type: Posix.SOCK_DGRAM)
let serverSock = try Socket(protocolFamily: AF_INET, type: .dgram)
try serverSock.bind(to: SocketAddress(ipAddress: "127.0.0.1", port: 0))
let serverChannelFuture = try serverSock.withUnsafeHandle {
DatagramBootstrap(group: group).withBoundSocket(descriptor: dup($0))
@ -417,7 +417,7 @@ public final class SocketChannelTest : XCTestCase {
let promise: EventLoopPromise<Void>
init(promise: EventLoopPromise<Void>) throws {
self.promise = promise
try super.init(protocolFamily: PF_INET, type: Posix.SOCK_STREAM)
try super.init(protocolFamily: PF_INET, type: .stream)
}
override func connect(to address: SocketAddress) throws -> Bool {
@ -585,7 +585,7 @@ public final class SocketChannelTest : XCTestCase {
.wait())
// Make a client socket to mess with the server. Setting SO_LINGER forces RST instead of FIN.
let clientSocket = try assertNoThrowWithValue(Socket(protocolFamily: AF_INET, type: Posix.SOCK_STREAM))
let clientSocket = try assertNoThrowWithValue(Socket(protocolFamily: AF_INET, type: .stream))
XCTAssertNoThrow(try clientSocket.setOption(level: .socket, name: .linger, value: linger(l_onoff: 1, l_linger: 0)))
XCTAssertNoThrow(try clientSocket.connect(to: serverChannel.localAddress!))
XCTAssertNoThrow(try clientSocket.close())
@ -635,7 +635,7 @@ public final class SocketChannelTest : XCTestCase {
func testSetSockOptDoesNotOverrideExistingFlags() throws {
let s = try assertNoThrowWithValue(Socket(protocolFamily: PF_INET,
type: Posix.SOCK_STREAM,
type: .stream,
setNonBlocking: false))
// check initial flags
XCTAssertNoThrow(try s.withUnsafeHandle { fd in
@ -675,7 +675,7 @@ public final class SocketChannelTest : XCTestCase {
throw NIOFailedToSetSocketNonBlockingError()
} else {
return try Socket(protocolFamily: PF_INET,
type: Posix.SOCK_STREAM,
type: .stream,
setNonBlocking: false)
}
}

View File

@ -270,7 +270,7 @@ func resolverDebugInformation(eventLoop: EventLoop, host: String, previouslyRece
return addr.addressDescription()
}
}
let res = GetaddrinfoResolver(loop: eventLoop, aiSocktype: Posix.SOCK_STREAM, aiProtocol: CInt(IPPROTO_TCP))
let res = GetaddrinfoResolver(loop: eventLoop, aiSocktype: .stream, aiProtocol: CInt(IPPROTO_TCP))
let ipv6Results = try assertNoThrowWithValue(res.initiateAAAAQuery(host: host, port: 0).wait()).map(printSocketAddress)
let ipv4Results = try assertNoThrowWithValue(res.initiateAQuery(host: host, port: 0).wait()).map(printSocketAddress)