Commit Graph

76 Commits

Author SHA1 Message Date
ser 6213ba7a06
Pooled control message storage. (#2422) 2023-05-31 06:06:23 -07:00
George Barnett d5519dba0b
Fix happy eyeballs races with custom resolver (#2436)
Motivation:

The HappyEyeballs connector synchronises state on an event loop but
calls out to a 'Resolver' to do DNS lookups. The resolver returns
results as a future which may be on a different loop than the connector.
The connector does not hop back to its own event loop before processing
the results.

For client bootstraps, if no resolver is specified then the default
resolver uses the same event loop as the connector so in many cases this
is not an issue. However, if a custom resolver is used this guarantee is
lost and data races are much more likely.

Modifications:

- Hop back to the connector's event loop after calling the resolver.
- Add a test.

Result:

Fewer data races.
2023-05-31 11:28:51 +01:00
Franz Busch d836d6bef5
Add `AsyncChannel` based `ServerBootstrap.bind()` methods (#2403)
* Add `AsyncChannel` based `ServerBootstrap.bind()` methods

# Motivation
In my previous PR, we added a new async bridge from a NIO `Channel` to Swift Concurrency primitives in the from of the `NIOAsyncChannel`. This type alone is already helpful in bridging `Channel`s to Concurrency; however, it is hard to use since it requires to wrap the `Channel` at the right time otherwise we will drop reads. Furthermore, in the case of protocol negotiation this becomes even trickier since we need to wait until it finishes and then wrap the `Channel`.

# Modification
This PR introduces a few things:
1. New methods on the `ServerBootstrap` which allow the creation of `NIOAsyncChannel` based channels. This can be used in all cases where no protocol negotiation is involved.
2. A new protocol and type called `NIOProtocolNegotiationHandler` and `NIOProtocolNegotiationResult` which is used to identify channel handlers that are doing protocol negotiation.
3. New methods on the `ServerBootstrap` that are aware of protocol negotiation.

# Result
We can now easily and safely create new `AsyncChannel`s from the `ServerBootstrap`

* Code review

* Fix typo

* Fix up tests

* Stop finishing the writer when an error is caught

* Code review

* Fix up writer tests

* Introduce shared protocol negotiation handler state machine

* Correctly handle multi threaded event loops

* Adapt test to assert the channel was closed correctly.

* Code review
2023-04-26 07:17:07 -07:00
Cory Benfield f7c4655298
Avoid double-closing on fcntl failures (#2409)
Motivation:

The fix provided in #2407 was subtly wrong. ignoreSIGPIPE, which throws
the error in question, closes the FD on error _except_ on EINVAL from
fcntl, where it instead does not. This inconsistent behaviour is the
source of the bug. Because this behaviour is inconsistent, the fix from
PR #2407 is also inconsistent and can in some cases double-close the
socket.

The actual issue is not as old as I expected: the code can be observed
by reviewing the change in #1598, which incorrectly inserted the error
transformation before the call to close.

Modifications:

- Revert the change from #2407.
- Move the close in ignoreSIGPIPE to before the error check, rather than
  after, so we unconditionally execute it.

Result:

More resilient fix.
2023-04-20 12:40:39 +01:00
Cory Benfield 003fbadf51
Don't have channels stop reading on errors they tolerate. (#2408)
Motivation:

When an error is hit during a read loop, a channel is able to tolerate
that error without closing. This is done for a number of reasons, but
the most important one is accepting sockets for already-closed
connections, which can trigger all kinds of errors on the read path.

Unfortunately, there was an edge-case in the code for handling this
case. If one or more reads in the loop had succeeded before the error
was caught, the inner code would be expecting a call to readIfNeeded,
but the outer code wouldn't make it. This would lead to autoRead
channels being wedged open.

Modifications:

This patch extends the Syscall Abstraction Layer to add support for
server sockets. It adds two tests: one for the basic accept flow, and
then one for the case discussed above.

This patch also refactors the code in BaseSocketChannel.readable0 to
more clearly show the path through the error case. There were a number
of early returns and partial conditionals that led to us checking the
same condition in a number of places. This refactor makes it clearer
that it is possible to exit this code in the happy path, with a
tolerated error, which should be considered the same as reading
_something_.

Result:

Harder to wedge a channel open.
2023-04-20 11:09:02 +01:00
Cory Benfield ad859ae82e
Close accepted FDs if we fail to create Socket (#2407)
Motivation:

In some circumstances we can accept a socket that is already closed. In
those cases, creating the underlying Socket type will fail, as
attempting to ignore SIGPIPE will fail. On Apple platforms, this causes
us to leak the accepted socket, and can lead to file descriptor
exhaustion.

Modifications:

- Close the accepted socket if we fail to create a Socket class

Result:

No FD leaks
2023-04-19 18:26:55 +01:00
David Nadoba 6720612111
Drop Swift 5.5 (#2406)
* Drop Swift 5.5

* Use `swift-atomics` 1.1.0 with `Sendable` adoption
2023-04-17 08:40:35 +01:00
ser 8193940b9a
Buffer pool for message headers and addresses. (#2378)
* Pool buffers for messages and addresses.

* Revert changes related to controlMessageStorage

* Cosmetic fix.

---------

Co-authored-by: Cory Benfield <lukasa@apple.com>
2023-03-10 16:06:02 +00:00
George Barnett d1fa3e29bf
Add support for UDP_GRO (#2385)
Motivation:

Support was added for UDP_SEGMENT in #2372 which allows for large UDP
datagrams to be written to a socket by letting the kernel or NIC segment
the data across multiple datagrams. This reduces traversals across the
network stack which can lead to performance improvements. UDP_GRO is the
receive-side counterpart allowing the kernel/NIC to aggregate datagrams
and reduce network stack traversals.

Modifications:

- Add a function in CNIOLinux to check whether UDP_GRO is supported
- Add the relevant socket and channel options
- Add tests

Result:

- UDP_GRO can be enabled where supported and applications may receive
  large buffers.
2023-03-06 07:12:09 -08:00
Rick Newton-Rogers 5f5fa9a2b2
mark syncShutdownGracefully noasync (#2381)
mark syncShutdownGracefully noasync

Motivation:

The code as-is blocks the calling thread.

Modifications:

* mark `EventLoopGroup.syncShutdownGracefully()` and `NIOThreadPool.syncShutdownGracefully()` noasync on Swift > 5.7
* offer NIOThreadPool.shutdownGracefully()
* add renamed to syncShutdownGracefully()
2023-03-02 06:20:23 -08:00
ser 652e01c003
Fix memory binding. (#2376)
* Fix memory binding.

* Cosmetic fix.
2023-03-01 03:54:42 -08:00
Andrew Trick e63326aa50
Fix an upcoming compiler warning on implicit raw pointer casts. (#2377)
setOption forms a raw pointer to a generic argument. The compiler will
warn on this as of:

[proposal] Constrain implicit raw pointer conversion... #1963
https://github.com/apple/swift-evolution/pull/1963

/Sources/NIOPosix/BaseSocket.swift:286:31: warning: forming
'UnsafeRawPointer' to a variable of type 'T'; this is likely incorrect
because 'T' may contain an object reference.

                option_value: &val,
                              ^

Ideally, this would be fixed by adding a BitwiseCopyable constraint to
the 'value' parameter of 'BaseSocker.setOption'. That would not only
eliminate the warning, but would make the API safer. But
BitwiseCopyable isn't quite ready for public use. In the meantime,
this is a reasonable workaround.

Co-authored-by: Cory Benfield <lukasa@apple.com>
2023-02-28 00:23:36 -08:00
George Barnett 19b878f461
Add support for UDP_SEGMENT (#2372)
Motivation:

On Linux, the UDP_SEGMENT socket option allows for large buffers to be
written to the kernel and segmented by the kernel (or in some cases the
NIC) into smaller datagrams. This can substantially decrease the number
of syscalls.

This can be set on a per message basis on a per socket basis. This
change adds per socket configuration.

Modifications:

- Add a CNIOLinux function to check whether UDP_SEGMENT is supported on
  that particular Linux.
- Add a helper to `System` to check whether UDP_SEGMENT is supported on
  the current platform.
- On Linux only:
  - add the udp socket option level
  - add the udp_segment socket option
- Add the `DatagramSegmentSize` channel option.
- Get/Set the option in `DatagramChannel`

Results:

UDP GSO is supported on Linux.

Co-authored-by: Cory Benfield <lukasa@apple.com>
2023-02-27 13:18:58 +00:00
George Barnett 4dfae01cc6
Add a pooled recv buffer allocator (#2362)
Motivation:

Channels can read `ChannelOptions.maxMessagesPerRead` times from a
socket in each read cycle. They typically re-use the same buffer for
each read and rely on it CoWing if necessary. If we read more than once
in a cycle then we may CoW the buffer. Instead of reusing one buffer we
can reuse a pool of buffers limited by `maxMessagesPerRead` and cycle
through each, reducing the chance of CoWing the buffers.

Modifications:

- Extend `RecvByteBufferAllocator` to provide the size of the next
  buffer with a default implementation returning `nil`.
- Add an recv buffer pool which lazily grows up to a fixed size and
  attempts to reuse buffers where possible if doing so avoids CoWing.

Results:

Fewer allocations
2023-02-20 17:00:19 +00:00
Cory Benfield 9afaf801e5
Don't retain a task when all we want is a time (#2373)
Motivation:

To know when we next need to wake up, we keep track of what the next
deadline will be. This works great, but in order to keep track of this
UInt64 we save off an entire ScheduledTask. This object is quite wide (6
pointers wide), and two of those pointers require ARC traffic, so doing
this saving produces unnecessary overhead.

Worse, saving this task plays poorly with task cancellation. If the
saved task is cancelled, this has the effect of "retaining" that task
until the next event loop tick. This is unlikely to produce catastrophic
bugs in real programs, where the loop does tick, but it violates our
tests which rigorously assume that we will always drop a task when it is
cancelled. In specific manufactured cases it's possible to produce leaks
of non-trivial duration.

Modifications:

- Wrote a weirdly complex test.
- Moved the implementation of Task.readyIn to a method on NIODeadline
- Saved a NIODeadline instead of a ScheduledTask

Result:

Minor performance improvement in the core event loop processing, minor
correctness improvement.
2023-02-20 07:27:58 -08:00
Cory Benfield 39047aec7c
Make PooledBuffer safer. (#2363)
Motivation:

PooledBuffer is an inherently unsafe type, but its original incarnation
was less safe than it needed to be. In particular, we can rewrite it to
ensure that it is compatible with automatic reference counting.

Modifications:

- Rewrite PooledBuffer to use ManagedBuffer
- Clean up alignment math
- Use scoped accessors
- Add hooks for future non-scoped access

Result:

Safer, clearer code
2023-02-08 07:59:17 +00:00
ser 1e7ad9a0db
Pool buffers for ivecs and storage refs in the event loop. (#2358)
* Pool buffers for ivecs and storage refs in the event loop.

* Introduce PoolElement for poolable objects and add some bounds checks for the pooled buffers.

* Some polishes.

* Fix build failure with Swift 5.5/5.6

* User raw pointers instead of typed.
2023-02-07 13:48:26 +00:00
George Barnett 0d6137f250
Remove unused array (#2361)
Motivation:

The `PendingDatagramWritesManager` unconditionally creates an array and
reserves capacity... only to never use it.

Modifications:

Remove the unsued code.

Result:

Fewer allocations.
2023-02-03 09:25:14 +00:00
ser c8ec84ef3b
Prepare mmsghdr structure properly. (#2346)
Motivation:

According to the Linux man page the msg_len field supposed to be used to return a number of bytes sent for the particular message.
It does not make a sense to initialize it with a size of the message.

Modifications:

Change msg_leg field initialization, use 0 instead of message size.

Result:

Use sendmmsg() call properly.

Co-authored-by: Cory Benfield <lukasa@apple.com>
2023-01-12 11:22:56 +00:00
Ahmad Alhashemi 91e5b3b609
Allow writing and reading empty datagrams (#2341)
Motivation:

Empty UDP datagrams could be used to have a meaning.
Empty datagrams were being silently dropped on write.
Receiving an empty diagram causes an assertion failure (possible DDoS).

Modifications:

Remove early exit when writing empty datagrams and non-empty assertion when reading them.

Result:

We can now write and read empty datagrams.
2023-01-09 02:45:15 -08:00
thomas-gill-0xff b201ff561d
Remove useless instance variables in the SelectableEventLoop (#2338)
Motivation:

Less code we have - less bugs we have.
The fix remove few lines of code keeping the same functionality.

Modifications:

Just remove some useless instance variables.

Result:

Less code.
2022-12-21 03:41:44 -08:00
David Nadoba 810544ec41
Add `RawSocketBootstrap` (#2320) 2022-12-01 15:35:04 +01:00
Rick Newton-Rogers 00341c9277
cap read+pread POSIX read sizes at Int32.max (#2323)
Cap NonBlockingFileIO reads at Int32.max

Motivation:

We wish to avoid overly large reads resulting in EINVAL signals being
triggered resulting in errors. We workaround the issiue in the
NonBlockingFileIO level to keep the lower levels as simple as possible.

Modifications:

`NonBlockingFileIO` `read0` amends read `byteCount`s to be `Int32.max` if they are larger than that value.

Result:

Large `NonBlockingFileIO` reads no longer result in precondition
failures.
2022-11-28 13:19:12 +00:00
David Nadoba 0b4edd8329
Add `NIOBSDSocket.ProtocolSubtype` (#2317)
* RawSocket prototype

* Conform `ProtocolSubtype` to `Hashable`

* Add public `NIOIPProtocol` type

Make `ProtocolSubtype` internal

* Subset of IANA protocols with an RFC

* Add `CustomStringConvertible` to `NIOIPProtocol`

* Add `init(_ rawValue: Int)`

* Rename `NIOBSDSocket.ProtocolSubtype.ip` to `.default`

* Add `NIOBSDSocket.ProtocolSubtype.mptcp`

and remove `NIOBSDSocket.mptcpProtocolSubtype`
2022-11-22 06:01:52 -08:00
Cory Benfield 558e4f2fb8
MPTCP support on Linux (#2308)
Motivation

MPTCP provides multipath capability for TCP connections. This
allows TCP connections to consume multiple independent network
paths, providing devices with a number of capabilities to
improve throughput, latency, or reliability.

MPTCP is not totally transparent, and requires servers to support
the functionality as well as clients. To that end, we should expose
some MPTCP capability.

Importantly, MPTCP uses a number of new socket flags and options.
To enable us to support this when it is available but gracefully fail
when it is not, we've hardcoded a number of Linux kernel constants
instead of relying on libc to expose them. This is safe to do on Linux
because its syscall layer is ABI stable.

Modifications

- Add ClientBootstrap and ServerBootstrap flags for MPTCP
- Plumb MPTCP through the stack
- Add new socket options for MPTCP

Result

MPTCP is supported on Linux
2022-11-09 11:02:45 +00:00
buttaface 6c31c9a46c
Add correct C directory function declarations for Android (#2302)
Motivation

Get the Android build working again

Modifications

- Modify close/open/readdir arguments, as they can be null
- Remove mkpath_np, as it's not there on Android

Result

Android builds again and the same tests pass
2022-10-25 18:12:42 +01:00
Artem Redkin d0ebe8da5d
adds create directory method (#2296)
Motivation:
Creating directories is a common task.

Modifications:
 - Adds mkdir syscall
 - Adds create directory implementation
 - Test
2022-10-24 15:02:10 +01:00
Artem Redkin 7bfceed5dc
Implements additional file operation in NonBlockingFileIO (#2244)
Motivation:
Basic set of function that NonBlockingFileIO provides is enough to read and write files, but as we get more and more into fully asynchronous world we need other non-blocking file-related function.

Modifications:
 - Adds support for getting file information using lstat
 - Adds ability to create a symlink, delete symlink and read it's destination
 - Adds ability to list directories
 - Adds ability to rename and remove files
2022-10-24 12:58:04 +01:00
David Nadoba 16b5b2b793
Replace `NIOSendable` with `Sendable` (#2291) 2022-10-13 15:56:27 +01:00
David Nadoba c7b4989b02
Remove `#if compiler(>=5.5)` (#2292)
### Motivation
We only support Swift 5.5.2+.

### Modification
Remove all `#if swift(>=5.5)` conditional compilation blocks.

### Result
less branching
2022-10-13 07:17:46 -07:00
Johannes Weiss 4ed8e1e228
rename class Lock to struct NIOLock (#2266) 2022-09-21 07:36:42 -07:00
David Nadoba ece5057615
Fix strict concurrency checking diagnostics in `MTELG` (#2229) 2022-07-28 11:57:02 +01:00
David Nadoba 33fc191001
Adopt `Sendable` for `MultiThreadedEventLoopGroup` (#2211)
* Adopt `Sendable` for `MultiThreadedEventLoopGroup`

* remove `@Sendable` from `withCurrentThreadAsEventLoop(_:)`

* Remove trailing whitespace

Co-authored-by: Cory Benfield <lukasa@apple.com>
2022-07-01 06:05:54 -07:00
David Nadoba 6c54e11eaa
Adopt `Sendable` in `NonBlockingFileIO` (#2212)
Co-authored-by: Cory Benfield <lukasa@apple.com>
2022-07-01 04:06:41 -07:00
David Nadoba d6f5e38af2
Adopt `Sendable` for Bootstraps (#2209)
* Adopt `Sendable` for Bootstraps

* fix swift nightly

Co-authored-by: Cory Benfield <lukasa@apple.com>
2022-07-01 03:45:07 -07:00
YR Chen a501353ef6
Deprecate `NIOAtomics` in favor of `Atomics` (#2204)
Co-authored-by: Cory Benfield <lukasa@apple.com>
2022-07-01 02:31:14 -07:00
David Nadoba adda7374af
Adopt `Sendable` for `NIOThreadPool` (#2210)
Co-authored-by: Cory Benfield <lukasa@apple.com>
2022-06-30 08:38:09 -07:00
David Nadoba 427d358d03
Adopt `Sendable` for types in `NIOPosix` (#2208) 2022-06-30 16:21:50 +01:00
David Nadoba e650ac1279
Adopt `noasync` for `ThreadSpecificVariable` (#2206) 2022-06-30 11:11:42 +02:00
Saleem Abdulrasool f7c3c45df4
NIOPosix: disable `timespec` extension on Windows (#2194)
This extension does not port cleanly to Windows as the time structures
on Windows are different.  This happens to be unused, so simply remove
the extension on Windows.
2022-06-15 10:37:30 +01:00
Si Beaumont 69bb75df32
Throw fatalError when scheduling on shutdown EL if SWIFTNIO_STRICT is set (#2190)
* Throw fatalError when scheduling on shutdown EL if SWIFTNIO_STRICT is set

Signed-off-by: Si Beaumont <beaumont@apple.com>

* Add CrashTest for SWIFTNIO_STRICT crash

Signed-off-by: Si Beaumont <beaumont@apple.com>

* fixup: Extract env var parsing to static let

Signed-off-by: Si Beaumont <beaumont@apple.com>

Co-authored-by: Cory Benfield <lukasa@apple.com>
2022-06-14 05:43:48 -07:00
Saleem Abdulrasool b393d39603
NIOPosix: add missing import for Windows (#2188)
Add an import of `NIOCore` on Windows which mirrors the other platforms.
This greatly reduces the noise in the error list.

Co-authored-by: Cory Benfield <lukasa@apple.com>
2022-06-14 04:37:27 -07:00
Saleem Abdulrasool 59cd8ff038
NIOPosix: import additional interfaces from WinSDK (#2189)
Import additional interfaces from WinSDK to enable additional paths to
build for Windows.
2022-06-14 10:56:44 +01:00
Saleem Abdulrasool 3c3c2b8f41
NIOPosix: add missing `CNIOWindows` import (#2184)
Add a missing import to match the other platforms.

Co-authored-by: Cory Benfield <lukasa@apple.com>
2022-06-13 05:53:07 -07:00
Saleem Abdulrasool e0df87c5c1
NIOPosix: adjust precondition for Windows (#2183)
The member names are not identical across platforms.  Add a case to
handle the name difference on Windows.

Co-authored-by: Cory Benfield <lukasa@apple.com>
2022-06-10 09:14:27 -07:00
Saleem Abdulrasool 01b13a5675
NIOPosix: reorganise packet info constants (#2182)
Co-locate the packet info constants and add Windows values.
2022-06-10 16:55:51 +01:00
Saleem Abdulrasool 03fa431216
NIOPosix: port file validation to Windows (#2179)
Use Win32 APIs to properly validate if a file is a pipe on Windows.
This enables providing the same semantics without leaking additional
Windows specifics.

Co-authored-by: Cory Benfield <lukasa@apple.com>
2022-06-09 23:27:14 -07:00
Saleem Abdulrasool 57d41b502c
NIOPosix: reorganise ECN constants, define for Windows (#2181)
Reorganise the ECN constants to colocate the definitions for the
different platforms.  Define the constants for Windows as the platform
does not provide them in the system headers.
2022-06-10 07:12:26 +01:00
Saleem Abdulrasool 055043e151
NIOPosix: use internal enumeration for GAI resolver (#2177)
Replace the use of raw constants with the internal enumeration.  This
ensures that the constant names are uniform and don't leak structural
information from the underlying information.
2022-06-09 08:21:24 +01:00
Saleem Abdulrasool 2560725d71
NIOPosix: use typealias instead of C name (#2180)
Switch to the typealias rather than the raw name to support Windows and
make the code homogeneous with the rest of the codebase.
2022-06-08 10:07:32 -07:00