1 //
2 // Copyright (C) 2001-2013 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 gsimpleclient.h
19 ///
20 
21 #ifndef G_SIMPLE_CLIENT_H
22 #define G_SIMPLE_CLIENT_H
23 
24 #include "gdef.h"
25 #include "gnet.h"
26 #include "gaddress.h"
27 #include "gmemory.h"
28 #include "gconnection.h"
29 #include "gexception.h"
30 #include "geventhandler.h"
31 #include "gresolver.h"
32 #include "gresolverinfo.h"
33 #include "gsocket.h"
34 #include "gsocketprotocol.h"
35 #include "gevent.h"
36 #include <string>
37 
38 /// \namespace GNet
39 namespace GNet
40 {
41 	class SimpleClient ;
42 	class ClientResolver ;
43 }
44 
45 /// \class GNet::ClientResolver
46 /// A resolver class which calls SimpleClient::resolveCon() when done.
47 ///
48 class GNet::ClientResolver : public GNet::Resolver
49 {
50 private:
51 	SimpleClient & m_client ;
52 
53 public:
54 	explicit ClientResolver( SimpleClient & ) ;
55 		///< Constructor.
56 
57 	void resolveCon( bool success , const Address &address , std::string reason ) ;
58 		///< From Resolver.
59 
60 private:
61 	ClientResolver( const ClientResolver & ) ;
62 	void operator=( const ClientResolver & ) ;
63 } ;
64 
65 /// \class GNet::SimpleClient
66 /// A class for making an outgoing connection to a remote server, with
67 /// support for socket-level protocols such as TLS/SSL and SOCKS 4a.
68 ///
69 /// The class handles name-to-address resolution, deals with connection issues,
70 /// reads incoming data, and manages flow-control when sending. The implementation
71 /// uses the SocketProtocol class in order to do TLS/SSL; see sslConnect().
72 ///
73 /// Name-to-address lookup is performed if the supplied ResolverInfo object
74 /// does not contain an address. This can be done synchronously or asynchronously.
75 /// The results of the lookup can be obtained via the resolverInfo() method
76 /// and possibly fed back to the next SimpleClient that connects to the same
77 /// host/service in order to implement name lookup cacheing (see GNet::ClientPtr).
78 /// However, most operating systems implement their own name lookup cacheing,
79 /// so this is not terribly useful in practice.
80 ///
81 class GNet::SimpleClient : public GNet::EventHandler , public GNet::Connection , public GNet::SocketProtocolSink
82 {
83 public:
84 	enum ConnectStatus { Success , Failure , Retry , ImmediateSuccess } ;
85     enum State { Idle , Resolving , Connecting , Connected , Socksing } ;
86 	G_EXCEPTION( DnsError , "dns error" ) ;
87 	G_EXCEPTION( ConnectError , "connect failure" ) ;
88 	G_EXCEPTION( SocksError , "socks error" ) ;
89 	G_EXCEPTION( NotConnected , "socket not connected" ) ;
90 	typedef std::string::size_type size_type ;
91 
92 	SimpleClient( const ResolverInfo & remote_info ,
93 		const Address & local_address = Address(0U) ,
94 		bool privileged = false ,
95 		bool sync_dns = synchronousDnsDefault() ,
96 		unsigned int secure_connection_timeout = 0U ) ;
97 			///< Constructor.
98 			///<
99 			///< If the 'privileged' parameter is true then the
100 			///< given 'local_address' is used to bind the local
101 			///< socket once its port number has been overwritten
102 			///< with a privileged port number (ie. < 1024)
103 			///< selected at random.
104 			///<
105 			///< Otherwise, if the given 'local_address' is
106 			///< not the default value then it is used to bind
107 			///< the local socket.
108 
109 	void connect() ;
110 		///< Initates a connection to the remote server.
111 		///<
112 		///< This default implementation throws on error, and may
113 		///< call onConnect() synchronously before returning. To
114 		///< ensure onConnect() is always called asynchronously
115 		///< it can be a good idea to call connect() from a
116 		///< zero-length timer (as HeapClient does).
117 
118 	bool connected() const ;
119 		///< Returns true if connected to the peer.
120 
121 	virtual std::pair<bool,Address> localAddress() const ;
122 		///< Override from Connection. Returns the local
123 		///< address. Pair.first is false on error.
124 		///< Final override from GNet::Connection.
125 
126 	virtual std::pair<bool,Address> peerAddress() const ;
127 		///< Override from Connection. Returns the peer
128 		///< address. Pair.first is false on error.
129 		///< Final override from GNet::Connection.
130 
131 	virtual std::string peerCertificate() const ;
132 		///< Returns the peer's TLS certificate.
133 		///< Final override from GNet::Connection.
134 
135 	ResolverInfo resolverInfo() const ;
136 		///< Returns a ResolverInfo structure containing the
137 		///< result of host() and service() name lookup if
138 		///< available.
139 
140 	static bool synchronousDnsDefault() ;
141 		///< Returns true if DNS queries should normally be
142 		///< synchronous on this platform. Used to default the
143 		///< relevant constructor parameter.
144 
145 	void updateResolverInfo( const ResolverInfo & ) ;
146 		///< Updates the constructor's ResolverInfo object with
147 		///< the given one as long as both objects have the
148 		///< same host and service name. This is only useful
149 		///< immediately after construction and before
150 		///< re-entering the event loop.
151 
152 	virtual void readEvent() ;
153 		///< Final override from GNet::EventHandler.
154 
155 	virtual void writeEvent() ;
156 		///< Final override from GNet::EventHandler.
157 
158 	bool send( const std::string & data , std::string::size_type offset = 0 ) ;
159 		///< Returns true if all sent, or false if flow
160 		///< control was asserted. Throws on error.
161 
162 protected:
163 	virtual ~SimpleClient() ;
164 		///< Destructor.
165 
166 	StreamSocket & socket() ;
167 		///< Returns a reference to the socket. Throws if not connected.
168 
169 	const StreamSocket & socket() const ;
170 		///< Returns a const reference to the socket. Throws if not connected.
171 
172 	virtual void onConnect() = 0 ;
173 		///< Called once connected. May (unfortunately) be
174 		///< called from within connect().
175 
176 	virtual void onConnectImp() ;
177 		///< An alternative to onConnect() for private implementation
178 		///< classes. The default implementation does nothing.
179 
180 	virtual void onSendComplete() = 0 ;
181 		///< Called when all residual data from send() has been sent.
182 
183 	virtual void onSendImp() ;
184 		///< Called from within send().
185 
186 	void sslConnect() ;
187 		///< Starts TLS/SSL client-side negotiation.
188 
189 	static bool canRetry( const std::string & reason ) ;
190 		///< Parses the given failure reason and returns
191 		///< true if the client can reasonably retry
192 		///< at some later time. (Not used?)
193 
194 	std::string logId() const ;
195 		///< Returns a identification string for logging purposes.
196 		///< Not guaranteed to stay the same during the lifetime
197 		///< of the object.
198 
199 private:
200 	friend class ClientResolver ;
201 	void resolveCon( bool , const Address & , std::string ) ;
202 
203 private:
204 	SimpleClient( const SimpleClient& ) ; // not implemented
205 	void operator=( const SimpleClient& ) ; // not implemented
206 	void close() ;
207 	static unsigned int getRandomPort() ;
208 	bool startConnecting() ;
209 	bool localBind( Address ) ;
210 	ConnectStatus connectCore( Address remote_address , std::string *error_p ) ;
211 	void setState( State ) ;
212 	void immediateConnection() ;
213 	void sendSocksRequest() ;
214 	bool readSocksResponse() ;
215 	void logFlowControlAsserted() const ;
216 	void logFlowControlReleased() const ;
217 
218 private:
219 	std::auto_ptr<ClientResolver> m_resolver ;
220 	std::auto_ptr<StreamSocket> m_s ;
221 	std::auto_ptr<SocketProtocol> m_sp ;
222 	ResolverInfo m_remote ;
223 	Address m_local_address ;
224 	bool m_privileged ;
225 	State m_state ;
226 	bool m_sync_dns ;
227 	unsigned int m_secure_connection_timeout ;
228 } ;
229 
230 #endif
231