Skip to content

Conversation

@vinniefalco
Copy link
Member

@vinniefalco vinniefalco commented Feb 8, 2026

Summary by CodeRabbit

  • New Features

    • Added reset() methods to TLS stream components, allowing applications to clear session state and re-establish secure connections without recreating streams.
  • Bug Fixes

    • Fixed session loop termination logic in the echo server.
  • Chores

    • Updated copyright notice email formatting across multiple files for consistency.

@coderabbitai
Copy link

coderabbitai bot commented Feb 8, 2026

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (38)
  • doc/modules/ROOT/nav.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/2.networking-tutorial/2.intro.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/2.networking-tutorial/2a.how-you-connect.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/2.networking-tutorial/2b.internet-addresses.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/2.networking-tutorial/2c.domain-name-system.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/2.networking-tutorial/2d.urls.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/2.networking-tutorial/2e.client-server-model.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/2.networking-tutorial/2f.internet-protocol.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/2.networking-tutorial/2g.udp.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/2.networking-tutorial/2h.tcp-fundamentals.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/2.networking-tutorial/2i.tcp-connections.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/2.networking-tutorial/2j.tcp-data-flow.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/2.networking-tutorial/2k.tcp-reliability.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/2.networking-tutorial/2l.tcp-performance.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/3.tutorials/3.intro.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/3.tutorials/3a.echo-server.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/3.tutorials/3b.http-client.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/3.tutorials/3c.dns-lookup.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/3.tutorials/3d.tls-context.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4.intro.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4a.tcp-networking.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4b.concurrent-programming.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4c.io-context.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4d.sockets.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4e.tcp-acceptor.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4f.endpoints.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4g.composed-operations.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4h.timers.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4i.signals.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4j.resolver.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4k.tcp-server.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4l.tls.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4m.error-handling.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4n.buffers.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/5.testing/5a.mocket.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/glossary.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/index.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/quick-start.adoc is excluded by !**/doc/**

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • 🔍 Trigger a full review
📝 Walkthrough

Walkthrough

This pull request updates copyright notices across the codebase from an obfuscated email format to standard format, and introduces reset() methods to TLS stream classes (openssl_stream, wolfssl_stream, and tls_stream) for session state reset capability. A logic change in echo_server.cpp modifies the break condition for stream termination.

Changes

Cohort / File(s) Summary
Copyright Notice Updates
example/*, include/boost/corosio/*, perf/profile/*, src/corosio/src/detail/*, src/corosio/src/*.cpp, src/openssl/src/wolfssl.cpp, src/wolfssl/src/wolfssl.cpp
Updated author email formatting from "vinnie dot falco at gmail dot com" to "vinnie.falco@gmail.com" across 60+ files. No functional changes.
Echo Server Logic Change
example/echo-server/echo_server.cpp
Modified stream termination condition from (ec || n == 0) to (ec) only, allowing loop continuation when zero bytes are read instead of breaking immediately.
TLS Stream Interface Reset Methods
include/boost/corosio/tls_stream.hpp, include/boost/corosio/openssl_stream.hpp, include/boost/corosio/wolfssl_stream.hpp
Added reset() method declarations to TLS stream classes. Pure virtual reset() added to base tls_stream interface; override implementations added to openssl_stream and wolfssl_stream headers.
TLS Stream Reset Implementations
src/openssl/src/openssl_stream.cpp, src/wolfssl/src/wolfssl_stream.cpp
Implemented reset() functionality with per-instance usage flags. Clears session state via SSL_clear/SSL_free while preserving buffer allocations and reapplying TLS extensions where applicable. Handshake flow modified to invoke reset if session already in use.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 A hop through headers, emails now plain,
Copyright reformatted, no logic strain!
Reset the sessions, clear TLS state,
Streams fresh and ready—correlation's great!

🚥 Pre-merge checks | ✅ 1 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'work' is vague and generic, providing no meaningful information about the actual changes in the pull request. Use a descriptive title that summarizes the main changes, such as 'Update email formatting in copyright notices and add TLS stream reset functionality' or similar.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In `@example/echo-server/echo_server.cpp`:
- Around line 56-57: The loop that reads into buf_ must resume checking for
zero-length reads to avoid a busy spin; restore the original guard so that after
calling read_some (the call that yields ec and n) you break when either ec is
set or n == 0. Update the conditional around the read result in the function
handling the socket read (the read_some return handling that currently only
tests ec) to include "|| n == 0" so zero-byte reads cause the loop to exit and
prevent repeated zero-length write/read cycles.

In `@include/boost/corosio/endpoint.hpp`:
- Line 2: The file header in include/boost/corosio/endpoint.hpp has the
copyright year 2026 which is inconsistent with other files in this PR that use
2025; update the copyright line in endpoint.hpp to use 2025 (or confirm and
leave as 2026 if the change was intentional) so it matches the rest of the
project; locate the top-of-file comment in endpoint.hpp (the file/identifier:
endpoint.hpp, namespace corosio is present) and change the year token from
"2026" to "2025".

In `@include/boost/corosio/openssl_stream.hpp`:
- Around line 86-92: The openssl_stream constructor currently assigns impl_ =
make_impl(...) without checking for nullptr, which can happen when init_ssl()
fails; update the constructor (the template overload of openssl_stream taking S
stream and tls_context ctx) to validate the returned pointer from
make_impl(stream_, ctx) and throw a suitable exception (e.g., std::runtime_error
or a domain-specific error) if make_impl returns nullptr so subsequent methods
(handshake, read, write, reset) cannot dereference a null impl_; reference
make_impl, impl_, and init_ssl() when implementing the check.

In `@src/corosio/src/timer.cpp`:
- Around line 10-13: Add a high-level /* */ overview comment immediately after
the includes in src/corosio/src/timer.cpp that describes how the timer
implementation works (e.g., interaction between boost::corosio::timer, its
scheduling/expiry mechanism, threading/strand assumptions, how callbacks are
enqueued/executed, and any subtle lifetime or cancellation behavior). Place this
paragraph right after the existing `#include` lines and reference the primary
symbols in the file (such as the timer class/constructors, start/stop/expiry
handlers, and any helper functions) so future readers can quickly understand
non-obvious implementation details.

