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()),
30 _send_buffer_flush_offset(0)
36 asio::socket_base::receive_buffer_size option;
37 _stream.next_layer().get_option(option);
38 return option.value();
43 asio::socket_base::send_buffer_size option;
44 _stream.next_layer().get_option(option);
45 return option.value();
50 asio::socket_base::receive_buffer_size option((
int)size);
51 socket().set_option(option);
56 asio::socket_base::send_buffer_size option((
int)size);
57 socket().set_option(option);
60void SSLSession::Connect()
63 if (_server->option_keep_alive())
64 socket().set_option(asio::ip::tcp::socket::keep_alive(
true));
66 if (_server->option_no_delay())
67 socket().set_option(asio::ip::tcp::no_delay(
true));
90 auto connected_session(this->shared_from_this());
91 _server->onConnected(connected_session);
97 auto self(this->shared_from_this());
98 auto async_handshake_handler = [
this, self](std::error_code ec)
115 auto handshaked_session(this->shared_from_this());
116 _server->onHandshaked(handshaked_session);
119 if (_send_buffer_main.empty())
129 if (_strand_required)
130 _stream.async_handshake(asio::ssl::stream_base::server, bind_executor(_strand, async_handshake_handler));
132 _stream.async_handshake(asio::ssl::stream_base::server, async_handshake_handler);
163 auto disconnected_session(this->shared_from_this());
164 _server->onDisconnected(disconnected_session);
167 auto self(this->shared_from_this());
168 auto unregister_session_handler = [
this, self]()
170 _server->UnregisterSession(
id());
172 if (_server->_strand_required)
173 asio::dispatch(_server->_strand, unregister_session_handler);
175 asio::dispatch(*_server->_io_context, unregister_session_handler);
178bool SSLSession::DisconnectAsync(
bool dispatch)
184 auto self(this->shared_from_this());
185 auto disconnect_handler = [
this, self]()
196 auto async_shutdown_handler = [
this, self](std::error_code ec2) {
Disconnect(ec2); };
197 if (_strand_required)
198 _stream.async_shutdown(bind_executor(_strand, async_shutdown_handler));
200 _stream.async_shutdown(async_shutdown_handler);
202 if (_strand_required)
205 asio::dispatch(_strand, disconnect_handler);
207 asio::post(_strand, disconnect_handler);
212 asio::dispatch(*_io_context, disconnect_handler);
214 asio::post(*_io_context, disconnect_handler);
228 assert((buffer !=
nullptr) &&
"Pointer to the buffer should not be null!");
229 if (buffer ==
nullptr)
235 size_t sent = asio::write(_stream, asio::buffer(buffer, size), ec);
240 _server->_bytes_sent += sent;
256size_t SSLSession::Send(
const void* buffer,
size_t size,
const CppCommon::Timespan& timeout)
264 assert((buffer !=
nullptr) &&
"Pointer to the buffer should not be null!");
265 if (buffer ==
nullptr)
270 std::condition_variable cv;
271 asio::error_code error;
272 asio::system_timer timer(_stream.get_executor());
275 auto async_done_handler = [&](asio::error_code ec)
277 std::unique_lock<std::mutex> lck(mtx);
288 timer.expires_after(timeout.chrono());
289 timer.async_wait([&](
const asio::error_code& ec) { async_done_handler(ec ? ec : asio::error::timed_out); });
293 _stream.async_write_some(asio::buffer(buffer, size), [&](std::error_code ec,
size_t write) { async_done_handler(ec); sent = write; });
296 std::unique_lock<std::mutex> lck(mtx);
297 cv.wait(lck, [&]() {
return done == 2; });
304 _server->_bytes_sent += sent;
311 if (error && (error != asio::error::timed_out))
328 assert((buffer !=
nullptr) &&
"Pointer to the buffer should not be null!");
329 if (buffer ==
nullptr)
333 std::scoped_lock locker(_send_lock);
336 bool send_required = _send_buffer_main.empty() || _send_buffer_flush.empty();
339 if (((_send_buffer_main.size() + size) > _send_buffer_limit) && (_send_buffer_limit > 0))
341 SendError(asio::error::no_buffer_space);
346 const uint8_t* bytes = (
const uint8_t*)buffer;
347 _send_buffer_main.insert(_send_buffer_main.end(), bytes, bytes + size);
350 _bytes_pending = _send_buffer_main.size();
358 auto self(this->shared_from_this());
359 auto send_handler = [
this, self]()
364 if (_strand_required)
365 asio::dispatch(_strand, send_handler);
367 asio::dispatch(*_io_context, send_handler);
380 assert((buffer !=
nullptr) &&
"Pointer to the buffer should not be null!");
381 if (buffer ==
nullptr)
387 size_t received = _stream.read_some(asio::buffer(buffer, size), ec);
391 _bytes_received += received;
392 _server->_bytes_received += received;
410 std::string text(size, 0);
411 text.resize(
Receive(text.data(), text.size()));
423 assert((buffer !=
nullptr) &&
"Pointer to the buffer should not be null!");
424 if (buffer ==
nullptr)
429 std::condition_variable cv;
430 asio::error_code error;
431 asio::system_timer timer(_stream.get_executor());
434 auto async_done_handler = [&](asio::error_code ec)
436 std::unique_lock<std::mutex> lck(mtx);
447 timer.expires_after(timeout.chrono());
448 timer.async_wait([&](
const asio::error_code& ec) { async_done_handler(ec ? ec : asio::error::timed_out); });
452 _stream.async_read_some(asio::buffer(buffer, size), [&](std::error_code ec,
size_t read) { async_done_handler(ec); received = read; });
455 std::unique_lock<std::mutex> lck(mtx);
456 cv.wait(lck, [&]() {
return done == 2; });
462 _bytes_received += received;
463 _server->_bytes_received += received;
470 if (error && (error != asio::error::timed_out))
481 std::string text(size, 0);
482 text.resize(
Receive(text.data(), text.size(), timeout));
492void SSLSession::TryReceive()
502 auto self(this->shared_from_this());
503 auto async_receive_handler =
make_alloc_handler(_receive_storage, [
this, self](std::error_code ec,
size_t size)
514 _bytes_received += size;
515 _server->_bytes_received += size;
521 if (_receive_buffer.size() == size)
524 if (((2 * size) > _receive_buffer_limit) && (_receive_buffer_limit > 0))
526 SendError(asio::error::no_buffer_space);
531 _receive_buffer.resize(2 * size);
544 if (_strand_required)
545 _stream.async_read_some(asio::buffer(_receive_buffer.data(), _receive_buffer.size()), bind_executor(_strand, async_receive_handler));
547 _stream.async_read_some(asio::buffer(_receive_buffer.data(), _receive_buffer.size()), async_receive_handler);
550void SSLSession::TrySend()
559 if (_send_buffer_flush.empty())
561 std::scoped_lock locker(_send_lock);
564 _send_buffer_flush.swap(_send_buffer_main);
565 _send_buffer_flush_offset = 0;
569 _bytes_sending += _send_buffer_flush.size();
573 if (_send_buffer_flush.empty())
582 auto self(this->shared_from_this());
583 auto async_write_handler =
make_alloc_handler(_send_storage, [
this, self](std::error_code ec,
size_t size)
594 _bytes_sending -= size;
596 _server->_bytes_sent += size;
599 _send_buffer_flush_offset += size;
602 if (_send_buffer_flush_offset == _send_buffer_flush.size())
605 _send_buffer_flush.clear();
606 _send_buffer_flush_offset = 0;
622 if (_strand_required)
623 _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));
625 _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);
628void SSLSession::ClearBuffers()
631 std::scoped_lock locker(_send_lock);
634 _send_buffer_main.clear();
635 _send_buffer_flush.clear();
636 _send_buffer_flush_offset = 0;
644void SSLSession::ResetServer()
650void SSLSession::SendError(std::error_code ec)
653 if ((ec == asio::error::connection_aborted) ||
654 (ec == asio::error::connection_refused) ||
655 (ec == asio::error::connection_reset) ||
656 (ec == asio::error::eof) ||
657 (ec == asio::error::operation_aborted))
661 if (ec == asio::ssl::error::stream_truncated)
663 if (ec.category() == asio::error::get_ssl_category())
665 if ((ERR_GET_REASON(ec.value()) == SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC) ||
666 (ERR_GET_REASON(ec.value()) == SSL_R_PROTOCOL_IS_SHUTDOWN) ||
667 (ERR_GET_REASON(ec.value()) == SSL_R_WRONG_VERSION_NUMBER))
671 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.
C++ Server project definitions.