-
Notifications
You must be signed in to change notification settings - Fork 720
don't just drop Channels on the floor if registration fails #413
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2360,6 +2360,106 @@ public class ChannelTests: XCTestCase { | |
| XCTAssertTrue(client.isActive) | ||
| XCTAssertEqual(serverChannel.localAddress!, client.remoteAddress!) | ||
| } | ||
|
|
||
| func testFailedRegistrationOfClientSocket() throws { | ||
| let group = MultiThreadedEventLoopGroup(numThreads: 2) | ||
| defer { | ||
| XCTAssertNoThrow(try group.syncShutdownGracefully()) | ||
| } | ||
| let serverChannel = try ServerBootstrap(group: group).bind(host: "localhost", port: 0).wait() | ||
| defer { | ||
| XCTAssertNoThrow(try serverChannel.close().wait()) | ||
| } | ||
| do { | ||
| let clientChannel = try ClientBootstrap(group: group) | ||
| .channelInitializer { channel in | ||
| channel.pipeline.add(handler: FailRegistrationHandler()) | ||
| } | ||
| .connect(to: serverChannel.localAddress!) | ||
| .wait() | ||
| XCTFail("shouldn't have reached this but got \(clientChannel)") | ||
| } catch FailRegistrationHandler.RegistrationFailedError.error { | ||
| // ok | ||
| } catch { | ||
| XCTFail("unexpected error \(error)") | ||
| } | ||
| } | ||
|
|
||
| func testFailedRegistrationOfAcceptedSocket() throws { | ||
| let group = MultiThreadedEventLoopGroup(numThreads: 2) | ||
| defer { | ||
| XCTAssertNoThrow(try group.syncShutdownGracefully()) | ||
| } | ||
| let serverChannel = try ServerBootstrap(group: group) | ||
| .childChannelInitializer { channel in | ||
| channel.pipeline.add(handler: FailRegistrationHandler()) | ||
| } | ||
| .bind(host: "localhost", port: 0).wait() | ||
| defer { | ||
| XCTAssertNoThrow(try serverChannel.close().wait()) | ||
| } | ||
| let clientChannel = try ClientBootstrap(group: group) | ||
| .connect(to: serverChannel.localAddress!) | ||
| .wait() | ||
| try clientChannel.closeFuture.wait() | ||
| } | ||
|
|
||
| func testFailedRegistrationOfServerSocket() throws { | ||
| let group = MultiThreadedEventLoopGroup(numThreads: 2) | ||
| defer { | ||
| XCTAssertNoThrow(try group.syncShutdownGracefully()) | ||
| } | ||
| do { | ||
| let serverChannel = try ServerBootstrap(group: group) | ||
| .serverChannelInitializer { channel in | ||
| channel.pipeline.add(handler: FailRegistrationHandler()) | ||
| } | ||
| .bind(host: "localhost", port: 0).wait() | ||
| XCTFail("shouldn't be reached") | ||
| XCTAssertNoThrow(try serverChannel.close().wait()) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove this one as it should never be reached anyway ?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added it because if it fails, not closing it leads to a crash (assert) and then hides the actual bug. I’d leave it in but am also happy to take out.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah right... Ignore me then (or maybe add a comment) :) |
||
| } catch FailRegistrationHandler.RegistrationFailedError.error { | ||
| // ok | ||
| } catch { | ||
| XCTFail("unexpected error \(error)") | ||
| } | ||
| } | ||
|
|
||
| func testTryingToBindOnPortThatIsAlreadyBoundFailsButDoesNotCrash() throws { | ||
| // this is a regression test for #417 | ||
|
|
||
| let group = MultiThreadedEventLoopGroup(numThreads: 1) | ||
| defer { | ||
| XCTAssertNoThrow(try group.syncShutdownGracefully()) | ||
| } | ||
|
|
||
| let serverChannel1 = try! ServerBootstrap(group: group) | ||
| .bind(host: "localhost", port: 0) | ||
| .wait() | ||
| defer { | ||
| XCTAssertNoThrow(try serverChannel1.close().wait()) | ||
| } | ||
|
|
||
| do { | ||
| let serverChannel2 = try ServerBootstrap(group: group) | ||
| .bind(to: serverChannel1.localAddress!) | ||
| .wait() | ||
| XCTFail("shouldn't have succeeded, got two server channels on the same port: \(serverChannel1) and \(serverChannel2)") | ||
| } catch let e as IOError where e.errnoCode == EADDRINUSE { | ||
| // OK | ||
| } catch { | ||
| XCTFail("unexpected error: \(error)") | ||
| } | ||
| } | ||
| } | ||
|
|
||
| fileprivate final class FailRegistrationHandler: ChannelOutboundHandler { | ||
| enum RegistrationFailedError: Error { case error } | ||
|
|
||
| typealias OutboundIn = Never | ||
|
|
||
| func register(ctx: ChannelHandlerContext, promise: EventLoopPromise<Void>?) { | ||
| promise!.fail(error: RegistrationFailedError.error) | ||
| } | ||
| } | ||
|
|
||
| fileprivate class VerifyConnectionFailureHandler: ChannelInboundHandler { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should
bind0do this error handling? There are a few other paths through this bootstrap that didn't get changed here but that still do registrations.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done now, thanks