E-MailRelay

gsocket.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2021 Graeme Walker <graeme_walker@users.sourceforge.net>
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/// \file gsocket.cpp
19///
20
21#include "gdef.h"
22#include "gsocket.h"
23#include "gtest.h"
24#include "gsleep.h"
25#include "gmsg.h"
26#include "gstr.h"
27#include "gassert.h"
28#include "glog.h"
29
30 namespace GNet
31{
32 namespace StreamSocketImp /// An implementation namespace for G::StreamSocket.
33 {
34 struct Options /// StreamSocket options.
35 {
36 enum class Linger { default_ , zero , nolinger } ;
37 Linger create_linger {Linger::nolinger} ;
38 bool create_keepalive { G::Test::enabled("socket-keepalive") } ;
39 Linger accept_linger {Linger::nolinger} ;
40 bool accept_keepalive { G::Test::enabled("socket-keepalive") } ;
41 } ;
42 }
43 namespace SocketImp /// An implementation namespace for G::Socket.
44 {
45 struct Options /// Socket options.
46 {
47 bool connect_pureipv6 {true} ;
48 bool bind_pureipv6 {true} ;
49 bool bind_reuse {true} ;
50 bool bind_exclusive { G::Test::enabled("socket-exclusive") } ;
51 } ;
52 }
53}
54
55// ==
56
57 GNet::SocketBase::SocketBase( Address::Family family , int type , int protocol ) :
58 m_reason(0) ,
59 m_domain(Address::domain(family)) ,
60 m_family(family) ,
61 m_added(false) ,
62 m_accepted(false)
63{
64 if( !create(m_domain,type,protocol) )
65 throw SocketCreateError( "cannot create socket" , reason() ) ;
66
67 if( !prepare(false) )
68 {
69 destroy() ;
70 throw SocketError( "cannot prepare socket" , reason() ) ;
71 }
72}
73
74 GNet::SocketBase::SocketBase( const SocketBase::Raw & , int domain , int type , int protocol ) :
75 m_reason(0) ,
76 m_domain(domain) ,
77 m_family(Address::Family::local) , // bogus value, see isFamily()
78 m_added(false) ,
79 m_accepted(false)
80{
81 G_ASSERT( !Address::supports( Address::Domain() , domain ) ) ;
82
83 if( !create(domain,type,protocol) )
84 throw SocketCreateError( "cannot create socket" , reason() ) ;
85
86 if( !prepare(false) )
87 {
88 destroy() ;
89 throw SocketError( "cannot prepare socket" , reason() ) ;
90 }
91}
92
93 GNet::SocketBase::SocketBase( Address::Family family , Descriptor fd ) :
94 m_reason(0) ,
95 m_domain(Address::domain(family)) ,
96 m_family(family) ,
97 m_fd(fd) ,
98 m_added(false) ,
99 m_accepted(false)
100{
101 if( !prepare(false) )
102 {
103 destroy() ;
104 throw SocketError( "cannot prepare socket" , reason() ) ;
105 }
106}
107
108 GNet::SocketBase::SocketBase( Address::Family family , Descriptor fd , const Accepted & ) :
109 m_reason(0) ,
110 m_domain(Address::domain(family)) ,
111 m_family(family) ,
112 m_fd(fd) ,
113 m_added(false) ,
114 m_accepted(true)
115{
116 if( !prepare(true) )
117 {
118 destroy() ;
119 throw SocketError( "cannot prepare socket" , reason() ) ;
120 }
121}
122
123 GNet::SocketBase::~SocketBase()
124{
125 drop() ;
126 destroy() ;
127}
128
129 bool GNet::SocketBase::isFamily( Address::Family family ) const
130{
131 // note that raw sockets to not have a family supported by
132 // GNet::Address and their m_address field is bogus
133 return Address::supports(Address::Domain(),m_domain) && family == m_family ;
134}
135
136 void GNet::SocketBase::drop() noexcept
137{
138 dropReadHandler() ;
139 dropWriteHandler() ;
140 dropOtherHandler() ;
141}
142
143 void GNet::SocketBase::clearReason()
144{
145 m_reason = 0 ;
146}
147
148 void GNet::SocketBase::saveReason() const
149{
150 const_cast<GNet::SocketBase*>(this)->saveReason() ;
151}
152
153GNet::SocketBase::ssize_type GNet::SocketBase::writeImp( const char * buffer , size_type length )
154{
155 if( static_cast<ssize_type>(length) < 0 )
156 G_WARNING( "GNet::SocketBase::writeImp: too big" ) ; // should get EMSGSIZE from ::send()
157
158 ssize_type nsent = G::Msg::send( m_fd.fd() , buffer , length , MSG_NOSIGNAL ) ;
159 if( sizeError(nsent) ) // if -1
160 {
161 saveReason() ;
162 G_DEBUG( "GNet::SocketBase::writeImp: write error: " << reason() ) ;
163 return -1 ;
164 }
165 else if( nsent < 0 || static_cast<size_type>(nsent) < length )
166 {
167 saveReason() ;
168 }
169 return nsent;
170}
171
172 void GNet::SocketBase::addReadHandler( EventHandler & handler , ExceptionSink es )
173{
174 G_DEBUG( "GNet::SocketBase::addReadHandler: fd " << m_fd ) ;
175 EventLoop::instance().addRead( m_fd , handler , es ) ;
176 m_added = true ;
177}
178
179 void GNet::SocketBase::addWriteHandler( EventHandler & handler , ExceptionSink es )
180{
181 G_DEBUG( "GNet::SocketBase::addWriteHandler: fd " << m_fd ) ;
182 EventLoop::instance().addWrite( m_fd , handler , es ) ;
183 m_added = true ;
184}
185
186 void GNet::SocketBase::addOtherHandler( EventHandler & handler , ExceptionSink es )
187{
188 G_DEBUG( "GNet::SocketBase::addOtherHandler: fd " << m_fd ) ;
189 EventLoop::instance().addOther( m_fd , handler , es ) ;
190 m_added = true ;
191}
192
193 void GNet::SocketBase::dropReadHandler() noexcept
194{
195 if( m_added && EventLoop::ptr() )
196 EventLoop::ptr()->dropRead( m_fd ) ;
197}
198
199 void GNet::SocketBase::dropWriteHandler() noexcept
200{
201 if( m_added && EventLoop::ptr() )
202 EventLoop::ptr()->dropWrite( m_fd ) ;
203}
204
205 void GNet::SocketBase::dropOtherHandler() noexcept
206{
207 if( m_added && EventLoop::ptr() )
208 EventLoop::ptr()->dropOther( m_fd ) ;
209}
210
211SOCKET GNet::SocketBase::fd() const noexcept
212{
213 return m_fd.fd() ;
214}
215
216std::string GNet::SocketBase::reason() const
217{
218 if( m_reason == 0 ) return {} ;
219 return reasonString( m_reason ) ;
220}
221
222std::string GNet::SocketBase::asString() const
223{
224 std::ostringstream ss ;
225 ss << m_fd ;
226 return ss.str() ;
227}
228
229// ==
230
231GNet::Socket::Socket( Address::Family af , int type , int protocol ) :
232 SocketBase(af,type,protocol)
233{
234}
235
236GNet::Socket::Socket( Address::Family af , Descriptor s , const Accepted & a ) :
237 SocketBase(af,s,a)
238{
239}
240
241 void GNet::Socket::bind( const Address & local_address )
242{
243 G_DEBUG( "Socket::bind: binding " << local_address.displayString() << " on fd " << fd() ) ;
244
245 if( !isFamily( local_address.family() ) )
246 throw SocketBindError( "address family does not match the socket domain" ) ;
247
248 setOptionsOnBind( local_address.family() ) ;
249
250 int rc = ::bind( fd() , local_address.address() , local_address.length() ) ;
251 if( error(rc) )
252 {
253 saveReason() ;
254 throw SocketBindError( local_address.displayString() , reason() ) ;
255 }
256 m_bound_scope_id = local_address.scopeId() ;
257}
258
259 bool GNet::Socket::bind( const Address & local_address , std::nothrow_t )
260{
261 G_DEBUG( "Socket::bind: binding " << local_address.displayString() << " on fd " << fd() ) ;
262 if( !isFamily( local_address.family() ) )
263 return false ;
264
265 setOptionsOnBind( local_address.family() ) ;
266
267 int rc = ::bind( fd() , local_address.address() , local_address.length() ) ;
268 if( error(rc) )
269 {
270 saveReason() ;
271 return false ;
272 }
273 m_bound_scope_id = local_address.scopeId() ;
274 return true ;
275}
276
277 unsigned long GNet::Socket::getBoundScopeId() const
278{
279 return m_bound_scope_id ;
280}
281
282 bool GNet::Socket::connect( const Address & address , bool * done )
283{
284 G_DEBUG( "GNet::Socket::connect: connecting to " << address.displayString() ) ;
285 if( !isFamily( address.family() ) )
286 {
287 G_WARNING( "GNet::Socket::connect: cannot connect: address family does not match the socket domain" ) ;
288 return false ;
289 }
290
291 setOptionsOnConnect( address.family() ) ;
292
293 int rc = ::connect( fd() , address.address() , address.length() ) ;
294 if( error(rc) )
295 {
296 saveReason() ;
297
298 if( G::Test::enabled("socket-slow-connect") )
299 sleep( 1 ) ;
300
301 if( eInProgress() )
302 {
303 G_DEBUG( "GNet::Socket::connect: connection in progress" ) ;
304 if( done != nullptr ) *done = false ;
305 return true ;
306 }
307
308 G_DEBUG( "GNet::Socket::connect: synchronous connect failure: " << reason() ) ;
309 return false;
310 }
311
312 if( done != nullptr ) *done = true ;
313 return true ;
314}
315
316 void GNet::Socket::listen( int backlog )
317{
318 int rc = ::listen( fd() , backlog ) ;
319 if( error(rc) )
320 {
321 saveReason() ;
322 throw SocketError( "cannot listen on socket" , reason() ) ;
323 }
324}
325
326 GNet::Address GNet::Socket::getLocalAddress() const
327{
328 AddressStorage address_storage ;
329 int rc = ::getsockname( fd() , address_storage.p1() , address_storage.p2() ) ;
330 if( error(rc) )
331 {
332 saveReason() ;
333 throw SocketError( "getsockname" , reason() ) ;
334 }
335 return Address( address_storage ) ;
336}
337
338std::pair<bool,GNet::Address> GNet::Socket::getPeerAddress() const
339{
340 AddressStorage address_storage ;
341 int rc = ::getpeername( fd() , address_storage.p1() , address_storage.p2() ) ;
342 if( error(rc) )
343 {
344 saveReason() ;
345 if( eNotConn() )
346 return { false , Address::defaultAddress() } ;
347 throw SocketError( "getpeername" , reason() ) ;
348 }
349 return { true , Address(address_storage) } ;
350}
351
352 void GNet::Socket::shutdown( int how )
353{
354 if( G::Test::enabled("socket-no-shutdown") ) return ;
355 ::shutdown( fd() , how ) ;
356}
357
358 void GNet::Socket::setOptionsOnConnect( Address::Family af )
359{
360 if( af == Address::Family::ipv4 || af == Address::Family::ipv6 )
361 {
362 using namespace SocketImp ;
363 Options options ;
364 if( af == Address::Family::ipv6 && options.connect_pureipv6 )
365 setOptionPureV6( std::nothrow ) ; // ignore errors - may fail if already bound
366 }
367}
368
369 void GNet::Socket::setOptionsOnBind( Address::Family af )
370{
371 if( af == Address::Family::ipv4 || af == Address::Family::ipv6 )
372 {
373 using namespace SocketImp ;
374 Options options ;
375 if( options.bind_reuse )
376 setOptionReuse() ; // allow us to rebind another socket's (eg. time-wait zombie's) address
377 if( options.bind_exclusive )
378 setOptionExclusive() ; // don't allow anyone else to bind our address
379 if( af == Address::Family::ipv6 && options.bind_pureipv6 )
380 setOptionPureV6() ;
381 }
382}
383
384 void GNet::Socket::setOptionKeepAlive()
385{
386 setOption( SOL_SOCKET , "so_keepalive" , SO_KEEPALIVE , 1 ) ;
387}
388
389 void GNet::Socket::setOptionNoLinger()
390{
391 setOptionLingerImp( 0 , 0 ) ;
392}
393
394 void GNet::Socket::setOptionLingerImp( int onoff , int time )
395{
396 struct linger options {} ;
397 options.l_onoff = onoff ;
398 options.l_linger = time ;
399 bool ok = setOptionImp( SOL_SOCKET , SO_LINGER , &options , sizeof(options) ) ;
400 if( !ok )
401 {
402 saveReason() ;
403 throw SocketError( "cannot set no_linger" , reason() ) ;
404 }
405}
406
407 bool GNet::Socket::setOption( int level , const char * , int op , int arg , std::nothrow_t )
408{
409 const void * const vp = static_cast<const void*>(&arg) ;
410 bool ok = setOptionImp( level , op , vp , sizeof(int) ) ;
411 if( !ok )
412 saveReason() ;
413 return ok ;
414}
415
416 void GNet::Socket::setOption( int level , const char * opp , int op , int arg )
417{
418 if( !setOption( level , opp , op , arg , std::nothrow ) )
419 throw SocketError( opp , reason() ) ;
420}
421
422//==
423
424 bool GNet::StreamSocket::supports( Address::Family af )
425{
426 if( af == Address::Family::ipv6 )
427 {
428 static bool first = true ;
429 static bool result = false ;
430 if( first )
431 {
432 first = false ;
433 if( !Address::supports(af) )
434 G_WARNING( "GNet::StreamSocket::supports: no ipv6 support built-in" ) ;
435 else if( !SocketBase::supports(af,SOCK_STREAM,0) )
436 G_WARNING( "GNet::StreamSocket::supports: no ipv6 support detected" ) ;
437 else
438 result = true ;
439 }
440 return result ;
441 }
442 else if( af == Address::Family::local )
443 {
444 return Address::supports( af ) ;
445 }
446 else
447 {
448 return true ; // ipv4 always supported
449 }
450}
451
452 GNet::StreamSocket::StreamSocket( Address::Family af ) :
453 Socket(af,SOCK_STREAM,0)
454{
455 setOptionsOnCreate( af , /*listener=*/false ) ;
456}
457
458 GNet::StreamSocket::StreamSocket( Address::Family af , const Listener & ) :
459 Socket(af,SOCK_STREAM,0)
460{
461 setOptionsOnCreate( af , /*listener=*/true ) ;
462}
463
464 GNet::StreamSocket::StreamSocket( Address::Family af , Descriptor s , const Accepted & accepted ) :
465 Socket(af,s,accepted)
466{
467 setOptionsOnAccept( af ) ;
468}
469
470GNet::Socket::ssize_type GNet::StreamSocket::read( char * buffer , size_type length )
471{
472 if( length == 0 ) return 0 ;
473 clearReason() ;
474 ssize_type nread = G::Msg::recv( fd() , buffer , length , 0 ) ;
475 if( sizeError(nread) )
476 {
477 saveReason() ;
478 G_DEBUG( "GNet::StreamSocket::read: cannot read from " << fd() ) ;
479 return -1 ;
480 }
481 return nread ;
482}
483
484GNet::Socket::ssize_type GNet::StreamSocket::write( const char * buffer , size_type length )
485{
486 return writeImp( buffer , length ) ; // SocketBase
487}
488
489 GNet::AcceptPair GNet::StreamSocket::accept()
490{
491 AddressStorage addr ;
492 Descriptor new_fd( ::accept(fd(),addr.p1(),addr.p2()) ) ;
493 if( ! new_fd.valid() )
494 {
495 saveReason() ;
496 if( eTooMany() )
497 throw SocketTooMany( "cannot accept on listening socket" , reason() ) ;
498 else
499 throw SocketError( "cannot accept on listening socket" , reason() ) ;
500 }
501
502 if( G::Test::enabled("socket-accept-throws") )
503 throw SocketError( "testing" ) ;
504
505 AcceptPair info ;
506 info.address = Address( addr ) ;
507 info.socket_ptr.reset( new StreamSocket( info.address.family() , new_fd , SocketBase::Accepted() ) ) ; // 'new' for access
508
509 G_DEBUG( "GNet::StreamSocket::accept: accepted from " << fd()
510 << " to " << new_fd << " (" << info.address.displayString() << ")" ) ;
511
512 return info ;
513}
514
515 void GNet::StreamSocket::setOptionsOnCreate( Address::Family af , bool /*listener*/ )
516{
517 if( af == Address::Family::ipv4 || af == Address::Family::ipv6 )
518 {
519 using namespace StreamSocketImp ;
520 Options options ;
521 if( options.create_linger == Options::Linger::zero )
522 setOptionLingerImp( 1 , 0 ) ;
523 else if( options.create_linger == Options::Linger::nolinger )
524 setOptionNoLinger() ;
525 if( options.create_keepalive )
526 setOptionKeepAlive() ;
527 }
528}
529
530 void GNet::StreamSocket::setOptionsOnAccept( Address::Family af )
531{
532 if( af == Address::Family::ipv4 || af == Address::Family::ipv6 )
533 {
534 using namespace StreamSocketImp ;
535 Options options ;
536 if( options.accept_linger == Options::Linger::zero )
537 setOptionLingerImp( 1 , 0 ) ;
538 else if( options.accept_linger == Options::Linger::nolinger )
539 setOptionNoLinger() ;
540 if( options.accept_keepalive )
541 setOptionKeepAlive() ;
542 }
543}
544
545//==
546
547 GNet::DatagramSocket::DatagramSocket( Address::Family af , int protocol ) :
548 Socket( af , SOCK_DGRAM , protocol )
549{
550}
551
552 void GNet::DatagramSocket::disconnect()
553{
554 int rc = ::connect( fd() , nullptr , 0 ) ;
555 if( error(rc) )
556 saveReason() ;
557}
558
559GNet::Socket::ssize_type GNet::DatagramSocket::read( char * buffer , size_type length )
560{
561 if( length == 0 ) return 0 ;
562 sockaddr sender {} ; // not used
563 socklen_t sender_len = sizeof(sender) ;
564 ssize_type nread = G::Msg::recvfrom( fd() , buffer , length , 0 , &sender , &sender_len ) ;
565 if( sizeError(nread) )
566 {
567 saveReason() ;
568 return -1 ;
569 }
570 return nread ;
571}
572
573GNet::Socket::ssize_type GNet::DatagramSocket::readfrom( char * buffer , size_type length , Address & src_address )
574{
575 if( length == 0 ) return 0 ;
576 sockaddr sender {} ;
577 socklen_t sender_len = sizeof(sender) ;
578 ssize_type nread = G::Msg::recvfrom( fd() , buffer , length , 0 , &sender , &sender_len ) ;
579 if( sizeError(nread) )
580 {
581 saveReason() ;
582 return -1 ;
583 }
584 src_address = Address( &sender , sender_len ) ;
585 return nread ;
586}
587
588GNet::Socket::ssize_type GNet::DatagramSocket::writeto( const char * buffer , size_type length , const Address & dst )
589{
590 ssize_type nsent = G::Msg::sendto( fd() , buffer , length , MSG_NOSIGNAL , dst.address() , dst.length() ) ;
591 if( nsent < 0 )
592 {
593 saveReason() ;
594 G_DEBUG( "GNet::DatagramSocket::write: write error " << reason() ) ;
595 return -1 ;
596 }
597 return nsent ;
598}
599
600GNet::Socket::ssize_type GNet::DatagramSocket::write( const char * buffer , size_type length )
601{
602 return writeImp( buffer , length ) ; // SocketBase
603}
604
GNet::AcceptPair
A class which is used to return a new()ed socket to calling code, together with associated address in...
Definition: gsocket.h:300
GNet::AddressStorage
A helper class for calling accept(), getsockname() and getpeername() and hiding the definition of soc...
Definition: gaddress.h:296
GNet::AddressStorage::p1
sockaddr * p1()
Returns the sockaddr pointer for accept()/getsockname()/getpeername() to write into.
Definition: gaddress.cpp:549
GNet::AddressStorage::p2
socklen_t * p2()
Returns the length pointer for accept()/getsockname()/getpeername() to write into.
Definition: gaddress.cpp:554
GNet::Address
The GNet::Address class encapsulates a TCP/UDP transport address.
Definition: gaddress.h:53
GNet::Address::family
Family family() const
Returns the address family enumeration.
Definition: gaddress.cpp:491
GNet::Address::supports
static bool supports(Family)
Returns true if the implementation supports the given address family.
Definition: gaddress.cpp:33
GNet::Address::length
socklen_t length() const
Returns the size of the sockaddr address. See address().
Definition: gaddress.cpp:443
GNet::Address::defaultAddress
static Address defaultAddress()
Returns a default address, being the IPv4 wildcard address with a zero port number.
Definition: gaddress.cpp:242
GNet::Address::displayString
std::string displayString(bool with_scope_id=false) const
Returns a string which represents the transport address.
Definition: gaddress.cpp:375
GNet::Address::address
const sockaddr * address() const
Returns the sockaddr address.
Definition: gaddress.cpp:434
GNet::Address::scopeId
unsigned long scopeId(unsigned long default_=0UL) const
Returns the scope-id.
Definition: gaddress.cpp:461
GNet::DatagramSocket::writeto
ssize_type writeto(const char *buffer, size_type len, const Address &dst)
Sends a datagram to the given address.
Definition: gsocket.cpp:588
GNet::DatagramSocket::DatagramSocket
DatagramSocket(Address::Family, int protocol=0)
Constructor.
Definition: gsocket.cpp:547
GNet::DatagramSocket::write
ssize_type write(const char *buffer, size_type len) override
Override from Socket::write().
Definition: gsocket.cpp:600
GNet::DatagramSocket::read
ssize_type read(char *buffer, size_type len) override
Override from ReadWrite::read().
Definition: gsocket.cpp:559
GNet::DatagramSocket::disconnect
void disconnect()
Releases the association between two datagram endpoints reversing the effect of the previous Socket::...
Definition: gsocket.cpp:552
GNet::DatagramSocket::readfrom
ssize_type readfrom(char *buffer, size_type len, Address &src)
Reads a datagram and returns the sender's address by reference.
Definition: gsocket.cpp:573
GNet::Descriptor
A class that encapsulates a network socket file descriptor and an associated windows event handle.
Definition: gdescriptor.h:37
GNet::Descriptor::valid
bool valid() const noexcept
Returns true if the socket part is valid, ignoring the handle.
Definition: gdescriptor_unix.cpp:29
GNet::EventHandler
A base class for classes that handle asynchronous events from the event loop.
Definition: geventhandler.h:48
GNet::EventLoop::dropWrite
virtual void dropWrite(Descriptor fd) noexcept=0
Removes the given event source descriptor from the list of write sources.
GNet::EventLoop::dropRead
virtual void dropRead(Descriptor fd) noexcept=0
Removes the given event source descriptor from the list of read sources.
GNet::EventLoop::ptr
static EventLoop * ptr() noexcept
Returns a pointer to an instance of the class, if any.
Definition: geventloop.cpp:42
GNet::EventLoop::addOther
virtual void addOther(Descriptor fd, EventHandler &, ExceptionSink)=0
Adds the given event source descriptor and associated handler to the exception list.
GNet::EventLoop::addWrite
virtual void addWrite(Descriptor fd, EventHandler &, ExceptionSink)=0
Adds the given event source descriptor and associated handler to the write list.
GNet::EventLoop::instance
static EventLoop & instance()
Returns a reference to an instance of the class, if any.
Definition: geventloop.cpp:47
GNet::EventLoop::addRead
virtual void addRead(Descriptor fd, EventHandler &, ExceptionSink)=0
Adds the given event source descriptor and associated handler to the read list.
GNet::EventLoop::dropOther
virtual void dropOther(Descriptor fd) noexcept=0
Removes the given event source descriptor from the list of exception sources.
GNet::ExceptionSink
A tuple containing an ExceptionHandler interface pointer and a bound 'exception source' pointer.
Definition: gexceptionsink.h:100
GNet::SocketBase
A socket base class that holds a non-blocking socket file descriptor and interfaces to the event loop...
Definition: gsocket.h:52
GNet::SocketBase::~SocketBase
~SocketBase() override
Destructor.
Definition: gsocket.cpp:123
GNet::SocketBase::reason
std::string reason() const
Returns the reason for the previous error.
Definition: gsocket.cpp:216
GNet::SocketBase::fd
SOCKET fd() const noexcept override
Returns the socket file descriptor.
Definition: gsocket.cpp:211
GNet::SocketBase::clearReason
void clearReason()
Clears the saved errno.
Definition: gsocket.cpp:143
GNet::SocketBase::asString
std::string asString() const
Returns the socket handle as a string.
Definition: gsocket.cpp:222
GNet::SocketBase::dropReadHandler
void dropReadHandler() noexcept
Reverses addReadHandler().
Definition: gsocket.cpp:193
GNet::SocketBase::addOtherHandler
void addOtherHandler(EventHandler &, ExceptionSink)
Adds this socket to the event source list so that the given handler receives exception events.
Definition: gsocket.cpp:186
GNet::SocketBase::SocketBase
SocketBase(Address::Family, int type, int protocol)
Constructor used by derived classes.
Definition: gsocket.cpp:57
GNet::SocketBase::isFamily
bool isFamily(Address::Family) const
Returns true if the socket family is as given.
Definition: gsocket.cpp:129
GNet::SocketBase::addReadHandler
void addReadHandler(EventHandler &, ExceptionSink)
Adds this socket to the event source list so that the given handler receives read events.
Definition: gsocket.cpp:172
GNet::SocketBase::supports
static bool supports(Address::Family, int type, int protocol)
Returns true if sockets can be created with the given parameters.
Definition: gsocket_unix.cpp:34
GNet::SocketBase::addWriteHandler
void addWriteHandler(EventHandler &, ExceptionSink)
Adds this socket to the event source list so that the given handler receives write events when flow c...
Definition: gsocket.cpp:179
GNet::SocketBase::dropOtherHandler
void dropOtherHandler() noexcept
Reverses addOtherHandler().
Definition: gsocket.cpp:205
GNet::SocketBase::writeImp
ssize_type writeImp(const char *buf, size_type len)
Writes to the socket.
Definition: gsocket.cpp:153
GNet::SocketBase::dropWriteHandler
void dropWriteHandler() noexcept
Reverses addWriteHandler().
Definition: gsocket.cpp:199
GNet::SocketBase::saveReason
void saveReason()
Saves the current errno following error()/sizeError().
Definition: gsocket_unix.cpp:100
GNet::Socket
An internet-protocol socket class.
Definition: gsocket.h:206
GNet::Socket::connect
bool connect(const Address &addr, bool *done=nullptr)
Initiates a connection to (or association with) the given address.
Definition: gsocket.cpp:282
GNet::Socket::shutdown
void shutdown(int how=1)
Modifies the local socket state so that so that new sends (1 or 2) and/or receives (0 or 2) will fail...
Definition: gsocket.cpp:352
GNet::Socket::bind
void bind(const Address &)
Binds the socket with the given address.
Definition: gsocket.cpp:241
GNet::Socket::getBoundScopeId
unsigned long getBoundScopeId() const
Returns the scope-id of the address last successfully bind()ed.
Definition: gsocket.cpp:277
GNet::Socket::getPeerAddress
std::pair< bool, Address > getPeerAddress() const
Retrieves address of socket's peer.
Definition: gsocket.cpp:338
GNet::Socket::listen
void listen(int backlog=1)
Starts the socket listening on the bound address for incoming connections or incoming datagrams.
Definition: gsocket.cpp:316
GNet::Socket::getLocalAddress
Address getLocalAddress() const
Retrieves local address of the socket.
Definition: gsocket.cpp:326
GNet::StreamSocket
A derivation of GNet::Socket for a stream socket.
Definition: gsocket.h:311
GNet::StreamSocket::write
ssize_type write(const char *buf, size_type len) override
Override from Socket::write().
Definition: gsocket.cpp:484
GNet::StreamSocket::accept
AcceptPair accept()
Accepts an incoming connection, returning a new()ed socket and the peer address.
Definition: gsocket.cpp:489
GNet::StreamSocket::StreamSocket
StreamSocket(Address::Family)
Constructor.
Definition: gsocket.cpp:452
GNet::StreamSocket::read
ssize_type read(char *buffer, size_type buffer_length) override
Override from ReadWrite::read().
Definition: gsocket.cpp:470
GNet::StreamSocket::supports
static bool supports(Address::Family)
Returns true if stream sockets can be created with the given the address family.
Definition: gsocket.cpp:424
G::Msg::recvfrom
static ssize_t recvfrom(SOCKET, void *, std::size_t, int flags, sockaddr *, socklen_t *)
A recvfrom() replacement using recvmsg().
Definition: gmsg_unix.cpp:50
G::Msg::recv
static ssize_t recv(SOCKET, void *, std::size_t, int flags)
A recv() wrapper.
Definition: gmsg_unix.cpp:45
G::Msg::send
static ssize_t send(SOCKET, const void *, std::size_t, int flags) noexcept
A send() replacement using sendmsg().
Definition: gmsg_unix.cpp:34
G::Msg::sendto
static ssize_t sendto(SOCKET, const void *, std::size_t, int flags, const sockaddr *, socklen_t) noexcept
A sendto() replacement using sendmsg().
Definition: gmsg_unix.cpp:39
G::Test::enabled
static bool enabled() noexcept
Returns true if test features are enabled.
Definition: gtest.cpp:79
gassert.h
glog.h
gmsg.h
gsleep.h
gsocket.h
gstr.h
gtest.h
GNet
Network classes.
Definition: gdef.h:1115
GNet::Address::Domain
Overload discriminator for Address::supports()
Definition: gaddress.h:62
GNet::SocketBase::Accepted
Overload discriminator class for GNet::SocketBase.
Definition: gsocket.h:61
GNet::SocketBase::Raw
Overload discriminator class for GNet::SocketBase.
Definition: gsocket.h:63
GNet::SocketImp::Options
Socket options.
Definition: gsocket.cpp:46
GNet::StreamSocketImp::Options
StreamSocket options.
Definition: gsocket.cpp:35
GNet::StreamSocket::Listener
Overload discriminator class for GNet::StreamSocket.
Definition: gsocket.h:316