38class GNet::SocketProtocolImp
41 using Result = GSsl::Protocol::Result ;
42 using Segment = std::string_view ;
43 using Segments = std::vector<Segment> ;
46 Position() = default ;
47 Position( std::size_t s , std::size_t o ) : segment(s) , offset(o) {}
48 std::size_t segment{0U} ;
49 std::size_t offset{0U} ;
53 SocketProtocolImp( EventHandler & , EventState , SocketProtocol::Sink & ,
54 StreamSocket & ,
const SocketProtocol::Config & ) ;
55 ~SocketProtocolImp() ;
56 bool readEvent(
bool ) ;
58 void otherEvent( EventHandler::Reason ,
bool ) ;
59 bool send( std::string_view data , std::size_t offset ) ;
60 bool send(
const Segments & , std::size_t ) ;
62 void secureConnect() ;
63 bool secureConnectCapable()
const ;
65 bool secureAcceptCapable()
const ;
68 std::string peerCertificate()
const ;
71 SocketProtocolImp(
const SocketProtocolImp & ) = delete ;
72 SocketProtocolImp( SocketProtocolImp && ) = delete ;
73 SocketProtocolImp & operator=(
const SocketProtocolImp & ) = delete ;
74 SocketProtocolImp & operator=( SocketProtocolImp && ) = delete ;
77 enum class State { raw , connecting , accepting , writing , idle , shuttingdown } ;
78 static std::unique_ptr<GSsl::Protocol> newProtocol(
const std::string & ) ;
79 static void log(
int level ,
const std::string & line ) ;
81 bool rawReadEvent(
bool ) ;
82 bool rawWriteEvent() ;
83 bool rawOtherEvent( EventHandler::Reason ) ;
84 bool rawSend(
const Segments & , Position ,
bool =
false ) ;
85 bool rawSendImp(
const Segments & , Position , Position & ) ;
88 bool sslSend(
const Segments & segments , Position pos ) ;
90 bool sslSendImp(
const Segments & segments , Position pos , Position & ) ;
91 void secureConnectImp() ;
92 void secureAcceptImp() ;
94 void logSecure(
const std::string & ,
const std::string & )
const ;
95 void onSecureConnectionTimeout() ;
96 static std::size_t size(
const Segments & ) ;
97 static bool finished(
const Segments & , Position ) ;
98 static Position firstPosition(
const Segments & , std::size_t ) ;
99 static Position newPosition(
const Segments & , Position , std::size_t ) ;
100 static std::string_view chunk(
const Segments & , Position ) ;
101 friend std::ostream & operator<<( std::ostream & , State ) ;
104 EventHandler & m_handler ;
106 SocketProtocol::Sink & m_sink ;
107 StreamSocket & m_socket ;
109 SocketProtocol::Config m_config ;
110 Segments m_one_segment ;
111 Segments m_segments ;
112 Position m_position ;
113 std::string m_data_copy ;
114 bool m_failed {
false} ;
115 std::unique_ptr<GSsl::Protocol> m_ssl ;
116 State m_state {State::raw} ;
117 std::vector<char> m_read_buffer ;
118 ssize_t m_read_buffer_n {0} ;
119 Timer<SocketProtocolImp> m_secure_connection_timer ;
120 std::string m_peer_certificate ;
125 std::ostream & operator<<( std::ostream & stream , SocketProtocolImp::State state )
127 return stream << static_cast<int>(state) ;
129 std::ostream & operator<<( std::ostream & stream ,
const SocketProtocolImp::Position & pos )
131 return stream <<
"(" << pos.segment <<
"," << pos.offset <<
")" ;
133 std::ostream & operator<<( std::ostream & stream ,
const SocketProtocolImp::Segments & segments )
136 const char * sep =
"" ;
137 for( std::size_t i = 0U ; i < segments.size() ; i++ , sep =
"," )
138 stream << sep <<
"(" <<
static_cast<const void*
>(segments.at(i).data())
139 <<
":" << segments.at(i).size() <<
")" ;
145GNet::SocketProtocolImp::SocketProtocolImp( EventHandler & handler , EventState es ,
146 SocketProtocol::Sink & sink , StreamSocket & socket ,
const SocketProtocol::Config & config ) :
153 m_read_buffer(
std::max(
std::size_t(1U),config.read_buffer_size)) ,
154 m_secure_connection_timer(*this,&SocketProtocolImp::onSecureConnectionTimeout,es)
156 if( m_config.server_tls_profile.empty() ) m_config.server_tls_profile =
"server" ;
157 if( m_config.client_tls_profile.empty() ) m_config.client_tls_profile =
"client" ;
160GNet::SocketProtocolImp::~SocketProtocolImp()
163void GNet::SocketProtocolImp::onSecureConnectionTimeout()
165 G_DEBUG(
"GNet::SocketProtocolImp::onSecureConnectionTimeout: timed out" ) ;
166 throw SocketProtocol::SecureConnectionTimeout() ;
169bool GNet::SocketProtocolImp::readEvent(
bool no_throw_on_peer_disconnect )
171 G_DEBUG(
"SocketProtocolImp::readEvent: read event: " << m_socket.asString() <<
": "
172 <<
"state=" <<
static_cast<int>(m_state) ) ;
173 bool all_sent = false ;
174 if( m_state == State::raw )
175 rawReadEvent( no_throw_on_peer_disconnect ) ;
176 else if( m_state == State::connecting )
178 else if( m_state == State::accepting )
180 else if( m_state == State::writing )
181 all_sent = sslSendImp() ;
182 else if( m_state == State::shuttingdown )
189bool GNet::SocketProtocolImp::writeEvent()
191 G_DEBUG(
"GNet::SocketProtocolImp::writeEvent: write event: " << m_socket.asString() <<
": "
192 <<
"state=" <<
static_cast<int>(m_state) ) ;
193 bool all_sent = false ;
194 if( m_state == State::raw )
195 all_sent = rawWriteEvent() ;
196 else if( m_state == State::connecting )
198 else if( m_state == State::accepting )
200 else if( m_state == State::writing )
201 all_sent = sslSendImp() ;
202 else if( m_state == State::shuttingdown )
209void GNet::SocketProtocolImp::otherEvent( EventHandler::Reason reason ,
bool no_throw_on_peer_disconnect )
211 m_socket.dropReadHandler() ;
212 m_socket.dropOtherHandler() ;
214 if( m_state == State::raw )
216 bool peer_disconnect = rawOtherEvent( reason ) ;
217 if( peer_disconnect && no_throw_on_peer_disconnect )
219 m_sink.onPeerDisconnect() ;
224 if( reason == EventHandler::Reason::closed )
225 throw SocketProtocol::Shutdown() ;
227 throw SocketProtocol::OtherEventError( EventHandler::str(reason) ) ;
230std::size_t GNet::SocketProtocolImp::size(
const Segments & segments )
232 return std::accumulate( segments.begin() , segments.end() , std::size_t(0) ,
233 [](std::size_t n,std::string_view s){return n+s.size();} ) ;
236GNet::SocketProtocolImp::Position GNet::SocketProtocolImp::firstPosition(
const Segments & s , std::size_t offset )
238 return newPosition( s , Position() , offset ) ;
241GNet::SocketProtocolImp::Position GNet::SocketProtocolImp::newPosition(
const Segments & s , Position pos ,
244 pos.offset += offset ;
245 for( ; pos.segment < s.size() && pos.offset >= s[pos.segment].size() ; pos.segment++ )
247 pos.offset -= s[pos.segment].size() ;
252std::string_view GNet::SocketProtocolImp::chunk(
const Segments & s , Position pos )
254 G_ASSERT( pos.segment < s.size() ) ;
255 G_ASSERT( pos.offset < s[pos.segment].size() ) ;
256 return s.at(pos.segment).substr( pos.offset ) ;
259bool GNet::SocketProtocolImp::send( std::string_view data , std::size_t offset )
261 if( data.empty() || offset >= data.size() )
265 if( m_state == State::raw )
267 G_ASSERT( m_one_segment.size() == 1U ) ;
268 m_one_segment[0] = data ;
269 rc = rawSend( m_one_segment , Position(0U,offset) ,
true ) ;
271 else if( m_state == State::connecting || m_state == State::accepting )
273 throw SocketProtocol::SendError(
"still busy negotiating" ) ;
275 else if( m_state == State::writing )
277 throw SocketProtocol::SendError(
"still busy sending the last packet" ) ;
279 else if( m_state == State::shuttingdown )
281 throw SocketProtocol::SendError(
"shuting down" ) ;
286 m_data_copy.assign( data.data()+offset , data.size()-offset ) ;
287 G_ASSERT( m_one_segment.size() == 1U ) ;
288 m_one_segment[0] = std::string_view( m_data_copy.data() , m_data_copy.size() ) ;
289 rc = sslSend( m_one_segment , Position() ) ;
294bool GNet::SocketProtocolImp::send(
const Segments & segments , std::size_t offset )
296 if( segments.empty() || offset >= size(segments) )
300 if( m_state == State::raw )
302 rc = rawSend( segments , firstPosition(segments,offset) ) ;
304 else if( m_state == State::connecting || m_state == State::accepting )
306 throw SocketProtocol::SendError(
"still busy negotiating" ) ;
308 else if( m_state == State::writing )
310 throw SocketProtocol::SendError(
"still busy sending the last packet" ) ;
312 else if( m_state == State::shuttingdown )
314 throw SocketProtocol::SendError(
"shutting down" ) ;
318 rc = sslSend( segments , firstPosition(segments,offset) ) ;
323void GNet::SocketProtocolImp::shutdown()
325 if( m_state == State::raw )
327 m_socket.dropWriteHandler() ;
328 m_socket.shutdown() ;
330 else if( m_state == State::idle )
332 m_state = State::shuttingdown ;
337void GNet::SocketProtocolImp::shutdownImp()
339 G_ASSERT( m_ssl !=
nullptr ) ;
340 G_ASSERT( m_state == State::shuttingdown ) ;
341 Result rc = m_ssl->shutdown() ;
342 if( rc == Result::ok )
344 m_socket.dropWriteHandler() ;
345 m_socket.shutdown() ;
346 m_state = State::idle ;
348 else if( rc == Result::error )
350 m_socket.dropReadHandler() ;
351 m_socket.dropWriteHandler() ;
352 throw SocketProtocol::ShutdownError() ;
354 else if( rc == Result::read )
356 m_socket.dropWriteHandler() ;
358 else if( rc == Result::write )
360 m_socket.addWriteHandler( m_handler , m_es ) ;
364bool GNet::SocketProtocolImp::secure()
const
367 m_state == State::writing ||
368 m_state == State::idle ||
369 m_state == State::shuttingdown ;
372bool GNet::SocketProtocolImp::raw()
const
374 return m_state == State::raw ;
377bool GNet::SocketProtocolImp::secureConnectCapable()
const
382void GNet::SocketProtocolImp::secureConnect()
384 G_DEBUG(
"SocketProtocolImp::secureConnect" ) ;
385 G_ASSERT( m_state == State::raw ) ;
386 G_ASSERT( m_ssl ==
nullptr ) ;
387 if( m_state != State::raw || m_ssl !=
nullptr )
388 throw SocketProtocol::ProtocolError() ;
391 m_ssl = newProtocol( m_config.client_tls_profile ) ;
392 m_state = State::connecting ;
393 if( m_config.secure_connection_timeout != 0U )
394 m_secure_connection_timer.startTimer( m_config.secure_connection_timeout ) ;
398void GNet::SocketProtocolImp::secureConnectImp()
400 G_DEBUG(
"SocketProtocolImp::secureConnectImp" ) ;
401 G_ASSERT( m_ssl !=
nullptr ) ;
402 G_ASSERT( m_state == State::connecting ) ;
404 Result rc = m_ssl->connect( m_socket ) ;
406 if( rc == Result::error )
408 m_socket.dropWriteHandler() ;
409 m_state = State::raw ;
410 throw SocketProtocol::ReadError(
"ssl connect" ) ;
412 else if( rc == Result::read )
414 m_socket.dropWriteHandler() ;
416 else if( rc == Result::write )
418 m_socket.addWriteHandler( m_handler , m_es ) ;
422 m_socket.dropWriteHandler() ;
423 m_state = State::idle ;
424 if( m_config.secure_connection_timeout != 0U )
425 m_secure_connection_timer.cancelTimer() ;
426 m_peer_certificate = m_ssl->peerCertificate() ;
427 std::string protocol = m_ssl->protocol() ;
428 std::string cipher = m_ssl->cipher() ;
429 logSecure( protocol , cipher ) ;
430 m_sink.onSecure( m_peer_certificate , protocol , cipher ) ;
434bool GNet::SocketProtocolImp::secureAcceptCapable()
const
439void GNet::SocketProtocolImp::secureAccept()
441 G_DEBUG(
"SocketProtocolImp::secureAccept" ) ;
442 G_ASSERT( m_state == State::raw ) ;
443 G_ASSERT( m_ssl ==
nullptr ) ;
444 if( m_state != State::raw || m_ssl !=
nullptr )
445 throw SocketProtocol::ProtocolError() ;
448 m_ssl = newProtocol( m_config.server_tls_profile ) ;
449 m_state = State::accepting ;
453void GNet::SocketProtocolImp::secureAcceptImp()
455 G_DEBUG(
"SocketProtocolImp::secureAcceptImp" ) ;
456 G_ASSERT( m_ssl !=
nullptr ) ;
457 G_ASSERT( m_state == State::accepting ) ;
459 Result rc = m_ssl->accept( m_socket ) ;
461 if( rc == Result::error )
463 m_socket.dropWriteHandler() ;
464 m_state = State::raw ;
465 throw SocketProtocol::ReadError(
"ssl accept" ) ;
467 else if( rc == Result::read )
469 m_socket.dropWriteHandler() ;
471 else if( rc == Result::write )
473 m_socket.addWriteHandler( m_handler , m_es ) ;
477 m_socket.dropWriteHandler() ;
478 m_state = State::idle ;
479 m_peer_certificate = m_ssl->peerCertificate() ;
480 std::string protocol = m_ssl->protocol() ;
481 std::string cipher = m_ssl->cipher() ;
482 logSecure( protocol , cipher ) ;
483 m_sink.onSecure( m_peer_certificate , protocol , cipher ) ;
487bool GNet::SocketProtocolImp::sslSend(
const Segments & segments , Position pos )
489 if( !finished(m_segments,m_position) )
490 throw SocketProtocol::SendError(
"still busy sending the last packet" ) ;
492 G_ASSERT( m_state == State::idle ) ;
493 m_state = State::writing ;
496 bool all_sent = sslSendImp( segments , pos , pos_out ) ;
497 if( !all_sent && failed() )
500 m_position = Position() ;
501 throw SocketProtocol::SendError() ;
506 m_position = Position() ;
510 m_segments = segments ;
511 m_position = pos_out ;
516bool GNet::SocketProtocolImp::sslSendImp()
518 return sslSendImp( m_segments , m_position , m_position ) ;
521bool GNet::SocketProtocolImp::sslSendImp(
const Segments & segments , Position pos , Position & pos_out )
523 while( !finished(segments,pos) )
526 std::string_view c = chunk( segments , pos ) ;
527 GSsl::Protocol::Result result = m_ssl->write( c.data() , c.size() , nsent ) ;
528 if( result == Result::error )
530 m_socket.dropWriteHandler() ;
531 m_state = State::idle ;
535 else if( result == Result::read )
537 m_socket.dropWriteHandler() ;
540 else if( result == Result::write )
542 m_socket.addWriteHandler( m_handler , m_es ) ;
548 G_ASSERT( nsent >= 0 ) ;
549 pos_out = pos = newPosition( segments , pos ,
550 nsent >= 0 ?
static_cast<std::size_t
>(nsent) : std::size_t(0U) ) ;
553 m_state = State::idle ;
557void GNet::SocketProtocolImp::sslReadImp()
559 G_DEBUG(
"SocketProtocolImp::sslReadImp" ) ;
560 G_ASSERT( m_state == State::idle ) ;
561 G_ASSERT( m_ssl !=
nullptr ) ;
563 Result rc = Result::more ;
564 for(
int sanity = 0 ; rc == Result::more && sanity < 100000 ; sanity++ )
566 rc = m_ssl->read( m_read_buffer.data() , m_read_buffer.size() , m_read_buffer_n ) ;
568 if( rc == Result::error )
570 m_socket.dropWriteHandler() ;
571 m_state = State::idle ;
572 throw SocketProtocol::ReadError(
"ssl read" ) ;
574 else if( rc == Result::read )
576 m_socket.dropWriteHandler() ;
578 else if( rc == Result::write )
580 m_socket.addWriteHandler( m_handler , m_es ) ;
584 G_ASSERT( rc == Result::ok || rc == Result::more ) ;
585 G_ASSERT( m_read_buffer_n >= 0 ) ;
586 m_socket.dropWriteHandler() ;
587 m_state = State::idle ;
588 std::size_t n =
static_cast<std::size_t
>(m_read_buffer_n) ;
589 m_read_buffer_n = 0 ;
590 G_DEBUG(
"SocketProtocolImp::sslReadImp: calling onData(): " << n ) ;
594 m_sink.onData( m_read_buffer.data() , n ) ;
595 if( this_.deleted() ) break ;
598 if( rc == Result::more )
600 G_DEBUG(
"SocketProtocolImp::sslReadImp: more available to read" ) ;
605bool GNet::SocketProtocolImp::rawOtherEvent( EventHandler::Reason reason )
608 if( reason == EventHandler::Reason::closed )
611 G_DEBUG(
"GNet::SocketProtocolImp::rawOtherEvent: shutdown: clearing receive queue" ) ;
614 const ssize_t rc = m_socket.read( m_read_buffer.data() , m_read_buffer.size() ) ;
615 G_DEBUG(
"GNet::SocketProtocolImp::rawOtherEvent: read " << m_socket.asString() <<
": " << rc ) ;
622 throw SocketProtocol::ReadError( m_socket.reason() ) ;
624 G_ASSERT(
static_cast<std::size_t
>(rc) <= m_read_buffer.size() ) ;
626 m_sink.onData( m_read_buffer.data() ,
static_cast<std::size_t
>(rc) ) ;
627 if( this_.deleted() ) break ;
637bool GNet::SocketProtocolImp::rawReadEvent(
bool no_throw_on_peer_disconnect )
639 const ssize_t rc = m_socket.read( m_read_buffer.data() , m_read_buffer.size() ) ;
640 if( rc == 0 && no_throw_on_peer_disconnect )
642 m_socket.dropReadHandler() ;
643 m_sink.onPeerDisconnect() ;
646 else if( rc == 0 || ( rc == -1 && !m_socket.eWouldBlock() ) )
648 throw SocketProtocol::ReadError( rc == 0 ? std::string() : m_socket.reason() ) ;
652 G_ASSERT(
static_cast<std::size_t
>(rc) <= m_read_buffer.size() ) ;
653 m_sink.onData( m_read_buffer.data() ,
static_cast<std::size_t
>(rc) ) ;
657 G_DEBUG(
"GNet::SocketProtocolImp::rawReadEvent: read event read nothing" ) ;
663bool GNet::SocketProtocolImp::rawSend(
const Segments & segments , Position pos ,
bool do_copy )
665 G_ASSERT( !do_copy || segments.size() == 1U ) ;
667 if( !finished(m_segments,m_position) )
668 throw SocketProtocol::SendError(
"still busy sending the last packet" ) ;
671 bool all_sent = rawSendImp( segments , pos , pos_out ) ;
672 if( !all_sent && failed() )
675 m_position = Position() ;
676 m_data_copy.clear() ;
677 throw SocketProtocol::SendError( m_socket.reason() ) ;
682 m_position = Position() ;
683 m_data_copy.clear() ;
688 G_ASSERT( segments.size() == 1U ) ;
689 G_ASSERT( pos_out.offset < segments[0].size() ) ;
690 m_segments = segments ;
691 m_data_copy.assign( segments[0].data()+pos_out.offset , segments[0].size()-pos_out.offset ) ;
692 m_segments[0] = std::string_view( m_data_copy.data() , m_data_copy.size() ) ;
693 m_position = Position() ;
695 m_socket.addWriteHandler( m_handler , m_es ) ;
700 m_segments = segments ;
701 m_data_copy.clear() ;
702 m_position = pos_out ;
704 m_socket.addWriteHandler( m_handler , m_es ) ;
709bool GNet::SocketProtocolImp::rawWriteEvent()
711 m_socket.dropWriteHandler() ;
712 bool all_sent = rawSendImp( m_segments , m_position , m_position ) ;
713 if( !all_sent && failed() )
716 m_position = Position() ;
717 m_data_copy.clear() ;
718 throw SocketProtocol::SendError() ;
723 m_position = Position() ;
724 m_data_copy.clear() ;
728 m_socket.addWriteHandler( m_handler , m_es ) ;
733bool GNet::SocketProtocolImp::rawSendImp(
const Segments & segments , Position pos , Position & pos_out )
735 while( !finished(segments,pos) )
737 std::string_view c = chunk( segments , pos ) ;
738 ssize_t rc = m_socket.write( c.data() , c.size() ) ;
739 if( rc < 0 && ! m_socket.eWouldBlock() )
742 pos_out = Position() ;
746 else if( rc < 0 ||
static_cast<std::size_t
>(rc) < c.size() )
749 std::size_t nsent = rc > 0 ?
static_cast<std::size_t
>(rc) : 0U ;
750 pos_out = newPosition( segments , pos , nsent ) ;
751 G_ASSERT( !finished(segments,pos_out) ) ;
756 pos = newPosition( segments , pos ,
static_cast<std::size_t
>(rc) ) ;
762void GNet::SocketProtocolImp::rawReset()
765 m_position = Position() ;
766 m_data_copy.clear() ;
767 m_socket.dropWriteHandler() ;
770std::unique_ptr<GSsl::Protocol> GNet::SocketProtocolImp::newProtocol(
const std::string & profile_name )
773 if( library ==
nullptr )
774 throw G::Exception(
"SocketProtocolImp::newProtocol: no tls library available" ) ;
776 return std::make_unique<GSsl::Protocol>( library->
profile(profile_name) ) ;
779bool GNet::SocketProtocolImp::finished(
const Segments & segments , Position pos )
781 G_ASSERT( pos.segment <= segments.size() ) ;
782 return pos.segment == segments.size() ;
785bool GNet::SocketProtocolImp::failed()
const
790std::string GNet::SocketProtocolImp::peerCertificate()
const
792 return m_peer_certificate ;
796void GNet::SocketProtocolImp::log(
int level ,
const std::string & log_line )
799 G_DEBUG(
"GNet::SocketProtocolImp::log: tls: " << log_line ) ;
800 else if( level == 2 )
801 G_LOG(
"GNet::SocketProtocolImp::log: tls: " << log_line ) ;
803 G_WARNING(
"GNet::SocketProtocolImp::log: tls: " << log_line ) ;
807void GNet::SocketProtocolImp::logSecure(
const std::string & protocol ,
const std::string & cipher )
const
809 G_LOG(
"GNet::SocketProtocolImp: tls protocol established with "
810 << m_socket.getPeerAddress().second.displayString()
811 << (protocol.empty()?
"":
" protocol ") << protocol
819 m_imp(
std::make_unique<SocketProtocolImp>(handler,es,sink,socket,config))
828 return m_imp->readEvent( no_throw_on_peer_disconnect ) ;
833 return m_imp->writeEvent() ;
838 m_imp->otherEvent( reason , no_throw_on_peer_disconnect ) ;
843 return m_imp->send( std::string_view(data.data(),data.size()) , offset ) ;
848 return m_imp->send( data , 0U ) ;
853 return m_imp->send( data , offset ) ;
863 return m_imp->secureConnectCapable() ;
868 m_imp->secureConnect() ;
873 return m_imp->secureAcceptCapable() ;
878 m_imp->secureAccept() ;
884 return m_imp->secure() ;
891 return m_imp->raw() ;
897 return m_imp->peerCertificate() ;
A base class for classes that have a file descriptor and handle asynchronous events from the event lo...
A lightweight object containing an ExceptionHandler pointer, optional ExceptionSource pointer and opt...
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.
SocketProtocol(EventHandler &, EventState, Sink &, StreamSocket &, const Config &)
Constructor.
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).
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 ...
An interface to an underlying TLS library.
A configuration structure for GNet::SocketProtocol.