E-MailRelay
gsocketprotocol.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 gsocketprotocol.h
19///
20
21#ifndef G_NET_SOCKET_PROTOCOL_H
22#define G_NET_SOCKET_PROTOCOL_H
23
24#include "gdef.h"
25#include "gsocket.h"
26#include "geventhandler.h"
27#include "gexception.h"
28#include "gstringview.h"
29#include "glimits.h"
30#include <string>
31#include <memory>
32#include <utility>
33#include <vector>
34
35namespace GNet
36{
37 class SocketProtocol ;
38 class SocketProtocolImp ;
39 class SocketProtocolSink ;
40}
41
42//| \class GNet::SocketProtocol
43/// An interface for implementing a low-level TLS/SSL protocol layer on top
44/// of a connected non-blocking socket.
45///
46/// Provides send() to send data, and onData() in a callback interface to
47/// receive data. The TLS/SSL socket protocol session is negotiated with the
48/// peer by calling secureConnect() or secureAccept(), and thereafter the
49/// interface is half-duplex. If no TLS/SSL session is in effect ('raw') then
50/// the protocol layer is transparent down to the socket.
51///
52/// The interface has read-event and write-event handlers that should be
53/// called when events are detected on the socket file descriptor. In raw
54/// mode the read handler delivers data via the onData() callback interface
55/// and the write handler is used to flush the output pipeline.
56///
58{
59public:
60 using Sink = SocketProtocolSink ;
61 G_EXCEPTION_CLASS( ReadError , tx("peer disconnected") )
62 G_EXCEPTION( SendError , tx("peer disconnected") )
63 G_EXCEPTION( ShutdownError , tx("shutdown error") )
64 G_EXCEPTION( SecureConnectionTimeout , tx("secure connection timeout") )
65 G_EXCEPTION( Shutdown , tx("peer shutdown") )
66 G_EXCEPTION( OtherEventError , tx("network event") )
67 G_EXCEPTION( ProtocolError , tx("socket protocol error") )
68
69 struct Config /// A configuration structure for GNet::SocketProtocol.
70 {
71 std::size_t read_buffer_size {G::Limits<>::net_buffer} ;
72 unsigned int secure_connection_timeout {0U} ;
73 std::string server_tls_profile ;
74 std::string client_tls_profile ;
75 Config & set_read_buffer_size( std::size_t n ) noexcept ;
76 Config & set_secure_connection_timeout( unsigned int t ) noexcept ;
77 Config & set_server_tls_profile( const std::string & s ) ;
78 Config & set_client_tls_profile( const std::string & s ) ;
79 } ;
80
82 StreamSocket & , const Config & ) ;
83 ///< Constructor.
84
86 ///< Destructor.
87
88 bool readEvent( bool no_throw_on_peer_disconnect = false ) ;
89 ///< Called on receipt of a read event. Delivers data via the
90 ///< sink interface onData(). By default throws ReadError on
91 ///< disconnection, or uses the onPeerDisconnect() callback
92 ///< otherwise. Returns true iff an incomplete send()
93 ///< over TLS has now completed.
94
95 bool writeEvent() ;
96 ///< Called on receipt of a write event. Sends more pending data
97 ///< down the connection. Returns true if an incomplete send() has
98 ///< now completed. Throws SendError on error.
99
100 void otherEvent( EventHandler::Reason , bool no_throw_on_peer_disconnect = false ) ;
101 ///< Called on receipt of an 'other' event. Any pending read
102 ///< data is delivered via onData() and if this is a peer
103 ///< disconnect event on a raw() socket (Windows) and the
104 ///< 'no_throw_on_peer_disconnect' parameter is true the
105 ///< onPeerDisconnect() is called and the method returns
106 ///< normally, otherwise an exception is thrown.
107
108 bool send( const std::string & data , std::size_t offset ) ;
109 ///< Sends data. Returns false if flow control asserted before
110 ///< all the data is sent. Returns true if all the data was sent,
111 ///< or if the data passed in (taking the offset into account)
112 ///< is empty. Throws SendError on error.
113 ///<
114 ///< If flow control is asserted then the socket write-event
115 ///< handler is installed and send() returns false. Unsent
116 ///< portions of the data string are copied internally. When
117 ///< the subsequent write-event is triggered the user should
118 ///< call writeEvent(). There should be no new calls to send()
119 ///< until writeEvent() or readEvent() returns true.
120
121 bool send( std::string_view data ) ;
122 ///< Overload for string_view.
123
124 bool send( const std::vector<std::string_view> & data , std::size_t offset = 0U ) ;
125 ///< Overload to send data using scatter-gather segments.
126 ///< In this overload any unsent residue is not copied
127 ///< and the segment pointers must stay valid until
128 ///< writeEvent() returns true.
129
130 void shutdown() ;
131 ///< Initiates a TLS-close if secure, together with a
132 ///< Socket::shutdown(1).
133
134 bool secureConnectCapable() const ;
135 ///< Returns true if the implementation supports TLS/SSL and a
136 ///< "client" profile has been configured. See also GSsl::enabledAs().
137
138 void secureConnect() ;
139 ///< Initiates the TLS/SSL handshake, acting as a client.
140 ///< Any send() data blocked by flow control is discarded.
141
142 bool secureAcceptCapable() const ;
143 ///< Returns true if the implementation supports TLS/SSL and a
144 ///< "server" profile has been configured. See also GSsl::enabledAs().
145
146 void secureAccept() ;
147 ///< Waits for the TLS/SSL handshake protocol, acting as a server.
148 ///< Any send() data blocked by flow control is discarded.
149
150 bool secure() const ;
151 ///< Returns true if the connection is currently secure
152 ///< ie. after onSecure(). Returns false if busy with the
153 ///< TLS/SSL handshake.
154
155 bool raw() const ;
156 ///< Returns true if no TLS/SSL.
157
158 std::string peerCertificate() const ;
159 ///< Returns the peer's TLS/SSL certificate or the empty
160 ///< string.
161
162public:
163 SocketProtocol( const SocketProtocol & ) = delete ;
164 SocketProtocol( SocketProtocol && ) = delete ;
165 SocketProtocol & operator=( const SocketProtocol & ) = delete ;
166 SocketProtocol & operator=( SocketProtocol && ) = delete ;
167
168private:
169 std::unique_ptr<SocketProtocolImp> m_imp ;
170} ;
171
172//| \class GNet::SocketProtocolSink
173/// An interface used by GNet::SocketProtocol to deliver data
174/// from a socket.
175///
177{
178public:
179 virtual ~SocketProtocolSink() = default ;
180 ///< Destructor.
181
182 virtual void onData( const char * , std::size_t ) = 0 ;
183 ///< Called when data is read from the socket.
184
185 virtual void onSecure( const std::string & peer_certificate ,
186 const std::string & protocol , const std::string & cipher ) = 0 ;
187 ///< Called once the secure socket protocol has
188 ///< been successfully negotiated.
189
190 virtual void onPeerDisconnect() = 0 ;
191 ///< Called, if enabled by the readEvent()/otherEvent() parameter,
192 ///< when the peer disconnects with a socket shutdown. This tells
193 ///< us that the peer will not send any more data but we can
194 ///< keep sending. The SocketProtocol class will have already
195 ///< dropped the socket read handler. If we have previously
196 ///< done our own shutdown then both directions are now closed
197 ///< and the connection is defunct.
198} ;
199
200inline GNet::SocketProtocol::Config & GNet::SocketProtocol::Config::set_read_buffer_size( std::size_t n ) noexcept { read_buffer_size = n ; return *this ; }
201inline GNet::SocketProtocol::Config & GNet::SocketProtocol::Config::set_secure_connection_timeout( unsigned int t ) noexcept { secure_connection_timeout = t ; return *this ; }
202inline GNet::SocketProtocol::Config & GNet::SocketProtocol::Config::set_server_tls_profile( const std::string & s ) { server_tls_profile = s ; return *this ; }
203inline GNet::SocketProtocol::Config & GNet::SocketProtocol::Config::set_client_tls_profile( const std::string & s ) { client_tls_profile = s ; return *this ; }
204
205#endif
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
An interface used by GNet::SocketProtocol to deliver data from a socket.
virtual ~SocketProtocolSink()=default
Destructor.
virtual void onPeerDisconnect()=0
Called, if enabled by the readEvent()/otherEvent() parameter, when the peer disconnects with a socket...
virtual void onSecure(const std::string &peer_certificate, const std::string &protocol, const std::string &cipher)=0
Called once the secure socket protocol has been successfully negotiated.
virtual void onData(const char *, std::size_t)=0
Called when data is read from the socket.
An interface for implementing a low-level TLS/SSL protocol layer on top of a connected non-blocking s...
bool readEvent(bool no_throw_on_peer_disconnect=false)
Called on receipt of a read event.
bool send(const std::string &data, std::size_t offset)
Sends data.
SocketProtocol(EventHandler &, EventState, Sink &, StreamSocket &, const Config &)
Constructor.
bool writeEvent()
Called on receipt of a write event.
bool secure() const
Returns true if the connection is currently secure ie.
bool secureAcceptCapable() const
Returns true if the implementation supports TLS/SSL and a "server" profile has been configured.
void secureAccept()
Waits for the TLS/SSL handshake protocol, acting as a server.
~SocketProtocol()
Destructor.
void otherEvent(EventHandler::Reason, bool no_throw_on_peer_disconnect=false)
Called on receipt of an 'other' event.
void shutdown()
Initiates a TLS-close if secure, together with a Socket::shutdown(1).
std::string peerCertificate() const
Returns the peer's TLS/SSL certificate or the empty string.
bool secureConnectCapable() const
Returns true if the implementation supports TLS/SSL and a "client" profile has been configured.
bool raw() const
Returns true if no TLS/SSL.
void secureConnect()
Initiates the TLS/SSL handshake, acting as a client.
A derivation of GNet::Socket for a stream socket.
Definition: gsocket.h:356
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
A configuration structure for GNet::SocketProtocol.
A set of compile-time buffer sizes.
Definition: glimits.h:48