E-MailRelay
gclient.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 gclient.h
19///
20
21#ifndef G_NET_CLIENT_H
22#define G_NET_CLIENT_H
23
24#include "gdef.h"
25#include "gaddress.h"
26#include "gsocks.h"
27#include "gconnection.h"
28#include "gexception.h"
29#include "gexceptionsource.h"
30#include "geventhandler.h"
31#include "gresolver.h"
32#include "glocation.h"
33#include "glinebuffer.h"
34#include "gstringview.h"
35#include "gcall.h"
36#include "gtimer.h"
37#include "gsocket.h"
38#include "gsocketprotocol.h"
39#include "gevent.h"
40#include "gslot.h"
41#include "gstr.h"
42#include <string>
43#include <memory>
44
45namespace GNet
46{
47 class Client ;
48}
49
50//| \class GNet::Client
51/// A class for making an outgoing connection to a remote server, with support
52/// for socket-level protocols such as TLS/SSL and SOCKS 4a.
53///
54/// The class handles name-to-address resolution, deals with connection issues,
55/// reads incoming data, and manages flow-control when sending. The
56/// implementation uses the SocketProtocol class in order to do TLS/SSL;
57/// see secureConnect().
58///
59/// Name-to-address lookup is performed if the supplied Location object does
60/// not contain an address. This can be done synchronously or asynchronously.
61/// The results of the lookup can be obtained via the remoteLocation()
62/// method and possibly fed back to the next Client that connects to the
63/// same host/service in order to implement name lookup cacheing.
64///
65/// Received data is delivered through a virtual method onReceive(), with
66/// optional line-buffering.
67///
68/// Clients should normally be instantiated on the heap and managed by a
69/// ClientPtr so that the onDelete() mechanism works as advertised: the
70/// ExceptionHandler passed to the Client constructor via the ExceptionSink
71/// object should be the ClientPtr instance. Clients that decide to
72/// terminate themselves cleanly should call Client::finish() and then throw
73/// a GNet::Done exception.
74///
76{
77public:
78 G_EXCEPTION( DnsError , tx("dns error") ) ;
79 G_EXCEPTION( ConnectError , tx("connect failure") ) ;
80 G_EXCEPTION( NotConnected , tx("socket not connected") ) ;
81 G_EXCEPTION( ResponseTimeout , tx("response timeout") ) ;
82 G_EXCEPTION( IdleTimeout , tx("idle timeout") ) ;
83
84 struct Config /// A structure containing GNet::Client configuration parameters.
85 {
86 StreamSocket::Config stream_socket_config ;
87 LineBuffer::Config line_buffer_config {LineBuffer::Config::transparent()} ;
88 SocketProtocol::Config socket_protocol_config ; // inc. secure_connection_timeout
89 Address local_address {Address::defaultAddress()} ;
90 bool sync_dns {false} ;
91 bool auto_start {true} ;
92 bool bind_local_address {false} ;
93 unsigned int connection_timeout {0U} ;
94 unsigned int response_timeout {0U} ;
95 unsigned int idle_timeout {0U} ;
96 bool no_throw_on_peer_disconnect {false} ; // see SocketProtocolSink::onPeerDisconnect()
97
98 Config & set_stream_socket_config( const StreamSocket::Config & ) ;
99 Config & set_line_buffer_config( const LineBuffer::Config & ) ;
100 Config & set_socket_protocol_config( const SocketProtocol::Config & ) ;
101 Config & set_sync_dns( bool = true ) noexcept ;
102 Config & set_auto_start( bool = true ) noexcept ;
103 Config & set_bind_local_address( bool = true ) noexcept ;
104 Config & set_local_address( const Address & ) ;
105 Config & set_connection_timeout( unsigned int ) noexcept ;
106 Config & set_secure_connection_timeout( unsigned int ) noexcept ;
107 Config & set_response_timeout( unsigned int ) noexcept ;
108 Config & set_idle_timeout( unsigned int ) noexcept ;
109 Config & set_all_timeouts( unsigned int ) noexcept ;
110 Config & set_no_throw_on_peer_disconnect( bool = true ) noexcept ;
111 } ;
112
113 Client( ExceptionSink , const Location & remote_location , const Config & ) ;
114 ///< Constructor. If not auto-starting then connect()
115 ///< is required to start connecting. The ExceptionSink
116 ///< should delete this Client object when an exception is
117 ///< delivered to it, otherwise the the underlying socket
118 ///< might continue to raise events.
119
120 ~Client() override ;
121 ///< Destructor.
122
123 void connect() ;
124 ///< Initiates a connection to the remote server. Calls back
125 ///< to onConnect() when complete (non-reentrantly). Throws
126 ///< on immediate failure.
127
128 bool connected() const ;
129 ///< Returns true if connected to the peer.
130
131 bool hasConnected() const ;
132 ///< Returns true if ever connected().
133
134 std::string peerAddressString( bool with_port = true ) const ;
135 ///< Returns the peer address display string
136 ///< or the empty string if not connected().
137
138 void disconnect() ;
139 ///< Aborts the connection and destroys the object's internal
140 ///< state, resulting in a zombie object. After disconnect()
141 ///< only calls to hasConnected(), finished() and the dtor
142 ///< are allowed.
143
144 Address localAddress() const override ;
145 ///< Returns the local address.
146 ///< Override from GNet::Connection.
147
148 Address peerAddress() const override ;
149 ///< Returns the peer address. Throws if not connected().
150 ///< Override from GNet::Connection.
151
152 std::string connectionState() const override ;
153 ///< Returns the connection state display string.
154 ///< Override from GNet::Connection.
155
156 std::string peerCertificate() const override ;
157 ///< Returns the peer's TLS certificate.
158 ///< Override from GNet::Connection.
159
160 Location remoteLocation() const ;
161 ///< Returns a Location structure, including the result of
162 ///< name lookup if available.
163
164 bool send( const std::string & data ) ;
165 ///< Sends data to the peer and starts the response
166 ///< timer (if configured). Returns true if all sent.
167 ///< Returns false if flow control was asserted, in which
168 ///< case the unsent portion is copied internally and
169 ///< onSendComplete() called when complete. Throws on error.
170
171 bool send( G::string_view data ) ;
172 ///< Overload for string_view.
173
174 bool send( const std::vector<G::string_view> & data , std::size_t offset = 0 ) ;
175 ///< Overload for scatter/gather segments.
176
178 ///< Returns a signal that indicates that something interesting
179 ///< has happened. The first signal parameter is one of
180 ///< "resolving", "connecting", or "connected", but other
181 ///< classes may inject the own events into this channel.
182
183 void doOnDelete( const std::string & reason , bool done ) ;
184 ///< This should be called by the Client owner (typically
185 ///< ClientPtr) just before this Client object is deleted
186 ///< as the result of an exception.
187 ///<
188 ///< A Client onDelete() call only ever comes from
189 ///< something external calling doOnDelete().
190 ///<
191 ///< The 'done' argument should be true if the current
192 ///< exception is GNet::Done. The 'reason' string passed
193 ///< to onDelete() will be the given 'reason' or the
194 ///< empty string if 'done||finished()'.
195 ///<
196 ///< See also GNet::ExceptionHandler::onException(),
197 ///< GNet::ServerPeer::onDelete().
198
199 bool finished() const ;
200 ///< Returns true if finish() has been called.
201
203 ///< Returns information about the state of the internal
204 ///< line-buffer.
205
206 bool secureConnectCapable() const ;
207 ///< Returns true if currently connected and secureConnect()
208 ///< can be used. Typically called from within the onConnect()
209 ///< callback.
210
211protected:
212 StreamSocket & socket() ;
213 ///< Returns a reference to the socket. Throws if not connected.
214
215 const StreamSocket & socket() const ;
216 ///< Returns a const reference to the socket. Throws if not connected.
217
218 void finish() ;
219 ///< Indicates that the last data has been sent and the client
220 ///< is expecting a peer disconnect. Any subsequent onDelete()
221 ///< callback from doOnDelete() will have an empty reason
222 ///< string.
223
224 void clearInput() ;
225 ///< Clears the input LineBuffer and cancels the response
226 ///< timer if running.
227
228 virtual bool onReceive( const char * data , std::size_t size , std::size_t eolsize , std::size_t linesize , char c0 ) = 0 ;
229 ///< Called with received data. If configured with no line
230 ///< buffering then only the first two parameters are
231 ///< relevant. The implementation should return false if
232 ///< it needs to stop further onReceive() calls being
233 ///< generated from data already received and buffered.
234
235 virtual void onConnect() = 0 ;
236 ///< Called once connected.
237
238 virtual void onSendComplete() = 0 ;
239 ///< Called when all residual data from send() has been sent.
240
241 virtual void onDelete( const std::string & reason ) = 0 ;
242 ///< Called just before ClientPtr destroys the Client as the
243 ///< result of handling an exception. The reason is the empty
244 ///< string if caused by a GNet::Done exception, or after
245 ///< finish() or disconnect(). Consider making the
246 ///< implementation non-throwing, in the spirit of a
247 ///< destructor, since the Client object is about to be
248 ///< deleted.
249
250 void secureConnect() ;
251 ///< Starts TLS/SSL client-side negotiation. Uses a profile
252 ///< called "client" by default; see GSsl::Library::addProfile().
253 ///< The callback GNet::SocketProtocolSink::onSecure() is
254 ///< triggered when the secure session is established.
255
256private: // overrides
257 void readEvent() override ; // Override from GNet::EventHandler.
258 void writeEvent() override ; // Override from GNet::EventHandler.
259 void otherEvent( EventHandler::Reason ) override ; // Override from GNet::EventHandler.
260 void onResolved( std::string , Location ) override ; // Override from GNet::Resolver.
261 void onData( const char * , std::size_t ) override ; // Override from GNet::SocketProtocolSink.
262 void onPeerDisconnect() override ; // Override from GNet::SocketProtocolSink.
263
264public:
265 Client( const Client & ) = delete ;
266 Client( Client && ) = delete ;
267 Client & operator=( const Client & ) = delete ;
268 Client & operator=( Client && ) = delete ;
269 bool send( const char * , std::size_t ) = delete ;
270 bool send( const char * ) = delete ;
271 bool send( const std::string & , std::size_t ) = delete ;
272
273private:
274 enum class State
275 {
276 Idle ,
277 Resolving ,
278 Connecting ,
279 Connected ,
280 Socksing ,
281 Disconnected ,
282 Testing
283 } ;
284 bool onDataImp( const char * , std::size_t , std::size_t , std::size_t , char ) ;
285 void emit( const std::string & ) ;
286 void startConnecting() ;
287 void bindLocalAddress( const Address & ) ;
288 void setState( State ) ;
289 void onStartTimeout() ;
290 void onConnectTimeout() ;
291 void onConnectedTimeout() ;
292 void onResponseTimeout() ;
293 void onIdleTimeout() ;
294 void onWriteable() ;
295 void doOnConnect() ;
296
297private:
298 ExceptionSink m_es ;
299 const Config m_config ;
300 G::CallStack m_call_stack ;
301 std::unique_ptr<StreamSocket> m_socket ;
302 std::unique_ptr<SocketProtocol> m_sp ;
303 std::unique_ptr<Socks> m_socks ;
304 LineBuffer m_line_buffer ;
305 std::unique_ptr<Resolver> m_resolver ;
306 Location m_remote_location ;
307 State m_state ;
308 bool m_finished ;
309 bool m_has_connected ;
310 Timer<Client> m_start_timer ;
311 Timer<Client> m_connect_timer ;
312 Timer<Client> m_connected_timer ;
313 Timer<Client> m_response_timer ;
314 Timer<Client> m_idle_timer ;
316} ;
317
318inline GNet::Client::Config & GNet::Client::Config::set_stream_socket_config( const StreamSocket::Config & cfg ) { stream_socket_config = cfg ; return *this ; }
319inline GNet::Client::Config & GNet::Client::Config::set_line_buffer_config( const LineBuffer::Config & cfg ) { line_buffer_config = cfg ; return *this ; }
320inline GNet::Client::Config & GNet::Client::Config::set_socket_protocol_config( const SocketProtocol::Config & cfg ) { socket_protocol_config = cfg ; return *this ; }
321inline GNet::Client::Config & GNet::Client::Config::set_sync_dns( bool b ) noexcept { sync_dns = b ; return *this ; }
322inline GNet::Client::Config & GNet::Client::Config::set_auto_start( bool b ) noexcept { auto_start = b ; return *this ; }
323inline GNet::Client::Config & GNet::Client::Config::set_bind_local_address( bool b ) noexcept { bind_local_address = b ; return *this ; }
324inline GNet::Client::Config & GNet::Client::Config::set_local_address( const Address & a ) { local_address = a ; return *this ; }
325inline GNet::Client::Config & GNet::Client::Config::set_connection_timeout( unsigned int t ) noexcept { connection_timeout = t ; return *this ; }
326inline GNet::Client::Config & GNet::Client::Config::set_secure_connection_timeout( unsigned int t ) noexcept { socket_protocol_config.secure_connection_timeout = t ; return *this ; }
327inline GNet::Client::Config & GNet::Client::Config::set_response_timeout( unsigned int t ) noexcept { response_timeout = t ; return *this ; }
328inline GNet::Client::Config & GNet::Client::Config::set_idle_timeout( unsigned int t ) noexcept { idle_timeout = t ; return *this ; }
329inline GNet::Client::Config & GNet::Client::Config::set_no_throw_on_peer_disconnect( bool b ) noexcept { no_throw_on_peer_disconnect = b ; return *this ; }
330
331#endif
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 class for making an outgoing connection to a remote server, with support for socket-level protocols...
Definition: gclient.h:76
virtual void onSendComplete()=0
Called when all residual data from send() has been sent.
void disconnect()
Aborts the connection and destroys the object's internal state, resulting in a zombie object.
Definition: gclient.cpp:63
std::string peerCertificate() const override
Returns the peer's TLS certificate.
Definition: gclient.cpp:467
std::string peerAddressString(bool with_port=true) const
Returns the peer address display string or the empty string if not connected().
Definition: gclient.cpp:446
void secureConnect()
Starts TLS/SSL client-side negotiation.
Definition: gclient.cpp:479
~Client() override
Destructor.
Definition: gclient.cpp:57
bool secureConnectCapable() const
Returns true if currently connected and secureConnect() can be used.
Definition: gclient.cpp:473
G::Slot::Signal< const std::string &, const std::string &, const std::string & > & eventSignal() noexcept
Returns a signal that indicates that something interesting has happened.
Definition: gclient.cpp:82
Address localAddress() const override
Returns the local address.
Definition: gclient.cpp:429
StreamSocket & socket()
Returns a reference to the socket. Throws if not connected.
Definition: gclient.cpp:92
std::string connectionState() const override
Returns the connection state display string.
Definition: gclient.cpp:459
bool finished() const
Returns true if finish() has been called.
Definition: gclient.cpp:226
void finish()
Indicates that the last data has been sent and the client is expecting a peer disconnect.
Definition: gclient.cpp:212
LineBufferState lineBuffer() const
Returns information about the state of the internal line-buffer.
Definition: gclient.cpp:512
bool hasConnected() const
Returns true if ever connected().
Definition: gclient.cpp:231
bool connected() const
Returns true if connected to the peer.
Definition: gclient.cpp:398
virtual bool onReceive(const char *data, std::size_t size, std::size_t eolsize, std::size_t linesize, char c0)=0
Called with received data.
Location remoteLocation() const
Returns a Location structure, including the result of name lookup if available.
Definition: gclient.cpp:87
Address peerAddress() const override
Returns the peer address.
Definition: gclient.cpp:434
bool send(const std::string &data)
Sends data to the peer and starts the response timer (if configured).
Definition: gclient.cpp:486
virtual void onConnect()=0
Called once connected.
Client(ExceptionSink, const Location &remote_location, const Config &)
Constructor.
Definition: gclient.cpp:37
void connect()
Initiates a connection to the remote server.
Definition: gclient.cpp:118
void doOnDelete(const std::string &reason, bool done)
This should be called by the Client owner (typically ClientPtr) just before this Client object is del...
Definition: gclient.cpp:236
virtual void onDelete(const std::string &reason)=0
Called just before ClientPtr destroys the Client as the result of handling an exception.
void clearInput()
Clears the input LineBuffer and cancels the response timer if running.
Definition: gclient.cpp:106
An abstract interface which provides information about a network connection.
Definition: gconnection.h:38
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 mixin base class that identifies the source of an exception when delivered to GNet::ExceptionHandle...
Provides information about the state of a line buffer.
Definition: glinebuffer.h:340
A class that does line buffering, supporting auto-detection of line endings and fixed-size block extr...
Definition: glinebuffer.h:83
A class that represents the remote target for out-going client connections.
Definition: glocation.h:71
An interface used by GNet::SocketProtocol to deliver data from a socket.
A derivation of GNet::Socket for a stream socket.
Definition: gsocket.h:341
A timer class template in which the timeout is delivered to the specified method.
Definition: gtimer.h:141
A linked list of CallFrame pointers.
Definition: gcall.h:59
A class like c++17's std::string_view.
Definition: gstringview.h:51
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 structure containing GNet::Client configuration parameters.
Definition: gclient.h:85
A configuration structure for GNet::LineBuffer.
Definition: glinebuffer.h:91
An interface used for GNet::Resolver callbacks.
Definition: gresolver.h:52
A configuration structure for GNet::SocketProtocol.
A configuration structure for GNet::StreamSocket.
Definition: gsocket.h:348