Commit Graph
1234 Commits
Author SHA1 Message Date
Rick Newton-Rogers 661bfc5aea ByteBuffer custom allocator support
Motivation

* Other libraries often have byte buffer storage with similar concepts as
NIO's `ByteBuffer`, linear storage with reader and writer indices - it would
be nice to have efficient conversion to and from these objects.
* Efficienct conversion would likely mean taking ownership of the byte
storage allocated by the other object and exposing `ByteBuffer`s
internals so that they may be owned by another object, there is no API
for this currently.

Modifications

* Added new methods behind `CustomByteBufferAllocator` SPI.
* Added public `ByteBuffer` initializer for adopting externally-allocated memory
* Made `ByteBufferAllocator` initializer public with custom `malloc`/`realloc`/`free`/`memcpy` hooks
* Updated `realloc` signature to pass old capacity alongside new capacity to allow implementations to
copy over bytes
* Added `withVeryUnsafeMutableBytesWithStorageManagement` for mutable storage access
* Updated all existing tests using internal allocator API to use the new API
* Added tests for custom allocator functionality

Result

* Custom allocators can manage `ByteBuffer` memory with full size information
* External systems can transfer memory ownership to `ByteBuffer`
* System allocator maintains zero overhead due to inlining of the wrapper
* API (SPI) is extensible for future allocation system integrations
2026-02-27 09:39:33 +00:00
Rick Newton-Rogers abe12cf13b Apple platforms CI issues (#3519)
Apple platform simulator CI failures

### Motivation

* Several tests failed when testing against simulators for Apple
platforms (iOS, tvOS, watchOS, visionOS)

### Modifications

* Added `@available(macOS 13, iOS 16, tvOS 16, watchOS 9, *)` to each
`@Test` method in `NIOThreadPoolTest`, `EventLoopFutureTest`, and
`NIOTransportAccessibleChannelCoreTests` to match the availability of
the APIs they use (`timeLimit` and `withUnsafeTransportIfAvailable`).
* Removed `.timeLimit(.minutes(1))` from the `@Suite` declarations on
`NIOThreadPoolTest` and `EventLoopFutureTest` - the `@Suite` macro
cannot be used with `@available`, so `timeLimit` cannot be used.
* Skip `testHomeDirectoryFromPasswd` on simulator targets via
`#if targetEnvironment(simulator)` / `XCTSkip`, since simulators retu>
success but nil information when invoking `getpwuid_r`.

### Result

* Apple simulator platform builds and test runs no longer fail due to
these issues. Some infrastructure issues remain to be resolved
separately.
2026-02-26 13:03:18 +00:00
Si Beaumont e932d3c4d8 Workaround test crashing when compiled in release mode on Swift 6.2 (#3511)
### Motivation:

Our post-merge, pre-release pipelines run tests for our supported Swift
versions in both debug and release mode. The recent PR to add
`withUnsafeTransportIfAvailable` added some tests for various valid and
invalid usages of the API. One of the invalid usages was causing the
tests to crash, when compiled in release mode, in the Swift runtime:

```
% docker run --rm -it -v $PWD:/pwd -w /pwd swift:6.2 swift test --filter testUnderlyingSocketAccessForSocketBasedChannel
[1/1] Planning build
Building for debugging...
[1/1] Write swift-version-24593BA9C3E375BF.txt
Build complete! (2.38s)
Test Suite 'Selected tests' started at 2026-02-18 13:28:18.905
Test Suite 'Selected tests' passed at 2026-02-18 13:28:18.905
         Executed 0 tests, with 0 failures (0 unexpected) in 0.0 (0.0) seconds
◇ Test run started.
↳ Testing Library Version: 6.2.3 (48a471ab313e858)
↳ Target Platform: aarch64-unknown-linux-gnu
◇ Suite NIOTransportAccessibleChannelCoreTests started.
◇ Test testUnderlyingSocketAccessForSocketBasedChannel() started.
✔ Test testUnderlyingSocketAccessForSocketBasedChannel() passed after 0.005 seconds.
✔ Suite NIOTransportAccessibleChannelCoreTests passed after 0.005 seconds.
✔ Test run with 1 test in 1 suite passed after 0.005 seconds.
```

```
% docker run --rm -it -v $PWD:/pwd -w /pwd swift:6.2 swift test -c release --filter testUnderlyingSocketAccessForSocketBasedChannel
[1/1] Planning build
Building for production...
[1/1] Write swift-version-24593BA9C3E375BF.txt
Build complete! (2.12s)
Test Suite 'Selected tests' started at 2026-02-18 13:27:12.102
Test Suite 'Selected tests' passed at 2026-02-18 13:27:12.103
         Executed 0 tests, with 0 failures (0 unexpected) in 0.0 (0.0) seconds
◇ Test run started.
↳ Testing Library Version: 6.2.3 (48a471ab313e858)
↳ Target Platform: aarch64-unknown-linux-gnu
◇ Suite NIOTransportAccessibleChannelCoreTests started.
◇ Test testUnderlyingSocketAccessForSocketBasedChannel() started.

*** Signal 11: Backtracing from 0xffff8854b1ec... done ***

*** Program crashed: Bad pointer dereference at 0x0000000000000000 ***

Platform: arm64 Linux (Ubuntu 24.04.4 LTS)

Thread 0 "NIO-ELT-1-#1" crashed:

  0                0x0000ffff8854b1ec tryCast(swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*&, swift::TargetMetadata<swift::InProcess> const*&, bool, bool, bool) + 52 in libswiftCore.so
  1 [ra]           0x0000ffff8854b148 swift_dynamicCast + 79 in libswiftCore.so
  2 [ra] [system]  0x0000aaaab8668588 specialized ChannelPipeline.SynchronousOperations.withUnsafeTransportIfAvailable<A, B>(of:_:) + 135 in swift-nioPackageTests.xctest at //<compiler-generated>
  3 [ra]           0x0000aaaab8668148 closure #1 in NIOTransportAccessibleChannelCoreTests.testUnderlyingSocketAccessForSocketBasedChannel() + 3103 in swift-nioPackageTests.xctest at /tmp/swift-generated-sources/@__swiftmacro_13NIOPosixTests0049NIOTransportAccessibleChannelCoreTestsswift_IhHJqfMX55_16_33_309B77F97E02F918EDFF07092681CD49Ll6expectfMf8_.swift:1:40
  4 [ra] [thunk]   0x0000aaaab866be1c partial apply for closure #1 in NIOTransportAccessibleChannelCoreTests.testUnderlyingSocketAccessForSocketBasedChannel() + 15 in swift-nioPackageTests.xctest at //<compiler-generated>
  5 [ra]           0x0000aaaab7f410ec closure #1 in EventLoop.submit<A>(_:) + 95 in swift-nioPackageTests.xctest at /pwd/Sources/NIOCore/EventLoop.swift:1030:69
  6 [ra] [inlined] 0x0000aaaab841d468 closure #1 in SelectableEventLoop.run(_:) in swift-nioPackageTests.xctest at /pwd/Sources/NIOPosix/SelectableEventLoop.swift:618:17
  7 [ra] [inlined] 0x0000aaaab841d468 specialized withAutoReleasePool<A>(_:) in swift-nioPackageTests.xctest at /pwd/Sources/NIOPosix/SelectableEventLoop.swift:49:16
  8 [ra] [inlined] 0x0000aaaab841d468 SelectableEventLoop.run(_:) in swift-nioPackageTests.xctest at /pwd/Sources/NIOPosix/SelectableEventLoop.swift:615:9
  9 [ra]           0x0000aaaab841d468 SelectableEventLoop.runOneLoopTick(selfIdentifier:) + 535 in swift-nioPackageTests.xctest at /pwd/Sources/NIOPosix/SelectableEventLoop.swift:809:22
 10 [ra]           0x0000aaaab8423e5c SelectableEventLoop.run() + 331 in swift-nioPackageTests.xctest at /pwd/Sources/NIOPosix/SelectableEventLoop.swift:923:38
 11 [ra] [inlined] 0x0000aaaab83de614 static MultiThreadedEventLoopGroup.runTheLoop(thread:uniqueID:parentGroup:canEventLoopBeShutdownIndividually:selectorFactory:initializer:metricsDelegate:_:) in swift-nioPackageTests.xctest at /pwd/Sources/NIOPosix/MultiThreadedEventLoopGroup.swift:117:22
 12 [ra]           0x0000aaaab83de614 closure #1 in static MultiThreadedEventLoopGroup.setupThreadAndEventLoop(name:uniqueID:parentGroup:selectorFactory:initializer:metricsDelegate:) + 1255 in swift-nioPackageTests.xctest at /pwd/Sources/NIOPosix/MultiThreadedEventLoopGroup.swift:139:41
 13 [ra] [thunk]   0x0000aaaab83e1eec partial apply for closure #1 in static MultiThreadedEventLoopGroup.setupThreadAndEventLoop(name:uniqueID:parentGroup:selectorFactory:initializer:metricsDelegate:) + 39 in swift-nioPackageTests.xctest at //<compiler-generated>
 14 [ra] [thunk]   0x0000aaaab843f534 thunk for @escaping @callee_guaranteed (@guaranteed NIOThread) -> () + 23 in swift-nioPackageTests.xctest at //<compiler-generated>
 15 [ra]           0x0000aaaab84409dc closure #1 in closure #1 in static ThreadOpsPosix.run(handle:args:) + 319 in swift-nioPackageTests.xctest at /pwd/Sources/NIOPosix/ThreadPosix.swift:186:21
 16 [ra]           0x0000ffff86af595c <unknown> in libc.so.6
...


Registers:

 x0 0x0000ffff62fddfe0  48 60 00 58 ff ff 00 00 e0 e0 fd 62 ff ff 00 00  H`·Xÿÿ··ààýbÿÿ··
 x1 0x0000000000000000  0
 x2 0x0000ffff62fddff0  40 b4 01 5c ff ff 00 00 20 83 d1 b8 aa aa 00 00  @´·\ÿÿ·· ·Ñ¸ªª··
 x3 0x0000ffff58002038  03 03 00 00 00 00 00 00 01 00 00 00 01 00 00 00  ················
 x4 0x0000ffff62fddfa8  00 00 00 00 00 00 00 00 00 e0 fd 62 ff ff 00 00  ·········àýbÿÿ··
 x5 0x0000ffff62fddfa0  38 20 00 58 ff ff 00 00 00 00 00 00 00 00 00 00  8 ·Xÿÿ··········
 x6 0x0000000000000001  1
 x7 0x0000000000000000  0
 x8 0x0000000000000000  0
 x9 0x0000ffff886cf4e8  98 73 54 88 ff ff 00 00 08 be 5b 88 ff ff 00 00  ·sT·ÿÿ···¾[·ÿÿ··
x10 0x000000000000ffff  65535
x11 0x0000000000000000  0
x12 0x0000000000000000  0
x13 0x0000000000000001  1
x14 0x0000aaaab8e3ff2c  05 00 00 00 d4 2e a7 ff 00 00 03 00 51 00 00 00  ····Ô.§ÿ····Q···
x15 0x0000000000000009  9
x16 0x0000aaaab8d70520  f8 b0 54 88 ff ff 00 00 b4 45 55 88 ff ff 00 00  ø°T·ÿÿ··´EU·ÿÿ··
x17 0x0000ffff8854b0f8  ff 43 01 d1 fd 7b 02 a9 f6 57 03 a9 f4 4f 04 a9  ÿC·Ñý{·©öW·©ôO·©
x18 0x0000000000000000  0
x19 0x0000ffff58002038  03 03 00 00 00 00 00 00 01 00 00 00 01 00 00 00  ················
x20 0x0000ffff62fddff0  40 b4 01 5c ff ff 00 00 20 83 d1 b8 aa aa 00 00  @´·\ÿÿ·· ·Ñ¸ªª··
x21 0x0000000000000006  6
x22 0x0000000000000000  0
x23 0x0000aaaab86688b0  09 00 40 f9 09 01 00 f9 c0 03 5f d6 ff c3 00 d1  ··@ù···ùÀ·_Öÿ÷Ñ
x24 0x0000ffff5c01b440  f0 9d d9 b8 aa aa 00 00 03 00 00 00 08 00 00 00  ð·Ù¸ªª··········
x25 0x0000aaaab8d18320  0c 9c e2 b8 aa aa 00 00 ec 3c 3a b8 aa aa 00 00  ··â¸ªª··ì<:¸ªª··
x26 0x0000ffff62fde170  6e 69 6c 00 00 00 00 00 00 00 00 00 00 00 00 e3  nil············ã
x27 0x0000ffff62fde0e0  2d 00 00 00 00 00 00 d0 a0 3b de b8 aa aa 00 80  -······Ð ;Þ¸ªª··
x28 0x0000ffff886c6c28  02 02 00 00 00 00 00 00 30 b0 6f 88 ff ff 00 00  ········0°o·ÿÿ··
 fp 0x0000ffff62fddf30  b0 df fd 62 ff ff 00 00 48 b1 54 88 ff ff 00 00  °ßýbÿÿ··H±T·ÿÿ··
 lr 0x0000ffff8854b148  1f 08 00 71 c0 00 00 54 1f 04 00 71 c1 00 00 54  ···qÀ··T···qÁ··T
 sp 0x0000ffff62fddf00  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ················
 pc 0x0000ffff8854b1ec  68 01 40 f9 69 00 40 f9 1f fd 1f f1 f3 83 88 1a  h·@ùi·@ù·ý·ñó···


Images (20 omitted):

0x0000aaaab7d20000–0x0000aaaab8cd6d00 a17d4d145f2d2621f7b9d43c2b2d2a754b69002b swift-nioPackageTests.xctest /pwd/.build/aarch64-unknown-linux-gnu/release/swift-nioPackageTests.xctest
0x0000ffff86a70000–0x0000ffff86c09ec1 d5ef86dde36cbd3289566cf5098226035d76f2e1 libc.so.6                    /usr/lib/aarch64-linux-gnu/libc.so.6
0x0000ffff88160000–0x0000ffff8869e0c8 f62b9374639c58d0b60814a6fbec69d2b596cfc7 libswiftCore.so              /usr/lib/swift/linux/libswiftCore.so

Backtrace took 0.62s

error: Exited with unexpected signal code 11
```

The test is fine for both debug and release mode on Swift 6.0, 6.1, and
6.3-nightly.

### Modifications:

Since this is a valid construction and the crash is a Swift bug, and
since it only manifests on a specific Swift version, and since it's only
triggered when mis-using the API, we can just not perform this part of
the test on Swift 6.2. The API is fully functional when used correctly.

### Result:

Running NIO tests, compiled in release mode, no longer crashes on Swift
6.2.3.

### Local testings:

With this branch:

```
% docker run --rm -it -v $PWD:/pwd -w /pwd swift:6.2 swift test -c release --filter testUnderlyingSocketAccessForSocketBasedChannel
[1/1] Planning build
Building for production...
[8/8] Linking swift-nioPackageTests.xctest
Build complete! (38.46s)
Test Suite 'Selected tests' started at 2026-02-18 14:23:12.902
Test Suite 'Selected tests' passed at 2026-02-18 14:23:12.902
         Executed 0 tests, with 0 failures (0 unexpected) in 0.0 (0.0) seconds
◇ Test run started.
↳ Testing Library Version: 6.2.3 (48a471ab313e858)
↳ Target Platform: aarch64-unknown-linux-gnu
◇ Suite NIOTransportAccessibleChannelCoreTests started.
◇ Test testUnderlyingSocketAccessForSocketBasedChannel() started.
✔ Test testUnderlyingSocketAccessForSocketBasedChannel() passed after 0.002 seconds.
✔ Suite NIOTransportAccessibleChannelCoreTests passed after 0.003 seconds.
✔ Test run with 1 test in 1 suite passed after 0.003 seconds.
```
2026-02-18 15:11:55 +00:00
Stepan UlyaninandGeorge Barnett be8fdc13c0 Allow to copy files and symlinks while overwriting the destination (#3508)
Adds capability to NIOFS to copy regular files and symlink, allowing to
overwrite the destination.

### Motivation:

Per https://github.com/apple/swift-nio/issues/3403 and
https://github.com/apple/swift-nio/pull/3470 we want to add
`replaceExisting: bool` to `FileSystem.copyItem`.

### Modifications:

1. Adds `replaceExisting: bool` parameter to
`FileSystemProtocol.copyItem`.
2. Adds `replaceExisting: bool` parameter to `FileSystem.copyItem` and
implementation for regular files and symbolic links.
3. Adds tests.

---------

Co-authored-by: George Barnett <gbarnett@apple.com>
2026-02-18 08:57:33 +00:00
Si BeaumontandAgam Dua b0e024792a Add opt-in API for channels to expose their underlying transport (#3509)
## Motivation

NIO channels abstract over an underlying transport mechanisms (sockets,
pipes, etc.), which users typically need not interact with. However,
there are scenarios where users need direct access to the underlying
transport for low-level operations that work outside NIOs abstraction.
One example is performing out out-of-band operations on the underlying
file descriptor for a socket-based channel.

This PR adds a structured way to access the underlying transport of a
channel, for channels that choose to implement it.

## Modifications

- Add a new `public protocol
NIOTransportAccessibleChannelCore<Transport>` which provides a scoped
`withUnsafeTransport(_:)`, used for channel implementations to opt-in.
- Add conformance to
`NIOTransportAccessibleChannel<NIOBSDSocket.Handle>` for
`BaseSocketChannel`, to make this API available for all socket-based
channels, including channels returned from the socket-based bootstrap
public APIs.
- Add public API
`ChannelPipeline.SynchronousOperations.withUnsafeTransportIfAvailable(_:)`

Note that not all channels need to or should their transport, which is
why this was added as an additional protocol that refines `ChannelCore`,
vs. extending `Channel` or `ChannelCore` with a default implementation.

The protocol uses a primary associated type allowing channels to provide
typed access to the transport. E.g. this could be used in NIO Transport
Services to expose the underlying `NWConnection`, if desired.

The method itself is spelled with "unsafe", uses scoped access, and has
clear documentation that users must not violated any of NIOs assumptions
about the state of the underlying transport. It's very much not intended
for every day use. It being on `ChannelCore` should defer users of the
low-level API, since `Channel._channelCore` is marked as for NIO
internal use, and the public `withUnsafeTransportIfAvailable(_:)` will
take care of the runtime checks for channels that have opted into this
API.

## Result

- New opt-in API for channel implementations to expose their underlying
transport
- All socket-based channels from NIOPosix now expose the underlying
socket file descriptor
- New API
`ChannelPipeline.SynchronousOperations.withUnsafeTransportIfAvailable(_:)`
for users

---------

Co-authored-by: Agam Dua <agam_dua@apple.com>
2026-02-17 16:12:58 +00:00
Raphael d948192838 Don't send (in)active when channel closes directly (#3497)
### Motivation

Issue #2773 reports a problem where channels can receive
`channelInactive` before `channelActive`. This breaks expectations and
should not happen. Instead of sending them in the wrong order, this PR
suppresses both of them in those cases.

### Modifications

* Add a test to reproduce the problematic behavior.
* Update the state machine to split the active state into two. This
decouples succeeding the promise from sending the signal. Transiting to
closing only sends `channelInactive` when originating from the state
that sent `channelActive`.

### Result

Address #2773.

Edit: Updated modifications to reflect latests commit.
2026-02-11 15:46:19 +00:00
Stepan Ulyanin db01d87942 Add symlinkat, renameatx_np, and unlinkat system call wrappers (#3505)
Adds three new system call wrappers for the `symlinkat`, `renameatx_np`,
and `unlinkat` system calls.

### Motivation:

Related to https://github.com/apple/swift-nio/issues/3403 and
https://github.com/apple/swift-nio/pull/3470. This PR adds syscall
wrappers needed to atomically overwrite existing files or symlinks at
the destination during copy operations. On Linux, atomic overwrites
require a "copy to temp file, then rename" strategy. We use the `*at`
family of syscalls (which operate relative to directory file
descriptors) to avoid TOCTOU race conditions.

### Modifications:

1. Adds three system call wrappers for the `symlinkat`, `renameatx_np`,
and `unlinkat` system calls.
2. Adds related tests
3. Updates the `FileSystemError` for `symlink` and `unlink` to take in
the system call name to allow for the `*at` names to be passed.
2026-02-09 08:38:25 +00:00
scottmarchant 90ed88baab test: Port NIOThreadPoolTest to Swift Testing. (#3490)
Ports NIOThreadPoolTest in NIOPosix from XCTest to Swift Testing.

### Motivation:

Tests should use the latest Swift Testing framework when possible.

### Modifications:

- Ported `NIOThreadPoolTest` from XCTest to Swift Testing
- Updated test implementation from Dispatch to Swift Concurrency as
needed to support test functionality

### Result:

All tests continue to pass, NIOThreadPoolTest now has more modern Swift
Testing syntax.
2026-02-06 15:19:18 +00:00
scottmarchant e0476c6072 test: Port EventLoopFutureTest to Swift Testing. (#3491)
Port `EventLoopFutureTest` to Swift Testing. Includes some adjustments
to ensure tests are ran from the event loop, among other minor changes

### Motivation:

Tests should use the latest Swift Testing framework when possible.

### Modifications:

- Ported `EventLoopFutureTest ` from XCTest to Swift Testing
- Consolidated instantiations of `EmbeddedEventLoop()` into a private
function called `makeEventLoop` to allow for easier injection of a
different loop from a single location.
- Migrated some `.wait` usages to `.get` to allow tests to run async.

### Result:

All tests continue to pass, EventLoopFutureTest now has more modern
Swift Testing syntax.
2026-02-05 08:24:43 +00:00
Fabian Fett 6a6f7d7c33 Centralize UnsafeTransfer in NIOCore (#3492)
We have a number of copies of `UnsafeTransfer` and two copies of
`UnsafeMutableTransferBox` in our code base. Before introducing more of
those, lets centralize to just one using a `package` access modifier.
2026-02-03 10:27:30 +00:00
Si Beaumont 37ffc4b8d5 Add API to enable throwing in EmbeddedChannel.getOption and .setOption if channel is closed (#3495)
### Motivation:

Channels based on `BaseSocketChannel` throw in both `getOption` and
`setOption` if the channel has been closed, since the `setsockopt` will
fail. However, the current behavior of `EmbeddedChannel` is options
remain writable and readable on closed channels.

There are situations where we'd like to be able to model the runtime
behaviour of the real channel in tests, e.g. to test this fix:
https://github.com/apple/swift-nio-extras/pull/304.

### Modifications:

- Add API to enable throwing in `EmbeddedChannel.getOption` and
`.setOption` if channel is closed.
- Add a test for this new behavior.

### Result:

- New API to enable throwing in `EmbeddedChannel.getOption` and
`.setOption` if channel is closed.
- No observable change for existing users of `EmbeddedChannel`.
2026-01-27 12:06:55 +00:00
scottmarchant 6ce9173261 fix: Ensure pthread_mutexattr_t is properly cleaned up with pthread_mutexattr_destroy in Lock (#3480)
### Motivation:

In reviewing a copy of this file in swift-log, @czechboy0 noticed that
the call to `pthread_mutexattr_destroy` is missing. Since
pthread_mutexattr_t is like allocated on the stack rather than heap on
most platforms, this is likely not a memory leak. But for correctness
the missing destroy call should be added.

This change is the start of a resolution
[requested](https://github.com/apple/swift-log/pull/398#discussion_r2689459360)
in a corresponding Lock rollout in swift-log

### Modifications:

- Added missing call to `pthread_mutexattr_destroy`
- Duplicated test for `NIOLock` to also test `Lock`, as a sanity test.

### Result:

The new sanity test passes. If there are other ways this change can be
realistically verified as safe and proper, please feel free to provide
feedback in the PR.
2026-01-19 08:13:02 +00:00
Adam FowlerandCory Benfield 61053a00bb NIOTypedHTTPClientUpgradeHandler will write Upgrade request on handlerAdded if active (#3473)
`NIOTypedHTTPClientUpgradeHandler.handlerAdded` will write upgrade
request if the channel is already active

### Motivation:

This has been added to make it easier to implement a websocket client
that supports proxies. If the upgrade handler is added after the proxy
connect has been processed previously nothing would happen.

### Modifications:

- Added new function
`NIOTypedHTTPClientUpgradeHandler.writeUpgradeRequest()` function. Call
this from `channelActive` and also from `handlerAdded` if the channel is
already active.
- Added test `testUpgradeHappensAfterHandlerAdded`

### Result:

NIOTypedHTTPClientUpgradeHandler now also works if it is added to a
channel after the channel is active

---------

Co-authored-by: Cory Benfield <lukasa@apple.com>
2026-01-14 11:40:00 +00:00
Karan LokchandaniandCory Benfield 608e511d7a Add homeDirectory accessor to FileSystem (#3471)
Add homeDirectory accessor to FileSystem

### Motivation:
Addresses #3381 by adding a `homeDirectory` property to FileSystem,
equivalent to `FileManager.default.homeDirectoryForCurrentUser`.

### Modifications:
- Added `homeDirectory` property to `FileSystemProtocol` and implemented
in `FileSystem`
- Implementation checks `HOME` environment variable first, falls back to
`USERPROFILE` on Windows, or uses `getpwuid_r(3)` on POSIX systems
- Added system call wrappers (`system_getuid`, `libc_getpwuid_r`) with
proper platform guards
- Added `FileSystemError.getpwuid_r()` error helper

### Result:
Users can now access the home directory via `FileSystem.homeDirectory`,
returning a `FilePath` asynchronously. Follows the same pattern as
`currentWorkingDirectory` and `temporaryDirectory`.

Co-authored-by: Cory Benfield <lukasa@apple.com>
2026-01-12 15:10:25 +00:00
aryan-25 5dc3b4ba4a Cancel pending in/outbound consumers in EmbeddedChannelCore upon channel close (#3464)
### Motivation:

Currently, pending consumer closures remain in the
`{in}{out}boundBufferConsumer` queues of `EmbeddedChannelCore` even
after the channel closes. It is also possible to enqueue consumers
*after* the channel closes. In these cases, the consumer closures will
never be invoked and this can lead to unfavourable behaviour, as
observed in `NIOAsyncTestingChannel`'s `waitFor{In}{Out}boundWrite`
methods (the only places these queues are currently used).

`NIOAsyncTestingChannel`'s `waitFor{In}{Out}boundWrite` methods complete
a continuation *inside* the consumer closure. In the cases described
above, the continuation never completes and therefore
`waitFor{In}{Out}boundWrite` never returns.

### Modifications:

- Updated the element type in `EmbeddedChannelCore`'s
`{in}{out}boundBufferConsumer` from `(NIOAny) -> Void` to
`(Result<NIOAny, Error>) -> Void`.
- This is so that the `.failure` case can be used to notify the consumer
closure that the channel has closed.
- Changed the visibility of the `{in}{out}boundBufferConsumer`
properties from `internal` to `private` in order to prevent the queues
from being accessed and being appended to without the call site
considering whether the channel has been closed.
- Added new `internal` methods named
`enqueue{In}{Out}boundBufferConsumer(_:)` which take the consumer
closure as an argument and only append to the corresponding queue if the
channel isn't closed.
- If the channel is closed, the consumer closure is invoked immediately
with `.failure(ChannelError.ioOnClosedChannel)`.
- Updated `EmbeddedChannelCore`'s `close0` method to return a
`.failure(ChannelError.ioOnClosedChannel)` result to each closure in
`{in}{out}boundBufferConsumer` and empty both buffers.
- Updated `NIOAsyncTestingChannel`'s `waitFor{In}{Out}boundWrite` to
throw an error in the continuation upon receiving a `.failure` result.
- Added associated test cases.

### Result:

`EmbeddedChannelCore`'s `{in}{out}boundBufferConsumer` queues can be
used more safely: all pending closures will be invoked upon channel
close. As a result, `NIOAsyncTestingChannel`'s
`waitFor{In}{Out}boundWrite` no longer indefinitely blocks when the
channel closes.
2026-01-06 17:52:06 +00:00
e3d5c560e0 Fix coreCount on Linux when using cgroup v2 with CFS throttling disabled (#3462)
Fix coreCount on Linux when using cgroup v2 with CFS throttling disabled

### Motivation:

When using `swift-nio` on Linux with cgroup v2 enabled, but with CFS
throttling disabled, it falls back to attempting to read the cpuset file
at the cgroup v1 path. This does not exist, which in turns falls back to
returning `_SC_NPROCESSORS_ONLN`, which will return the total number of
cores available (ignoring cgroup assignments).

This has unexpected effects, including the default behaviour of starting
the `MultiThreadedEventLoopGroup.singleton` with significantly more
event loops than cores available to the workload.

### Modifications:

- Adds `SystemCalls.statfs`, and associated constants, to determine the
cgroup version.
- Adds `Linux.cgroupVersion()` API to expose cgroup version.
- Adds `Linux.cgroupV2MountPoint` variable to determine the cgroup v2
mount point.
- Adds `Linux.cpuSetPathV1` & `Linux.cpuSetPathV2` (and
`Linux.cpuSetPath` convenience) variables to determine the correct cpu
set path.
- Alters `System.coreCount` to use the appropriate logic from above to
ensure that `cpuset.cpus` is parsed from the correct location.

### Result:

`Linux.coreCount` should correctly parse and return the core count on
Linux cgroup v2 enabled systems (when CFS throttling is disabled), while
maintaining correctness for other configurations.

---------

Co-authored-by: Johannes Weiss <johannesweiss@apple.com>
Co-authored-by: Cory Benfield <lukasa@apple.com>
2026-01-05 14:26:21 +00:00
Adam Fowler 888f4affd6 Add ByteBuffer.readableBytesUInt8Span (#3458)
Add  ByteBuffer.readableBytesUInt8Span

### Motivation:

Provide access to readableBytes as a Span<UInt8>

### Modifications:

Added computed property `ByteBuffer.readableBytesUInt8Span`. I also
attempted to add `ByteBuffer.mutableReadableBytesUInt8Span` but due to
an apparently faulty exclusivity issue I couldn't get this to work. See
https://github.com/swiftlang/swift/issues/81218.

### Result:

You can access the readable bytes of a ByteBuffer as a Span<UInt8>
2025-12-05 15:32:17 +00:00
George Barnett d2feeaa363 Handle cancellation between dropping and reaquiring lock (#3453)
Motivation:

This is a follow up to 5bf841dd to handle the yield task being cancelled
between dropping the lock and re-acquiring it a moment later in the
'withContinuation' block.

Modifications:

- Add an extra cancellation check when yielding with a continuation.

Result:

Fewer issues
2025-11-25 09:16:35 +00:00
Rick Newton-Rogers 56724a2b6d NIOAsyncTestingChannel local/remote addrs on EmbeddedChannelCore (#3442)
### Motivation:

`NIOAsyncTestingChannel` stored its `localAddress` and `remoteAddress`
in a locked storage on itself for thread safety, however in doing so
left us open to bugs because a handler grabbing the addresses of the
context had no visibility of the values.

### Modifications:

Reach into `EmbeddedChannelCore` for the addresses instead of storing
them on the `NIOAsyncTestinghannel`. I also considered a delegate
approach where the `EmbeddedChannelCore` could offload the
responsibility for storing the values back to the
`NIOAsyncTestingChannel` but it was complicated and of questionable
value.

### Result:

* The correct address values are seen no matter how they are obtained.
* We probably take a performance hit locking the values in this way but
this is testing code so probably not the end of the world.
2025-11-11 15:08:15 +00:00
Fabian Fett 45b463c5eb Quality of Life: Add NIOLoopBoundBox.withValue (#3385)
When having a state machine inside the `NIOLoopBoundBox` we currently
check the EL when reading and writing. This is unnecessary. Because of
this, this PR introduces a new `withValue` method, that allows users to read and
write the value inside the NIOLoopBoundBox while only paying the cost
for the EL check once.
2025-11-10 10:08:50 -05:00
Cory Benfield 5741df9cc4 Enable per-message GRO on Linux (#3439)
Motivation:

NIO has existing GRO support. This GRO support is applied at Channel
scope, which makes it somewhat less than ideal, as it forces the
datagram sizes to be accessed using socket options. In real applications
this is less desirable than being able to do this on a per-superbuffer
context.

Linux supports this already by using recvmsg/recvmmsg control data. We
just need to wire this up in NIO. We can re-use the existing metadata
fields on AddressedEnvelope.

Modifications:

- Add a new ChannelOption to extra metadata
- Reject setting this option on non-Linux devices.
- On Linux, use this to load the control data.
- Added new tests that validate the behaviour is correct.

Result:

Enable per-message GRO.
2025-11-07 13:24:30 -05:00
Cory Benfield a7da98c3ac Enable per-message GSO on Linux (#3436)
Motivation:

NIO has existing GSO support. This GSO support is applied at Channel
scope, which makes it somewhat less than ideal, as it forces the
datagram sizes to be known statically ahead of time. In real
applications this is less common than being able to do this on a
per-superbuffer
context.

Linux supports this already by using sendmsg/sendmmsg control data. We
just need to wire this up in NIO.

An extension to this is that we can also do per-message GRO in Linux.
I'll tackle this in a later patch to keep the diffs small.

Modifications:

- Adding a new field on AddressedEnvelope Metadata.
- Reject setting this field on non-Linux devices.
- On Linux, use this to set the control data.
- Added new tests that validate the behaviour is correct.

Result:

Enable per-message GSO.
2025-11-07 08:34:33 +00:00
Cory Benfield 88dc99031f Add some spans to ByteBuffer (#3371)
Motivation:

Users would like to be able to access the underlying memory of a
ByteBuffer, as evidenced by the plethora of `withUnsafe*` methods that
ByteBuffer has. As Swift 6.2 has introduced some initial APIs for safe
memory access to underlying storage, we should offer similar APIs on
ByteBuffer to enable users to get safer access to that storage.

For now, the obvious APIs to be able to supplement are:

- withUnsafeReadableBytes
- withUnsafeMutableReadableBytes
- writeWithUnsafeMutableWritableBytes

We can also offer some new APIs to allow initializing a buffer directly
from an OutputSpan.

Note that we can only do this because the Language Steering Group has
pinky promised that they will not break the "Lifetimes" experimental
feature: see

https://forums.swift.org/t/experimental-support-for-lifetime-dependencies-in-swift-6-2-and-beyond/78638
for more details. We are taking them at their word, and so we are
enabling that feature.

Modifications:

Many new methods and tests.

Result:

Safer access.
2025-11-06 11:54:06 -05:00
George Barnett d963335ba0 Fail on early errors in parallel copy (#3435)
Motivation:

'copyItem' can be used to copy files/directories from a source to a
destination address and fails if the destination already exists. The
parallel version of it can wedge if a directory is being copied and the
directory can't be created at the destination path (for example, if a
file already exists at the destination).

The parallel copy works by feeding tasks (e.g. "copy this item from here
to there") into an async sequence and processing each task in a separate
child task within a task group. When copying directories a new directory
is created at the destination path and then each file within the source
directory is emitted as a separate item to process. Another item is sent
on the async sequence to indicate when the source directory is finished
with which may result in finishing the async sequence.

However, if creating the destination directory fails then that event
isn't sent. This results in the calling code never terminating the async
sequence and causes 'copyItem' to wedge.

Modifications:

- Use non-idempotent directory creation (copy item should fail if the
destination already exists, this was a regression introduced in
7124f096).
- Check whether to continue when a dir can't be created but always emit
the end of dir event
- If terminating when the task group hasn't reached its width limit then
check child tasks for errors

Result:

Parallel copy doesn't wedge
2025-11-05 08:47:05 +00:00
Zamderax ec26755611 Tests: inline TestUtils.swift in NIOHTTP1Tests to avoid broken symlink on non-symlink filesystems (#3426)
On filesystems without symlink support for Windows, the symlinked test
helper at is materialized as a plain text file containing the relative
path, which breaks compilation with errors like:
```
expressions are not allowed at the top level
cannot find 'assertNoThrowWithValue' in scope
```
This change inlines the contents, restoring the intended shared test
utilities for the NIOHTTP1 test target. This helps Windows compile the
Test target
2025-10-29 13:27:40 +00:00
Mahdi Bahrami 0469372396 Implement AsyncSequence/splitLines() (#3411)
~~Implement `AsyncSequence/split()` functions similar to
`String/split()` functions in std-lib.~~
Implement `AsyncSequence/splitLines()` functions similar to
`String/split(whereSeparator: \.isNewline)` in std-lib.

### Motivation:

~~Provide an easy way for users to split the data incoming from an async
sequence, using their preferred separator.~~
Provide an easy way for users to split the data incoming from an async
sequence, on new lines.

### Modifications:

Add `internal SplitMessageDecoder: NIOSingleStepByteToMessageDecoder`.
Add `public NIOSplitLinesMessageDecoder:
NIOSingleStepByteToMessageDecoder`.
Add `public
AsyncSequence/splitLines(omittingEmptySubsequences:maximumBufferSize) ->
AsyncSeq<ByteBuffer>`.
Add `public
AsyncSequence/splitUTF8Lines(omittingEmptySubsequences:maximumBufferSize)
-> AsyncSeq<String>`.

### Result:

Users can easily split the data.
2025-10-21 16:13:43 +01:00
Mahdi Bahrami f2ad915d57 [perf] Manually implement lastIndex(where:) in ByteBufferView (#3413)
### Motivation:

`ByteBuffer.lastIndex(where:)` is of suboptimal performance.
The default Collection implementations don't go through any "magic
underscored" functions like `_customIndexOfEquatableElement`.

### Modifications:

Manually implement `lastIndex(where:)`.

### Result:

Basically free performance boost. 2x+ boost even for not big buffers of
a few hundred bytes.

This function is currently used in
`ByteBufferView.trim(limitingElements:)`.

I have no immediate use case for this function, but it's still an issue
worth addressing.
2025-10-21 14:02:55 +01:00
Hamza Hassanain 7124f0963a feat(NIOFileSystem): Add idempotent directory creation behavior (#3404) (#3410)
The createDirectory function will succeed without error if the target
directory already exists.

###  Motivation

This change addresses issue #3404. Currently,
`fileSystem.createDirectory` fails if the target directory already
exists, forcing users to write boilerplate try/catch blocks to handle
this common and expected case.

The goal is to make this function's behavior idempotent.

### Modifications

To achieve this, I've made the following changes:

**(Implementation)** A new private helper function,
`_handleCreateDirectoryFileExists`, was introduced. This function is
responsible for:

1. Performing a `stat` call on the path that failed.
2. Checking if the existing item is a directory (`S_IFDIR`).
3. Returning a success result if it's a directory, or re-throwing the
original `.fileExists` error if it's a file or another type of entity.

**(Logic)** The core `_createDirectory` function was updated to call
this new helper function whenever `Syscall.mkdir` fails with an `EEXIST`
(`.fileExists`) error. This check is applied in both internal loops to
correctly handle cases where either an intermediate directory or the
final target directory already exists.

### Result
With this change, users can now call the function
`fileSystem.createDirectory` and the operation will succeed even if the
directory is already present, leading to cleaner and more predictable
code.
2025-10-20 15:49:26 +01:00
Mahdi Bahrami 767ea9ee09 [perf] Manually implement firstIndex(where:) in ByteBufferView (#3412)
### Motivation:

`ByteBuffer.firsIndex` is of suboptimal performance.
The default Collection implementations don't go through any "magic
underscored" functions like `_customIndexOfEquatableElement`.

### Modifications:

Manually implement `firstIndex(where:)`.

### Result:

Basically free performance boost. 2x+ boost even for not big buffers of
a few hundred bytes.

There are some usage of this function in `BufferedReader`. Those will
become much faster.
Also this function is used in `ByteBufferView.trim(limitingElements:)`.

Also makes #3411 stuff faster. See:
https://github.com/apple/swift-nio/pull/3411#discussion_r2436260691
2025-10-17 07:15:44 +00:00
Mahdi Bahrami 86c5ead5dd Introduce NIODecodedAsyncSequence for easy decoding of async sequences (#3407)
Previous PR: #3405 

Add an API on top of `AsyncSequence<ByteBuffer>` which can dynamically
decode values.
~~Add an API on top of the new `AsyncSequence<ByteBuffer>` APIs which
splits the file based on its content.~~

### Motivation:

Provides a nice API to decode files, instead of users having to go
though manually handling `BufferedReader.read(while:)`.
I struggled with this, as documented in
https://swift-open-source.slack.com/archives/C9MMT6VGB/p1760115481607159

### Modifications:

Add `NIODecodedAsyncSequence` + functions on `AsyncSequence<ByteBuffer>`
to create such a sequence.
~~Add `NIOSplitMessageDecoder` + stdlib-like functions on
`AsyncSequence<ByteBuffer>` to create such a sequence.~~

### Result:

Users can decode an async sequence of `ByteBuffer`s easier.
~~Users can easily split files based on their content.~~

### Checklist

See this comment for a checklist of the remaining things to do:
https://github.com/apple/swift-nio/pull/3407#issuecomment-3403382404
2025-10-16 09:49:55 +00:00
Cory Benfield cdf721f4d6 Avoid zombie pipe channels when receiving writeEOF (#3408)
Motivation

In rare cases where the inbound side of a pipe channel is already closed
(either because it was never open or because it was closed during use),
we can get into trouble if the reader drops the read side of our write
pipe. In that context, the Linux kernel will deliver an EPOLLHUP, but
while we'll close the FD we'll let the channel hang out as a zombie.
This is, obviously, suboptimal.

Modifications

In writeEOF, we check whether the read side is already closed. If it is,
we trigger a close internally to shut the channel down. Added a test for
this as needed, and modified an existing test that would now trip over
this behaviour. Also added a new test for the reverse case to ensure we
don't end up with zombies there (we don't).

Results

No zombie channels.
2025-10-15 10:16:39 +01:00
Cory Benfield 97c3f28ad0 Fix flakiness in testWithConfiguredStreamSocket (#3399)
Motivation:

This test occasionally fails in our ongoing continuous CI solution.
Flaky tests are bad, and we should aim not to have them, so let's fix
it.

My diagnosis of the most likely race here (which leads to
`alreadyClosed`) being thrown _somewhere_ from this code is that the
client channel got closed unexpectedly. This would happen if an unusual
series of events occurs:

1. The client connection succeeds and the channel starts up
2. The server close then goes through and the server channel is closed
_before_ it actually accepts the connection.
3. This causes the client connection to be reset.
4. The client channel observes this and handles that close.
5. We then close the client from the outside.

Modifications:

Add a ConditionLock we can use to wait for a connection to be
established.
Make the use of this ConditionLock resilient to weird test behaviour by
always using timeouts for blocking operations.

Result:

Less flaky tests.
2025-10-06 14:53:44 +01:00
Fabian FettandCory Benfield a3ed8e10ab Drop Swift 5.10 (#3393)
This PR drops Swift 5.10 and enables Swift 6 language mode.

---------

Co-authored-by: Cory Benfield <lukasa@apple.com>
2025-10-06 10:58:33 +01:00
Cory Benfield 2143eb91f1 Tweak test availability to avoid segfaults (#3397)
Motivation

Availability guards on test functions don't work the way we'd want them
to: in particular, xctest still ends up calling these functions even on
platforms that are less available than the functions in question. We
need to move these to checks in in the function themselves.

Modifications

Replace @available with guard available

Result

No more segfaults in tests.
2025-10-04 09:30:21 +01:00
Mahdi BahramiandCory Benfield 2e22c89844 Add InlineArray helpers to ByteBuffer (#3252)
### Motivation:

Useful for parsing packets, for example `ipv4: InlineArray<4, UInt8>`
and `ipv6: InlineArray<16, UInt8>`.

### Modifications:

For now I've only added a `readInlineArray` function. I know some other
functions are missing, such as `writeInlineArray`.
I wanted to first open up a discussion and see if these changes are
acceptable. I can add those functions too if required, in this PR or
other PRs.

### Result:

Users can read `ByteBuffer` into stack-allocated memory, which can be
more performant than the other alternatives like `Array`, or more
convenient than reading as a tuple like `(UInt8, UInt8, UInt8, UInt8)`.

### Caveats:

Swift 6.2 is required so I've used `#if compiler(>=6.2)`.
Furthermore, `InlineArray` is marked as available on `macOS(9999)` since
the Swift team have yet to update that mark, although `InlineArray` is
planned for Swift 6.2 per the
[proposal](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0453-vector.md).

Edit: to be clear things work fine on Linux and that's where I've been
using this same `readInlineArray` function that I've proposed.

---------

Co-authored-by: Cory Benfield <lukasa@apple.com>
2025-09-24 09:18:00 +00:00
George Barnett a18bddb0ac Add back NIOFileSystem (#3380)
Motivation:

We accidentally removed the 'NIOFileSystem' module from the
'_NIOFileSystem' product in the last release.

Modifications:

- Rename 'NIOFileSystem' and 'NIOFileSystemFoundationCompat' to 'NIOFS'
  and 'NIOFSFoundationCompat'
- Add back 'NIOFileSystem' which re-exports '_NIOFileSystem' (there was
  no publicly available 'NIOFileSystemFoundationCompat' module to
  remove, only '_NIOFileSystemFoundationCompat').

Result:

Fewer breaks
2025-09-23 17:29:01 +01:00
Cory Benfield f2ebedb36a The formatter changed its mind (#3379) 2025-09-23 14:58:24 +01:00
George Barnett 7290551b7f Add a NIOFilePath based NIOFileSystem (#3363)
Motivation:

We changed the file path type in `_NIOFileSystem` to use `NIOFilePath`
instead of `FilePath`. Originally we planned to use API shims to avoid
breaking API, however in some cases this was inevitable (i.e. where a
file path is returned to the caller).

To roll over to the new API we will instead introduce the
`NIOFileSystem` module using `NIOFilePath` and have `_NIOFileSystem` use
`FilePath`. Users can then opt-in to the new stable API rather than
having it forced upon them.

The first wave of these changes turns `_NIOFileSystem` into
`NIOFileSystem` and uses `NIOFilePath` for its APIs.

Modifications:

- Remove disfavoured overloads (i.e. `FilePath` APIs)
- Update the `DirectoryEntry` API to use `NIOFilePath`.
- Update tests to use `NIOFilePath` since many were relying on the newly
removed shims
- Remove the underscore from the module names and products
- Remove deprecated methods

A follow up change will re-instate the `_NIOFileSystem` (and compat)
module and products using `FilePath`.

Result:

`NIOFileSystem` has a stable API.
2025-09-01 08:11:14 +01:00
Johannes Weiss f656af6b79 SelectableEventLoop.debugDescription: fix debugDescription deadlock (#3360)
### Motivation:

In #3297, I introduced a deadlock involving `SelectableEventLoop`'s
`debugDescription`. I was under the impression that it's not possible to
call this from outside the `NIO` module so I deemed it safe. That was a
mistake :).

### Modifications:

- Make it impossible to deadlock around
`SelectableEventLoop.debugDescription`.

### Result:

- Fewer deadlocks
2025-08-28 13:08:45 +01:00
George BarnettandCory Benfield a65e9735ac Drop all server response parts after an invalid header (#3339)
Motivation:

NIOHTTPResponseHeadersValidator drops head/end response parts if they
contain invalid header fields. If a head part is dropped and the server
allows pipelining then the subsequent body/end part will reach the
pipelining handler and result in an assertion failure in debug builds.
In release builds, some parts may be incorrectly written out leading to
protocol violations.

Modifications:

- Drop all response parts after an invalid response part

Result:

- Fewer bugs
- Resolves #3326

Co-authored-by: Cory Benfield <lukasa@apple.com>
2025-08-12 09:33:24 +00:00
aryan-25andGeorge Barnett 8997a24524 Update FilePath references to NIOFilePath (#3333)
Motivation:

Currently, file paths are represented by the `SystemPackage.FilePath`
type in `NIOFileSystem`. Following from #3322, we want to use
`NIOFilePath` instead.

Modifications:

This change provides `NIOFilePath` accepting/returning variants to all
existing public methods that accept/return `SystemPackage.FilePath`.

The bulk of the changes are in `FileSystemProtocol` and
`FileHandleProtocol`, and their conforming types. The protocols have
been modified to require `NIOFilePath` accepting/returning methods.
Default implementations are provided for `SystemPackage.FilePath`
accepting/returning methods---these call through to the `NIOFilePath`
variants.

Result:

`NIOFilePath` path representations can now be used with the methods for
interacting with the file system.

---------

Co-authored-by: George Barnett <gbarnett@apple.com>
2025-08-11 17:29:02 +01:00
Fabian Fett b881f6ec60 [Windows] Add msghdr extension for Windows (#3336)
To be able to compile on Windows eventually, we need to bridge msghdr
and WSAMSG. This PR tries to accomplish this by using extensions on
those types.
2025-08-11 15:49:00 +01:00
George Barnett 6b484ecafc Make testMetricsDelegateTickInfo less flaky (#3335)
Motivation:

testMetricsDelegateTickInfo fails occasionally because there are more
event loop ticks than it expects. This is because the expectation in the
test was incorrect.

Modifications:

- Update the test expectation and an explanation of how we got to that
number.
- Shutdown the ELG while we're at it.

Result:

Tests are less flaky
2025-08-07 14:40:57 +00:00
finagolfin 4151adfff5 Add Android imports for some new tests in #3308 that require it (#3334)
My Android CI [just broke because it couldn't find these newly used C
symbols in the NIO
tests](https://github.com/finagolfin/swift-android-sdk/actions/runs/16768316992/job/47477878652#step:19:242),
this patch [fixed it
again](https://github.com/finagolfin/swift-android-sdk/actions/runs/16787226279/job/47540691932).
Unsure why this only affects Android, likely the module leaks postulated
before.
2025-08-07 10:40:51 +01:00
Klaas Pieter AnnemaandCory Benfield 1c30f0f205 Support options on AsyncTestingChannel and EmbeddedChannel (#3308)
Support options on AsyncTestingChannel and EmbeddedChannel

Fixes #3305 

### Motivation:

The channels are intended for testing purposes so while most options
have no practical use setting and getting them can be useful for
testing.

For example a traceroute implementation will set TTL to the current hop
number. Testing such an implementation requires the channels to pretend
to support the TTL option.

### Modifications:

Added option storage to AsyncTestingChannel and EmbedededChannel and
made `getOptionSync` and `setOptionSync` read and write from that
storage.

### Result:

EmbeddedChannel and AsyncTestingChannel support changing their options.

---------

Co-authored-by: Cory Benfield <lukasa@apple.com>
2025-08-05 11:37:04 +01:00
Cory Benfield 41b126283c Don't double-initialize Pipe Bootstraps (#3330)
Motivation:

In #3309 I fixed an issue where the channel initializer would not be
called in some PipeBootstrap paths. Unfortunately, that introduced a new
bug where the initializer was now called twice on some other paths.

Modifications:

Get the number of calls back to 1 on the non-async paths. Add some tests

Result:

Better pipe bootstrap behaviour.
2025-08-01 10:11:41 +00:00
aryan-25andGeorge Barnett 96fbe40aae Add a new file path type, NIOFilePath, backed by SystemPackage's FilePath type (#3322)
Motivation:

Two separate types for representing file paths currently exist:
[`SystemPackage`'s
`FilePath`](https://swiftpackageindex.com/apple/swift-system/1.6.0/documentation/systempackage/filepath)
type and [`System`'s
`FilePath`](https://developer.apple.com/documentation/system/filepath)
type.

`NIOFileSystem` currently uses `SystemPackage`'s `FilePath`. However,
the lack of an API for converting between the two representations means
that users whose application also uses `System.FilePath` may find
interacting with `NIOFileSystem` difficult.

Modifications:

- Added `NIOFilePath`, and its subcomponents `NIOFilePath.Root`,
`NIOFilePath.Component`, and `NIOFilePath.ComponentView`.
- These types mirror the API of `SystemPackage`'s `FilePath` and are
internally backed by it.
- `NIOFilePath` can be initialized from either an instance of
`SystemPackage.FilePath` or `System.FilePath`.

Result:

Reduces the friction of interacting with `NIOFileSystem` by providing a
bridge between `SystemPackage.FilePath` and `System.FilePath`.

---------

Co-authored-by: George Barnett <gbarnett@apple.com>
2025-07-30 15:13:50 +01:00
Max Desiatov 175417d85c Fix typo in HTTPServerClientTest.swift comments (#3323)
`we read faster then we can write` -> `we read faster than we can write`
2025-07-28 12:46:19 +00:00
Cory Benfield ee67a96bcb Call channel initializer when using async methods on pipe bootstrap (#3309)
Motivation:

For our async initializers on bootstraps, it's imortant that _both_
channel initializers are called, not only the one that comes as an
argument on the bind function.

Modifications:

Fix the takeOwnershipOfDescriptor async functions to call the
initializer from the bootstrap, and add regression tests.

Result:

Better behaved code.
2025-07-18 09:13:00 +01:00
Johannes Weiss 344db24aaa NIOThread: remove the detached threads functionality (#3304)
### Motivation:

Detached threads are a bad idea, their lifetime becomes random and NIO
doesn't need this functionality (except for in some tests that are
easily refactored)

### Modifications:

- Refactor tests to not use detached threads
- Remove detached threads functionality

### Result:

- Cleaner, less complex and more correct code
2025-07-15 15:20:20 +01:00