39class GNet::SocketProtocolImp
42 using Result = GSsl::Protocol::Result ;
44 using Segments = std::vector<Segment> ;
47 Position() = default ;
48 Position( std::size_t s , std::size_t o ) : segment(s) , offset(o) {}
49 std::size_t segment{0U} ;
50 std::size_t offset{0U} ;
54 SocketProtocolImp( EventHandler & , ExceptionSink , SocketProtocol::Sink & ,
55 StreamSocket & ,
const SocketProtocol::Config & ) ;
56 ~SocketProtocolImp() ;
57 bool readEvent(
bool ) ;
59 void otherEvent( EventHandler::Reason ,
bool ) ;
61 bool send(
const Segments & , std::size_t ) ;
63 void secureConnect() ;
64 bool secureConnectCapable()
const ;
66 bool secureAcceptCapable()
const ;
69 std::string peerCertificate()
const ;
72 SocketProtocolImp(
const SocketProtocolImp & ) = delete ;
73 SocketProtocolImp( SocketProtocolImp && ) = delete ;
74 SocketProtocolImp & operator=(
const SocketProtocolImp & ) = delete ;
75 SocketProtocolImp & operator=( SocketProtocolImp && ) = delete ;
78 enum class State { raw , connecting , accepting , writing , idle , shuttingdown } ;
79 static std::unique_ptr<GSsl::Protocol> newProtocol(
const std::string & ) ;
80 static void log(
int level ,
const std::string & line ) ;
82 bool rawReadEvent(
bool ) ;
83 bool rawWriteEvent() ;
84 bool rawOtherEvent( EventHandler::Reason ) ;
85 bool rawSend(
const Segments & , Position ,
bool =
false ) ;
86 bool rawSendImp(
const Segments & , Position , Position & ) ;
89 bool sslSend(
const Segments & segments , Position pos ) ;
91 bool sslSendImp(
const Segments & segments , Position pos , Position & ) ;
92 void secureConnectImp() ;
93 void secureAcceptImp() ;
95 void logSecure(
const std::string & ,
const std::string & )
const ;
96 void onSecureConnectionTimeout() ;
97 static std::size_t size(
const Segments & ) ;
98 static bool finished(
const Segments & , Position ) ;
99 static Position firstPosition(
const Segments & , std::size_t ) ;
100 static Position newPosition(
const Segments & , Position , std::size_t ) ;
102 friend std::ostream & operator<<( std::ostream & , State ) ;
105 EventHandler & m_handler ;
107 SocketProtocol::Sink & m_sink ;
108 StreamSocket & m_socket ;
110 SocketProtocol::Config m_config ;
111 Segments m_one_segment ;
112 Segments m_segments ;
113 Position m_position ;
114 std::string m_data_copy ;
116 std::unique_ptr<GSsl::Protocol> m_ssl ;
118 std::vector<char> m_read_buffer ;
119 ssize_t m_read_buffer_n ;
120 Timer<SocketProtocolImp> m_secure_connection_timer ;
121 std::string m_peer_certificate ;
126 std::ostream & operator<<( std::ostream & stream , SocketProtocolImp::State state )
128 return stream << static_cast<int>(state) ;
130 std::ostream & operator<<( std::ostream & stream ,
const SocketProtocolImp::Position & pos )
132 return stream <<
"(" << pos.segment <<
"," << pos.offset <<
")" ;
134 std::ostream & operator<<( std::ostream & stream ,
const SocketProtocolImp::Segments & segments )
137 const char * sep =
"" ;
138 for( std::size_t i = 0U ; i < segments.size() ; i++ , sep =
"," )
139 stream << sep <<
"(" <<
static_cast<const void*
>(segments.at(i).data())
140 <<
":" << segments.at(i).size() <<
")" ;
146GNet::SocketProtocolImp::SocketProtocolImp( EventHandler & handler , ExceptionSink es ,
147 SocketProtocol::Sink & sink , StreamSocket & socket ,
const SocketProtocol::Config & config ) :
155 m_state(State::raw) ,
156 m_read_buffer(
std::max(
std::size_t(1U),config.read_buffer_size)) ,
158 m_secure_connection_timer(*this,&SocketProtocolImp::onSecureConnectionTimeout,es)
160 if( m_config.server_tls_profile.empty() ) m_config.server_tls_profile =
"server" ;
161 if( m_config.client_tls_profile.empty() ) m_config.client_tls_profile =
"client" ;
164GNet::SocketProtocolImp::~SocketProtocolImp()
167void GNet::SocketProtocolImp::onSecureConnectionTimeout()
169 G_DEBUG(
"GNet::SocketProtocolImp::onSecureConnectionTimeout: timed out" ) ;
170 throw SocketProtocol::SecureConnectionTimeout() ;
173bool GNet::SocketProtocolImp::readEvent(
bool no_throw_on_peer_disconnect )
175 G_DEBUG(
"SocketProtocolImp::readEvent: read event: " << m_socket.asString() <<
": "
176 <<
"state=" <<
static_cast<int>(m_state) ) ;
177 bool all_sent = false ;
178 if( m_state == State::raw )
179 rawReadEvent( no_throw_on_peer_disconnect ) ;
180 else if( m_state == State::connecting )
182 else if( m_state == State::accepting )
184 else if( m_state == State::writing )
185 all_sent = sslSendImp() ;
186 else if( m_state == State::shuttingdown )
193bool GNet::SocketProtocolImp::writeEvent()
195 G_DEBUG(
"GNet::SocketProtocolImp::writeEvent: write event: " << m_socket.asString() <<
": "
196 <<
"state=" <<
static_cast<int>(m_state) ) ;
197 bool all_sent = false ;
198 if( m_state == State::raw )
199 all_sent = rawWriteEvent() ;
200 else if( m_state == State::connecting )
202 else if( m_state == State::accepting )
204 else if( m_state == State::writing )
205 all_sent = sslSendImp() ;
206 else if( m_state == State::shuttingdown )
213void GNet::SocketProtocolImp::otherEvent( EventHandler::Reason reason ,
bool no_throw_on_peer_disconnect )
215 m_socket.dropReadHandler() ;
216 m_socket.dropOtherHandler() ;
218 if( m_state == State::raw )
220 bool peer_disconnect = rawOtherEvent( reason ) ;
221 if( peer_disconnect && no_throw_on_peer_disconnect )
223 m_sink.onPeerDisconnect() ;
228 if( reason == EventHandler::Reason::closed )
229 throw SocketProtocol::Shutdown() ;
231 throw SocketProtocol::OtherEventError( EventHandler::str(reason) ) ;
234std::size_t GNet::SocketProtocolImp::size(
const Segments & segments )
236 return std::accumulate( segments.begin() , segments.end() , std::size_t(0) ,
240GNet::SocketProtocolImp::Position GNet::SocketProtocolImp::firstPosition(
const Segments & s , std::size_t offset )
242 return newPosition( s , Position() , offset ) ;
245GNet::SocketProtocolImp::Position GNet::SocketProtocolImp::newPosition(
const Segments & s , Position pos ,
248 pos.offset += offset ;
249 for( ; pos.segment < s.size() && pos.offset >= s[pos.segment].size() ; pos.segment++ )
251 pos.offset -= s[pos.segment].size() ;
256G::string_view GNet::SocketProtocolImp::chunk(
const Segments & s , Position pos )
258 G_ASSERT( pos.segment < s.size() ) ;
259 G_ASSERT( pos.offset < s[pos.segment].size() ) ;
260 return s.at(pos.segment).substr( pos.offset ) ;
263bool GNet::SocketProtocolImp::send(
G::string_view data , std::size_t offset )
265 if( data.empty() || offset >= data.size() )
269 if( m_state == State::raw )
271 G_ASSERT( m_one_segment.size() == 1U ) ;
272 m_one_segment[0] = data ;
273 rc = rawSend( m_one_segment , Position(0U,offset) ,
true ) ;
275 else if( m_state == State::connecting || m_state == State::accepting )
277 throw SocketProtocol::SendError(
"still busy negotiating" ) ;
279 else if( m_state == State::writing )
281 throw SocketProtocol::SendError(
"still busy sending the last packet" ) ;
283 else if( m_state == State::shuttingdown )
285 throw SocketProtocol::SendError(
"shuting down" ) ;
290 m_data_copy.assign( data.data()+offset , data.size()-offset ) ;
291 G_ASSERT( m_one_segment.size() == 1U ) ;
292 m_one_segment[0] =
G::string_view( m_data_copy.data() , m_data_copy.size() ) ;
293 rc = sslSend( m_one_segment , Position() ) ;
298bool GNet::SocketProtocolImp::send(
const Segments & segments , std::size_t offset )
300 if( segments.empty() || offset >= size(segments) )
304 if( m_state == State::raw )
306 rc = rawSend( segments , firstPosition(segments,offset) ) ;
308 else if( m_state == State::connecting || m_state == State::accepting )
310 throw SocketProtocol::SendError(
"still busy negotiating" ) ;
312 else if( m_state == State::writing )
314 throw SocketProtocol::SendError(
"still busy sending the last packet" ) ;
316 else if( m_state == State::shuttingdown )
318 throw SocketProtocol::SendError(
"shutting down" ) ;
322 rc = sslSend( segments , firstPosition(segments,offset) ) ;
327void GNet::SocketProtocolImp::shutdown()
329 if( m_state == State::raw )
331 m_socket.dropWriteHandler() ;
332 m_socket.shutdown() ;
334 else if( m_state == State::idle )
336 m_state = State::shuttingdown ;
341void GNet::SocketProtocolImp::shutdownImp()
343 G_ASSERT( m_ssl !=
nullptr ) ;
344 G_ASSERT( m_state == State::shuttingdown ) ;
345 Result rc = m_ssl->shutdown() ;
346 if( rc == Result::ok )
348 m_socket.dropWriteHandler() ;
349 m_socket.shutdown() ;
350 m_state = State::idle ;
352 else if( rc == Result::error )
354 m_socket.dropReadHandler() ;
355 m_socket.dropWriteHandler() ;
356 throw SocketProtocol::ShutdownError() ;
358 else if( rc == Result::read )
360 m_socket.dropWriteHandler() ;
362 else if( rc == Result::write )
364 m_socket.addWriteHandler( m_handler , m_es ) ;
368bool GNet::SocketProtocolImp::secure()
const
371 m_state == State::writing ||
372 m_state == State::idle ||
373 m_state == State::shuttingdown ;
376bool GNet::SocketProtocolImp::raw()
const
378 return m_state == State::raw ;
381bool GNet::SocketProtocolImp::secureConnectCapable()
const
386void GNet::SocketProtocolImp::secureConnect()
388 G_DEBUG(
"SocketProtocolImp::secureConnect" ) ;
389 G_ASSERT( m_state == State::raw ) ;
390 G_ASSERT( m_ssl ==
nullptr ) ;
391 if( m_state != State::raw || m_ssl !=
nullptr )
392 throw SocketProtocol::ProtocolError() ;
395 m_ssl = newProtocol( m_config.client_tls_profile ) ;
396 m_state = State::connecting ;
397 if( m_config.secure_connection_timeout != 0U )
398 m_secure_connection_timer.startTimer( m_config.secure_connection_timeout ) ;
402void GNet::SocketProtocolImp::secureConnectImp()
404 G_DEBUG(
"SocketProtocolImp::secureConnectImp" ) ;
405 G_ASSERT( m_ssl !=
nullptr ) ;
406 G_ASSERT( m_state == State::connecting ) ;
408 Result rc = m_ssl->connect( m_socket ) ;
410 if( rc == Result::error )
412 m_socket.dropWriteHandler() ;
413 m_state = State::raw ;
414 throw SocketProtocol::ReadError(
"ssl connect" ) ;
416 else if( rc == Result::read )
418 m_socket.dropWriteHandler() ;
420 else if( rc == Result::write )
422 m_socket.addWriteHandler( m_handler , m_es ) ;
426 m_socket.dropWriteHandler() ;
427 m_state = State::idle ;
428 if( m_config.secure_connection_timeout != 0U )
429 m_secure_connection_timer.cancelTimer() ;
430 m_peer_certificate = m_ssl->peerCertificate() ;
431 std::string protocol = m_ssl->protocol() ;
432 std::string cipher = m_ssl->cipher() ;
433 logSecure( protocol , cipher ) ;
434 m_sink.onSecure( m_peer_certificate , protocol , cipher ) ;
438bool GNet::SocketProtocolImp::secureAcceptCapable()
const
443void GNet::SocketProtocolImp::secureAccept()
445 G_DEBUG(
"SocketProtocolImp::secureAccept" ) ;
446 G_ASSERT( m_state == State::raw ) ;
447 G_ASSERT( m_ssl ==
nullptr ) ;
448 if( m_state != State::raw || m_ssl !=
nullptr )
449 throw SocketProtocol::ProtocolError() ;
452 m_ssl = newProtocol( m_config.server_tls_profile ) ;
453 m_state = State::accepting ;
457void GNet::SocketProtocolImp::secureAcceptImp()
459 G_DEBUG(
"SocketProtocolImp::secureAcceptImp" ) ;
460 G_ASSERT( m_ssl !=
nullptr ) ;
461 G_ASSERT( m_state == State::accepting ) ;
463 Result rc = m_ssl->accept( m_socket ) ;
465 if( rc == Result::error )
467 m_socket.dropWriteHandler() ;
468 m_state = State::raw ;
469 throw SocketProtocol::ReadError(
"ssl accept" ) ;
471 else if( rc == Result::read )
473 m_socket.dropWriteHandler() ;
475 else if( rc == Result::write )
477 m_socket.addWriteHandler( m_handler , m_es ) ;
481 m_socket.dropWriteHandler() ;
482 m_state = State::idle ;
483 m_peer_certificate = m_ssl->peerCertificate() ;
484 std::string protocol = m_ssl->protocol() ;
485 std::string cipher = m_ssl->cipher() ;
486 logSecure( protocol , cipher ) ;
487 m_sink.onSecure( m_peer_certificate , protocol , cipher ) ;
491bool GNet::SocketProtocolImp::sslSend(
const Segments & segments , Position pos )
493 if( !finished(m_segments,m_position) )
494 throw SocketProtocol::SendError(
"still busy sending the last packet" ) ;
496 G_ASSERT( m_state == State::idle ) ;
497 m_state = State::writing ;
500 bool all_sent = sslSendImp( segments , pos , pos_out ) ;
501 if( !all_sent && failed() )
504 m_position = Position() ;
505 throw SocketProtocol::SendError() ;
510 m_position = Position() ;
514 m_segments = segments ;
515 m_position = pos_out ;
520bool GNet::SocketProtocolImp::sslSendImp()
522 return sslSendImp( m_segments , m_position , m_position ) ;
525bool GNet::SocketProtocolImp::sslSendImp(
const Segments & segments , Position pos , Position & pos_out )
527 while( !finished(segments,pos) )
531 GSsl::Protocol::Result result = m_ssl->write( c.data() , c.size() , nsent ) ;
532 if( result == Result::error )
534 m_socket.dropWriteHandler() ;
535 m_state = State::idle ;
539 else if( result == Result::read )
541 m_socket.dropWriteHandler() ;
544 else if( result == Result::write )
546 m_socket.addWriteHandler( m_handler , m_es ) ;
552 G_ASSERT( nsent >= 0 ) ;
553 pos_out = pos = newPosition( segments , pos ,
554 nsent >= 0 ?
static_cast<std::size_t
>(nsent) : std::size_t(0U) ) ;
557 m_state = State::idle ;
561void GNet::SocketProtocolImp::sslReadImp()
563 G_DEBUG(
"SocketProtocolImp::sslReadImp" ) ;
564 G_ASSERT( m_state == State::idle ) ;
565 G_ASSERT( m_ssl !=
nullptr ) ;
567 Result rc = Result::more ;
568 for(
int sanity = 0 ; rc == Result::more && sanity < 100000 ; sanity++ )
570 rc = m_ssl->read( &m_read_buffer[0] , m_read_buffer.size() , m_read_buffer_n ) ;
572 if( rc == Result::error )
574 m_socket.dropWriteHandler() ;
575 m_state = State::idle ;
576 throw SocketProtocol::ReadError(
"ssl read" ) ;
578 else if( rc == Result::read )
580 m_socket.dropWriteHandler() ;
582 else if( rc == Result::write )
584 m_socket.addWriteHandler( m_handler , m_es ) ;
588 G_ASSERT( rc == Result::ok || rc == Result::more ) ;
589 G_ASSERT( m_read_buffer_n >= 0 ) ;
590 m_socket.dropWriteHandler() ;
591 m_state = State::idle ;
592 std::size_t n =
static_cast<std::size_t
>(m_read_buffer_n) ;
593 m_read_buffer_n = 0 ;
594 G_DEBUG(
"SocketProtocolImp::sslReadImp: calling onData(): " << n ) ;
598 m_sink.onData( &m_read_buffer[0] , n ) ;
599 if( this_.deleted() ) break ;
602 if( rc == Result::more )
604 G_DEBUG(
"SocketProtocolImp::sslReadImp: more available to read" ) ;
609bool GNet::SocketProtocolImp::rawOtherEvent( EventHandler::Reason reason )
612 if( reason == EventHandler::Reason::closed )
615 G_DEBUG(
"GNet::SocketProtocolImp::rawOtherEvent: shutdown: clearing receive queue" ) ;
618 const ssize_t rc = m_socket.read( &m_read_buffer[0] , m_read_buffer.size() ) ;
619 G_DEBUG(
"GNet::SocketProtocolImp::rawOtherEvent: read " << m_socket.asString() <<
": " << rc ) ;
626 throw SocketProtocol::ReadError( m_socket.reason() ) ;
628 G_ASSERT(
static_cast<std::size_t
>(rc) <= m_read_buffer.size() ) ;
630 m_sink.onData( &m_read_buffer[0] ,
static_cast<std::size_t
>(rc) ) ;
631 if( this_.deleted() ) break ;
641bool GNet::SocketProtocolImp::rawReadEvent(
bool no_throw_on_peer_disconnect )
643 const ssize_t rc = m_socket.read( &m_read_buffer[0] , m_read_buffer.size() ) ;
644 if( rc == 0 && no_throw_on_peer_disconnect )
646 m_socket.dropReadHandler() ;
647 m_sink.onPeerDisconnect() ;
650 else if( rc == 0 || ( rc == -1 && !m_socket.eWouldBlock() ) )
652 throw SocketProtocol::ReadError( rc == 0 ? std::string() : m_socket.reason() ) ;
656 G_ASSERT(
static_cast<std::size_t
>(rc) <= m_read_buffer.size() ) ;
657 m_sink.onData( &m_read_buffer[0] ,
static_cast<std::size_t
>(rc) ) ;
661 G_DEBUG(
"GNet::SocketProtocolImp::rawReadEvent: read event read nothing" ) ;
667bool GNet::SocketProtocolImp::rawSend(
const Segments & segments , Position pos ,
bool do_copy )
669 G_ASSERT( !do_copy || segments.size() == 1U ) ;
671 if( !finished(m_segments,m_position) )
672 throw SocketProtocol::SendError(
"still busy sending the last packet" ) ;
675 bool all_sent = rawSendImp( segments , pos , pos_out ) ;
676 if( !all_sent && failed() )
679 m_position = Position() ;
680 m_data_copy.clear() ;
681 throw SocketProtocol::SendError( m_socket.reason() ) ;
686 m_position = Position() ;
687 m_data_copy.clear() ;
692 G_ASSERT( segments.size() == 1U ) ;
693 G_ASSERT( pos_out.offset < segments[0].size() ) ;
694 m_segments = segments ;
695 m_data_copy.assign( segments[0].data()+pos_out.offset , segments[0].size()-pos_out.offset ) ;
696 m_segments[0] =
G::string_view( m_data_copy.data() , m_data_copy.size() ) ;
697 m_position = Position() ;
699 m_socket.addWriteHandler( m_handler , m_es ) ;
704 m_segments = segments ;
705 m_data_copy.clear() ;
706 m_position = pos_out ;
708 m_socket.addWriteHandler( m_handler , m_es ) ;
713bool GNet::SocketProtocolImp::rawWriteEvent()
715 m_socket.dropWriteHandler() ;
716 bool all_sent = rawSendImp( m_segments , m_position , m_position ) ;
717 if( !all_sent && failed() )
720 m_position = Position() ;
721 m_data_copy.clear() ;
722 throw SocketProtocol::SendError() ;
727 m_position = Position() ;
728 m_data_copy.clear() ;
732 m_socket.addWriteHandler( m_handler , m_es ) ;
737bool GNet::SocketProtocolImp::rawSendImp(
const Segments & segments , Position pos , Position & pos_out )
739 while( !finished(segments,pos) )
742 ssize_t rc = m_socket.write( c.data() , c.size() ) ;
743 if( rc < 0 && ! m_socket.eWouldBlock() )
746 pos_out = Position() ;
750 else if( rc < 0 ||
static_cast<std::size_t
>(rc) < c.size() )
753 std::size_t nsent = rc > 0 ?
static_cast<std::size_t
>(rc) : 0U ;
754 pos_out = newPosition( segments , pos , nsent ) ;
755 G_ASSERT( !finished(segments,pos_out) ) ;
760 pos = newPosition( segments , pos ,
static_cast<std::size_t
>(rc) ) ;
766void GNet::SocketProtocolImp::rawReset()
769 m_position = Position() ;
770 m_data_copy.clear() ;
771 m_socket.dropWriteHandler() ;
774std::unique_ptr<GSsl::Protocol> GNet::SocketProtocolImp::newProtocol(
const std::string & profile_name )
777 if( library ==
nullptr )
778 throw G::Exception(
"SocketProtocolImp::newProtocol: no tls library available" ) ;
780 return std::make_unique<GSsl::Protocol>( library->
profile(profile_name) ) ;
783bool GNet::SocketProtocolImp::finished(
const Segments & segments , Position pos )
785 G_ASSERT( pos.segment <= segments.size() ) ;
786 return pos.segment == segments.size() ;
789bool GNet::SocketProtocolImp::failed()
const
794std::string GNet::SocketProtocolImp::peerCertificate()
const
796 return m_peer_certificate ;
800void GNet::SocketProtocolImp::log(
int level ,
const std::string & log_line )
803 G_DEBUG(
"GNet::SocketProtocolImp::log: tls: " << log_line ) ;
804 else if( level == 2 )
805 G_LOG(
"GNet::SocketProtocolImp::log: tls: " << log_line ) ;
807 G_WARNING(
"GNet::SocketProtocolImp::log: tls: " << log_line ) ;
811void GNet::SocketProtocolImp::logSecure(
const std::string & protocol ,
const std::string & cipher )
const
813 G_LOG(
"GNet::SocketProtocolImp: tls protocol established with "
814 << m_socket.getPeerAddress().second.displayString()
815 << (protocol.empty()?
"":
" protocol ") << protocol
823 m_imp(
std::make_unique<SocketProtocolImp>(handler,es,sink,socket,config))
832 return m_imp->readEvent( no_throw_on_peer_disconnect ) ;
837 return m_imp->writeEvent() ;
842 m_imp->otherEvent( reason , no_throw_on_peer_disconnect ) ;
847 return m_imp->send(
G::string_view(data.data(),data.size()) , offset ) ;
852 return m_imp->send( data , 0U ) ;
857 return m_imp->send( data , offset ) ;
867 return m_imp->secureConnectCapable() ;
872 m_imp->secureConnect() ;
877 return m_imp->secureAcceptCapable() ;
882 m_imp->secureAccept() ;
888 return m_imp->secure() ;
895 return m_imp->raw() ;
901 return m_imp->peerCertificate() ;
A base class for classes that have a file descriptor and handle asynchronous events from the event lo...
A tuple containing an ExceptionHandler interface pointer and a bound 'exception source' pointer.
An interface used by GNet::SocketProtocol to deliver data from a socket.
bool readEvent(bool no_throw_on_peer_disconnect=false)
Called on receipt of a read event.
bool send(const std::string &data, std::size_t offset)
Sends data.
bool writeEvent()
Called on receipt of a write event.
bool secure() const
Returns true if the connection is currently secure ie.
bool secureAcceptCapable() const
Returns true if the implementation supports TLS/SSL and a "server" profile has been configured.
void secureAccept()
Waits for the TLS/SSL handshake protocol, acting as a server.
~SocketProtocol()
Destructor.
void otherEvent(EventHandler::Reason, bool no_throw_on_peer_disconnect=false)
Called on receipt of an 'other' event.
void shutdown()
Initiates a TLS-close if secure, together with a Socket::shutdown(1).
SocketProtocol(EventHandler &, ExceptionSink, Sink &, StreamSocket &, const Config &)
Constructor.
std::string peerCertificate() const
Returns the peer's TLS/SSL certificate or the empty string.
bool secureConnectCapable() const
Returns true if the implementation supports TLS/SSL and a "client" profile has been configured.
bool raw() const
Returns true if no TLS/SSL.
void secureConnect()
Initiates the TLS/SSL handshake, acting as a client.
A derivation of GNet::Socket for a stream socket.
A singleton class for initialising the underlying TLS library.
static bool enabledAs(const std::string &profile_name)
A static convenience function that returns true if there is an enabled() Library instance() that has ...
static Library * instance()
Returns a pointer to a library object, if any.
const Profile & profile(const std::string &profile_name) const
Returns an opaque reference to the named profile.
static std::string str(Result result)
Converts a result enumeration into a printable string.
An object to represent a nested execution context.
A linked list of CallFrame pointers.
A general-purpose exception class derived from std::exception and containing an error message.
static std::string printable(const std::string &in, char escape='\\')
Returns a printable representation of the given input string, using chacter code ranges 0x20 to 0x7e ...
A class like c++17's std::string_view.
An interface to an underlying TLS library.
A configuration structure for GNet::SocketProtocol.