Skip to content
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

NIO can send channelInactive before channelActive reordered if user Channel.close()s in connect promise callback #2773

Open
weissi opened this issue Jul 9, 2024 · 2 comments

Comments

@weissi
Copy link
Member

weissi commented Jul 9, 2024

Expected behavior

  • channelInactive comes after channelActive
  • channelInactive doesn't happen if channelActive hasn't happened

Actual behavior

It's possible to get channelActive following channelInactive.

Steps to reproduce

  • Create an SSL channel that gets Channel.close()d really early on.

This seems related to apple/swift-nio-ssl#467

NIOSSLHandler observes the channel events in this order:

NIOSSLHandler sees the following channel events:

  • handlerAdded
  • close (triggered from a Channel.close())
  • channelInactive (triggered from BaseSocketChannel.close0) [BUG HERE (channelInactive without channelActive)]
  • channelActive (triggered from BaseSocketChannel.writable -> BaseSocketChannel.finishConnect -> BaseSocketChannel.becomeActive()) [BUG HERE (channelActive after channelInactive)]

Obviously those channel events are wrong. That's a bug in NIO too.

@weissi
Copy link
Member Author

weissi commented Jul 9, 2024

The issues is that the connect promise gets (by design) priority over fireChannelActive. The code's here:

promise?.succeed(())
pipeline.syncOperations.fireChannelActive()

        case (.fullyRegistered, .activate):
            self.currentState = .activated
            return { promise, pipeline in
                promise?.succeed(())
                pipeline.syncOperations.fireChannelActive()
            }

So NIO (like Netty) will always fulfil the promise first and then fire the channel pipeline event. That leads to this reorder:

  • Channel.connect succeeds
  • connect's promise gets fulfilled
  • user calls Channel.close() in connect promise callback
  • channelInactive gets called (because of the close)
  • channelActive gets called once we move past the promise?.succeed(()) line

@weissi weissi changed the title NIO can send channelInactive before channelActive reordered NIO can send channelInactive before channelActive reordered if user Channel.close()s in connect promise callback Jul 9, 2024
@weissi
Copy link
Member Author

weissi commented Jul 9, 2024

I think this is a rediscovery of #196 . Please note this comment: #196 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant