Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Return failed EventLoopFuture when getOption(...) / setOption(...) is… #198

Merged
merged 2 commits into from
Mar 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions Sources/NIO/SocketChannel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,10 @@ class BaseSocketChannel<T: BaseSocket>: SelectableChannel, ChannelCore {
fileprivate func setOption0<T: ChannelOption>(option: T, value: T.OptionType) throws {
assert(eventLoop.inEventLoop)

guard isOpen else {
throw ChannelError.ioOnClosedChannel
}

switch option {
case _ as SocketOption:
let (level, name) = option.value as! (SocketOptionLevel, SocketOptionName)
Expand Down Expand Up @@ -328,6 +332,10 @@ class BaseSocketChannel<T: BaseSocket>: SelectableChannel, ChannelCore {
fileprivate func getOption0<T: ChannelOption>(option: T) throws -> T.OptionType {
assert(eventLoop.inEventLoop)

guard isOpen else {
throw ChannelError.ioOnClosedChannel
}

switch option {
case _ as SocketOption:
let (level, name) = option.value as! (SocketOptionLevel, SocketOptionName)
Expand Down Expand Up @@ -802,6 +810,11 @@ final class SocketChannel: BaseSocketChannel<Socket> {

override fileprivate func setOption0<T: ChannelOption>(option: T, value: T.OptionType) throws {
assert(eventLoop.inEventLoop)

guard isOpen else {
throw ChannelError.ioOnClosedChannel
}

switch option {
case _ as ConnectTimeoutOption:
connectTimeout = value as? TimeAmount
Expand All @@ -818,6 +831,11 @@ final class SocketChannel: BaseSocketChannel<Socket> {

override fileprivate func getOption0<T: ChannelOption>(option: T) throws -> T.OptionType {
assert(eventLoop.inEventLoop)

guard isOpen else {
throw ChannelError.ioOnClosedChannel
}

switch option {
case _ as ConnectTimeoutOption:
return connectTimeout as! T.OptionType
Expand Down Expand Up @@ -1046,6 +1064,11 @@ final class ServerSocketChannel: BaseSocketChannel<ServerSocket> {

override fileprivate func setOption0<T: ChannelOption>(option: T, value: T.OptionType) throws {
assert(eventLoop.inEventLoop)

guard isOpen else {
throw ChannelError.ioOnClosedChannel
}

switch option {
case _ as BacklogOption:
backlog = value as! Int32
Expand All @@ -1056,6 +1079,11 @@ final class ServerSocketChannel: BaseSocketChannel<ServerSocket> {

override fileprivate func getOption0<T: ChannelOption>(option: T) throws -> T.OptionType {
assert(eventLoop.inEventLoop)

guard isOpen else {
throw ChannelError.ioOnClosedChannel
}

switch option {
case _ as BacklogOption:
return backlog as! T.OptionType
Expand Down Expand Up @@ -1212,6 +1240,11 @@ final class DatagramChannel: BaseSocketChannel<Socket> {

override fileprivate func setOption0<T: ChannelOption>(option: T, value: T.OptionType) throws {
assert(eventLoop.inEventLoop)

guard isOpen else {
throw ChannelError.ioOnClosedChannel
}

switch option {
case _ as WriteSpinOption:
pendingWrites.writeSpinCount = value as! UInt
Expand All @@ -1224,6 +1257,11 @@ final class DatagramChannel: BaseSocketChannel<Socket> {

override fileprivate func getOption0<T: ChannelOption>(option: T) throws -> T.OptionType {
assert(eventLoop.inEventLoop)

guard isOpen else {
throw ChannelError.ioOnClosedChannel
}

switch option {
case _ as WriteSpinOption:
return pendingWrites.writeSpinCount as! T.OptionType
Expand Down
1 change: 1 addition & 0 deletions Tests/NIOTests/DatagramChannelTests+XCTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ extension DatagramChannelTests {
("testRecvFromFailsWithECONNREFUSED", testRecvFromFailsWithECONNREFUSED),
("testRecvFromFailsWithENOMEM", testRecvFromFailsWithENOMEM),
("testRecvFromFailsWithEFAULT", testRecvFromFailsWithEFAULT),
("testSetGetOptionClosedDatagramChannel", testSetGetOptionClosedDatagramChannel),
]
}
}
Expand Down
4 changes: 4 additions & 0 deletions Tests/NIOTests/DatagramChannelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -403,4 +403,8 @@ final class DatagramChannelTests: XCTestCase {
let ioError = try promise.futureResult.wait()
XCTAssertEqual(error, ioError.errnoCode)
}

public func testSetGetOptionClosedDatagramChannel() throws {
try assertSetGetOptionOnOpenAndClosed(channel: firstChannel, option: ChannelOptions.maxMessagesPerRead, value: 1)
}
}
1 change: 1 addition & 0 deletions Tests/NIOTests/SocketChannelTest+XCTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ extension SocketChannelTest {
("testAcceptFailsWithENOBUFS", testAcceptFailsWithENOBUFS),
("testAcceptFailsWithENOMEM", testAcceptFailsWithENOMEM),
("testAcceptFailsWithEFAULT", testAcceptFailsWithEFAULT),
("testSetGetOptionClosedServerSocketChannel", testSetGetOptionClosedServerSocketChannel),
]
}
}
Expand Down
12 changes: 12 additions & 0 deletions Tests/NIOTests/SocketChannelTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,16 @@ public class SocketChannelTest : XCTestCase {
let ioError = try promise.futureResult.wait()
XCTAssertEqual(error, ioError.errnoCode)
}

public func testSetGetOptionClosedServerSocketChannel() throws {
let group = MultiThreadedEventLoopGroup(numThreads: 1)
defer { XCTAssertNoThrow(try group.syncShutdownGracefully()) }

// Create two channels with different event loops.
let serverChannel = try ServerBootstrap(group: group).bind(host: "127.0.0.1", port: 0).wait()
let clientChannel = try ClientBootstrap(group: group).connect(to: serverChannel.localAddress!).wait()

try assertSetGetOptionOnOpenAndClosed(channel: clientChannel, option: ChannelOptions.allowRemoteHalfClosure, value: true)
try assertSetGetOptionOnOpenAndClosed(channel: serverChannel, option: ChannelOptions.backlog, value: 100)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you do this for datagram channels too?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}
19 changes: 19 additions & 0 deletions Tests/NIOTests/TestUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,22 @@ final class NonAcceptingServerSocket: ServerSocket {
return nil
}
}

func assertSetGetOptionOnOpenAndClosed<T: ChannelOption>(channel: Channel, option: T, value: T.OptionType) throws {
_ = try channel.setOption(option: option, value: value).wait()
_ = try channel.getOption(option: option).wait()
try channel.close().wait()
try channel.closeFuture.wait()

do {
_ = try channel.setOption(option: option, value: value).wait()
} catch let err as ChannelError where err == .ioOnClosedChannel {
// expected
}

do {
_ = try channel.getOption(option: option).wait()
} catch let err as ChannelError where err == .ioOnClosedChannel {
// expected
}
}