Add configuration of multipathServiceType in NIOTSConnectionBootstrap (#205)
### Motivation:
Allow different devices to leverage the capabilities of Mutipath TCP
(MPTCP) to enhance the network reliability. Thanks to MPTCP, a
connection can for example automatically migrate to another interface if
it deteriorates on the first one. This can be especially interesting on
MacOS X and iOS, where devices may frequently benefit from multiple
interfaces (ethernet + Wi-Fi for Macs and Wi-fi + cellular for iOS).
Allowing developers to enable MPTCP on their connections seems thus like
a fine addition to this library.
### Modifications:
Added a function "withMultipath" on NIOTSConnectionBootstrap, that allow
to configure the type of service used for MPTCP (defaults to disabled).
This value will be stored in a field, and then propagated to the
underlying channel when the connect method will be called. Also updated
the parameters field of NIOTSConnectionChannel to set the
multipathServiceType accordingly.
### Result:
Users will now be able to easily enable Multipath TCP, allowing them to
benefit from seamless handover, interactive mode to automatically use
the lowest delay interface or aggregate mode to send data in parallel on
both interfaces.
Example:
```swift
let group = NIOTSEventLoopGroup()
defer {
try! group.syncShutdownGracefully()
}
let bootstrap = NIOTSConnectionBootstrap(group: group)
.withMultipath(.handover) // set handover mode
.channelInitializer { channel in
channel.pipeline.addHandler(MyChannelHandler())
}
try! bootstrap.connect(host: "example.org", port: 12345).wait()
/* the Channel is now connected */
```
Co-authored-by: Cory Benfield <lukasa@apple.com>
This commit is contained in:
parent
99d28e05f7
commit
afd169118c
|
|
@ -154,6 +154,12 @@ public final class NIOTSConnectionBootstrap {
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Specifies a type of Multipath service to use for this connection, instead of the default
|
||||||
|
/// service type for the event loop.
|
||||||
|
public func withMultipath(_ type: NWParameters.MultipathServiceType) -> Self {
|
||||||
|
self.channelOption(NIOTSChannelOptions.multipathServiceType, value: type)
|
||||||
|
}
|
||||||
|
|
||||||
/// Specify the `host` and `port` to connect to for the TCP `Channel` that will be established.
|
/// Specify the `host` and `port` to connect to for the TCP `Channel` that will be established.
|
||||||
///
|
///
|
||||||
/// - parameters:
|
/// - parameters:
|
||||||
|
|
|
||||||
|
|
@ -235,6 +235,16 @@ public final class NIOTSListenerBootstrap {
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Specifies a type of Multipath service to use for this listener, instead of the default
|
||||||
|
/// service type for the event loop.
|
||||||
|
///
|
||||||
|
/// Warning: Multipath service doesn't seem supported on the listener side yet, as
|
||||||
|
/// described on https://www.mptcp.dev/macOS.html. Note that enabling Multipath
|
||||||
|
/// may then generate unexpected errors, use this function with caution.
|
||||||
|
public func withMultipath(_ type: NWParameters.MultipathServiceType) -> Self {
|
||||||
|
self.serverChannelOption(NIOTSChannelOptions.multipathServiceType, value: type)
|
||||||
|
}
|
||||||
|
|
||||||
/// Bind the `NIOTSListenerChannel` to `host` and `port`.
|
/// Bind the `NIOTSListenerChannel` to `host` and `port`.
|
||||||
///
|
///
|
||||||
/// - parameters:
|
/// - parameters:
|
||||||
|
|
|
||||||
|
|
@ -336,6 +336,25 @@ final class NIOTSBootstrapTests: XCTestCase {
|
||||||
try? connectionChannel?.close().wait()
|
try? connectionChannel?.close().wait()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testBootstrapsMultipath() throws {
|
||||||
|
let group = NIOTSEventLoopGroup()
|
||||||
|
defer {
|
||||||
|
try! group.syncShutdownGracefully()
|
||||||
|
}
|
||||||
|
|
||||||
|
let listenerBootstrap = NIOTSListenerBootstrap(group: group).withMultipath(.handover)
|
||||||
|
let connectionBootstrap = NIOTSConnectionBootstrap(group: group).withMultipath(.handover)
|
||||||
|
|
||||||
|
let listenerChannel: Channel = try listenerBootstrap.bind(host: "localhost", port: 0).wait()
|
||||||
|
let connectionChannel: Channel = try connectionBootstrap.connect(to: listenerChannel.localAddress!).wait()
|
||||||
|
defer{
|
||||||
|
try? listenerChannel.close().wait()
|
||||||
|
try? connectionChannel.close().wait()
|
||||||
|
}
|
||||||
|
XCTAssertEqual(try listenerChannel.getOption(NIOTSChannelOptions.multipathServiceType).wait(), .handover)
|
||||||
|
XCTAssertEqual(try connectionChannel.getOption(NIOTSChannelOptions.multipathServiceType).wait(), .handover)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Channel {
|
extension Channel {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue