diff --git a/Sources/NIOTransportServices/StateManagedNWConnectionChannel.swift b/Sources/NIOTransportServices/StateManagedNWConnectionChannel.swift index 0aa0d56..394e896 100644 --- a/Sources/NIOTransportServices/StateManagedNWConnectionChannel.swift +++ b/Sources/NIOTransportServices/StateManagedNWConnectionChannel.swift @@ -272,6 +272,12 @@ extension StateManagedNWConnectionChannel { self.connectPromise = nil pendingConnect.fail(error) } + + // Step 4 Forward the connection state failed Error + let channelError = error as? ChannelError + if channelError != .eof { + self.pipeline.fireErrorCaught(error) + } } public func doHalfClose0(error: Error, promise: EventLoopPromise?) { diff --git a/Tests/NIOTransportServicesTests/NIOTSConnectionChannelTests.swift b/Tests/NIOTransportServicesTests/NIOTSConnectionChannelTests.swift index 10056e6..486d472 100644 --- a/Tests/NIOTransportServicesTests/NIOTSConnectionChannelTests.swift +++ b/Tests/NIOTransportServicesTests/NIOTSConnectionChannelTests.swift @@ -865,5 +865,58 @@ class NIOTSConnectionChannelTests: XCTestCase { .wait() XCTAssertNoThrow(try connection.close().wait()) } + + func testErrorIsForwardedFromFailedConnectionState() throws { + final class ForwardErrorHandler: ChannelDuplexHandler { + typealias OutboundIn = ByteBuffer + typealias InboundIn = ByteBuffer + + private let testCompletePromise: EventLoopPromise + let listenerChannel: Channel + + init(testCompletePromise: EventLoopPromise, listenerChannel: Channel) { + self.testCompletePromise = testCompletePromise + self.listenerChannel = listenerChannel + } + + func channelActive(context: ChannelHandlerContext) { + listenerChannel + .close() + .whenSuccess { _ in + _ = context.channel.write(ByteBuffer(data: Data())) + } + } + + func errorCaught(context: ChannelHandlerContext, error: Error) { + let error = error as? ChannelError + XCTAssertNotEqual(error, ChannelError.eof) + XCTAssertEqual(error, ChannelError.ioOnClosedChannel) + XCTAssertNotNil(error) + testCompletePromise.succeed(error!) + } + } + + let listener = try NIOTSListenerBootstrap(group: self.group) + .childChannelInitializer { channel in + return channel.eventLoop.makeSucceededVoidFuture() + } + .bind(host: "localhost", port: 0) + .wait() + + let testCompletePromise = self.group.next().makePromise(of: Error.self) + let connection = try NIOTSConnectionBootstrap(group: self.group) + .channelInitializer { channel in + channel.pipeline.addHandler( + ForwardErrorHandler( + testCompletePromise: testCompletePromise, + listenerChannel: listener + ) + ) + } + .connect(to: listener.localAddress!) + .wait() + XCTAssertNoThrow(try connection.close().wait()) + XCTAssertNoThrow(try testCompletePromise.futureResult.wait()) + } } #endif