NIO: split out `FileDescriptor` and `Selectable` (#1444)
A `FileDescriptor` is not necessarily selectable (e.g. Windows), and a selectable is not necessarily a `FileDescriptor` (e.g. Windows). This will allow a basic `Selector` on Windows which will use `WSASelect` to select on sockets for some basic functionality even though IOCompletionPorts are preferred.
This commit is contained in:
parent
2673be6ae3
commit
834a5f2185
|
@ -206,7 +206,7 @@ extension sockaddr_storage {
|
|||
/// Base class for sockets.
|
||||
///
|
||||
/// This should not be created directly but one of its sub-classes should be used, like `ServerSocket` or `Socket`.
|
||||
class BaseSocket: Selectable, BaseSocketProtocol {
|
||||
class BaseSocket: BaseSocketProtocol {
|
||||
typealias SelectableType = BaseSocket
|
||||
|
||||
private var descriptor: CInt
|
||||
|
@ -214,13 +214,6 @@ class BaseSocket: Selectable, BaseSocketProtocol {
|
|||
return descriptor >= 0
|
||||
}
|
||||
|
||||
func withUnsafeFileDescriptor<T>(_ body: (CInt) throws -> T) throws -> T {
|
||||
guard self.isOpen else {
|
||||
throw IOError(errnoCode: EBADF, reason: "file descriptor already closed!")
|
||||
}
|
||||
return try body(descriptor)
|
||||
}
|
||||
|
||||
/// Returns the local bound `SocketAddress` of the socket.
|
||||
///
|
||||
/// - returns: The local bound address.
|
||||
|
@ -244,8 +237,8 @@ class BaseSocket: Selectable, BaseSocketProtocol {
|
|||
try addr.withMutableSockAddr { addressPtr, size in
|
||||
var size = socklen_t(size)
|
||||
|
||||
try withUnsafeFileDescriptor { fd in
|
||||
try body(fd, addressPtr, &size)
|
||||
try self.withUnsafeHandle {
|
||||
try body($0, addressPtr, &size)
|
||||
}
|
||||
}
|
||||
return addr.convert()
|
||||
|
@ -272,7 +265,7 @@ class BaseSocket: Selectable, BaseSocketProtocol {
|
|||
#if !os(Linux)
|
||||
if setNonBlocking {
|
||||
do {
|
||||
try BaseSocket.setNonBlocking(fileDescriptor: sock)
|
||||
try Posix.setNonBlocking(socket: sock)
|
||||
} catch {
|
||||
// best effort close
|
||||
try? Posix.close(descriptor: sock)
|
||||
|
@ -325,8 +318,8 @@ class BaseSocket: Selectable, BaseSocketProtocol {
|
|||
///
|
||||
/// throws: An `IOError` if the operation failed.
|
||||
final func setNonBlocking() throws {
|
||||
return try withUnsafeFileDescriptor { fd in
|
||||
try BaseSocket.setNonBlocking(fileDescriptor: fd)
|
||||
return try self.withUnsafeHandle {
|
||||
try Posix.setNonBlocking(socket: $0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -345,11 +338,11 @@ class BaseSocket: Selectable, BaseSocketProtocol {
|
|||
// most socket options settings so for the time being we'll just ignore this. Let's revisit for NIO 2.0.
|
||||
return
|
||||
}
|
||||
return try withUnsafeFileDescriptor { fd in
|
||||
return try self.withUnsafeHandle {
|
||||
var val = value
|
||||
|
||||
try Posix.setsockopt(
|
||||
socket: fd,
|
||||
socket: $0,
|
||||
level: level,
|
||||
optionName: name,
|
||||
optionValue: &val,
|
||||
|
@ -366,7 +359,7 @@ class BaseSocket: Selectable, BaseSocketProtocol {
|
|||
/// - name: The name of the option to set.
|
||||
/// - throws: An `IOError` if the operation failed.
|
||||
final func getOption<T>(level: Int32, name: Int32) throws -> T {
|
||||
return try withUnsafeFileDescriptor { fd in
|
||||
return try self.withUnsafeHandle { fd in
|
||||
var length = socklen_t(MemoryLayout<T>.size)
|
||||
let storage = UnsafeMutableRawBufferPointer.allocate(byteCount: MemoryLayout<T>.stride,
|
||||
alignment: MemoryLayout<T>.alignment)
|
||||
|
@ -390,7 +383,7 @@ class BaseSocket: Selectable, BaseSocketProtocol {
|
|||
/// - address: The `SocketAddress` to which the socket should be bound.
|
||||
/// - throws: An `IOError` if the operation failed.
|
||||
final func bind(to address: SocketAddress) throws {
|
||||
try withUnsafeFileDescriptor { fd in
|
||||
try self.withUnsafeHandle { fd in
|
||||
func doBind(ptr: UnsafePointer<sockaddr>, bytes: Int) throws {
|
||||
try Posix.bind(descriptor: fd, ptr: ptr, bytes: bytes)
|
||||
}
|
||||
|
@ -425,13 +418,22 @@ class BaseSocket: Selectable, BaseSocketProtocol {
|
|||
///
|
||||
/// - throws: An `IOError` if the operation failed.
|
||||
final func takeDescriptorOwnership() throws -> CInt {
|
||||
return try withUnsafeFileDescriptor { fd in
|
||||
return try self.withUnsafeHandle {
|
||||
self.descriptor = -1
|
||||
return fd
|
||||
return $0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension BaseSocket: Selectable {
|
||||
func withUnsafeHandle<T>(_ body: (CInt) throws -> T) throws -> T {
|
||||
guard self.isOpen else {
|
||||
throw IOError(errnoCode: EBADF, reason: "file descriptor already closed!")
|
||||
}
|
||||
return try body(self.descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
extension BaseSocket: CustomStringConvertible {
|
||||
var description: String {
|
||||
return "BaseSocket { fd=\(self.descriptor) }"
|
||||
|
|
|
@ -350,13 +350,6 @@ public enum ChannelError: Error {
|
|||
|
||||
extension ChannelError: Equatable { }
|
||||
|
||||
/// `NIOFailedToSetSocketNonBlockingError` indicates that NIO was unable to set a socket to non-blocking mode, either
|
||||
/// when connecting a socket as a client or when accepting a socket as a server.
|
||||
///
|
||||
/// This error should never happen because a socket should always be able to be set to non-blocking mode. Unfortunately,
|
||||
/// we have seen this happen on Darwin.
|
||||
public struct NIOFailedToSetSocketNonBlockingError: Error {}
|
||||
|
||||
/// The removal of a `ChannelHandler` using `ChannelPipeline.removeHandler` has been attempted more than once.
|
||||
public struct NIOAttemptedToRemoveHandlerMultipleTimesError: Error {}
|
||||
|
||||
|
|
|
@ -12,18 +12,37 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
extension NIOFileHandle: Selectable {
|
||||
struct SelectableFileHandle {
|
||||
var handle: NIOFileHandle
|
||||
|
||||
var isOpen: Bool {
|
||||
return handle.isOpen
|
||||
}
|
||||
|
||||
init(_ handle: NIOFileHandle) {
|
||||
self.handle = handle
|
||||
}
|
||||
|
||||
func close() throws {
|
||||
try handle.close()
|
||||
}
|
||||
}
|
||||
|
||||
extension SelectableFileHandle: Selectable {
|
||||
func withUnsafeHandle<T>(_ body: (CInt) throws -> T) throws -> T {
|
||||
return try self.handle.withUnsafeFileDescriptor(body)
|
||||
}
|
||||
}
|
||||
|
||||
final class PipePair: SocketProtocol {
|
||||
typealias SelectableType = NIOFileHandle
|
||||
typealias SelectableType = SelectableFileHandle
|
||||
|
||||
let inputFD: NIOFileHandle
|
||||
let outputFD: NIOFileHandle
|
||||
let inputFD: SelectableFileHandle
|
||||
let outputFD: SelectableFileHandle
|
||||
|
||||
init(inputFD: NIOFileHandle, outputFD: NIOFileHandle) throws {
|
||||
self.inputFD = inputFD
|
||||
self.outputFD = outputFD
|
||||
self.inputFD = SelectableFileHandle(inputFD)
|
||||
self.outputFD = SelectableFileHandle(outputFD)
|
||||
try self.ignoreSIGPIPE()
|
||||
for fileHandle in [inputFD, outputFD] {
|
||||
try fileHandle.withUnsafeFileDescriptor {
|
||||
|
@ -34,7 +53,7 @@ final class PipePair: SocketProtocol {
|
|||
|
||||
func ignoreSIGPIPE() throws {
|
||||
for fileHandle in [self.inputFD, self.outputFD] {
|
||||
try fileHandle.withUnsafeFileDescriptor {
|
||||
try fileHandle.withUnsafeHandle {
|
||||
try PipePair.ignoreSIGPIPE(descriptor: $0)
|
||||
}
|
||||
}
|
||||
|
@ -53,14 +72,14 @@ final class PipePair: SocketProtocol {
|
|||
}
|
||||
|
||||
func write(pointer: UnsafeRawBufferPointer) throws -> IOResult<Int> {
|
||||
return try self.outputFD.withUnsafeFileDescriptor { fd in
|
||||
try Posix.write(descriptor: fd, pointer: pointer.baseAddress!, size: pointer.count)
|
||||
return try self.outputFD.withUnsafeHandle {
|
||||
try Posix.write(descriptor: $0, pointer: pointer.baseAddress!, size: pointer.count)
|
||||
}
|
||||
}
|
||||
|
||||
func writev(iovecs: UnsafeBufferPointer<IOVector>) throws -> IOResult<Int> {
|
||||
return try self.outputFD.withUnsafeFileDescriptor { fd in
|
||||
try Posix.writev(descriptor: fd, iovecs: iovecs)
|
||||
return try self.outputFD.withUnsafeHandle {
|
||||
try Posix.writev(descriptor: $0, iovecs: iovecs)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,8 +88,8 @@ final class PipePair: SocketProtocol {
|
|||
}
|
||||
|
||||
func read(pointer: UnsafeMutableRawBufferPointer) throws -> IOResult<Int> {
|
||||
return try self.inputFD.withUnsafeFileDescriptor { fd in
|
||||
try Posix.read(descriptor: fd, pointer: pointer.baseAddress!, size: pointer.count)
|
||||
return try self.inputFD.withUnsafeHandle {
|
||||
try Posix.read(descriptor: $0, pointer: pointer.baseAddress!, size: pointer.count)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,8 +12,12 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Represents a selectable resource which can be registered to a `Selector` to be notified once there are some events ready for it.
|
||||
/// Represents a selectable resource which can be registered to a `Selector` to
|
||||
/// be notified once there are some events ready for it.
|
||||
///
|
||||
/// - warning: `Selectable`s are not thread-safe, only to be used on the appropriate `EventLoop`.
|
||||
protocol Selectable: FileDescriptor {
|
||||
/// - warning:
|
||||
/// `Selectable`s are not thread-safe, only to be used on the appropriate
|
||||
/// `EventLoop`.
|
||||
protocol Selectable {
|
||||
func withUnsafeHandle<T>(_: (CInt) throws -> T) throws -> T
|
||||
}
|
||||
|
|
|
@ -410,9 +410,9 @@ internal class Selector<R: Registration> {
|
|||
assert(interested.contains(.reset))
|
||||
assert(oldInterested?.contains(.reset) ?? true)
|
||||
|
||||
try selectable.withUnsafeFileDescriptor { fd in
|
||||
try selectable.withUnsafeHandle {
|
||||
try newKQueueFilters.calculateKQueueFilterSetChanges(previousKQueueFilterSet: oldKQueueFilters,
|
||||
fileDescriptor: fd,
|
||||
fileDescriptor: $0,
|
||||
kqueueApplyEventChangeSet)
|
||||
}
|
||||
}
|
||||
|
@ -431,7 +431,7 @@ internal class Selector<R: Registration> {
|
|||
throw IOError(errnoCode: EBADF, reason: "can't register on selector as it's \(self.lifecycleState).")
|
||||
}
|
||||
|
||||
try selectable.withUnsafeFileDescriptor { fd in
|
||||
try selectable.withUnsafeHandle { fd in
|
||||
assert(registrations[Int(fd)] == nil)
|
||||
#if os(Linux)
|
||||
var ev = Epoll.epoll_event()
|
||||
|
@ -457,7 +457,7 @@ internal class Selector<R: Registration> {
|
|||
throw IOError(errnoCode: EBADF, reason: "can't re-register on selector as it's \(self.lifecycleState).")
|
||||
}
|
||||
assert(interested.contains(.reset), "must register for at least .reset but tried registering for \(interested)")
|
||||
try selectable.withUnsafeFileDescriptor { fd in
|
||||
try selectable.withUnsafeHandle { fd in
|
||||
var reg = registrations[Int(fd)]!
|
||||
|
||||
#if os(Linux)
|
||||
|
@ -487,7 +487,7 @@ internal class Selector<R: Registration> {
|
|||
}
|
||||
// temporary workaround to stop us delivering outdated events
|
||||
self.deregistrationsHappened = true
|
||||
try selectable.withUnsafeFileDescriptor { fd in
|
||||
try selectable.withUnsafeHandle { fd in
|
||||
guard let reg = registrations.removeValue(forKey: Int(fd)) else {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -53,8 +53,8 @@
|
|||
/// - backlog: The backlog to use.
|
||||
/// - throws: An `IOError` if creation of the socket failed.
|
||||
func listen(backlog: Int32 = 128) throws {
|
||||
try withUnsafeFileDescriptor { fd in
|
||||
_ = try Posix.listen(descriptor: fd, backlog: backlog)
|
||||
try withUnsafeHandle {
|
||||
_ = try Posix.listen(descriptor: $0, backlog: backlog)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@
|
|||
/// - returns: A `Socket` once a new connection was established or `nil` if this `ServerSocket` is in non-blocking mode and there is no new connection that can be accepted when this method is called.
|
||||
/// - throws: An `IOError` if the operation failed.
|
||||
func accept(setNonBlocking: Bool = false) throws -> Socket? {
|
||||
return try withUnsafeFileDescriptor { fd in
|
||||
return try withUnsafeHandle { fd in
|
||||
#if os(Linux)
|
||||
let flags: Int32
|
||||
if setNonBlocking {
|
||||
|
|
|
@ -80,7 +80,7 @@ typealias IOVector = iovec
|
|||
|
||||
/// Private helper function to handle connection attempts.
|
||||
private func connectSocket<T>(addr: T) throws -> Bool {
|
||||
return try withUnsafeFileDescriptor { fd in
|
||||
return try withUnsafeHandle { fd in
|
||||
var addr = addr
|
||||
return try withUnsafePointer(to: &addr) { ptr in
|
||||
try ptr.withMemoryRebound(to: sockaddr.self, capacity: 1) { ptr in
|
||||
|
@ -107,8 +107,8 @@ typealias IOVector = iovec
|
|||
/// - returns: The `IOResult` which indicates how much data could be written and if the operation returned before all could be written (because the socket is in non-blocking mode).
|
||||
/// - throws: An `IOError` if the operation failed.
|
||||
func write(pointer: UnsafeRawBufferPointer) throws -> IOResult<Int> {
|
||||
return try withUnsafeFileDescriptor { fd in
|
||||
try Posix.write(descriptor: fd, pointer: pointer.baseAddress!, size: pointer.count)
|
||||
return try withUnsafeHandle {
|
||||
try Posix.write(descriptor: $0, pointer: pointer.baseAddress!, size: pointer.count)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,8 +119,8 @@ typealias IOVector = iovec
|
|||
/// - returns: The `IOResult` which indicates how much data could be written and if the operation returned before all could be written (because the socket is in non-blocking mode).
|
||||
/// - throws: An `IOError` if the operation failed.
|
||||
func writev(iovecs: UnsafeBufferPointer<IOVector>) throws -> IOResult<Int> {
|
||||
return try withUnsafeFileDescriptor { fd in
|
||||
try Posix.writev(descriptor: fd, iovecs: iovecs)
|
||||
return try withUnsafeHandle {
|
||||
try Posix.writev(descriptor: $0, iovecs: iovecs)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,8 +132,8 @@ typealias IOVector = iovec
|
|||
/// - returns: The `IOResult` which indicates how much data could be written and if the operation returned before all could be written (because the socket is in non-blocking mode).
|
||||
/// - throws: An `IOError` if the operation failed.
|
||||
func sendto(pointer: UnsafeRawBufferPointer, destinationPtr: UnsafePointer<sockaddr>, destinationSize: socklen_t) throws -> IOResult<Int> {
|
||||
return try withUnsafeFileDescriptor { fd in
|
||||
try Posix.sendto(descriptor: fd, pointer: UnsafeMutableRawPointer(mutating: pointer.baseAddress!),
|
||||
return try withUnsafeHandle {
|
||||
try Posix.sendto(descriptor: $0, pointer: UnsafeMutableRawPointer(mutating: pointer.baseAddress!),
|
||||
size: pointer.count, destinationPtr: destinationPtr,
|
||||
destinationSize: destinationSize)
|
||||
}
|
||||
|
@ -146,8 +146,8 @@ typealias IOVector = iovec
|
|||
/// - returns: The `IOResult` which indicates how much data could be read and if the operation returned before all could be read (because the socket is in non-blocking mode).
|
||||
/// - throws: An `IOError` if the operation failed.
|
||||
func read(pointer: UnsafeMutableRawBufferPointer) throws -> IOResult<Int> {
|
||||
return try withUnsafeFileDescriptor { fd in
|
||||
try Posix.read(descriptor: fd, pointer: pointer.baseAddress!, size: pointer.count)
|
||||
return try withUnsafeHandle {
|
||||
try Posix.read(descriptor: $0, pointer: pointer.baseAddress!, size: pointer.count)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,7 +160,7 @@ typealias IOVector = iovec
|
|||
/// - returns: The `IOResult` which indicates how much data could be received and if the operation returned before all could be received (because the socket is in non-blocking mode).
|
||||
/// - throws: An `IOError` if the operation failed.
|
||||
func recvfrom(pointer: UnsafeMutableRawBufferPointer, storage: inout sockaddr_storage, storageLen: inout socklen_t) throws -> IOResult<(Int)> {
|
||||
return try withUnsafeFileDescriptor { fd in
|
||||
return try withUnsafeHandle { fd in
|
||||
try storage.withMutableSockAddr { (storagePtr, _) in
|
||||
try Posix.recvfrom(descriptor: fd, pointer: pointer.baseAddress!,
|
||||
len: pointer.count,
|
||||
|
@ -179,8 +179,8 @@ typealias IOVector = iovec
|
|||
/// - returns: The `IOResult` which indicates how much data could be send and if the operation returned before all could be send (because the socket is in non-blocking mode).
|
||||
/// - throws: An `IOError` if the operation failed.
|
||||
func sendFile(fd: Int32, offset: Int, count: Int) throws -> IOResult<Int> {
|
||||
return try withUnsafeFileDescriptor { desc in
|
||||
try Posix.sendfile(descriptor: desc, fd: fd, offset: off_t(offset), count: count)
|
||||
return try withUnsafeHandle {
|
||||
try Posix.sendfile(descriptor: $0, fd: fd, offset: off_t(offset), count: count)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,8 +191,8 @@ typealias IOVector = iovec
|
|||
/// - returns: The `IOResult` which indicates how many messages could be received and if the operation returned before all messages could be received (because the socket is in non-blocking mode).
|
||||
/// - throws: An `IOError` if the operation failed.
|
||||
func recvmmsg(msgs: UnsafeMutableBufferPointer<MMsgHdr>) throws -> IOResult<Int> {
|
||||
return try withUnsafeFileDescriptor { fd in
|
||||
try Posix.recvmmsg(sockfd: fd, msgvec: msgs.baseAddress!, vlen: CUnsignedInt(msgs.count), flags: 0, timeout: nil)
|
||||
return try withUnsafeHandle {
|
||||
try Posix.recvmmsg(sockfd: $0, msgvec: msgs.baseAddress!, vlen: CUnsignedInt(msgs.count), flags: 0, timeout: nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -203,8 +203,8 @@ typealias IOVector = iovec
|
|||
/// - returns: The `IOResult` which indicates how many messages could be send and if the operation returned before all messages could be send (because the socket is in non-blocking mode).
|
||||
/// - throws: An `IOError` if the operation failed.
|
||||
func sendmmsg(msgs: UnsafeMutableBufferPointer<MMsgHdr>) throws -> IOResult<Int> {
|
||||
return try withUnsafeFileDescriptor { fd in
|
||||
try Posix.sendmmsg(sockfd: fd, msgvec: msgs.baseAddress!, vlen: CUnsignedInt(msgs.count), flags: 0)
|
||||
return try withUnsafeHandle {
|
||||
try Posix.sendmmsg(sockfd: $0, msgvec: msgs.baseAddress!, vlen: CUnsignedInt(msgs.count), flags: 0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,8 +214,8 @@ typealias IOVector = iovec
|
|||
/// - how: the mode of `Shutdown`.
|
||||
/// - throws: An `IOError` if the operation failed.
|
||||
func shutdown(how: Shutdown) throws {
|
||||
return try withUnsafeFileDescriptor { fd in
|
||||
try Posix.shutdown(descriptor: fd, how: how)
|
||||
return try withUnsafeHandle {
|
||||
try Posix.shutdown(descriptor: $0, how: how)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -538,6 +538,29 @@ internal enum Posix {
|
|||
}
|
||||
}
|
||||
|
||||
/// `NIOFailedToSetSocketNonBlockingError` indicates that NIO was unable to set a socket to non-blocking mode, either
|
||||
/// when connecting a socket as a client or when accepting a socket as a server.
|
||||
///
|
||||
/// This error should never happen because a socket should always be able to be set to non-blocking mode. Unfortunately,
|
||||
/// we have seen this happen on Darwin.
|
||||
public struct NIOFailedToSetSocketNonBlockingError: Error {}
|
||||
|
||||
internal extension Posix {
|
||||
static func setNonBlocking(socket: CInt) throws {
|
||||
let flags = try Posix.fcntl(descriptor: socket, command: F_GETFL, value: 0)
|
||||
do {
|
||||
let ret = try Posix.fcntl(descriptor: socket, command: F_SETFL, value: flags | O_NONBLOCK)
|
||||
assert(ret == 0, "unexpectedly, fcntl(\(socket), F_SETFL, \(flags) | O_NONBLOCK) returned \(ret)")
|
||||
} catch let error as IOError {
|
||||
if error.errnoCode == EINVAL {
|
||||
// Darwin seems to sometimes do this despite the docs claiming it can't happen
|
||||
throw NIOFailedToSetSocketNonBlockingError()
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
|
||||
internal enum KQueue {
|
||||
|
||||
|
|
|
@ -2469,7 +2469,7 @@ public final class ChannelTests: XCTestCase {
|
|||
guard let channel = channel as? SocketChannel else {
|
||||
throw ThisIsNotASocketChannelError()
|
||||
}
|
||||
try channel.socket.withUnsafeFileDescriptor { fd in
|
||||
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)
|
||||
XCTAssertEqual(1, nfds)
|
||||
|
|
|
@ -43,7 +43,7 @@ final class SALChannelTest: XCTestCase, SALTest {
|
|||
try self.assertWrite(expectedFD: .max, expectedBytes: buffer, return: .processed(buffer.readableBytes))
|
||||
try self.assertWritev(expectedFD: .max, expectedBytes: [buffer, buffer], return: .processed(2 * buffer.readableBytes))
|
||||
try self.assertDeregister { selectable in
|
||||
try selectable.withUnsafeFileDescriptor {
|
||||
try selectable.withUnsafeHandle {
|
||||
XCTAssertEqual(.max, $0)
|
||||
}
|
||||
return true
|
||||
|
|
|
@ -329,7 +329,7 @@ public final class SocketChannelTest : XCTestCase {
|
|||
|
||||
let serverSock = try Socket(protocolFamily: AF_INET, type: Posix.SOCK_STREAM)
|
||||
try serverSock.bind(to: SocketAddress(ipAddress: "127.0.0.1", port: 0))
|
||||
let serverChannelFuture = try serverSock.withUnsafeFileDescriptor {
|
||||
let serverChannelFuture = try serverSock.withUnsafeHandle {
|
||||
ServerBootstrap(group: group).withBoundSocket(descriptor: dup($0))
|
||||
}
|
||||
try serverSock.close()
|
||||
|
@ -338,7 +338,7 @@ public final class SocketChannelTest : XCTestCase {
|
|||
let clientSock = try Socket(protocolFamily: AF_INET, type: Posix.SOCK_STREAM)
|
||||
let connected = try clientSock.connect(to: serverChannel.localAddress!)
|
||||
XCTAssertEqual(connected, true)
|
||||
let clientChannelFuture = try clientSock.withUnsafeFileDescriptor {
|
||||
let clientChannelFuture = try clientSock.withUnsafeHandle {
|
||||
ClientBootstrap(group: group).withConnectedSocket(descriptor: dup($0))
|
||||
}
|
||||
try clientSock.close()
|
||||
|
@ -356,7 +356,7 @@ public final class SocketChannelTest : XCTestCase {
|
|||
|
||||
let serverSock = try Socket(protocolFamily: AF_INET, type: Posix.SOCK_DGRAM)
|
||||
try serverSock.bind(to: SocketAddress(ipAddress: "127.0.0.1", port: 0))
|
||||
let serverChannelFuture = try serverSock.withUnsafeFileDescriptor {
|
||||
let serverChannelFuture = try serverSock.withUnsafeHandle {
|
||||
DatagramBootstrap(group: group).withBoundSocket(descriptor: dup($0))
|
||||
}
|
||||
try serverSock.close()
|
||||
|
@ -523,14 +523,14 @@ public final class SocketChannelTest : XCTestCase {
|
|||
|
||||
func testSocketFlagNONBLOCKWorks() throws {
|
||||
var socket = try assertNoThrowWithValue(try ServerSocket(protocolFamily: PF_INET, setNonBlocking: true))
|
||||
XCTAssertNoThrow(try socket.withUnsafeFileDescriptor { fd in
|
||||
XCTAssertNoThrow(try socket.withUnsafeHandle { fd in
|
||||
let flags = try assertNoThrowWithValue(Posix.fcntl(descriptor: fd, command: F_GETFL, value: 0))
|
||||
XCTAssertEqual(O_NONBLOCK, flags & O_NONBLOCK)
|
||||
})
|
||||
XCTAssertNoThrow(try socket.close())
|
||||
|
||||
socket = try assertNoThrowWithValue(ServerSocket(protocolFamily: PF_INET, setNonBlocking: false))
|
||||
XCTAssertNoThrow(try socket.withUnsafeFileDescriptor { fd in
|
||||
XCTAssertNoThrow(try socket.withUnsafeHandle { fd in
|
||||
var flags = try assertNoThrowWithValue(Posix.fcntl(descriptor: fd, command: F_GETFL, value: 0))
|
||||
XCTAssertEqual(0, flags & O_NONBLOCK)
|
||||
let ret = try assertNoThrowWithValue(Posix.fcntl(descriptor: fd, command: F_SETFL, value: flags | O_NONBLOCK))
|
||||
|
@ -638,13 +638,13 @@ public final class SocketChannelTest : XCTestCase {
|
|||
type: Posix.SOCK_STREAM,
|
||||
setNonBlocking: false))
|
||||
// check initial flags
|
||||
XCTAssertNoThrow(try s.withUnsafeFileDescriptor { fd in
|
||||
XCTAssertNoThrow(try s.withUnsafeHandle { fd in
|
||||
let flags = try Posix.fcntl(descriptor: fd, command: F_GETFL, value: 0)
|
||||
XCTAssertEqual(0, flags & O_NONBLOCK)
|
||||
})
|
||||
|
||||
// set other random flag
|
||||
XCTAssertNoThrow(try s.withUnsafeFileDescriptor { fd in
|
||||
XCTAssertNoThrow(try s.withUnsafeHandle { fd in
|
||||
let oldFlags = try Posix.fcntl(descriptor: fd, command: F_GETFL, value: 0)
|
||||
let ret = try Posix.fcntl(descriptor: fd, command: F_SETFL, value: oldFlags | O_ASYNC)
|
||||
XCTAssertEqual(0, ret)
|
||||
|
@ -656,7 +656,7 @@ public final class SocketChannelTest : XCTestCase {
|
|||
XCTAssertNoThrow(try s.setNonBlocking())
|
||||
|
||||
// check both are enabled
|
||||
XCTAssertNoThrow(try s.withUnsafeFileDescriptor { fd in
|
||||
XCTAssertNoThrow(try s.withUnsafeHandle { fd in
|
||||
let flags = try Posix.fcntl(descriptor: fd, command: F_GETFL, value: 0)
|
||||
XCTAssertEqual(O_ASYNC, flags & O_ASYNC)
|
||||
XCTAssertEqual(O_NONBLOCK, flags & O_NONBLOCK)
|
||||
|
|
|
@ -285,7 +285,7 @@ class HookedSocket: Socket, UserKernelInterface {
|
|||
}
|
||||
|
||||
override func write(pointer: UnsafeRawBufferPointer) throws -> IOResult<Int> {
|
||||
return try self.withUnsafeFileDescriptor { fd in
|
||||
return try self.withUnsafeHandle { fd in
|
||||
var buffer = ByteBufferAllocator().buffer(capacity: pointer.count)
|
||||
buffer.writeBytes(pointer)
|
||||
try self.userToKernel.waitForEmptyAndSet(.write(fd, buffer))
|
||||
|
@ -299,7 +299,7 @@ class HookedSocket: Socket, UserKernelInterface {
|
|||
}
|
||||
|
||||
override func writev(iovecs: UnsafeBufferPointer<IOVector>) throws -> IOResult<Int> {
|
||||
return try self.withUnsafeFileDescriptor { fd in
|
||||
return try self.withUnsafeHandle { fd in
|
||||
let buffers = iovecs.map { iovec -> ByteBuffer in
|
||||
var buffer = ByteBufferAllocator().buffer(capacity: iovec.iov_len)
|
||||
buffer.writeBytes(UnsafeRawBufferPointer(start: iovec.iov_base, count: iovec.iov_len))
|
||||
|
|
Loading…
Reference in New Issue