Side-port apple/swift-nio#597. (#41)

Motivation:

We never brought across the fix to apple/swift-nio#597 into swift-nio-transport-services. This
has caused some users a few hard-to-track-down surprises. We fixed this in the mainline by way
of #40, but users running the old codebase probably want this fix too.

Modifications:

- Side-ported the fix from apple/swift-nio#597.
- Back-ported the test from #40.

Result:

Users can set multiple socket options.
This commit is contained in:
Cory Benfield 2019-05-01 14:24:23 +01:00 committed by Johannes Weiss
parent 1c2269d04b
commit 553f2f73ed
2 changed files with 43 additions and 2 deletions

View File

@ -177,8 +177,27 @@ public final class NIOTSConnectionBootstrap {
internal struct ChannelOptionStorage {
private var storage: [(Any, (Any, (Channel) -> (Any, Any) -> EventLoopFuture<Void>))] = []
mutating func put<K: ChannelOption & Equatable>(key: K, value: K.OptionType) {
return self.put(key: key, value: value, equalsFunc: ==)
}
// HACK: this function should go for NIO 2.0, all ChannelOptions should be equatable
mutating func put<K: ChannelOption>(key: K, value: K.OptionType) {
if K.self == SocketOption.self {
return self.put(key: key as! SocketOption, value: value as! SocketOptionValue) { lhs, rhs in
switch (lhs, rhs) {
case (.const(let lLevel, let lName), .const(let rLevel, let rName)):
return lLevel == rLevel && lName == rName
}
}
} else {
return self.put(key: key, value: value) { _, _ in true }
}
}
mutating func put<K: ChannelOption>(key: K,
value newValue: K.OptionType) {
value newValue: K.OptionType,
equalsFunc: (K, K) -> Bool) {
func applier(_ t: Channel) -> (Any, Any) -> EventLoopFuture<Void> {
return { (x, y) in
return t.setOption(option: x as! K, value: y as! K.OptionType)
@ -187,7 +206,7 @@ internal struct ChannelOptionStorage {
var hasSet = false
self.storage = self.storage.map { typeAndValue in
let (type, value) = typeAndValue
if type is K {
if type is K && equalsFunc(type as! K, key) {
hasSet = true
return (key, (newValue, applier))
} else {

View File

@ -120,5 +120,27 @@ class NIOTSSocketOptionsOnChannelTests: XCTestCase {
func testSO_KEEPALIVE() throws {
try self.assertChannelOptionAfterCreation(option: SocketOption(level: SOL_SOCKET, name: SO_KEEPALIVE), initialValue: 0, testAlternativeValue: 1)
}
func testMultipleSocketOptions() throws {
let listener = try NIOTSListenerBootstrap(group: group)
.serverChannelOption(ChannelOptions.socket(SOL_SOCKET, SO_REUSEADDR), value: 1)
.serverChannelOption(ChannelOptions.socket(IPPROTO_TCP, TCP_NODELAY), value: 1)
.bind(host: "127.0.0.1", port: 0).wait()
defer {
XCTAssertNoThrow(try listener.close().wait())
}
let connector = try NIOTSConnectionBootstrap(group: group)
.channelOption(ChannelOptions.socket(SOL_SOCKET, SO_REUSEADDR), value: 1)
.channelOption(ChannelOptions.socket(IPPROTO_TCP, TCP_NODELAY), value: 1)
.connect(to: listener.localAddress!).wait()
defer {
XCTAssertNoThrow(try connector.close().wait())
}
XCTAssertNoThrow(XCTAssertEqual(1, try listener.getOption(option: ChannelOptions.socket(SOL_SOCKET, SO_REUSEADDR)).wait()))
XCTAssertNoThrow(XCTAssertEqual(1, try listener.getOption(option: ChannelOptions.socket(IPPROTO_TCP, TCP_NODELAY)).wait()))
XCTAssertNoThrow(XCTAssertEqual(1, try connector.getOption(option: ChannelOptions.socket(SOL_SOCKET, SO_REUSEADDR)).wait()))
XCTAssertNoThrow(XCTAssertEqual(1, try connector.getOption(option: ChannelOptions.socket(IPPROTO_TCP, TCP_NODELAY)).wait()))
}
}