16 : _id(CppCommon::UUID::Sequential()),
18 _io_context(
server->service()->GetAsioContext()),
19 _strand(*_io_context),
20 _strand_required(_server->_strand_required),
21 _stream(*_io_context, *
server->context()),
31 _send_buffer_flush_offset(0)
37 asio::socket_base::receive_buffer_size option;
38 _stream.next_layer().get_option(option);
39 return option.value();
44 asio::socket_base::send_buffer_size option;
45 _stream.next_layer().get_option(option);
46 return option.value();
51 asio::socket_base::receive_buffer_size option((
int)size);
52 socket().set_option(option);
57 asio::socket_base::send_buffer_size option((
int)size);
58 socket().set_option(option);
61void SSLSession::Connect()
64 if (_server->option_keep_alive())
65 socket().set_option(asio::ip::tcp::socket::keep_alive(
true));
67 if (_server->option_no_delay())
68 socket().set_option(asio::ip::tcp::no_delay(
true));
91 auto connected_session(this->shared_from_this());
92 _server->onConnected(connected_session);
98 auto self(this->shared_from_this());
99 auto async_handshake_handler = [
this, self](std::error_code ec)
116 auto handshaked_session(this->shared_from_this());
117 _server->onHandshaked(handshaked_session);
120 if (_send_buffer_main.empty())
130 if (_strand_required)
131 _stream.async_handshake(asio::ssl::stream_base::server, bind_executor(_strand, async_handshake_handler));
133 _stream.async_handshake(asio::ssl::stream_base::server, async_handshake_handler);
165 auto disconnected_session(this->shared_from_this());
166 _server->onDisconnected(disconnected_session);
169 auto self(this->shared_from_this());
170 auto unregister_session_handler = [
this, self]()
172 _server->UnregisterSession(
id());
174 if (_server->_strand_required)
175 asio::dispatch(_server->_strand, unregister_session_handler);
177 asio::dispatch(*_server->_io_context, unregister_session_handler);
180bool SSLSession::DisconnectAsync(
bool dispatch)
186 auto self(this->shared_from_this());
187 auto disconnect_handler = [
this, self]()
200 auto async_shutdown_handler = [
this, self](std::error_code ec2)
206 if (_strand_required)
207 _stream.async_shutdown(bind_executor(_strand, async_shutdown_handler));
209 _stream.async_shutdown(async_shutdown_handler);
211 if (_strand_required)
214 asio::dispatch(_strand, disconnect_handler);
216 asio::post(_strand, disconnect_handler);
221 asio::dispatch(*_io_context, disconnect_handler);
223 asio::post(*_io_context, disconnect_handler);
237 assert((buffer !=
nullptr) &&
"Pointer to the buffer should not be null!");
238 if (buffer ==
nullptr)
244 size_t sent = asio::write(_stream, asio::buffer(buffer, size), ec);
249 _server->_bytes_sent += sent;
265size_t SSLSession::Send(
const void* buffer,
size_t size,
const CppCommon::Timespan& timeout)
273 assert((buffer !=
nullptr) &&
"Pointer to the buffer should not be null!");
274 if (buffer ==
nullptr)
279 std::condition_variable cv;
280 asio::error_code error;
281 asio::system_timer timer(_stream.get_executor());
284 auto async_done_handler = [&](asio::error_code ec)
286 std::unique_lock<std::mutex> lck(mtx);
297 timer.expires_after(timeout.chrono());
298 timer.async_wait([&](
const asio::error_code& ec) { async_done_handler(ec ? ec : asio::error::timed_out); });
302 _stream.async_write_some(asio::buffer(buffer, size), [&](std::error_code ec,
size_t write) { async_done_handler(ec); sent = write; });
305 std::unique_lock<std::mutex> lck(mtx);
306 cv.wait(lck, [&]() {
return done == 2; });
313 _server->_bytes_sent += sent;
320 if (error && (error != asio::error::timed_out))
337 assert((buffer !=
nullptr) &&
"Pointer to the buffer should not be null!");
338 if (buffer ==
nullptr)
342 std::scoped_lock locker(_send_lock);
345 bool send_required = _send_buffer_main.empty() || _send_buffer_flush.empty();
348 if (((_send_buffer_main.size() + size) > _send_buffer_limit) && (_send_buffer_limit > 0))
350 SendError(asio::error::no_buffer_space);
355 const uint8_t* bytes = (
const uint8_t*)buffer;
356 _send_buffer_main.insert(_send_buffer_main.end(), bytes, bytes + size);
359 _bytes_pending = _send_buffer_main.size();
367 auto self(this->shared_from_this());
368 auto send_handler = [
this, self]()
373 if (_strand_required)
374 asio::dispatch(_strand, send_handler);
376 asio::dispatch(*_io_context, send_handler);
389 assert((buffer !=
nullptr) &&
"Pointer to the buffer should not be null!");
390 if (buffer ==
nullptr)
396 size_t received = _stream.read_some(asio::buffer(buffer, size), ec);
400 _bytes_received += received;
401 _server->_bytes_received += received;
419 std::string text(size, 0);
420 text.resize(
Receive(text.data(), text.size()));
432 assert((buffer !=
nullptr) &&
"Pointer to the buffer should not be null!");
433 if (buffer ==
nullptr)
438 std::condition_variable cv;
439 asio::error_code error;
440 asio::system_timer timer(_stream.get_executor());
443 auto async_done_handler = [&](asio::error_code ec)
445 std::unique_lock<std::mutex> lck(mtx);
456 timer.expires_after(timeout.chrono());
457 timer.async_wait([&](
const asio::error_code& ec) { async_done_handler(ec ? ec : asio::error::timed_out); });
461 _stream.async_read_some(asio::buffer(buffer, size), [&](std::error_code ec,
size_t read) { async_done_handler(ec); received = read; });
464 std::unique_lock<std::mutex> lck(mtx);
465 cv.wait(lck, [&]() {
return done == 2; });
471 _bytes_received += received;
472 _server->_bytes_received += received;
479 if (error && (error != asio::error::timed_out))
490 std::string text(size, 0);
491 text.resize(
Receive(text.data(), text.size(), timeout));
501void SSLSession::TryReceive()
511 auto self(this->shared_from_this());
512 auto async_receive_handler =
make_alloc_handler(_receive_storage, [
this, self](std::error_code ec,
size_t size)
523 _bytes_received += size;
524 _server->_bytes_received += size;
530 if (_receive_buffer.size() == size)
533 if (((2 * size) > _receive_buffer_limit) && (_receive_buffer_limit > 0))
535 SendError(asio::error::no_buffer_space);
540 _receive_buffer.resize(2 * size);
553 if (_strand_required)
554 _stream.async_read_some(asio::buffer(_receive_buffer.data(), _receive_buffer.size()), bind_executor(_strand, async_receive_handler));
556 _stream.async_read_some(asio::buffer(_receive_buffer.data(), _receive_buffer.size()), async_receive_handler);
559void SSLSession::TrySend()
568 if (_send_buffer_flush.empty())
570 std::scoped_lock locker(_send_lock);
573 _send_buffer_flush.swap(_send_buffer_main);
574 _send_buffer_flush_offset = 0;
578 _bytes_sending += _send_buffer_flush.size();
582 if (_send_buffer_flush.empty())
591 auto self(this->shared_from_this());
592 auto async_write_handler =
make_alloc_handler(_send_storage, [
this, self](std::error_code ec,
size_t size)
603 _bytes_sending -= size;
605 _server->_bytes_sent += size;
608 _send_buffer_flush_offset += size;
611 if (_send_buffer_flush_offset == _send_buffer_flush.size())
614 _send_buffer_flush.clear();
615 _send_buffer_flush_offset = 0;
631 if (_strand_required)
632 _stream.async_write_some(asio::buffer(_send_buffer_flush.data() + _send_buffer_flush_offset, _send_buffer_flush.size() - _send_buffer_flush_offset), bind_executor(_strand, async_write_handler));
634 _stream.async_write_some(asio::buffer(_send_buffer_flush.data() + _send_buffer_flush_offset, _send_buffer_flush.size() - _send_buffer_flush_offset), async_write_handler);
637void SSLSession::ClearBuffers()
640 std::scoped_lock locker(_send_lock);
643 _send_buffer_main.clear();
644 _send_buffer_flush.clear();
645 _send_buffer_flush_offset = 0;
653void SSLSession::ResetServer()
659void SSLSession::SendError(std::error_code ec)
662 if ((ec == asio::error::connection_aborted) ||
663 (ec == asio::error::connection_refused) ||
664 (ec == asio::error::connection_reset) ||
665 (ec == asio::error::eof) ||
666 (ec == asio::error::operation_aborted))
670 if (ec == asio::ssl::error::stream_truncated)
672 if (ec.category() == asio::error::get_ssl_category())
674 if ((ERR_GET_REASON(ec.value()) == SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC) ||
675 (ERR_GET_REASON(ec.value()) == SSL_R_PROTOCOL_IS_SHUTDOWN) ||
676 (ERR_GET_REASON(ec.value()) == SSL_R_WRONG_VERSION_NUMBER))
680 onError(ec.value(), ec.category().name(), ec.message());
uint64_t bytes_pending() const noexcept
Get the number of bytes pending sent by the session.
virtual void onSent(size_t sent, size_t pending)
Handle buffer sent notification.
virtual bool SendAsync(const void *buffer, size_t size)
Send data to the client (asynchronous).
asio::ssl::stream< asio::ip::tcp::socket >::next_layer_type & socket() noexcept
Get the session socket.
void SetupReceiveBufferSize(size_t size)
Setup option: receive buffer size.
void SetupSendBufferSize(size_t size)
Setup option: send buffer size.
virtual void ReceiveAsync()
Receive data from the client (asynchronous).
virtual void onDisconnecting()
Handle session disconnecting notification.
virtual bool Disconnect()
Disconnect the session.
virtual void onConnected()
Handle session connected notification.
virtual void onReceived(const void *buffer, size_t size)
Handle buffer received notification.
std::shared_ptr< SSLServer > & server() noexcept
Get the server.
virtual void onConnecting()
Handle session connecting notification.
virtual void onHandshaking()
Handle session handshaking notification.
size_t option_send_buffer_size() const
Get the option: send buffer size.
virtual size_t Send(const void *buffer, size_t size)
Send data to the client (synchronous).
SSLSession(const std::shared_ptr< SSLServer > &server)
Initialize the session with a given server.
virtual void onEmpty()
Handle empty send buffer notification.
bool IsConnected() const noexcept
Is the session connected?
virtual void onError(int error, const std::string &category, const std::string &message)
Handle error notification.
bool IsHandshaked() const noexcept
Is the session handshaked?
virtual size_t Receive(void *buffer, size_t size)
Receive data from the client (synchronous).
virtual void onHandshaked()
Handle session handshaked notification.
virtual void onDisconnected()
Handle session disconnected notification.
size_t option_receive_buffer_size() const
Get the option: receive buffer size.
AllocateHandler< THandler > make_alloc_handler(HandlerStorage &storage, THandler handler)
Helper function to wrap a handler object to add custom allocation.
constexpr size_t MIN_RECEIVE_BUFFER_SIZE
Minimal receive buffer size.
constexpr size_t MIN_SEND_BUFFER_SIZE
Minimal send buffer size.
C++ Server project definitions.