Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
kcenon::network::internal::secure_tcp_socket Class Reference

A lightweight wrapper around asio::ssl::stream<asio::ip::tcp::socket>, enabling asynchronous TLS/SSL encrypted read and write operations. More...

#include <secure_tcp_socket.h>

Inheritance diagram for kcenon::network::internal::secure_tcp_socket:
Inheritance graph
Collaboration diagram for kcenon::network::internal::secure_tcp_socket:
Collaboration graph

Public Types

using ssl_socket = asio::ssl::stream<asio::ip::tcp::socket>
 

Public Member Functions

 secure_tcp_socket (asio::ip::tcp::socket socket, asio::ssl::context &ssl_context)
 Constructs a secure_tcp_socket by taking ownership of a moved socket and SSL context.
 
 ~secure_tcp_socket ()=default
 Default destructor (no special cleanup needed).
 
auto async_handshake (asio::ssl::stream_base::handshake_type type, std::function< void(std::error_code)> handler) -> void
 Performs asynchronous SSL handshake.
 
auto set_receive_callback (std::function< void(const std::vector< uint8_t > &)> callback) -> void
 Sets a callback to receive inbound data chunks.
 
auto set_receive_callback_view (std::function< void(std::span< const uint8_t >)> callback) -> void
 Sets a zero-copy callback to receive inbound data as a view.
 
auto set_error_callback (std::function< void(std::error_code)> callback) -> void
 Sets a callback to handle socket errors (e.g., read/write failures).
 
auto start_read () -> void
 Begins the continuous asynchronous read loop.
 
auto async_send (std::vector< uint8_t > &&data, std::function< void(std::error_code, std::size_t)> handler) -> void
 Initiates an asynchronous write of the given data buffer with encryption.
 
auto stream () -> ssl_socket &
 Provides direct access to the underlying SSL stream.
 
auto socket () -> ssl_socket::lowest_layer_type &
 Provides access to the underlying TCP socket.
 
auto stop_read () -> void
 Stops the read loop to prevent further async operations.
 
auto close () -> void
 Safely closes the socket and stops all async operations.
 
auto is_closed () const -> bool
 Checks if the socket has been closed.
 

Private Types

using receive_callback_t = std::function<void(const std::vector<uint8_t>&)>
 Callback type aliases for lock-free storage.
 
using receive_callback_view_t = std::function<void(std::span<const uint8_t>)>
 
using error_callback_t = std::function<void(std::error_code)>
 

Private Member Functions

auto do_read () -> void
 Internal function to handle the read logic with async_read_some().
 

Private Attributes

ssl_socket ssl_stream_
 
std::array< uint8_t, 4096 > read_buffer_
 
std::shared_ptr< receive_callback_treceive_callback_
 
std::shared_ptr< receive_callback_view_treceive_callback_view_
 
std::shared_ptr< error_callback_terror_callback_
 
std::mutex callback_mutex_
 
std::atomic< bool > is_reading_ {false}
 
std::atomic< bool > is_closed_ {false}
 

Detailed Description

A lightweight wrapper around asio::ssl::stream<asio::ip::tcp::socket>, enabling asynchronous TLS/SSL encrypted read and write operations.

Key Features

  • Maintains a ssl_stream_ (from ASIO SSL) for secure TCP communication.
  • Performs SSL handshake before data transmission.
  • Exposes set_receive_callback() to handle inbound encrypted data and set_error_callback() for error handling.
  • start_read() begins an ongoing loop of async_read_some().
  • async_send() performs an async_write of a given data buffer with encryption.

Thread Safety

  • All public methods are thread-safe. Callback registration is protected by callback_mutex_.
  • ASIO operations are serialized through the io_context, ensuring read_buffer_ is only accessed by one async operation at a time.
  • The provided callbacks will be invoked on an ASIO worker thread; ensure that your callback logic is thread-safe if it shares data.

Definition at line 46 of file secure_tcp_socket.h.

Member Typedef Documentation

◆ error_callback_t

using kcenon::network::internal::secure_tcp_socket::error_callback_t = std::function<void(std::error_code)>
private

Definition at line 217 of file secure_tcp_socket.h.

◆ receive_callback_t

using kcenon::network::internal::secure_tcp_socket::receive_callback_t = std::function<void(const std::vector<uint8_t>&)>
private

Callback type aliases for lock-free storage.

Definition at line 215 of file secure_tcp_socket.h.

◆ receive_callback_view_t

using kcenon::network::internal::secure_tcp_socket::receive_callback_view_t = std::function<void(std::span<const uint8_t>)>
private