In `@src/openssl/src/openssl_stream.cpp`:
- Around line 305-328: The reset() method currently ignores SSL_clear()'s return
value; change impl::reset() to return a std::error_code (or similar error
indicator), call SSL_clear(ssl_) and if it returns 0 convert the OpenSSL error
(ERR_get_error / ERR_reason_error_string) into a meaningful std::error_code and
return it immediately (before draining ext_bio_ or reapplying hostname),
otherwise continue and return success; then update callers (notably
do_handshake() and the public wrapper that invokes impl::reset()) to check the
returned std::error_code and abort/propagate the error instead of proceeding
with SSL operations when reset fails.
🧹 Nitpick comments (4)
include/boost/corosio/tls_stream.hpp (1)

127-151: Well-documented reset() addition to the TLS stream interface.

The docstring covers purpose, preconditions, thread safety, and behavioral notes — nicely done.

One minor gap: consider documenting exception behavior (@throws or marking noexcept). If the concrete implementations never throw during reset, noexcept on the virtual would enforce that contract across all backends.

     virtual void
-    reset() = 0;
+    reset() noexcept = 0;

As per coding guidelines: "Document thread-safety guarantees and exception specifications where applicable."

include/boost/corosio/wolfssl_stream.hpp (1)

127-128: Consider adding a brief docstring for reset().

The other overrides in this class follow a no-doc pattern (relying on the base class), but reset() is a newly introduced operation. A one-line /// Reset the TLS session state for reuse. comment would help readers understand the semantics without navigating to tls_stream.hpp. As per coding guidelines, docstrings are required for all functions in public headers in non-detail namespaces: "Docstrings should include a brief description of purpose, document all parameters, return values, and any preconditions, postconditions, or exceptions."

include/boost/corosio/openssl_stream.hpp (1)

127-128: Missing documentation for reset().

This is a new public API method on a public header. Per the coding guidelines, it needs at minimum a brief description, @par notes on preconditions (e.g., must not be called while an async operation is in flight), and what state the stream is left in after reset. The tls_stream base class declares virtual void reset() = 0 so ideally the base should carry the contract docs, but each override should at least have a /** @copydoc tls_stream::reset */ or its own brief.

src/wolfssl/src/wolfssl_stream.cpp (1)

345-363: WolfSSL reset() frees the SSL object; OpenSSL reset() preserves it — asymmetric behavior worth noting.

The WolfSSL reset() calls wolfSSL_free(ssl_) and nulls the pointer, while the OpenSSL variant calls SSL_clear() to preserve the SSL*/BIO pair. Both are valid approaches given the different initialization strategies (deferred vs. eager), but the behavioral asymmetry may confuse maintainers.

Consider adding a brief comment in each reset() explaining why the strategy differs (e.g., "WolfSSL defers SSL creation to handshake, so reset frees it entirely" vs. "OpenSSL eagerly creates SSL/BIO in make_impl, so reset preserves them").

Comment on lines +56 to 57
if (ec)
break;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Removing the n == 0 break guard may cause a busy loop on zero-byte reads.

The old condition was if (ec || n == 0). With only if (ec), a read_some that returns 0 bytes without an error will spin the loop: buf_.resize(0) → zero-length write → zero-length read_some → repeat. Even if the socket contract guarantees EOF via ec on peer shutdown, defensive coding against a zero-byte return (e.g., from a spurious wakeup or platform quirk) is cheap and prevents a potential tight loop.

