33 m_domain(
Address::domain(family)) ,
36 m_write_added(false) ,
37 m_other_added(false) ,
40 if( !create(m_domain,type,protocol) )
41 throw SocketCreateError(
"cannot create socket" ,
reason() ) ;
46 throw SocketError(
"cannot prepare socket" ,
reason() ) ;
53 m_family(
Address::Family::local) ,
55 m_write_added(false) ,
56 m_other_added(false) ,
61 if( !create(domain,type,protocol) )
62 throw SocketCreateError(
"cannot create socket" ,
reason() ) ;
67 throw SocketError(
"cannot prepare socket" ,
reason() ) ;
73 m_domain(
Address::domain(family)) ,
77 m_write_added(false) ,
78 m_other_added(false) ,
84 throw SocketError(
"cannot prepare socket" ,
reason() ) ;
90 m_domain(
Address::domain(family)) ,
94 m_write_added(false) ,
95 m_other_added(false) ,
101 throw SocketError(
"cannot prepare socket" ,
reason() ) ;
118void GNet::SocketBase::drop() noexcept
120 static_assert(
noexcept(dropReadHandler()) ,
"" ) ;
136GNet::SocketBase::ssize_type GNet::SocketBase::writeImp(
const char * buffer , size_type length )
138 if(
static_cast<ssize_type
>(length) < 0 )
139 G_WARNING(
"GNet::SocketBase::writeImp: too big" ) ;
141 ssize_type nsent =
G::Msg::send( m_fd.fd() , buffer , length , MSG_NOSIGNAL ) ;
142 if( sizeError(nsent) )
145 G_DEBUG(
"GNet::SocketBase::writeImp: write error: " << reason() ) ;
148 else if( nsent < 0 ||
static_cast<size_type
>(nsent) < length )
157 G_DEBUG(
"GNet::SocketBase::addReadHandler: fd " << m_fd ) ;
160 m_read_added = true ;
165 G_DEBUG(
"GNet::SocketBase::addWriteHandler: fd " << m_fd ) ;
168 m_write_added = true ;
173 G_DEBUG(
"GNet::SocketBase::addOtherHandler: fd " << m_fd ) ;
176 m_other_added = true ;
183 m_read_added = false ;
190 m_write_added = false ;
197 m_other_added = false ;
214 if( m_reason == 0 )
return {} ;
215 return reasonString( m_reason ) ;
220 std::ostringstream ss ;
227GNet::Socket::Config::Config()
230GNet::Socket::Socket( Address::Family af ,
int type ,
int protocol ,
const Config & config ) :
236GNet::Socket::Socket( Address::Family af , Descriptor s ,
const Accepted & a ,
const Config & config ) :
242GNet::Socket::Socket( Address::Family af , Descriptor s ,
const Adopted & ,
const Config & config ) :
250 G_DEBUG(
"Socket::bind: binding " << local_address.
displayString() <<
" on fd " << fd() ) ;
252 if( !isFamily( local_address.
family() ) )
253 throw SocketBindError(
"address family does not match the socket domain" ) ;
255 setOptionsOnBind( local_address.
family() ) ;
257 int rc = ::bind( fd() , local_address.
address() , local_address.
length() ) ;
263 m_bound_scope_id = local_address.
scopeId() ;
268 G_DEBUG(
"Socket::bind: binding " << local_address.
displayString() <<
" on fd " << fd() ) ;
269 if( !isFamily( local_address.
family() ) )
272 setOptionsOnBind( local_address.
family() ) ;
274 int rc = ::bind( fd() , local_address.
address() , local_address.
length() ) ;
280 m_bound_scope_id = local_address.
scopeId() ;
286 return m_bound_scope_id ;
291 G_DEBUG(
"GNet::Socket::connect: connecting to " << address.
displayString() ) ;
292 if( !isFamily( address.
family() ) )
294 G_WARNING(
"GNet::Socket::connect: cannot connect: address family does not match the socket domain" ) ;
298 setOptionsOnConnect( address.
family() ) ;
300 int rc = ::connect( fd() , address.
address() , address.
length() ) ;
307 G_DEBUG(
"GNet::Socket::connect: connection in progress" ) ;
308 if( done !=
nullptr ) *done = false ;
312 G_DEBUG(
"GNet::Socket::connect: synchronous connect failure: " << reason() ) ;
316 if( done !=
nullptr ) *done = true ;
322 int listen_queue = m_config.listen_queue ;
323 if( listen_queue <= 0 )
326 int rc = ::listen( fd() , std::max(1,listen_queue) ) ;
330 throw SocketError(
"cannot listen on socket" , reason() ) ;
337 int rc = ::getsockname( fd.fd() , address_storage.
p1() , address_storage.
p2() ) ;
339 throw SocketError( std::string(
"no bound address on fd ").append(std::to_string(fd.fd())) ) ;
340 return Address( address_storage ) ;
346 int rc = ::getsockname( fd() , address_storage.
p1() , address_storage.
p2() ) ;
350 throw SocketError(
"getsockname" , reason() ) ;
352 return Address( address_storage ) ;
358 int rc = ::getpeername( fd() , address_storage.
p1() , address_storage.
p2() ) ;
364 throw SocketError(
"getpeername" , reason() ) ;
366 return { true ,
Address(address_storage) } ;
372 ::shutdown( fd() , how ) ;
375void GNet::Socket::setOptionsOnConnect( Address::Family af )
377 if( af == Address::Family::ipv4 || af == Address::Family::ipv6 )
379 if( af == Address::Family::ipv6 && m_config.connect_pureipv6 )
380 setOptionPureV6( std::nothrow ) ;
384void GNet::Socket::setOptionsOnBind( Address::Family af )
386 if( af == Address::Family::ipv4 || af == Address::Family::ipv6 )
388 if( m_config.bind_reuse )
390 if( m_config.bind_exclusive )
391 setOptionExclusive() ;
392 if( m_config.free_bind )
393 setOptionFreeBind() ;
394 if( af == Address::Family::ipv6 && m_config.bind_pureipv6 )
399void GNet::Socket::setOptionKeepAlive()
401 setOption( SOL_SOCKET ,
"so_keepalive" , SO_KEEPALIVE , 1 ) ;
404void GNet::Socket::setOptionFreeBind()
410void GNet::Socket::setOptionLinger(
int onoff ,
int time )
412 struct linger linger_config {} ;
413 linger_config.l_onoff =
static_cast<decltype(linger::l_onoff)
>(onoff) ;
414 linger_config.l_linger =
static_cast<decltype(linger::l_linger)
>(time) ;
415 bool ok = setOptionImp( SOL_SOCKET , SO_LINGER , &linger_config ,
sizeof(linger_config) ) ;
419 throw SocketError(
"cannot set socket linger option" , reason() ) ;
423bool GNet::Socket::setOption(
int level ,
const char * ,
int op ,
int arg , std::nothrow_t )
425 const void *
const vp =
static_cast<const void*
>(&arg) ;
426 bool ok = setOptionImp( level , op , vp ,
sizeof(
int) ) ;
432void GNet::Socket::setOption(
int level ,
const char * opp ,
int op ,
int arg )
434 if( !setOption( level , opp , op , arg , std::nothrow ) )
435 throw SocketError( opp , reason() ) ;
440GNet::StreamSocket::Config::Config()
443GNet::StreamSocket::Config::Config(
const Socket::Config & base ) :
450 if( af == Address::Family::ipv6 )
452 static bool first = true ;
453 static bool result = false ;
458 G_WARNING(
"GNet::StreamSocket::supports: no ipv6 support built-in" ) ;
460 G_WARNING(
"GNet::StreamSocket::supports: no ipv6 support detected" ) ;
466 else if( af == Address::Family::local )
477 Socket(af,SOCK_STREAM,0,config) ,
480 setOptionsOnCreate( af ,
false ) ;
484 Socket(af,SOCK_STREAM,0,config) ,
487 setOptionsOnCreate( af ,
true ) ;
497 Socket(af,fd,accepted,config) ,
500 setOptionsOnAccept( af ) ;
503GNet::Address::Family GNet::StreamSocket::family( Descriptor fd )
505 return getLocalAddress(fd).family() ;
510 if( length == 0 )
return 0 ;
512 ssize_type nread =
G::Msg::recv( fd() , buffer , length , 0 ) ;
513 if( sizeError(nread) )
516 G_DEBUG(
"GNet::StreamSocket::read: cannot read from " << fd() ) ;
524 return writeImp( buffer , length ) ;
535 throw SocketTooMany(
"cannot accept on listening socket" , reason() ) ;
537 throw SocketError(
"cannot accept on listening socket" , reason() ) ;
541 throw SocketError(
"testing" ) ;
544 info.address =
Address( addr ) ;
547 G_DEBUG(
"GNet::StreamSocket::accept: accepted from " << fd()
548 <<
" to " << new_fd <<
" (" << info.address.displayString() <<
")" ) ;
553void GNet::StreamSocket::setOptionsOnCreate( Address::Family af ,
bool )
555 if( af == Address::Family::ipv4 || af == Address::Family::ipv6 )
557 if( m_config.create_linger_onoff == 1 )
558 setOptionLinger( 1 , m_config.create_linger_time ) ;
559 else if( m_config.create_linger_onoff == 0 )
560 setOptionLinger( 0 , 0 ) ;
561 if( m_config.create_keepalive )
562 setOptionKeepAlive() ;
566void GNet::StreamSocket::setOptionsOnAccept( Address::Family af )
568 if( af == Address::Family::ipv4 || af == Address::Family::ipv6 )
570 if( m_config.accept_linger_onoff == 1 )
571 setOptionLinger( 1 , m_config.accept_linger_time ) ;
572 else if( m_config.accept_linger_onoff == 0 )
573 setOptionLinger( 0 , 0 ) ;
574 if( m_config.accept_keepalive )
575 setOptionKeepAlive() ;
581GNet::DatagramSocket::Config::Config()
584GNet::DatagramSocket::Config::Config(
const Socket::Config & base ) :
590 Socket(af,SOCK_DGRAM,protocol,config)
597 int rc = ::connect( fd() ,
nullptr , 0 ) ;
605 if( length == 0 )
return 0 ;
607 socklen_t sender_len =
sizeof(sender) ;
608 ssize_type nread =
G::Msg::recvfrom( fd() , buffer , length , 0 , &sender , &sender_len ) ;
609 if( sizeError(nread) )
619 if( length == 0 )
return 0 ;
621 socklen_t sender_len =
sizeof(sender) ;
622 ssize_type nread =
G::Msg::recvfrom( fd() , buffer , length , 0 , &sender , &sender_len ) ;
623 if( sizeError(nread) )
628 src_address =
Address( &sender , sender_len ) ;
638 G_DEBUG(
"GNet::DatagramSocket::write: write error: " << reason() ) ;
646 return writeImp( buffer , length ) ;
A move-only class which is used to return a new()ed socket to calling code, together with associated ...
A helper class for calling accept(), getsockname() and getpeername() and hiding the definition of soc...
sockaddr * p1()
Returns the sockaddr pointer for accept()/getsockname()/getpeername() to write into.
socklen_t * p2()
Returns the length pointer for accept()/getsockname()/getpeername() to write into.
The GNet::Address class encapsulates a TCP/UDP transport address.
socklen_t length() const
Returns the size of the sockaddr address. See address().
static Address defaultAddress()
Returns a default address, being the IPv4 wildcard address with a zero port number.
static bool supports(Family) noexcept
Returns true if the implementation supports the given address family.
std::string displayString(bool with_scope_id=false) const
Returns a printable string that represents the transport address.
const sockaddr * address() const
Returns the sockaddr address.
unsigned long scopeId(unsigned long default_=0UL) const
Returns the scope-id.
Family family() const noexcept
Returns the address family enumeration.
ssize_type writeto(const char *buffer, size_type len, const Address &dst)
Sends a datagram to the given address.
ssize_type write(const char *buffer, size_type len) override
Override from Socket::write().
ssize_type read(char *buffer, size_type len) override
Override from ReadWrite::read().
void disconnect()
Releases the association between two datagram endpoints reversing the effect of the previous Socket::...
DatagramSocket(Address::Family, int protocol, const Config &config)
Constructor.
ssize_type readfrom(char *buffer, size_type len, Address &src)
Reads a datagram and returns the sender's address by reference.
A class that encapsulates a network socket file descriptor and an associated windows event handle.
bool validfd() const noexcept
Returns true if the socket part is valid, ignoring the handle.
A base class for classes that have a file descriptor and handle asynchronous events from the event lo...
virtual void dropWrite(Descriptor fd) noexcept=0
Removes the given event descriptor from the list of write sources.
virtual void dropRead(Descriptor fd) noexcept=0
Removes the given event descriptor from the list of read sources.
static EventLoop * ptr() noexcept
Returns a pointer to an instance of the class, if any.
virtual void addWrite(Descriptor fd, EventHandler &, EventState)=0
Adds the given event source descriptor and associated handler to the write list.
static EventLoop & instance()
Returns a reference to an instance of the class, if any.
virtual void dropOther(Descriptor fd) noexcept=0
Removes the given event descriptor from the list of other-event sources.
virtual void addRead(Descriptor fd, EventHandler &, EventState)=0
Adds the given event source descriptor and associated handler to the read list.
virtual void addOther(Descriptor fd, EventHandler &, EventState)=0
Adds the given event source descriptor and associated handler to the exception list.
A lightweight object containing an ExceptionHandler pointer, optional ExceptionSource pointer and opt...
A socket base class that holds a non-blocking socket file descriptor and interfaces to the event loop...
~SocketBase() override
Destructor.
std::string reason() const
Returns the reason for the previous error.
void addOtherHandler(EventHandler &, EventState)
Adds this socket to the event source list so that the given handler receives exception events.
SOCKET fd() const noexcept override
Returns the socket file descriptor.
void clearReason()
Clears the saved errno.
std::string asString() const
Returns the socket handle as a string.
void dropReadHandler() noexcept
Reverses addReadHandler().
void addWriteHandler(EventHandler &, EventState)
Adds this socket to the event source list so that the given handler receives write events when flow c...
SocketBase(Address::Family, int type, int protocol)
Constructor used by derived classes.
void addReadHandler(EventHandler &, EventState)
Adds this socket to the event source list so that the given handler receives read events.
bool isFamily(Address::Family) const
Returns true if the socket family is as given.
Descriptor fdd() const noexcept
Returns the socket descriptor.
static bool supports(Address::Family, int type, int protocol)
Returns true if sockets can be created with the given parameters.
void dropOtherHandler() noexcept
Reverses addOtherHandler().
void dropWriteHandler() noexcept
Reverses addWriteHandler().
void saveReason()
Saves the current errno following error()/sizeError().
An internet-protocol socket class.
bool connect(const Address &addr, bool *done=nullptr)
Initiates a connection to (or association with) the given address.
void shutdown(int how=1)
Modifies the local socket state so that new sends (1 or 2) and/or receives (0 or 2) will fail.
void bind(const Address &)
Binds the socket with the given address.
unsigned long getBoundScopeId() const
Returns the scope-id of the address last successfully bind()ed.
std::pair< bool, Address > getPeerAddress() const
Retrieves address of socket's peer.
void listen()
Starts the socket listening on the bound address for incoming connections or incoming datagrams.
Address getLocalAddress() const
Retrieves the local address of the socket.
A derivation of GNet::Socket for a stream socket.
AcceptInfo accept()
Accepts an incoming connection, returning a new()ed socket and the peer address.
ssize_type write(const char *buf, size_type len) override
Override from Socket::write().
StreamSocket(Address::Family, const Config &config)
Constructor.
ssize_type read(char *buffer, size_type buffer_length) override
Override from ReadWrite::read().
static bool supports(Address::Family)
Returns true if stream sockets can be created with the given the address family.
static ssize_t recv(SOCKET, void *, std::size_t, int flags) noexcept
A recv() wrapper.
static ssize_t send(SOCKET, const void *, std::size_t, int flags) noexcept
A send() wrapper.
static ssize_t sendto(SOCKET, const void *, std::size_t, int flags, const sockaddr *, socklen_t) noexcept
A sendto() wrapper.
static ssize_t recvfrom(SOCKET, void *, std::size_t, int, sockaddr *, socklen_t *) noexcept
A recvfrom() wrapper.
static bool enabled() noexcept
Returns true if test features are enabled.
Overload discriminator for Address::supports()
A configuration structure for GNet::DatagramSocket.
Overload discriminator class for GNet::SocketBase.
Overload discriminator class for GNet::SocketBase.
Exception class for GNet::SocketBase bind failures.
Overload discriminator class for GNet::Socket.
A configuration structure for GNet::StreamSocket.
Overload discriminator class for GNet::StreamSocket.
A set of compile-time buffer sizes.