Definition at line 216 of file secure_tcp_socket.h.

◆ ssl_socket

using kcenon::network::internal::secure_tcp_socket::ssl_socket = asio::ssl::stream<asio::ip::tcp::socket>

Definition at line 49 of file secure_tcp_socket.h.

Constructor & Destructor Documentation

◆ secure_tcp_socket()

kcenon::network::internal::secure_tcp_socket::secure_tcp_socket ( asio::ip::tcp::socket socket,
asio::ssl::context & ssl_context )

Constructs a secure_tcp_socket by taking ownership of a moved socket and SSL context.

Parameters
socketAn asio::ip::tcp::socket that must be open/connected or at least valid.
ssl_contextSSL context for encryption settings

After construction, you must call async_handshake() before using the socket for data transmission.

Definition at line 14 of file secure_tcp_socket.cpp.

16 : ssl_stream_(std::move(socket), ssl_context)
17 {
18 }
auto socket() -> ssl_socket::lowest_layer_type &
Provides access to the underlying TCP socket.

◆ ~secure_tcp_socket()

kcenon::network::internal::secure_tcp_socket::~secure_tcp_socket ( )
default

Default destructor (no special cleanup needed).

Member Function Documentation

◆ async_handshake()

auto kcenon::network::internal::secure_tcp_socket::async_handshake ( asio::ssl::stream_base::handshake_type type,
std::function< void(std::error_code)> handler ) -> void

Performs asynchronous SSL handshake.

Parameters
typeHandshake type (client or server)
handlerCompletion handler with signature void(std::error_code)

Must be called before start_read() or async_send().

Definition at line 20 of file secure_tcp_socket.cpp.

23 {
24 auto self = shared_from_this();
25 ssl_stream_.async_handshake(
26 type,
27 [handler = std::move(handler), self](std::error_code ec)
28 {
29 if constexpr (std::is_invocable_v<decltype(handler), std::error_code>)
30 {
31 if (handler)
32 {
33 handler(ec);
34 }
35 }
36 });
37 }

◆ async_send()

auto kcenon::network::internal::secure_tcp_socket::async_send ( std::vector< uint8_t > && data,
std::function< void(std::error_code, std::size_t)> handler ) -> void

Initiates an asynchronous write of the given data buffer with encryption.

Parameters
dataThe buffer to send over TLS (moved for efficiency).
handlerA completion handler with signature void(std::error_code, std::size_t) that is invoked upon success or failure.

The handler receives:

  • ec : the std::error_code from the write operation,
  • bytes_transferred : how many bytes were actually written.
Note
Data is moved (not copied) to avoid memory allocation overhead.
The original vector will be empty after this call.

Definition at line 169 of file secure_tcp_socket.cpp.

172 {
173 // Check if socket has been closed before starting async operation
174 // Use atomic is_closed_ flag to prevent data race with close()
175 if (is_closed_.load())
176 {
177 if (handler)
178 {
179 handler(asio::error::not_connected, 0);
180 }
181 return;
182 }
183
184 auto self = shared_from_this();
185 // Move data into shared_ptr for lifetime management
186 auto buffer = std::make_shared<std::vector<uint8_t>>(std::move(data));
187 asio::async_write(
188 ssl_stream_, asio::buffer(*buffer),
189 [handler = std::move(handler), self, buffer](std::error_code ec, std::size_t bytes_transferred)
190 {
191 if constexpr (std::is_invocable_v<decltype(handler), std::error_code, std::size_t>)
192 {
193 if (handler)
194 {
195 handler(ec, bytes_transferred);
196 }
197 }
198 });
199 }

◆ close()

auto kcenon::network::internal::secure_tcp_socket::close ( ) -> void

Safely closes the socket and stops all async operations.

This method atomically sets the closed flag before closing the socket, preventing data races between the close operation and async read operations. Thread-safe with respect to concurrent async operations.

Definition at line 76 of file secure_tcp_socket.cpp.

77 {
78 // Atomically mark socket as closed before actual close
79 // This prevents data races with concurrent async operations
80 is_closed_.store(true);
81 is_reading_.store(false);
82
83 std::error_code ec;
84 ssl_stream_.lowest_layer().close(ec);
85 // Ignore close errors - socket may already be closed
86 }

◆ do_read()

auto kcenon::network::internal::secure_tcp_socket::do_read ( ) -> void
private

Internal function to handle the read logic with async_read_some().

Upon success, it calls receive_callback_ if set, then schedules another read. On error, it calls error_callback_ if available.

Definition at line 93 of file secure_tcp_socket.cpp.

