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