16 : _id(CppCommon::UUID::Sequential()),
18 _io_service(server->service()->GetAsioService()),
19 _strand(*_io_service),
20 _strand_required(_server->_strand_required),
21 _stream(*_io_service, *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);
60 void 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));
87 auto connected_session(this->shared_from_this());
88 _server->onConnected(connected_session);
91 auto self(this->shared_from_this());
92 auto async_handshake_handler = [
this,
self](std::error_code ec)
109 auto handshaked_session(this->shared_from_this());
110 _server->onHandshaked(handshaked_session);
113 if (_send_buffer_main.empty())
123 if (_strand_required)
124 _stream.async_handshake(asio::ssl::stream_base::server, bind_executor(_strand, async_handshake_handler));
126 _stream.async_handshake(asio::ssl::stream_base::server, async_handshake_handler);
154 auto disconnected_session(this->shared_from_this());
155 _server->onDisconnected(disconnected_session);
158 auto self(this->shared_from_this());
159 auto unregister_session_handler = [
this,
self]()
161 _server->UnregisterSession(
id());
163 if (_server->_strand_required)
164 _server->_strand.dispatch(unregister_session_handler);
166 _server->_io_service->dispatch(unregister_session_handler);
169 bool SSLSession::DisconnectAsync(
bool dispatch)
175 auto self(this->shared_from_this());
176 auto disconnect_handler = [
this,
self]()
187 auto async_shutdown_handler = [
this,
self](std::error_code ec2) {
Disconnect(ec2); };
188 if (_strand_required)
189 _stream.async_shutdown(bind_executor(_strand, async_shutdown_handler));
191 _stream.async_shutdown(async_shutdown_handler);
193 if (_strand_required)
196 _strand.dispatch(disconnect_handler);
198 _strand.post(disconnect_handler);
203 _io_service->dispatch(disconnect_handler);
205 _io_service->post(disconnect_handler);
219 assert((buffer !=
nullptr) &&
"Pointer to the buffer should not be null!");
220 if (buffer ==
nullptr)
226 size_t sent = asio::write(_stream, asio::buffer(buffer, size), ec);
231 _server->_bytes_sent += sent;
247 size_t SSLSession::Send(
const void* buffer,
size_t size,
const CppCommon::Timespan& timeout)
255 assert((buffer !=
nullptr) &&
"Pointer to the buffer should not be null!");
256 if (buffer ==
nullptr)
261 std::condition_variable cv;
262 asio::error_code error;
263 asio::system_timer timer(_stream.get_executor());
266 auto async_done_handler = [&](asio::error_code ec)
268 std::unique_lock<std::mutex> lck(mtx);
279 timer.expires_from_now(timeout.chrono());
280 timer.async_wait([&](
const asio::error_code& ec) { async_done_handler(ec ? ec : asio::error::timed_out); });
284 _stream.async_write_some(asio::buffer(buffer, size), [&](std::error_code ec,
size_t write) { async_done_handler(ec); sent = write; });
287 std::unique_lock<std::mutex> lck(mtx);
288 cv.wait(lck, [&]() {
return done == 2; });
295 _server->_bytes_sent += sent;
302 if (error && (error != asio::error::timed_out))
319 assert((buffer !=
nullptr) &&
"Pointer to the buffer should not be null!");
320 if (buffer ==
nullptr)
324 std::scoped_lock locker(_send_lock);
327 bool send_required = _send_buffer_main.empty() || _send_buffer_flush.empty();
330 if (((_send_buffer_main.size() + size) > _send_buffer_limit) && (_send_buffer_limit > 0))
332 SendError(asio::error::no_buffer_space);
337 const uint8_t* bytes = (
const uint8_t*)buffer;
338 _send_buffer_main.insert(_send_buffer_main.end(), bytes, bytes + size);
341 _bytes_pending = _send_buffer_main.size();
349 auto self(this->shared_from_this());
350 auto send_handler = [
this,
self]()
355 if (_strand_required)
356 _strand.dispatch(send_handler);
358 _io_service->dispatch(send_handler);
371 assert((buffer !=
nullptr) &&
"Pointer to the buffer should not be null!");
372 if (buffer ==
nullptr)
378 size_t received = _stream.read_some(asio::buffer(buffer, size), ec);
382 _bytes_received += received;
383 _server->_bytes_received += received;
401 std::string text(size, 0);
402 text.resize(
Receive(text.data(), text.size()));
414 assert((buffer !=
nullptr) &&
"Pointer to the buffer should not be null!");
415 if (buffer ==
nullptr)
420 std::condition_variable cv;
421 asio::error_code error;
422 asio::system_timer timer(_stream.get_executor());
425 auto async_done_handler = [&](asio::error_code ec)
427 std::unique_lock<std::mutex> lck(mtx);
438 timer.expires_from_now(timeout.chrono());
439 timer.async_wait([&](
const asio::error_code& ec) { async_done_handler(ec ? ec : asio::error::timed_out); });
443 _stream.async_read_some(asio::buffer(buffer, size), [&](std::error_code ec,
size_t read) { async_done_handler(ec); received = read; });
446 std::unique_lock<std::mutex> lck(mtx);
447 cv.wait(lck, [&]() {
return done == 2; });
453 _bytes_received += received;
454 _server->_bytes_received += received;
461 if (error && (error != asio::error::timed_out))
472 std::string text(size, 0);
473 text.resize(
Receive(text.data(), text.size(), timeout));
483 void SSLSession::TryReceive()
493 auto self(this->shared_from_this());
494 auto async_receive_handler =
make_alloc_handler(_receive_storage, [
this,
self](std::error_code ec,
size_t size)
505 _bytes_received += size;
506 _server->_bytes_received += size;
512 if (_receive_buffer.size() == size)
515 if (((2 * size) > _receive_buffer_limit) && (_receive_buffer_limit > 0))
517 SendError(asio::error::no_buffer_space);
522 _receive_buffer.resize(2 * size);
535 if (_strand_required)
536 _stream.async_read_some(asio::buffer(_receive_buffer.data(), _receive_buffer.size()), bind_executor(_strand, async_receive_handler));
538 _stream.async_read_some(asio::buffer(_receive_buffer.data(), _receive_buffer.size()), async_receive_handler);
541 void SSLSession::TrySend()
550 if (_send_buffer_flush.empty())
552 std::scoped_lock locker(_send_lock);
555 _send_buffer_flush.swap(_send_buffer_main);
556 _send_buffer_flush_offset = 0;
560 _bytes_sending += _send_buffer_flush.size();
564 if (_send_buffer_flush.empty())
573 auto self(this->shared_from_this());
574 auto async_write_handler =
make_alloc_handler(_send_storage, [
this,
self](std::error_code ec,
size_t size)
585 _bytes_sending -= size;
587 _server->_bytes_sent += size;
590 _send_buffer_flush_offset += size;
593 if (_send_buffer_flush_offset == _send_buffer_flush.size())
596 _send_buffer_flush.clear();
597 _send_buffer_flush_offset = 0;
613 if (_strand_required)
614 _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));
616 _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);
619 void SSLSession::ClearBuffers()
622 std::scoped_lock locker(_send_lock);
625 _send_buffer_main.clear();
626 _send_buffer_flush.clear();
627 _send_buffer_flush_offset = 0;
635 void SSLSession::ResetServer()
641 void SSLSession::SendError(std::error_code ec)
644 if ((ec == asio::error::connection_aborted) ||
645 (ec == asio::error::connection_refused) ||
646 (ec == asio::error::connection_reset) ||
647 (ec == asio::error::eof) ||
648 (ec == asio::error::operation_aborted))
652 if (ec == asio::ssl::error::stream_truncated)
654 if (ec.category() == asio::error::get_ssl_category())
656 if ((ERR_GET_REASON(ec.value()) == SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC) ||
657 (ERR_GET_REASON(ec.value()) == SSL_R_PROTOCOL_IS_SHUTDOWN) ||
658 (ERR_GET_REASON(ec.value()) == SSL_R_WRONG_VERSION_NUMBER))
662 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)
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 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.
asio::ssl::stream< asio::ip::tcp::socket >::next_layer_type & socket() noexcept
Get the session socket.
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.