Skip to content

Commit 49cd78b

Browse files
authored
Fix withConnectedSocket in async mode (#2937)
Motivation: The async flavour of withConnectedSocket accidentally type-erased the channel, which caused it to be unable to be used. Modifications: Un-erase the type of the channel. Add a test. Result: withConnectedSocket works again Resolves #2936
1 parent cc1c57c commit 49cd78b

File tree

2 files changed

+80
-1
lines changed

2 files changed

+80
-1
lines changed

Sources/NIOPosix/Bootstrap.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1398,7 +1398,7 @@ extension ClientBootstrap {
13981398
private func initializeAndRegisterChannel<ChannelInitializerResult, PostRegistrationTransformationResult>(
13991399
channel: SocketChannel,
14001400
channelInitializer: @escaping @Sendable (Channel) -> EventLoopFuture<ChannelInitializerResult>,
1401-
registration: @escaping @Sendable (Channel) -> EventLoopFuture<Void>,
1401+
registration: @escaping @Sendable (SocketChannel) -> EventLoopFuture<Void>,
14021402
postRegisterTransformation: @escaping @Sendable (ChannelInitializerResult, EventLoop) -> EventLoopFuture<
14031403
PostRegistrationTransformationResult
14041404
>

Tests/NIOPosixTests/AsyncChannelBootstrapTests.swift

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,69 @@ final class AsyncChannelBootstrapTests: XCTestCase {
609609
}
610610
}
611611

612+
func testServerClientBootstrap_withAsyncChannel_clientConnectedSocket() async throws {
613+
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 3)
614+
defer {
615+
try! eventLoopGroup.syncShutdownGracefully()
616+
}
617+
618+
let channel = try await ServerBootstrap(group: eventLoopGroup)
619+
.serverChannelOption(.socketOption(.so_reuseaddr), value: 1)
620+
.childChannelOption(.autoRead, value: true)
621+
.bind(
622+
host: "127.0.0.1",
623+
port: 0
624+
) { channel in
625+
channel.eventLoop.makeCompletedFuture { () -> NIOAsyncChannel<String, String> in
626+
try channel.pipeline.syncOperations.addHandler(ByteToMessageHandler(LineDelimiterCoder()))
627+
try channel.pipeline.syncOperations.addHandler(MessageToByteHandler(LineDelimiterCoder()))
628+
try channel.pipeline.syncOperations.addHandler(ByteBufferToStringHandler())
629+
return try NIOAsyncChannel(
630+
wrappingChannelSynchronously: channel,
631+
configuration: .init(
632+
inboundType: String.self,
633+
outboundType: String.self
634+
)
635+
)
636+
}
637+
}
638+
639+
try await withThrowingTaskGroup(of: Void.self) { group in
640+
let (stream, continuation) = AsyncStream<StringOrByte>.makeStream()
641+
var iterator = stream.makeAsyncIterator()
642+
643+
group.addTask {
644+
try await withThrowingTaskGroup(of: Void.self) { _ in
645+
try await channel.executeThenClose { inbound in
646+
for try await childChannel in inbound {
647+
try await childChannel.executeThenClose { childChannelInbound, _ in
648+
for try await value in childChannelInbound {
649+
continuation.yield(.string(value))
650+
}
651+
}
652+
}
653+
}
654+
}
655+
}
656+
657+
let s = try Socket(protocolFamily: .inet, type: .stream)
658+
XCTAssert(try s.connect(to: channel.channel.localAddress!))
659+
let fd = try s.takeDescriptorOwnership()
660+
661+
let stringChannel = try await self.makeClientChannel(
662+
eventLoopGroup: eventLoopGroup,
663+
fileDescriptor: fd
664+
)
665+
try await stringChannel.executeThenClose { _, outbound in
666+
try await outbound.write("hello")
667+
}
668+
669+
await XCTAsyncAssertEqual(await iterator.next(), .string("hello"))
670+
671+
group.cancelAll()
672+
}
673+
}
674+
612675
// MARK: Datagram Bootstrap
613676

614677
func testDatagramBootstrap_withAsyncChannel_andHostPort() async throws {
@@ -1280,6 +1343,22 @@ final class AsyncChannelBootstrapTests: XCTestCase {
12801343
}
12811344
}
12821345

1346+
private func makeClientChannel(
1347+
eventLoopGroup: EventLoopGroup,
1348+
fileDescriptor: CInt
1349+
) async throws -> NIOAsyncChannel<String, String> {
1350+
try await ClientBootstrap(group: eventLoopGroup)
1351+
.withConnectedSocket(fileDescriptor) { channel in
1352+
channel.eventLoop.makeCompletedFuture {
1353+
try channel.pipeline.syncOperations.addHandler(AddressedEnvelopingHandler())
1354+
try channel.pipeline.syncOperations.addHandler(ByteToMessageHandler(LineDelimiterCoder()))
1355+
try channel.pipeline.syncOperations.addHandler(MessageToByteHandler(LineDelimiterCoder()))
1356+
try channel.pipeline.syncOperations.addHandler(ByteBufferToStringHandler())
1357+
return try NIOAsyncChannel(wrappingChannelSynchronously: channel)
1358+
}
1359+
}
1360+
}
1361+
12831362
private func makeClientChannelWithProtocolNegotiation(
12841363
eventLoopGroup: EventLoopGroup,
12851364
port: Int,

0 commit comments

Comments
 (0)