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
135GNet::SocketBase::ssize_type GNet::SocketBase::writeImp(
const char * buffer , size_type length )
137 if(
static_cast<ssize_type
>(length) < 0 )
138 G_WARNING(
"GNet::SocketBase::writeImp: too big" ) ;
140 ssize_type nsent =
G::Msg::send( m_fd.fd() , buffer , length , MSG_NOSIGNAL ) ;
141 if( sizeError(nsent) )
144 G_DEBUG(
"GNet::SocketBase::writeImp: write error: " << reason() ) ;
147 else if( nsent < 0 ||
static_cast<size_type
>(nsent) < length )
156 G_DEBUG(
"GNet::SocketBase::addReadHandler: fd " << m_fd ) ;
159 m_read_added = true ;
164 G_DEBUG(
"GNet::SocketBase::addWriteHandler: fd " << m_fd ) ;
167 m_write_added = true ;
172 G_DEBUG(
"GNet::SocketBase::addOtherHandler: fd " << m_fd ) ;
175 m_other_added = true ;
182 m_read_added = false ;
189 m_write_added = false ;
196 m_other_added = false ;
206 if( m_reason == 0 )
return {} ;
207 return reasonString( m_reason ) ;
212 std::ostringstream ss ;
219GNet::Socket::Config::Config()
222GNet::Socket::Socket( Address::Family af ,
int type ,
int protocol ,
const Config & config ) :
228GNet::Socket::Socket( Address::Family af , Descriptor s ,
const Accepted & a ,
const Config & config ) :
234GNet::Socket::Socket( Address::Family af , Descriptor s ,
const Adopted & ,
const Config & config ) :
242 G_DEBUG(
"Socket::bind: binding " << local_address.
displayString() <<
" on fd " << fd() ) ;
244 if( !isFamily( local_address.
family() ) )
245 throw SocketBindError(
"address family does not match the socket domain" ) ;
247 setOptionsOnBind( local_address.
family() ) ;
249 int rc = ::bind( fd() , local_address.
address() , local_address.
length() ) ;
253 throw SocketBindError( local_address.
displayString() , reason() ) ;
255 m_bound_scope_id = local_address.
scopeId() ;
260 G_DEBUG(
"Socket::bind: binding " << local_address.
displayString() <<
" on fd " << fd() ) ;
261 if( !isFamily( local_address.
family() ) )
264 setOptionsOnBind( local_address.
family() ) ;
266 int rc = ::bind( fd() , local_address.
address() , local_address.
length() ) ;
272 m_bound_scope_id = local_address.
scopeId() ;
278 return m_bound_scope_id ;
283 G_DEBUG(
"GNet::Socket::connect: connecting to " << address.
displayString() ) ;
284 if( !isFamily( address.
family() ) )
286 G_WARNING(
"GNet::Socket::connect: cannot connect: address family does not match the socket domain" ) ;
290 setOptionsOnConnect( address.
family() ) ;
292 int rc = ::connect( fd() , address.
address() , address.
length() ) ;
299 G_DEBUG(
"GNet::Socket::connect: connection in progress" ) ;
300 if( done !=
nullptr ) *done = false ;
304 G_DEBUG(
"GNet::Socket::connect: synchronous connect failure: " << reason() ) ;
308 if( done !=
nullptr ) *done = true ;
314 int listen_queue = m_config.listen_queue ;
315 if( listen_queue <= 0 )
318 int rc = ::listen( fd() , std::max(1,listen_queue) ) ;
322 throw SocketError(
"cannot listen on socket" , reason() ) ;
329 int rc = ::getsockname( fd.fd() , address_storage.
p1() , address_storage.
p2() ) ;
331 throw SocketError( std::string(
"no bound address on fd ").append(std::to_string(fd.fd())) ) ;
332 return Address( address_storage ) ;
338 int rc = ::getsockname( fd() , address_storage.
p1() , address_storage.
p2() ) ;
342 throw SocketError(
"getsockname" , reason() ) ;
344 return Address( address_storage ) ;
350 int rc = ::getpeername( fd() , address_storage.
p1() , address_storage.
p2() ) ;
356 throw SocketError(
"getpeername" , reason() ) ;
358 return { true ,
Address(address_storage) } ;
364 ::shutdown( fd() , how ) ;
367void GNet::Socket::setOptionsOnConnect( Address::Family af )
369 if( af == Address::Family::ipv4 || af == Address::Family::ipv6 )
371 if( af == Address::Family::ipv6 && m_config.connect_pureipv6 )
372 setOptionPureV6( std::nothrow ) ;
376void GNet::Socket::setOptionsOnBind( Address::Family af )
378 if( af == Address::Family::ipv4 || af == Address::Family::ipv6 )
380 if( m_config.bind_reuse )
382 if( m_config.bind_exclusive )
383 setOptionExclusive() ;
384 if( m_config.free_bind )
385 setOptionFreeBind() ;
386 if( af == Address::Family::ipv6 && m_config.bind_pureipv6 )
391void GNet::Socket::setOptionKeepAlive()
393 setOption( SOL_SOCKET ,
"so_keepalive" , SO_KEEPALIVE , 1 ) ;
396void GNet::Socket::setOptionFreeBind()
402void GNet::Socket::setOptionLinger(
int onoff ,
int time )
404 struct linger linger_config {} ;
405 linger_config.l_onoff =
static_cast<decltype(linger::l_onoff)
>(onoff) ;
406 linger_config.l_linger =
static_cast<decltype(linger::l_linger)
>(time) ;
407 bool ok = setOptionImp( SOL_SOCKET , SO_LINGER , &linger_config ,
sizeof(linger_config) ) ;
411 throw SocketError(
"cannot set socket linger option" , reason() ) ;
415bool GNet::Socket::setOption(
int level ,
const char * ,
int op ,
int arg , std::nothrow_t )
417 const void *
const vp =
static_cast<const void*
>(&arg) ;
418 bool ok = setOptionImp( level , op , vp ,
sizeof(
int) ) ;
424void GNet::Socket::setOption(
int level ,
const char * opp ,
int op ,
int arg )
426 if( !setOption( level , opp , op , arg , std::nothrow ) )
427 throw SocketError( opp , reason() ) ;
432GNet::StreamSocket::Config::Config()
435GNet::StreamSocket::Config::Config(
const Socket::Config & base ) :
442 if( af == Address::Family::ipv6 )
444 static bool first = true ;
445 static bool result = false ;
450 G_WARNING(
"GNet::StreamSocket::supports: no ipv6 support built-in" ) ;
452 G_WARNING(
"GNet::StreamSocket::supports: no ipv6 support detected" ) ;
458 else if( af == Address::Family::local )
469 Socket(af,SOCK_STREAM,0,config) ,
472 setOptionsOnCreate( af ,
false ) ;
476 Socket(af,SOCK_STREAM,0,config) ,
479 setOptionsOnCreate( af ,
true ) ;
489 Socket(af,fd,accepted,config) ,
492 setOptionsOnAccept( af ) ;
495GNet::Address::Family GNet::StreamSocket::family( Descriptor fd )
497 return getLocalAddress(fd).family() ;
502 if( length == 0 )
return 0 ;
504 ssize_type nread =
G::Msg::recv( fd() , buffer , length , 0 ) ;
505 if( sizeError(nread) )
508 G_DEBUG(
"GNet::StreamSocket::read: cannot read from " << fd() ) ;
516 return writeImp( buffer , length ) ;
523 if( ! new_fd.
valid() )
527 throw SocketTooMany(
"cannot accept on listening socket" , reason() ) ;
529 throw SocketError(
"cannot accept on listening socket" , reason() ) ;
533 throw SocketError(
"testing" ) ;
536 info.address =
Address( addr ) ;
539 G_DEBUG(
"GNet::StreamSocket::accept: accepted from " << fd()
540 <<
" to " << new_fd <<
" (" << info.address.displayString() <<
")" ) ;
545void GNet::StreamSocket::setOptionsOnCreate( Address::Family af ,
bool )
547 if( af == Address::Family::ipv4 || af == Address::Family::ipv6 )
549 if( m_config.create_linger_onoff == 1 )
550 setOptionLinger( 1 , m_config.create_linger_time ) ;
551 else if( m_config.create_linger_onoff == 0 )
552 setOptionLinger( 0 , 0 ) ;
553 if( m_config.create_keepalive )
554 setOptionKeepAlive() ;
558void GNet::StreamSocket::setOptionsOnAccept( Address::Family af )
560 if( af == Address::Family::ipv4 || af == Address::Family::ipv6 )
562 if( m_config.accept_linger_onoff == 1 )
563 setOptionLinger( 1 , m_config.accept_linger_time ) ;
564 else if( m_config.accept_linger_onoff == 0 )
565 setOptionLinger( 0 , 0 ) ;
566 if( m_config.accept_keepalive )
567 setOptionKeepAlive() ;
573GNet::DatagramSocket::Config::Config()
576GNet::DatagramSocket::Config::Config(
const Socket::Config & base ) :
582 Socket(af,SOCK_DGRAM,protocol,config)
589 int rc = ::connect( fd() ,
nullptr , 0 ) ;
597 if( length == 0 )
return 0 ;
599 socklen_t sender_len =
sizeof(sender) ;
600 ssize_type nread =
G::Msg::recvfrom( fd() , buffer , length , 0 , &sender , &sender_len ) ;
601 if( sizeError(nread) )
611 if( length == 0 )
return 0 ;
613 socklen_t sender_len =
sizeof(sender) ;
614 ssize_type nread =
G::Msg::recvfrom( fd() , buffer , length , 0 , &sender , &sender_len ) ;
615 if( sizeError(nread) )
620 src_address =
Address( &sender , sender_len ) ;
630 G_DEBUG(
"GNet::DatagramSocket::write: write error " << reason() ) ;
638 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 valid() 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 addOther(Descriptor fd, EventHandler &, ExceptionSink)=0
Adds the given event source descriptor and associated handler to the exception list.
virtual void addWrite(Descriptor fd, EventHandler &, ExceptionSink)=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 addRead(Descriptor fd, EventHandler &, ExceptionSink)=0
Adds the given event source descriptor and associated handler to the read list.
virtual void dropOther(Descriptor fd) noexcept=0
Removes the given event descriptor from the list of other-event sources.
A tuple containing an ExceptionHandler interface pointer and a bound 'exception source' pointer.
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.
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 addOtherHandler(EventHandler &, ExceptionSink)
Adds this socket to the event source list so that the given handler receives exception events.
SocketBase(Address::Family, int type, int protocol)
Constructor used by derived classes.
bool isFamily(Address::Family) const
Returns true if the socket family is as given.
void addReadHandler(EventHandler &, ExceptionSink)
Adds this socket to the event source list so that the given handler receives read events.
static bool supports(Address::Family, int type, int protocol)
Returns true if sockets can be created with the given parameters.
void addWriteHandler(EventHandler &, ExceptionSink)
Adds this socket to the event source list so that the given handler receives write events when flow c...
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.
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.