94 {
95 // Check if reading has been stopped before initiating new async operation
96 if (!is_reading_.load())
97 {
98 return;
99 }
100
101 // Check if socket has been closed or is no longer open before starting async operation
102 // This prevents data races and UBSAN errors from accessing null descriptor_state
103 // Both checks are needed: is_closed_ for explicit close() calls, is_open() for ASIO state
104 if (is_closed_.load() || !ssl_stream_.lowest_layer().is_open())
105 {
106 is_reading_.store(false);
107 return;
108 }
109
110 auto self = shared_from_this();
111 ssl_stream_.async_read_some(
112 asio::buffer(read_buffer_),
113 [this, self](std::error_code ec, std::size_t length)
114 {
115 // Check if reading has been stopped or socket closed at callback time
116 // This prevents accessing invalid socket state after close()
117 if (!is_reading_.load() || is_closed_.load())
118 {
119 return;
120 }
121
122 if (ec)
123 {
124 // On error, invoke the error callback
125 // Lock-free callback access via atomic_load
126 auto error_cb = std::atomic_load(&error_callback_);
127 if (error_cb && *error_cb)
128 {
129 (*error_cb)(ec);
130 }
131 return;
132 }
133
134 // On success, if length > 0, dispatch to the appropriate callback
135 if (length > 0)
136 {
137 // Lock-free callback access via atomic_load
138 // Prefer view callback (zero-copy) over vector callback
139 auto view_cb = std::atomic_load(&receive_callback_view_);
140 if (view_cb && *view_cb)
141 {
142 // Zero-copy path: create span view directly into read_buffer_
143 // No std::vector allocation or copy required
144 std::span<const uint8_t> data_view(read_buffer_.data(), length);
145 (*view_cb)(data_view);
146 }
147 else
148 {
149 // Legacy path: allocate and copy into vector for compatibility
150 auto recv_cb = std::atomic_load(&receive_callback_);
151 if (recv_cb && *recv_cb)
152 {
153 std::vector<uint8_t> chunk(read_buffer_.begin(),
154 read_buffer_.begin() + length);
155 (*recv_cb)(chunk);
156 }
157 }
158 }
159
160 // Continue reading only if still active and socket is not closed
161 // Use atomic is_closed_ flag to prevent data race with close()
162 if (is_reading_.load() && !is_closed_.load())
163 {
164 do_read();
165 }
166 });
167 }
std::shared_ptr< receive_callback_view_t > receive_callback_view_
std::shared_ptr< error_callback_t > error_callback_
auto do_read() -> void
Internal function to handle the read logic with async_read_some().
std::shared_ptr< receive_callback_t > receive_callback_

◆ is_closed()

auto kcenon::network::internal::secure_tcp_socket::is_closed ( ) const -> bool
nodiscard

Checks if the socket has been closed.

Returns
true if close() has been called on this socket.

Definition at line 88 of file secure_tcp_socket.cpp.

89 {
90 return is_closed_.load();
91 }

References is_closed_.

◆ set_error_callback()

auto kcenon::network::internal::secure_tcp_socket::set_error_callback ( std::function< void(std::error_code)> callback) -> void

Sets a callback to handle socket errors (e.g., read/write failures).

Parameters
callbackA function with signature void(std::error_code), invoked when any asynchronous operation fails.

If no callback is set, errors are not explicitly handled here (beyond stopping reads).

Definition at line 55 of file secure_tcp_socket.cpp.

57 {
58 auto new_cb = std::make_shared<error_callback_t>(std::move(callback));
59 std::lock_guard<std::mutex> lock(callback_mutex_);
60 std::atomic_store(&error_callback_, new_cb);
61 }

◆ set_receive_callback()

auto kcenon::network::internal::secure_tcp_socket::set_receive_callback ( std::function< void(const std::vector< uint8_t > &)> callback) -> void

Sets a callback to receive inbound data chunks.

Parameters
callbackA function with signature void(const std::vector<uint8_t>&), called whenever a chunk of data is successfully read and decrypted.

If no callback is set, received data is effectively discarded.

Note
This is the legacy callback API. For better performance, consider using set_receive_callback_view() instead.

Definition at line 39 of file secure_tcp_socket.cpp.

41 {
42 auto new_cb = std::make_shared<receive_callback_t>(std::move(callback));
43 std::lock_guard<std::mutex> lock(callback_mutex_);
44 std::atomic_store(&receive_callback_, new_cb);
45 }

◆ set_receive_callback_view()

auto kcenon::network::internal::secure_tcp_socket::set_receive_callback_view ( std::function< void(std::span< const uint8_t >)> callback) -> void

