Skip to content

Auto-port 4.2: Fix DiscardClient hang under -Dssl by using a client SSL context#16724

Merged
normanmaurer merged 1 commit into
4.2from
auto-port-pr-16717-to-4.2
Apr 29, 2026
Merged

Auto-port 4.2: Fix DiscardClient hang under -Dssl by using a client SSL context#16724
normanmaurer merged 1 commit into
4.2from
auto-port-pr-16717-to-4.2

Conversation

@netty-project-bot
Copy link
Copy Markdown
Contributor

Auto-port of #16717 to 4.2
Cherry-picked commit: b55fabc


Problem

./run-example -Dssl discard-client against ./run-example -Dssl discard-server does not complete the TLS handshake — it hangs until the handshake times out.

Root Cause

DiscardClient.main builds its SslContext via ServerUtil.buildSslContext():

// example/src/main/java/io/netty/example/util/ServerUtil.java
public static SslContext buildSslContext() throws ... {
    if (!SSL) return null;
    SelfSignedCertificate ssc = new SelfSignedCertificate();
    return SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
}

SslContextBuilder.forServer(...) produces a context whose isClient() is false, so its SSLEngine is created with setUseClientMode(false) (see JdkSslContext). When the example's "client" attaches that engine to its SslHandler, both ends of the connection are configured as TLS servers: each side waits for an inbound ClientHello from the other, and neither sends one. The handshake deadlocks until the configured handshake timeout fires.

Fix

In DiscardClient, build a client SslContext with InsecureTrustManagerFactory when -Dssl is set, and leave sslCtx as null otherwise. This is the same pattern already used by ObjectEchoClient, HttpUploadClient, SecureChatClient, Http2Client, MemcacheClient, and other client examples in the same module.

The server side (DiscardServer) is unchanged and continues to use ServerUtil.buildSslContext() correctly.

Tests Added

The example module has no unit-test infrastructure (example/src/ contains only main); examples are runnable demos rather than testable units. The fix is verified by inspection against the matching if (SSL) { SslContextBuilder.forClient()... } pattern in the other client examples cited above.

Impact

  • ./run-example -Dssl discard-client against ./run-example -Dssl discard-server now completes the TLS handshake instead of timing out.
  • Plaintext mode (no -Dssl) is unchanged: sslCtx is null exactly as before.
  • Only DiscardClient.java is touched. DiscardServer.java, DiscardClientHandler.java, and DiscardServerHandler.java are unchanged.

Other example clients (EchoClient, FactorialClient, WorldClockClient, TelnetClient) call the same ServerUtil.buildSslContext() and exhibit the same hang under -Dssl. Those are kept out of this PR to keep the scope tied to the reported issue and can be addressed in a follow-up.

Fixes #14499

)

## Problem

`./run-example -Dssl discard-client` against `./run-example -Dssl
discard-server` does not complete the TLS handshake — it hangs until the
handshake times out.

## Root Cause

`DiscardClient.main` builds its `SslContext` via
`ServerUtil.buildSslContext()`:

```java
// example/src/main/java/io/netty/example/util/ServerUtil.java
public static SslContext buildSslContext() throws ... {
    if (!SSL) return null;
    SelfSignedCertificate ssc = new SelfSignedCertificate();
    return SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
}
```

`SslContextBuilder.forServer(...)` produces a context whose `isClient()`
is `false`, so its `SSLEngine` is created with `setUseClientMode(false)`
(see `JdkSslContext`). When the example's "client" attaches that engine
to its `SslHandler`, both ends of the connection are configured as TLS
servers: each side waits for an inbound `ClientHello` from the other,
and neither sends one. The handshake deadlocks until the configured
handshake timeout fires.

## Fix

In `DiscardClient`, build a client `SslContext` with
`InsecureTrustManagerFactory` when `-Dssl` is set, and leave `sslCtx` as
`null` otherwise. This is the same pattern already used by
`ObjectEchoClient`, `HttpUploadClient`, `SecureChatClient`,
`Http2Client`, `MemcacheClient`, and other client examples in the same
module.

The server side (`DiscardServer`) is unchanged and continues to use
`ServerUtil.buildSslContext()` correctly.

## Tests Added

The `example` module has no unit-test infrastructure (`example/src/`
contains only `main`); examples are runnable demos rather than testable
units. The fix is verified by inspection against the matching `if (SSL)
{ SslContextBuilder.forClient()... }` pattern in the other client
examples cited above.

## Impact

- `./run-example -Dssl discard-client` against `./run-example -Dssl
discard-server` now completes the TLS handshake instead of timing out.
- Plaintext mode (no `-Dssl`) is unchanged: `sslCtx` is `null` exactly
as before.
- Only `DiscardClient.java` is touched. `DiscardServer.java`,
`DiscardClientHandler.java`, and `DiscardServerHandler.java` are
unchanged.

Other example clients (`EchoClient`, `FactorialClient`,
`WorldClockClient`, `TelnetClient`) call the same
`ServerUtil.buildSslContext()` and exhibit the same hang under `-Dssl`.
Those are kept out of this PR to keep the scope tied to the reported
issue and can be addressed in a follow-up.

Fixes #14499

(cherry picked from commit b55fabc)
@normanmaurer normanmaurer merged commit 6ecb63d into 4.2 Apr 29, 2026
20 checks passed
@normanmaurer normanmaurer modified the milestone: 4.2.13.Final Apr 29, 2026
@normanmaurer normanmaurer deleted the auto-port-pr-16717-to-4.2 branch April 29, 2026 12:55
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

Successfully merging this pull request may close these issues.

Discard example broken

3 participants