Based on learnings: in boost::corosio, socket::shutdown(shutdown_send) has a contract that requires subsequent read operations to return an explicit EOF error code, not just zero bytes — but this contract may not cover all edge cases or platforms.

Proposed fix
-            if (ec)
+            if (ec || n == 0)
                 break;
🤖 Prompt for AI Agents
In `@example/echo-server/echo_server.cpp` around lines 56 - 57, The loop that
reads into buf_ must resume checking for zero-length reads to avoid a busy spin;
restore the original guard so that after calling read_some (the call that yields
ec and n) you break when either ec is set or n == 0. Update the conditional
around the read result in the function handling the socket read (the read_some
return handling that currently only tests ec) to include "|| n == 0" so
zero-byte reads cause the loop to exit and prevent repeated zero-length
write/read cycles.

@@ -1,5 +1,5 @@
//
// Copyright (c) 2026 Vinnie Falco (vinnie dot falco at gmail dot com)
// Copyright (c) 2026 Vinnie Falco (vinnie.falco@gmail.com)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Inconsistent copyright year: this file says 2026 while other files in this PR use 2025.

Other updated files (e.g., echo_server.cpp, timers.hpp, resolver.hpp) use Copyright (c) 2025. This file has Copyright (c) 2026. If this is intentional (e.g., file was created/modified in 2026), ignore; otherwise, align for consistency.

🤖 Prompt for AI Agents
In `@include/boost/corosio/endpoint.hpp` at line 2, The file header in
include/boost/corosio/endpoint.hpp has the copyright year 2026 which is
inconsistent with other files in this PR that use 2025; update the copyright
line in endpoint.hpp to use 2025 (or confirm and leave as 2026 if the change was
intentional) so it matches the rest of the project; locate the top-of-file
comment in endpoint.hpp (the file/identifier: endpoint.hpp, namespace corosio is
present) and change the year token from "2026" to "2025".

