E-MailRelay

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