VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gsocketprotocol.cpp
1 //
2 // Copyright (C) 2017 Graeme Walker
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 //
18 // gsocketprotocol.cpp
19 //
20 
21 #include "gdef.h"
22 #include "glimits.h"
23 #include "gnet.h"
24 #include "gmonitor.h"
25 #include "gtimer.h"
26 #include "gssl.h"
27 #include "gsocketprotocol.h"
28 #include "gstr.h"
29 #include "gtest.h"
30 #include "gassert.h"
31 #include "glog.h"
32 
33 namespace
34 {
35  const size_t c_buffer_size = G::limits::net_buffer ;
36  const int Result_ok = GSsl::Protocol::Result_ok ;
37  const int Result_more = GSsl::Protocol::Result_more ;
38  const int Result_read = GSsl::Protocol::Result_read ;
39  const int Result_write = GSsl::Protocol::Result_write ;
40  const int Result_error = GSsl::Protocol::Result_error ;
41 }
42 
43 /// \class GNet::SocketProtocolImp
44 /// A pimple-pattern implementation class used by GNet::SocketProtocol.
45 ///
47 {
48 public:
49  typedef std::pair<const char *,size_t> Segment ;
50  typedef std::vector<Segment> Segments ;
51  struct Position /// A pointer into the scatter/gather payload of GNet::SocketProtocolImp::send().
52  {
53  size_t segment ;
54  size_t offset ;
55  Position( size_t segment_ , size_t offset_ ) : segment(segment_) , offset(offset_) {}
56  Position() : segment(0U) , offset(0U) {}
57  } ;
58 
60  unsigned int secure_connection_timeout ) ;
62  void readEvent() ;
63  bool writeEvent() ;
64  bool send( const std::string & data , size_t offset ) ;
65  bool send( const Segments & ) ;
66  void sslConnect() ;
67  void sslAccept() ;
68  bool sslEnabled() const ;
69  std::string peerCertificate() const ;
70 
71 private:
73  void operator=( const SocketProtocolImp & ) ;
74  static GSsl::Protocol * newProtocol( const std::string & ) ;
75  static void log( int level , const std::string & line ) ;
76  bool failed() const ;
77  bool rawSendImp( const Segments & , Position , Position & ) ;
78  void rawReadEvent() ;
79  bool rawWriteEvent() ;
80  bool rawSend( const Segments & , Position , bool ) ;
81  void sslReadImp() ;
82  bool sslSendImp() ;
83  void sslConnectImp() ;
84  void sslAcceptImp() ;
85  void logSecure( const std::string & ) const ;
86  void logCertificate( const std::string & , const std::string & ) const ;
87  void logFlowControl( const char * what ) ;
88  void onSecureConnectionTimeout() ;
89  static size_t size( const Segments & ) ;
90  static bool finished( const Segments & , Position ) ;
91  static Position position( const Segments & , Position , size_t ) ;
92  static const char * chunk_p( const Segments & , Position ) ;
93  static size_t chunk_n( const Segments & , Position ) ;
94 
95 private:
96  enum State { State_raw , State_connecting , State_accepting , State_writing , State_idle } ;
97  EventHandler & m_handler ;
98  SocketProtocol::Sink & m_sink ;
99  StreamSocket & m_socket ;
100  unsigned int m_secure_connection_timeout ;
101  Segments m_segments ;
102  Position m_raw_pos ;
103  std::string m_raw_copy ;
104  std::string m_ssl_send_data ;
105  bool m_failed ;
106  GSsl::Protocol * m_ssl ;
107  State m_state ;
108  std::vector<char> m_read_buffer ;
109  GSsl::Protocol::ssize_type m_read_buffer_n ;
110  Timer<SocketProtocolImp> m_secure_connection_timer ;
111  std::string m_peer_certificate ;
112 } ;
113 
114 namespace GNet
115 {
116  std::ostream & operator<<( std::ostream & stream , const SocketProtocolImp::Position & pos )
117  {
118  return stream << "(" << pos.segment << "," << pos.offset << ")" ;
119  }
120  std::ostream & operator<<( std::ostream & stream , const SocketProtocolImp::Segment & segment )
121  {
122  return stream << "(" << (const void*)(segment.first) << ":" << segment.second << ")" ;
123  }
124  std::ostream & operator<<( std::ostream & stream , const SocketProtocolImp::Segments & segments )
125  {
126  stream << "[" ;
127  const char * sep = "" ;
128  for( size_t i = 0U ; i < segments.size() ; i++ , sep = "," )
129  stream << sep << segments.at(i) ;
130  stream << "]" ;
131  return stream ;
132  }
133 }
134 
135 GNet::SocketProtocolImp::SocketProtocolImp( EventHandler & handler ,
136  SocketProtocol::Sink & sink , StreamSocket & socket ,
137  unsigned int secure_connection_timeout ) :
138  m_handler(handler) ,
139  m_sink(sink) ,
140  m_socket(socket) ,
141  m_secure_connection_timeout(secure_connection_timeout) ,
142  m_failed(false) ,
143  m_ssl(nullptr) ,
144  m_state(State_raw) ,
145  m_read_buffer(c_buffer_size) ,
146  m_read_buffer_n(0) ,
147  m_secure_connection_timer(*this,&SocketProtocolImp::onSecureConnectionTimeout,handler)
148 {
149  G_ASSERT( m_read_buffer.size() == c_buffer_size ) ;
150 }
151 
152 GNet::SocketProtocolImp::~SocketProtocolImp()
153 {
154  delete m_ssl ;
155 }
156 
157 void GNet::SocketProtocolImp::onSecureConnectionTimeout()
158 {
159  G_DEBUG( "GNet::SocketProtocolImp::onSecureConnectionTimeout: timed out" ) ;
160  throw SocketProtocol::SecureConnectionTimeout() ;
161 }
162 
163 void GNet::SocketProtocolImp::readEvent()
164 {
165  G_DEBUG( "SocketProtocolImp::readEvent: read event in state=" << m_state ) ;
166  if( m_state == State_raw )
167  rawReadEvent() ;
168  else if( m_state == State_connecting )
169  sslConnectImp() ;
170  else if( m_state == State_accepting )
171  sslAcceptImp() ;
172  else if( m_state == State_writing )
173  sslSendImp() ;
174  else // State_idle
175  sslReadImp() ;
176 }
177 
178 bool GNet::SocketProtocolImp::writeEvent()
179 {
180  G_DEBUG( "GNet::SocketProtocolImp::writeEvent: write event in state=" << m_state ) ;
181  bool rc = true ;
182  if( m_state == State_raw )
183  rc = rawWriteEvent() ;
184  else if( m_state == State_connecting )
185  sslConnectImp() ;
186  else if( m_state == State_accepting )
187  sslAcceptImp() ;
188  else if( m_state == State_writing )
189  sslSendImp() ;
190  else // State_idle
191  sslReadImp() ;
192  return rc ;
193 }
194 
195 size_t GNet::SocketProtocolImp::size( const Segments & segments )
196 {
197  size_t n = 0U ;
198  for( Segments::const_iterator p = segments.begin() ; p != segments.end() ; ++p )
199  {
200  G_ASSERT( (*p).first != nullptr ) ;
201  G_ASSERT( (*p).second != 0U ) ; // for chunk_p()
202  n += (*p).second ;
203  }
204  return n ;
205 }
206 
207 GNet::SocketProtocolImp::Position GNet::SocketProtocolImp::position( const Segments & s , Position pos , size_t offset )
208 {
209  G_ASSERT( pos.segment < s.size() ) ;
210  G_ASSERT( (pos.offset+offset) <= s.at(pos.segment).second ) ; // because chunk_p()
211  pos.offset += offset ;
212  if( pos.offset >= s.at(pos.segment).second ) // in practice if==
213  {
214  pos.segment++ ;
215  pos.offset = 0U ;
216  }
217  return pos ;
218 }
219 
220 const char * GNet::SocketProtocolImp::chunk_p( const Segments & s , Position pos )
221 {
222  G_ASSERT( pos.segment < s.size() ) ;
223  G_ASSERT( pos.offset < s[pos.segment].second ) ;
224 
225  const Segment & segment = s.at( pos.segment ) ;
226  return segment.first + pos.offset ;
227 }
228 
229 size_t GNet::SocketProtocolImp::chunk_n( const Segments & s , Position pos )
230 {
231  G_ASSERT( pos.segment < s.size() ) ;
232  G_ASSERT( pos.offset < s[pos.segment].second ) ;
233 
234  const Segment & segment = s.at( pos.segment ) ;
235  return segment.second - pos.offset ;
236 }
237 
238 bool GNet::SocketProtocolImp::send( const Segments & segments )
239 {
240  // for now only support scatter-gather segments in raw mode
241  if( m_state != State_raw )
242  throw std::runtime_error( "scatter/gather overload not implemented for tls" ) ; // TODO scatter-gather with tls library
243 
244  if( size(segments) == 0U )
245  return true ;
246 
247  return rawSend( segments , Position() , false/*copy*/ ) ;
248 }
249 
250 bool GNet::SocketProtocolImp::send( const std::string & data , size_t offset )
251 {
252  if( data.empty() || offset >= data.length() )
253  return true ;
254 
255  bool rc = true ;
256  if( m_state == State_raw )
257  {
258  Segments segments( 1U ) ;
259  segments[0].first = data.data() ;
260  segments[0].second = data.size() ;
261  rc = rawSend( segments , Position(0U,offset) , true/*copy*/ ) ;
262  }
263  else if( m_state == State_connecting || m_state == State_accepting )
264  {
265  throw SocketProtocol::SendError( "still busy negotiating" ) ;
266  }
267  else if( m_state == State_writing )
268  {
269  // we've been asked to send more stuff even though the previous send()
270  // returned false - we could add to the pending buffer but it then
271  // gets complicated to retry the ssl->write(), so just throw an error
272  throw SocketProtocol::SendError( "still busy sending the last packet" ) ;
273  }
274  else
275  {
276  m_state = State_writing ;
277  m_ssl_send_data.append( data.substr(offset) ) ;
278  rc = sslSendImp() ;
279  }
280  return rc ;
281 }
282 
283 void GNet::SocketProtocolImp::log( int level , const std::string & log_line )
284 {
285  if( level == 1 )
286  G_DEBUG( "GNet::SocketProtocolImp::log: tls: " << log_line ) ;
287  else if( level == 2 )
288  G_LOG( "GNet::SocketProtocolImp::log: tls: " << log_line ) ;
289  else
290  G_WARNING( "GNet::SocketProtocolImp::log: tls: " << log_line ) ;
291 }
292 
293 GSsl::Protocol * GNet::SocketProtocolImp::newProtocol( const std::string & profile_name )
294 {
295  GSsl::Library * library = GSsl::Library::instance() ;
296  if( library == nullptr )
297  throw G::Exception( "SocketProtocolImp::newProtocol: internal error: no library instance" ) ;
298 
299  return new GSsl::Protocol( library->profile(profile_name) , log ) ;
300 }
301 
302 void GNet::SocketProtocolImp::sslConnect()
303 {
304  G_DEBUG( "SocketProtocolImp::sslConnect" ) ;
305  G_ASSERT( m_ssl == nullptr ) ;
306 
307  m_ssl = newProtocol( "client" ) ;
308  m_state = State_connecting ;
309  if( m_secure_connection_timeout != 0U )
310  m_secure_connection_timer.startTimer( m_secure_connection_timeout ) ;
311  sslConnectImp() ;
312 }
313 
314 void GNet::SocketProtocolImp::sslConnectImp()
315 {
316  G_DEBUG( "SocketProtocolImp::sslConnectImp" ) ;
317  G_ASSERT( m_ssl != nullptr ) ;
318  G_ASSERT( m_state == State_connecting ) ;
319 
320  GSsl::Protocol::Result rc = m_ssl->connect( m_socket ) ;
321  G_DEBUG( "SocketProtocolImp::sslConnectImp: result=" << GSsl::Protocol::str(rc) ) ;
322  if( rc == Result_error )
323  {
324  m_socket.dropWriteHandler() ;
325  m_state = State_raw ;
326  throw SocketProtocol::ReadError( "ssl connect" ) ;
327  }
328  else if( rc == Result_read )
329  {
330  m_socket.dropWriteHandler() ;
331  }
332  else if( rc == Result_write )
333  {
334  m_socket.addWriteHandler( m_handler ) ;
335  }
336  else
337  {
338  m_socket.dropWriteHandler() ;
339  m_state = State_idle ;
340  if( m_secure_connection_timeout != 0U )
341  m_secure_connection_timer.cancelTimer() ;
342  m_peer_certificate = m_ssl->peerCertificate().first ;
343  logSecure( m_peer_certificate ) ;
344  G_DEBUG( "SocketProtocolImp::sslConnectImp: calling onSecure: " << G::Str::printable(m_peer_certificate) ) ;
345  m_sink.onSecure( m_peer_certificate ) ;
346  }
347 }
348 
349 void GNet::SocketProtocolImp::sslAccept()
350 {
351  G_DEBUG( "SocketProtocolImp::sslAccept" ) ;
352  G_ASSERT( m_ssl == nullptr ) ;
353 
354  m_ssl = newProtocol( "server" ) ;
355  m_state = State_accepting ;
356  sslAcceptImp() ;
357 }
358 
359 void GNet::SocketProtocolImp::sslAcceptImp()
360 {
361  G_DEBUG( "SocketProtocolImp::sslAcceptImp" ) ;
362  G_ASSERT( m_ssl != nullptr ) ;
363  G_ASSERT( m_state == State_accepting ) ;
364 
365  GSsl::Protocol::Result rc = m_ssl->accept( m_socket ) ;
366  G_DEBUG( "SocketProtocolImp::sslAcceptImp: result=" << GSsl::Protocol::str(rc) ) ;
367  if( rc == Result_error )
368  {
369  m_socket.dropWriteHandler() ;
370  m_state = State_raw ;
371  throw SocketProtocol::ReadError( "ssl accept" ) ;
372  }
373  else if( rc == Result_read )
374  {
375  m_socket.dropWriteHandler() ;
376  }
377  else if( rc == Result_write )
378  {
379  m_socket.addWriteHandler( m_handler ) ;
380  }
381  else
382  {
383  m_socket.dropWriteHandler() ;
384  m_state = State_idle ;
385  m_peer_certificate = m_ssl->peerCertificate().first ;
386  logSecure( m_peer_certificate ) ;
387  G_DEBUG( "SocketProtocolImp::sslAcceptImp: calling onSecure: " << G::Str::printable(m_peer_certificate) ) ;
388  m_sink.onSecure( m_peer_certificate ) ;
389  }
390 }
391 
392 bool GNet::SocketProtocolImp::sslEnabled() const
393 {
394  return m_state == State_writing || m_state == State_idle ;
395 }
396 
397 bool GNet::SocketProtocolImp::sslSendImp()
398 {
399  G_ASSERT( m_state == State_writing ) ;
400 
401  bool rc = false ;
402  GSsl::Protocol::ssize_type n = 0 ;
403  GSsl::Protocol::Result result = m_ssl->write( m_ssl_send_data.data() , m_ssl_send_data.size() , n ) ;
404  if( result == Result_error )
405  {
406  m_socket.dropWriteHandler() ;
407  m_state = State_idle ;
408  throw SocketProtocol::SendError( "ssl write" ) ;
409  }
410  else if( result == Result_read )
411  {
412  m_socket.dropWriteHandler() ;
413  }
414  else if( result == Result_write )
415  {
416  m_socket.addWriteHandler( m_handler ) ;
417  }
418  else
419  {
420  m_socket.dropWriteHandler() ;
421  if( n < 0 ) throw SocketProtocol::SendError( "ssl arithmetic underflow" ) ;
422  size_t un = static_cast<size_t>(n) ;
423  rc = un == m_ssl_send_data.size() ;
424  m_ssl_send_data.erase( 0U , un ) ;
425  m_state = State_idle ;
426  }
427  return rc ;
428 }
429 
430 void GNet::SocketProtocolImp::sslReadImp()
431 {
432  G_DEBUG( "SocketProtocolImp::sslReadImp" ) ;
433  G_ASSERT( m_state == State_idle ) ;
434  G_ASSERT( m_ssl != nullptr ) ;
435 
436  std::vector<char> more_data ;
437  GSsl::Protocol::Result rc = GSsl::Protocol::Result_more ;
438  for( int sanity = 0 ; rc == Result_more && sanity < 1000 ; sanity++ )
439  {
440  rc = m_ssl->read( &m_read_buffer[0] , m_read_buffer.size() , m_read_buffer_n ) ;
441  G_DEBUG( "SocketProtocolImp::sslReadImp: result=" << GSsl::Protocol::str(rc) ) ;
442  if( rc == Result_error )
443  {
444  m_socket.dropWriteHandler() ;
445  m_state = State_idle ;
446  throw SocketProtocol::ReadError( "ssl read" ) ;
447  }
448  else if( rc == Result_read )
449  {
450  m_socket.dropWriteHandler() ;
451  }
452  else if( rc == Result_write )
453  {
454  m_socket.addWriteHandler( m_handler ) ;
455  }
456  else // Result_ok, Result_more
457  {
458  G_ASSERT( rc == Result_ok || rc == Result_more ) ;
459  m_socket.dropWriteHandler() ;
460  m_state = State_idle ;
461  size_t n = static_cast<size_t>(m_read_buffer_n) ;
462  m_read_buffer_n = 0 ;
463  G_DEBUG( "SocketProtocolImp::sslReadImp: calling onData(): " << n ) ;
464  m_sink.onData( &m_read_buffer[0] , n ) ;
465  }
466  if( rc == Result_more )
467  G_DEBUG( "SocketProtocolImp::sslReadImp: more available to read" ) ;
468  }
469 }
470 
471 void GNet::SocketProtocolImp::rawReadEvent()
472 {
473  const size_t read_buffer_size = G::Test::enabled("small-client-input-buffer") ? 3 : m_read_buffer.size() ;
474  const ssize_t rc = m_socket.read( &m_read_buffer[0] , read_buffer_size ) ;
475 
476  if( rc == 0 || ( rc == -1 && !m_socket.eWouldBlock() ) )
477  {
478  throw SocketProtocol::ReadError() ;
479  }
480  else if( rc != -1 )
481  {
482  G_ASSERT( static_cast<size_t>(rc) <= read_buffer_size ) ;
483  m_sink.onData( &m_read_buffer[0] , static_cast<size_t>(rc) ) ;
484  }
485  else
486  {
487  G_DEBUG( "GNet::SocketProtocolImp::rawReadEvent: read event read nothing" ) ;
488  ; // -1 && eWouldBlock() -- no-op (esp. for windows)
489  }
490 }
491 
492 bool GNet::SocketProtocolImp::finished( const Segments & segments , Position pos )
493 {
494  return pos.segment == segments.size() ;
495 }
496 
497 bool GNet::SocketProtocolImp::rawSend( const Segments & segments , Position pos , bool do_copy )
498 {
499  G_ASSERT( !do_copy || segments.size() == 1U ) ; // copy => one segment
500 
501  if( !finished(m_segments,m_raw_pos) )
502  throw SocketProtocol::SendError( "still busy sending the last packet" ) ;
503 
504  Position pos_out ;
505  bool all_sent = rawSendImp( segments , pos , pos_out ) ;
506  if( !all_sent && failed() )
507  {
508  m_segments.clear() ;
509  m_raw_pos = Position() ;
510  m_raw_copy.clear() ;
511  throw SocketProtocol::SendError() ;
512  }
513  if( all_sent )
514  {
515  m_segments.clear() ;
516  m_raw_pos = Position() ;
517  m_raw_copy.clear() ;
518  }
519  else
520  {
521  // keep the residue in m_segments/m_raw_pos/m_raw_copy
522  m_segments = segments ;
523  m_raw_pos = pos_out ;
524  G_ASSERT( m_segments.empty() || m_segments[0].first != m_raw_copy.data() ) ;
525  m_raw_copy.clear() ;
526 
527  // if the caller's data is temporary then keep our own copy
528  if( do_copy )
529  {
530  G_ASSERT( segments.size() == 1U ) ; // precondition
531  G_ASSERT( pos_out.offset < segments[0].second ) ; // since not all sent
532  m_raw_copy.assign( segments[0].first+pos_out.offset , segments[0].second-pos_out.offset ) ;
533  m_segments[0].first = m_raw_copy.data() ;
534  m_segments[0].second = m_raw_copy.size() ;
535  m_raw_pos = Position() ;
536  }
537 
538  m_socket.addWriteHandler( m_handler ) ;
539  logFlowControl( "asserted" ) ;
540  }
541  return all_sent ;
542 }
543 
544 bool GNet::SocketProtocolImp::rawWriteEvent()
545 {
546  m_socket.dropWriteHandler() ;
547  logFlowControl( "released" ) ;
548 
549  bool all_sent = rawSendImp( m_segments , m_raw_pos , m_raw_pos ) ;
550  if( !all_sent && failed() )
551  {
552  m_segments.clear() ;
553  m_raw_pos = Position() ;
554  m_raw_copy.clear() ;
555  throw SocketProtocol::SendError() ;
556  }
557  if( all_sent )
558  {
559  m_segments.clear() ;
560  m_raw_pos = Position() ;
561  m_raw_copy.clear() ;
562  }
563  else
564  {
565  m_socket.addWriteHandler( m_handler ) ;
566  logFlowControl( "reasserted" ) ;
567  }
568  return all_sent ;
569 }
570 
571 bool GNet::SocketProtocolImp::rawSendImp( const Segments & segments , Position pos , Position & pos_out )
572 {
573  while( !finished(segments,pos) )
574  {
575  const char * chunk_data = chunk_p( segments , pos ) ;
576  size_t chunk_size = chunk_n( segments , pos ) ;
577 
578  ssize_t rc = m_socket.write( chunk_data , chunk_size ) ;
579  if( rc < 0 && ! m_socket.eWouldBlock() )
580  {
581  // fatal error, eg. disconnection
582  m_failed = true ;
583  pos_out = Position() ;
584  return false ; // failed()
585  }
586  else if( rc < 0 || static_cast<size_t>(rc) < chunk_size )
587  {
588  // flow control asserted -- return the position where we stopped
589  size_t nsent = rc > 0 ? static_cast<size_t>(rc) : 0U ;
590  pos_out = position( segments , pos , nsent ) ;
591  G_ASSERT( !finished(segments,pos_out) ) ;
592  return false ; // not all sent
593  }
594  else
595  {
596  pos = position( segments , pos , static_cast<size_t>(rc) ) ;
597  }
598  }
599  return true ; // all sent
600 }
601 
602 bool GNet::SocketProtocolImp::failed() const
603 {
604  return m_failed ;
605 }
606 
607 void GNet::SocketProtocolImp::logSecure( const std::string & certificate ) const
608 {
609  std::pair<std::string,bool> rc( std::string() , false ) ;
611  rc = GNet::Monitor::instance()->findCertificate( certificate ) ;
612  if( rc.second ) // is new
613  logCertificate( rc.first , certificate ) ;
614 
615  G_LOG( "GNet::SocketProtocolImp: tls/ssl protocol established with "
616  << m_socket.getPeerAddress().second.displayString()
617  << (rc.first.empty()?"":" certificate ") << rc.first ) ;
618 }
619 
620 void GNet::SocketProtocolImp::logCertificate( const std::string & certid , const std::string & certificate ) const
621 {
622  G::StringArray lines ;
623  lines.reserve( 30U ) ;
624  G::Str::splitIntoFields( certificate , lines , "\n" ) ;
625  for( G::StringArray::iterator line_p = lines.begin() ; line_p != lines.end() ; ++line_p )
626  {
627  if( !(*line_p).empty() )
628  {
629  G_LOG( "GNet::SocketProtocolImp: certificate " << certid << ": " << *line_p ) ;
630  }
631  }
632 }
633 
634 void GNet::SocketProtocolImp::logFlowControl( const char * what )
635 {
636  const bool log = G::Test::enabled("log-flow-control") ;
637  if( log )
638  G_LOG( "GNet::SocketProtocolImp::send: @" << m_socket.asString() << ": flow control " << what ) ;
639 }
640 
641 std::string GNet::SocketProtocolImp::peerCertificate() const
642 {
643  return m_peer_certificate ;
644 }
645 
646 //
647 
649  unsigned int secure_connection_timeout ) :
650  m_imp( new SocketProtocolImp(handler,sink,socket,secure_connection_timeout) )
651 {
652 }
653 
655 {
656  delete m_imp ;
657 }
658 
660 {
661  m_imp->readEvent() ;
662 }
663 
665 {
666  return m_imp->writeEvent() ;
667 }
668 
669 bool GNet::SocketProtocol::send( const std::string & data , size_t offset )
670 {
671  return m_imp->send( data , offset ) ;
672 }
673 
674 bool GNet::SocketProtocol::send( const std::vector<std::pair<const char *,size_t> > & data )
675 {
676  return m_imp->send( data ) ;
677 }
678 
680 {
681  return GSsl::Library::instance() != nullptr && GSsl::Library::instance()->enabled() ;
682 }
683 
685 {
686  m_imp->sslConnect() ;
687 }
688 
690 {
691  m_imp->sslAccept() ;
692 }
693 
695 {
696  return m_imp->sslEnabled() ;
697 }
698 
700 {
701  return m_imp->peerCertificate() ;
702 }
703 
704 //
705 
707 {
708 }
709 
static Library * instance()
Returns a pointer to a library object, if any.
Definition: gssl_none.cpp:46
An interface to an underlying TLS library.
static std::string printable(const std::string &in, char escape= '\\')
Returns a printable represention of the given input string.
Definition: gstr.cpp:663
void readEvent()
Called on receipt of a read event.
virtual bool eWouldBlock()
Returns true if the previous socket operation failed because the socket would have blocked...
void addWriteHandler(EventHandler &handler)
Adds this socket to the event source list so that the given handler receives write events when flow c...
Definition: gsocket.cpp:233
virtual void onData(const char *, size_t)=0
Called when data is read from the socket.
A TLS protocol class.
Definition: gssl.h:65
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstrings.h:33
static std::string str(Result result)
Converts a result enumeration into a printable string.
Definition: gssl_none.cpp:115
virtual ~SocketProtocolSink()
Destructor.
virtual void onSecure(const std::string &peer_certificate)=0
Called once the secure socket protocol has been successfully negotiated.
void sslAccept()
Accepts the TLS/SSL protocol.
std::pair< std::string, bool > peerCertificate(int format=0)
Returns the peer certificate and a verified flag.
Definition: gssl_none.cpp:120
A pimple-pattern implementation class used by GNet::SocketProtocol.
void dropWriteHandler()
Reverses addWriteHandler().
Definition: gsocket.cpp:245
std::pair< bool, Address > getPeerAddress() const
Retrieves address of socket's peer.
Definition: gsocket.cpp:212
std::string peerCertificate() const
Returns the peer's TLS/SSL certificate or the empty string.
A derivation of GNet::Socket for a stream socket.
Definition: gsocket.h:245
~SocketProtocol()
Destructor.
static bool enabled()
Returns true if test features are enabled.
Definition: gtest.cpp:49
Result accept(G::ReadWrite &io)
Starts the protocol passively (as a server).
Definition: gssl_none.cpp:95
static Monitor * instance()
Returns the singleton pointer. Returns null if none.
Definition: gmonitor.cpp:114
Result connect(G::ReadWrite &io)
Starts the protocol actively (as a client).
Definition: gssl_none.cpp:90
bool send(const std::string &data, size_t offset=0U)
Sends data.
const Profile & profile(const std::string &profile_name) const
Returns an opaque reference to the named profile.
Definition: gssl_none.cpp:60
SocketProtocol(EventHandler &, Sink &, StreamSocket &, unsigned int secure_connection_timeout)
Constructor. The references are kept.
A base class for classes that handle asynchronous events from the event loop.
Definition: geventhandler.h:78
virtual ssize_type read(char *buffer, size_type buffer_length)
Override from Socket::read().
Definition: gsocket.cpp:297
A pointer into the scatter/gather payload of GNet::SocketProtocolImp::send().
virtual ssize_type write(const char *buf, size_type len)
Override from Socket::write().
Definition: gsocket.cpp:312
static bool sslCapable()
Returns true if the implementation supports TLS/SSL.
void sslConnect()
Initiates the TLS/SSL protocol.
A general-purpose exception class derived from std::exception and containing a std::string.
Definition: gexception.h:43
Result read(char *buffer, size_type buffer_size_in, ssize_type &data_size_out)
Reads user data into the supplied buffer.
Definition: gssl_none.cpp:105
std::pair< std::string, bool > findCertificate(const std::string &certificate)
Returns a short id for the given certificate and a boolean flag to indicate if it is a new certificat...
Definition: gmonitor.cpp:149
A singleton class for initialising the underlying TLS library.
Definition: gssl.h:157
bool enabled() const
Returns true if this is a real TLS library and the constructor's active parameter was set...
Definition: gssl_none.cpp:65
Result write(const char *buffer, size_type data_size_in, ssize_type &data_size_out)
Writes user data.
Definition: gssl_none.cpp:110
A timer class template in which the timeout is delivered to the specified method. ...
Definition: gtimer.h:110
to deliver data from a socket.
bool sslEnabled() const
Returns true if TLS/SSL is active.
bool writeEvent()
Called on receipt of a write event.
std::string asString() const
Returns the socket handle as a string.
Definition: gsocket.cpp:255
static void splitIntoFields(const std::string &in, StringArray &out, const std::string &seperators, char escape= '\0', bool remove_escapes=true)
Splits the string into fields.
Definition: gstr.cpp:921