* Revert "Back out SPI(AsyncChannel) changes"
This reverts commit 33d2b2993f.
* Add new typed async bootstrap APIs back and drop SPI
# Motivation
We just merged the removal of the `AsyncChannel` SPI in NIO and can now add back the new APIs in transport services as well.
# Modification
This PR brings back the previous SPI and promotes it to API.
# Result
New typed async bootstraps API for `NIOTransportServices`.
* George review
* Fire the pipelines error caughted method when NWConnection's state changes to failed
* Added check if failed error is ChannelError.eof and added a unit test for forwarding failed connnection state errors
* Completing a promise for the error caught
* Fixed Typo
* Removed whitespace
* Binding the listener to port 0 and connecting to listerner's localAddress
Motivation:
The datagram tests use a handler which sets its event loop in
`channelRegistered`. A function on the handler is called which relies on
the EL being set. However, this can race: the function can be called
before `channelRegistered` is called.
Modifications:
- set the EL in `handlerAdded`
Result:
Fewer crashes
Motivation:
This change was made because UDP support was lacking on iOS. It's needed by my DNS client implementation, which I am in turn using for an iOS app I'm working on relying on SRV typed records.
Modifications:
Adds a NIOTSDatagramListenerBootstrap for making UDP services
Adds a NIOTSDatagramListenerChannel that accepts UDP connections
Adds a NIOTSDatagramChannel for UDP client connections
Adds a NIOTSDatagramBootstrap that can create a new UDP client
# Motivation
We want to release a new `NIOTS` version without the SPI changes for now.
# Modification
This PR backs out the new `NIOAsyncChannel` APIs.
# Result
No more SPI usage so we can safely release.
# Motivation
We had some breaking changes in the NIO AsyncChannel SPI which we have to adapt here.
# Modification
This PR updates to the latest AsyncChannel SPI
# Result
No more warnings and errors when building.
# Motivation
After my recent PR we failed to compile on 5.6 since the compiler isn't capable to infer the return type of one of the closures.
# Modification
This PR adds the closure's return type explicitly.
# Result
Compiling on 5.6 again
# Motivation
We introduced some breaking SPI(AsyncChannel) changes in NIO that we have to adopt here.
# Modification
This PR adopts the latest `NIOProtocolNegotiationResult` APIs. Additionally, it also drops all bind/connect methods on the bootstraps that are specific to protocol negotiation or `NIOAsyncChannel`.
# Result
Green CI on `main` and alignment between `NIOPosix` and `NIOTS.
# Motivation
We introduced a new configuration struct for `NIOAsyncChannel` to make handling and configuring it easier.
# Modification
This PR adopts the new APIs.
# Result
Less boilerplate in our bootstrap methods
* Extract the NWConnection code into StateManagedNWConnectionChannel
* Add a general setup for NWListener implementations
* Add support for UDPOptions as a NWOptionsProtocol type
* Complete the rebase to main
* Fix nits from PR review
* Clean up some of the invalid rebase
* Async methods for `NIOTSListenerBootstrap` and `NIOTSConnectionBootstrap`
# Motivation
We want to support async bootstrapping with all our bootstraps.
# Modification
This PR adds support for the `NIOTSListenerBootstrap` and `NIOTSConnectionBootstrap`. It also adds the three variants of methods to it (abstract output, `NIOAsyncChannel` based and protocol negotiation based)
# Result
We now support asynchronous interaction with the `NIOTSListenerBootstrap` and `NIOTSConnectionBootstrap`
* Use protocolHandlers properly
* Update NIO version
* code review
* REview
* Doc indention
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.
Motivation:
#fileID introduced in Swift 5.3, so no longer need to use #file anywhere
Modifications:
Changed #file to #filePath or #fileID depending on situation
* Allow retrieval of metadata for a specific protocol from the underlying `NWConnection`
* Address review comments
* Address review comment
* Add availability annotation to tests
* Rename `NIOTSChannelIsNotATransportServicesChannel ` to `NIOTSChannelIsNotANIOTSConnectionChannel `
Motivation:
Lock has been deprecated in favour of NIOLock. Warnings aren't great.
Modifications:
- Replace Lock with NIOLock
- Update the minimum required NIO version to 2.42.0.
Result:
Everything builds cleanly
NIO Transport Services is not capable of launching services with existing NWConnection or NWListener objects. Being able to get
an existing NWConnection through a connection bootstrap and into a channel is a useful capability for advanced use cases.
Modifications:
* Added an option to bootstrap with existing NWListener and NWConnection
* Completed promise connection earlier within NIOTSChannels when AlreadyConfigured is called
* Added test with new NWConnection and NWListener to register Channels
Result:
Able to create and register a channel using an existing NWListener and NWConnection
Motivation
Documentation is nice, and we can help support users by providing useful
clear docs.
Modifications
Add Docc to 5.6 and later builds
Make sure symbol references work
Add overview docs
Result
Nice rendering docs
Motivation:
When we're waiting for connectivity, the user might tell us that they
aren't interested in waiting. In that case we take advantage of the
signal and close early.
However, the code as-written had a bug: we didn't care whether the user
told us they _didn't_ want to wait, or they _did_: we just closed
because they had an opinion! That's no good! We should only close if
they don't want to wait.
Modifications:
- Only close if the user doesn't want to wait.
- Add tests
Result:
We won't close if users don't want us to.
Motivation:
Private Relay kicks in to secure unencrypted data transfers, and
connections to port 80 are a good signal. As a result, the current
construction of this test will invoke Private Relay and attempt to route
over it.
While Private Relay is in beta this is a bad outcome, as it risks
causing bugs in unusual network scenarios. So let's tell Private Relay
we don't need it.
Modifications:
Pretend we're gonna connect to 443 instead.
Result:
More reliable test.
Motivation:
With NIO 2.32.0 we broke the core NIO module up into modules that split
apart the POSIX layer and the core abstractions. As a result, this
package no longer needs to express a hard dependency on the POSIX layer.
Modifications:
- Rewrote imports of NIO to NIOCore.
- Added NIOEmbedded imports where necessary in tests.
- Note that the main package still _depends_ on NIO, which is necessary
for backwards-compatibility reasons. This dependency is unused.
Result:
No need to use NIOPosix.
Motivation:
NIO 2.27.0 added optional support for synchronous channel options.
NIOTSListenerChannel and NIOTSConnectionChannel should support this.
Modifications:
- Add synchronous options for NIOTSConnectionChannel and
NIOTSListenerChannel
- Avoid an allocation in 'getOption' for each channel if the caller is
already on the right event loop by using 'makeSucceededFuture'
- Remove a no longer used internal function and an already dead private
helper
Result:
- Support for sync options and fewer allocations
Motivation:
We shouldn't crash if the user gives us a bad port.
Modifications:
- Check the ports are in-band before we move on.
Result:
We won't crash.
Motivation:
The zero-length writes handler will crash if it receives channelInactive
before channelActive. Sadly, that's totally possible if a channel is
closed from the connect promise.
Modifications:
- Tone back the preconditions a bit.
- Add a test that triggers this path.
Result:
Channel handler behaves better on early close
Motivation:
Network.framework will crash when we attempt to connect to the host
string "". That's not ideal, so we should detect that case and avoid it.
Modifications:
- Add code to detect the empty host string.
Result:
No crashes when accidentally connecting to "".
Motivation:
The NetworkFramework directly supports the concept of allowLocalEndPointReuse. Currently to get through the nio system, this is mapped to the SO_REUSEADDR option.
Now there is a shorthand option for this, it is sad to map from allowLocalEndPointReuse to SO_REUSEADDR and back again.
Modifications:
Add a new NIOTS channel option for this setting.
Set the underlying based on any of new setting, reuseAddr or reusePort.
Add a override to interpret the shorthand option directly into the new option.
Add shorthand options for client with tests of equivalence to long options.
Result:
Behaviour is identical but we can feel happier that the option mapping is less confusing.
Motivation:
On Apple's devices it is considered a best practice to wait for network
connectivity in cases when a connection request cannot immediately be
satisfied, rather than erroring out. This reflects the dynamic and fluid
network environment on Apple devices, with their many network interfaces
and complex interactions between radios, VPNs, and network devices.
While NIOTS supports this model of interaction (and indeed uses it out
of the box), and supports configuring it (by setting
`NIOTSChannelOptions.waitForActivity`), a key pillar is missing:
observability. Right now we don't actually _tell_ the user when we're
waiting for connectivity. This makes it difficult to act on this
information.
Modifications:
- Added a user event, `NIOTSNetworkEvents.WaitingForConnectivity` that
is fired when connectivity could not be established, but the situation
may change in future.
Result:
Our users can tell their users when they're waiting for something!
* Initial draft implementation of new channel options for NWConnection.currentPath, metadata for a given NWProtocol, establishment report and data transfer report. Add a new error for not existing connection. Add tests for all of these. The data transfer report option has to be implemented in another way, as the collection of the final data transfer report does not seem very straightforward.
* Fix incorrect available attributes. Make the Value of NIOTSEstablishmentReportOption an EventLoopFuture returning an optional report. Move handling of NIOTSEstablishmentReportOption and NIOTSDataTransferReportOption to getOption0. Remove nwConnection0().
* Use full type on currentPath too.
* Add a DispatchQueue to do collect of the pending data transfer report, use a DispatchGroup to wait for completion of report collection. Remove redundant attribute. Fix nits related to spacing and file header.
* Fix available attributes for tests too.
Motivation:
Today, we just expect the ELGs passed to the bootstraps to be the
correct ones, if not, we crash.
Modifications:
Offer an alternative validatingGroup: init that just returns nil
if the ELGs are of the wrong types.
Result:
Easier to work with multi-stack systems for example when the user might
pass an ELG for either NIO on Sockets or NIO on Network.framework.
This is the NIOTS companion for https://github.com/apple/swift-nio/pull/1464
Add filter removing empty writes to remedy a bug in Network Framework. This is a work in progress, after some initial discussions and suggestions by @weissi.
Motivation:
There is a known bug in Network Framework affecting iOS devices, which will stall a TCP connection after an empty, zero length write. This bug is not found in Network Framework on MacOS. While the bug fix will be rolled out in future versions of iOS it may take some time. Also, to better support the current and older versions of iOS where the bug remains, @weissi suggested to add a ChannelOutboundHandler, that filters out empty writes.
Modifications:
Add a FilterEmptyWritesHandler, which on affected iOS versions can be added by default to all Channels.
Unit tests for all additions and modifications.
Result:
With this workaround NIOTransportServices can support all iOS versions with Network Framework.
Motivation:
Syncing onto the event loop queues is essentially never acceptable: we
can't appropriately guard against it going terribly wrong.
Modifications:
- Use locks instead, locks are good.
Result:
Removes some crashes.
Resolves#70.
Motivation:
We deprecated Atomic because we made a new, better one. We should use
it.
Modifications:
Replaced all use of Atomic with NIOAtomic.
Result:
Better performance, fewer compiler warnings.
Motivation:
Sadly the previous NIO warnings patch failed to notice that the tests
had a bunch of errors, despite the fact that those tests were
(repeatedly) run.
Modifications:
Directly apply the fixits.
Result:
Fewer warnings
Motivation:
NIO on BSD Sockets had an issue where it wouldn't tolerate futures from
foreign EventLoops being returned from the channel initializers. NIOTS
should also have a test that tests this situation despite the fact that
it didn't have the same bug.
Modification:
- add a test case
- add more assertions
Result:
Better tests.
Motivation:
In Network.framework it is possible for a bind operation to take a while
to complete if it ends up waiting for appropriate network conditions. As
a result, unlike in the POSIX case, we need to give users the ability
to configure the maximum amount of time they'd be willing to wait for a
bind call to succeed.
Modifications:
- Add a bind timeout.
Result:
Users won't have to wait forever.
Motivation:
When autoRead is on, the pipeline must observe the read calls in order
to be able to exert backpressure. Otherwise, autoRead is a
zero-backpressure mode, which isn't great.
Correctly call pipeline.read instead of self.read0 to avoid this.
Modifications:
- Updated NIOTSConnectionChannel to call pipeline.read().
Result:
Backpressure can be exerted.
Motivation:
Networking software like SwiftNIO that always has explicit flushes
usually does not benefit from having TCP_NODELAY switched off. The
benefits of having it turned on are usually quite substantial and yet we
forced our users for the longest time to enable it manually.
Quite a bit of engineering time has been lost finding performance
problems and it turns out switching TCP_NODELAY on solves them
magically.
Netty has made the switch to TCP_NODELAY on by default, SwiftNIO should
follow. This patch is the equivalent of apple/swift-nio#1020.
Modifications:
Enable TCP_NODELAY by default.
Result:
If the user forgot to enable TCP_NODELAY, their software should now be
faster.
Motivation:
The expectation is that server channels use Channel as their data type,
but the initial data type in NIOTSListenerChannel was actually
NWConnection. This is unnecessary and it makes it hard to interop
between NIOTS and NIO.
Modifications:
- Initialize the NIOTSConnectionChannel in the NIOTSListenerChannel
instead of in AcceptHandler.
- Added some missing @available annotations in the tests.
Result:
More consistency
Motivation:
While we fixed a bug in SwiftNIO about setting multiple options of the same type in
apple/swift-nio#597, we never brought a fix for that issue forward. We did aim to resolve
this in SwiftNIO 2.0 by providing ChannelOptions.Storage, but unfortunately we forgot to
make the initializer for that type public (see apple/swift-nio#988). While SwiftNIO core
has to get its ducks in a row, users of this library should still be able to set more than
one socket option, in my humble opinion.
Modifications:
- Ported over ChannelOptions.Storage until apple/swift-nio#988 is fixed.
- Transitioned our code to use it.
- Tested it works.
Result:
Users can set multiple channel options.
Motivation:
NIOTS will not work on Linux but we can at least make it not fail
compilation when compiled on Linux. That way consumers of the API can
depend on NIOTS but make sure they only use NIOTS when wrapped in a
`#if canImport(Network)` block.
Modification:
Guard everything by `#if canImport(Network)`
Result:
This package will now build on Linux (without providing any useful
code).
Motivation:
Previously we would use the combination of DispatchQueue.asyncAfter and
a DispatchWorkItem for the connect timeout. If the connection succeeded
we would just cancel the DispatchWorkItem. Unfortunately that will still
keep everything that's captured in the DispatchWorkItem alive until the
deadline has come (because DispatchWorkItem is just a dumb wrapper over
a closure).
Modifications:
use a DispatchSource of type timer source instead.
Result:
- we won't keep the ELG/EL/Channel/... alive until at least the connect
timeout expires.
- fixes#28
Motivation:
Once every few thousand years, an event called syzygy (or "convergence")
occurs in our solar system. When these events occur, the fabric of spacetime
becomes thin, allowing reflections of a possible future to appear in our
reality.
This gives a few brave souls the opportunity to experience a future: a
possibility of the way the universe may one day be. But be warned: to
toy with causality is to risk unbearable pain and suffering. Only the
bravest of souls should look too closely at these shadows of the future.
Modifications:
- Chose a firm anchor point in the SwiftNIO timeline.
- Removed the braces that kept time travellers safe.
- Said a quiet prayer.
Result:
Opportunity.