E-MailRelay
gsocket.h
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2021 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 <memory>
34#include <new>
35
36namespace GNet
37{
38 class SocketBase ;
39 class Socket ;
40 class SocketProtocol ;
41 class StreamSocket ;
42 class DatagramSocket ;
43 class RawSocket ;
44 class AcceptPair ;
45}
46
47//| \class GNet::SocketBase
48/// A socket base class that holds a non-blocking socket file descriptor and
49/// interfaces to the event loop.
50///
52{
53public:
54 G_EXCEPTION( SocketError , "socket error" ) ;
55 G_EXCEPTION_CLASS( SocketCreateError , "socket create error" ) ;
56 G_EXCEPTION_CLASS( SocketBindError , "socket bind error" ) ;
57 G_EXCEPTION_CLASS( SocketTooMany , "socket accept error" ) ;
58 using size_type = G::ReadWrite::size_type ;
59 using ssize_type = G::ReadWrite::ssize_type ;
60 struct Accepted /// Overload discriminator class for GNet::SocketBase.
61 {} ;
62 struct Raw /// Overload discriminator class for GNet::SocketBase.
63 {} ;
64
65 static bool supports( Address::Family , int type , int protocol ) ;
66 ///< Returns true if sockets can be created with the
67 ///< given parameters.
68
69 ~SocketBase() override ;
70 ///< Destructor. The socket file descriptor is closed and
71 ///< removed from the event loop.
72
73 SOCKET fd() const noexcept override ;
74 ///< Returns the socket file descriptor.
75
76 bool eWouldBlock() const override ;
77 ///< Returns true if the previous socket operation
78 ///< failed because the socket would have blocked.
79
80 bool eInProgress() const ;
81 ///< Returns true if the previous socket operation
82 ///< failed with the EINPROGRESS error status.
83 ///< When connecting this can be considered a
84 ///< non-error.
85
86 bool eMsgSize() const ;
87 ///< Returns true if the previous socket operation
88 ///< failed with the EMSGSIZE error status. When
89 ///< writing to a datagram socket this indicates that
90 ///< the message was too big to send atomically.
91
92 bool eTooMany() const ;
93 ///< Returns true if the previous socket operation
94 ///< failed with the EMFILE error status, or similar.
95
96 bool eNotConn() const ;
97 ///< Returns true if the previous socket operation
98 ///< failed with the ENOTCONN error status, or similar.
99
101 ///< Adds this socket to the event source list so that
102 ///< the given handler receives read events.
103
104 void dropReadHandler() noexcept ;
105 ///< Reverses addReadHandler().
106
108 ///< Adds this socket to the event source list so that
109 ///< the given handler receives write events when flow
110 ///< control is released. (Not used for datagram
111 ///< sockets.)
112
113 void dropWriteHandler() noexcept ;
114 ///< Reverses addWriteHandler().
115
117 ///< Adds this socket to the event source list so that
118 ///< the given handler receives exception events.
119 ///< A TCP exception event should be treated as a
120 ///< disconnection event. (Not used for datagram
121 ///< sockets.)
122
123 void dropOtherHandler() noexcept ;
124 ///< Reverses addOtherHandler().
125
126 std::string asString() const ;
127 ///< Returns the socket handle as a string.
128 ///< Only used in debugging.
129
130 std::string reason() const ;
131 ///< Returns the reason for the previous error.
132
133protected:
134 SocketBase( Address::Family , int type , int protocol ) ;
135 ///< Constructor used by derived classes. Creates the
136 ///< socket using socket() and makes it non-blocking.
137
138 SocketBase( Address::Family , Descriptor s ) ;
139 ///< Constructor used by derived classes. Creates the
140 ///< socket object from a newly-created socket handle
141 ///< and makes it non-blocking.
142
143 SocketBase( Address::Family , Descriptor s , const Accepted & ) ;
144 ///< Constructor used by StreamSocket::accept() to create
145 ///< a socket object from a newly accept()ed socket
146 ///< handle.
147
148 SocketBase( const Raw & , int domain , int type , int protocol ) ;
149 ///< Constructor for a raw socket.
150
151 ssize_type writeImp( const char * buf , size_type len ) ;
152 ///< Writes to the socket. This is a default implementation
153 ///< for write() that can be called from derived classes'
154 ///< overrides.
155
156 static bool error( int rc ) ;
157 ///< Returns true if the given return code indicates an
158 ///< error.
159
160 static bool sizeError( ssize_type size ) ;
161 ///< Returns true if the given write() return value
162 ///< indicates an error.
163
164 void clearReason() ;
165 ///< Clears the saved errno.
166
167 void saveReason() ;
168 ///< Saves the current errno following error()/sizeError().
169
170 void saveReason() const ;
171 ///< Saves the current errno following error()/sizeError().
172
173 bool isFamily( Address::Family ) const ;
174 ///< Returns true if the socket family is as given.
175
176private:
177 static std::string reasonString( int ) ;
178 bool create( int , int , int ) ;
179 bool prepare( bool ) ;
180 void drop() noexcept ;
181 void destroy() noexcept ;
182 void unlink() noexcept ;
183 bool setNonBlocking() ;
184
185public:
186 SocketBase( const SocketBase & ) = delete ;
187 SocketBase( SocketBase && ) = delete ;
188 void operator=( const SocketBase & ) = delete ;
189 void operator=( SocketBase && ) = delete ;
190
191private:
192 int m_reason ;
193 int m_domain ;
194 Address::Family m_family ; // valid depending on m_domain
195 Descriptor m_fd ;
196 bool m_added ;
197 bool m_accepted ;
198} ;
199
200//| \class GNet::Socket
201/// An internet-protocol socket class. Provides bind(), listen(),
202/// and connect(); the base classes provide write(); and derived
203/// classes provide accept() and read().
204///
205class GNet::Socket : public SocketBase
206{
207public:
208 Address getLocalAddress() const ;
209 ///< Retrieves local address of the socket.
210
211 std::pair<bool,Address> getPeerAddress() const ;
212 ///< Retrieves address of socket's peer.
213 ///< Returns false in 'first' if none, ie. not yet
214 ///< connected.
215
216 void bind( const Address & ) ;
217 ///< Binds the socket with the given address.
218
219 bool bind( const Address & , std::nothrow_t ) ;
220 ///< No-throw overload. Returns false on error.
221
222 static std::string canBindHint( const Address & address , bool stream_socket = true ) ;
223 ///< Returns the empty string if a socket could probably be
224 ///< bound with the given address or a failure reason.
225 ///< Some implementations will always return the empty
226 ///< string.
227
228 unsigned long getBoundScopeId() const ;
229 ///< Returns the scope-id of the address last successfully
230 ///< bind()ed. Note that getLocalAddress() has a zero
231 ///< scope-id even after bind()ing an address with
232 ///< a non-zero scope-id.
233
234 bool connect( const Address & addr , bool *done = nullptr ) ;
235 ///< Initiates a connection to (or association with)
236 ///< the given address. Returns false on error.
237 ///<
238 ///< If successful, a 'done' flag is returned by
239 ///< reference indicating whether the connect completed
240 ///< immediately. Normally a stream socket connection
241 ///< will take some time to complete so the 'done' flag
242 ///< will be false: the completion will be indicated by
243 ///< a write event some time later.
244 ///<
245 ///< For datagram sockets this sets up an association
246 ///< between two addresses. The socket should first be
247 ///< bound with a local address.
248
249 void listen( int backlog = 1 ) ;
250 ///< Starts the socket listening on the bound
251 ///< address for incoming connections or incoming
252 ///< datagrams.
253
254 void shutdown( int how = 1 ) ;
255 ///< Modifies the local socket state so that so that new
256 ///< sends (1 or 2) and/or receives (0 or 2) will fail.
257 ///<
258 ///< If receives are shut-down then anything received
259 ///< will be rejected with a RST.
260 ///<
261 ///< If sends are shut-down then the transmit queue is
262 ///< drained and a final empty FIN packet is sent when
263 ///< fully acknowledged. See also RFC-793 3.5.
264 ///<
265 ///< Errors are ignored.
266
267public:
268 ~Socket() override = default ;
269 Socket( const Socket & ) = delete ;
270 Socket( Socket && ) = delete ;
271 void operator=( const Socket & ) = delete ;
272 void operator=( Socket && ) = delete ;
273
274protected:
275 Socket( Address::Family , int type , int protocol ) ;
276 Socket( Address::Family , Descriptor s , const Accepted & ) ;
277 std::pair<bool,Address> getLocalAddress( std::nothrow_t ) const ;
278 void setOption( int , const char * , int , int ) ;
279 bool setOption( int , const char * , int , int , std::nothrow_t ) ;
280 bool setOptionImp( int , int , const void * , socklen_t ) ;
281 void setOptionsOnBind( Address::Family ) ;
282 void setOptionsOnConnect( Address::Family ) ;
283 void setOptionLingerImp( int , int ) ;
284 void setOptionNoLinger() ;
285 void setOptionReuse() ;
286 void setOptionExclusive() ;
287 void setOptionPureV6() ;
288 bool setOptionPureV6( std::nothrow_t ) ;
289 void setOptionKeepAlive() ;
290
291private:
292 unsigned long m_bound_scope_id{0UL} ;
293} ;
294
295//| \class GNet::AcceptPair
296/// A class which is used to return a new()ed socket to calling
297/// code, together with associated address information.
298///
300{
301public:
302 std::shared_ptr<StreamSocket> socket_ptr ;
303 Address address ;
304 AcceptPair() : address(Address::defaultAddress()) {}
305} ;
306
307//| \class GNet::StreamSocket
308/// A derivation of GNet::Socket for a stream socket.
309///
311{
312public:
313 using size_type = Socket::size_type ;
314 using ssize_type = Socket::ssize_type ;
315 struct Listener /// Overload discriminator class for GNet::StreamSocket.
316 {} ;
317
318 static bool supports( Address::Family ) ;
319 ///< Returns true if stream sockets can be created with the
320 ///< given the address family. This is a one-off run-time
321 ///< check on socket creation, with a warning if it fails.
322 ///< Note that a run-time check is useful when running a
323 ///< new binary on an old operating system.
324
325 explicit StreamSocket( Address::Family ) ;
326 ///< Constructor.
327
328 StreamSocket( Address::Family , const Listener & ) ;
329 ///< Constructor overload specifically for a listening
330 ///< socket, which might need slightly different socket
331 ///< options.
332
333 ssize_type read( char * buffer , size_type buffer_length ) override ;
334 ///< Override from ReadWrite::read().
335
336 ssize_type write( const char * buf , size_type len ) override ;
337 ///< Override from Socket::write().
338
339 AcceptPair accept() ;
340 ///< Accepts an incoming connection, returning a new()ed
341 ///< socket and the peer address.
342
343public:
344 ~StreamSocket() override = default ;
345 StreamSocket( const StreamSocket & ) = delete ;
346 StreamSocket( StreamSocket && ) = delete ;
347 void operator=( const StreamSocket & ) = delete ;
348 void operator=( StreamSocket && ) = delete ;
349
350private:
351 StreamSocket( Address::Family , Descriptor s , const Accepted & ) ;
352 void setOptionsOnCreate( Address::Family , bool listener ) ;
353 void setOptionsOnAccept( Address::Family ) ;
354} ;
355
356//| \class GNet::DatagramSocket
357/// A derivation of GNet::Socket for a datagram socket.
358///
360{
361public:
362 explicit DatagramSocket( Address::Family , int protocol = 0 ) ;
363 ///< Constructor.
364
365 ssize_type read( char * buffer , size_type len ) override ;
366 ///< Override from ReadWrite::read().
367
368 ssize_type write( const char * buffer , size_type len ) override ;
369 ///< Override from Socket::write().
370
371 ssize_type readfrom( char * buffer , size_type len , Address & src ) ;
372 ///< Reads a datagram and returns the sender's address by reference.
373 ///< If connect() has been used then only datagrams from the address
374 ///< specified in the connect() call will be received.
375
376 ssize_type writeto( const char * buffer , size_type len , const Address & dst ) ;
377 ///< Sends a datagram to the given address. This should be used
378 ///< if there is no connect() assocation in effect.
379
380 void disconnect() ;
381 ///< Releases the association between two datagram endpoints
382 ///< reversing the effect of the previous Socket::connect().
383
384public:
385 ~DatagramSocket() override = default ;
386 DatagramSocket( const DatagramSocket & ) = delete ;
387 DatagramSocket( DatagramSocket && ) = delete ;
388 void operator=( const DatagramSocket & ) = delete ;
389 void operator=( DatagramSocket && ) = delete ;
390} ;
391
392//| \class GNet::RawSocket
393/// A derivation of GNet::SocketBase for a raw socket, typically of
394/// type AF_NETLINK or PF_ROUTE.
395///
397{
398public:
399 RawSocket( int domain , int type , int protocol ) ;
400 ///< Constructor.
401
402 ssize_type read( char * buffer , size_type buffer_length ) override ;
403 ///< Reads from the socket.
404
405 ssize_type write( const char * buf , size_type len ) override ;
406 ///< Writes to the socket.
407
408public:
409 ~RawSocket() override = default ;
410 RawSocket( const RawSocket & ) = delete ;
411 RawSocket( RawSocket && ) = delete ;
412 void operator=( const RawSocket & ) = delete ;
413 void operator=( RawSocket && ) = delete ;
414} ;
415
416#endif
A class which is used to return a new()ed socket to calling code, together with associated address in...
Definition: gsocket.h:300
The GNet::Address class encapsulates a TCP/UDP transport address.
Definition: gaddress.h:53
static Address defaultAddress()
Returns a default address, being the IPv4 wildcard address with a zero port number.
Definition: gaddress.cpp:242
A derivation of GNet::Socket for a datagram socket.
Definition: gsocket.h:360
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 handle asynchronous events from the event loop.
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:397
A socket base class that holds a non-blocking socket file descriptor and interfaces to the event loop...
Definition: gsocket.h:52
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:123
std::string reason() const
Returns the reason for the previous error.
Definition: gsocket.cpp:216
SOCKET fd() const noexcept override
Returns the socket file descriptor.
Definition: gsocket.cpp:211
void clearReason()
Clears the saved errno.
Definition: gsocket.cpp:143
std::string asString() const
Returns the socket handle as a string.
Definition: gsocket.cpp:222
void dropReadHandler() noexcept
Reverses addReadHandler().
Definition: gsocket.cpp:193
void addOtherHandler(EventHandler &, ExceptionSink)
Adds this socket to the event source list so that the given handler receives exception events.
Definition: gsocket.cpp:186
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:129
void addReadHandler(EventHandler &, ExceptionSink)
Adds this socket to the event source list so that the given handler receives read events.
Definition: gsocket.cpp:172
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:179
void dropOtherHandler() noexcept
Reverses addOtherHandler().
Definition: gsocket.cpp:205
ssize_type writeImp(const char *buf, size_type len)
Writes to the socket.
Definition: gsocket.cpp:153
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:199
void saveReason()
Saves the current errno following error()/sizeError().
An internet-protocol socket class.
Definition: gsocket.h:206
A derivation of GNet::Socket for a stream socket.
Definition: gsocket.h:311
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:1115
Overload discriminator class for GNet::SocketBase.
Definition: gsocket.h:61
Overload discriminator class for GNet::SocketBase.
Definition: gsocket.h:63
Overload discriminator class for GNet::StreamSocket.
Definition: gsocket.h:316