1 /** \file TcpSocket.cpp
3 ** \author grymse@alhem.net
6 Copyright (C) 2004-2007 Anders Hedstrom
8 This library is made available under the terms of the GNU GPL.
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.
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.
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.
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.
32 #pragma warning(disable:4786)
38 #include "ISocketHandler.h"
43 #include <openssl/rand.h>
44 #include <openssl/err.h>
47 #include "TcpSocket.h"
49 #include "Ipv4Address.h"
50 #include "Ipv6Address.h"
54 #ifdef SOCKETS_NAMESPACE
55 namespace SOCKETS_NAMESPACE
{
68 SSLInitializer
TcpSocket::m_ssl_init
;
74 #pragma warning(disable:4355)
76 TcpSocket::TcpSocket(ISocketHandler
& h
) : StreamSocket(h
)
77 ,ibuf(TCP_BUFSIZE_READ
)
78 ,m_b_input_buffer_disabled(false)
82 #ifdef SOCKETS_DYNAMIC_TEMP
83 ,m_buf(new char[TCP_BUFSIZE_READ
+ 1])
96 #ifdef ENABLE_RESOLVER
99 #ifdef ENABLE_RECONNECT
100 ,m_b_reconnect(false)
101 ,m_b_is_reconnect(false)
106 #pragma warning(default:4355)
111 #pragma warning(disable:4355)
113 TcpSocket::TcpSocket(ISocketHandler
& h
,size_t isize
,size_t osize
) : StreamSocket(h
)
115 ,m_b_input_buffer_disabled(false)
119 #ifdef SOCKETS_DYNAMIC_TEMP
120 ,m_buf(new char[TCP_BUFSIZE_READ
+ 1])
133 #ifdef ENABLE_RESOLVER
136 #ifdef ENABLE_RECONNECT
137 ,m_b_reconnect(false)
138 ,m_b_is_reconnect(false)
143 #pragma warning(default:4355)
147 TcpSocket::~TcpSocket()
149 #ifdef SOCKETS_DYNAMIC_TEMP
162 bool TcpSocket::Open(ipaddr_t ip
,port_t port
,bool skip_socks
)
164 Ipv4Address
ad(ip
, port
);
166 return Open(ad
, local
, skip_socks
);
172 bool TcpSocket::Open(in6_addr ip
,port_t port
,bool skip_socks
)
174 Ipv6Address
ad(ip
, port
);
175 return Open(ad
, skip_socks
);
181 bool TcpSocket::Open(SocketAddress
& ad
,bool skip_socks
)
183 Ipv4Address
bind_ad("0.0.0.0", 0);
184 return Open(ad
, bind_ad
, skip_socks
);
188 bool TcpSocket::Open(SocketAddress
& ad
,SocketAddress
& bind_ad
,bool skip_socks
)
192 Handler().LogError(this, "Open", 0, "Invalid SocketAddress", LOG_LEVEL_FATAL
);
196 if (Handler().GetCount() >= FD_SETSIZE
)
198 Handler().LogError(this, "Open", 0, "no space left in fd_set", LOG_LEVEL_FATAL
);
202 SetConnecting(false);
208 if (Handler().PoolEnabled())
210 ISocketHandler::PoolSocket
*pools
= Handler().FindConnection(SOCK_STREAM
, "tcp", ad
);
213 CopyConnection( pools
);
217 SetCallOnConnect(); // ISocketHandler must call OnConnect
218 Handler().LogError(this, "SetCallOnConnect", 0, "Found pooled connection", LOG_LEVEL_INFO
);
223 // if not, create new connection
224 SOCKET s
= CreateSocket(ad
.GetFamily(), SOCK_STREAM
, "tcp");
225 if (s
== INVALID_SOCKET
)
229 // socket must be nonblocking for async connect
230 if (!SetNonblocking(true, s
))
237 SetIsClient(); // client because we connect
239 SetClientRemoteAddress(ad
);
241 if (bind_ad
.GetPort() != 0)
243 bind(s
, bind_ad
, bind_ad
);
246 if (!skip_socks
&& GetSocks4Host() && GetSocks4Port())
248 Ipv4Address
sa(GetSocks4Host(), GetSocks4Port());
250 std::string sockshost
;
251 Utility::l2ip(GetSocks4Host(), sockshost
);
252 Handler().LogError(this, "Open", 0, "Connecting to socks4 server @ " + sockshost
+ ":" +
253 Utility::l2string(GetSocks4Port()), LOG_LEVEL_INFO
);
256 n
= connect(s
, sa
, sa
);
257 SetRemoteAddress(sa
);
262 n
= connect(s
, ad
, ad
);
263 SetRemoteAddress(ad
);
267 // check error code that means a connect is in progress
269 if (Errno
== WSAEWOULDBLOCK
)
271 if (Errno
== EINPROGRESS
)
275 SetConnecting( true ); // this flag will control fd_set's
279 if (Socks4() && Handler().Socks4TryDirect() ) // retry
282 return Open(ad
, true);
286 #ifdef ENABLE_RECONNECT
289 Handler().LogError(this, "connect: failed, reconnect pending", Errno
, StrError(Errno
), LOG_LEVEL_INFO
);
291 SetConnecting( true ); // this flag will control fd_set's
296 Handler().LogError(this, "connect: failed", Errno
, StrError(Errno
), LOG_LEVEL_FATAL
);
305 SetCallOnConnect(); // ISocketHandler must call OnConnect
308 // 'true' means connected or connecting(not yet connected)
309 // 'false' means something failed
310 return true; //!Connecting();
314 bool TcpSocket::Open(const std::string
&host
,port_t port
)
320 #ifdef ENABLE_RESOLVER
321 if (!Handler().ResolverEnabled() || Utility::isipv6(host
) )
325 if (!Utility::u2ip(host
, a
))
330 Ipv6Address
ad(a
, port
);
332 return Open(ad
, local
);
333 #ifdef ENABLE_RESOLVER
335 m_resolver_id
= Resolve6(host
, port
);
341 #ifdef ENABLE_RESOLVER
342 if (!Handler().ResolverEnabled() || Utility::isipv4(host
) )
346 if (!Utility::u2ip(host
,l
))
351 Ipv4Address
ad(l
, port
);
353 return Open(ad
, local
);
354 #ifdef ENABLE_RESOLVER
356 // resolve using async resolver thread
357 m_resolver_id
= Resolve(host
, port
);
363 #ifdef ENABLE_RESOLVER
364 void TcpSocket::OnResolved(int id
,ipaddr_t a
,port_t port
)
366 DEB( fprintf(stderr
, "TcpSocket::OnResolved id %d addr %x port %d\n", id
, a
, port
);)
367 if (id
== m_resolver_id
)
371 Ipv4Address
ad(a
, port
);
375 if (!Handler().Valid(this))
383 Handler().LogError(this, "OnResolved", 0, "Resolver failed", LOG_LEVEL_FATAL
);
389 Handler().LogError(this, "OnResolved", id
, "Resolver returned wrong job id", LOG_LEVEL_FATAL
);
396 void TcpSocket::OnResolved(int id
,in6_addr
& a
,port_t port
)
398 if (id
== m_resolver_id
)
400 Ipv6Address
ad(a
, port
);
406 if (!Handler().Valid(this))
415 Handler().LogError(this, "OnResolved", id
, "Resolver returned wrong job id", LOG_LEVEL_FATAL
);
423 void TcpSocket::OnRead()
426 #ifdef SOCKETS_DYNAMIC_TEMP
429 char buf
[TCP_BUFSIZE_READ
];
436 n
= SSL_read(m_ssl
, buf
, TCP_BUFSIZE_READ
);
439 n
= SSL_get_error(m_ssl
, n
);
443 case SSL_ERROR_WANT_READ
:
444 case SSL_ERROR_WANT_WRITE
:
446 case SSL_ERROR_ZERO_RETURN
:
447 DEB( fprintf(stderr
, "SSL_read() returns zero - closing socket\n");)
449 SetCloseAndDelete(true);
450 SetFlushBeforeClose(false);
456 DEB( fprintf(stderr
, "SSL read problem, errcode = %d\n",n
);)
458 SetCloseAndDelete(true);
459 SetFlushBeforeClose(false);
470 SetCloseAndDelete(true);
471 SetFlushBeforeClose(false);
475 SetShutdown(SHUT_WR
);
479 if (n
> 0 && n
<= TCP_BUFSIZE_READ
)
481 m_bytes_received
+= n
;
482 if (GetTrafficMonitor())
484 GetTrafficMonitor() -> fwrite(buf
, 1, n
);
486 if (!m_b_input_buffer_disabled
&& !ibuf
.Write(buf
,n
))
488 Handler().LogError(this, "OnRead(ssl)", 0, "ibuf overflow", LOG_LEVEL_WARNING
);
493 Handler().LogError(this, "OnRead(ssl)", n
, "abnormal value from SSL_read", LOG_LEVEL_ERROR
);
497 #endif // HAVE_OPENSSL
499 n
= recv(GetSocket(), buf
, TCP_BUFSIZE_READ
, MSG_NOSIGNAL
);
502 Handler().LogError(this, "read", Errno
, StrError(Errno
), LOG_LEVEL_FATAL
);
504 SetCloseAndDelete(true);
505 SetFlushBeforeClose(false);
515 SetCloseAndDelete(true);
516 SetFlushBeforeClose(false);
520 SetShutdown(SHUT_WR
);
524 if (n
> 0 && n
<= TCP_BUFSIZE_READ
)
526 m_bytes_received
+= n
;
527 if (GetTrafficMonitor())
529 GetTrafficMonitor() -> fwrite(buf
, 1, n
);
531 if (!m_b_input_buffer_disabled
&& !ibuf
.Write(buf
,n
))
533 Handler().LogError(this, "OnRead", 0, "ibuf overflow", LOG_LEVEL_WARNING
);
538 Handler().LogError(this, "OnRead", n
, "abnormal value from recv", LOG_LEVEL_ERROR
);
546 void TcpSocket::OnRead( char *buf
, size_t n
)
549 if (n
> 0 && n
<= TCP_BUFSIZE_READ
)
555 if (m_skip_c
&& (buf
[i
] == 13 || buf
[i
] == 10) && buf
[i
] != m_c
)
561 for (; i
< n
&& LineProtocol(); i
++)
563 while ((buf
[i
] == 13 || buf
[i
] == 10) && LineProtocol())
575 if (i
< n
&& (buf
[i
] == 13 || buf
[i
] == 10) && buf
[i
] != c
)
592 OnRawData(buf
+ i
, n
- i
);
606 if (m_b_input_buffer_disabled
)
610 // further processing: socks4
614 bool need_more
= false;
615 while (GetInputLength() && !need_more
&& !CloseAndDelete())
617 need_more
= OnSocks4Read();
624 void TcpSocket::OnWriteComplete()
629 void TcpSocket::OnWrite()
635 // don't reset connecting flag on error here, we want the OnConnectFailed timeout later on
638 Set(!IsDisableRead(), false);
639 SetConnecting(false);
643 Handler().LogError(this, "tcp: connect failed", err
, StrError(err
), LOG_LEVEL_FATAL
);
644 Set(false, false); // no more monitoring because connection failed
650 // %! leave 'Connecting' flag set?
651 OnSocks4ConnectFailed();
655 if (GetConnectionRetry() == -1 ||
656 (GetConnectionRetry() && GetConnectionRetries() < GetConnectionRetry()) )
658 // even though the connection failed at once, only retry after
659 // the connection timeout.
660 // should we even try to connect again, when CheckConnect returns
661 // false it's because of a connection error - not a timeout...
664 SetConnecting(false);
665 SetCloseAndDelete( true );
666 /// \todo state reason why connect failed
670 // try send next block in buffer
671 // if full block is sent, repeat
672 // if all blocks are sent, reset m_wfds
675 size_t sz
= m_transfer_limit
? GetOutputLength() : 0;
678 output_l::iterator it
= m_obuf
.begin();
681 int n
= TryWrite(p
-> Buf(), p
-> Len());
684 size_t left
= p
-> Remove(n
);
685 m_output_length
-= n
;
703 if (m_transfer_limit
&& sz
> m_transfer_limit
&& GetOutputLength() < m_transfer_limit
)
708 // check output buffer set, set/reset m_wfds accordingly
713 Handler().Get(GetSocket(), br
, bw
, bx
);
722 int TcpSocket::TryWrite(const char *buf
, size_t len
)
728 n
= SSL_write(m_ssl
, buf
, (int)len
);
731 int errnr
= SSL_get_error(m_ssl
, n
);
732 if ( errnr
!= SSL_ERROR_WANT_READ
&& errnr
!= SSL_ERROR_WANT_WRITE
)
735 SetCloseAndDelete(true);
736 SetFlushBeforeClose(false);
740 const char *errbuf
= ERR_error_string(errnr
, NULL
);
741 Handler().LogError(this, "OnWrite/SSL_write", errnr
, errbuf
, LOG_LEVEL_FATAL
);
749 SetCloseAndDelete(true);
750 SetFlushBeforeClose(false);
754 DEB( int errnr
= SSL_get_error(m_ssl
, n
);
755 const char *errbuf
= ERR_error_string(errnr
, NULL
);
756 fprintf(stderr
, "SSL_write() returns 0: %d : %s\n",errnr
, errbuf
);)
760 #endif // HAVE_OPENSSL
762 n
= send(GetSocket(), buf
, (int)len
, MSG_NOSIGNAL
);
765 // normal error codes:
767 // EAGAIN or EWOULDBLOCK
769 if (Errno
!= WSAEWOULDBLOCK
)
771 if (Errno
!= EWOULDBLOCK
)
774 Handler().LogError(this, "send", Errno
, StrError(Errno
), LOG_LEVEL_FATAL
);
776 SetCloseAndDelete(true);
777 SetFlushBeforeClose(false);
788 if (GetTrafficMonitor())
790 GetTrafficMonitor() -> fwrite(buf
, 1, n
);
797 void TcpSocket::Buffer(const char *buf
, size_t len
)
800 m_output_length
+= len
;
803 // buf/len => pbuf/sz
805 if (m_obuf_top
&& (space
= m_obuf_top
-> Space()) > 0)
807 const char *pbuf
= buf
+ ptr
;
808 size_t sz
= len
- ptr
;
811 m_obuf_top
-> Add(pbuf
, sz
);
816 m_obuf_top
-> Add(pbuf
, space
);
822 m_obuf_top
= new OUTPUT
;
823 m_obuf
.push_back( m_obuf_top
);
829 void TcpSocket::Send(const std::string
&str
,int i
)
831 SendBuf(str
.c_str(),str
.size(),i
);
835 void TcpSocket::SendBuf(const char *buf
,size_t len
,int)
837 if (!Ready() && !Connecting())
839 Handler().LogError(this, "SendBuf", -1, "Attempt to write to a non-ready socket" ); // warning
840 if (GetSocket() == INVALID_SOCKET
)
841 Handler().LogError(this, "SendBuf", 0, " * GetSocket() == INVALID_SOCKET", LOG_LEVEL_INFO
);
843 Handler().LogError(this, "SendBuf", 0, " * Connecting()", LOG_LEVEL_INFO
);
844 if (CloseAndDelete())
845 Handler().LogError(this, "SendBuf", 0, " * CloseAndDelete()", LOG_LEVEL_INFO
);
850 Handler().LogError(this, "SendBuf", -1, "Attempt to write to a non-connected socket, will be sent on connect" ); // warning
859 int n
= TryWrite(buf
, len
);
860 if (n
>= 0 && n
< (int)len
)
862 Buffer(buf
+ n
, len
- n
);
864 // if ( data in buffer || !IsConnected )
870 // if any data is unsent, buffer it and set m_wfds
872 // check output buffer set, set/reset m_wfds accordingly
877 Handler().Get(GetSocket(), br
, bw
, bx
);
886 void TcpSocket::OnLine(const std::string
& )
892 #pragma warning(disable:4355)
894 TcpSocket::TcpSocket(const TcpSocket
& s
)
900 #pragma warning(default:4355)
905 void TcpSocket::OnSocks4Connect()
908 memset(request
, 0, sizeof(request
));
909 request
[0] = 4; // socks v4
910 request
[1] = 1; // command code: CONNECT
912 std::auto_ptr
<SocketAddress
> ad
= GetClientRemoteAddress();
915 struct sockaddr
*p0
= (struct sockaddr
*)*ad
;
916 struct sockaddr_in
*p
= (struct sockaddr_in
*)p0
;
917 if (p
-> sin_family
== AF_INET
)
919 memcpy(request
+ 2, &p
-> sin_port
, 2); // nwbo is ok here
920 memcpy(request
+ 4, &p
-> sin_addr
, sizeof(struct in_addr
));
932 strcpy(request
+ 8, GetSocks4Userid().c_str());
933 size_t length
= GetSocks4Userid().size() + 8 + 1;
934 SendBuf(request
, length
);
939 void TcpSocket::OnSocks4ConnectFailed()
941 Handler().LogError(this,"OnSocks4ConnectFailed",0,"connection to socks4 server failed, trying direct connection",LOG_LEVEL_WARNING
);
942 if (!Handler().Socks4TryDirect())
944 SetConnecting(false);
946 OnConnectFailed(); // just in case
950 SetRetryClientConnect();
955 bool TcpSocket::OnSocks4Read()
957 switch (m_socks4_state
)
960 ibuf
.Read(&m_socks4_vn
, 1);
964 ibuf
.Read(&m_socks4_cd
, 1);
968 if (GetInputLength() > 1)
970 ibuf
.Read( (char *)&m_socks4_dstport
, 2);
979 if (GetInputLength() > 3)
981 ibuf
.Read( (char *)&m_socks4_dstip
, 4);
988 Handler().LogError(this, "OnSocks4Read", 0, "Connection established", LOG_LEVEL_INFO
);
993 Handler().LogError(this,"OnSocks4Read",m_socks4_cd
,"socks4 server reports connect failed",LOG_LEVEL_FATAL
);
994 SetConnecting(false);
999 Handler().LogError(this,"OnSocks4Read",m_socks4_cd
,"socks4 server unrecognized response",LOG_LEVEL_FATAL
);
1000 SetCloseAndDelete();
1015 void TcpSocket::Sendf(const char *format
, ...)
1018 va_start(ap
, format
);
1019 char slask
[5000]; // vsprintf / vsnprintf temporary
1021 vsprintf(slask
, format
, ap
);
1023 vsnprintf(slask
, 5000, format
, ap
);
1031 void TcpSocket::OnSSLConnect()
1033 SetNonblocking(true);
1037 DEB( fprintf(stderr
, "SSL Context already initialized - closing socket\n");)
1038 SetCloseAndDelete(true);
1045 /* Connect the SSL socket */
1046 m_ssl
= SSL_new(m_ssl_ctx
);
1049 DEB( fprintf(stderr
, " m_ssl is NULL\n");)
1050 SetCloseAndDelete(true);
1053 SSL_set_mode(m_ssl
, SSL_MODE_AUTO_RETRY
);
1054 m_sbio
= BIO_new_socket((int)GetSocket(), BIO_NOCLOSE
);
1057 DEB( fprintf(stderr
, " m_sbio is NULL\n");)
1058 SetCloseAndDelete(true);
1061 SSL_set_bio(m_ssl
, m_sbio
, m_sbio
);
1062 if (!SSLNegotiate())
1069 SetCloseAndDelete();
1074 void TcpSocket::OnSSLAccept()
1076 SetNonblocking(true);
1080 DEB( fprintf(stderr
, "SSL Context already initialized - closing socket\n");)
1081 SetCloseAndDelete(true);
1089 m_ssl
= SSL_new(m_ssl_ctx
);
1092 DEB( fprintf(stderr
, " m_ssl is NULL\n");)
1093 SetCloseAndDelete(true);
1096 SSL_set_mode(m_ssl
, SSL_MODE_AUTO_RETRY
);
1097 m_sbio
= BIO_new_socket((int)GetSocket(), BIO_NOCLOSE
);
1100 DEB( fprintf(stderr
, " m_sbio is NULL\n");)
1101 SetCloseAndDelete(true);
1104 SSL_set_bio(m_ssl
, m_sbio
, m_sbio
);
1105 // if (!SSLNegotiate())
1113 bool TcpSocket::SSLNegotiate()
1115 if (!IsSSLServer()) // client
1117 int r
= SSL_connect(m_ssl
);
1120 SetSSLNegotiate(false);
1121 /// \todo: resurrect certificate check... client
1122 // CheckCertificateChain( "");//ServerHOST);
1123 SetNonblocking(false);
1127 if (GetOutputLength())
1132 #ifdef ENABLE_RECONNECT
1140 Handler().LogError(this, "SSLNegotiate/SSL_connect", 0, "Connection established", LOG_LEVEL_INFO
);
1146 Handler().LogError(this, "SSLNegotiate/SSL_connect", 0, "Connection failed", LOG_LEVEL_INFO
);
1147 SetSSLNegotiate(false);
1148 SetCloseAndDelete();
1149 OnSSLConnectFailed();
1153 r
= SSL_get_error(m_ssl
, r
);
1154 if (r
!= SSL_ERROR_WANT_READ
&& r
!= SSL_ERROR_WANT_WRITE
)
1156 Handler().LogError(this, "SSLNegotiate/SSL_connect", -1, "Connection failed", LOG_LEVEL_INFO
);
1157 DEB( fprintf(stderr
, "SSL_connect() failed - closing socket, return code: %d\n",r
);)
1158 SetSSLNegotiate(false);
1159 SetCloseAndDelete(true);
1160 OnSSLConnectFailed();
1166 int r
= SSL_accept(m_ssl
);
1169 SetSSLNegotiate(false);
1170 /// \todo: resurrect certificate check... server
1171 // CheckCertificateChain( "");//ClientHOST);
1172 SetNonblocking(false);
1176 if (GetOutputLength())
1182 Handler().LogError(this, "SSLNegotiate/SSL_accept", 0, "Connection established", LOG_LEVEL_INFO
);
1188 Handler().LogError(this, "SSLNegotiate/SSL_accept", 0, "Connection failed", LOG_LEVEL_INFO
);
1189 SetSSLNegotiate(false);
1190 SetCloseAndDelete();
1191 OnSSLAcceptFailed();
1195 r
= SSL_get_error(m_ssl
, r
);
1196 if (r
!= SSL_ERROR_WANT_READ
&& r
!= SSL_ERROR_WANT_WRITE
)
1198 Handler().LogError(this, "SSLNegotiate/SSL_accept", -1, "Connection failed", LOG_LEVEL_INFO
);
1199 DEB( fprintf(stderr
, "SSL_accept() failed - closing socket, return code: %d\n",r
);)
1200 SetSSLNegotiate(false);
1201 SetCloseAndDelete(true);
1202 OnSSLAcceptFailed();
1210 void TcpSocket::InitSSLClient()
1212 InitializeContext("", SSLv23_method());
1216 void TcpSocket::InitSSLServer()
1218 Handler().LogError(this, "InitSSLServer", 0, "You MUST implement your own InitSSLServer method", LOG_LEVEL_FATAL
);
1219 SetCloseAndDelete();
1223 void TcpSocket::InitializeContext(const std::string
& context
, SSL_METHOD
*meth_in
)
1225 /* Create our context*/
1226 static std::map
<std::string
, SSL_CTX
*> client_contexts
;
1227 if (client_contexts
.find(context
) == client_contexts
.end())
1229 SSL_METHOD
*meth
= meth_in
? meth_in
: SSLv3_method();
1230 m_ssl_ctx
= client_contexts
[context
] = SSL_CTX_new(meth
);
1231 SSL_CTX_set_mode(m_ssl_ctx
, SSL_MODE_AUTO_RETRY
);
1235 m_ssl_ctx
= client_contexts
[context
];
1240 void TcpSocket::InitializeContext(const std::string
& context
,const std::string
& keyfile
,const std::string
& password
,SSL_METHOD
*meth_in
)
1242 /* Create our context*/
1243 static std::map
<std::string
, SSL_CTX
*> server_contexts
;
1244 if (server_contexts
.find(context
) == server_contexts
.end())
1246 SSL_METHOD
*meth
= meth_in
? meth_in
: SSLv3_method();
1247 m_ssl_ctx
= server_contexts
[context
] = SSL_CTX_new(meth
);
1248 SSL_CTX_set_mode(m_ssl_ctx
, SSL_MODE_AUTO_RETRY
);
1251 SSL_CTX_set_session_id_context(m_ssl_ctx
, (const unsigned char *)context
.c_str(), (unsigned int)context
.size());
1253 SSL_CTX_set_session_id_context(m_ssl_ctx
, (const unsigned char *)"--empty--", 9);
1257 m_ssl_ctx
= server_contexts
[context
];
1260 /* Load our keys and certificates*/
1261 if (!(SSL_CTX_use_certificate_file(m_ssl_ctx
, keyfile
.c_str(), SSL_FILETYPE_PEM
)))
1263 Handler().LogError(this, "TcpSocket InitializeContext", 0, "Couldn't read certificate file " + keyfile
, LOG_LEVEL_FATAL
);
1266 m_password
= password
;
1267 SSL_CTX_set_default_passwd_cb(m_ssl_ctx
, SSL_password_cb
);
1268 SSL_CTX_set_default_passwd_cb_userdata(m_ssl_ctx
, this);
1269 if (!(SSL_CTX_use_PrivateKey_file(m_ssl_ctx
, keyfile
.c_str(), SSL_FILETYPE_PEM
)))
1271 Handler().LogError(this, "TcpSocket InitializeContext", 0, "Couldn't read private key file " + keyfile
, LOG_LEVEL_FATAL
);
1276 void TcpSocket::InitializeContext(const std::string
& context
,const std::string
& certfile
,const std::string
& keyfile
,const std::string
& password
,SSL_METHOD
*meth_in
)
1278 /* Create our context*/
1279 static std::map
<std::string
, SSL_CTX
*> server_contexts
;
1280 if (server_contexts
.find(context
) == server_contexts
.end())
1282 SSL_METHOD
*meth
= meth_in
? meth_in
: SSLv3_method();
1283 m_ssl_ctx
= server_contexts
[context
] = SSL_CTX_new(meth
);
1284 SSL_CTX_set_mode(m_ssl_ctx
, SSL_MODE_AUTO_RETRY
);
1287 SSL_CTX_set_session_id_context(m_ssl_ctx
, (const unsigned char *)context
.c_str(), (unsigned int)context
.size());
1289 SSL_CTX_set_session_id_context(m_ssl_ctx
, (const unsigned char *)"--empty--", 9);
1293 m_ssl_ctx
= server_contexts
[context
];
1296 /* Load our keys and certificates*/
1297 if (!(SSL_CTX_use_certificate_file(m_ssl_ctx
, certfile
.c_str(), SSL_FILETYPE_PEM
)))
1299 Handler().LogError(this, "TcpSocket InitializeContext", 0, "Couldn't read certificate file " + keyfile
, LOG_LEVEL_FATAL
);
1302 m_password
= password
;
1303 SSL_CTX_set_default_passwd_cb(m_ssl_ctx
, SSL_password_cb
);
1304 SSL_CTX_set_default_passwd_cb_userdata(m_ssl_ctx
, this);
1305 if (!(SSL_CTX_use_PrivateKey_file(m_ssl_ctx
, keyfile
.c_str(), SSL_FILETYPE_PEM
)))
1307 Handler().LogError(this, "TcpSocket InitializeContext", 0, "Couldn't read private key file " + keyfile
, LOG_LEVEL_FATAL
);
1312 int TcpSocket::SSL_password_cb(char *buf
,int num
,int rwflag
,void *userdata
)
1314 Socket
*p0
= static_cast<Socket
*>(userdata
);
1315 TcpSocket
*p
= dynamic_cast<TcpSocket
*>(p0
);
1316 std::string pw
= p
? p
-> GetPassword() : "";
1317 if ( (size_t)num
< pw
.size() + 1)
1321 strcpy(buf
,pw
.c_str());
1322 return (int)pw
.size();
1324 #endif // HAVE_OPENSSL
1327 int TcpSocket::Close()
1329 if (GetSocket() == INVALID_SOCKET
) // this could happen
1331 Handler().LogError(this, "Socket::Close", 0, "file descriptor invalid", LOG_LEVEL_WARNING
);
1335 SetNonblocking(true);
1336 if (IsConnected() && !(GetShutdown() & SHUT_WR
))
1338 if (shutdown(GetSocket(), SHUT_WR
) == -1)
1341 Handler().LogError(this, "shutdown", Errno
, StrError(Errno
), LOG_LEVEL_ERROR
);
1346 if ((n
= recv(GetSocket(),tmp
,1000,0)) >= 0)
1350 Handler().LogError(this, "read() after shutdown", n
, "bytes read", LOG_LEVEL_WARNING
);
1354 if (IsSSL() && m_ssl
)
1355 SSL_shutdown(m_ssl
);
1362 return Socket::Close();
1367 SSL_CTX
*TcpSocket::GetSslContext()
1370 Handler().LogError(this, "GetSslContext", 0, "SSL Context is NULL; check InitSSLServer/InitSSLClient", LOG_LEVEL_WARNING
);
1374 SSL
*TcpSocket::GetSsl()
1377 Handler().LogError(this, "GetSsl", 0, "SSL is NULL; check InitSSLServer/InitSSLClient", LOG_LEVEL_WARNING
);
1383 #ifdef ENABLE_RECONNECT
1384 void TcpSocket::SetReconnect(bool x
)
1391 void TcpSocket::OnRawData(const char *buf_in
,size_t len
)
1396 size_t TcpSocket::GetInputLength()
1398 return ibuf
.GetLength();
1402 size_t TcpSocket::GetOutputLength()
1404 return m_output_length
;
1408 uint64_t TcpSocket::GetBytesReceived(bool clear
)
1410 uint64_t z
= m_bytes_received
;
1412 m_bytes_received
= 0;
1417 uint64_t TcpSocket::GetBytesSent(bool clear
)
1419 uint64_t z
= m_bytes_sent
;
1426 #ifdef ENABLE_RECONNECT
1427 bool TcpSocket::Reconnect()
1429 return m_b_reconnect
;
1433 void TcpSocket::SetIsReconnect(bool x
)
1435 m_b_is_reconnect
= x
;
1439 bool TcpSocket::IsReconnect()
1441 return m_b_is_reconnect
;
1447 const std::string
& TcpSocket::GetPassword()
1454 void TcpSocket::DisableInputBuffer(bool x
)
1456 m_b_input_buffer_disabled
= x
;
1460 void TcpSocket::OnOptions(int family
,int type
,int protocol
,SOCKET s
)
1462 DEB( fprintf(stderr
, "Socket::OnOptions()\n");)
1464 SetSoNosigpipe(true);
1466 SetSoReuseaddr(true);
1467 SetSoKeepalive(true);
1471 void TcpSocket::SetLineProtocol(bool x
)
1473 StreamSocket::SetLineProtocol(x
);
1474 DisableInputBuffer(x
);
1478 bool TcpSocket::SetTcpNodelay(bool x
)
1481 int optval
= x
? 1 : 0;
1482 if (setsockopt(GetSocket(), IPPROTO_TCP
, TCP_NODELAY
, (char *)&optval
, sizeof(optval
)) == -1)
1484 Handler().LogError(this, "setsockopt(IPPROTO_TCP, TCP_NODELAY)", Errno
, StrError(Errno
), LOG_LEVEL_FATAL
);
1489 Handler().LogError(this, "socket option not available", 0, "TCP_NODELAY", LOG_LEVEL_INFO
);
1495 TcpSocket::CircularBuffer::CircularBuffer(size_t size
)
1496 :buf(new char[2 * size
])
1506 TcpSocket::CircularBuffer::~CircularBuffer()
1512 bool TcpSocket::CircularBuffer::Write(const char *s
,size_t l
)
1514 if (m_q
+ l
> m_max
)
1516 return false; // overflow
1518 m_count
+= (unsigned long)l
;
1519 if (m_t
+ l
> m_max
) // block crosses circular border
1521 size_t l1
= m_max
- m_t
; // size left until circular border crossing
1522 // always copy full block to buffer(buf) + top pointer(m_t)
1523 // because we have doubled the buffer size for performance reasons
1524 memcpy(buf
+ m_t
, s
, l
);
1525 memcpy(buf
, s
+ l1
, l
- l1
);
1531 memcpy(buf
+ m_t
, s
, l
);
1532 memcpy(buf
+ m_max
+ m_t
, s
, l
);
1542 bool TcpSocket::CircularBuffer::Read(char *s
,size_t l
)
1546 return false; // not enough chars
1548 if (m_b
+ l
> m_max
) // block crosses circular border
1550 size_t l1
= m_max
- m_b
;
1553 memcpy(s
, buf
+ m_b
, l1
);
1554 memcpy(s
+ l1
, buf
, l
- l1
);
1563 memcpy(s
, buf
+ m_b
, l
);
1578 bool TcpSocket::CircularBuffer::Remove(size_t l
)
1580 return Read(NULL
, l
);
1584 size_t TcpSocket::CircularBuffer::GetLength()
1590 const char *TcpSocket::CircularBuffer::GetStart()
1596 size_t TcpSocket::CircularBuffer::GetL()
1598 return (m_b
+ m_q
> m_max
) ? m_max
- m_b
: m_q
;
1602 size_t TcpSocket::CircularBuffer::Space()
1608 unsigned long TcpSocket::CircularBuffer::ByteCounter(bool clear
)
1612 unsigned long x
= m_count
;
1620 std::string
TcpSocket::CircularBuffer::ReadString(size_t l
)
1622 char *sz
= new char[l
+ 1];
1623 if (!Read(sz
, l
)) // failed, debug printout in Read() method
1629 std::string tmp
= sz
;
1635 void TcpSocket::OnConnectTimeout()
1637 Handler().LogError(this, "connect", -1, "connect timeout", LOG_LEVEL_FATAL
);
1638 #ifdef ENABLE_SOCKS4
1641 OnSocks4ConnectFailed();
1642 // retry direct connection
1646 if (GetConnectionRetry() == -1 ||
1647 (GetConnectionRetry() && GetConnectionRetries() < GetConnectionRetry()) )
1649 IncreaseConnectionRetries();
1650 // ask socket via OnConnectRetry callback if we should continue trying
1651 if (OnConnectRetry())
1653 SetRetryClientConnect();
1657 SetCloseAndDelete( true );
1658 /// \todo state reason why connect failed
1664 SetCloseAndDelete(true);
1665 /// \todo state reason why connect failed
1669 SetConnecting(false);
1674 void TcpSocket::OnException()
1678 #ifdef ENABLE_SOCKS4
1680 OnSocks4ConnectFailed();
1683 if (GetConnectionRetry() == -1 ||
1684 (GetConnectionRetry() &&
1685 GetConnectionRetries() < GetConnectionRetry() ))
1687 // even though the connection failed at once, only retry after
1688 // the connection timeout
1689 // should we even try to connect again, when CheckConnect returns
1690 // false it's because of a connection error - not a timeout...
1694 SetConnecting(false); // tnx snibbe
1695 SetCloseAndDelete();
1700 // %! exception doesn't always mean something bad happened, this code should be reworked
1701 // errno valid here?
1702 int err
= SoError();
1703 Handler().LogError(this, "exception on select", err
, StrError(err
), LOG_LEVEL_FATAL
);
1704 SetCloseAndDelete();
1709 int TcpSocket::Protocol()
1715 void TcpSocket::SetTransferLimit(size_t sz
)
1717 m_transfer_limit
= sz
;
1721 void TcpSocket::OnTransferLimit()
1726 #ifdef SOCKETS_NAMESPACE