Skip to content

Close channel on TLS exception to prevent half-open connections#16202

Merged
zrlw merged 4 commits into
apache:3.3from
uuuyuqi:fix/ssl-server-tls-handler-exception-swallowed
Jul 9, 2026
Merged

Close channel on TLS exception to prevent half-open connections#16202
zrlw merged 4 commits into
apache:3.3from
uuuyuqi:fix/ssl-server-tls-handler-exception-swallowed

Conversation

@uuuyuqi

@uuuyuqi uuuyuqi commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

What is the purpose of the change?

Fixes #16201

SslServerTlsHandler.exceptionCaught() only logged errors without closing the channel or propagating the exception. This caused channels to remain TCP-active but application-dead (half-open) when non-IOException/non-OutOfMemoryError exceptions (e.g., NoClassDefFoundError) occurred during Netty's read loop.

Impact: Consumer-side DubboInvoker.isAvailable() always returned true for these broken connections (it only checks TCP-level channel.isActive()), so the addInvalidateInvoker mechanism never triggered. The broken Provider was never removed from validInvokers, causing continuous RPC timeouts.

Changes:

  • SslServerTlsHandler.exceptionCaught(): Added ctx.close() after logging, consistent with the userEventTriggered() method in the same class which already closes the channel on TLS handshake failure.
  • SslClientTlsHandler.userEventTriggered(): Changed from ctx.fireExceptionCaught() to ctx.close() on handshake failure, consistent with server-side behavior and ensuring the channel is properly closed so the Consumer can detect the failure.

Checklist

Made with Cursor

uuuyuqi added 2 commits April 9, 2026 17:48
SslServerTlsHandler.exceptionCaught() only logged the error without
closing the channel or propagating the exception. This caused channels
to remain TCP-active but application-dead when exceptions like
NoClassDefFoundError occurred during Netty read loops.

Similarly, SslClientTlsHandler did not close the channel on TLS
handshake failure, only firing exceptionCaught to downstream handlers.

This fix ensures both handlers close the channel on failure, allowing
Dubbo's existing health-check mechanism (isAvailable/addInvalidateInvoker)
to properly detect and remove broken invokers.

Change-Id: Ia466bc4db9e59b1f5c1f01a3062c619aabbbb4e1
Co-developed-by: Cursor <noreply@cursor.com>
Change-Id: Ie3ac6e2e6d1ce5e8f6bd2ad4fe2a5c9286d66fbf
Co-developed-by: Cursor <noreply@cursor.com>
@codecov-commenter

codecov-commenter commented Apr 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 60.87%. Comparing base (316df8e) to head (44698a3).

Additional details and impacted files
@@            Coverage Diff            @@
##                3.3   #16202   +/-   ##
=========================================
  Coverage     60.87%   60.87%           
+ Complexity    11767    11764    -3     
=========================================
  Files          1953     1953           
  Lines         89260    89261    +1     
  Branches      13471    13471           
=========================================
+ Hits          54334    54341    +7     
+ Misses        29342    29331   -11     
- Partials       5584     5589    +5     
Flag Coverage Δ
integration-tests-java21 32.09% <0.00%> (+<0.01%) ⬆️
integration-tests-java8 32.20% <0.00%> (-0.01%) ⬇️
samples-tests-java21 32.19% <0.00%> (+<0.01%) ⬆️
samples-tests-java8 29.81% <0.00%> (+0.07%) ⬆️
unit-tests-java11 59.11% <100.00%> (+0.01%) ⬆️
unit-tests-java17 58.63% <100.00%> (+0.03%) ⬆️
unit-tests-java21 58.58% <100.00%> (-0.01%) ⬇️
unit-tests-java25 58.56% <100.00%> (+0.04%) ⬆️
unit-tests-java8 59.12% <100.00%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a TLS failure mode where Netty channels could remain TCP-active but unusable (“half-open”) by ensuring TLS handler failures actively close the channel so higher layers can detect disconnection.

Changes:

  • Close the channel in SslServerTlsHandler.exceptionCaught() after logging TLS negotiation failures.
  • Close the channel on client-side TLS handshake failure in SslClientTlsHandler.userEventTriggered().
  • Add unit tests verifying both server exception handling and client handshake failure paths close the channel.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/ssl/SslServerTlsHandler.java Ensures server-side TLS exceptions close the channel to avoid half-open connections.
dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/ssl/SslClientTlsHandler.java Changes client-side handshake failure handling to close the channel instead of only propagating the exception.
dubbo-remoting/dubbo-remoting-netty4/src/test/java/org/apache/dubbo/remoting/transport/netty4/ssl/SslHandlerExceptionTest.java Adds tests asserting the channel is closed for server exception and client handshake failure scenarios.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…g message, clean up test

- Restore ctx.fireExceptionCaught() before ctx.close() in SslClientTlsHandler
  so downstream handlers can observe the TLS handshake failure cause
- Fix misleading "accept new connection" log message to "connecting to remote server"
- Remove unused ChannelPipeline mock and when() stub in test

🤖 Generated with [Qoder][https://qoder.com]

Change-Id: Ic8d46b8ab340d5d9b40a5e48caf1df7aaccad532
Co-developed-by: Qoder CLI <noreply@qoder.com>
@uuuyuqi uuuyuqi force-pushed the fix/ssl-server-tls-handler-exception-swallowed branch from d761b2a to bcaef85 Compare April 24, 2026 08:31
zrlw
zrlw previously approved these changes May 6, 2026

@zrlw zrlw left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@chickenlj chickenlj left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@uuuyuqi uuuyuqi requested a review from zrlw July 9, 2026 01:33
@zrlw zrlw merged commit c587ff6 into apache:3.3 Jul 9, 2026
32 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] SslServerTlsHandler.exceptionCaught() swallows exceptions without closing channel, causing permanent half-open TLS connections

5 participants