Sets a zero-copy callback to receive inbound data as a view.

Parameters
callbackA function with signature void(std::span<const uint8_t>), called whenever a chunk of data is successfully read and decrypted.

Zero-Copy Performance

Unlike set_receive_callback(), this callback receives data as a non-owning view directly into the internal read buffer, avoiding per-read std::vector allocations and copies.

Lifetime Contract

  • The span is valid only until the callback returns.
  • Callers must not store, capture, or use the span after returning from the callback.
  • If data must be retained, copy it into your own container within the callback.

Dispatch Priority

  • If both view and vector callbacks are set, the view callback takes priority and the vector callback is not invoked.

Example

sock->set_receive_callback_view([](std::span<const uint8_t> data) {
// Process data directly (zero-copy)
process_bytes(data.data(), data.size());
// If you need to keep the data:
// my_buffer.insert(my_buffer.end(), data.begin(), data.end());
});

Definition at line 47 of file secure_tcp_socket.cpp.

49 {
50 auto new_cb = std::make_shared<receive_callback_view_t>(std::move(callback));
51 std::lock_guard<std::mutex> lock(callback_mutex_);
52 std::atomic_store(&receive_callback_view_, new_cb);
53 }

◆ socket()

auto kcenon::network::internal::secure_tcp_socket::socket ( ) -> ssl_socket::lowest_layer_type&
inline

Provides access to the underlying TCP socket.

Returns
A reference to the lowest layer socket.

Definition at line 178 of file secure_tcp_socket.h.

179 {
180 return ssl_stream_.lowest_layer();
181 }

References ssl_stream_.

◆ start_read()

auto kcenon::network::internal::secure_tcp_socket::start_read ( ) -> void

Begins the continuous asynchronous read loop.

Once called, the class repeatedly calls async_read_some(). If an error occurs, on_error() is triggered, stopping further reads.

Definition at line 63 of file secure_tcp_socket.cpp.

64 {
65 // Set reading flag and kick off the initial read loop
66 is_reading_.store(true);
67 do_read();
68 }

◆ stop_read()

auto kcenon::network::internal::secure_tcp_socket::stop_read ( ) -> void

Stops the read loop to prevent further async operations.

Definition at line 70 of file secure_tcp_socket.cpp.

71 {
72 // Stop further read operations
73 is_reading_.store(false);
74 }

◆ stream()

auto kcenon::network::internal::secure_tcp_socket::stream ( ) -> ssl_socket&
inline

Provides direct access to the underlying SSL stream.

Returns
A reference to the wrapped asio::ssl::stream.

Definition at line 172 of file secure_tcp_socket.h.

172{ return ssl_stream_; }

References ssl_stream_.

Member Data Documentation

◆ callback_mutex_

std::mutex kcenon::network::internal::secure_tcp_socket::callback_mutex_
private

Protects callback registration only.

Definition at line 232 of file secure_tcp_socket.h.

◆ error_callback_

std::shared_ptr<error_callback_t> kcenon::network::internal::secure_tcp_socket::error_callback_
private

Definition at line 230 of file secure_tcp_socket.h.

◆ is_closed_

std::atomic<bool> kcenon::network::internal::secure_tcp_socket::is_closed_ {false}
private

Flag to indicate socket is closed.

Definition at line 235 of file secure_tcp_socket.h.

235{false};

Referenced by is_closed().

◆ is_reading_

std::atomic<bool> kcenon::network::internal::secure_tcp_socket::is_reading_ {false}
private

Flag to prevent read after stop.

Definition at line 234 of file secure_tcp_socket.h.

234{false};

◆ read_buffer_

std::array<uint8_t, 4096> kcenon::network::internal::secure_tcp_socket::read_buffer_
private

Buffer for receiving data in do_read().

Definition at line 222 of file secure_tcp_socket.h.

◆ receive_callback_

std::shared_ptr<receive_callback_t> kcenon::network::internal::secure_tcp_socket::receive_callback_
private

Lock-free callback storage using shared_ptr + atomic operations. This eliminates mutex contention on the receive hot path.

Definition at line 228 of file secure_tcp_socket.h.

◆ receive_callback_view_

std::shared_ptr<receive_callback_view_t> kcenon::network::internal::secure_tcp_socket::receive_callback_view_
private

Definition at line 229 of file secure_tcp_socket.h.

◆ ssl_stream_

ssl_socket kcenon::network::internal::secure_tcp_socket::ssl_stream_
private

The underlying ASIO SSL stream.

Definition at line 219 of file secure_tcp_socket.h.

Referenced by socket(), and stream().


The documentation for this class was generated from the following files: