Expose multicast service type (#165)

Motivation

As we've rolled out support for multicast on Linux, it makes sense to
add equivalent configuration for swift-nio-transport-services. The two
features aren't one-to-one, as Network.framework has substantially more
capability than the Linux functionality.

Modifications

- Expose a multipathServiceType channel option
- Add a test to confirm we use it properly

Result

Multicast service types are available.
This commit is contained in:
Cory Benfield 2022-11-09 11:00:20 +00:00 committed by GitHub
parent d3345ffc2a
commit e676b1f044
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 0 deletions

View File

@ -46,6 +46,9 @@ public struct NIOTSChannelOptions {
/// See: ``Types/NIOTSDataTransferReportOption``.
@available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public static let dataTransferReport = NIOTSChannelOptions.Types.NIOTSDataTransferReportOption()
/// See: ``Types/NIOTSMultipathOption``
public static let multipathServiceType = NIOTSChannelOptions.Types.NIOTSMultipathOption()
}
@ -135,6 +138,15 @@ extension NIOTSChannelOptions {
public init() {}
}
/// ``NIOTSMultipathOption`` sets the multipath behaviour for a given `NWConnection`
/// or `NWListener`.
@available(OSX 10.14, iOS 12.0, tvOS 12.0, watchOS 6.0, *)
public struct NIOTSMultipathOption: ChannelOption, Equatable {
public typealias Value = NWParameters.MultipathServiceType
public init() {}
}
}
}

View File

@ -200,6 +200,9 @@ internal final class NIOTSConnectionChannel {
/// Whether to use peer-to-peer connectivity when connecting to Bonjour services.
private var enablePeerToPeer = false
/// The default multipath service type.
private var multipathServiceType = NWParameters.MultipathServiceType.disabled
/// The cache of the local and remote socket addresses. Must be accessed using _addressCacheLock.
private var _addressCache = AddressCache(local: nil, remote: nil)
@ -322,6 +325,8 @@ extension NIOTSConnectionChannel: Channel {
self.enablePeerToPeer = value as! NIOTSChannelOptions.Types.NIOTSEnablePeerToPeerOption.Value
case is NIOTSChannelOptions.Types.NIOTSAllowLocalEndpointReuse:
self.allowLocalEndpointReuse = value as! NIOTSChannelOptions.Types.NIOTSEnablePeerToPeerOption.Value
case is NIOTSChannelOptions.Types.NIOTSMultipathOption:
self.multipathServiceType = value as! NIOTSChannelOptions.Types.NIOTSMultipathOption.Value
default:
fatalError("option \(type(of: option)).\(option) not supported")
}
@ -378,6 +383,8 @@ extension NIOTSConnectionChannel: Channel {
throw NIOTSErrors.NoCurrentConnection()
}
return nwConnection.metadata(definition: optionValue.definition) as! Option.Value
case is NIOTSChannelOptions.Types.NIOTSMultipathOption:
return self.multipathServiceType as! Option.Value
default:
// watchOS 6.0 availability is covered by the @available on this extension.
if #available(OSX 10.15, iOS 13.0, tvOS 13.0, *) {
@ -493,6 +500,8 @@ extension NIOTSConnectionChannel: StateManagedChannel {
parameters.includePeerToPeer = self.enablePeerToPeer
parameters.multipathServiceType = self.multipathServiceType
let connection = NWConnection(to: target, using: parameters)
connection.stateUpdateHandler = self.stateUpdateHandler(newState:)
connection.betterPathUpdateHandler = self.betterPathHandler

View File

@ -85,6 +85,9 @@ internal final class NIOTSListenerChannel {
/// Whether to enable peer-to-peer connectivity when using Bonjour services.
private var enablePeerToPeer = false
/// The default multipath service type.
private var multipathServiceType = NWParameters.MultipathServiceType.disabled
/// The event loop group to use for child channels.
private let childLoopGroup: EventLoopGroup
@ -220,6 +223,8 @@ extension NIOTSListenerChannel: Channel {
self.enablePeerToPeer = value as! NIOTSChannelOptions.Types.NIOTSEnablePeerToPeerOption.Value
case is NIOTSChannelOptions.Types.NIOTSAllowLocalEndpointReuse:
self.allowLocalEndpointReuse = value as! NIOTSChannelOptions.Types.NIOTSEnablePeerToPeerOption.Value
case is NIOTSChannelOptions.Types.NIOTSMultipathOption:
self.multipathServiceType = value as! NIOTSChannelOptions.Types.NIOTSMultipathOption.Value
default:
fatalError("option \(option) not supported")
}
@ -257,6 +262,8 @@ extension NIOTSListenerChannel: Channel {
return self.enablePeerToPeer as! Option.Value
case is NIOTSChannelOptions.Types.NIOTSAllowLocalEndpointReuse:
return self.allowLocalEndpointReuse as! Option.Value
case is NIOTSChannelOptions.Types.NIOTSMultipathOption:
return self.multipathServiceType as! Option.Value
default:
fatalError("option \(option) not supported")
}
@ -349,6 +356,8 @@ extension NIOTSListenerChannel: StateManagedChannel {
parameters.includePeerToPeer = self.enablePeerToPeer
parameters.multipathServiceType = self.multipathServiceType
let listener: NWListener
do {
listener = try NWListener(using: parameters)

View File

@ -117,5 +117,27 @@ class NIOTSChannelOptionsTests: XCTestCase {
collectGroup.wait()
}
func testMultipathOptions() throws {
let listener = try NIOTSListenerBootstrap(group: self.group)
.serverChannelOption(NIOTSChannelOptions.multipathServiceType, value: .handover)
.bind(host: "localhost", port: 0).wait()
defer {
XCTAssertNoThrow(try listener.close().wait())
}
let connection = try NIOTSConnectionBootstrap(group: self.group)
.channelOption(NIOTSChannelOptions.multipathServiceType, value: .interactive)
.connect(to: listener.localAddress!)
.wait()
defer {
XCTAssertNoThrow(try connection.close().wait())
}
let listenerValue = try assertNoThrowWithValue(listener.getOption(NIOTSChannelOptions.multipathServiceType).wait())
let connectionValue = try assertNoThrowWithValue(connection.getOption(NIOTSChannelOptions.multipathServiceType).wait())
XCTAssertEqual(listenerValue, .handover)
XCTAssertEqual(connectionValue, .interactive)
}
}
#endif