]>
Commit | Line | Data |
---|---|---|
ed120ee5 | 1 | /** @file |
8a769a6f | 2 | * |
9a2e17c6 | 3 | * Copyright (c) 1999-2009 Jim Hull <imaginos@imaginos.net> |
8a769a6f | 4 | * All rights reserved |
79aaf3d5 | 5 | * |
6 | * Redistribution and use in source and binary forms, with or without modification, | |
8a769a6f | 7 | * are permitted provided that the following conditions are met: |
79aaf3d5 | 8 | * Redistributions of source code must retain the above copyright notice, this |
8a769a6f | 9 | * list of conditions and the following disclaimer. |
79aaf3d5 | 10 | * Redistributions in binary form must reproduce the above copyright notice, this list |
8a769a6f | 11 | * of conditions and the following disclaimer in the documentation and/or other materials |
12 | * provided with the distribution. | |
79aaf3d5 | 13 | * Redistributions in any form must be accompanied by information on how to obtain |
ed120ee5 | 14 | * complete source code for this software and any accompanying software that uses this software. |
79aaf3d5 | 15 | * The source code must either be included in the distribution or be available for no more than |
16 | * the cost of distribution plus a nominal fee, and must be freely redistributable | |
17 | * under reasonable conditions. For an executable file, complete source code means the source | |
18 | * code for all modules it contains. It does not include source code for modules or files | |
8a769a6f | 19 | * that typically accompany the major components of the operating system on which the executable file runs. |
20 | * | |
79aaf3d5 | 21 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, |
22 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, | |
ed120ee5 | 23 | * OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OF THIS SOFTWARE BE LIABLE FOR ANY DIRECT, |
79aaf3d5 | 24 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
25 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | |
27 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |
8a769a6f | 28 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | * | |
30 | * | |
8a769a6f | 31 | */ |
32 | ||
8a769a6f | 33 | #include "Csocket.h" |
b63b7d03 | 34 | #ifdef __NetBSD__ |
35 | #include <sys/param.h> | |
36 | #endif /* __NetBSD__ */ | |
37 | ||
e77adef0 | 38 | #ifdef HAVE_LIBSSL |
88e7f093 | 39 | #include <stdio.h> |
e77adef0 | 40 | #include <openssl/conf.h> |
41 | #include <openssl/engine.h> | |
42 | #endif /* HAVE_LIBSSL */ | |
43 | ||
493d5154 | 44 | #include <list> |
45 | ||
b63b7d03 | 46 | #define CS_SRANDBUFFER 128 |
8a769a6f | 47 | |
2d1602ec | 48 | using namespace std; |
49 | ||
f1515361 | 50 | #define CREATE_ARES_VER( a, b, c ) ((a<<16)|(b<<8)|c) |
25ef3439 | 51 | |
2d1602ec | 52 | #ifndef _NO_CSOCKET_NS // some people may not want to use a namespace |
53 | namespace Csocket | |
54 | { | |
55 | #endif /* _NO_CSOCKET_NS */ | |
56 | ||
b63b7d03 | 57 | static int g_iCsockSSLIdx = 0; //!< this get setup once in InitSSL |
58 | int GetCsockClassIdx() | |
59 | { | |
60 | return( g_iCsockSSLIdx ); | |
61 | } | |
62 | ||
c6664d5a | 63 | #ifdef _WIN32 |
583b91f7 | 64 | static const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) |
65 | { | |
66 | if( af == AF_INET ) | |
67 | { | |
68 | struct sockaddr_in in; | |
69 | memset(&in, 0, sizeof(in)); | |
70 | in.sin_family = AF_INET; | |
71 | memcpy( &in.sin_addr, src, sizeof(struct in_addr) ); | |
72 | getnameinfo( (struct sockaddr *)&in, sizeof(struct sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST ); | |
73 | return dst; | |
74 | } | |
75 | else if( af == AF_INET6 ) | |
76 | { | |
77 | struct sockaddr_in6 in; | |
78 | memset( &in, 0, sizeof(in) ); | |
79 | in.sin6_family = AF_INET6; | |
80 | memcpy( &in.sin6_addr, src, sizeof(struct in_addr6) ); | |
81 | getnameinfo( (struct sockaddr *)&in, sizeof(struct sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST ); | |
82 | return dst; | |
83 | } | |
84 | return( NULL ); | |
85 | } | |
86 | ||
5ea1f8cc | 87 | #if defined(_WIN32) && (!defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0600)) |
88 | //! thanks to KiNgMaR @ #znc for this wrapper | |
89 | static int inet_pton( int af, const char *src, void *dst ) | |
90 | { | |
91 | sockaddr_storage aAddress; | |
92 | int iAddrLen = sizeof( sockaddr_storage ); | |
93 | memset( &aAddress, 0, iAddrLen ); | |
94 | char *pTmp = strdup( src ); | |
95 | aAddress.ss_family = af; // this is important: | |
96 | // The function fails if the sin_family member of the SOCKADDR_IN structure is not set to AF_INET or AF_INET6. | |
97 | int iRet = WSAStringToAddressA( pTmp, af, NULL, (sockaddr *)&aAddress, &iAddrLen ); | |
98 | free( pTmp ); | |
99 | if( iRet == 0 ) | |
100 | { | |
101 | if( af == AF_INET6 ) | |
102 | memcpy(dst, &((sockaddr_in6 *)&aAddress)->sin6_addr, sizeof(in6_addr)); | |
103 | else | |
104 | memcpy(dst, &((sockaddr_in *)&aAddress)->sin_addr, sizeof(in_addr)); | |
105 | return( 1 ); | |
106 | } | |
107 | return( -1 ); | |
108 | } | |
109 | #endif | |
110 | ||
25ef3439 | 111 | static inline void set_non_blocking(cs_sock_t fd) |
c6664d5a | 112 | { |
113 | u_long iOpts = 1; | |
114 | ioctlsocket( fd, FIONBIO, &iOpts ); | |
115 | } | |
116 | ||
25ef3439 | 117 | static inline void set_blocking(cs_sock_t fd) |
c6664d5a | 118 | { |
119 | u_long iOpts = 0; | |
120 | ioctlsocket( fd, FIONBIO, &iOpts ); | |
121 | } | |
122 | ||
25ef3439 | 123 | static inline void set_close_on_exec(cs_sock_t fd) |
c6664d5a | 124 | { |
125 | // TODO add this for windows | |
126 | // see http://gcc.gnu.org/ml/java-patches/2002-q1/msg00696.html | |
127 | // for infos on how to do this | |
128 | } | |
129 | #else | |
25ef3439 | 130 | static inline void set_non_blocking(cs_sock_t fd) |
c6664d5a | 131 | { |
132 | int fdflags = fcntl(fd, F_GETFL, 0); | |
133 | if ( fdflags < 0 ) | |
134 | return; // Ignore errors | |
135 | fcntl( fd, F_SETFL, fdflags|O_NONBLOCK ); | |
136 | } | |
137 | ||
25ef3439 | 138 | static inline void set_blocking(cs_sock_t fd) |
c6664d5a | 139 | { |
140 | int fdflags = fcntl(fd, F_GETFL, 0); | |
141 | if ( fdflags < 0 ) | |
142 | return; // Ignore errors | |
143 | fdflags &= ~O_NONBLOCK; | |
144 | fcntl( fd, F_SETFL, fdflags ); | |
145 | } | |
146 | ||
25ef3439 | 147 | static inline void set_close_on_exec(cs_sock_t fd) |
c6664d5a | 148 | { |
149 | int fdflags = fcntl(fd, F_GETFD, 0); | |
150 | if ( fdflags < 0 ) | |
151 | return; // Ignore errors | |
152 | fcntl( fd, F_SETFD, fdflags|FD_CLOEXEC); | |
153 | } | |
154 | #endif /* _WIN32 */ | |
155 | ||
babc0f9f | 156 | #ifdef HAVE_LIBSSL |
b63b7d03 | 157 | Csock *GetCsockFromCTX( X509_STORE_CTX *pCTX ) |
158 | { | |
159 | Csock *pSock = NULL; | |
160 | SSL *pSSL = (SSL *)X509_STORE_CTX_get_ex_data( pCTX, SSL_get_ex_data_X509_STORE_CTX_idx() ); | |
161 | if( pSSL ) | |
162 | pSock = (Csock *)SSL_get_ex_data( pSSL, GetCsockClassIdx() ); | |
163 | return( pSock ); | |
164 | } | |
babc0f9f | 165 | #endif /* HAVE_LIBSSL */ |
166 | ||
b63b7d03 | 167 | |
168 | #ifndef HAVE_IPV6 | |
169 | ||
170 | // this issue here is getaddrinfo has a significant behavior difference when dealing with round robin dns on an | |
171 | // ipv4 network. This is not desirable IMHO. so when this is compiled without ipv6 support backwards compatibility | |
172 | // is maintained. | |
173 | ||
174 | static int __GetHostByName( const CS_STRING & sHostName, struct in_addr *paddr, u_int iNumRetries ) | |
175 | { | |
176 | int iReturn = HOST_NOT_FOUND; | |
177 | struct hostent *hent = NULL; | |
178 | #ifdef __linux__ | |
179 | char hbuff[2048]; | |
180 | struct hostent hentbuff; | |
181 | ||
182 | int err; | |
183 | for( u_int a = 0; a < iNumRetries; a++ ) | |
184 | { | |
185 | memset( (char *)hbuff, '\0', 2048 ); | |
186 | iReturn = gethostbyname_r( sHostName.c_str(), &hentbuff, hbuff, 2048, &hent, &err ); | |
187 | ||
188 | if ( iReturn == 0 ) | |
189 | break; | |
190 | ||
191 | if ( iReturn != TRY_AGAIN ) | |
294c82a9 | 192 | { |
193 | CS_DEBUG( "gethostyname_r: " << hstrerror( h_errno ) ); | |
b63b7d03 | 194 | break; |
294c82a9 | 195 | } |
b63b7d03 | 196 | |
b63b7d03 | 197 | } |
198 | if ( ( !hent ) && ( iReturn == 0 ) ) | |
199 | iReturn = HOST_NOT_FOUND; | |
200 | #else | |
294c82a9 | 201 | for( u_int a = 0; a < iNumRetries; a++ ) |
202 | { | |
203 | iReturn = HOST_NOT_FOUND; | |
204 | hent = gethostbyname( sHostName.c_str() ); | |
b63b7d03 | 205 | |
294c82a9 | 206 | if ( hent ) |
207 | { | |
208 | iReturn = 0; | |
209 | break; | |
210 | } | |
211 | ||
212 | if( h_errno != TRY_AGAIN ) | |
213 | { | |
583b91f7 | 214 | #ifndef _WIN32 |
294c82a9 | 215 | CS_DEBUG( "gethostyname: " << hstrerror( h_errno ) ); |
583b91f7 | 216 | #endif /* _WIN32 */ |
294c82a9 | 217 | break; |
218 | } | |
219 | } | |
b63b7d03 | 220 | |
221 | #endif /* __linux__ */ | |
222 | ||
223 | if ( iReturn == 0 ) | |
224 | memcpy( &paddr->s_addr, hent->h_addr_list[0], sizeof( paddr->s_addr ) ); | |
225 | ||
6faf0980 | 226 | return( iReturn == TRY_AGAIN ? EAGAIN : iReturn ); |
b63b7d03 | 227 | } |
228 | #endif /* !HAVE_IPV6 */ | |
229 | ||
6ce29e77 | 230 | #ifdef HAVE_C_ARES |
231 | void Csock::FreeAres() | |
232 | { | |
233 | if( m_pARESChannel ) | |
234 | { | |
235 | ares_destroy( m_pARESChannel ); | |
236 | m_pARESChannel = NULL; | |
237 | } | |
238 | } | |
239 | #endif /* HAVE_C_ARES */ | |
240 | ||
241 | #ifdef HAVE_C_ARES | |
1b51f15d | 242 | static void AresHostCallback( void *pArg, int status, int timeouts, struct hostent *hent ) |
6ce29e77 | 243 | { |
244 | Csock *pSock = (Csock *)pArg; | |
88e7f093 | 245 | if( status == ARES_SUCCESS && hent && hent->h_addr_list[0] != NULL ) |
6ce29e77 | 246 | { |
247 | CSSockAddr *pSockAddr = pSock->GetCurrentAddr(); | |
248 | if( hent->h_addrtype == AF_INET ) | |
249 | { | |
250 | pSock->SetIPv6( false ); | |
251 | memcpy( pSockAddr->GetAddr(), hent->h_addr_list[0], sizeof( *(pSockAddr->GetAddr()) ) ); | |
252 | } | |
253 | #ifdef HAVE_IPV6 | |
254 | else if( hent->h_addrtype == AF_INET6 ) | |
255 | { | |
256 | pSock->SetIPv6( true ); | |
257 | memcpy( pSockAddr->GetAddr6(), hent->h_addr_list[0], sizeof( *(pSockAddr->GetAddr6()) ) ); | |
258 | } | |
259 | #endif /* HAVE_IPV6 */ | |
260 | else | |
261 | { | |
262 | status = ARES_ENOTFOUND; | |
263 | } | |
264 | } | |
265 | else | |
266 | { | |
267 | CS_DEBUG( ares_strerror( status ) ); | |
88e7f093 US |
268 | if( status == ARES_SUCCESS ) |
269 | { | |
270 | CS_DEBUG("Received ARES_SUCCESS without any useful reply, using NODATA instead"); | |
271 | status = ARES_ENODATA; | |
272 | } | |
6ce29e77 | 273 | } |
274 | pSock->SetAresFinished( status ); | |
275 | } | |
276 | #endif /* HAVE_C_ARES */ | |
277 | ||
9d4be439 | 278 | int GetAddrInfo( const CS_STRING & sHostname, Csock *pSock, CSSockAddr & csSockAddr ) |
279 | { | |
b63b7d03 | 280 | #ifndef HAVE_IPV6 |
493d5154 | 281 | // if ipv6 is not enabled, then simply use gethostbyname, nothing special outside of this is done |
b63b7d03 | 282 | if( pSock ) |
283 | pSock->SetIPv6( false ); | |
284 | csSockAddr.SetIPv6( false ); | |
285 | if( __GetHostByName( sHostname, csSockAddr.GetAddr(), 3 ) == 0 ) | |
286 | return( 0 ); | |
be3edeee | 287 | |
b63b7d03 | 288 | #else /* HAVE_IPV6 */ |
9d4be439 | 289 | struct addrinfo *res = NULL; |
290 | struct addrinfo hints; | |
291 | memset( (struct addrinfo *)&hints, '\0', sizeof( hints ) ); | |
acb90125 | 292 | hints.ai_family = csSockAddr.GetAFRequire(); |
293 | ||
9d4be439 | 294 | hints.ai_socktype = SOCK_STREAM; |
295 | hints.ai_protocol = IPPROTO_TCP; | |
a89fa461 | 296 | #ifdef AI_ADDRCONFIG |
493d5154 | 297 | // this is suppose to eliminate host from appearing that this system can not support |
298 | hints.ai_flags = AI_ADDRCONFIG; | |
a89fa461 | 299 | #endif /* AI_ADDRCONFIG */ |
300 | ||
4059f8c3 | 301 | if( pSock && ( pSock->GetType() == Csock::LISTENER || pSock->GetConState() == Csock::CST_BINDVHOST ) ) |
493d5154 | 302 | { // when doing a dns for bind only, set the AI_PASSIVE flag as suggested by the man page |
303 | hints.ai_flags |= AI_PASSIVE; | |
304 | } | |
a89fa461 | 305 | |
9d4be439 | 306 | int iRet = getaddrinfo( sHostname.c_str(), NULL, &hints, &res ); |
307 | if( iRet == EAI_AGAIN ) | |
493d5154 | 308 | return( EAGAIN ); // need to return telling the user to try again |
9d4be439 | 309 | else if( ( iRet == 0 ) && ( res ) ) |
88e7f093 | 310 | { |
493d5154 | 311 | std::list<struct addrinfo *> lpTryAddrs; |
312 | bool bFound = false; | |
9d4be439 | 313 | for( struct addrinfo *pRes = res; pRes; pRes = pRes->ai_next ) |
493d5154 | 314 | { // pass through the list building out a lean list of candidates to try. AI_CONFIGADDR doesn't always seem to work |
577d7528 | 315 | #ifdef __sun |
316 | if( ( pRes->ai_socktype != SOCK_STREAM ) || ( pRes->ai_protocol != IPPROTO_TCP && pRes->ai_protocol != IPPROTO_IP ) ) | |
317 | #else | |
9d4be439 | 318 | if( ( pRes->ai_socktype != SOCK_STREAM ) || ( pRes->ai_protocol != IPPROTO_TCP ) ) |
577d7528 | 319 | #endif /* __sun work around broken impl of getaddrinfo */ |
5e8c075c | 320 | continue; |
88e7f093 | 321 | |
acb90125 | 322 | if( ( csSockAddr.GetAFRequire() != CSSockAddr::RAF_ANY ) && ( pRes->ai_family != csSockAddr.GetAFRequire() ) ) |
323 | continue; // they requested a special type, so be certain we woop past anything unwanted | |
493d5154 | 324 | lpTryAddrs.push_back( pRes ); |
325 | } | |
326 | for( std::list<struct addrinfo *>::iterator it = lpTryAddrs.begin(); it != lpTryAddrs.end(); ) | |
327 | { // cycle through these, leaving the last iterator for the outside caller to call, so if there is an error it can call the events | |
328 | struct addrinfo * pRes = *it; | |
329 | bool bTryConnect = false; | |
9d4be439 | 330 | if( pRes->ai_family == AF_INET ) |
331 | { | |
493d5154 | 332 | if( pSock ) |
333 | pSock->SetIPv6( false ); | |
334 | csSockAddr.SetIPv6( false ); | |
335 | struct sockaddr_in *pTmp = (struct sockaddr_in *)pRes->ai_addr; | |
336 | memcpy( csSockAddr.GetAddr(), &(pTmp->sin_addr), sizeof( *(csSockAddr.GetAddr()) ) ); | |
337 | if( pSock && pSock->GetConState() == Csock::CST_DESTDNS && pSock->GetType() == Csock::OUTBOUND ) | |
338 | { | |
339 | bTryConnect = true; | |
340 | } | |
341 | else | |
342 | { | |
343 | bFound = true; | |
344 | break; | |
345 | } | |
9d4be439 | 346 | } |
9d4be439 | 347 | else if( pRes->ai_family == AF_INET6 ) |
348 | { | |
493d5154 | 349 | if( pSock ) |
350 | pSock->SetIPv6( true ); | |
351 | csSockAddr.SetIPv6( true ); | |
352 | struct sockaddr_in6 *pTmp = (struct sockaddr_in6 *)pRes->ai_addr; | |
353 | memcpy( csSockAddr.GetAddr6(), &(pTmp->sin6_addr), sizeof( *(csSockAddr.GetAddr6()) ) ); | |
354 | if( pSock && pSock->GetConState() == Csock::CST_DESTDNS && pSock->GetType() == Csock::OUTBOUND ) | |
355 | { | |
356 | bTryConnect = true; | |
357 | } | |
358 | else | |
359 | { | |
360 | bFound = true; | |
361 | break; | |
362 | } | |
b63b7d03 | 363 | } |
493d5154 | 364 | |
365 | it++; // increment the iterator her so we know if its the last element or not | |
366 | ||
367 | if( bTryConnect && it != lpTryAddrs.end() ) | |
368 | { // save the last attempt for the outer loop, the issue then becomes that the error is thrown on the last failure | |
369 | if( pSock->CreateSocksFD() && pSock->Connect( pSock->GetBindHost(), true ) ) | |
370 | { | |
371 | pSock->SetSkipConnect( true ); // this tells the socket that the connection state has been started | |
372 | bFound = true; | |
373 | break; | |
374 | } | |
ebbc126b | 375 | pSock->CloseSocksFD(); |
9d4be439 | 376 | } |
493d5154 | 377 | else if( bTryConnect ) |
b63b7d03 | 378 | { |
493d5154 | 379 | bFound = true; |
b63b7d03 | 380 | } |
381 | } | |
b63b7d03 | 382 | |
9d4be439 | 383 | freeaddrinfo( res ); |
493d5154 | 384 | if( bFound ) // the data pointed to here is invalid now, but the pointer itself is a good test |
1fb00397 | 385 | { |
9d4be439 | 386 | return( 0 ); |
1fb00397 | 387 | } |
61920317 | 388 | } |
b63b7d03 | 389 | #endif /* ! HAVE_IPV6 */ |
9d4be439 | 390 | return( ETIMEDOUT ); |
487b6b65 | 391 | } |
9d4be439 | 392 | |
c03bd915 | 393 | bool InitCsocket() |
394 | { | |
395 | #ifdef _WIN32 | |
396 | WSADATA wsaData; | |
397 | int iResult = WSAStartup( MAKEWORD( 2, 2 ), &wsaData ); | |
398 | if( iResult != NO_ERROR ) | |
399 | return( false ); | |
400 | #endif /* _WIN32 */ | |
f1515361 | 401 | #ifdef HAVE_C_ARES |
402 | #if ARES_VERSION >= CREATE_ARES_VER( 1, 6, 1 ) | |
403 | if( ares_library_init( ARES_LIB_INIT_ALL ) != 0 ) | |
404 | return( false ); | |
405 | #endif /* ARES_VERSION >= CREATE_ARES_VER( 1, 6, 1 ) */ | |
406 | #endif /* HAVE_C_ARES */ | |
c03bd915 | 407 | #ifdef HAVE_LIBSSL |
408 | if( !InitSSL() ) | |
409 | return( false ); | |
410 | #endif /* HAVE_LIBSSL */ | |
411 | return( true ); | |
412 | } | |
413 | ||
414 | void ShutdownCsocket() | |
415 | { | |
416 | #ifdef HAVE_LIBSSL | |
e77adef0 | 417 | ERR_remove_state(0); |
418 | ENGINE_cleanup(); | |
419 | CONF_modules_unload(1); | |
c03bd915 | 420 | ERR_free_strings(); |
e77adef0 | 421 | EVP_cleanup(); |
422 | CRYPTO_cleanup_all_ex_data(); | |
c03bd915 | 423 | #endif /* HAVE_LIBSSL */ |
f1515361 | 424 | #ifdef HAVE_C_ARES |
425 | #if ARES_VERSION >= CREATE_ARES_VER( 1, 6, 1 ) | |
426 | ares_library_cleanup(); | |
427 | #endif /* ARES_VERSION >= CREATE_ARES_VER( 1, 6, 1 ) */ | |
428 | #endif /* HAVE_C_ARES */ | |
c03bd915 | 429 | #ifdef _WIN32 |
430 | WSACleanup(); | |
431 | #endif /* _WIN32 */ | |
432 | } | |
433 | ||
8a769a6f | 434 | #ifdef HAVE_LIBSSL |
435 | bool InitSSL( ECompType eCompressionType ) | |
436 | { | |
437 | SSL_load_error_strings(); | |
438 | if ( SSL_library_init() != 1 ) | |
439 | { | |
440 | CS_DEBUG( "SSL_library_init() failed!" ); | |
441 | return( false ); | |
442 | } | |
443 | ||
2d1602ec | 444 | #ifndef _WIN32 |
8a769a6f | 445 | if ( access( "/dev/urandom", R_OK ) == 0 ) |
446 | RAND_load_file( "/dev/urandom", 1024 ); | |
447 | else if( access( "/dev/random", R_OK ) == 0 ) | |
448 | RAND_load_file( "/dev/random", 1024 ); | |
449 | else | |
450 | { | |
451 | CS_DEBUG( "Unable to locate entropy location! Tried /dev/urandom and /dev/random" ); | |
452 | return( false ); | |
453 | } | |
2d1602ec | 454 | #endif /* _WIN32 */ |
8a769a6f | 455 | |
456 | COMP_METHOD *cm = NULL; | |
457 | ||
458 | if ( CT_ZLIB & eCompressionType ) | |
459 | { | |
460 | cm = COMP_zlib(); | |
461 | if ( cm ) | |
462 | SSL_COMP_add_compression_method( CT_ZLIB, cm ); | |
463 | } | |
464 | ||
dba60545 | 465 | #if 0 |
8a769a6f | 466 | if ( CT_RLE & eCompressionType ) |
467 | { | |
468 | cm = COMP_rle(); | |
469 | if ( cm ) | |
470 | SSL_COMP_add_compression_method( CT_RLE, cm ); | |
471 | } | |
dba60545 | 472 | #endif |
8a769a6f | 473 | |
b63b7d03 | 474 | // setting this up once in the begining |
475 | g_iCsockSSLIdx = SSL_get_ex_new_index( 0, (void *)"CsockGlobalIndex", NULL, NULL, NULL); | |
476 | ||
8a769a6f | 477 | return( true ); |
478 | } | |
479 | ||
480 | void SSLErrors( const char *filename, u_int iLineNum ) | |
481 | { | |
482 | unsigned long iSSLError = 0; | |
483 | while( ( iSSLError = ERR_get_error() ) != 0 ) | |
484 | { | |
485 | CS_DEBUG( "at " << filename << ":" << iLineNum ); | |
486 | char szError[512]; | |
487 | memset( (char *) szError, '\0', 512 ); | |
488 | ERR_error_string_n( iSSLError, szError, 511 ); | |
e48a6be4 | 489 | if ( *szError ) |
8a769a6f | 490 | CS_DEBUG( szError ); |
491 | } | |
492 | } | |
493 | #endif /* HAVE_LIBSSL */ | |
494 | ||
4c5d81b2 | 495 | void __Perror( const CS_STRING & s, const char *pszFile, unsigned int iLineNo ) |
8a769a6f | 496 | { |
88e7f093 | 497 | #if defined( sgi ) || defined(__sun) || defined(_WIN32) || (defined(__NetBSD_Version__) && __NetBSD_Version__ < 4000000000) |
4c5d81b2 | 498 | std::cerr << s << "(" << pszFile << ":" << iLineNo << "): " << strerror( GetSockError() ) << endl; |
8a769a6f | 499 | #else |
500 | char buff[512]; | |
501 | memset( (char *)buff, '\0', 512 ); | |
2d1602ec | 502 | if ( strerror_r( GetSockError(), buff, 511 ) == 0 ) |
4c5d81b2 | 503 | std::cerr << s << "(" << pszFile << ":" << iLineNo << "): " << buff << endl; |
8a769a6f | 504 | else |
4c5d81b2 | 505 | std::cerr << s << "(" << pszFile << ":" << iLineNo << "): Unknown Error Occured " << endl; |
8a769a6f | 506 | #endif /* __sun */ |
507 | } | |
508 | ||
509 | unsigned long long millitime() | |
510 | { | |
8a769a6f | 511 | unsigned long long iTime = 0; |
2d1602ec | 512 | #ifdef _WIN32 |
513 | struct timeb tm; | |
514 | ftime( &tm ); | |
515 | iTime = tm.time * 1000; | |
516 | iTime += tm.millitm; | |
517 | #else | |
518 | struct timeval tv; | |
8a769a6f | 519 | gettimeofday( &tv, NULL ); |
520 | iTime = (unsigned long long )tv.tv_sec * 1000; | |
79aaf3d5 | 521 | iTime += ( (unsigned long long)tv.tv_usec / 1000 ); |
2d1602ec | 522 | #endif /* _WIN32 */ |
8a769a6f | 523 | return( iTime ); |
524 | } | |
525 | ||
2d1602ec | 526 | #ifndef _NO_CSOCKET_NS // some people may not want to use a namespace |
527 | } | |
528 | using namespace Csocket; | |
529 | #endif /* _NO_CSOCKET_NS */ | |
530 | ||
79aaf3d5 | 531 | CCron::CCron() |
8a769a6f | 532 | { |
533 | m_iCycles = 0; | |
534 | m_iMaxCycles = 0; | |
535 | m_bActive = true; | |
536 | m_iTime = 0; | |
537 | m_iTimeSequence = 60; | |
538 | m_bPause = false; | |
c3b6a4b2 | 539 | m_bRunOnNextCall = false; |
8a769a6f | 540 | } |
541 | ||
2bbdb72a | 542 | void CCron::run( time_t & iNow ) |
8a769a6f | 543 | { |
544 | if ( m_bPause ) | |
545 | return; | |
546 | ||
2bbdb72a | 547 | if( iNow == 0 ) |
548 | iNow = time( NULL ); | |
549 | ||
c3b6a4b2 | 550 | if ( ( m_bActive ) && ( iNow >= m_iTime || m_bRunOnNextCall ) ) |
8a769a6f | 551 | { |
c3b6a4b2 | 552 | m_bRunOnNextCall = false; // Setting this here because RunJob() could set it back to true |
8a769a6f | 553 | RunJob(); |
554 | ||
555 | if ( ( m_iMaxCycles > 0 ) && ( ++m_iCycles >= m_iMaxCycles ) ) | |
556 | m_bActive = false; | |
557 | else | |
30cf3a30 | 558 | m_iTime = iNow + m_iTimeSequence; |
8a769a6f | 559 | } |
560 | } | |
561 | ||
8a769a6f | 562 | void CCron::StartMaxCycles( int TimeSequence, u_int iMaxCycles ) |
563 | { | |
564 | m_iTimeSequence = TimeSequence; | |
565 | m_iTime = time( NULL ) + m_iTimeSequence; | |
566 | m_iMaxCycles = iMaxCycles; | |
567 | } | |
568 | ||
8a769a6f | 569 | void CCron::Start( int TimeSequence ) |
570 | { | |
571 | m_iTimeSequence = TimeSequence; | |
572 | m_iTime = time( NULL ) + m_iTimeSequence; | |
573 | m_iMaxCycles = 0; | |
574 | } | |
575 | ||
8a769a6f | 576 | void CCron::Stop() |
577 | { | |
578 | m_bActive = false; | |
579 | } | |
580 | ||
8a769a6f | 581 | void CCron::Pause() |
582 | { | |
583 | m_bPause = true; | |
584 | } | |
585 | ||
8a769a6f | 586 | void CCron::UnPause() |
587 | { | |
588 | m_bPause = false; | |
589 | } | |
590 | ||
591 | int CCron::GetInterval() const { return( m_iTimeSequence ); } | |
592 | u_int CCron::GetMaxCycles() const { return( m_iMaxCycles ); } | |
593 | u_int CCron::GetCyclesLeft() const { return( ( m_iMaxCycles > m_iCycles ? ( m_iMaxCycles - m_iCycles ) : 0 ) ); } | |
594 | ||
8a769a6f | 595 | bool CCron::isValid() { return( m_bActive ); } |
596 | const CS_STRING & CCron::GetName() const { return( m_sName ); } | |
597 | void CCron::SetName( const CS_STRING & sName ) { m_sName = sName; } | |
d8f4e319 | 598 | void CCron::RunJob() { CS_DEBUG( "This should be overridden" ); } |
8a769a6f | 599 | |
79aaf3d5 | 600 | Csock::Csock( int itimeout ) |
601 | { | |
ed120ee5 | 602 | #ifdef HAVE_LIBSSL |
603 | m_pCerVerifyCB = NULL; | |
604 | #endif /* HAVE_LIBSSL */ | |
79aaf3d5 | 605 | Init( "", 0, itimeout ); |
8a769a6f | 606 | } |
607 | ||
6dbb196e | 608 | Csock::Csock( const CS_STRING & sHostname, u_short iport, int itimeout ) |
8a769a6f | 609 | { |
ed120ee5 | 610 | #ifdef HAVE_LIBSSL |
611 | m_pCerVerifyCB = NULL; | |
612 | #endif /* HAVE_LIBSSL */ | |
8a769a6f | 613 | Init( sHostname, iport, itimeout ); |
614 | } | |
615 | ||
616 | // override this for accept sockets | |
6dbb196e | 617 | Csock *Csock::GetSockObj( const CS_STRING & sHostname, u_short iPort ) |
79aaf3d5 | 618 | { |
619 | return( NULL ); | |
8a769a6f | 620 | } |
621 | ||
2d1602ec | 622 | #ifdef _WIN32 |
623 | #define CS_CLOSE closesocket | |
624 | #else | |
625 | #define CS_CLOSE close | |
626 | #endif /* _WIN32 */ | |
627 | ||
8a769a6f | 628 | Csock::~Csock() |
629 | { | |
6ce29e77 | 630 | #ifdef HAVE_C_ARES |
631 | if( m_pARESChannel ) | |
632 | ares_cancel( m_pARESChannel ); | |
633 | FreeAres(); | |
634 | #endif /* HAVE_C_ARES */ | |
635 | ||
ba619d0b | 636 | #ifdef HAVE_LIBSSL |
637 | FREE_SSL(); | |
638 | FREE_CTX(); | |
639 | #endif /* HAVE_LIBSSL */ | |
640 | ||
ebbc126b | 641 | CloseSocksFD(); |
642 | ||
643 | // delete any left over crons | |
644 | for( vector<CCron *>::size_type i = 0; i < m_vcCrons.size(); i++ ) | |
645 | CS_Delete( m_vcCrons[i] ); | |
646 | } | |
647 | ||
648 | void Csock::CloseSocksFD() | |
649 | { | |
8a769a6f | 650 | if ( m_iReadSock != m_iWriteSock ) |
651 | { | |
c7546c0c | 652 | if( m_iReadSock != CS_INVALID_SOCK ) |
9736711c | 653 | CS_CLOSE( m_iReadSock ); |
c7546c0c | 654 | if( m_iWriteSock != CS_INVALID_SOCK ) |
9736711c | 655 | CS_CLOSE( m_iWriteSock ); |
b18e42df | 656 | } else if( m_iReadSock != CS_INVALID_SOCK ) |
2d1602ec | 657 | CS_CLOSE( m_iReadSock ); |
8a769a6f | 658 | |
25ef3439 | 659 | m_iReadSock = CS_INVALID_SOCK; |
660 | m_iWriteSock = CS_INVALID_SOCK; | |
8a769a6f | 661 | } |
662 | ||
ebbc126b | 663 | |
9736711c | 664 | void Csock::Dereference() |
665 | { | |
25ef3439 | 666 | m_iWriteSock = m_iReadSock = CS_INVALID_SOCK; |
9736711c | 667 | |
668 | #ifdef HAVE_LIBSSL | |
669 | m_ssl = NULL; | |
670 | m_ssl_ctx = NULL; | |
671 | #endif /* HAVE_LIBSSL */ | |
672 | ||
673 | m_vcCrons.clear(); | |
9210bdc9 | 674 | Close( CLT_DEREFERENCE ); |
9736711c | 675 | } |
676 | ||
677 | void Csock::Copy( const Csock & cCopy ) | |
678 | { | |
b63b7d03 | 679 | m_iTcount = cCopy.m_iTcount; |
680 | m_iLastCheckTimeoutTime = cCopy.m_iLastCheckTimeoutTime; | |
25ef3439 | 681 | m_uPort = cCopy.m_uPort; |
be3edeee | 682 | m_iRemotePort = cCopy.m_iRemotePort; |
9736711c | 683 | m_iLocalPort = cCopy.m_iLocalPort; |
684 | m_iReadSock = cCopy.m_iReadSock; | |
685 | m_iWriteSock = cCopy.m_iWriteSock; | |
2137d5a7 | 686 | m_itimeout = cCopy.m_itimeout; |
be3edeee | 687 | m_iConnType = cCopy.m_iConnType; |
9736711c | 688 | m_iMethod = cCopy.m_iMethod; |
689 | m_bssl = cCopy.m_bssl; | |
690 | m_bIsConnected = cCopy.m_bIsConnected; | |
691 | m_bBLOCK = cCopy.m_bBLOCK; | |
9736711c | 692 | m_bsslEstablished = cCopy.m_bsslEstablished; |
be3edeee | 693 | m_bEnableReadLine = cCopy.m_bEnableReadLine; |
be3edeee | 694 | m_bPauseRead = cCopy.m_bPauseRead; |
9736711c | 695 | m_shostname = cCopy.m_shostname; |
be3edeee | 696 | m_sbuffer = cCopy.m_sbuffer; |
697 | m_sSockName = cCopy.m_sSockName; | |
698 | m_sPemFile = cCopy.m_sPemFile; | |
699 | m_sCipherType = cCopy.m_sCipherType; | |
700 | m_sParentName = cCopy.m_sParentName; | |
9736711c | 701 | m_sSend = cCopy.m_sSend; |
be3edeee | 702 | m_sPemPass = cCopy.m_sPemPass; |
703 | m_sLocalIP = cCopy.m_sLocalIP; | |
704 | m_sRemoteIP = cCopy.m_sRemoteIP; | |
9736711c | 705 | m_eCloseType = cCopy.m_eCloseType; |
706 | ||
707 | m_iMaxMilliSeconds = cCopy.m_iMaxMilliSeconds; | |
be3edeee | 708 | m_iLastSendTime = cCopy.m_iLastSendTime; |
709 | m_iBytesRead = cCopy.m_iBytesRead; | |
710 | m_iBytesWritten = cCopy.m_iBytesWritten; | |
711 | m_iStartTime = cCopy.m_iStartTime; | |
9736711c | 712 | m_iMaxBytes = cCopy.m_iMaxBytes; |
be3edeee | 713 | m_iLastSend = cCopy.m_iLastSend; |
714 | m_iMaxStoredBufferLength = cCopy.m_iMaxStoredBufferLength; | |
715 | m_iTimeoutType = cCopy.m_iTimeoutType; | |
9736711c | 716 | |
717 | m_address = cCopy.m_address; | |
be3edeee | 718 | m_bindhost = cCopy.m_bindhost; |
9736711c | 719 | m_bIsIPv6 = cCopy.m_bIsIPv6; |
493d5154 | 720 | m_bSkipConnect = cCopy.m_bSkipConnect; |
6ce29e77 | 721 | #ifdef HAVE_C_ARES |
722 | FreeAres(); // Not copying this state, but making sure its nulled out | |
723 | m_iARESStatus = -1; // set it to unitialized | |
724 | m_pCurrAddr = NULL; | |
725 | #endif /* HAVE_C_ARES */ | |
9736711c | 726 | |
727 | #ifdef HAVE_LIBSSL | |
37d0c5e5 | 728 | m_iRequireClientCertFlags = cCopy.m_iRequireClientCertFlags; |
1fb00397 | 729 | m_sSSLBuffer = cCopy.m_sSSLBuffer; |
730 | ||
9736711c | 731 | FREE_SSL(); |
732 | FREE_CTX(); // be sure to remove anything that was already here | |
733 | m_ssl = cCopy.m_ssl; | |
734 | m_ssl_ctx = cCopy.m_ssl_ctx; | |
9736711c | 735 | |
736 | m_pCerVerifyCB = cCopy.m_pCerVerifyCB; | |
737 | ||
738 | #endif /* HAVE_LIBSSL */ | |
739 | ||
8d37abf3 | 740 | if( !m_vcCrons.empty() ) |
9736711c | 741 | { |
742 | for( u_long a = 0; a < m_vcCrons.size(); a++ ) | |
743 | { | |
744 | CS_Delete( m_vcCrons[a] ); | |
745 | } | |
746 | m_vcCrons.clear(); | |
747 | } | |
748 | m_vcCrons = cCopy.m_vcCrons; | |
749 | ||
750 | m_eConState = cCopy.m_eConState; | |
751 | m_sBindHost = cCopy.m_sBindHost; | |
752 | m_iCurBindCount = cCopy.m_iCurBindCount; | |
be3edeee | 753 | m_iDNSTryCount = cCopy.m_iDNSTryCount; |
9736711c | 754 | |
9736711c | 755 | } |
756 | ||
79aaf3d5 | 757 | Csock & Csock::operator<<( const CS_STRING & s ) |
8a769a6f | 758 | { |
759 | Write( s ); | |
760 | return( *this ); | |
761 | } | |
762 | ||
763 | Csock & Csock::operator<<( ostream & ( *io )( ostream & ) ) | |
764 | { | |
765 | Write( "\r\n" ); | |
766 | return( *this ); | |
767 | } | |
768 | ||
79aaf3d5 | 769 | Csock & Csock::operator<<( int i ) |
8a769a6f | 770 | { |
771 | stringstream s; | |
772 | s << i; | |
773 | Write( s.str() ); | |
774 | return( *this ); | |
775 | } | |
79aaf3d5 | 776 | Csock & Csock::operator<<( unsigned int i ) |
8a769a6f | 777 | { |
778 | stringstream s; | |
779 | s << i; | |
780 | Write( s.str() ); | |
781 | return( *this ); | |
782 | } | |
79aaf3d5 | 783 | Csock & Csock::operator<<( long i ) |
784 | { | |
8a769a6f | 785 | stringstream s; |
786 | s << i; | |
787 | Write( s.str() ); | |
788 | return( *this ); | |
789 | } | |
79aaf3d5 | 790 | Csock & Csock::operator<<( unsigned long i ) |
8a769a6f | 791 | { |
792 | stringstream s; | |
793 | s << i; | |
794 | Write( s.str() ); | |
795 | return( *this ); | |
796 | } | |
79aaf3d5 | 797 | Csock & Csock::operator<<( unsigned long long i ) |
8a769a6f | 798 | { |
799 | stringstream s; | |
800 | s << i; | |
801 | Write( s.str() ); | |
802 | return( *this ); | |
803 | } | |
79aaf3d5 | 804 | Csock & Csock::operator<<( float i ) |
8a769a6f | 805 | { |
806 | stringstream s; | |
807 | s << i; | |
808 | Write( s.str() ); | |
809 | return( *this ); | |
810 | } | |
79aaf3d5 | 811 | Csock & Csock::operator<<( double i ) |
8a769a6f | 812 | { |
813 | stringstream s; | |
814 | s << i; | |
815 | Write( s.str() ); | |
816 | return( *this ); | |
79aaf3d5 | 817 | } |
8a769a6f | 818 | |
6dbb196e | 819 | bool Csock::Connect( const CS_STRING & sBindHost, bool bSkipSetup ) |
8a769a6f | 820 | { |
493d5154 | 821 | if( m_bSkipConnect ) |
822 | { // this was already called, so skipping now. this is to allow easy pass through | |
3583b4b5 | 823 | if ( m_eConState != CST_OK ) |
824 | { | |
825 | m_eConState = ( GetSSL() ? CST_CONNECTSSL : CST_OK ); | |
826 | } | |
493d5154 | 827 | return( true ); |
828 | } | |
c287c5cd | 829 | // bind to a hostname if requested |
830 | m_sBindHost = sBindHost; | |
6dbb196e | 831 | if ( !bSkipSetup ) |
8a769a6f | 832 | { |
6dbb196e | 833 | if ( !sBindHost.empty() ) |
8a769a6f | 834 | { |
6dbb196e | 835 | // try to bind 3 times, otherwise exit failure |
836 | bool bBound = false; | |
837 | for( int a = 0; a < 3 && !bBound; a++ ) | |
8a769a6f | 838 | { |
6dbb196e | 839 | if ( SetupVHost() ) |
840 | bBound = true; | |
2d1602ec | 841 | #ifdef _WIN32 |
6dbb196e | 842 | Sleep( 5000 ); |
2d1602ec | 843 | #else |
6dbb196e | 844 | usleep( 5000 ); // quick pause, common lets BIND!)(!*! |
2d1602ec | 845 | #endif /* _WIN32 */ |
6dbb196e | 846 | } |
8a769a6f | 847 | |
6dbb196e | 848 | if ( !bBound ) |
849 | { | |
850 | CS_DEBUG( "Failure to bind to " << sBindHost ); | |
851 | return( false ); | |
852 | } | |
8a769a6f | 853 | } |
1fb00397 | 854 | |
855 | int iDNSRet = ETIMEDOUT; | |
856 | while( true ) | |
857 | { | |
858 | iDNSRet = DNSLookup( DNS_VHOST ); | |
859 | if ( iDNSRet == EAGAIN ) | |
860 | continue; | |
861 | ||
862 | break; | |
863 | } | |
864 | if ( iDNSRet != 0 ) | |
865 | return( false ); | |
866 | ||
8a769a6f | 867 | } |
868 | ||
869 | // set it none blocking | |
c6664d5a | 870 | set_non_blocking( m_iReadSock ); |
2d1602ec | 871 | |
8a769a6f | 872 | m_iConnType = OUTBOUND; |
873 | ||
487b6b65 | 874 | int ret = -1; |
875 | if( !GetIPv6() ) | |
876 | ret = connect( m_iReadSock, (struct sockaddr *)m_address.GetSockAddr(), m_address.GetSockAddrLen() ); | |
877 | #ifdef HAVE_IPV6 | |
878 | else | |
879 | ret = connect( m_iReadSock, (struct sockaddr *)m_address.GetSockAddr6(), m_address.GetSockAddrLen6() ); | |
880 | #endif /* HAVE_IPV6 */ | |
2d1602ec | 881 | #ifndef _WIN32 |
882 | if ( ( ret == -1 ) && ( GetSockError() != EINPROGRESS ) ) | |
883 | #else | |
884 | if ( ( ret == -1 ) && ( GetSockError() != EINPROGRESS ) && ( GetSockError() != WSAEWOULDBLOCK ) ) | |
885 | #endif /* _WIN32 */ | |
886 | ||
8a769a6f | 887 | { |
2d1602ec | 888 | CS_DEBUG( "Connect Failed. ERRNO [" << GetSockError() << "] FD [" << m_iReadSock << "]" ); |
8a769a6f | 889 | return( false ); |
890 | } | |
891 | ||
892 | if ( m_bBLOCK ) | |
79aaf3d5 | 893 | { |
c6664d5a | 894 | set_blocking( m_iReadSock ); |
8a769a6f | 895 | } |
896 | ||
6dbb196e | 897 | if ( m_eConState != CST_OK ) |
3583b4b5 | 898 | { |
899 | m_eConState = ( GetSSL() ? CST_CONNECTSSL : CST_OK ); | |
900 | } | |
6dbb196e | 901 | |
8a769a6f | 902 | return( true ); |
903 | } | |
904 | ||
905 | int Csock::WriteSelect() | |
906 | { | |
c7546c0c | 907 | if ( m_iWriteSock == CS_INVALID_SOCK ) |
8a769a6f | 908 | return( SEL_ERR ); |
909 | ||
910 | struct timeval tv; | |
911 | fd_set wfds; | |
912 | ||
913 | TFD_ZERO( &wfds ); | |
914 | TFD_SET( m_iWriteSock, &wfds ); | |
915 | ||
916 | tv.tv_sec = m_itimeout; | |
917 | tv.tv_usec = 0; | |
918 | ||
919 | int ret = select( FD_SETSIZE, NULL, &wfds, NULL, &tv ); | |
920 | ||
921 | if ( ret == 0 ) | |
922 | return( SEL_TIMEOUT ); | |
923 | ||
924 | if ( ret == -1 ) | |
925 | { | |
2d1602ec | 926 | if ( GetSockError() == EINTR ) |
8a769a6f | 927 | return( SEL_EAGAIN ); |
928 | else | |
929 | return( SEL_ERR ); | |
930 | } | |
931 | ||
932 | return( SEL_OK ); | |
933 | } | |
934 | ||
935 | int Csock::ReadSelect() | |
936 | { | |
c7546c0c | 937 | if ( m_iReadSock == CS_INVALID_SOCK ) |
8a769a6f | 938 | return( SEL_ERR ); |
939 | ||
940 | struct timeval tv; | |
941 | fd_set rfds; | |
942 | ||
943 | TFD_ZERO( &rfds ); | |
944 | TFD_SET( m_iReadSock, &rfds ); | |
945 | ||
946 | tv.tv_sec = m_itimeout; | |
947 | tv.tv_usec = 0; | |
948 | ||
949 | int ret = select( FD_SETSIZE, &rfds, NULL, NULL, &tv ); | |
950 | ||
951 | if ( ret == 0 ) | |
952 | return( SEL_TIMEOUT ); | |
953 | ||
954 | if ( ret == -1 ) | |
955 | { | |
2d1602ec | 956 | if ( GetSockError() == EINTR ) |
8a769a6f | 957 | return( SEL_EAGAIN ); |
958 | else | |
959 | return( SEL_ERR ); | |
960 | } | |
961 | ||
962 | return( SEL_OK ); | |
963 | } | |
964 | ||
6dbb196e | 965 | bool Csock::Listen( u_short iPort, int iMaxConns, const CS_STRING & sBindHost, u_int iTimeout ) |
8a769a6f | 966 | { |
8a769a6f | 967 | m_iConnType = LISTENER; |
968 | m_itimeout = iTimeout; | |
969 | ||
6dbb196e | 970 | m_sBindHost = sBindHost; |
487b6b65 | 971 | if ( !sBindHost.empty() ) |
972 | { | |
3fd82a60 | 973 | // forcing this to block regardless of resolver overloading, because listen is not currently setup to |
974 | // to handle nonblocking operations. This is used to resolve local ip's for binding anyways and should be instant | |
975 | if( ::GetAddrInfo( sBindHost, this, m_address ) != 0 ) | |
9d4be439 | 976 | return( false ); |
487b6b65 | 977 | } |
9d4be439 | 978 | |
25ef3439 | 979 | m_iReadSock = m_iWriteSock = CreateSocket( true ); |
9d4be439 | 980 | |
25ef3439 | 981 | if ( m_iReadSock == CS_INVALID_SOCK ) |
9d4be439 | 982 | return( false ); |
983 | ||
f5ede26c | 984 | #ifdef HAVE_IPV6 |
8d37abf3 | 985 | // there's no IPPROTO_IPV6 below Win XP. - KiNgMaR |
986 | #if (!defined(_WIN32) && defined(IPV6_V6ONLY)) || (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0501) | |
987 | if( GetIPv6() ) | |
988 | { | |
989 | // per RFC3493#5.3 | |
990 | const int on = ( m_address.GetAFRequire() == CSSockAddr::RAF_INET6 ? 1 : 0 ); | |
991 | if( setsockopt( m_iReadSock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof( on ) ) != 0 ) | |
992 | PERROR( "IPV6_V6ONLY" ); | |
993 | } | |
f5ede26c | 994 | #endif /* IPV6_V6ONLY */ |
995 | #endif /* HAVE_IPV6 */ | |
996 | ||
9d4be439 | 997 | m_address.SinFamily(); |
487b6b65 | 998 | m_address.SinPort( iPort ); |
487b6b65 | 999 | if( !GetIPv6() ) |
1000 | { | |
1001 | if ( bind( m_iReadSock, (struct sockaddr *) m_address.GetSockAddr(), m_address.GetSockAddrLen() ) == -1 ) | |
1002 | return( false ); | |
1003 | } | |
1004 | #ifdef HAVE_IPV6 | |
8a769a6f | 1005 | else |
1006 | { | |
487b6b65 | 1007 | if ( bind( m_iReadSock, (struct sockaddr *) m_address.GetSockAddr6(), m_address.GetSockAddrLen6() ) == -1 ) |
8a769a6f | 1008 | return( false ); |
1009 | } | |
487b6b65 | 1010 | #endif /* HAVE_IPV6 */ |
8a769a6f | 1011 | |
1012 | if ( listen( m_iReadSock, iMaxConns ) == -1 ) | |
1013 | return( false ); | |
1014 | ||
1015 | if ( !m_bBLOCK ) | |
1016 | { | |
1017 | // set it none blocking | |
c6664d5a | 1018 | set_non_blocking( m_iReadSock ); |
8a769a6f | 1019 | } |
1020 | ||
1021 | return( true ); | |
1022 | } | |
1023 | ||
c7546c0c | 1024 | cs_sock_t Csock::Accept( CS_STRING & sHost, u_short & iRPort ) |
8a769a6f | 1025 | { |
c7546c0c | 1026 | cs_sock_t iSock = CS_INVALID_SOCK; |
487b6b65 | 1027 | if( !GetIPv6() ) |
1028 | { | |
1029 | struct sockaddr_in client; | |
1030 | socklen_t clen = sizeof( client ); | |
1031 | iSock = accept( m_iReadSock, (struct sockaddr *) &client, &clen ); | |
c7546c0c | 1032 | if( iSock != CS_INVALID_SOCK ) |
69f44c35 | 1033 | { |
1034 | getpeername( iSock, (struct sockaddr *) &client, &clen ); | |
635fb4bc | 1035 | sHost = ConvertAddress( &client.sin_addr, false ); |
69f44c35 | 1036 | iRPort = ntohs( client.sin_port ); |
1037 | } | |
487b6b65 | 1038 | } |
1039 | #ifdef HAVE_IPV6 | |
1040 | else | |
1041 | { | |
487b6b65 | 1042 | struct sockaddr_in6 client; |
1043 | socklen_t clen = sizeof( client ); | |
1044 | iSock = accept( m_iReadSock, (struct sockaddr *) &client, &clen ); | |
c7546c0c | 1045 | if( iSock != CS_INVALID_SOCK ) |
487b6b65 | 1046 | { |
69f44c35 | 1047 | getpeername( iSock, (struct sockaddr *) &client, &clen ); |
635fb4bc | 1048 | sHost = ConvertAddress( &client.sin6_addr, true ); |
1049 | iRPort = ntohs( client.sin6_port ); | |
487b6b65 | 1050 | } |
1051 | } | |
1052 | #endif /* HAVE_IPV6 */ | |
8a769a6f | 1053 | |
c7546c0c | 1054 | if ( iSock != CS_INVALID_SOCK ) |
8a769a6f | 1055 | { |
c6664d5a | 1056 | // Make it close-on-exec |
1057 | set_close_on_exec( iSock ); | |
1058 | ||
8a769a6f | 1059 | if ( !m_bBLOCK ) |
1060 | { | |
88e7f093 | 1061 | // make it none blocking |
331f8b1e | 1062 | set_non_blocking( iSock ); |
8a769a6f | 1063 | } |
1064 | ||
8a769a6f | 1065 | if ( !ConnectionFrom( sHost, iRPort ) ) |
1066 | { | |
a2abf0fd | 1067 | CS_CLOSE( iSock ); |
c7546c0c | 1068 | iSock = CS_INVALID_SOCK; |
8a769a6f | 1069 | } |
1070 | ||
1071 | } | |
1072 | ||
1073 | return( iSock ); | |
1074 | } | |
1075 | ||
1076 | bool Csock::AcceptSSL() | |
1077 | { | |
1078 | #ifdef HAVE_LIBSSL | |
1079 | if ( !m_ssl ) | |
1080 | if ( !SSLServerSetup() ) | |
1081 | return( false ); | |
1082 | ||
1083 | int err = SSL_accept( m_ssl ); | |
1084 | ||
1085 | if ( err == 1 ) | |
1086 | { | |
79aaf3d5 | 1087 | return( true ); |
8a769a6f | 1088 | } |
1089 | ||
8a769a6f | 1090 | int sslErr = SSL_get_error( m_ssl, err ); |
1091 | ||
1092 | if ( ( sslErr == SSL_ERROR_WANT_READ ) || ( sslErr == SSL_ERROR_WANT_WRITE ) ) | |
1093 | return( true ); | |
1094 | ||
1095 | SSLErrors( __FILE__, __LINE__ ); | |
1096 | ||
1097 | #endif /* HAVE_LIBSSL */ | |
1098 | ||
79aaf3d5 | 1099 | return( false ); |
8a769a6f | 1100 | } |
1101 | ||
8a769a6f | 1102 | bool Csock::SSLClientSetup() |
1103 | { | |
79aaf3d5 | 1104 | #ifdef HAVE_LIBSSL |
8a769a6f | 1105 | m_bssl = true; |
1106 | FREE_SSL(); | |
1107 | FREE_CTX(); | |
1108 | ||
25ef3439 | 1109 | #ifdef _WIN64 |
1110 | if( m_iReadSock != (int)m_iReadSock || m_iWriteSock != (int)m_iWriteSock ) | |
1111 | { | |
1112 | // sanity check the FD to be sure its compatible with openssl | |
1113 | CS_DEBUG( "ERROR: sockfd larger than OpenSSL can handle" ); | |
1114 | return( false ); | |
1115 | } | |
5ea1f8cc | 1116 | #endif /* _WIN64 */ |
25ef3439 | 1117 | |
dba60545 A |
1118 | m_ssl_ctx = SSL_CTX_new(TLS_client_method()); |
1119 | if (!m_ssl_ctx) | |
8a769a6f | 1120 | { |
dba60545 A |
1121 | CS_DEBUG( "WARNING: MakeConnection .... TLS_client_method failed!" ); |
1122 | return( false ); | |
8a769a6f | 1123 | } |
1124 | ||
9210bdc9 | 1125 | SSL_CTX_set_default_verify_paths( m_ssl_ctx ); |
1126 | ||
8a769a6f | 1127 | if ( !m_sPemFile.empty() ) |
1128 | { // are we sending a client cerificate ? | |
1129 | SSL_CTX_set_default_passwd_cb( m_ssl_ctx, PemPassCB ); | |
1130 | SSL_CTX_set_default_passwd_cb_userdata( m_ssl_ctx, (void *)this ); | |
1131 | ||
1132 | // | |
1133 | // set up the CTX | |
1134 | if ( SSL_CTX_use_certificate_file( m_ssl_ctx, m_sPemFile.c_str() , SSL_FILETYPE_PEM ) <= 0 ) | |
1135 | { | |
1136 | CS_DEBUG( "Error with PEM file [" << m_sPemFile << "]" ); | |
1137 | SSLErrors( __FILE__, __LINE__ ); | |
1138 | } | |
1139 | ||
1140 | if ( SSL_CTX_use_PrivateKey_file( m_ssl_ctx, m_sPemFile.c_str(), SSL_FILETYPE_PEM ) <= 0 ) | |
1141 | { | |
1142 | CS_DEBUG( "Error with PEM file [" << m_sPemFile << "]" ); | |
1143 | SSLErrors( __FILE__, __LINE__ ); | |
1144 | } | |
1145 | } | |
1146 | ||
1147 | m_ssl = SSL_new ( m_ssl_ctx ); | |
1148 | if ( !m_ssl ) | |
1149 | return( false ); | |
1150 | ||
25ef3439 | 1151 | SSL_set_rfd( m_ssl, (int)m_iReadSock ); |
1152 | SSL_set_wfd( m_ssl, (int)m_iWriteSock ); | |
ed120ee5 | 1153 | SSL_set_verify( m_ssl, SSL_VERIFY_PEER, ( m_pCerVerifyCB ? m_pCerVerifyCB : CertVerifyCB ) ); |
b63b7d03 | 1154 | SSL_set_ex_data( m_ssl, GetCsockClassIdx(), this ); |
8a769a6f | 1155 | |
ed120ee5 | 1156 | SSLFinishSetup( m_ssl ); |
8a769a6f | 1157 | return( true ); |
1158 | #else | |
1159 | return( false ); | |
1160 | ||
79aaf3d5 | 1161 | #endif /* HAVE_LIBSSL */ |
8a769a6f | 1162 | } |
1163 | ||
1164 | bool Csock::SSLServerSetup() | |
1165 | { | |
1166 | #ifdef HAVE_LIBSSL | |
1167 | m_bssl = true; | |
79aaf3d5 | 1168 | FREE_SSL(); |
8a769a6f | 1169 | FREE_CTX(); |
1170 | ||
25ef3439 | 1171 | #ifdef _WIN64 |
1172 | if( m_iReadSock != (int)m_iReadSock || m_iWriteSock != (int)m_iWriteSock ) | |
1173 | { | |
1174 | // sanity check the FD to be sure its compatible with openssl | |
1175 | CS_DEBUG( "ERROR: sockfd larger than OpenSSL can handle" ); | |
1176 | return( false ); | |
1177 | } | |
5ea1f8cc | 1178 | #endif /* _WIN64 */ |
25ef3439 | 1179 | |
1180 | ||
dba60545 A |
1181 | m_ssl_ctx = SSL_CTX_new(TLS_server_method()); |
1182 | if ( !m_ssl_ctx ) | |
8a769a6f | 1183 | { |
dba60545 A |
1184 | CS_DEBUG( "WARNING: MakeConnection .... TLS_server_method failed!" ); |
1185 | return( false ); | |
8a769a6f | 1186 | } |
1187 | ||
9210bdc9 | 1188 | SSL_CTX_set_default_verify_paths( m_ssl_ctx ); |
8a769a6f | 1189 | |
1190 | // set the pemfile password | |
1191 | SSL_CTX_set_default_passwd_cb( m_ssl_ctx, PemPassCB ); | |
1192 | SSL_CTX_set_default_passwd_cb_userdata( m_ssl_ctx, (void *)this ); | |
1193 | ||
1194 | if ( ( m_sPemFile.empty() ) || ( access( m_sPemFile.c_str(), R_OK ) != 0 ) ) | |
79aaf3d5 | 1195 | { |
8a769a6f | 1196 | CS_DEBUG( "There is a problem with [" << m_sPemFile << "]" ); |
1197 | return( false ); | |
1198 | } | |
1199 | ||
1200 | // | |
1201 | // set up the CTX | |
88e7f093 | 1202 | if( SSL_CTX_use_certificate_chain_file( m_ssl_ctx, m_sPemFile.c_str() ) <= 0 ) |
8a769a6f | 1203 | { |
1204 | CS_DEBUG( "Error with PEM file [" << m_sPemFile << "]" ); | |
1205 | SSLErrors( __FILE__, __LINE__ ); | |
1206 | return( false ); | |
1207 | } | |
1208 | ||
88e7f093 | 1209 | if( SSL_CTX_use_PrivateKey_file( m_ssl_ctx, m_sPemFile.c_str(), SSL_FILETYPE_PEM ) <= 0 ) |
8a769a6f | 1210 | { |
1211 | CS_DEBUG( "Error with PEM file [" << m_sPemFile << "]" ); | |
1212 | SSLErrors( __FILE__, __LINE__ ); | |
1213 | return( false ); | |
1214 | } | |
1215 | ||
88e7f093 US |
1216 | // check to see if this pem file contains a DH structure for use with DH key exchange |
1217 | // https://github.com/znc/znc/pull/46 | |
1218 | FILE *dhParamsFile = fopen( m_sPemFile.c_str(), "r" ); | |
1219 | if( !dhParamsFile ) | |
1220 | { | |
1221 | CS_DEBUG( "There is a problem with [" << m_sPemFile << "]" ); | |
1222 | return( false ); | |
1223 | } | |
1224 | ||
1225 | DH * dhParams = PEM_read_DHparams( dhParamsFile, NULL, NULL, NULL ); | |
1226 | fclose( dhParamsFile ); | |
1227 | if( dhParams ) | |
1228 | { | |
1229 | SSL_CTX_set_options( m_ssl_ctx, SSL_OP_SINGLE_DH_USE ); | |
1230 | if( !SSL_CTX_set_tmp_dh( m_ssl_ctx, dhParams ) ) | |
1231 | { | |
1232 | CS_DEBUG( "Error setting ephemeral DH parameters from [" << m_sPemFile << "]" ); | |
1233 | SSLErrors( __FILE__, __LINE__ ); | |
1234 | DH_free( dhParams ); | |
1235 | return( false ); | |
1236 | } | |
1237 | DH_free( dhParams ); | |
1238 | } | |
1239 | else | |
1240 | { // Presumably PEM_read_DHparams failed, as there was no DH structure. Clearing those errors here so they are removed off the stack | |
1241 | ERR_clear_error(); | |
1242 | } | |
1243 | ||
1244 | if( SSL_CTX_set_cipher_list( m_ssl_ctx, m_sCipherType.c_str() ) <= 0 ) | |
8a769a6f | 1245 | { |
1246 | CS_DEBUG( "Could not assign cipher [" << m_sCipherType << "]" ); | |
1247 | return( false ); | |
1248 | } | |
1249 | ||
1250 | // | |
1251 | // setup the SSL | |
88e7f093 | 1252 | m_ssl = SSL_new( m_ssl_ctx ); |
8a769a6f | 1253 | if ( !m_ssl ) |
1254 | return( false ); | |
1255 | ||
1256 | // Call for client Verification | |
25ef3439 | 1257 | SSL_set_rfd( m_ssl, (int)m_iReadSock ); |
1258 | SSL_set_wfd( m_ssl, (int)m_iWriteSock ); | |
8a769a6f | 1259 | SSL_set_accept_state( m_ssl ); |
37d0c5e5 | 1260 | if ( m_iRequireClientCertFlags ) |
b63b7d03 | 1261 | { |
37d0c5e5 | 1262 | SSL_set_verify( m_ssl, m_iRequireClientCertFlags, ( m_pCerVerifyCB ? m_pCerVerifyCB : CertVerifyCB ) ); |
b63b7d03 | 1263 | SSL_set_ex_data( m_ssl, GetCsockClassIdx(), this ); |
1264 | } | |
8a769a6f | 1265 | |
ed120ee5 | 1266 | SSLFinishSetup( m_ssl ); |
8a769a6f | 1267 | return( true ); |
1268 | #else | |
1269 | return( false ); | |
79aaf3d5 | 1270 | #endif /* HAVE_LIBSSL */ |
1271 | } | |
8a769a6f | 1272 | |
1273 | bool Csock::ConnectSSL( const CS_STRING & sBindhost ) | |
1274 | { | |
79aaf3d5 | 1275 | #ifdef HAVE_LIBSSL |
25ef3439 | 1276 | if ( m_iReadSock == CS_INVALID_SOCK ) |
8a769a6f | 1277 | if ( !Connect( sBindhost ) ) |
1278 | return( false ); | |
8a769a6f | 1279 | if ( !m_ssl ) |
1280 | if ( !SSLClientSetup() ) | |
1281 | return( false ); | |
1282 | ||
1283 | bool bPass = true; | |
1284 | ||
1285 | if ( m_bBLOCK ) | |
1286 | { | |
c6664d5a | 1287 | set_non_blocking( m_iReadSock ); |
79aaf3d5 | 1288 | } |
8a769a6f | 1289 | |
1290 | int iErr = SSL_connect( m_ssl ); | |
1291 | if ( iErr != 1 ) | |
1292 | { | |
1293 | int sslErr = SSL_get_error( m_ssl, iErr ); | |
583b91f7 | 1294 | bPass = false; |
1295 | if( sslErr == SSL_ERROR_WANT_READ || sslErr == SSL_ERROR_WANT_WRITE ) | |
1296 | bPass = true; | |
1297 | #ifdef _WIN32 | |
1298 | else if( sslErr == SSL_ERROR_SYSCALL && iErr < 0 && GetLastError() == WSAENOTCONN ) | |
88e7f093 | 1299 | { |
583b91f7 | 1300 | // this seems to be an issue with win32 only. I've seen it happen on slow connections |
1301 | // the issue is calling this before select(), which isn't a problem on unix. Allowing this | |
1302 | // to pass in this case is fine because subsequent ssl transactions will occur and the handshake | |
1303 | // will finish. At this point, its just instantiating the handshake. | |
1304 | bPass = true; | |
1305 | } | |
1306 | #endif /* _WIN32 */ | |
8a769a6f | 1307 | } else |
1308 | bPass = true; | |
1309 | ||
1310 | if ( m_bBLOCK ) | |
79aaf3d5 | 1311 | { |
8a769a6f | 1312 | // unset the flags afterwords, rather then have connect block |
c6664d5a | 1313 | set_blocking( m_iReadSock ); |
79aaf3d5 | 1314 | } |
8a769a6f | 1315 | |
3583b4b5 | 1316 | if ( m_eConState != CST_OK ) |
1317 | m_eConState = CST_OK; | |
8a769a6f | 1318 | return( bPass ); |
1319 | #else | |
1320 | return( false ); | |
1321 | #endif /* HAVE_LIBSSL */ | |
1322 | } | |
1323 | ||
2bbdb72a | 1324 | bool Csock::AllowWrite( unsigned long long & iNOW ) const |
ed120ee5 | 1325 | { |
1326 | if ( ( m_iMaxBytes > 0 ) && ( m_iMaxMilliSeconds > 0 ) ) | |
1327 | { | |
2bbdb72a | 1328 | if( iNOW == 0 ) |
1329 | iNOW = millitime(); | |
1330 | ||
ed120ee5 | 1331 | if( m_iLastSend < m_iMaxBytes ) |
1332 | return( true ); // allow sending if our out buffer was less than what we can send | |
1333 | if ( ( iNOW - m_iLastSendTime ) < m_iMaxMilliSeconds ) | |
1334 | return( false ); | |
1335 | } | |
1336 | return( true ); | |
1337 | } | |
1338 | ||
f5ede26c | 1339 | bool Csock::Write( const char *data, size_t len ) |
8a769a6f | 1340 | { |
1341 | m_sSend.append( data, len ); | |
1342 | ||
1343 | if ( m_sSend.empty() ) | |
1344 | return( true ); | |
1345 | ||
6dbb196e | 1346 | if ( m_eConState != CST_OK ) |
1347 | return( true ); | |
1348 | ||
8a769a6f | 1349 | if ( m_bBLOCK ) |
1350 | { | |
1351 | if ( WriteSelect() != SEL_OK ) | |
1352 | return( false ); | |
1353 | ||
1354 | } | |
1355 | // rate shaping | |
f5ede26c | 1356 | u_long iBytesToSend = 0; |
8a769a6f | 1357 | |
a2abf0fd | 1358 | #ifdef HAVE_LIBSSL |
1359 | if( m_bssl && m_sSSLBuffer.empty() && !m_bsslEstablished ) | |
1360 | { | |
1361 | // to keep openssl from spinning, just initiate the connection with 1 byte so the connection establishes faster | |
1362 | iBytesToSend = 1; | |
1363 | } | |
9a2e17c6 | 1364 | else |
a2abf0fd | 1365 | #endif /* HAVE_LIBSSL */ |
9a2e17c6 | 1366 | if ( ( m_iMaxBytes > 0 ) && ( m_iMaxMilliSeconds > 0 ) ) |
8a769a6f | 1367 | { |
1368 | unsigned long long iNOW = millitime(); | |
79aaf3d5 | 1369 | // figure out the shaping here |
8a769a6f | 1370 | // if NOW - m_iLastSendTime > m_iMaxMilliSeconds then send a full length of ( iBytesToSend ) |
1371 | if ( ( iNOW - m_iLastSendTime ) > m_iMaxMilliSeconds ) | |
1372 | { | |
1373 | m_iLastSendTime = iNOW; | |
1374 | iBytesToSend = m_iMaxBytes; | |
1375 | m_iLastSend = 0; | |
1376 | ||
1377 | } else // otherwise send m_iMaxBytes - m_iLastSend | |
1378 | iBytesToSend = m_iMaxBytes - m_iLastSend; | |
1379 | ||
1380 | // take which ever is lesser | |
1381 | if ( m_sSend.length() < iBytesToSend ) | |
1382 | iBytesToSend = m_sSend.length(); | |
1383 | ||
1384 | // add up the bytes sent | |
1385 | m_iLastSend += iBytesToSend; | |
1386 | ||
1387 | // so, are we ready to send anything ? | |
1388 | if ( iBytesToSend == 0 ) | |
1389 | return( true ); | |
1390 | ||
1391 | } else | |
1392 | iBytesToSend = m_sSend.length(); | |
1393 | ||
79aaf3d5 | 1394 | #ifdef HAVE_LIBSSL |
8a769a6f | 1395 | if ( m_bssl ) |
79aaf3d5 | 1396 | { |
8a769a6f | 1397 | |
1398 | if ( m_sSSLBuffer.empty() ) // on retrying to write data, ssl wants the data in the SAME spot and the SAME size | |
1399 | m_sSSLBuffer.append( m_sSend.data(), iBytesToSend ); | |
1400 | ||
f5ede26c | 1401 | int iErr = SSL_write( m_ssl, m_sSSLBuffer.data(), (int)m_sSSLBuffer.length() ); |
8a769a6f | 1402 | |
2d1602ec | 1403 | if ( ( iErr < 0 ) && ( GetSockError() == ECONNREFUSED ) ) |
79aaf3d5 | 1404 | { |
8a769a6f | 1405 | // If ret == -1, the underlying BIO reported an I/O error (man SSL_get_error) |
1406 | ConnectionRefused(); | |
1407 | return( false ); | |
1408 | } | |
1409 | ||
1410 | switch( SSL_get_error( m_ssl, iErr ) ) | |
1411 | { | |
1412 | case SSL_ERROR_NONE: | |
79aaf3d5 | 1413 | m_bsslEstablished = true; |
8a769a6f | 1414 | // all ok |
1415 | break; | |
1416 | ||
1417 | case SSL_ERROR_ZERO_RETURN: | |
1418 | { | |
1419 | // weird closer alert | |
1420 | return( false ); | |
1421 | } | |
1422 | ||
1423 | case SSL_ERROR_WANT_READ: | |
1424 | // retry | |
1425 | break; | |
1426 | ||
1427 | case SSL_ERROR_WANT_WRITE: | |
1428 | // retry | |
1429 | break; | |
1430 | ||
1431 | case SSL_ERROR_SSL: | |
1432 | { | |
1433 | SSLErrors( __FILE__, __LINE__ ); | |
1434 | return( false ); | |
1435 | } | |
1436 | } | |
1437 | ||
79aaf3d5 | 1438 | if ( iErr > 0 ) |
8a769a6f | 1439 | { |
1440 | m_sSSLBuffer.clear(); | |
1441 | m_sSend.erase( 0, iErr ); | |
1442 | // reset the timer on successful write (we have to set it here because the write | |
1443 | // bit might not always be set, so need to trigger) | |
1444 | if ( TMO_WRITE & GetTimeoutType() ) | |
79aaf3d5 | 1445 | ResetTimer(); |
8a769a6f | 1446 | |
1447 | m_iBytesWritten += (unsigned long long)iErr; | |
1448 | } | |
1449 | ||
1450 | return( true ); | |
1451 | } | |
1452 | #endif /* HAVE_LIBSSL */ | |
2d1602ec | 1453 | #ifdef _WIN32 |
8d37abf3 | 1454 | cs_ssize_t bytes = send( m_iWriteSock, m_sSend.data(), iBytesToSend, 0 ); |
2d1602ec | 1455 | #else |
8d37abf3 | 1456 | cs_ssize_t bytes = write( m_iWriteSock, m_sSend.data(), iBytesToSend ); |
2d1602ec | 1457 | #endif /* _WIN32 */ |
8a769a6f | 1458 | |
2d1602ec | 1459 | if ( ( bytes == -1 ) && ( GetSockError() == ECONNREFUSED ) ) |
8a769a6f | 1460 | { |
1461 | ConnectionRefused(); | |
1462 | return( false ); | |
1463 | } | |
1464 | ||
2d1602ec | 1465 | #ifdef _WIN32 |
1466 | if ( ( bytes <= 0 ) && ( GetSockError() != WSAEWOULDBLOCK ) ) | |
1467 | return( false ); | |
1468 | #else | |
1469 | if ( ( bytes <= 0 ) && ( GetSockError() != EAGAIN ) ) | |
8a769a6f | 1470 | return( false ); |
2d1602ec | 1471 | #endif /* _WIN32 */ |
8a769a6f | 1472 | |
1473 | // delete the bytes we sent | |
1474 | if ( bytes > 0 ) | |
1475 | { | |
1476 | m_sSend.erase( 0, bytes ); | |
1477 | if ( TMO_WRITE & GetTimeoutType() ) | |
1478 | ResetTimer(); // reset the timer on successful write | |
1479 | m_iBytesWritten += (unsigned long long)bytes; | |
1480 | } | |
1481 | ||
1482 | return( true ); | |
1483 | } | |
1484 | ||
1485 | bool Csock::Write( const CS_STRING & sData ) | |
1486 | { | |
1487 | return( Write( sData.c_str(), sData.length() ) ); | |
1488 | } | |
1489 | ||
8d37abf3 | 1490 | cs_ssize_t Csock::Read( char *data, size_t len ) |
8a769a6f | 1491 | { |
8d37abf3 | 1492 | cs_ssize_t bytes = 0; |
8a769a6f | 1493 | |
88e7f093 | 1494 | if ( IsReadPaused() && SslIsEstablished() ) |
8a769a6f | 1495 | return( READ_EAGAIN ); // allow the handshake to complete first |
1496 | ||
1497 | if ( m_bBLOCK ) | |
1498 | { | |
1499 | switch( ReadSelect() ) | |
1500 | { | |
1501 | case SEL_OK: | |
1502 | break; | |
1503 | case SEL_TIMEOUT: | |
1504 | return( READ_TIMEDOUT ); | |
1505 | default: | |
1506 | return( READ_ERR ); | |
1507 | } | |
1508 | } | |
1509 | ||
1510 | #ifdef HAVE_LIBSSL | |
1511 | if ( m_bssl ) | |
88e7f093 | 1512 | { |
f5ede26c | 1513 | bytes = SSL_read( m_ssl, data, (int)len ); |
88e7f093 US |
1514 | if( bytes >= 0 ) |
1515 | m_bsslEstablished = true; // this means all is good in the realm of ssl | |
1516 | } | |
8a769a6f | 1517 | else |
1518 | #endif /* HAVE_LIBSSL */ | |
2d1602ec | 1519 | #ifdef _WIN32 |
1520 | bytes = recv( m_iReadSock, data, len, 0 ); | |
1521 | #else | |
8a769a6f | 1522 | bytes = read( m_iReadSock, data, len ); |
2d1602ec | 1523 | #endif /* _WIN32 */ |
8a769a6f | 1524 | if ( bytes == -1 ) |
1525 | { | |
2d1602ec | 1526 | if ( GetSockError() == ECONNREFUSED ) |
79aaf3d5 | 1527 | return( READ_CONNREFUSED ); |
8a769a6f | 1528 | |
2d1602ec | 1529 | if ( GetSockError() == ETIMEDOUT ) |
8a769a6f | 1530 | return( READ_TIMEDOUT ); |
1531 | ||
2d1602ec | 1532 | if ( ( GetSockError() == EINTR ) || ( GetSockError() == EAGAIN ) ) |
1533 | return( READ_EAGAIN ); | |
1534 | ||
1535 | #ifdef _WIN32 | |
1536 | if ( GetSockError() == WSAEWOULDBLOCK ) | |
8a769a6f | 1537 | return( READ_EAGAIN ); |
2d1602ec | 1538 | #endif /* _WIN32 */ |
1539 | ||
8a769a6f | 1540 | #ifdef HAVE_LIBSSL |
1541 | if ( m_bssl ) | |
1542 | { | |
f5ede26c | 1543 | int iErr = SSL_get_error( m_ssl, (int)bytes ); |
8a769a6f | 1544 | if ( ( iErr != SSL_ERROR_WANT_READ ) && ( iErr != SSL_ERROR_WANT_WRITE ) ) |
1545 | return( READ_ERR ); | |
1546 | else | |
1547 | return( READ_EAGAIN ); | |
1548 | } | |
1549 | #else | |
1550 | return( READ_ERR ); | |
79aaf3d5 | 1551 | #endif /* HAVE_LIBSSL */ |
8a769a6f | 1552 | } |
1553 | ||
ed120ee5 | 1554 | if( bytes > 0 ) // becareful not to add negative bytes :P |
1555 | m_iBytesRead += (unsigned long long)bytes; | |
8a769a6f | 1556 | |
1557 | return( bytes ); | |
1558 | } | |
1559 | ||
1560 | CS_STRING Csock::GetLocalIP() | |
1561 | { | |
1562 | if ( !m_sLocalIP.empty() ) | |
1563 | return( m_sLocalIP ); | |
1564 | ||
c7546c0c | 1565 | cs_sock_t iSock = GetSock(); |
8a769a6f | 1566 | |
c7546c0c | 1567 | if ( iSock == CS_INVALID_SOCK ) |
8a769a6f | 1568 | return( "" ); |
1569 | ||
487b6b65 | 1570 | if( !GetIPv6() ) |
1571 | { | |
cc552fb3 | 1572 | char straddr[INET_ADDRSTRLEN]; |
487b6b65 | 1573 | struct sockaddr_in mLocalAddr; |
1574 | socklen_t mLocalLen = sizeof( mLocalAddr ); | |
cc552fb3 US |
1575 | if ( ( getsockname( iSock, (struct sockaddr *) &mLocalAddr, &mLocalLen ) == 0 ) |
1576 | && ( inet_ntop( AF_INET, &mLocalAddr.sin_addr, straddr, sizeof(straddr) ) ) ) | |
1577 | { | |
1578 | m_sLocalIP = straddr; | |
1579 | } | |
487b6b65 | 1580 | } |
1581 | #ifdef HAVE_IPV6 | |
1582 | else | |
1583 | { | |
1584 | char straddr[INET6_ADDRSTRLEN]; | |
1585 | struct sockaddr_in6 mLocalAddr; | |
1586 | socklen_t mLocalLen = sizeof( mLocalAddr ); | |
be3edeee | 1587 | if ( ( getsockname( iSock, (struct sockaddr *) &mLocalAddr, &mLocalLen ) == 0 ) |
487b6b65 | 1588 | && ( inet_ntop( AF_INET6, &mLocalAddr.sin6_addr, straddr, sizeof(straddr) ) ) ) |
1589 | { | |
1590 | m_sLocalIP = straddr; | |
1591 | } | |
1592 | } | |
1593 | #endif /* HAVE_IPV6 */ | |
8a769a6f | 1594 | |
1595 | return( m_sLocalIP ); | |
1596 | } | |
1597 | ||
1598 | CS_STRING Csock::GetRemoteIP() | |
1599 | { | |
1600 | if ( !m_sRemoteIP.empty() ) | |
1601 | return( m_sRemoteIP ); | |
1602 | ||
c7546c0c | 1603 | cs_sock_t iSock = GetSock(); |
8a769a6f | 1604 | |
c7546c0c | 1605 | if ( iSock == CS_INVALID_SOCK ) |
8a769a6f | 1606 | return( "" ); |
8a769a6f | 1607 | |
487b6b65 | 1608 | if( !GetIPv6() ) |
1609 | { | |
1610 | struct sockaddr_in mRemoteAddr; | |
1611 | socklen_t mRemoteLen = sizeof( mRemoteAddr ); | |
1612 | if ( getpeername( iSock, (struct sockaddr *) &mRemoteAddr, &mRemoteLen ) == 0 ) | |
635fb4bc | 1613 | m_sRemoteIP = ConvertAddress( &mRemoteAddr.sin_addr, false ); |
487b6b65 | 1614 | } |
1615 | #ifdef HAVE_IPV6 | |
1616 | else | |
1617 | { | |
487b6b65 | 1618 | struct sockaddr_in6 mRemoteAddr; |
1619 | socklen_t mRemoteLen = sizeof( mRemoteAddr ); | |
635fb4bc | 1620 | if ( getpeername( iSock, (struct sockaddr *) &mRemoteAddr, &mRemoteLen ) == 0 ) |
1621 | m_sRemoteIP = ConvertAddress( &mRemoteAddr.sin6_addr, true ); | |
487b6b65 | 1622 | } |
1623 | #endif /* HAVE_IPV6 */ | |
8a769a6f | 1624 | |
1625 | return( m_sRemoteIP ); | |
1626 | } | |
1627 | ||
635fb4bc | 1628 | CS_STRING Csock::ConvertAddress( void *addr, bool bIPv6 ) |
1629 | { | |
1630 | CS_STRING sRet; | |
1631 | ||
88e7f093 | 1632 | if( !bIPv6 ) |
635fb4bc | 1633 | { |
1634 | in_addr *p = (in_addr*) addr; | |
1635 | sRet = inet_ntoa(*p); | |
88e7f093 US |
1636 | } |
1637 | else | |
635fb4bc | 1638 | { |
1639 | char straddr[INET6_ADDRSTRLEN]; | |
1640 | if( inet_ntop( AF_INET6, addr, straddr, sizeof(straddr) ) > 0 ) | |
1641 | sRet = straddr; | |
1642 | } | |
1643 | ||
1644 | return( sRet ); | |
1645 | } | |
1646 | ||
d8f4e319 | 1647 | bool Csock::IsConnected() const { return( m_bIsConnected ); } |
79aaf3d5 | 1648 | void Csock::SetIsConnected( bool b ) { m_bIsConnected = b; } |
8a769a6f | 1649 | |
25ef3439 | 1650 | cs_sock_t & Csock::GetRSock() { return( m_iReadSock ); } |
1651 | void Csock::SetRSock( cs_sock_t iSock ) { m_iReadSock = iSock; } | |
1652 | cs_sock_t & Csock::GetWSock() { return( m_iWriteSock ); } | |
1653 | void Csock::SetWSock( cs_sock_t iSock ) { m_iWriteSock = iSock; } | |
1654 | void Csock::SetSock( cs_sock_t iSock ) { m_iWriteSock = iSock; m_iReadSock = iSock; } | |
1655 | cs_sock_t & Csock::GetSock() { return( m_iReadSock ); } | |
b63b7d03 | 1656 | void Csock::ResetTimer() { m_iLastCheckTimeoutTime = 0; m_iTcount = 0; } |
8a769a6f | 1657 | void Csock::PauseRead() { m_bPauseRead = true; } |
1658 | bool Csock::IsReadPaused() { return( m_bPauseRead ); } | |
1659 | ||
79aaf3d5 | 1660 | void Csock::UnPauseRead() |
1661 | { | |
1662 | m_bPauseRead = false; | |
8a769a6f | 1663 | ResetTimer(); |
4f2599e7 | 1664 | PushBuff( "", 0, true ); |
8a769a6f | 1665 | } |
1666 | ||
79aaf3d5 | 1667 | void Csock::SetTimeout( int iTimeout, u_int iTimeoutType ) |
1668 | { | |
8a769a6f | 1669 | m_iTimeoutType = iTimeoutType; |
79aaf3d5 | 1670 | m_itimeout = iTimeout; |
8a769a6f | 1671 | } |
1672 | ||
1673 | void Csock::SetTimeoutType( u_int iTimeoutType ) { m_iTimeoutType = iTimeoutType; } | |
1674 | int Csock::GetTimeout() const { return m_itimeout; } | |
1675 | u_int Csock::GetTimeoutType() const { return( m_iTimeoutType ); } | |
1676 | ||
b63b7d03 | 1677 | bool Csock::CheckTimeout( time_t iNow ) |
8a769a6f | 1678 | { |
b63b7d03 | 1679 | if( m_iLastCheckTimeoutTime == 0 ) |
1680 | { | |
1681 | m_iLastCheckTimeoutTime = iNow; | |
1682 | return( false ); | |
1683 | } | |
1684 | ||
8a769a6f | 1685 | if ( IsReadPaused() ) |
1686 | return( false ); | |
1687 | ||
b63b7d03 | 1688 | time_t iDiff = 0; |
1689 | if( iNow > m_iLastCheckTimeoutTime ) | |
1690 | iDiff = iNow - m_iLastCheckTimeoutTime; | |
1691 | else | |
babc0f9f | 1692 | { |
1693 | // this is weird, but its possible if someone changes a clock and it went back in time, this essentially has to reset the last check | |
1694 | // the worst case scenario is the timeout is about to it and the clock changes, it would then cause | |
1695 | // this to pass over the last half the time | |
be3edeee | 1696 | m_iLastCheckTimeoutTime = iNow; |
babc0f9f | 1697 | } |
b63b7d03 | 1698 | |
8a769a6f | 1699 | if ( m_itimeout > 0 ) |
1700 | { | |
babc0f9f | 1701 | // this is basically to help stop a clock adjust ahead, stuff could reset immediatly on a clock jump |
1702 | // otherwise | |
b63b7d03 | 1703 | time_t iRealTimeout = m_itimeout; |
1704 | if( iRealTimeout <= 1 ) | |
1705 | m_iTcount++; | |
1706 | else if( m_iTcount == 0 ) | |
1707 | iRealTimeout /= 2; | |
1708 | if( iDiff >= iRealTimeout ) | |
8a769a6f | 1709 | { |
b63b7d03 | 1710 | if( m_iTcount == 0 ) |
1711 | m_iLastCheckTimeoutTime = iNow - iRealTimeout; | |
1712 | if( m_iTcount++ >= 1 ) | |
1713 | { | |
1714 | Timeout(); | |
1715 | return( true ); | |
1716 | } | |
8a769a6f | 1717 | } |
79aaf3d5 | 1718 | } |
8a769a6f | 1719 | return( false ); |
1720 | } | |
1721 | ||
f5ede26c | 1722 | void Csock::PushBuff( const char *data, size_t len, bool bStartAtZero ) |
8a769a6f | 1723 | { |
1724 | if ( !m_bEnableReadLine ) | |
1725 | return; // If the ReadLine event is disabled, just ditch here | |
1726 | ||
f5ede26c | 1727 | size_t iStartPos = ( m_sbuffer.empty() || bStartAtZero ? 0 : m_sbuffer.length() - 1 ); |
8a769a6f | 1728 | |
1729 | if ( data ) | |
1730 | m_sbuffer.append( data, len ); | |
1731 | ||
c6664d5a | 1732 | while( !m_bPauseRead && GetCloseType() == CLT_DONT ) |
8a769a6f | 1733 | { |
1734 | CS_STRING::size_type iFind = m_sbuffer.find( "\n", iStartPos ); | |
1735 | ||
1736 | if ( iFind != CS_STRING::npos ) | |
1737 | { | |
1738 | CS_STRING sBuff = m_sbuffer.substr( 0, iFind + 1 ); // read up to(including) the newline | |
1739 | m_sbuffer.erase( 0, iFind + 1 ); // erase past the newline | |
1740 | ReadLine( sBuff ); | |
1741 | iStartPos = 0; // reset this back to 0, since we need to look for the next newline here. | |
1742 | ||
1743 | } else | |
1744 | break; | |
1745 | } | |
1746 | ||
1747 | if ( ( m_iMaxStoredBufferLength > 0 ) && ( m_sbuffer.length() > m_iMaxStoredBufferLength ) ) | |
1748 | ReachedMaxBuffer(); // call the max read buffer event | |
1749 | ||
1750 | } | |
1751 | ||
5665fd87 | 1752 | CS_STRING & Csock::GetInternalReadBuffer() { return( m_sbuffer ); } |
1753 | CS_STRING & Csock::GetInternalWriteBuffer() { return( m_sSend ); } | |
8a769a6f | 1754 | void Csock::SetMaxBufferThreshold( u_int iThreshold ) { m_iMaxStoredBufferLength = iThreshold; } |
583b91f7 | 1755 | u_int Csock::GetMaxBufferThreshold() const { return( m_iMaxStoredBufferLength ); } |
1756 | int Csock::GetType() const { return( m_iConnType ); } | |
8a769a6f | 1757 | void Csock::SetType( int iType ) { m_iConnType = iType; } |
583b91f7 | 1758 | const CS_STRING & Csock::GetSockName() const { return( m_sSockName ); } |
8a769a6f | 1759 | void Csock::SetSockName( const CS_STRING & sName ) { m_sSockName = sName; } |
583b91f7 | 1760 | const CS_STRING & Csock::GetHostName() const { return( m_shostname ); } |
8a769a6f | 1761 | void Csock::SetHostName( const CS_STRING & sHostname ) { m_shostname = sHostname; } |
79aaf3d5 | 1762 | unsigned long long Csock::GetStartTime() const { return( m_iStartTime ); } |
8a769a6f | 1763 | void Csock::ResetStartTime() { m_iStartTime = 0; } |
1764 | unsigned long long Csock::GetBytesRead() const { return( m_iBytesRead ); } | |
1765 | void Csock::ResetBytesRead() { m_iBytesRead = 0; } | |
1766 | unsigned long long Csock::GetBytesWritten() const { return( m_iBytesWritten ); } | |
1767 | void Csock::ResetBytesWritten() { m_iBytesWritten = 0; } | |
1768 | ||
1769 | double Csock::GetAvgRead( unsigned long long iSample ) | |
1770 | { | |
1771 | unsigned long long iDifference = ( millitime() - m_iStartTime ); | |
1772 | ||
1773 | if ( ( m_iBytesRead == 0 ) || ( iSample > iDifference ) ) | |
1774 | return( (double)m_iBytesRead ); | |
1775 | ||
1776 | return( ( (double)m_iBytesRead / ( (double)iDifference / (double)iSample ) ) ); | |
1777 | } | |
1778 | ||
1779 | double Csock::GetAvgWrite( unsigned long long iSample ) | |
1780 | { | |
1781 | unsigned long long iDifference = ( millitime() - m_iStartTime ); | |
1782 | ||
1783 | if ( ( m_iBytesWritten == 0 ) || ( iSample > iDifference ) ) | |
1784 | return( (double)m_iBytesWritten ); | |
1785 | ||
1786 | return( ( (double)m_iBytesWritten / ( (double)iDifference / (double)iSample ) ) ); | |
1787 | } | |
1788 | ||
6dbb196e | 1789 | u_short Csock::GetRemotePort() |
8a769a6f | 1790 | { |
1791 | if ( m_iRemotePort > 0 ) | |
1792 | return( m_iRemotePort ); | |
1793 | ||
c7546c0c | 1794 | cs_sock_t iSock = GetSock(); |
8a769a6f | 1795 | |
c7546c0c | 1796 | if ( iSock != CS_INVALID_SOCK ) |
8a769a6f | 1797 | { |
487b6b65 | 1798 | if( !GetIPv6() ) |
1799 | { | |
1800 | struct sockaddr_in mAddr; | |
1801 | socklen_t mLen = sizeof( mAddr ); | |
1802 | if ( getpeername( iSock, (struct sockaddr *) &mAddr, &mLen ) == 0 ) | |
1803 | m_iRemotePort = ntohs( mAddr.sin_port ); | |
1804 | } | |
1805 | #ifdef HAVE_IPV6 | |
1806 | else | |
1807 | { | |
1808 | struct sockaddr_in6 mAddr; | |
1809 | socklen_t mLen = sizeof( mAddr ); | |
1810 | if ( getpeername( iSock, (struct sockaddr *) &mAddr, &mLen ) == 0 ) | |
1811 | m_iRemotePort = ntohs( mAddr.sin6_port ); | |
1812 | } | |
1813 | #endif /* HAVE_IPV6 */ | |
8a769a6f | 1814 | } |
1815 | ||
1816 | return( m_iRemotePort ); | |
1817 | } | |
1818 | ||
6dbb196e | 1819 | u_short Csock::GetLocalPort() |
8a769a6f | 1820 | { |
1821 | if ( m_iLocalPort > 0 ) | |
1822 | return( m_iLocalPort ); | |
1823 | ||
c7546c0c | 1824 | cs_sock_t iSock = GetSock(); |
8a769a6f | 1825 | |
c7546c0c | 1826 | if ( iSock != CS_INVALID_SOCK ) |
8a769a6f | 1827 | { |
487b6b65 | 1828 | if( !GetIPv6() ) |
1829 | { | |
1830 | struct sockaddr_in mLocalAddr; | |
9bb57639 | 1831 | socklen_t mLocalLen = sizeof( mLocalAddr ); |
487b6b65 | 1832 | if ( getsockname( iSock, (struct sockaddr *) &mLocalAddr, &mLocalLen ) == 0 ) |
1833 | m_iLocalPort = ntohs( mLocalAddr.sin_port ); | |
1834 | } | |
1835 | #ifdef HAVE_IPV6 | |
1836 | else | |
1837 | { | |
1838 | struct sockaddr_in6 mLocalAddr; | |
9bb57639 | 1839 | socklen_t mLocalLen = sizeof( mLocalAddr ); |
487b6b65 | 1840 | if ( getsockname( iSock, (struct sockaddr *) &mLocalAddr, &mLocalLen ) == 0 ) |
1841 | m_iLocalPort = ntohs( mLocalAddr.sin6_port ); | |
1842 | } | |
1843 | #endif /* HAVE_IPV6 */ | |
8a769a6f | 1844 | } |
1845 | ||
1846 | return( m_iLocalPort ); | |
1847 | } | |
1848 | ||
25ef3439 | 1849 | u_short Csock::GetPort() { return( m_uPort ); } |
1850 | void Csock::SetPort( u_short iPort ) { m_uPort = iPort; } | |
e41a7f46 | 1851 | void Csock::Close( ECloseType eCloseType ) |
be3edeee | 1852 | { |
e41a7f46 | 1853 | m_eCloseType = eCloseType; |
1854 | } | |
8a769a6f | 1855 | void Csock::BlockIO( bool bBLOCK ) { m_bBLOCK = bBLOCK; } |
1856 | ||
1857 | void Csock::NonBlockingIO() | |
1858 | { | |
c6664d5a | 1859 | set_non_blocking( m_iReadSock ); |
8a769a6f | 1860 | |
1861 | if ( m_iReadSock != m_iWriteSock ) | |
1862 | { | |
c6664d5a | 1863 | set_non_blocking( m_iWriteSock ); |
8a769a6f | 1864 | } |
1865 | ||
1866 | BlockIO( false ); | |
1867 | } | |
1868 | ||
8a769a6f | 1869 | bool Csock::GetSSL() { return( m_bssl ); } |
1870 | void Csock::SetSSL( bool b ) { m_bssl = b; } | |
1871 | ||
1872 | #ifdef HAVE_LIBSSL | |
1873 | void Csock::SetCipher( const CS_STRING & sCipher ) { m_sCipherType = sCipher; } | |
1874 | const CS_STRING & Csock::GetCipher() { return( m_sCipherType ); } | |
1875 | void Csock::SetPemLocation( const CS_STRING & sPemFile ) { m_sPemFile = sPemFile; } | |
1876 | const CS_STRING & Csock::GetPemLocation() { return( m_sPemFile ); } | |
1877 | void Csock::SetPemPass( const CS_STRING & sPassword ) { m_sPemPass = sPassword; } | |
1878 | const CS_STRING & Csock::GetPemPass() const { return( m_sPemPass ); } | |
1879 | ||
1880 | int Csock::PemPassCB( char *buf, int size, int rwflag, void *pcSocket ) | |
1881 | { | |
1882 | Csock *pSock = (Csock *)pcSocket; | |
1883 | const CS_STRING & sPassword = pSock->GetPemPass(); | |
1884 | memset( buf, '\0', size ); | |
1885 | strncpy( buf, sPassword.c_str(), size ); | |
1886 | buf[size-1] = '\0'; | |
c7546c0c | 1887 | return( (int)strlen( buf ) ); |
8a769a6f | 1888 | } |
1889 | ||
1890 | int Csock::CertVerifyCB( int preverify_ok, X509_STORE_CTX *x509_ctx ) | |
1891 | { | |
b63b7d03 | 1892 | /* |
1893 | * A small quick example on how to get ahold of the Csock in the data portion of x509_ctx | |
1894 | Csock *pSock = GetCsockFromCTX( x509_ctx ); | |
1895 | assert( pSock ); | |
1896 | cerr << pSock->GetRemoteIP() << endl; | |
1897 | */ | |
1898 | ||
8a769a6f | 1899 | /* return 1 always for now, probably want to add some code for cert verification */ |
1900 | return( 1 ); | |
1901 | } | |
1902 | ||
8a769a6f | 1903 | void Csock::SetSSLMethod( int iMethod ) { m_iMethod = iMethod; } |
1904 | int Csock::GetSSLMethod() { return( m_iMethod ); } | |
1905 | void Csock::SetSSLObject( SSL *ssl ) { m_ssl = ssl; } | |
1906 | void Csock::SetCTXObject( SSL_CTX *sslCtx ) { m_ssl_ctx = sslCtx; } | |
8a769a6f | 1907 | |
79aaf3d5 | 1908 | SSL_SESSION * Csock::GetSSLSession() |
8a769a6f | 1909 | { |
79aaf3d5 | 1910 | if ( m_ssl ) |
1911 | return( SSL_get_session( m_ssl ) ); | |
8a769a6f | 1912 | |
1913 | return( NULL ); | |
1914 | } | |
1915 | #endif /* HAVE_LIBSSL */ | |
1916 | ||
1917 | const CS_STRING & Csock::GetWriteBuffer() { return( m_sSend ); } | |
1918 | void Csock::ClearWriteBuffer() { m_sSend.clear(); } | |
8a769a6f | 1919 | bool Csock::SslIsEstablished() { return ( m_bsslEstablished ); } |
1920 | ||
1921 | bool Csock::ConnectInetd( bool bIsSSL, const CS_STRING & sHostname ) | |
1922 | { | |
1923 | if ( !sHostname.empty() ) | |
1924 | m_sSockName = sHostname; | |
1925 | ||
1926 | // set our hostname | |
1927 | if ( m_sSockName.empty() ) | |
1928 | { | |
1929 | struct sockaddr_in client; | |
1930 | socklen_t clen = sizeof( client ); | |
1931 | if ( getpeername( 0, (struct sockaddr *)&client, &clen ) < 0 ) | |
1932 | m_sSockName = "0.0.0.0:0"; | |
1933 | else | |
1934 | { | |
1935 | stringstream s; | |
1936 | s << inet_ntoa( client.sin_addr ) << ":" << ntohs( client.sin_port ); | |
1937 | m_sSockName = s.str(); | |
1938 | } | |
1939 | } | |
1940 | ||
1941 | return( ConnectFD( 0, 1, m_sSockName, bIsSSL, INBOUND ) ); | |
1942 | } | |
1943 | ||
1944 | bool Csock::ConnectFD( int iReadFD, int iWriteFD, const CS_STRING & sName, bool bIsSSL, ETConn eDirection ) | |
1945 | { | |
1946 | if ( eDirection == LISTENER ) | |
1947 | { | |
1948 | CS_DEBUG( "You can not use a LISTENER type here!" ); | |
1949 | return( false ); | |
1950 | } | |
1951 | ||
1952 | // set our socket type | |
1953 | SetType( eDirection ); | |
1954 | ||
1955 | // set the hostname | |
1956 | m_sSockName = sName; | |
1957 | ||
1958 | // set the file descriptors | |
1959 | SetRSock( iReadFD ); | |
1960 | SetWSock( iWriteFD ); | |
1961 | ||
1962 | // set it up as non-blocking io | |
1963 | NonBlockingIO(); | |
1964 | ||
1965 | if ( bIsSSL ) | |
1966 | { | |
1967 | if ( ( eDirection == INBOUND ) && ( !AcceptSSL() ) ) | |
1968 | return( false ); | |
1969 | else if ( ( eDirection == OUTBOUND ) && ( !ConnectSSL() ) ) | |
1970 | return( false ); | |
1971 | } | |
1972 | ||
1973 | return( true ); | |
1974 | } | |
1975 | ||
1976 | #ifdef HAVE_LIBSSL | |
1977 | X509 *Csock::getX509() | |
1978 | { | |
1979 | if ( m_ssl ) | |
1980 | return( SSL_get_peer_certificate( m_ssl ) ); | |
1981 | ||
1982 | return( NULL ); | |
1983 | } | |
1984 | ||
1985 | CS_STRING Csock::GetPeerPubKey() | |
1986 | { | |
1987 | CS_STRING sKey; | |
1988 | ||
dba60545 A |
1989 | X509 *pCert = getX509(); |
1990 | if( pCert ) | |
8a769a6f | 1991 | { |
dba60545 A |
1992 | EVP_PKEY * pKey = X509_get_pubkey( pCert ); |
1993 | if( pKey ) | |
8a769a6f | 1994 | { |
dba60545 A |
1995 | const BIGNUM * pPubKey = NULL; |
1996 | int iType = EVP_PKEY_base_id( pKey ); | |
1997 | switch( iType ) | |
8a769a6f | 1998 | { |
dba60545 A |
1999 | #ifndef OPENSSL_NO_RSA |
2000 | case EVP_PKEY_RSA: | |
2001 | RSA_get0_key( EVP_PKEY_get0_RSA( pKey ), &pPubKey, NULL, NULL ); | |
2002 | break; | |
2003 | #endif /* OPENSSL_NO_RSA */ | |
2004 | #ifndef OPENSSL_NO_DSA | |
2005 | case EVP_PKEY_DSA: | |
2006 | DSA_get0_key( EVP_PKEY_get0_DSA( pKey ), &pPubKey, NULL ); | |
2007 | break; | |
2008 | #endif /* OPENSSL_NO_DSA */ | |
2009 | default: | |
2010 | CS_DEBUG( "Not Prepared for Public Key Type [" << iType << "]" ); | |
2011 | break; | |
8a769a6f | 2012 | } |
dba60545 | 2013 | if( pPubKey ) |
8a769a6f | 2014 | { |
dba60545 | 2015 | char *hxKey = BN_bn2hex( pPubKey ); |
8a769a6f | 2016 | sKey = hxKey; |
2017 | OPENSSL_free( hxKey ); | |
2018 | } | |
2019 | EVP_PKEY_free( pKey ); | |
2020 | } | |
dba60545 | 2021 | X509_free( pCert ); |
79aaf3d5 | 2022 | } |
8a769a6f | 2023 | return( sKey ); |
2024 | } | |
dba60545 | 2025 | |
e77adef0 | 2026 | int Csock::GetPeerFingerprint( CS_STRING & sFP ) |
2027 | { | |
2028 | sFP.clear(); | |
2029 | ||
2030 | if ( !GetSSL() ) | |
2031 | return 0; | |
2032 | ||
2033 | X509* pCert = getX509(); | |
2034 | ||
dba60545 A |
2035 | unsigned char sha1_hash[SHA_DIGEST_LENGTH]; |
2036 | ||
2037 | if( pCert && X509_digest( pCert, EVP_sha1(), sha1_hash, NULL ) ) | |
e77adef0 | 2038 | { |
2039 | for (int i = 0; i < SHA_DIGEST_LENGTH; i++) | |
2040 | { | |
2041 | char buf[3]; | |
dba60545 | 2042 | snprintf(buf, 3, "%02x", sha1_hash[i]); |
e77adef0 | 2043 | sFP += buf; |
2044 | } | |
e77adef0 | 2045 | } |
dba60545 | 2046 | X509_free(pCert); |
e77adef0 | 2047 | |
2048 | return SSL_get_verify_result(m_ssl); | |
2049 | } | |
37d0c5e5 | 2050 | unsigned int Csock::GetRequireClientCertFlags() { return( m_iRequireClientCertFlags ); } |
2051 | void Csock::SetRequiresClientCert( bool bRequiresCert ) { m_iRequireClientCertFlags = ( bRequiresCert ? SSL_VERIFY_FAIL_IF_NO_PEER_CERT|SSL_VERIFY_PEER : 0 ); } | |
8a769a6f | 2052 | |
2053 | #endif /* HAVE_LIBSSL */ | |
2054 | ||
2055 | void Csock::SetParentSockName( const CS_STRING & sParentName ) { m_sParentName = sParentName; } | |
2056 | const CS_STRING & Csock::GetParentSockName() { return( m_sParentName ); } | |
2057 | ||
2058 | void Csock::SetRate( u_int iBytes, unsigned long long iMilliseconds ) | |
2059 | { | |
2060 | m_iMaxBytes = iBytes; | |
2061 | m_iMaxMilliSeconds = iMilliseconds; | |
2062 | } | |
2063 | ||
2064 | u_int Csock::GetRateBytes() { return( m_iMaxBytes ); } | |
2065 | unsigned long long Csock::GetRateTime() { return( m_iMaxMilliSeconds ); } | |
2066 | ||
2067 | void Csock::Cron() | |
2068 | { | |
2bbdb72a | 2069 | time_t iNow = 0; |
2070 | ||
8a769a6f | 2071 | for( vector<CCron *>::size_type a = 0; a < m_vcCrons.size(); a++ ) |
79aaf3d5 | 2072 | { |
8a769a6f | 2073 | CCron *pcCron = m_vcCrons[a]; |
2074 | ||
2075 | if ( !pcCron->isValid() ) | |
2076 | { | |
2077 | CS_Delete( pcCron ); | |
2078 | m_vcCrons.erase( m_vcCrons.begin() + a-- ); | |
2079 | } else | |
30cf3a30 | 2080 | pcCron->run( iNow ); |
8a769a6f | 2081 | } |
2082 | } | |
2083 | ||
8a769a6f | 2084 | void Csock::AddCron( CCron * pcCron ) |
2085 | { | |
2086 | m_vcCrons.push_back( pcCron ); | |
2087 | } | |
2088 | ||
8a769a6f | 2089 | void Csock::DelCron( const CS_STRING & sName, bool bDeleteAll, bool bCaseSensitive ) |
2090 | { | |
2091 | for( u_int a = 0; a < m_vcCrons.size(); a++ ) | |
2092 | { | |
2093 | int (*Cmp)(const char *, const char *) = ( bCaseSensitive ? strcmp : strcasecmp ); | |
2094 | if ( Cmp( m_vcCrons[a]->GetName().c_str(), sName.c_str() ) == 0 ) | |
2095 | { | |
2096 | m_vcCrons[a]->Stop(); | |
2097 | CS_Delete( m_vcCrons[a] ); | |
2098 | m_vcCrons.erase( m_vcCrons.begin() + a-- ); | |
b63b7d03 | 2099 | if( !bDeleteAll ) |
2100 | break; | |
8a769a6f | 2101 | } |
2102 | } | |
2103 | } | |
2104 | ||
8a769a6f | 2105 | void Csock::DelCron( u_int iPos ) |
2106 | { | |
2107 | if ( iPos < m_vcCrons.size() ) | |
2108 | { | |
2109 | m_vcCrons[iPos]->Stop(); | |
2110 | CS_Delete( m_vcCrons[iPos] ); | |
2111 | m_vcCrons.erase( m_vcCrons.begin() + iPos ); | |
2112 | } | |
2113 | } | |
ed120ee5 | 2114 | |
8a769a6f | 2115 | void Csock::DelCronByAddr( CCron *pcCron ) |
2116 | { | |
2117 | for( u_int a = 0; a < m_vcCrons.size(); a++ ) | |
2118 | { | |
2119 | if ( m_vcCrons[a] == pcCron ) | |
2120 | { | |
2121 | m_vcCrons[a]->Stop(); | |
2122 | CS_Delete( m_vcCrons[a] ); | |
2123 | m_vcCrons.erase( m_vcCrons.begin() + a ); | |
2124 | return; | |
2125 | } | |
2126 | } | |
2127 | } | |
2128 | ||
2129 | void Csock::EnableReadLine() { m_bEnableReadLine = true; } | |
2809dd11 | 2130 | void Csock::DisableReadLine() { |
2131 | m_bEnableReadLine = false; | |
2132 | m_sbuffer.clear(); | |
2133 | } | |
8a769a6f | 2134 | |
2135 | void Csock::ReachedMaxBuffer() | |
2136 | { | |
2d1602ec | 2137 | std::cerr << "Warning, Max Buffer length Warning Threshold has been hit" << endl; |
2138 | std::cerr << "If you don't care, then set SetMaxBufferThreshold to 0" << endl; | |
8a769a6f | 2139 | } |
2140 | ||
2141 | int Csock::GetPending() | |
2142 | { | |
2143 | #ifdef HAVE_LIBSSL | |
2144 | if( m_ssl ) | |
9f7c0db4 | 2145 | { |
2146 | // in v23 method, the pending function is initialized to ssl_undefined_const_function | |
2147 | // which throws SSL_UNDEFINED_CONST_FUNCTION on to the error stack | |
2148 | // this is one of the more stupid things in openssl, it seems bizarre that even though SSL_pending | |
2149 | // returns an int, they don't bother returning in error to notify us, so basically | |
2150 | // we have to always clear errors here generated by SSL_pending, otherwise the stack could | |
2151 | // have a lame error on it causing SSL_write to fail in certain instances. | |
94479f39 | 2152 | #if defined( OPENSSL_VERSION_NUMBER ) && OPENSSL_VERSION_NUMBER >= 0x00908000 |
9f7c0db4 | 2153 | ERR_set_mark(); |
2154 | int iBytes = SSL_pending( m_ssl ); | |
2155 | ERR_pop_to_mark(); | |
2156 | return( iBytes ); | |
88e7f093 | 2157 | #else |
558e2779 | 2158 | int iBytes = SSL_pending( m_ssl ); |
2159 | ERR_clear_error(); // to get safer handling, upgrade your openssl version! | |
635fb4bc | 2160 | return( iBytes ); |
558e2779 | 2161 | #endif /* OPENSSL_VERSION_NUMBER */ |
9f7c0db4 | 2162 | } |
8a769a6f | 2163 | else |
2164 | return( 0 ); | |
2165 | #else | |
2166 | return( 0 ); | |
2167 | #endif /* HAVE_LIBSSL */ | |
2168 | } | |
2169 | ||
6faf0980 | 2170 | int Csock::GetAddrInfo( const CS_STRING & sHostname, CSSockAddr & csSockAddr ) |
2171 | { | |
6ce29e77 | 2172 | #ifdef HAVE_IPV6 |
2173 | if( csSockAddr.GetAFRequire() != AF_INET && inet_pton( AF_INET6, sHostname.c_str(), csSockAddr.GetAddr6() ) > 0 ) | |
2174 | { | |
2175 | SetIPv6( true ); | |
2176 | return( 0 ); | |
2177 | } | |
2178 | #endif /* HAVE_IPV6 */ | |
2179 | if( inet_pton( AF_INET, sHostname.c_str(), csSockAddr.GetAddr() ) > 0 ) | |
2180 | { | |
2181 | #ifdef HAVE_IPV6 | |
2182 | SetIPv6( false ); | |
2183 | #endif /* HAVE_IPV6 */ | |
2184 | return( 0 ); | |
2185 | } | |
2186 | ||
2187 | #ifdef HAVE_C_ARES | |
2188 | if( GetType() != LISTENER ) | |
2189 | { // right now the current function in Listen() is it blocks, the easy way around this at the moment is to use ip | |
f1515361 | 2190 | // need to compute this up here |
6ce29e77 | 2191 | if( !m_pARESChannel ) |
2192 | { | |
2193 | if( ares_init( &m_pARESChannel ) != ARES_SUCCESS ) | |
2194 | { // TODO throw some debug? | |
2195 | FreeAres(); | |
2196 | return( ETIMEDOUT ); | |
2197 | } | |
2198 | m_pCurrAddr = &csSockAddr; // flag its starting | |
6ce29e77 | 2199 | |
e566a535 | 2200 | int iFamily = AF_INET; |
6ce29e77 | 2201 | #ifdef HAVE_IPV6 |
25ef3439 | 2202 | // as of ares 1.6.0 if it fails on af_inet6, it falls back to af_inet, this code was here in the previous Csocket version, just adding the comment as a reminder |
e566a535 | 2203 | iFamily = csSockAddr.GetAFRequire() == CSSockAddr::RAF_ANY ? AF_INET6 : csSockAddr.GetAFRequire(); |
6ce29e77 | 2204 | #endif /* HAVE_IPV6 */ |
2205 | ares_gethostbyname( m_pARESChannel, sHostname.c_str(), iFamily, AresHostCallback, this ); | |
2206 | } | |
2207 | if( !m_pCurrAddr ) | |
2208 | { // this means its finished | |
2209 | FreeAres(); | |
f1515361 | 2210 | #ifdef HAVE_IPV6 |
ca1e8d43 | 2211 | if( m_iARESStatus == ARES_SUCCESS && csSockAddr.GetAFRequire() == CSSockAddr::RAF_ANY && GetIPv6() ) |
2212 | { | |
2213 | // this means that ares_host returned an ipv6 host, so try a connect right away | |
2214 | if( CreateSocksFD() && Connect( GetBindHost(), true ) ) | |
2215 | { | |
2216 | SetSkipConnect( true ); | |
2217 | } | |
2218 | else if( GetSockError() == ENETUNREACH ) | |
2219 | { | |
2220 | // the Connect() failed, so throw a retry back in with ipv4, and let it process normally | |
2221 | CS_DEBUG( "Failed ipv6 connection with PF_UNSPEC, falling back to ipv4" ); | |
2222 | m_iARESStatus = -1; | |
ebbc126b | 2223 | CloseSocksFD(); |
ca1e8d43 | 2224 | SetAFRequire( CSSockAddr::RAF_INET ); |
2225 | return( GetAddrInfo( sHostname, csSockAddr ) ); | |
2226 | } | |
2227 | } | |
f1515361 | 2228 | #if ARES_VERSION < CREATE_ARES_VER( 1, 5, 3 ) |
e566a535 | 2229 | if( m_iARESStatus != ARES_SUCCESS && csSockAddr.GetAFRequire() == CSSockAddr::RAF_ANY ) |
f1515361 | 2230 | { // this is a workaround for ares < 1.5.3 where the builtin retry on failed AF_INET6 isn't there yet |
2231 | CS_DEBUG( "Retry for older version of c-ares with AF_INET only" ); | |
2232 | // this means we tried previously with AF_INET6 and failed, so force AF_INET and retry | |
2233 | SetAFRequire( CSSockAddr::RAF_INET ); | |
2234 | return( GetAddrInfo( sHostname, csSockAddr ) ); | |
2235 | } | |
2236 | #endif /* ARES_VERSION < CREATE_ARES_VER( 1, 5, 3 ) */ | |
2237 | #endif /* HAVE_IPV6 */ | |
6ce29e77 | 2238 | return( m_iARESStatus == ARES_SUCCESS ? 0 : ETIMEDOUT ); |
2239 | } | |
2240 | return( EAGAIN ); | |
2241 | } | |
2242 | #endif /* HAVE_C_ARES */ | |
2243 | ||
6faf0980 | 2244 | return( ::GetAddrInfo( sHostname, this, csSockAddr ) ); |
2245 | } | |
2246 | ||
6dbb196e | 2247 | int Csock::DNSLookup( EDNSLType eDNSLType ) |
2248 | { | |
2249 | if ( eDNSLType == DNS_VHOST ) | |
2250 | { | |
2251 | if ( m_sBindHost.empty() ) | |
2252 | { | |
2253 | if ( m_eConState != CST_OK ) | |
493d5154 | 2254 | m_eConState = CST_DESTDNS; // skip binding, there is no vhost |
6dbb196e | 2255 | return( 0 ); |
2256 | } | |
2257 | ||
487b6b65 | 2258 | m_bindhost.SinFamily(); |
2259 | m_bindhost.SinPort( 0 ); | |
6dbb196e | 2260 | } |
2261 | ||
fd90be44 | 2262 | int iRet = ETIMEDOUT; |
6dbb196e | 2263 | if ( eDNSLType == DNS_VHOST ) |
487b6b65 | 2264 | { |
6faf0980 | 2265 | iRet = GetAddrInfo( m_sBindHost, m_bindhost ); |
b5e6518f | 2266 | #ifdef HAVE_IPV6 |
2267 | if( m_bindhost.GetIPv6() ) | |
2268 | { | |
2269 | SetAFRequire( CSSockAddr::RAF_INET6 ); | |
2270 | } | |
2271 | else | |
2272 | { | |
2273 | SetAFRequire( CSSockAddr::RAF_INET ); | |
2274 | } | |
2275 | #endif /* HAVE_IPV6 */ | |
487b6b65 | 2276 | } |
6dbb196e | 2277 | else |
487b6b65 | 2278 | { |
6faf0980 | 2279 | iRet = GetAddrInfo( m_shostname, m_address ); |
487b6b65 | 2280 | } |
6dbb196e | 2281 | |
2282 | if ( iRet == 0 ) | |
2283 | { | |
4c14b1bf | 2284 | if( !CreateSocksFD() ) |
2285 | { | |
2286 | m_iDNSTryCount = 0; | |
9bb57639 | 2287 | return( ETIMEDOUT ); |
4c14b1bf | 2288 | } |
6dbb196e | 2289 | if ( m_eConState != CST_OK ) |
fc191e49 | 2290 | m_eConState = ( ( eDNSLType == DNS_VHOST ) ? CST_BINDVHOST : CST_CONNECT ); |
6dbb196e | 2291 | m_iDNSTryCount = 0; |
2292 | return( 0 ); | |
2293 | } | |
6faf0980 | 2294 | else if ( iRet == EAGAIN ) |
6dbb196e | 2295 | { |
25ef3439 | 2296 | #ifndef HAVE_C_ARES |
6dbb196e | 2297 | m_iDNSTryCount++; |
2298 | if ( m_iDNSTryCount > 20 ) | |
2299 | { | |
2300 | m_iDNSTryCount = 0; | |
2301 | return( ETIMEDOUT ); | |
2302 | } | |
25ef3439 | 2303 | #endif /* HAVE_C_ARES */ |
6dbb196e | 2304 | return( EAGAIN ); |
2305 | } | |
2306 | m_iDNSTryCount = 0; | |
2307 | return( ETIMEDOUT ); | |
6dbb196e | 2308 | } |
2309 | ||
2310 | bool Csock::SetupVHost() | |
2311 | { | |
2312 | if ( m_sBindHost.empty() ) | |
2313 | { | |
2314 | if ( m_eConState != CST_OK ) | |
493d5154 | 2315 | m_eConState = CST_DESTDNS; |
6dbb196e | 2316 | return( true ); |
2317 | } | |
12ed0475 | 2318 | int iRet = -1; |
2319 | if( !GetIPv6() ) | |
2320 | iRet = bind( m_iReadSock, (struct sockaddr *) m_bindhost.GetSockAddr(), m_bindhost.GetSockAddrLen() ); | |
2321 | #ifdef HAVE_IPV6 | |
2322 | else | |
2323 | iRet = bind( m_iReadSock, (struct sockaddr *) m_bindhost.GetSockAddr6(), m_bindhost.GetSockAddrLen6() ); | |
2324 | #endif /* HAVE_IPV6 */ | |
2325 | ||
2326 | if ( iRet == 0 ) | |
6dbb196e | 2327 | { |
2328 | if ( m_eConState != CST_OK ) | |
493d5154 | 2329 | m_eConState = CST_DESTDNS; |
6dbb196e | 2330 | return( true ); |
2331 | } | |
2332 | m_iCurBindCount++; | |
2333 | if ( m_iCurBindCount > 3 ) | |
2334 | { | |
2335 | CS_DEBUG( "Failure to bind to " << m_sBindHost ); | |
2336 | return( false ); | |
2337 | } | |
2338 | ||
2339 | return( true ); | |
2340 | } | |
2341 | ||
8a769a6f | 2342 | #ifdef HAVE_LIBSSL |
2343 | void Csock::FREE_SSL() | |
2344 | { | |
2345 | if ( m_ssl ) | |
2346 | { | |
2347 | SSL_shutdown( m_ssl ); | |
2348 | SSL_free( m_ssl ); | |
2349 | } | |
2350 | m_ssl = NULL; | |
2351 | } | |
2352 | ||
2353 | void Csock::FREE_CTX() | |
2354 | { | |
2355 | if ( m_ssl_ctx ) | |
2356 | SSL_CTX_free( m_ssl_ctx ); | |
2357 | ||
2358 | m_ssl_ctx = NULL; | |
2359 | } | |
2360 | ||
2361 | #endif /* HAVE_LIBSSL */ | |
2362 | ||
25ef3439 | 2363 | cs_sock_t Csock::CreateSocket( bool bListen ) |
8a769a6f | 2364 | { |
ed120ee5 | 2365 | #ifdef HAVE_IPV6 |
25ef3439 | 2366 | cs_sock_t iRet = socket( ( GetIPv6() ? PF_INET6 : PF_INET ), SOCK_STREAM, IPPROTO_TCP ); |
ed120ee5 | 2367 | #else |
25ef3439 | 2368 | cs_sock_t iRet = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ); |
ed120ee5 | 2369 | #endif /* HAVE_IPV6 */ |
2370 | ||
88e7f093 | 2371 | if ( iRet != CS_INVALID_SOCK ) |
f5ede26c | 2372 | { |
c6664d5a | 2373 | set_close_on_exec( iRet ); |
8a769a6f | 2374 | |
88e7f093 | 2375 | if ( bListen ) |
f5ede26c | 2376 | { |
c6664d5a | 2377 | const int on = 1; |
8a769a6f | 2378 | |
f5ede26c | 2379 | if ( setsockopt( iRet, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof( on ) ) != 0 ) |
2380 | PERROR( "SO_REUSEADDR" ); | |
c6664d5a | 2381 | } |
88e7f093 | 2382 | } |
f5ede26c | 2383 | else |
8a769a6f | 2384 | PERROR( "socket" ); |
2385 | ||
2386 | return( iRet ); | |
2387 | } | |
2388 | ||
6ce29e77 | 2389 | void Csock::Init( const CS_STRING & sHostname, u_short uPort, int itimeout ) |
8a769a6f | 2390 | { |
79aaf3d5 | 2391 | #ifdef HAVE_LIBSSL |
8a769a6f | 2392 | m_ssl = NULL; |
2393 | m_ssl_ctx = NULL; | |
37d0c5e5 | 2394 | m_iRequireClientCertFlags = 0; |
79aaf3d5 | 2395 | #endif /* HAVE_LIBSSL */ |
b63b7d03 | 2396 | m_iTcount = 0; |
25ef3439 | 2397 | m_iReadSock = CS_INVALID_SOCK; |
2398 | m_iWriteSock = CS_INVALID_SOCK; | |
8a769a6f | 2399 | m_itimeout = itimeout; |
2400 | m_bssl = false; | |
2401 | m_bIsConnected = false; | |
25ef3439 | 2402 | m_uPort = uPort; |
8a769a6f | 2403 | m_shostname = sHostname; |
8a769a6f | 2404 | m_sbuffer.clear(); |
e41a7f46 | 2405 | m_eCloseType = CLT_DONT; |
8a769a6f | 2406 | m_bBLOCK = true; |
2407 | m_iMethod = SSL23; | |
2408 | m_sCipherType = "ALL"; | |
2409 | m_iMaxBytes = 0; | |
2410 | m_iMaxMilliSeconds = 0; | |
2411 | m_iLastSendTime = 0; | |
2412 | m_iLastSend = 0; | |
8a769a6f | 2413 | m_bsslEstablished = false; |
2414 | m_bEnableReadLine = false; | |
8a769a6f | 2415 | m_iMaxStoredBufferLength = 1024; |
2416 | m_iConnType = INBOUND; | |
2417 | m_iRemotePort = 0; | |
2418 | m_iLocalPort = 0; | |
2419 | m_iBytesRead = 0; | |
2420 | m_iBytesWritten = 0; | |
2421 | m_iStartTime = millitime(); | |
2422 | m_bPauseRead = false; | |
2423 | m_iTimeoutType = TMO_ALL; | |
6dbb196e | 2424 | m_eConState = CST_OK; // default should be ok |
2425 | m_iDNSTryCount = 0; | |
2426 | m_iCurBindCount = 0; | |
487b6b65 | 2427 | m_bIsIPv6 = false; |
493d5154 | 2428 | m_bSkipConnect = false; |
b63b7d03 | 2429 | m_iLastCheckTimeoutTime = 0; |
6ce29e77 | 2430 | #ifdef HAVE_C_ARES |
2431 | m_pARESChannel = NULL; | |
2432 | m_pCurrAddr = NULL; | |
2433 | m_iARESStatus = -1; | |
2434 | #endif /* HAVE_C_ARES */ | |
8a769a6f | 2435 | } |
2d1602ec | 2436 |