32 namespace StreamSocketImp
36 enum class Linger { default_ , zero , nolinger } ;
37 Linger create_linger {Linger::nolinger} ;
39 Linger accept_linger {Linger::nolinger} ;
47 bool connect_pureipv6 {
true} ;
48 bool bind_pureipv6 {
true} ;
49 bool bind_reuse {
true} ;
59 m_domain(
Address::domain(family)) ,
64 if( !create(m_domain,type,protocol) )
65 throw SocketCreateError(
"cannot create socket" ,
reason() ) ;
70 throw SocketError(
"cannot prepare socket" ,
reason() ) ;
77 m_family(
Address::Family::local) ,
83 if( !create(domain,type,protocol) )
84 throw SocketCreateError(
"cannot create socket" ,
reason() ) ;
89 throw SocketError(
"cannot prepare socket" ,
reason() ) ;
95 m_domain(
Address::domain(family)) ,
101 if( !prepare(
false) )
104 throw SocketError(
"cannot prepare socket" ,
reason() ) ;
110 m_domain(
Address::domain(family)) ,
119 throw SocketError(
"cannot prepare socket" ,
reason() ) ;
136void GNet::SocketBase::drop() noexcept
155 if(
static_cast<ssize_type
>(length) < 0 )
156 G_WARNING(
"GNet::SocketBase::writeImp: too big" ) ;
158 ssize_type nsent =
G::Msg::send( m_fd.fd() , buffer , length , MSG_NOSIGNAL ) ;
159 if( sizeError(nsent) )
162 G_DEBUG(
"GNet::SocketBase::writeImp: write error: " << reason() ) ;
165 else if( nsent < 0 ||
static_cast<size_type
>(nsent) < length )
174 G_DEBUG(
"GNet::SocketBase::addReadHandler: fd " << m_fd ) ;
181 G_DEBUG(
"GNet::SocketBase::addWriteHandler: fd " << m_fd ) ;
188 G_DEBUG(
"GNet::SocketBase::addOtherHandler: fd " << m_fd ) ;
218 if( m_reason == 0 )
return {} ;
219 return reasonString( m_reason ) ;
224 std::ostringstream ss ;
231GNet::Socket::Socket( Address::Family af ,
int type ,
int protocol ) :
236GNet::Socket::Socket( Address::Family af , Descriptor s ,
const Accepted & a ) :
243 G_DEBUG(
"Socket::bind: binding " << local_address.
displayString() <<
" on fd " << fd() ) ;
245 if( !isFamily( local_address.
family() ) )
246 throw SocketBindError(
"address family does not match the socket domain" ) ;
248 setOptionsOnBind( local_address.
family() ) ;
250 int rc = ::bind( fd() , local_address.
address() , local_address.
length() ) ;
254 throw SocketBindError( local_address.
displayString() , reason() ) ;
256 m_bound_scope_id = local_address.
scopeId() ;
261 G_DEBUG(
"Socket::bind: binding " << local_address.
displayString() <<
" on fd " << fd() ) ;
262 if( !isFamily( local_address.
family() ) )
265 setOptionsOnBind( local_address.
family() ) ;
267 int rc = ::bind( fd() , local_address.
address() , local_address.
length() ) ;
273 m_bound_scope_id = local_address.
scopeId() ;
279 return m_bound_scope_id ;
284 G_DEBUG(
"GNet::Socket::connect: connecting to " << address.
displayString() ) ;
285 if( !isFamily( address.
family() ) )
287 G_WARNING(
"GNet::Socket::connect: cannot connect: address family does not match the socket domain" ) ;
291 setOptionsOnConnect( address.
family() ) ;
293 int rc = ::connect( fd() , address.
address() , address.
length() ) ;
303 G_DEBUG(
"GNet::Socket::connect: connection in progress" ) ;
304 if( done !=
nullptr ) *done = false ;
308 G_DEBUG(
"GNet::Socket::connect: synchronous connect failure: " << reason() ) ;
312 if( done !=
nullptr ) *done = true ;
318 int rc = ::listen( fd() , backlog ) ;
322 throw SocketError(
"cannot listen on socket" , reason() ) ;
329 int rc = ::getsockname( fd() , address_storage.
p1() , address_storage.
p2() ) ;
333 throw SocketError(
"getsockname" , reason() ) ;
335 return Address( address_storage ) ;
341 int rc = ::getpeername( fd() , address_storage.
p1() , address_storage.
p2() ) ;
347 throw SocketError(
"getpeername" , reason() ) ;
349 return { true ,
Address(address_storage) } ;
355 ::shutdown( fd() , how ) ;
358void GNet::Socket::setOptionsOnConnect( Address::Family af )
360 if( af == Address::Family::ipv4 || af == Address::Family::ipv6 )
362 using namespace SocketImp ;
364 if( af == Address::Family::ipv6 && options.connect_pureipv6 )
365 setOptionPureV6( std::nothrow ) ;
369void GNet::Socket::setOptionsOnBind( Address::Family af )
371 if( af == Address::Family::ipv4 || af == Address::Family::ipv6 )
373 using namespace SocketImp ;
375 if( options.bind_reuse )
377 if( options.bind_exclusive )
378 setOptionExclusive() ;
379 if( af == Address::Family::ipv6 && options.bind_pureipv6 )
384void GNet::Socket::setOptionKeepAlive()
386 setOption( SOL_SOCKET ,
"so_keepalive" , SO_KEEPALIVE , 1 ) ;
389void GNet::Socket::setOptionNoLinger()
391 setOptionLingerImp( 0 , 0 ) ;
394void GNet::Socket::setOptionLingerImp(
int onoff ,
int time )
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) ) ;
403 throw SocketError(
"cannot set no_linger" , reason() ) ;
407bool GNet::Socket::setOption(
int level ,
const char * ,
int op ,
int arg , std::nothrow_t )
409 const void *
const vp =
static_cast<const void*
>(&arg) ;
410 bool ok = setOptionImp( level , op , vp ,
sizeof(
int) ) ;
416void GNet::Socket::setOption(
int level ,
const char * opp ,
int op ,
int arg )
418 if( !setOption( level , opp , op , arg , std::nothrow ) )
419 throw SocketError( opp , reason() ) ;
426 if( af == Address::Family::ipv6 )
428 static bool first = true ;
429 static bool result = false ;
434 G_WARNING(
"GNet::StreamSocket::supports: no ipv6 support built-in" ) ;
436 G_WARNING(
"GNet::StreamSocket::supports: no ipv6 support detected" ) ;
442 else if( af == Address::Family::local )
455 setOptionsOnCreate( af ,
false ) ;
461 setOptionsOnCreate( af ,
true ) ;
467 setOptionsOnAccept( af ) ;
472 if( length == 0 )
return 0 ;
474 ssize_type nread =
G::Msg::recv( fd() , buffer , length , 0 ) ;
475 if( sizeError(nread) )
478 G_DEBUG(
"GNet::StreamSocket::read: cannot read from " << fd() ) ;
486 return writeImp( buffer , length ) ;
493 if( ! new_fd.
valid() )
497 throw SocketTooMany(
"cannot accept on listening socket" , reason() ) ;
499 throw SocketError(
"cannot accept on listening socket" , reason() ) ;
503 throw SocketError(
"testing" ) ;
506 info.address =
Address( addr ) ;
509 G_DEBUG(
"GNet::StreamSocket::accept: accepted from " << fd()
510 <<
" to " << new_fd <<
" (" << info.address.
displayString() <<
")" ) ;
515void GNet::StreamSocket::setOptionsOnCreate( Address::Family af ,
bool )
517 if( af == Address::Family::ipv4 || af == Address::Family::ipv6 )
519 using namespace StreamSocketImp ;
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() ;
530void GNet::StreamSocket::setOptionsOnAccept( Address::Family af )
532 if( af == Address::Family::ipv4 || af == Address::Family::ipv6 )
534 using namespace StreamSocketImp ;
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() ;
548 Socket( af , SOCK_DGRAM , protocol )
554 int rc = ::connect( fd() ,
nullptr , 0 ) ;
561 if( length == 0 )
return 0 ;
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) )
575 if( length == 0 )
return 0 ;
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) )
584 src_address =
Address( &sender , sender_len ) ;
594 G_DEBUG(
"GNet::DatagramSocket::write: write error " << reason() ) ;
602 return writeImp( buffer , length ) ;
A class which is used to return a new()ed socket to calling code, together with associated address in...
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.
Family family() const
Returns the address family enumeration.
static bool supports(Family)
Returns true if the implementation supports the given address family.
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.
std::string displayString(bool with_scope_id=false) const
Returns a string which represents the transport address.
const sockaddr * address() const
Returns the sockaddr address.
unsigned long scopeId(unsigned long default_=0UL) const
Returns the scope-id.
ssize_type writeto(const char *buffer, size_type len, const Address &dst)
Sends a datagram to the given address.
DatagramSocket(Address::Family, int protocol=0)
Constructor.
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::...
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 handle asynchronous events from the event loop.
virtual void dropWrite(Descriptor fd) noexcept=0
Removes the given event source descriptor from the list of write sources.
virtual void dropRead(Descriptor fd) noexcept=0
Removes the given event source 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 source descriptor from the list of exception 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().
ssize_type writeImp(const char *buf, size_type len)
Writes to the socket.
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 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(int backlog=1)
Starts the socket listening on the bound address for incoming connections or incoming datagrams.
Address getLocalAddress() const
Retrieves local address of the socket.
A derivation of GNet::Socket for a stream socket.
ssize_type write(const char *buf, size_type len) override
Override from Socket::write().
AcceptPair accept()
Accepts an incoming connection, returning a new()ed socket and the peer address.
StreamSocket(Address::Family)
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 recvfrom(SOCKET, void *, std::size_t, int flags, sockaddr *, socklen_t *)
A recvfrom() replacement using recvmsg().
static ssize_t recv(SOCKET, void *, std::size_t, int flags)
A recv() wrapper.
static ssize_t send(SOCKET, const void *, std::size_t, int flags) noexcept
A send() replacement using sendmsg().
static ssize_t sendto(SOCKET, const void *, std::size_t, int flags, const sockaddr *, socklen_t) noexcept
A sendto() replacement using sendmsg().
static bool enabled() noexcept
Returns true if test features are enabled.
Overload discriminator for Address::supports()
Overload discriminator class for GNet::SocketBase.
Overload discriminator class for GNet::SocketBase.
Overload discriminator class for GNet::StreamSocket.