1 | /** \file TcpSocket.h |
---|
2 | ** \date 2004-02-13 |
---|
3 | ** \author grymse@alhem.net |
---|
4 | **/ |
---|
5 | /* |
---|
6 | Copyright (C) 2004-2007 Anders Hedstrom |
---|
7 | |
---|
8 | This library is made available under the terms of the GNU GPL. |
---|
9 | |
---|
10 | If you would like to use this library in a closed-source application, |
---|
11 | a separate license agreement is available. For information about |
---|
12 | the closed-source license agreement for the C++ sockets library, |
---|
13 | please visit http://www.alhem.net/Sockets/license.html and/or |
---|
14 | email license@alhem.net. |
---|
15 | |
---|
16 | This program is free software; you can redistribute it and/or |
---|
17 | modify it under the terms of the GNU General Public License |
---|
18 | as published by the Free Software Foundation; either version 2 |
---|
19 | of the License, or (at your option) any later version. |
---|
20 | |
---|
21 | This program is distributed in the hope that it will be useful, |
---|
22 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
23 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
24 | GNU General Public License for more details. |
---|
25 | |
---|
26 | You should have received a copy of the GNU General Public License |
---|
27 | along with this program; if not, write to the Free Software |
---|
28 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
---|
29 | */ |
---|
30 | #ifndef _SOCKETS_TcpSocket_H |
---|
31 | #define _SOCKETS_TcpSocket_H |
---|
32 | #include "sockets-config.h" |
---|
33 | #include "StreamSocket.h" |
---|
34 | #ifdef HAVE_OPENSSL |
---|
35 | #include <openssl/ssl.h> |
---|
36 | #include "SSLInitializer.h" |
---|
37 | #endif |
---|
38 | |
---|
39 | #include <string.h> |
---|
40 | |
---|
41 | #define TCP_BUFSIZE_READ 16400 |
---|
42 | #define TCP_OUTPUT_CAPACITY 1024000 |
---|
43 | |
---|
44 | |
---|
45 | #ifdef SOCKETS_NAMESPACE |
---|
46 | namespace SOCKETS_NAMESPACE { |
---|
47 | #endif |
---|
48 | |
---|
49 | class SocketAddress; |
---|
50 | |
---|
51 | |
---|
52 | /** Socket implementation for TCP. |
---|
53 | \ingroup basic */ |
---|
54 | class TcpSocket : public StreamSocket |
---|
55 | { |
---|
56 | /** \defgroup internal Internal utility */ |
---|
57 | protected: |
---|
58 | /** Buffer class containing one read/write circular buffer. |
---|
59 | \ingroup internal */ |
---|
60 | class CircularBuffer |
---|
61 | { |
---|
62 | public: |
---|
63 | CircularBuffer(size_t size); |
---|
64 | ~CircularBuffer(); |
---|
65 | |
---|
66 | /** append l bytes from p to buffer */ |
---|
67 | bool Write(const char *p,size_t l); |
---|
68 | /** copy l bytes from buffer to dest */ |
---|
69 | bool Read(char *dest,size_t l); |
---|
70 | /** copy l bytes from buffer to dest, dont touch buffer pointers */ |
---|
71 | bool SoftRead(char *dest, size_t l); |
---|
72 | /** skip l bytes from buffer */ |
---|
73 | bool Remove(size_t l); |
---|
74 | /** read l bytes from buffer, returns as string. */ |
---|
75 | std::string ReadString(size_t l); |
---|
76 | |
---|
77 | /** total buffer length */ |
---|
78 | size_t GetLength(); |
---|
79 | /** pointer to circular buffer beginning */ |
---|
80 | const char *GetStart(); |
---|
81 | /** return number of bytes from circular buffer beginning to buffer physical end */ |
---|
82 | size_t GetL(); |
---|
83 | /** return free space in buffer, number of bytes until buffer overrun */ |
---|
84 | size_t Space(); |
---|
85 | |
---|
86 | /** return total number of bytes written to this buffer, ever */ |
---|
87 | unsigned long ByteCounter(bool clear = false); |
---|
88 | |
---|
89 | private: |
---|
90 | CircularBuffer(const CircularBuffer& /*s*/) {} |
---|
91 | CircularBuffer& operator=(const CircularBuffer& ) { return *this; } |
---|
92 | char *buf; |
---|
93 | size_t m_max; |
---|
94 | size_t m_q; |
---|
95 | size_t m_b; |
---|
96 | size_t m_t; |
---|
97 | unsigned long m_count; |
---|
98 | }; |
---|
99 | /** Output buffer struct. |
---|
100 | \ingroup internal */ |
---|
101 | struct OUTPUT { |
---|
102 | OUTPUT() : _b(0), _t(0), _q(0) {} |
---|
103 | OUTPUT(const char *buf, size_t len) : _b(0), _t(len), _q(len) { |
---|
104 | memcpy(_buf, buf, len); |
---|
105 | } |
---|
106 | size_t Space() { |
---|
107 | return TCP_OUTPUT_CAPACITY - _t; |
---|
108 | } |
---|
109 | void Add(const char *buf, size_t len) { |
---|
110 | memcpy(_buf + _t, buf, len); |
---|
111 | _t += len; |
---|
112 | _q += len; |
---|
113 | } |
---|
114 | size_t Remove(size_t len) { |
---|
115 | _b += len; |
---|
116 | _q -= len; |
---|
117 | return _q; |
---|
118 | } |
---|
119 | const char *Buf() { |
---|
120 | return _buf + _b; |
---|
121 | } |
---|
122 | size_t Len() { |
---|
123 | return _q; |
---|
124 | } |
---|
125 | size_t _b; |
---|
126 | size_t _t; |
---|
127 | size_t _q; |
---|
128 | char _buf[TCP_OUTPUT_CAPACITY]; |
---|
129 | }; |
---|
130 | typedef std::list<OUTPUT *> output_l; |
---|
131 | |
---|
132 | public: |
---|
133 | /** Constructor with standard values on input/output buffers. */ |
---|
134 | TcpSocket(ISocketHandler& ); |
---|
135 | /** Constructor with custom values for i/o buffer. |
---|
136 | \param h ISocketHandler reference |
---|
137 | \param isize Input buffer size |
---|
138 | \param osize Output buffer size */ |
---|
139 | TcpSocket(ISocketHandler& h,size_t isize,size_t osize); |
---|
140 | ~TcpSocket(); |
---|
141 | |
---|
142 | /** Open a connection to a remote server. |
---|
143 | If you want your socket to connect to a server, |
---|
144 | always call Open before Add'ing a socket to the sockethandler. |
---|
145 | If not, the connection attempt will not be monitored by the |
---|
146 | socket handler... |
---|
147 | \param ip IP address |
---|
148 | \param port Port number |
---|
149 | \param skip_socks Do not use socks4 even if configured */ |
---|
150 | bool Open(ipaddr_t ip,port_t port,bool skip_socks = false); |
---|
151 | #ifdef ENABLE_IPV6 |
---|
152 | #ifdef IPPROTO_IPV6 |
---|
153 | /** Open connection. |
---|
154 | \param ip Ipv6 address |
---|
155 | \param port Port number |
---|
156 | \param skip_socks Do not use socks4 even if configured */ |
---|
157 | bool Open(in6_addr ip,port_t port,bool skip_socks = false); |
---|
158 | #endif |
---|
159 | #endif |
---|
160 | bool Open(SocketAddress&,bool skip_socks = false); |
---|
161 | bool Open(SocketAddress&,SocketAddress& bind_address,bool skip_socks = false); |
---|
162 | /** Open connection. |
---|
163 | \param host Hostname |
---|
164 | \param port Port number */ |
---|
165 | bool Open(const std::string &host,port_t port); |
---|
166 | |
---|
167 | /** Connect timeout callback. */ |
---|
168 | void OnConnectTimeout(); |
---|
169 | #ifdef _WIN32 |
---|
170 | /** Connection failed reported as exception on win32 */ |
---|
171 | void OnException(); |
---|
172 | #endif |
---|
173 | |
---|
174 | /** Close file descriptor - internal use only. |
---|
175 | \sa SetCloseAndDelete */ |
---|
176 | int Close(); |
---|
177 | |
---|
178 | /** Send a string. |
---|
179 | \param s String to send |
---|
180 | \param f Dummy flags -- not used */ |
---|
181 | void Send(const std::string &s,int f = 0); |
---|
182 | /** Send string using printf formatting. */ |
---|
183 | void Sendf(const char *format, ...); |
---|
184 | /** Send buffer of bytes. |
---|
185 | \param buf Buffer pointer |
---|
186 | \param len Length of data |
---|
187 | \param f Dummy flags -- not used */ |
---|
188 | void SendBuf(const char *buf,size_t len,int f = 0); |
---|
189 | /** This callback is executed after a successful read from the socket. |
---|
190 | \param buf Pointer to the data |
---|
191 | \param len Length of the data */ |
---|
192 | virtual void OnRawData(const char *buf,size_t len); |
---|
193 | |
---|
194 | /** Called when output buffer has been sent. |
---|
195 | Note: Will only be called IF the output buffer has been used. |
---|
196 | Send's that was successful without needing the output buffer |
---|
197 | will not generate a call to this method. */ |
---|
198 | virtual void OnWriteComplete(); |
---|
199 | /** Number of bytes in input buffer. */ |
---|
200 | size_t GetInputLength(); |
---|
201 | /** Number of bytes in output buffer. */ |
---|
202 | size_t GetOutputLength(); |
---|
203 | |
---|
204 | /** Callback fires when a socket in line protocol has read one full line. |
---|
205 | \param line Line read */ |
---|
206 | void OnLine(const std::string& line); |
---|
207 | /** Get counter of number of bytes received. */ |
---|
208 | uint64_t GetBytesReceived(bool clear = false); |
---|
209 | /** Get counter of number of bytes sent. */ |
---|
210 | uint64_t GetBytesSent(bool clear = false); |
---|
211 | |
---|
212 | /** Socks4 specific callback. */ |
---|
213 | void OnSocks4Connect(); |
---|
214 | /** Socks4 specific callback. */ |
---|
215 | void OnSocks4ConnectFailed(); |
---|
216 | /** Socks4 specific callback. |
---|
217 | \return 'need_more' */ |
---|
218 | bool OnSocks4Read(); |
---|
219 | |
---|
220 | #ifdef ENABLE_RESOLVER |
---|
221 | /** Callback executed when resolver thread has finished a resolve request. */ |
---|
222 | void OnResolved(int id,ipaddr_t a,port_t port); |
---|
223 | #ifdef ENABLE_IPV6 |
---|
224 | void OnResolved(int id,in6_addr& a,port_t port); |
---|
225 | #endif |
---|
226 | #endif |
---|
227 | #ifdef HAVE_OPENSSL |
---|
228 | /** Callback for 'New' ssl support - replaces SSLSocket. Internal use. */ |
---|
229 | void OnSSLConnect(); |
---|
230 | /** Callback for 'New' ssl support - replaces SSLSocket. Internal use. */ |
---|
231 | void OnSSLAccept(); |
---|
232 | /** This method must be implemented to initialize |
---|
233 | the ssl context for an outgoing connection. */ |
---|
234 | virtual void InitSSLClient(); |
---|
235 | /** This method must be implemented to initialize |
---|
236 | the ssl context for an incoming connection. */ |
---|
237 | virtual void InitSSLServer(); |
---|
238 | #endif |
---|
239 | |
---|
240 | #ifdef ENABLE_RECONNECT |
---|
241 | /** Flag that says a broken connection will try to reconnect. */ |
---|
242 | void SetReconnect(bool = true); |
---|
243 | /** Check reconnect on lost connection flag status. */ |
---|
244 | bool Reconnect(); |
---|
245 | /** Flag to determine if a reconnect is in progress. */ |
---|
246 | void SetIsReconnect(bool x = true); |
---|
247 | /** Socket is reconnecting. */ |
---|
248 | bool IsReconnect(); |
---|
249 | #endif |
---|
250 | |
---|
251 | void DisableInputBuffer(bool = true); |
---|
252 | |
---|
253 | void OnOptions(int,int,int,SOCKET); |
---|
254 | |
---|
255 | void SetLineProtocol(bool = true); |
---|
256 | |
---|
257 | // TCP options |
---|
258 | bool SetTcpNodelay(bool = true); |
---|
259 | |
---|
260 | virtual int Protocol(); |
---|
261 | |
---|
262 | /** Trigger limit for callback OnTransferLimit. */ |
---|
263 | void SetTransferLimit(size_t sz); |
---|
264 | /** This callback fires when the output buffer drops below the value |
---|
265 | set by SetTransferLimit. Default: 0 (disabled). */ |
---|
266 | virtual void OnTransferLimit(); |
---|
267 | |
---|
268 | protected: |
---|
269 | TcpSocket(const TcpSocket& ); |
---|
270 | void OnRead(); |
---|
271 | void OnRead( char *buf, size_t n ); |
---|
272 | void OnWrite(); |
---|
273 | #ifdef HAVE_OPENSSL |
---|
274 | /** SSL; Initialize ssl context for a client socket. |
---|
275 | \param meth_in SSL method */ |
---|
276 | void InitializeContext(const std::string& context, SSL_METHOD *meth_in = NULL); |
---|
277 | /** SSL; Initialize ssl context for a server socket. |
---|
278 | \param keyfile Combined private key/certificate file |
---|
279 | \param password Password for private key |
---|
280 | \param meth_in SSL method */ |
---|
281 | void InitializeContext(const std::string& context, const std::string& keyfile, const std::string& password, SSL_METHOD *meth_in = NULL); |
---|
282 | /** SSL; Initialize ssl context for a server socket. |
---|
283 | \param certfile Separate certificate file |
---|
284 | \param keyfile Combined private key/certificate file |
---|
285 | \param password Password for private key |
---|
286 | \param meth_in SSL method */ |
---|
287 | void InitializeContext(const std::string& context, const std::string& certfile, const std::string& keyfile, const std::string& password, SSL_METHOD *meth_in = NULL); |
---|
288 | /** SSL; Password callback method. */ |
---|
289 | static int SSL_password_cb(char *buf,int num,int rwflag,void *userdata); |
---|
290 | /** SSL; Get pointer to ssl context structure. */ |
---|
291 | virtual SSL_CTX *GetSslContext(); |
---|
292 | /** SSL; Get pointer to ssl structure. */ |
---|
293 | virtual SSL *GetSsl(); |
---|
294 | /** ssl; still negotiating connection. */ |
---|
295 | bool SSLNegotiate(); |
---|
296 | /** SSL; Get ssl password. */ |
---|
297 | const std::string& GetPassword(); |
---|
298 | #endif |
---|
299 | |
---|
300 | CircularBuffer ibuf; ///< Circular input buffer |
---|
301 | |
---|
302 | private: |
---|
303 | TcpSocket& operator=(const TcpSocket& ) { return *this; } |
---|
304 | |
---|
305 | /** the actual send() */ |
---|
306 | int TryWrite(const char *buf, size_t len); |
---|
307 | /** add data to output buffer top */ |
---|
308 | void Buffer(const char *buf, size_t len); |
---|
309 | |
---|
310 | // |
---|
311 | bool m_b_input_buffer_disabled; |
---|
312 | uint64_t m_bytes_sent; |
---|
313 | uint64_t m_bytes_received; |
---|
314 | bool m_skip_c; ///< Skip second char of CRLF or LFCR sequence in OnRead |
---|
315 | char m_c; ///< First char in CRLF or LFCR sequence |
---|
316 | std::string m_line; ///< Current line in line protocol mode |
---|
317 | #ifdef SOCKETS_DYNAMIC_TEMP |
---|
318 | char *m_buf; ///< temporary read buffer |
---|
319 | #endif |
---|
320 | output_l m_obuf; ///< output buffer |
---|
321 | OUTPUT *m_obuf_top; ///< output buffer on top |
---|
322 | size_t m_transfer_limit; |
---|
323 | size_t m_output_length; |
---|
324 | |
---|
325 | #ifdef HAVE_OPENSSL |
---|
326 | static SSLInitializer m_ssl_init; |
---|
327 | SSL_CTX *m_ssl_ctx; ///< ssl context |
---|
328 | SSL *m_ssl; ///< ssl 'socket' |
---|
329 | BIO *m_sbio; ///< ssl bio |
---|
330 | std::string m_password; ///< ssl password |
---|
331 | #endif |
---|
332 | |
---|
333 | #ifdef ENABLE_SOCKS4 |
---|
334 | int m_socks4_state; ///< socks4 support |
---|
335 | char m_socks4_vn; ///< socks4 support, temporary variable |
---|
336 | char m_socks4_cd; ///< socks4 support, temporary variable |
---|
337 | unsigned short m_socks4_dstport; ///< socks4 support |
---|
338 | unsigned long m_socks4_dstip; ///< socks4 support |
---|
339 | #endif |
---|
340 | |
---|
341 | #ifdef ENABLE_RESOLVER |
---|
342 | int m_resolver_id; ///< Resolver id (if any) for current Open call |
---|
343 | #endif |
---|
344 | |
---|
345 | #ifdef ENABLE_RECONNECT |
---|
346 | bool m_b_reconnect; ///< Reconnect on lost connection flag |
---|
347 | bool m_b_is_reconnect; ///< Trying to reconnect |
---|
348 | #endif |
---|
349 | |
---|
350 | }; |
---|
351 | |
---|
352 | |
---|
353 | #ifdef SOCKETS_NAMESPACE |
---|
354 | } |
---|
355 | #endif |
---|
356 | |
---|
357 | #endif // _SOCKETS_TcpSocket_H |
---|
358 | |
---|