Comment on lines +86 to +92
template<capy::Stream S>
requires (!std::same_as<std::decay_t<S>, openssl_stream>)
openssl_stream(S stream, tls_context ctx)
: stream_(std::move(stream))
, impl_(make_impl(stream_, ctx))
{
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

make_impl can return nullptr, but the constructor doesn't check.

Looking at openssl_stream.cpp line 700–710, make_impl returns nullptr when init_ssl() fails. The constructor stores the result directly into impl_ without validation, so any subsequent member call (handshake, read, write, reset) will dereference a null pointer.

The wolfssl_stream constructor has the same pattern but its make_impl never returns nullptr (it defers SSL creation to handshake time), so it's safe there. The openssl variant is not.

Proposed fix: throw on init failure
     template<capy::Stream S>
         requires (!std::same_as<std::decay_t<S>, openssl_stream>)
     openssl_stream(S stream, tls_context ctx)
         : stream_(std::move(stream))
         , impl_(make_impl(stream_, ctx))
     {
+        if(!impl_)
+            throw std::runtime_error("OpenSSL initialization failed");
     }

Apply the same check to the pointer-based constructor.

🤖 Prompt for AI Agents
In `@include/boost/corosio/openssl_stream.hpp` around lines 86 - 92, The
openssl_stream constructor currently assigns impl_ = make_impl(...) without
checking for nullptr, which can happen when init_ssl() fails; update the
constructor (the template overload of openssl_stream taking S stream and
tls_context ctx) to validate the returned pointer from make_impl(stream_, ctx)
and throw a suitable exception (e.g., std::runtime_error or a domain-specific
error) if make_impl returns nullptr so subsequent methods (handshake, read,
write, reset) cannot dereference a null impl_; reference make_impl, impl_, and
init_ssl() when implementing the check.

Comment on lines +10 to +13
#include <boost/corosio/timer.hpp>

#include <boost/corosio/detail/except.hpp>

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add the required implementation overview comment after the includes.

This file contains non-trivial implementation logic but lacks the mandated /* */ high-level overview comment immediately after the includes. Please add a brief paragraph describing how the timer implementation works and any non-obvious details. As per coding guidelines “Files containing non-trivial implementation logic should include a /* */ block comment after the includes that provides a high-level overview of how the implementation works.”

🤖 Prompt for AI Agents
In `@src/corosio/src/timer.cpp` around lines 10 - 13, Add a high-level /* */
overview comment immediately after the includes in src/corosio/src/timer.cpp
that describes how the timer implementation works (e.g., interaction between
boost::corosio::timer, its scheduling/expiry mechanism, threading/strand
assumptions, how callbacks are enqueued/executed, and any subtle lifetime or
cancellation behavior). Place this paragraph right after the existing `#include`
lines and reference the primary symbols in the file (such as the timer
class/constructors, start/stop/expiry handlers, and any helper functions) so
future readers can quickly understand non-obvious implementation details.

Comment on lines +305 to +328
void
reset()
{
if(!ssl_)
return;

// Preserves SSL* and BIO pair, releases session state
SSL_clear(ssl_);

// Drain stale data from the external BIO
char drain[1024];
while(BIO_ctrl_pending(ext_bio_) > 0)
BIO_read(ext_bio_, drain, sizeof(drain));

// SSL_clear clears per-session settings; reapply hostname
auto& cd = detail::get_tls_context_data(ctx_);
if(!cd.hostname.empty())
{
SSL_set_tlsext_host_name(ssl_, cd.hostname.c_str());
SSL_set1_host(ssl_, cd.hostname.c_str());
}

used_ = false;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

OpenSSL SSL_clear return value documentation

💡 Result:

SSL_clear(SSL *ssl) returns an int:

  • 1: success — the SSL object was reset and can be used for another connection. [1]
  • 0: failure — the reset could not be performed; check the OpenSSL error stack to determine why. [1]

Source: OpenSSL SSL_clear manual page (see RETURN VALUES). [1]

References

Citations:


🏁 Script executed:

# Search for all calls to reset() in the codebase to understand usage context
rg "reset\(" --type cpp --type hpp | head -20

Repository: cppalliance/corosio

Length of output: 90


🏁 Script executed:

# Check the do_handshake function context where reset is called
sed -n '520,535p' src/openssl/src/openssl_stream.cpp

Repository: cppalliance/corosio

Length of output: 317


🏁 Script executed:

# Check the public reset() method mentioned in observations
sed -n '768,773p' src/openssl/src/openssl_stream.cpp

Repository: cppalliance/corosio

Length of output: 116


🏁 Script executed:

# Find all call sites of reset() in the codebase
rg "\.reset\(\)" --type-add 'cpp:*.{cpp,cc,cxx,h,hpp,hxx}' -A 2 -B 2

Repository: cppalliance/corosio

Length of output: 19285


🏁 Script executed:

# Check the full do_handshake function to see error handling context
sed -n '526,600p' src/openssl/src/openssl_stream.cpp

Repository: cppalliance/corosio

Length of output: 1964


🏁 Script executed:

# Check if there's any error checking pattern for SSL operations in the file
rg "SSL_" src/openssl/src/openssl_stream.cpp | grep -E "(if|return|error)" | head -15

Repository: cppalliance/corosio

Length of output: 874


Check SSL_clear() return value in reset().

SSL_clear() returns 0 on failure and 1 on success. Ignoring the return value means the stream silently proceeds with a potentially corrupted SSL session on the next handshake, leading to undefined behavior or security issues.

Change impl::reset() to check the return value and propagate the error. Since this is called from do_handshake(), consider returning std::error_code from reset() and handling the failure before proceeding with SSL operations.

Proposed approach
-    void
-    reset()
+    std::error_code
+    reset()
     {
         if(!ssl_)
-            return;
+            return {};
 
-        // Preserves SSL* and BIO pair, releases session state
-        SSL_clear(ssl_);
+        if(!SSL_clear(ssl_))
+        {
+            unsigned long err = ERR_get_error();
+            return std::error_code(static_cast<int>(err), std::system_category());
+        }
 
         // ... hostname reapplication ...
         
         used_ = false;
+        return {};
     }

Update the public wrapper and do_handshake() to check the returned error code.

🤖 Prompt for AI Agents
In `@src/openssl/src/openssl_stream.cpp` around lines 305 - 328, The reset()
method currently ignores SSL_clear()'s return value; change impl::reset() to
return a std::error_code (or similar error indicator), call SSL_clear(ssl_) and
if it returns 0 convert the OpenSSL error (ERR_get_error /
ERR_reason_error_string) into a meaningful std::error_code and return it
immediately (before draining ext_bio_ or reapplying hostname), otherwise
continue and return success; then update callers (notably do_handshake() and the
public wrapper that invokes impl::reset()) to check the returned std::error_code
and abort/propagate the error instead of proceeding with SSL operations when
reset fails.

@cppalliance-bot
Copy link

cppalliance-bot commented Feb 8, 2026

An automated preview of the documentation is available at https://108.corosio.prtest3.cppalliance.org/index.html

If more commits are pushed to the pull request, the docs will rebuild at the same URL.

2026-02-09 00:08:13 UTC

@cppalliance-bot
Copy link

cppalliance-bot commented Feb 8, 2026

GCOVR code coverage report https://108.corosio.prtest3.cppalliance.org/gcovr/index.html
LCOV code coverage report https://108.corosio.prtest3.cppalliance.org/genhtml/index.html
Coverage Diff Report https://108.corosio.prtest3.cppalliance.org/diff-report/index.html

Build time: 2026-02-09 00:11:55 UTC

@sgerbino sgerbino closed this Feb 9, 2026
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.

3 participants