Add `NWParameters` configurator to bootstraps (#230)
Allow users to provide a closure taking an `NWParameters` to customise them before they're used to create `NWConnection`s. ### Motivation: `NWParameters` are currently created using the provided TLS and UDP options, and then passed over to new `NWConnection`s. However, there are more ways in which `NWParameters` can be customised, so this new API provides a way for users to do this. ### Modifications: Introduce new `configureNWParameters` methods to the existing bootstraps to allow configuring a closure for customising `NWParameters`. ### Result: Users can now customise the `NWParameters` used to create new `NWConnection`s.
This commit is contained in:
parent
3d21b85af4
commit
cd1e89816d
|
|
@ -47,6 +47,7 @@ public final class NIOTSDatagramBootstrap {
|
||||||
private var qos: DispatchQoS?
|
private var qos: DispatchQoS?
|
||||||
private var udpOptions: NWProtocolUDP.Options = .init()
|
private var udpOptions: NWProtocolUDP.Options = .init()
|
||||||
private var tlsOptions: NWProtocolTLS.Options?
|
private var tlsOptions: NWProtocolTLS.Options?
|
||||||
|
private var nwParametersConfigurator: (@Sendable (NWParameters) -> Void)?
|
||||||
|
|
||||||
/// Create a `NIOTSDatagramConnectionBootstrap` on the `EventLoopGroup` `group`.
|
/// Create a `NIOTSDatagramConnectionBootstrap` on the `EventLoopGroup` `group`.
|
||||||
///
|
///
|
||||||
|
|
@ -133,6 +134,14 @@ public final class NIOTSDatagramBootstrap {
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Customise the `NWParameters` to be used when creating the connection.
|
||||||
|
public func configureNWParameters(
|
||||||
|
_ configurator: @Sendable @escaping (NWParameters) -> Void
|
||||||
|
) -> Self {
|
||||||
|
self.nwParametersConfigurator = configurator
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
/// Specify the `host` and `port` to connect to for the UDP `Channel` that will be established.
|
/// Specify the `host` and `port` to connect to for the UDP `Channel` that will be established.
|
||||||
///
|
///
|
||||||
/// - parameters:
|
/// - parameters:
|
||||||
|
|
@ -188,7 +197,8 @@ public final class NIOTSDatagramBootstrap {
|
||||||
eventLoop: self.group.next() as! NIOTSEventLoop,
|
eventLoop: self.group.next() as! NIOTSEventLoop,
|
||||||
qos: self.qos,
|
qos: self.qos,
|
||||||
udpOptions: self.udpOptions,
|
udpOptions: self.udpOptions,
|
||||||
tlsOptions: self.tlsOptions
|
tlsOptions: self.tlsOptions,
|
||||||
|
nwParametersConfigurator: self.nwParametersConfigurator
|
||||||
)
|
)
|
||||||
let initializer = self.channelInitializer ?? { @Sendable _ in conn.eventLoop.makeSucceededFuture(()) }
|
let initializer = self.channelInitializer ?? { @Sendable _ in conn.eventLoop.makeSucceededFuture(()) }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -140,8 +140,12 @@ internal final class NIOTSDatagramChannel: StateManagedNWConnectionChannel {
|
||||||
internal var allowLocalEndpointReuse = false
|
internal var allowLocalEndpointReuse = false
|
||||||
internal var multipathServiceType: NWParameters.MultipathServiceType = .disabled
|
internal var multipathServiceType: NWParameters.MultipathServiceType = .disabled
|
||||||
|
|
||||||
|
internal let nwParametersConfigurator: (@Sendable (NWParameters) -> Void)?
|
||||||
|
|
||||||
var parameters: NWParameters {
|
var parameters: NWParameters {
|
||||||
NWParameters(dtls: self.tlsOptions, udp: self.udpOptions)
|
let parameters = NWParameters(dtls: self.tlsOptions, udp: self.udpOptions)
|
||||||
|
self.nwParametersConfigurator?(parameters)
|
||||||
|
return parameters
|
||||||
}
|
}
|
||||||
|
|
||||||
var _inboundStreamOpen: Bool {
|
var _inboundStreamOpen: Bool {
|
||||||
|
|
@ -182,7 +186,8 @@ internal final class NIOTSDatagramChannel: StateManagedNWConnectionChannel {
|
||||||
minimumIncompleteReceiveLength: Int = 1,
|
minimumIncompleteReceiveLength: Int = 1,
|
||||||
maximumReceiveLength: Int = 8192,
|
maximumReceiveLength: Int = 8192,
|
||||||
udpOptions: NWProtocolUDP.Options,
|
udpOptions: NWProtocolUDP.Options,
|
||||||
tlsOptions: NWProtocolTLS.Options?
|
tlsOptions: NWProtocolTLS.Options?,
|
||||||
|
nwParametersConfigurator: (@Sendable (NWParameters) -> Void)?
|
||||||
) {
|
) {
|
||||||
self.tsEventLoop = eventLoop
|
self.tsEventLoop = eventLoop
|
||||||
self.closePromise = eventLoop.makePromise()
|
self.closePromise = eventLoop.makePromise()
|
||||||
|
|
@ -192,6 +197,7 @@ internal final class NIOTSDatagramChannel: StateManagedNWConnectionChannel {
|
||||||
self.connectionQueue = eventLoop.channelQueue(label: "nio.nioTransportServices.connectionchannel", qos: qos)
|
self.connectionQueue = eventLoop.channelQueue(label: "nio.nioTransportServices.connectionchannel", qos: qos)
|
||||||
self.udpOptions = udpOptions
|
self.udpOptions = udpOptions
|
||||||
self.tlsOptions = tlsOptions
|
self.tlsOptions = tlsOptions
|
||||||
|
self.nwParametersConfigurator = nwParametersConfigurator
|
||||||
|
|
||||||
// Must come last, as it requires self to be completely initialized.
|
// Must come last, as it requires self to be completely initialized.
|
||||||
self._pipeline = ChannelPipeline(channel: self)
|
self._pipeline = ChannelPipeline(channel: self)
|
||||||
|
|
@ -206,7 +212,8 @@ internal final class NIOTSDatagramChannel: StateManagedNWConnectionChannel {
|
||||||
minimumIncompleteReceiveLength: Int = 1,
|
minimumIncompleteReceiveLength: Int = 1,
|
||||||
maximumReceiveLength: Int = 8192,
|
maximumReceiveLength: Int = 8192,
|
||||||
udpOptions: NWProtocolUDP.Options,
|
udpOptions: NWProtocolUDP.Options,
|
||||||
tlsOptions: NWProtocolTLS.Options?
|
tlsOptions: NWProtocolTLS.Options?,
|
||||||
|
nwParametersConfigurator: (@Sendable (NWParameters) -> Void)?
|
||||||
) {
|
) {
|
||||||
self.init(
|
self.init(
|
||||||
eventLoop: eventLoop,
|
eventLoop: eventLoop,
|
||||||
|
|
@ -215,7 +222,8 @@ internal final class NIOTSDatagramChannel: StateManagedNWConnectionChannel {
|
||||||
minimumIncompleteReceiveLength: minimumIncompleteReceiveLength,
|
minimumIncompleteReceiveLength: minimumIncompleteReceiveLength,
|
||||||
maximumReceiveLength: maximumReceiveLength,
|
maximumReceiveLength: maximumReceiveLength,
|
||||||
udpOptions: udpOptions,
|
udpOptions: udpOptions,
|
||||||
tlsOptions: tlsOptions
|
tlsOptions: tlsOptions,
|
||||||
|
nwParametersConfigurator: nwParametersConfigurator
|
||||||
)
|
)
|
||||||
self.connection = connection
|
self.connection = connection
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,12 @@ public final class NIOTSDatagramListenerBootstrap {
|
||||||
private var serverQoS: DispatchQoS?
|
private var serverQoS: DispatchQoS?
|
||||||
private var childQoS: DispatchQoS?
|
private var childQoS: DispatchQoS?
|
||||||
private var udpOptions: NWProtocolUDP.Options = .init()
|
private var udpOptions: NWProtocolUDP.Options = .init()
|
||||||
|
private var childUDPOptions: NWProtocolUDP.Options = .init()
|
||||||
private var tlsOptions: NWProtocolTLS.Options?
|
private var tlsOptions: NWProtocolTLS.Options?
|
||||||
|
private var childTLSOptions: NWProtocolTLS.Options?
|
||||||
private var bindTimeout: TimeAmount?
|
private var bindTimeout: TimeAmount?
|
||||||
|
private var nwParametersConfigurator: (@Sendable (NWParameters) -> Void)?
|
||||||
|
private var childNWParametersConfigurator: (@Sendable (NWParameters) -> Void)?
|
||||||
|
|
||||||
/// Create a ``NIOTSListenerBootstrap`` for the `EventLoopGroup` `group`.
|
/// Create a ``NIOTSListenerBootstrap`` for the `EventLoopGroup` `group`.
|
||||||
///
|
///
|
||||||
|
|
@ -224,18 +228,46 @@ public final class NIOTSDatagramListenerBootstrap {
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specifies the TCP options to use on the child `Channel`s.
|
/// Specifies the TCP options to use on the listener.
|
||||||
public func udpOptions(_ options: NWProtocolUDP.Options) -> Self {
|
public func udpOptions(_ options: NWProtocolUDP.Options) -> Self {
|
||||||
self.udpOptions = options
|
self.udpOptions = options
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specifies the TLS options to use on the child `Channel`s.
|
/// Specifies the TCP options to use on the child `Channel`s.
|
||||||
|
public func childUDPOptions(_ options: NWProtocolUDP.Options) -> Self {
|
||||||
|
self.childUDPOptions = options
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Specifies the TLS options to use on the listener.
|
||||||
public func tlsOptions(_ options: NWProtocolTLS.Options) -> Self {
|
public func tlsOptions(_ options: NWProtocolTLS.Options) -> Self {
|
||||||
self.tlsOptions = options
|
self.tlsOptions = options
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Specifies the TLS options to use on the child `Channel`s.
|
||||||
|
public func childTLSOptions(_ options: NWProtocolTLS.Options) -> Self {
|
||||||
|
self.childTLSOptions = options
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Customise the `NWParameters` to be used when creating the `NWConnection` for the listener.
|
||||||
|
public func configureNWParameters(
|
||||||
|
_ configurator: @Sendable @escaping (NWParameters) -> Void
|
||||||
|
) -> Self {
|
||||||
|
self.nwParametersConfigurator = configurator
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Customise the `NWParameters` to be used when creating the `NWConnection`s for the child `Channel`s.
|
||||||
|
public func configureChildNWParameters(
|
||||||
|
_ configurator: @Sendable @escaping (NWParameters) -> Void
|
||||||
|
) -> Self {
|
||||||
|
self.childNWParametersConfigurator = configurator
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
/// Bind the `NIOTSListenerChannel` to `host` and `port`.
|
/// Bind the `NIOTSListenerChannel` to `host` and `port`.
|
||||||
///
|
///
|
||||||
/// - parameters:
|
/// - parameters:
|
||||||
|
|
@ -327,10 +359,12 @@ public final class NIOTSDatagramListenerBootstrap {
|
||||||
qos: self.serverQoS,
|
qos: self.serverQoS,
|
||||||
udpOptions: self.udpOptions,
|
udpOptions: self.udpOptions,
|
||||||
tlsOptions: self.tlsOptions,
|
tlsOptions: self.tlsOptions,
|
||||||
|
nwParametersConfigurator: self.nwParametersConfigurator,
|
||||||
childLoopGroup: self.childGroup,
|
childLoopGroup: self.childGroup,
|
||||||
childChannelQoS: self.childQoS,
|
childChannelQoS: self.childQoS,
|
||||||
childUDPOptions: self.udpOptions,
|
childUDPOptions: self.childUDPOptions,
|
||||||
childTLSOptions: self.tlsOptions
|
childTLSOptions: self.childTLSOptions,
|
||||||
|
childNWParametersConfigurator: self.childNWParametersConfigurator
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
serverChannel = NIOTSDatagramListenerChannel(
|
serverChannel = NIOTSDatagramListenerChannel(
|
||||||
|
|
@ -338,10 +372,12 @@ public final class NIOTSDatagramListenerBootstrap {
|
||||||
qos: self.serverQoS,
|
qos: self.serverQoS,
|
||||||
udpOptions: self.udpOptions,
|
udpOptions: self.udpOptions,
|
||||||
tlsOptions: self.tlsOptions,
|
tlsOptions: self.tlsOptions,
|
||||||
|
nwParametersConfigurator: self.nwParametersConfigurator,
|
||||||
childLoopGroup: self.childGroup,
|
childLoopGroup: self.childGroup,
|
||||||
childChannelQoS: self.childQoS,
|
childChannelQoS: self.childQoS,
|
||||||
childUDPOptions: self.udpOptions,
|
childUDPOptions: self.childUDPOptions,
|
||||||
childTLSOptions: self.tlsOptions
|
childTLSOptions: self.childTLSOptions,
|
||||||
|
childNWParametersConfigurator: self.childNWParametersConfigurator
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,19 +81,23 @@ internal final class NIOTSDatagramListenerChannel: StateManagedListenerChannel<N
|
||||||
qos: DispatchQoS? = nil,
|
qos: DispatchQoS? = nil,
|
||||||
udpOptions: NWProtocolUDP.Options,
|
udpOptions: NWProtocolUDP.Options,
|
||||||
tlsOptions: NWProtocolTLS.Options?,
|
tlsOptions: NWProtocolTLS.Options?,
|
||||||
|
nwParametersConfigurator: (@Sendable (NWParameters) -> Void)?,
|
||||||
childLoopGroup: EventLoopGroup,
|
childLoopGroup: EventLoopGroup,
|
||||||
childChannelQoS: DispatchQoS?,
|
childChannelQoS: DispatchQoS?,
|
||||||
childUDPOptions: NWProtocolUDP.Options,
|
childUDPOptions: NWProtocolUDP.Options,
|
||||||
childTLSOptions: NWProtocolTLS.Options?
|
childTLSOptions: NWProtocolTLS.Options?,
|
||||||
|
childNWParametersConfigurator: (@Sendable (NWParameters) -> Void)?
|
||||||
) {
|
) {
|
||||||
self.init(
|
self.init(
|
||||||
eventLoop: eventLoop,
|
eventLoop: eventLoop,
|
||||||
protocolOptions: .udp(udpOptions),
|
protocolOptions: .udp(udpOptions),
|
||||||
tlsOptions: tlsOptions,
|
tlsOptions: tlsOptions,
|
||||||
|
nwParametersConfigurator: nwParametersConfigurator,
|
||||||
childLoopGroup: childLoopGroup,
|
childLoopGroup: childLoopGroup,
|
||||||
childChannelQoS: childChannelQoS,
|
childChannelQoS: childChannelQoS,
|
||||||
childProtocolOptions: .udp(childUDPOptions),
|
childProtocolOptions: .udp(childUDPOptions),
|
||||||
childTLSOptions: childTLSOptions
|
childTLSOptions: childTLSOptions,
|
||||||
|
childNWParametersConfigurator: childNWParametersConfigurator
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -104,20 +108,24 @@ internal final class NIOTSDatagramListenerChannel: StateManagedListenerChannel<N
|
||||||
qos: DispatchQoS? = nil,
|
qos: DispatchQoS? = nil,
|
||||||
udpOptions: NWProtocolUDP.Options,
|
udpOptions: NWProtocolUDP.Options,
|
||||||
tlsOptions: NWProtocolTLS.Options?,
|
tlsOptions: NWProtocolTLS.Options?,
|
||||||
|
nwParametersConfigurator: (@Sendable (NWParameters) -> Void)?,
|
||||||
childLoopGroup: EventLoopGroup,
|
childLoopGroup: EventLoopGroup,
|
||||||
childChannelQoS: DispatchQoS?,
|
childChannelQoS: DispatchQoS?,
|
||||||
childUDPOptions: NWProtocolUDP.Options,
|
childUDPOptions: NWProtocolUDP.Options,
|
||||||
childTLSOptions: NWProtocolTLS.Options?
|
childTLSOptions: NWProtocolTLS.Options?,
|
||||||
|
childNWParametersConfigurator: (@Sendable (NWParameters) -> Void)?
|
||||||
) {
|
) {
|
||||||
self.init(
|
self.init(
|
||||||
wrapping: listener,
|
wrapping: listener,
|
||||||
eventLoop: eventLoop,
|
eventLoop: eventLoop,
|
||||||
protocolOptions: .udp(udpOptions),
|
protocolOptions: .udp(udpOptions),
|
||||||
tlsOptions: tlsOptions,
|
tlsOptions: tlsOptions,
|
||||||
|
nwParametersConfigurator: nwParametersConfigurator,
|
||||||
childLoopGroup: childLoopGroup,
|
childLoopGroup: childLoopGroup,
|
||||||
childChannelQoS: childChannelQoS,
|
childChannelQoS: childChannelQoS,
|
||||||
childProtocolOptions: .udp(childUDPOptions),
|
childProtocolOptions: .udp(childUDPOptions),
|
||||||
childTLSOptions: childTLSOptions
|
childTLSOptions: childTLSOptions,
|
||||||
|
childNWParametersConfigurator: childNWParametersConfigurator
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,7 +140,8 @@ internal final class NIOTSDatagramListenerChannel: StateManagedListenerChannel<N
|
||||||
on: self.childLoopGroup.next() as! NIOTSEventLoop,
|
on: self.childLoopGroup.next() as! NIOTSEventLoop,
|
||||||
parent: self,
|
parent: self,
|
||||||
udpOptions: self.childUDPOptions,
|
udpOptions: self.childUDPOptions,
|
||||||
tlsOptions: self.childTLSOptions
|
tlsOptions: self.childTLSOptions,
|
||||||
|
nwParametersConfigurator: self.childNWParametersConfigurator
|
||||||
)
|
)
|
||||||
|
|
||||||
self.pipeline.fireChannelRead(newChannel)
|
self.pipeline.fireChannelRead(newChannel)
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ public final class NIOTSConnectionBootstrap {
|
||||||
private var tcpOptions: NWProtocolTCP.Options = .init()
|
private var tcpOptions: NWProtocolTCP.Options = .init()
|
||||||
private var tlsOptions: NWProtocolTLS.Options?
|
private var tlsOptions: NWProtocolTLS.Options?
|
||||||
private var protocolHandlers: (@Sendable () -> [ChannelHandler])? = nil
|
private var protocolHandlers: (@Sendable () -> [ChannelHandler])? = nil
|
||||||
|
private var nwParametersConfigurator: (@Sendable (NWParameters) -> Void)?
|
||||||
|
|
||||||
/// Create a `NIOTSConnectionBootstrap` on the `EventLoopGroup` `group`.
|
/// Create a `NIOTSConnectionBootstrap` on the `EventLoopGroup` `group`.
|
||||||
///
|
///
|
||||||
|
|
@ -165,6 +166,14 @@ public final class NIOTSConnectionBootstrap {
|
||||||
self.channelOption(NIOTSChannelOptions.multipathServiceType, value: type)
|
self.channelOption(NIOTSChannelOptions.multipathServiceType, value: type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Customise the `NWParameters` to be used when creating the connection.
|
||||||
|
public func configureNWParameters(
|
||||||
|
_ configurator: @Sendable @escaping (NWParameters) -> Void
|
||||||
|
) -> Self {
|
||||||
|
self.nwParametersConfigurator = configurator
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
/// 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:
|
||||||
|
|
@ -243,14 +252,16 @@ public final class NIOTSConnectionBootstrap {
|
||||||
wrapping: newConnection,
|
wrapping: newConnection,
|
||||||
on: self.group.next() as! NIOTSEventLoop,
|
on: self.group.next() as! NIOTSEventLoop,
|
||||||
tcpOptions: self.tcpOptions,
|
tcpOptions: self.tcpOptions,
|
||||||
tlsOptions: self.tlsOptions
|
tlsOptions: self.tlsOptions,
|
||||||
|
nwParametersConfigurator: self.nwParametersConfigurator
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
conn = NIOTSConnectionChannel(
|
conn = NIOTSConnectionChannel(
|
||||||
eventLoop: self.group.next() as! NIOTSEventLoop,
|
eventLoop: self.group.next() as! NIOTSEventLoop,
|
||||||
qos: self.qos,
|
qos: self.qos,
|
||||||
tcpOptions: self.tcpOptions,
|
tcpOptions: self.tcpOptions,
|
||||||
tlsOptions: self.tlsOptions
|
tlsOptions: self.tlsOptions,
|
||||||
|
nwParametersConfigurator: self.nwParametersConfigurator
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
let initializer = self.channelInitializer
|
let initializer = self.channelInitializer
|
||||||
|
|
@ -437,14 +448,16 @@ extension NIOTSConnectionBootstrap {
|
||||||
wrapping: newConnection,
|
wrapping: newConnection,
|
||||||
on: self.group.next() as! NIOTSEventLoop,
|
on: self.group.next() as! NIOTSEventLoop,
|
||||||
tcpOptions: self.tcpOptions,
|
tcpOptions: self.tcpOptions,
|
||||||
tlsOptions: self.tlsOptions
|
tlsOptions: self.tlsOptions,
|
||||||
|
nwParametersConfigurator: self.nwParametersConfigurator
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
connectionChannel = NIOTSConnectionChannel(
|
connectionChannel = NIOTSConnectionChannel(
|
||||||
eventLoop: self.group.next() as! NIOTSEventLoop,
|
eventLoop: self.group.next() as! NIOTSEventLoop,
|
||||||
qos: self.qos,
|
qos: self.qos,
|
||||||
tcpOptions: self.tcpOptions,
|
tcpOptions: self.tcpOptions,
|
||||||
tlsOptions: self.tlsOptions
|
tlsOptions: self.tlsOptions,
|
||||||
|
nwParametersConfigurator: self.nwParametersConfigurator
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
let initializer = self.channelInitializer
|
let initializer = self.channelInitializer
|
||||||
|
|
|
||||||
|
|
@ -164,8 +164,12 @@ internal final class NIOTSConnectionChannel: StateManagedNWConnectionChannel {
|
||||||
/// An `EventLoopPromise` that will be succeeded or failed when a connection attempt succeeds or fails.
|
/// An `EventLoopPromise` that will be succeeded or failed when a connection attempt succeeds or fails.
|
||||||
internal var connectPromise: EventLoopPromise<Void>?
|
internal var connectPromise: EventLoopPromise<Void>?
|
||||||
|
|
||||||
|
internal let nwParametersConfigurator: (@Sendable (NWParameters) -> Void)?
|
||||||
|
|
||||||
internal var parameters: NWParameters {
|
internal var parameters: NWParameters {
|
||||||
NWParameters(tls: self.tlsOptions, tcp: self.tcpOptions)
|
let parameters = NWParameters(tls: self.tlsOptions, tcp: self.tcpOptions)
|
||||||
|
self.nwParametersConfigurator?(parameters)
|
||||||
|
return parameters
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The TCP options for this connection.
|
/// The TCP options for this connection.
|
||||||
|
|
@ -242,7 +246,8 @@ internal final class NIOTSConnectionChannel: StateManagedNWConnectionChannel {
|
||||||
minimumIncompleteReceiveLength: Int = 1,
|
minimumIncompleteReceiveLength: Int = 1,
|
||||||
maximumReceiveLength: Int = 8192,
|
maximumReceiveLength: Int = 8192,
|
||||||
tcpOptions: NWProtocolTCP.Options,
|
tcpOptions: NWProtocolTCP.Options,
|
||||||
tlsOptions: NWProtocolTLS.Options?
|
tlsOptions: NWProtocolTLS.Options?,
|
||||||
|
nwParametersConfigurator: (@Sendable (NWParameters) -> Void)?
|
||||||
) {
|
) {
|
||||||
self.tsEventLoop = eventLoop
|
self.tsEventLoop = eventLoop
|
||||||
self.closePromise = eventLoop.makePromise()
|
self.closePromise = eventLoop.makePromise()
|
||||||
|
|
@ -252,6 +257,7 @@ internal final class NIOTSConnectionChannel: StateManagedNWConnectionChannel {
|
||||||
self.connectionQueue = eventLoop.channelQueue(label: "nio.nioTransportServices.connectionchannel", qos: qos)
|
self.connectionQueue = eventLoop.channelQueue(label: "nio.nioTransportServices.connectionchannel", qos: qos)
|
||||||
self.tcpOptions = tcpOptions
|
self.tcpOptions = tcpOptions
|
||||||
self.tlsOptions = tlsOptions
|
self.tlsOptions = tlsOptions
|
||||||
|
self.nwParametersConfigurator = nwParametersConfigurator
|
||||||
|
|
||||||
// Must come last, as it requires self to be completely initialized.
|
// Must come last, as it requires self to be completely initialized.
|
||||||
self._pipeline = ChannelPipeline(channel: self)
|
self._pipeline = ChannelPipeline(channel: self)
|
||||||
|
|
@ -266,7 +272,8 @@ internal final class NIOTSConnectionChannel: StateManagedNWConnectionChannel {
|
||||||
minimumIncompleteReceiveLength: Int = 1,
|
minimumIncompleteReceiveLength: Int = 1,
|
||||||
maximumReceiveLength: Int = 8192,
|
maximumReceiveLength: Int = 8192,
|
||||||
tcpOptions: NWProtocolTCP.Options,
|
tcpOptions: NWProtocolTCP.Options,
|
||||||
tlsOptions: NWProtocolTLS.Options?
|
tlsOptions: NWProtocolTLS.Options?,
|
||||||
|
nwParametersConfigurator: (@Sendable (NWParameters) -> Void)?
|
||||||
) {
|
) {
|
||||||
self.init(
|
self.init(
|
||||||
eventLoop: eventLoop,
|
eventLoop: eventLoop,
|
||||||
|
|
@ -275,7 +282,8 @@ internal final class NIOTSConnectionChannel: StateManagedNWConnectionChannel {
|
||||||
minimumIncompleteReceiveLength: minimumIncompleteReceiveLength,
|
minimumIncompleteReceiveLength: minimumIncompleteReceiveLength,
|
||||||
maximumReceiveLength: maximumReceiveLength,
|
maximumReceiveLength: maximumReceiveLength,
|
||||||
tcpOptions: tcpOptions,
|
tcpOptions: tcpOptions,
|
||||||
tlsOptions: tlsOptions
|
tlsOptions: tlsOptions,
|
||||||
|
nwParametersConfigurator: nwParametersConfigurator
|
||||||
)
|
)
|
||||||
self.connection = connection
|
self.connection = connection
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,12 @@ public final class NIOTSListenerBootstrap {
|
||||||
private var serverQoS: DispatchQoS?
|
private var serverQoS: DispatchQoS?
|
||||||
private var childQoS: DispatchQoS?
|
private var childQoS: DispatchQoS?
|
||||||
private var tcpOptions: NWProtocolTCP.Options = .init()
|
private var tcpOptions: NWProtocolTCP.Options = .init()
|
||||||
|
private var childTCPOptions: NWProtocolTCP.Options = .init()
|
||||||
private var tlsOptions: NWProtocolTLS.Options?
|
private var tlsOptions: NWProtocolTLS.Options?
|
||||||
|
private var childTLSOptions: NWProtocolTLS.Options?
|
||||||
private var bindTimeout: TimeAmount?
|
private var bindTimeout: TimeAmount?
|
||||||
|
private var nwParametersConfigurator: (@Sendable (NWParameters) -> Void)?
|
||||||
|
private var childNWParametersConfigurator: (@Sendable (NWParameters) -> Void)?
|
||||||
|
|
||||||
/// Create a ``NIOTSListenerBootstrap`` for the `EventLoopGroup` `group`.
|
/// Create a ``NIOTSListenerBootstrap`` for the `EventLoopGroup` `group`.
|
||||||
///
|
///
|
||||||
|
|
@ -227,18 +231,46 @@ public final class NIOTSListenerBootstrap {
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specifies the TCP options to use on the child `Channel`s.
|
/// Specifies the TCP options to use on the listener.
|
||||||
public func tcpOptions(_ options: NWProtocolTCP.Options) -> Self {
|
public func tcpOptions(_ options: NWProtocolTCP.Options) -> Self {
|
||||||
self.tcpOptions = options
|
self.tcpOptions = options
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specifies the TLS options to use on the child `Channel`s.
|
/// Specifies the TCP options to use on the child `Channel`s.
|
||||||
|
public func childTCPOptions(_ options: NWProtocolTCP.Options) -> Self {
|
||||||
|
self.childTCPOptions = options
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Specifies the TLS options to use on the listener.
|
||||||
public func tlsOptions(_ options: NWProtocolTLS.Options) -> Self {
|
public func tlsOptions(_ options: NWProtocolTLS.Options) -> Self {
|
||||||
self.tlsOptions = options
|
self.tlsOptions = options
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Specifies the TLS options to use on the child `Channel`s.
|
||||||
|
public func childTLSOptions(_ options: NWProtocolTLS.Options) -> Self {
|
||||||
|
self.childTLSOptions = options
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Customise the `NWParameters` to be used when creating the `NWConnection` for the listener.
|
||||||
|
public func configureNWParameters(
|
||||||
|
_ configurator: @Sendable @escaping (NWParameters) -> Void
|
||||||
|
) -> Self {
|
||||||
|
self.nwParametersConfigurator = configurator
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Customise the `NWParameters` to be used when creating the `NWConnection`s for the child `Channel`s.
|
||||||
|
public func configureChildNWParameters(
|
||||||
|
_ configurator: @Sendable @escaping (NWParameters) -> Void
|
||||||
|
) -> Self {
|
||||||
|
self.childNWParametersConfigurator = configurator
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
/// Specifies a type of Multipath service to use for this listener, instead of the default
|
/// Specifies a type of Multipath service to use for this listener, instead of the default
|
||||||
/// service type for the event loop.
|
/// service type for the event loop.
|
||||||
///
|
///
|
||||||
|
|
@ -337,10 +369,12 @@ public final class NIOTSListenerBootstrap {
|
||||||
qos: self.serverQoS,
|
qos: self.serverQoS,
|
||||||
tcpOptions: self.tcpOptions,
|
tcpOptions: self.tcpOptions,
|
||||||
tlsOptions: self.tlsOptions,
|
tlsOptions: self.tlsOptions,
|
||||||
|
nwParametersConfigurator: self.nwParametersConfigurator,
|
||||||
childLoopGroup: self.childGroup,
|
childLoopGroup: self.childGroup,
|
||||||
childChannelQoS: self.childQoS,
|
childChannelQoS: self.childQoS,
|
||||||
childTCPOptions: self.tcpOptions,
|
childTCPOptions: self.childTCPOptions,
|
||||||
childTLSOptions: self.tlsOptions
|
childTLSOptions: self.childTLSOptions,
|
||||||
|
childNWParametersConfigurator: self.childNWParametersConfigurator
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
serverChannel = NIOTSListenerChannel(
|
serverChannel = NIOTSListenerChannel(
|
||||||
|
|
@ -348,10 +382,12 @@ public final class NIOTSListenerBootstrap {
|
||||||
qos: self.serverQoS,
|
qos: self.serverQoS,
|
||||||
tcpOptions: self.tcpOptions,
|
tcpOptions: self.tcpOptions,
|
||||||
tlsOptions: self.tlsOptions,
|
tlsOptions: self.tlsOptions,
|
||||||
|
nwParametersConfigurator: self.nwParametersConfigurator,
|
||||||
childLoopGroup: self.childGroup,
|
childLoopGroup: self.childGroup,
|
||||||
childChannelQoS: self.childQoS,
|
childChannelQoS: self.childQoS,
|
||||||
childTCPOptions: self.tcpOptions,
|
childTCPOptions: self.childTCPOptions,
|
||||||
childTLSOptions: self.tlsOptions
|
childTLSOptions: self.childTLSOptions,
|
||||||
|
childNWParametersConfigurator: self.childNWParametersConfigurator
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -558,10 +594,12 @@ extension NIOTSListenerBootstrap {
|
||||||
qos: self.serverQoS,
|
qos: self.serverQoS,
|
||||||
tcpOptions: self.tcpOptions,
|
tcpOptions: self.tcpOptions,
|
||||||
tlsOptions: self.tlsOptions,
|
tlsOptions: self.tlsOptions,
|
||||||
|
nwParametersConfigurator: self.nwParametersConfigurator,
|
||||||
childLoopGroup: self.childGroup,
|
childLoopGroup: self.childGroup,
|
||||||
childChannelQoS: self.childQoS,
|
childChannelQoS: self.childQoS,
|
||||||
childTCPOptions: self.tcpOptions,
|
childTCPOptions: self.tcpOptions,
|
||||||
childTLSOptions: self.tlsOptions
|
childTLSOptions: self.tlsOptions,
|
||||||
|
childNWParametersConfigurator: self.nwParametersConfigurator
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
serverChannel = NIOTSListenerChannel(
|
serverChannel = NIOTSListenerChannel(
|
||||||
|
|
@ -569,10 +607,12 @@ extension NIOTSListenerBootstrap {
|
||||||
qos: self.serverQoS,
|
qos: self.serverQoS,
|
||||||
tcpOptions: self.tcpOptions,
|
tcpOptions: self.tcpOptions,
|
||||||
tlsOptions: self.tlsOptions,
|
tlsOptions: self.tlsOptions,
|
||||||
|
nwParametersConfigurator: self.nwParametersConfigurator,
|
||||||
childLoopGroup: self.childGroup,
|
childLoopGroup: self.childGroup,
|
||||||
childChannelQoS: self.childQoS,
|
childChannelQoS: self.childQoS,
|
||||||
childTCPOptions: self.tcpOptions,
|
childTCPOptions: self.tcpOptions,
|
||||||
childTLSOptions: self.tlsOptions
|
childTLSOptions: self.tlsOptions,
|
||||||
|
childNWParametersConfigurator: self.nwParametersConfigurator
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,19 +81,23 @@ internal final class NIOTSListenerChannel: StateManagedListenerChannel<NIOTSConn
|
||||||
qos: DispatchQoS? = nil,
|
qos: DispatchQoS? = nil,
|
||||||
tcpOptions: NWProtocolTCP.Options,
|
tcpOptions: NWProtocolTCP.Options,
|
||||||
tlsOptions: NWProtocolTLS.Options?,
|
tlsOptions: NWProtocolTLS.Options?,
|
||||||
|
nwParametersConfigurator: (@Sendable (NWParameters) -> Void)?,
|
||||||
childLoopGroup: EventLoopGroup,
|
childLoopGroup: EventLoopGroup,
|
||||||
childChannelQoS: DispatchQoS?,
|
childChannelQoS: DispatchQoS?,
|
||||||
childTCPOptions: NWProtocolTCP.Options,
|
childTCPOptions: NWProtocolTCP.Options,
|
||||||
childTLSOptions: NWProtocolTLS.Options?
|
childTLSOptions: NWProtocolTLS.Options?,
|
||||||
|
childNWParametersConfigurator: (@Sendable (NWParameters) -> Void)?
|
||||||
) {
|
) {
|
||||||
self.init(
|
self.init(
|
||||||
eventLoop: eventLoop,
|
eventLoop: eventLoop,
|
||||||
protocolOptions: .tcp(tcpOptions),
|
protocolOptions: .tcp(tcpOptions),
|
||||||
tlsOptions: tlsOptions,
|
tlsOptions: tlsOptions,
|
||||||
|
nwParametersConfigurator: nwParametersConfigurator,
|
||||||
childLoopGroup: childLoopGroup,
|
childLoopGroup: childLoopGroup,
|
||||||
childChannelQoS: childChannelQoS,
|
childChannelQoS: childChannelQoS,
|
||||||
childProtocolOptions: .tcp(childTCPOptions),
|
childProtocolOptions: .tcp(childTCPOptions),
|
||||||
childTLSOptions: childTLSOptions
|
childTLSOptions: childTLSOptions,
|
||||||
|
childNWParametersConfigurator: childNWParametersConfigurator
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -104,10 +108,12 @@ internal final class NIOTSListenerChannel: StateManagedListenerChannel<NIOTSConn
|
||||||
qos: DispatchQoS? = nil,
|
qos: DispatchQoS? = nil,
|
||||||
tcpOptions: NWProtocolTCP.Options,
|
tcpOptions: NWProtocolTCP.Options,
|
||||||
tlsOptions: NWProtocolTLS.Options?,
|
tlsOptions: NWProtocolTLS.Options?,
|
||||||
|
nwParametersConfigurator: (@Sendable (NWParameters) -> Void)?,
|
||||||
childLoopGroup: EventLoopGroup,
|
childLoopGroup: EventLoopGroup,
|
||||||
childChannelQoS: DispatchQoS?,
|
childChannelQoS: DispatchQoS?,
|
||||||
childTCPOptions: NWProtocolTCP.Options,
|
childTCPOptions: NWProtocolTCP.Options,
|
||||||
childTLSOptions: NWProtocolTLS.Options?
|
childTLSOptions: NWProtocolTLS.Options?,
|
||||||
|
childNWParametersConfigurator: (@Sendable (NWParameters) -> Void)?
|
||||||
) {
|
) {
|
||||||
self.init(
|
self.init(
|
||||||
wrapping: listener,
|
wrapping: listener,
|
||||||
|
|
@ -115,10 +121,12 @@ internal final class NIOTSListenerChannel: StateManagedListenerChannel<NIOTSConn
|
||||||
qos: qos,
|
qos: qos,
|
||||||
protocolOptions: .tcp(tcpOptions),
|
protocolOptions: .tcp(tcpOptions),
|
||||||
tlsOptions: tlsOptions,
|
tlsOptions: tlsOptions,
|
||||||
|
nwParametersConfigurator: nwParametersConfigurator,
|
||||||
childLoopGroup: childLoopGroup,
|
childLoopGroup: childLoopGroup,
|
||||||
childChannelQoS: childChannelQoS,
|
childChannelQoS: childChannelQoS,
|
||||||
childProtocolOptions: .tcp(childTCPOptions),
|
childProtocolOptions: .tcp(childTCPOptions),
|
||||||
childTLSOptions: childTLSOptions
|
childTLSOptions: childTLSOptions,
|
||||||
|
childNWParametersConfigurator: childNWParametersConfigurator
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -134,7 +142,8 @@ internal final class NIOTSListenerChannel: StateManagedListenerChannel<NIOTSConn
|
||||||
parent: self,
|
parent: self,
|
||||||
qos: self.childChannelQoS,
|
qos: self.childChannelQoS,
|
||||||
tcpOptions: self.childTCPOptions,
|
tcpOptions: self.childTCPOptions,
|
||||||
tlsOptions: self.childTLSOptions
|
tlsOptions: self.childTLSOptions,
|
||||||
|
nwParametersConfigurator: self.childNWParametersConfigurator
|
||||||
)
|
)
|
||||||
|
|
||||||
self.pipeline.fireChannelRead(newChannel)
|
self.pipeline.fireChannelRead(newChannel)
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,9 @@ internal class StateManagedListenerChannel<ChildChannel: StateManagedChannel>: S
|
||||||
/// The TLS options for this listener.
|
/// The TLS options for this listener.
|
||||||
internal let tlsOptions: NWProtocolTLS.Options?
|
internal let tlsOptions: NWProtocolTLS.Options?
|
||||||
|
|
||||||
|
/// A customization point for this listener's `NWParameters`.
|
||||||
|
internal let nwParametersConfigurator: (@Sendable (NWParameters) -> Void)?
|
||||||
|
|
||||||
/// The `DispatchQueue` that socket events for this connection will be dispatched onto.
|
/// The `DispatchQueue` that socket events for this connection will be dispatched onto.
|
||||||
internal let connectionQueue: DispatchQueue
|
internal let connectionQueue: DispatchQueue
|
||||||
|
|
||||||
|
|
@ -113,6 +116,9 @@ internal class StateManagedListenerChannel<ChildChannel: StateManagedChannel>: S
|
||||||
/// The TLS options to use for child channels.
|
/// The TLS options to use for child channels.
|
||||||
internal let childTLSOptions: NWProtocolTLS.Options?
|
internal let childTLSOptions: NWProtocolTLS.Options?
|
||||||
|
|
||||||
|
/// A customization point for each child's `NWParameters`.
|
||||||
|
internal let childNWParametersConfigurator: (@Sendable (NWParameters) -> Void)?
|
||||||
|
|
||||||
/// The cache of the local and remote socket addresses. Must be accessed using _addressCacheLock.
|
/// The cache of the local and remote socket addresses. Must be accessed using _addressCacheLock.
|
||||||
internal var addressCache = AddressCache(local: nil, remote: nil)
|
internal var addressCache = AddressCache(local: nil, remote: nil)
|
||||||
|
|
||||||
|
|
@ -130,20 +136,24 @@ internal class StateManagedListenerChannel<ChildChannel: StateManagedChannel>: S
|
||||||
qos: DispatchQoS? = nil,
|
qos: DispatchQoS? = nil,
|
||||||
protocolOptions: ProtocolOptions,
|
protocolOptions: ProtocolOptions,
|
||||||
tlsOptions: NWProtocolTLS.Options?,
|
tlsOptions: NWProtocolTLS.Options?,
|
||||||
|
nwParametersConfigurator: (@Sendable (NWParameters) -> Void)?,
|
||||||
childLoopGroup: EventLoopGroup,
|
childLoopGroup: EventLoopGroup,
|
||||||
childChannelQoS: DispatchQoS?,
|
childChannelQoS: DispatchQoS?,
|
||||||
childProtocolOptions: ProtocolOptions,
|
childProtocolOptions: ProtocolOptions,
|
||||||
childTLSOptions: NWProtocolTLS.Options?
|
childTLSOptions: NWProtocolTLS.Options?,
|
||||||
|
childNWParametersConfigurator: (@Sendable (NWParameters) -> Void)?
|
||||||
) {
|
) {
|
||||||
self.tsEventLoop = eventLoop
|
self.tsEventLoop = eventLoop
|
||||||
self.closePromise = eventLoop.makePromise()
|
self.closePromise = eventLoop.makePromise()
|
||||||
self.connectionQueue = eventLoop.channelQueue(label: "nio.transportservices.listenerchannel", qos: qos)
|
self.connectionQueue = eventLoop.channelQueue(label: "nio.transportservices.listenerchannel", qos: qos)
|
||||||
self.protocolOptions = protocolOptions
|
self.protocolOptions = protocolOptions
|
||||||
self.tlsOptions = tlsOptions
|
self.tlsOptions = tlsOptions
|
||||||
|
self.nwParametersConfigurator = nwParametersConfigurator
|
||||||
self.childLoopGroup = childLoopGroup
|
self.childLoopGroup = childLoopGroup
|
||||||
self.childChannelQoS = childChannelQoS
|
self.childChannelQoS = childChannelQoS
|
||||||
self.childProtocolOptions = childProtocolOptions
|
self.childProtocolOptions = childProtocolOptions
|
||||||
self.childTLSOptions = childTLSOptions
|
self.childTLSOptions = childTLSOptions
|
||||||
|
self.childNWParametersConfigurator = childNWParametersConfigurator
|
||||||
|
|
||||||
// Must come last, as it requires self to be completely initialized.
|
// Must come last, as it requires self to be completely initialized.
|
||||||
self._pipeline = ChannelPipeline(channel: self)
|
self._pipeline = ChannelPipeline(channel: self)
|
||||||
|
|
@ -155,20 +165,24 @@ internal class StateManagedListenerChannel<ChildChannel: StateManagedChannel>: S
|
||||||
qos: DispatchQoS? = nil,
|
qos: DispatchQoS? = nil,
|
||||||
protocolOptions: ProtocolOptions,
|
protocolOptions: ProtocolOptions,
|
||||||
tlsOptions: NWProtocolTLS.Options?,
|
tlsOptions: NWProtocolTLS.Options?,
|
||||||
|
nwParametersConfigurator: (@Sendable (NWParameters) -> Void)?,
|
||||||
childLoopGroup: EventLoopGroup,
|
childLoopGroup: EventLoopGroup,
|
||||||
childChannelQoS: DispatchQoS?,
|
childChannelQoS: DispatchQoS?,
|
||||||
childProtocolOptions: ProtocolOptions,
|
childProtocolOptions: ProtocolOptions,
|
||||||
childTLSOptions: NWProtocolTLS.Options?
|
childTLSOptions: NWProtocolTLS.Options?,
|
||||||
|
childNWParametersConfigurator: (@Sendable (NWParameters) -> Void)?
|
||||||
) {
|
) {
|
||||||
self.init(
|
self.init(
|
||||||
eventLoop: eventLoop,
|
eventLoop: eventLoop,
|
||||||
qos: qos,
|
qos: qos,
|
||||||
protocolOptions: protocolOptions,
|
protocolOptions: protocolOptions,
|
||||||
tlsOptions: tlsOptions,
|
tlsOptions: tlsOptions,
|
||||||
|
nwParametersConfigurator: nwParametersConfigurator,
|
||||||
childLoopGroup: childLoopGroup,
|
childLoopGroup: childLoopGroup,
|
||||||
childChannelQoS: childChannelQoS,
|
childChannelQoS: childChannelQoS,
|
||||||
childProtocolOptions: childProtocolOptions,
|
childProtocolOptions: childProtocolOptions,
|
||||||
childTLSOptions: childTLSOptions
|
childTLSOptions: childTLSOptions,
|
||||||
|
childNWParametersConfigurator: childNWParametersConfigurator
|
||||||
)
|
)
|
||||||
self.nwListener = listener
|
self.nwListener = listener
|
||||||
}
|
}
|
||||||
|
|
@ -398,6 +412,8 @@ extension StateManagedListenerChannel {
|
||||||
|
|
||||||
parameters.multipathServiceType = self.multipathServiceType
|
parameters.multipathServiceType = self.multipathServiceType
|
||||||
|
|
||||||
|
self.nwParametersConfigurator?(parameters)
|
||||||
|
|
||||||
let listener: NWListener
|
let listener: NWListener
|
||||||
do {
|
do {
|
||||||
listener = try NWListener(using: parameters)
|
listener = try NWListener(using: parameters)
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,8 @@ internal protocol StateManagedNWConnectionChannel: StateManagedChannel where Act
|
||||||
|
|
||||||
var multipathServiceType: NWParameters.MultipathServiceType { get }
|
var multipathServiceType: NWParameters.MultipathServiceType { get }
|
||||||
|
|
||||||
|
var nwParametersConfigurator: (@Sendable (NWParameters) -> Void)? { get }
|
||||||
|
|
||||||
func setChannelSpecificOption0<Option: ChannelOption>(option: Option, value: Option.Value) throws
|
func setChannelSpecificOption0<Option: ChannelOption>(option: Option, value: Option.Value) throws
|
||||||
|
|
||||||
func getChannelSpecificOption0<Option: ChannelOption>(option: Option) throws -> Option.Value
|
func getChannelSpecificOption0<Option: ChannelOption>(option: Option) throws -> Option.Value
|
||||||
|
|
@ -242,6 +244,7 @@ extension StateManagedNWConnectionChannel {
|
||||||
connection.betterPathUpdateHandler = self.betterPathHandler
|
connection.betterPathUpdateHandler = self.betterPathHandler
|
||||||
connection.viabilityUpdateHandler = self.viabilityUpdateHandler
|
connection.viabilityUpdateHandler = self.viabilityUpdateHandler
|
||||||
connection.pathUpdateHandler = self.pathChangedHandler(newPath:)
|
connection.pathUpdateHandler = self.pathChangedHandler(newPath:)
|
||||||
|
self.nwParametersConfigurator?(connection.parameters)
|
||||||
connection.start(queue: self.connectionQueue)
|
connection.start(queue: self.connectionQueue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -371,6 +371,49 @@ final class NIOTSBootstrapTests: XCTestCase {
|
||||||
XCTAssertEqual(try listenerChannel.getOption(NIOTSChannelOptions.multipathServiceType).wait(), .handover)
|
XCTAssertEqual(try listenerChannel.getOption(NIOTSChannelOptions.multipathServiceType).wait(), .handover)
|
||||||
XCTAssertEqual(try connectionChannel.getOption(NIOTSChannelOptions.multipathServiceType).wait(), .handover)
|
XCTAssertEqual(try connectionChannel.getOption(NIOTSChannelOptions.multipathServiceType).wait(), .handover)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testNWParametersConfigurator() async throws {
|
||||||
|
try await withEventLoopGroup { group in
|
||||||
|
let configuratorServerListenerCounter = NIOLockedValueBox(0)
|
||||||
|
let configuratorServerConnectionCounter = NIOLockedValueBox(0)
|
||||||
|
let configuratorClientConnectionCounter = NIOLockedValueBox(0)
|
||||||
|
let waitForConnectionHandler = WaitForConnectionHandler(
|
||||||
|
connectionPromise: group.next().makePromise()
|
||||||
|
)
|
||||||
|
|
||||||
|
let listenerChannel = try await NIOTSListenerBootstrap(group: group)
|
||||||
|
.childChannelInitializer { connectionChannel in
|
||||||
|
connectionChannel.eventLoop.makeCompletedFuture {
|
||||||
|
try connectionChannel.pipeline.syncOperations.addHandler(waitForConnectionHandler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.configureNWParameters { _ in
|
||||||
|
configuratorServerListenerCounter.withLockedValue { $0 += 1 }
|
||||||
|
}
|
||||||
|
.configureChildNWParameters { _ in
|
||||||
|
configuratorServerConnectionCounter.withLockedValue { $0 += 1 }
|
||||||
|
}
|
||||||
|
.bind(host: "localhost", port: 0)
|
||||||
|
.get()
|
||||||
|
|
||||||
|
let connectionChannel: Channel = try await NIOTSConnectionBootstrap(group: group)
|
||||||
|
.configureNWParameters { _ in
|
||||||
|
configuratorClientConnectionCounter.withLockedValue { $0 += 1 }
|
||||||
|
}
|
||||||
|
.connect(to: listenerChannel.localAddress!)
|
||||||
|
.get()
|
||||||
|
|
||||||
|
// Wait for the server to activate the connection channel to the client.
|
||||||
|
try await waitForConnectionHandler.connectionPromise.futureResult.get()
|
||||||
|
|
||||||
|
try await listenerChannel.close().get()
|
||||||
|
try await connectionChannel.close().get()
|
||||||
|
|
||||||
|
XCTAssertEqual(1, configuratorServerListenerCounter.withLockedValue { $0 })
|
||||||
|
XCTAssertEqual(1, configuratorServerConnectionCounter.withLockedValue { $0 })
|
||||||
|
XCTAssertEqual(1, configuratorClientConnectionCounter.withLockedValue { $0 })
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Channel {
|
extension Channel {
|
||||||
|
|
|
||||||
|
|
@ -37,13 +37,14 @@ final class NIOTSChannelMetadataTests: XCTestCase {
|
||||||
}.wait()
|
}.wait()
|
||||||
|
|
||||||
}
|
}
|
||||||
func testThowsIfCalledOnANonInitializedChannel() {
|
func testThrowsIfCalledOnANonInitializedChannel() {
|
||||||
let eventLoopGroup = NIOTSEventLoopGroup()
|
let eventLoopGroup = NIOTSEventLoopGroup()
|
||||||
defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) }
|
defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) }
|
||||||
let channel = NIOTSConnectionChannel(
|
let channel = NIOTSConnectionChannel(
|
||||||
eventLoop: eventLoopGroup.next() as! NIOTSEventLoop,
|
eventLoop: eventLoopGroup.next() as! NIOTSEventLoop,
|
||||||
tcpOptions: .init(),
|
tcpOptions: .init(),
|
||||||
tlsOptions: .init()
|
tlsOptions: .init(),
|
||||||
|
nwParametersConfigurator: nil
|
||||||
)
|
)
|
||||||
XCTAssertThrowsError(try channel.getMetadata(definition: NWProtocolTLS.definition).wait()) { error in
|
XCTAssertThrowsError(try channel.getMetadata(definition: NWProtocolTLS.definition).wait()) { error in
|
||||||
XCTAssertTrue(error is NIOTSConnectionNotInitialized, "unexpected error \(error)")
|
XCTAssertTrue(error is NIOTSConnectionNotInitialized, "unexpected error \(error)")
|
||||||
|
|
|
||||||
|
|
@ -272,11 +272,15 @@ class NIOTSConnectionChannelTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSettingTCPOptionsWholesale() throws {
|
func testSettingTCPOptionsWholesale() throws {
|
||||||
let tcpOptions = NWProtocolTCP.Options()
|
let listenerTCPOptions = NWProtocolTCP.Options()
|
||||||
tcpOptions.disableAckStretching = true
|
listenerTCPOptions.disableAckStretching = true
|
||||||
|
|
||||||
|
let connectionTCPOptions = NWProtocolTCP.Options()
|
||||||
|
connectionTCPOptions.disableAckStretching = true
|
||||||
|
|
||||||
let listener = try NIOTSListenerBootstrap(group: self.group)
|
let listener = try NIOTSListenerBootstrap(group: self.group)
|
||||||
.tcpOptions(tcpOptions)
|
.tcpOptions(listenerTCPOptions)
|
||||||
|
.childTCPOptions(connectionTCPOptions)
|
||||||
.serverChannelInitializer { channel in
|
.serverChannelInitializer { channel in
|
||||||
channel.getOption(ChannelOptions.socket(IPPROTO_TCP, TCP_SENDMOREACKS)).map { value in
|
channel.getOption(ChannelOptions.socket(IPPROTO_TCP, TCP_SENDMOREACKS)).map { value in
|
||||||
XCTAssertEqual(value, 1)
|
XCTAssertEqual(value, 1)
|
||||||
|
|
@ -293,7 +297,7 @@ class NIOTSConnectionChannelTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
let connection = try NIOTSConnectionBootstrap(group: self.group)
|
let connection = try NIOTSConnectionBootstrap(group: self.group)
|
||||||
.tcpOptions(tcpOptions)
|
.tcpOptions(connectionTCPOptions)
|
||||||
.channelInitializer { channel in
|
.channelInitializer { channel in
|
||||||
channel.getOption(ChannelOptions.socket(IPPROTO_TCP, TCP_SENDMOREACKS)).map { value in
|
channel.getOption(ChannelOptions.socket(IPPROTO_TCP, TCP_SENDMOREACKS)).map { value in
|
||||||
XCTAssertEqual(value, 1)
|
XCTAssertEqual(value, 1)
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import Network
|
||||||
import NIOCore
|
import NIOCore
|
||||||
import NIOTransportServices
|
import NIOTransportServices
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import NIOConcurrencyHelpers
|
||||||
|
|
||||||
extension Channel {
|
extension Channel {
|
||||||
func wait<T: Sendable>(for type: T.Type, count: Int) throws -> [T] {
|
func wait<T: Sendable>(for type: T.Type, count: Int) throws -> [T] {
|
||||||
|
|
@ -232,6 +233,54 @@ final class NIOTSDatagramConnectionChannelTests: XCTestCase {
|
||||||
XCTAssertNoThrow(try connection.close().wait())
|
XCTAssertNoThrow(try connection.close().wait())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testNWParametersConfigurator() async throws {
|
||||||
|
try await withEventLoopGroup { group in
|
||||||
|
let configuratorServerListenerCounter = NIOLockedValueBox(0)
|
||||||
|
let configuratorServerConnectionCounter = NIOLockedValueBox(0)
|
||||||
|
let configuratorClientConnectionCounter = NIOLockedValueBox(0)
|
||||||
|
let waitForConnectionHandler = WaitForConnectionHandler(
|
||||||
|
connectionPromise: group.next().makePromise()
|
||||||
|
)
|
||||||
|
|
||||||
|
let listenerChannel = try await NIOTSDatagramListenerBootstrap(group: group)
|
||||||
|
.childChannelInitializer { connectionChannel in
|
||||||
|
connectionChannel.eventLoop.makeCompletedFuture {
|
||||||
|
try connectionChannel.pipeline.syncOperations.addHandler(waitForConnectionHandler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.configureNWParameters { _ in
|
||||||
|
configuratorServerListenerCounter.withLockedValue { $0 += 1 }
|
||||||
|
}
|
||||||
|
.configureChildNWParameters { _ in
|
||||||
|
configuratorServerConnectionCounter.withLockedValue { $0 += 1 }
|
||||||
|
}
|
||||||
|
.bind(host: "localhost", port: 0)
|
||||||
|
.get()
|
||||||
|
|
||||||
|
let connectionChannel: Channel = try await NIOTSDatagramBootstrap(group: group)
|
||||||
|
.configureNWParameters { _ in
|
||||||
|
configuratorClientConnectionCounter.withLockedValue { $0 += 1 }
|
||||||
|
}
|
||||||
|
.connect(to: listenerChannel.localAddress!)
|
||||||
|
.get()
|
||||||
|
|
||||||
|
// Need to write something so the server can activate the connection channel: this is UDP,
|
||||||
|
// so there is no handshaking that happens and thus the server cannot know that the
|
||||||
|
// connection has been established and the channel can be activated until we receive something.
|
||||||
|
try await connectionChannel.writeAndFlush(ByteBuffer(bytes: [42]))
|
||||||
|
|
||||||
|
// Wait for the server to activate the connection channel to the client.
|
||||||
|
try await waitForConnectionHandler.connectionPromise.futureResult.get()
|
||||||
|
|
||||||
|
try await listenerChannel.close().get()
|
||||||
|
try await connectionChannel.close().get()
|
||||||
|
|
||||||
|
XCTAssertEqual(1, configuratorServerListenerCounter.withLockedValue { $0 })
|
||||||
|
XCTAssertEqual(1, configuratorServerConnectionCounter.withLockedValue { $0 })
|
||||||
|
XCTAssertEqual(1, configuratorClientConnectionCounter.withLockedValue { $0 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testCanExtractTheConnection() throws {
|
func testCanExtractTheConnection() throws {
|
||||||
guard #available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *) else {
|
guard #available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *) else {
|
||||||
throw XCTSkip("Option not available")
|
throw XCTSkip("Option not available")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// This source file is part of the SwiftNIO open source project
|
||||||
|
//
|
||||||
|
// Copyright (c) 2017-2025 Apple Inc. and the SwiftNIO project authors
|
||||||
|
// Licensed under Apache License v2.0
|
||||||
|
//
|
||||||
|
// See LICENSE.txt for license information
|
||||||
|
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#if canImport(Network)
|
||||||
|
import NIOCore
|
||||||
|
import NIOTransportServices
|
||||||
|
|
||||||
|
func withEventLoopGroup(_ test: (EventLoopGroup) async throws -> Void) async rethrows {
|
||||||
|
let group = NIOTSEventLoopGroup()
|
||||||
|
do {
|
||||||
|
try await test(group)
|
||||||
|
try? await group.shutdownGracefully()
|
||||||
|
} catch {
|
||||||
|
try? await group.shutdownGracefully()
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class WaitForConnectionHandler: ChannelInboundHandler, Sendable {
|
||||||
|
typealias InboundIn = Never
|
||||||
|
|
||||||
|
let connectionPromise: EventLoopPromise<Void>
|
||||||
|
|
||||||
|
init(connectionPromise: EventLoopPromise<Void>) {
|
||||||
|
self.connectionPromise = connectionPromise
|
||||||
|
}
|
||||||
|
|
||||||
|
func channelActive(context: ChannelHandlerContext) {
|
||||||
|
self.connectionPromise.succeed()
|
||||||
|
context.fireChannelActive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Loading…
Reference in New Issue