E-MailRelay
gsocket.h
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2024 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.h
19///
20
21#ifndef G_NET_SOCKET_H
22#define G_NET_SOCKET_H
23
24#include "gdef.h"
25#include "gaddress.h"
26#include "geventstate.h"
27#include "gexception.h"
28#include "gevent.h"
29#include "gdescriptor.h"
30#include "greadwrite.h"
31#include "gstringview.h"
32#include <string>
33#include <utility>
34#include <memory>
35#include <new>
36
37namespace GNet
38{
39 class SocketBase ;
40 class Socket ;
41 class SocketProtocol ;
42 class StreamSocket ;
43 class DatagramSocket ;
44 class RawSocket ;
45 class AcceptInfo ;
46}
47
48//| \class GNet::SocketBase
49/// A socket base class that holds a non-blocking socket file descriptor and
50/// interfaces to the event loop.
51///
53{
54public:
55 G_EXCEPTION( SocketError , tx("socket error") )
56 G_EXCEPTION_CLASS( SocketCreateError , tx("socket create error") )
57 G_EXCEPTION_CLASS( SocketTooMany , tx("socket accept error") )
58 G_EXCEPTION_CLASS( SocketBindErrorBase , tx("socket bind error") )
59 struct SocketBindError : SocketBindErrorBase /// Exception class for GNet::SocketBase bind failures.
60 {
61 explicit SocketBindError( const std::string & s ) ;
62 SocketBindError( const Address & a , const std::string & s , bool e_in_use ) ;
63 Address m_address {Address::defaultAddress()} ;
64 std::string m_reason ;
65 bool m_einuse {false} ;
66 } ;
67 using size_type = G::ReadWrite::size_type ;
68 using ssize_type = G::ReadWrite::ssize_type ;
69 struct Accepted /// Overload discriminator class for GNet::SocketBase.
70 {} ;
71 struct Raw /// Overload discriminator class for GNet::SocketBase.
72 {} ;
73
74 static bool supports( Address::Family , int type , int protocol ) ;
75 ///< Returns true if sockets can be created with the
76 ///< given parameters.
77
78 ~SocketBase() override ;
79 ///< Destructor. The socket file descriptor is closed and
80 ///< removed from the event loop.
81
82 SOCKET fd() const noexcept override ;
83 ///< Returns the socket file descriptor.
84
85 Descriptor fdd() const noexcept ;
86 ///< Returns the socket descriptor.
87
88 bool eWouldBlock() const override ;
89 ///< Returns true if the previous socket operation
90 ///< failed because the socket would have blocked.
91
92 bool eInProgress() const ;
93 ///< Returns true if the previous socket operation
94 ///< failed with the EINPROGRESS error status.
95 ///< When connecting this can be considered a
96 ///< non-error.
97
98 bool eInUse() const ;
99 ///< Returns true if the previous socket bind operation
100 ///< failed because the socket was already in use.
101
102 bool eMsgSize() const ;
103 ///< Returns true if the previous socket operation
104 ///< failed with the EMSGSIZE error status. When
105 ///< writing to a datagram socket this indicates that
106 ///< the message was too big to send atomically.
107
108 bool eTooMany() const ;
109 ///< Returns true if the previous socket operation
110 ///< failed with the EMFILE error status, or similar.
111
112 bool eNotConn() const ;
113 ///< Returns true if the previous socket operation
114 ///< failed with the ENOTCONN error status, or similar.
115
117 ///< Adds this socket to the event source list so that
118 ///< the given handler receives read events.
119
120 void dropReadHandler() noexcept ;
121 ///< Reverses addReadHandler(). Does nothing if no
122 ///< read handler is currently installed.
123
125 ///< Adds this socket to the event source list so that
126 ///< the given handler receives write events when flow
127 ///< control is released. (Not used for datagram
128 ///< sockets.)
129
130 void dropWriteHandler() noexcept ;
131 ///< Reverses addWriteHandler(). Does nothing if no
132 ///< write handler is currently installed.
133
135 ///< Adds this socket to the event source list so that
136 ///< the given handler receives exception events.
137 ///< A TCP exception event should be treated as a
138 ///< disconnection event. (Not used for datagram
139 ///< sockets.)
140
141 void dropOtherHandler() noexcept ;
142 ///< Reverses addOtherHandler(). Does nothing if no
143 ///< 'other' handler is currently installed.
144
145 std::string asString() const ;
146 ///< Returns the socket handle as a string.
147 ///< Only used in debugging.
148
149 std::string reason() const ;
150 ///< Returns the reason for the previous error.
151
152protected:
153 SocketBase( Address::Family , int type , int protocol ) ;
154 ///< Constructor used by derived classes. Creates the
155 ///< socket using socket() and makes it non-blocking.
156
157 SocketBase( Address::Family , Descriptor s ) ;
158 ///< Constructor used by derived classes. Creates the
159 ///< socket object from a newly-created socket handle
160 ///< and makes it non-blocking.
161
162 SocketBase( Address::Family , Descriptor s , const Accepted & ) ;
163 ///< Constructor used by StreamSocket::accept() to create
164 ///< a socket object from a newly accept()ed socket
165 ///< handle.
166
167 SocketBase( const Raw & , int domain , int type , int protocol ) ;
168 ///< Constructor for a raw socket.
169
170 ssize_type writeImp( const char * buf , size_type len ) ;
171 ///< Writes to the socket. This is a default implementation
172 ///< for write() that can be called from derived classes'
173 ///< overrides.
174
175 static bool error( int rc ) ;
176 ///< Returns true if the given return code indicates an
177 ///< error.
178
179 static bool sizeError( ssize_type size ) ;
180 ///< Returns true if the given write() return value
181 ///< indicates an error.
182
183 void clearReason() ;
184 ///< Clears the saved errno.
185
186 void saveReason() ;
187 ///< Saves the current errno following error()/sizeError().
188
189 void saveReason() const ;
190 ///< Saves the current errno following error()/sizeError().
191
192 bool isFamily( Address::Family ) const ;
193 ///< Returns true if the socket family is as given.
194
195private:
196 static std::string reasonString( int ) ;
197 bool create( int , int , int ) ;
198 bool prepare( bool ) ;
199 void drop() noexcept ;
200 void destroy() noexcept ;
201 void unlink() noexcept ;
202 bool setNonBlocking() ;
203
204public:
205 SocketBase( const SocketBase & ) = delete ;
206 SocketBase( SocketBase && ) = delete ;
207 SocketBase & operator=( const SocketBase & ) = delete ;
208 SocketBase & operator=( SocketBase && ) = delete ;
209
210private:
211 int m_reason ;
212 int m_domain ;
213 Address::Family m_family ; // valid depending on m_domain
214 Descriptor m_fd ;
215 bool m_read_added ;
216 bool m_write_added ;
217 bool m_other_added ;
218 bool m_accepted ;
219} ;
220
221//| \class GNet::Socket
222/// An internet-protocol socket class. Provides bind(), listen(),
223/// and connect(); the base classes provide write(); and derived
224/// classes provide accept() and read().
225///
226class GNet::Socket : public SocketBase
227{
228public:
229 struct Adopted /// Overload discriminator class for GNet::Socket.
230 {} ;
231 struct Config /// A configuration structure for GNet::Socket.
232 {
233 Config() ;
234 int listen_queue {0} ; // zero for compile-time default
235 bool connect_pureipv6 {true} ;
236 bool bind_pureipv6 {true} ;
237 bool bind_reuse {true} ;
238 bool bind_exclusive {false} ; // (windows, einval if also bind_reuse)
239 bool free_bind {false} ; // (linux) (not yet implemented)
240 Config & set_listen_queue( int ) noexcept ;
241 Config & set_bind_reuse( bool ) noexcept ;
242 Config & set_bind_exclusive( bool ) noexcept ;
243 Config & set_free_bind( bool ) noexcept ;
244 template <typename T> const T & set_last() ;
245 } ;
246
247 Address getLocalAddress() const ;
248 ///< Retrieves the local address of the socket.
249
250 std::pair<bool,Address> getPeerAddress() const ;
251 ///< Retrieves address of socket's peer.
252 ///< Returns false in 'first' if none, ie. not yet
253 ///< connected.
254
255 void bind( const Address & ) ;
256 ///< Binds the socket with the given address.
257
258 bool bind( const Address & , std::nothrow_t ) ;
259 ///< No-throw overload. Returns false on error.
260
261 static std::string canBindHint( const Address & address , bool stream_socket , const Config & ) ;
262 ///< Returns the empty string if a socket could probably be
263 ///< bound with the given address or a failure reason.
264 ///< Some implementations will always return the empty
265 ///< string.
266
267 unsigned long getBoundScopeId() const ;
268 ///< Returns the scope-id of the address last successfully
269 ///< bind()ed. Note that getLocalAddress() has a zero
270 ///< scope-id even after bind()ing an address with
271 ///< a non-zero scope-id.
272
273 bool connect( const Address & addr , bool *done = nullptr ) ;
274 ///< Initiates a connection to (or association with)
275 ///< the given address. Returns false on error.
276 ///<
277 ///< If successful, a 'done' flag is returned by
278 ///< reference indicating whether the connect completed
279 ///< immediately. Normally a stream socket connection
280 ///< will take some time to complete so the 'done' flag
281 ///< will be false: the completion will be indicated by
282 ///< a write event some time later.
283 ///<
284 ///< For datagram sockets this sets up an association
285 ///< between two addresses. The socket should first be
286 ///< bound with a local address.
287
288 void listen() ;
289 ///< Starts the socket listening on the bound
290 ///< address for incoming connections or incoming
291 ///< datagrams.
292
293 void shutdown( int how = 1 ) ;
294 ///< Modifies the local socket state so that new
295 ///< sends (1 or 2) and/or receives (0 or 2) will fail.
296 ///<
297 ///< If receives are shut-down then anything received
298 ///< will be rejected with a RST.
299 ///<
300 ///< If sends are shut-down then the transmit queue is
301 ///< drained and a final empty FIN packet is sent when
302 ///< fully acknowledged. See also RFC-793 3.5.
303 ///<
304 ///< Errors are ignored.
305
306public:
307 ~Socket() override = default ;
308 Socket( const Socket & ) = delete ;
309 Socket( Socket && ) = delete ;
310 Socket & operator=( const Socket & ) = delete ;
311 Socket & operator=( Socket && ) = delete ;
312
313protected:
314 Socket( Address::Family , int type , int protocol , const Config & ) ;
315 Socket( Address::Family , Descriptor s , const Accepted & , const Config & ) ;
316 Socket( Address::Family , Descriptor s , const Adopted & , const Config & ) ;
317 static Address getLocalAddress( Descriptor ) ;
318
319protected:
320 void setOptionLinger( int onoff , int time ) ;
321 void setOptionKeepAlive() ;
322 void setOptionFreeBind() ;
323
324private:
325 void setOption( int , const char * , int , int ) ;
326 bool setOption( int , const char * , int , int , std::nothrow_t ) ;
327 bool setOptionImp( int , int , const void * , socklen_t ) ;
328 void setOptionsOnBind( Address::Family ) ;
329 void setOptionsOnConnect( Address::Family ) ;
330 void setOptionReuse() ;
331 void setOptionExclusive() ;
332 void setOptionPureV6() ;
333 bool setOptionPureV6( std::nothrow_t ) ;
334
335private:
336 Config m_config ;
337 unsigned long m_bound_scope_id {0UL} ;
338} ;
339
340//| \class GNet::AcceptInfo
341/// A move-only class which is used to return a new()ed socket to calling
342/// code, together with associated address information.
343///
345{
346public:
347 std::unique_ptr<StreamSocket> socket_ptr ;
348 Address address ;
349 AcceptInfo() : address(Address::defaultAddress()) {}
350} ;
351
352//| \class GNet::StreamSocket
353/// A derivation of GNet::Socket for a stream socket.
354///
356{
357public:
358 using size_type = Socket::size_type ;
359 using ssize_type = Socket::ssize_type ;
360 struct Listener /// Overload discriminator class for GNet::StreamSocket.
361 {} ;
362 struct Config : Socket::Config /// A configuration structure for GNet::StreamSocket.
363 {
364 Config() ;
365 explicit Config( const Socket::Config & ) ;
366 int create_linger_onoff {0} ; // -1 no-op, 0 nolinger, 1 linger with time
367 int create_linger_time {0} ;
368 int accept_linger_onoff {0} ;
369 int accept_linger_time {0} ;
370 bool create_keepalive {false} ;
371 bool accept_keepalive {false} ;
372 Config & set_create_linger( std::pair<int,int> ) noexcept ;
373 Config & set_create_linger_onoff( int ) noexcept ;
374 Config & set_create_linger_time( int ) noexcept ;
375 Config & set_accept_linger( std::pair<int,int> ) noexcept ;
376 Config & set_accept_linger_onoff( int ) noexcept ;
377 Config & set_accept_linger_time( int ) noexcept ;
378 } ;
379
380 static bool supports( Address::Family ) ;
381 ///< Returns true if stream sockets can be created with the
382 ///< given the address family. This is a one-off run-time
383 ///< check on socket creation, with a warning if it fails.
384 ///< Note that a run-time check is useful when running a
385 ///< new binary on an old operating system.
386
387 StreamSocket( Address::Family , const Config & config ) ;
388 ///< Constructor.
389
390 StreamSocket( Address::Family , const Listener & , const Config & config ) ;
391 ///< Constructor overload specifically for a listening
392 ///< socket, which might need slightly different socket
393 ///< options.
394
395 StreamSocket( const Listener & , Descriptor fd , const Config & config ) ;
396 ///< Constructor overload for adopting an externally-managed
397 ///< listening file descriptor.
398
399 ssize_type read( char * buffer , size_type buffer_length ) override ;
400 ///< Override from ReadWrite::read().
401
402 ssize_type write( const char * buf , size_type len ) override ;
403 ///< Override from Socket::write().
404
405 AcceptInfo accept() ;
406 ///< Accepts an incoming connection, returning a new()ed
407 ///< socket and the peer address.
408
409public:
410 ~StreamSocket() override = default ;
411 StreamSocket( const StreamSocket & ) = delete ;
412 StreamSocket( StreamSocket && ) = delete ;
413 StreamSocket & operator=( const StreamSocket & ) = delete ;
414 StreamSocket & operator=( StreamSocket && ) = delete ;
415
416private:
417 StreamSocket( Address::Family , Descriptor s , const Accepted & , const Config & config ) ;
418 void setOptionsOnCreate( Address::Family , bool listener ) ;
419 void setOptionsOnAccept( Address::Family ) ;
420 static Address::Family family( Descriptor ) ;
421
422private:
423 Config m_config ;
424} ;
425
426//| \class GNet::DatagramSocket
427/// A derivation of GNet::Socket for a datagram socket.
428///
430{
431public:
432 struct Config : Socket::Config /// A configuration structure for GNet::DatagramSocket.
433 {
434 Config() ;
435 explicit Config( const Socket::Config & ) ;
436 } ;
437
438 explicit DatagramSocket( Address::Family , int protocol , const Config & config ) ;
439 ///< Constructor.
440
441 ssize_type read( char * buffer , size_type len ) override ;
442 ///< Override from ReadWrite::read().
443
444 ssize_type write( const char * buffer , size_type len ) override ;
445 ///< Override from Socket::write().
446
447 ssize_type readfrom( char * buffer , size_type len , Address & src ) ;
448 ///< Reads a datagram and returns the sender's address by reference.
449 ///< If connect() has been used then only datagrams from the address
450 ///< specified in the connect() call will be received.
451
452 ssize_type writeto( const char * buffer , size_type len , const Address & dst ) ;
453 ///< Sends a datagram to the given address. This should be used
454 ///< if there is no connect() assocation in effect.
455
456 ssize_type writeto( const std::vector<std::string_view> & , const Address & dst ) ;
457 ///< Sends a datagram to the given address, overloaded for
458 ///< scatter-gather data chunks.
459
460 void disconnect() ;
461 ///< Releases the association between two datagram endpoints
462 ///< reversing the effect of the previous Socket::connect().
463
464 std::size_t limit( std::size_t default_ = 1024U ) const ;
465 ///< Returns the systems's maximum datagram size if the
466 ///< value is known and greater than the given default
467 ///< value. Returns the given default value if the system
468 ///< limit is not known.
469 ///<
470 /// \see SO_SNDBUF, /proc/sys/net/core/wmem_default
471
472public:
473 ~DatagramSocket() override = default ;
474 DatagramSocket( const DatagramSocket & ) = delete ;
475 DatagramSocket( DatagramSocket && ) = delete ;
476 DatagramSocket & operator=( const DatagramSocket & ) = delete ;
477 DatagramSocket & operator=( DatagramSocket && ) = delete ;
478} ;
479
480//| \class GNet::RawSocket
481/// A derivation of GNet::SocketBase for a raw socket, typically of
482/// type AF_NETLINK or PF_ROUTE.
483///
485{
486public:
487 RawSocket( int domain , int type , int protocol ) ;
488 ///< Constructor.
489
490 ssize_type read( char * buffer , size_type buffer_length ) override ;
491 ///< Reads from the socket.
492
493 ssize_type write( const char * buf , size_type len ) override ;
494 ///< Writes to the socket.
495
496public:
497 ~RawSocket() override = default ;
498 RawSocket( const RawSocket & ) = delete ;
499 RawSocket( RawSocket && ) = delete ;
500 RawSocket & operator=( const RawSocket & ) = delete ;
501 RawSocket & operator=( RawSocket && ) = delete ;
502} ;
503
504inline GNet::Socket::SocketBindError::SocketBindError( const std::string & s ) : SocketBindErrorBase(s) , m_reason(s) {}
505inline GNet::Socket::SocketBindError::SocketBindError( const Address & a , const std::string & s , bool b ) : SocketBindErrorBase(s) , m_address(a) , m_reason(s) , m_einuse(b) {}
506
507inline GNet::Socket::Config & GNet::Socket::Config::set_listen_queue( int n ) noexcept { listen_queue = n ; return *this ; }
508inline GNet::Socket::Config & GNet::Socket::Config::set_bind_reuse( bool b ) noexcept { bind_reuse = b ; return *this ; }
509inline GNet::Socket::Config & GNet::Socket::Config::set_bind_exclusive( bool b ) noexcept { bind_exclusive = b ; return *this ; }
510inline GNet::Socket::Config & GNet::Socket::Config::set_free_bind( bool b ) noexcept { free_bind = b ; return *this ; }
511template <typename T> const T & GNet::Socket::Config::set_last() { return static_cast<const T&>(*this) ; }
512
513inline GNet::StreamSocket::Config & GNet::StreamSocket::Config::set_create_linger( std::pair<int,int> p ) noexcept { create_linger_onoff = p.first ; create_linger_time = p.second ; return *this ; }
514inline GNet::StreamSocket::Config & GNet::StreamSocket::Config::set_create_linger_onoff( int n ) noexcept { create_linger_onoff = n ; return *this ; }
515inline GNet::StreamSocket::Config & GNet::StreamSocket::Config::set_create_linger_time( int n ) noexcept { create_linger_time = n ; return *this ; }
516inline GNet::StreamSocket::Config & GNet::StreamSocket::Config::set_accept_linger( std::pair<int,int> p ) noexcept { accept_linger_onoff = p.first ; accept_linger_time = p.second ; return *this ; }
517inline GNet::StreamSocket::Config & GNet::StreamSocket::Config::set_accept_linger_onoff( int n ) noexcept { accept_linger_onoff = n ; return *this ; }
518inline GNet::StreamSocket::Config & GNet::StreamSocket::Config::set_accept_linger_time( int n ) noexcept { accept_linger_time = n ; return *this ; }
519
520#endif
A move-only class which is used to return a new()ed socket to calling code, together with associated ...
Definition: gsocket.h:345
The GNet::Address class encapsulates a TCP/UDP transport address.
Definition: gaddress.h:63
static Address defaultAddress()
Returns a default address, being the IPv4 wildcard address with a zero port number.
Definition: gaddress.cpp:203
A derivation of GNet::Socket for a datagram socket.
Definition: gsocket.h:430
A class that encapsulates a network socket file descriptor and an associated windows event handle.
Definition: gdescriptor.h:37
A base class for classes that have a file descriptor and handle asynchronous events from the event lo...
Definition: geventhandler.h:48
A lightweight object containing an ExceptionHandler pointer, optional ExceptionSource pointer and opt...
Definition: geventstate.h:131
A derivation of GNet::SocketBase for a raw socket, typically of type AF_NETLINK or PF_ROUTE.
Definition: gsocket.h:485
A socket base class that holds a non-blocking socket file descriptor and interfaces to the event loop...
Definition: gsocket.h:53
bool eNotConn() const
Returns true if the previous socket operation failed with the ENOTCONN error status,...
bool eInProgress() const
Returns true if the previous socket operation failed with the EINPROGRESS error status.
~SocketBase() override
Destructor.
Definition: gsocket.cpp:105
std::string reason() const
Returns the reason for the previous error.
Definition: gsocket.cpp:212
void addOtherHandler(EventHandler &, EventState)
Adds this socket to the event source list so that the given handler receives exception events.
Definition: gsocket.cpp:171
SOCKET fd() const noexcept override
Returns the socket file descriptor.
Definition: gsocket.cpp:200
void clearReason()
Clears the saved errno.
Definition: gsocket.cpp:126
std::string asString() const
Returns the socket handle as a string.
Definition: gsocket.cpp:218
void dropReadHandler() noexcept
Reverses addReadHandler().
Definition: gsocket.cpp:179
void addWriteHandler(EventHandler &, EventState)
Adds this socket to the event source list so that the given handler receives write events when flow c...
Definition: gsocket.cpp:163
static bool error(int rc)
Returns true if the given return code indicates an error.
bool eMsgSize() const
Returns true if the previous socket operation failed with the EMSGSIZE error status.
void addReadHandler(EventHandler &, EventState)
Adds this socket to the event source list so that the given handler receives read events.
Definition: gsocket.cpp:155
bool isFamily(Address::Family) const
Returns true if the socket family is as given.
Definition: gsocket.cpp:111
static bool sizeError(ssize_type size)
Returns true if the given write() return value indicates an error.
bool eInUse() const
Returns true if the previous socket bind operation failed because the socket was already in use.
Descriptor fdd() const noexcept
Returns the socket descriptor.
Definition: gsocket.cpp:206
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().
Definition: gsocket.cpp:193
bool eWouldBlock() const override
Returns true if the previous socket operation failed because the socket would have blocked.
bool eTooMany() const
Returns true if the previous socket operation failed with the EMFILE error status,...
void dropWriteHandler() noexcept
Reverses addWriteHandler().
Definition: gsocket.cpp:186
void saveReason()
Saves the current errno following error()/sizeError().
An internet-protocol socket class.
Definition: gsocket.h:227
A derivation of GNet::Socket for a stream socket.
Definition: gsocket.h:356
An abstract interface for reading and writing from a non-blocking i/o channel.
Definition: greadwrite.h:50
virtual ssize_type write(const char *buf, size_type len)=0
Sends data.
virtual ssize_type read(char *buffer, size_type buffer_length)=0
Reads data.
Network classes.
Definition: gdef.h:1243
constexpr const char * tx(const char *p) noexcept
A briefer alternative to G::gettext_noop().
Definition: ggettext.h:84
STL namespace.
A configuration structure for GNet::DatagramSocket.
Definition: gsocket.h:433
Overload discriminator class for GNet::SocketBase.
Definition: gsocket.h:70
Overload discriminator class for GNet::SocketBase.
Definition: gsocket.h:72
Exception class for GNet::SocketBase bind failures.
Definition: gsocket.h:60
Overload discriminator class for GNet::Socket.
Definition: gsocket.h:230
A configuration structure for GNet::Socket.
Definition: gsocket.h:232
A configuration structure for GNet::StreamSocket.
Definition: gsocket.h:363
Overload discriminator class for GNet::StreamSocket.
Definition: gsocket.h:361