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
;
75 #pragma warning(disable:4355)
78 TcpSocket::TcpSocket(ISocketHandler
& h
) : StreamSocket(h
)
79 ,ibuf(TCP_BUFSIZE_READ
)
80 ,m_b_input_buffer_disabled(false)
84 #ifdef SOCKETS_DYNAMIC_TEMP
85 ,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)
107 #pragma warning(default:4355)
114 #pragma warning(disable:4355)
117 TcpSocket::TcpSocket(ISocketHandler
& h
,size_t isize
,size_t osize
) : StreamSocket(h
)
119 ,m_b_input_buffer_disabled(false)
123 #ifdef SOCKETS_DYNAMIC_TEMP
124 ,m_buf(new char[TCP_BUFSIZE_READ
+ 1])
135 #ifdef ENABLE_RESOLVER
138 #ifdef ENABLE_RECONNECT
139 ,m_b_reconnect(false)
140 ,m_b_is_reconnect(false)
146 #pragma warning(default:4355)
151 TcpSocket::~TcpSocket()
153 #ifdef SOCKETS_DYNAMIC_TEMP
166 bool TcpSocket::Open(ipaddr_t ip
,port_t port
,bool skip_socks
)
168 Ipv4Address
ad(ip
, port
);
170 return Open(ad
, local
, skip_socks
);
176 bool TcpSocket::Open(in6_addr ip
,port_t port
,bool skip_socks
)
178 Ipv6Address
ad(ip
, port
);
179 return Open(ad
, skip_socks
);
185 bool TcpSocket::Open(SocketAddress
& ad
,bool skip_socks
)
187 Ipv4Address
bind_ad("0.0.0.0", 0);
188 return Open(ad
, bind_ad
, skip_socks
);
192 bool TcpSocket::Open(SocketAddress
& ad
,SocketAddress
& bind_ad
,bool skip_socks
)
196 Handler().LogError(this, "Open", 0, "Invalid SocketAddress", LOG_LEVEL_FATAL
);
200 if (Handler().GetCount() >= FD_SETSIZE
)
202 Handler().LogError(this, "Open", 0, "no space left in fd_set", LOG_LEVEL_FATAL
);
206 SetConnecting(false);
212 if (Handler().PoolEnabled())
214 ISocketHandler::PoolSocket
*pools
= Handler().FindConnection(SOCK_STREAM
, "tcp", ad
);
217 CopyConnection( pools
);
221 SetCallOnConnect(); // ISocketHandler must call OnConnect
222 Handler().LogError(this, "SetCallOnConnect", 0, "Found pooled connection", LOG_LEVEL_INFO
);
227 // if not, create new connection
228 SOCKET s
= CreateSocket(ad
.GetFamily(), SOCK_STREAM
, "tcp");
229 if (s
== INVALID_SOCKET
)
233 // socket must be nonblocking for async connect
234 if (!SetNonblocking(true, s
))
241 SetIsClient(); // client because we connect
243 SetClientRemoteAddress(ad
);
245 if (bind_ad
.GetPort() != 0)
247 bind(s
, bind_ad
, bind_ad
);
250 if (!skip_socks
&& GetSocks4Host() && GetSocks4Port())
252 Ipv4Address
sa(GetSocks4Host(), GetSocks4Port());
254 std::string sockshost
;
255 Utility::l2ip(GetSocks4Host(), sockshost
);
256 Handler().LogError(this, "Open", 0, "Connecting to socks4 server @ " + sockshost
+ ":" +
257 Utility::l2string(GetSocks4Port()), LOG_LEVEL_INFO
);
260 n
= connect(s
, sa
, sa
);
261 SetRemoteAddress(sa
);
266 n
= connect(s
, ad
, ad
);
267 SetRemoteAddress(ad
);
271 // check error code that means a connect is in progress
273 if (Errno
== WSAEWOULDBLOCK
)
275 if (Errno
== EINPROGRESS
)
279 SetConnecting( true ); // this flag will control fd_set's
283 if (Socks4() && Handler().Socks4TryDirect() ) // retry
286 return Open(ad
, true);
290 #ifdef ENABLE_RECONNECT
293 Handler().LogError(this, "connect: failed, reconnect pending", Errno
, StrError(Errno
), LOG_LEVEL_INFO
);
295 SetConnecting( true ); // this flag will control fd_set's
300 Handler().LogError(this, "connect: failed", Errno
, StrError(Errno
), LOG_LEVEL_FATAL
);
309 SetCallOnConnect(); // ISocketHandler must call OnConnect
312 // 'true' means connected or connecting(not yet connected)
313 // 'false' means something failed
314 return true; //!Connecting();
318 bool TcpSocket::Open(const std::string
&host
,port_t port
)
324 #ifdef ENABLE_RESOLVER
325 if (!Handler().ResolverEnabled() || Utility::isipv6(host
) )
329 if (!Utility::u2ip(host
, a
))
334 Ipv6Address
ad(a
, port
);
336 return Open(ad
, local
);
337 #ifdef ENABLE_RESOLVER
339 m_resolver_id
= Resolve6(host
, port
);
345 #ifdef ENABLE_RESOLVER
346 if (!Handler().ResolverEnabled() || Utility::isipv4(host
) )
350 if (!Utility::u2ip(host
,l
))
355 Ipv4Address
ad(l
, port
);
357 return Open(ad
, local
);
358 #ifdef ENABLE_RESOLVER
360 // resolve using async resolver thread
361 m_resolver_id
= Resolve(host
, port
);
367 #ifdef ENABLE_RESOLVER
368 void TcpSocket::OnResolved(int id
,ipaddr_t a
,port_t port
)
370 if (id
== m_resolver_id
)
374 Ipv4Address
ad(a
, port
);
378 if (!Handler().Valid(this))
386 Handler().LogError(this, "OnResolved", 0, "Resolver failed", LOG_LEVEL_FATAL
);
392 Handler().LogError(this, "OnResolved", id
, "Resolver returned wrong job id", LOG_LEVEL_FATAL
);
399 void TcpSocket::OnResolved(int id
,in6_addr
& a
,port_t port
)
401 if (id
== m_resolver_id
)
403 Ipv6Address
ad(a
, port
);
409 if (!Handler().Valid(this))
418 Handler().LogError(this, "OnResolved", id
, "Resolver returned wrong job id", LOG_LEVEL_FATAL
);
426 void TcpSocket::OnRead()
429 #ifdef SOCKETS_DYNAMIC_TEMP
432 char buf
[TCP_BUFSIZE_READ
];
439 n
= SSL_read(m_ssl
, buf
, TCP_BUFSIZE_READ
);
442 n
= SSL_get_error(m_ssl
, n
);
446 case SSL_ERROR_WANT_READ
:
447 case SSL_ERROR_WANT_WRITE
:
449 case SSL_ERROR_ZERO_RETURN
:
450 DEB( fprintf(stderr
, "SSL_read() returns zero - closing socket\n");)
451 SetCloseAndDelete(true);
452 SetFlushBeforeClose(false);
458 DEB( fprintf(stderr
, "SSL read problem, errcode = %d\n",n
);)
459 SetCloseAndDelete(true);
460 SetFlushBeforeClose(false);
470 Handler().LogError(this, "SSL_read", 0, "read returns 0", LOG_LEVEL_FATAL
);
471 SetCloseAndDelete(true);
472 SetFlushBeforeClose(false);
476 SetShutdown(SHUT_WR
);
480 if (n
> 0 && n
<= TCP_BUFSIZE_READ
)
482 m_bytes_received
+= n
;
483 if (GetTrafficMonitor())
485 GetTrafficMonitor() -> fwrite(buf
, 1, n
);
487 if (!m_b_input_buffer_disabled
&& !ibuf
.Write(buf
,n
))
489 Handler().LogError(this, "OnRead(ssl)", 0, "ibuf overflow", LOG_LEVEL_WARNING
);
494 Handler().LogError(this, "OnRead(ssl)", n
, "abnormal value from SSL_read", LOG_LEVEL_ERROR
);
498 #endif // HAVE_OPENSSL
500 n
= recv(GetSocket(), buf
, TCP_BUFSIZE_READ
, MSG_NOSIGNAL
);
503 Handler().LogError(this, "read", Errno
, StrError(Errno
), LOG_LEVEL_FATAL
);
504 SetCloseAndDelete(true);
505 SetFlushBeforeClose(false);
514 SetCloseAndDelete(true);
515 SetFlushBeforeClose(false);
519 SetShutdown(SHUT_WR
);
523 if (n
> 0 && n
<= TCP_BUFSIZE_READ
)
525 m_bytes_received
+= n
;
526 if (GetTrafficMonitor())
528 GetTrafficMonitor() -> fwrite(buf
, 1, n
);
530 if (!m_b_input_buffer_disabled
&& !ibuf
.Write(buf
,n
))
532 Handler().LogError(this, "OnRead", 0, "ibuf overflow", LOG_LEVEL_WARNING
);
537 Handler().LogError(this, "OnRead", n
, "abnormal value from recv", LOG_LEVEL_ERROR
);
541 if (n
> 0 && n
<= TCP_BUFSIZE_READ
)
547 if (m_skip_c
&& (buf
[i
] == 13 || buf
[i
] == 10) && buf
[i
] != m_c
)
553 for (; i
< n
&& LineProtocol(); i
++)
555 while ((buf
[i
] == 13 || buf
[i
] == 10) && LineProtocol())
567 if (i
< n
&& (buf
[i
] == 13 || buf
[i
] == 10) && buf
[i
] != c
)
584 OnRawData(buf
+ i
, n
- i
);
598 if (m_b_input_buffer_disabled
)
602 // further processing: socks4
606 bool need_more
= false;
607 while (GetInputLength() && !need_more
&& !CloseAndDelete())
609 need_more
= OnSocks4Read();
616 void TcpSocket::OnWriteComplete()
621 void TcpSocket::OnWrite()
627 // don't reset connecting flag on error here, we want the OnConnectFailed timeout later on
630 Set(!IsDisableRead(), false);
631 SetConnecting(false);
635 Handler().LogError(this, "tcp: connect failed", err
, StrError(err
), LOG_LEVEL_FATAL
);
636 Set(false, false); // no more monitoring because connection failed
642 // %! leave 'Connecting' flag set?
643 OnSocks4ConnectFailed();
647 if (GetConnectionRetry() == -1 ||
648 (GetConnectionRetry() && GetConnectionRetries() < GetConnectionRetry()) )
650 // even though the connection failed at once, only retry after
651 // the connection timeout.
652 // should we even try to connect again, when CheckConnect returns
653 // false it's because of a connection error - not a timeout...
656 SetConnecting(false);
657 SetCloseAndDelete( true );
658 /// \todo state reason why connect failed
662 // try send next block in buffer
663 // if full block is sent, repeat
664 // if all blocks are sent, reset m_wfds
669 output_l::iterator it
= m_obuf
.begin();
672 int n
= TryWrite(p
-> Buf(), p
-> Len());
675 size_t left
= p
-> Remove(n
);
693 // check output buffer set, set/reset m_wfds accordingly
698 Handler().Get(GetSocket(), br
, bw
, bx
);
707 int TcpSocket::TryWrite(const char *buf
, size_t len
)
713 n
= SSL_write(m_ssl
, buf
, len
);
716 int errnr
= SSL_get_error(m_ssl
, n
);
717 if ( errnr
!= SSL_ERROR_WANT_READ
&& errnr
!= SSL_ERROR_WANT_WRITE
)
719 SetCloseAndDelete(true);
720 SetFlushBeforeClose(false);
724 const char *errbuf
= ERR_error_string(errnr
, NULL
);
725 Handler().LogError(this, "OnWrite/SSL_write", errnr
, errbuf
, LOG_LEVEL_FATAL
);
731 SetCloseAndDelete(true);
732 SetFlushBeforeClose(false);
736 DEB( int errnr
= SSL_get_error(m_ssl
, n
);
737 const char *errbuf
= ERR_error_string(errnr
, NULL
);
738 fprintf(stderr
, "SSL_write() returns 0: %d : %s\n",errnr
, errbuf
);)
742 #endif // HAVE_OPENSSL
744 n
= send(GetSocket(), buf
, (int)len
, MSG_NOSIGNAL
);
747 // normal error codes:
749 // EAGAIN or EWOULDBLOCK
751 if (Errno
!= WSAEWOULDBLOCK
)
753 if (Errno
!= EWOULDBLOCK
)
756 Handler().LogError(this, "send", Errno
, StrError(Errno
), LOG_LEVEL_FATAL
);
757 SetCloseAndDelete(true);
758 SetFlushBeforeClose(false);
768 if (GetTrafficMonitor())
770 GetTrafficMonitor() -> fwrite(buf
, 1, n
);
777 void TcpSocket::Buffer(const char *buf
, size_t len
)
782 // buf/len => pbuf/sz
784 if (m_obuf_top
&& (space
= m_obuf_top
-> Space()) > 0)
786 const char *pbuf
= buf
+ ptr
;
787 size_t sz
= len
- ptr
;
790 m_obuf_top
-> Add(pbuf
, sz
);
795 m_obuf_top
-> Add(pbuf
, space
);
801 m_obuf_top
= new OUTPUT
;
802 m_obuf
.push_back( m_obuf_top
);
808 void TcpSocket::Send(const std::string
&str
,int i
)
810 SendBuf(str
.c_str(),str
.size(),i
);
814 void TcpSocket::SendBuf(const char *buf
,size_t len
,int)
816 if (!Ready() && !Connecting())
818 Handler().LogError(this, "SendBuf", -1, "Attempt to write to a non-ready socket" ); // warning
819 if (GetSocket() == INVALID_SOCKET
)
820 Handler().LogError(this, "SendBuf", 0, " * GetSocket() == INVALID_SOCKET", LOG_LEVEL_INFO
);
822 Handler().LogError(this, "SendBuf", 0, " * Connecting()", LOG_LEVEL_INFO
);
823 if (CloseAndDelete())
824 Handler().LogError(this, "SendBuf", 0, " * CloseAndDelete()", LOG_LEVEL_INFO
);
829 Handler().LogError(this, "SendBuf", -1, "Attempt to write to a non-connected socket, will be sent on connect" ); // warning
838 int n
= TryWrite(buf
, len
);
839 if (n
> 0 && n
< (int)len
)
841 Buffer(buf
+ n
, len
- n
);
843 // if ( data in buffer || !IsConnected )
849 // if any data is unsent, buffer it and set m_wfds
851 // check output buffer set, set/reset m_wfds accordingly
856 Handler().Get(GetSocket(), br
, bw
, bx
);
865 void TcpSocket::OnLine(const std::string
& )
872 #pragma warning(disable:4355)
875 TcpSocket::TcpSocket(const TcpSocket
& s
)
882 #pragma warning(default:4355)
888 void TcpSocket::OnSocks4Connect()
891 memset(request
, 0, sizeof(request
));
892 request
[0] = 4; // socks v4
893 request
[1] = 1; // command code: CONNECT
895 std::auto_ptr
<SocketAddress
> ad
= GetClientRemoteAddress();
898 struct sockaddr
*p0
= (struct sockaddr
*)*ad
;
899 struct sockaddr_in
*p
= (struct sockaddr_in
*)p0
;
900 if (p
-> sin_family
== AF_INET
)
902 memcpy(request
+ 2, &p
-> sin_port
, 2); // nwbo is ok here
903 memcpy(request
+ 4, &p
-> sin_addr
, sizeof(struct in_addr
));
915 strcpy(request
+ 8, GetSocks4Userid().c_str());
916 size_t length
= GetSocks4Userid().size() + 8 + 1;
917 SendBuf(request
, length
);
922 void TcpSocket::OnSocks4ConnectFailed()
924 Handler().LogError(this,"OnSocks4ConnectFailed",0,"connection to socks4 server failed, trying direct connection",LOG_LEVEL_WARNING
);
925 if (!Handler().Socks4TryDirect())
927 SetConnecting(false);
929 OnConnectFailed(); // just in case
933 SetRetryClientConnect();
938 bool TcpSocket::OnSocks4Read()
940 switch (m_socks4_state
)
943 ibuf
.Read(&m_socks4_vn
, 1);
947 ibuf
.Read(&m_socks4_cd
, 1);
951 if (GetInputLength() > 1)
953 ibuf
.Read( (char *)&m_socks4_dstport
, 2);
962 if (GetInputLength() > 3)
964 ibuf
.Read( (char *)&m_socks4_dstip
, 4);
971 Handler().LogError(this, "OnSocks4Read", 0, "Connection established", LOG_LEVEL_INFO
);
976 Handler().LogError(this,"OnSocks4Read",m_socks4_cd
,"socks4 server reports connect failed",LOG_LEVEL_FATAL
);
977 SetConnecting(false);
982 Handler().LogError(this,"OnSocks4Read",m_socks4_cd
,"socks4 server unrecognized response",LOG_LEVEL_FATAL
);
998 void TcpSocket::Sendf(const char *format
, ...)
1001 va_start(ap
, format
);
1002 char slask
[5000]; // vsprintf / vsnprintf temporary
1004 vsprintf(slask
, format
, ap
);
1006 vsnprintf(slask
, 5000, format
, ap
);
1014 void TcpSocket::OnSSLConnect()
1016 SetNonblocking(true);
1020 DEB( fprintf(stderr
, "SSL Context already initialized - closing socket\n");)
1021 SetCloseAndDelete(true);
1028 /* Connect the SSL socket */
1029 m_ssl
= SSL_new(m_ssl_ctx
);
1032 DEB( fprintf(stderr
, " m_ssl is NULL\n");)
1033 SetCloseAndDelete(true);
1036 SSL_set_mode(m_ssl
, SSL_MODE_AUTO_RETRY
);
1037 m_sbio
= BIO_new_socket((int)GetSocket(), BIO_NOCLOSE
);
1040 DEB( fprintf(stderr
, " m_sbio is NULL\n");)
1041 SetCloseAndDelete(true);
1044 SSL_set_bio(m_ssl
, m_sbio
, m_sbio
);
1045 // if (!SSLNegotiate())
1052 SetCloseAndDelete();
1057 void TcpSocket::OnSSLAccept()
1059 SetNonblocking(true);
1063 DEB( fprintf(stderr
, "SSL Context already initialized - closing socket\n");)
1064 SetCloseAndDelete(true);
1072 m_ssl
= SSL_new(m_ssl_ctx
);
1075 DEB( fprintf(stderr
, " m_ssl is NULL\n");)
1076 SetCloseAndDelete(true);
1079 SSL_set_mode(m_ssl
, SSL_MODE_AUTO_RETRY
);
1080 m_sbio
= BIO_new_socket((int)GetSocket(), BIO_NOCLOSE
);
1083 DEB( fprintf(stderr
, " m_sbio is NULL\n");)
1084 SetCloseAndDelete(true);
1087 SSL_set_bio(m_ssl
, m_sbio
, m_sbio
);
1088 // if (!SSLNegotiate())
1096 bool TcpSocket::SSLNegotiate()
1098 if (!IsSSLServer()) // client
1100 int r
= SSL_connect(m_ssl
);
1103 SetSSLNegotiate(false);
1104 /// \todo: resurrect certificate check... client
1105 // CheckCertificateChain( "");//ServerHOST);
1106 SetNonblocking(false);
1110 if (GetOutputLength())
1115 #ifdef ENABLE_RECONNECT
1123 Handler().LogError(this, "SSLNegotiate/SSL_connect", 0, "Connection established", LOG_LEVEL_INFO
);
1129 Handler().LogError(this, "SSLNegotiate/SSL_connect", 0, "Connection failed", LOG_LEVEL_INFO
);
1130 SetSSLNegotiate(false);
1131 SetCloseAndDelete();
1132 OnSSLConnectFailed();
1136 r
= SSL_get_error(m_ssl
, r
);
1137 if (r
!= SSL_ERROR_WANT_READ
&& r
!= SSL_ERROR_WANT_WRITE
)
1139 Handler().LogError(this, "SSLNegotiate/SSL_connect", -1, "Connection failed", LOG_LEVEL_INFO
);
1140 DEB( fprintf(stderr
, "SSL_connect() failed - closing socket, return code: %d\n",r
);)
1141 SetSSLNegotiate(false);
1142 SetCloseAndDelete(true);
1143 OnSSLConnectFailed();
1149 int r
= SSL_accept(m_ssl
);
1152 SetSSLNegotiate(false);
1153 /// \todo: resurrect certificate check... server
1154 // CheckCertificateChain( "");//ClientHOST);
1155 SetNonblocking(false);
1159 if (GetOutputLength())
1165 Handler().LogError(this, "SSLNegotiate/SSL_accept", 0, "Connection established", LOG_LEVEL_INFO
);
1171 Handler().LogError(this, "SSLNegotiate/SSL_accept", 0, "Connection failed", LOG_LEVEL_INFO
);
1172 SetSSLNegotiate(false);
1173 SetCloseAndDelete();
1174 OnSSLAcceptFailed();
1178 r
= SSL_get_error(m_ssl
, r
);
1179 if (r
!= SSL_ERROR_WANT_READ
&& r
!= SSL_ERROR_WANT_WRITE
)
1181 Handler().LogError(this, "SSLNegotiate/SSL_accept", -1, "Connection failed", LOG_LEVEL_INFO
);
1182 DEB( fprintf(stderr
, "SSL_accept() failed - closing socket, return code: %d\n",r
);)
1183 SetSSLNegotiate(false);
1184 SetCloseAndDelete(true);
1185 OnSSLAcceptFailed();
1193 void TcpSocket::InitSSLClient()
1195 InitializeContext("", SSLv23_method());
1199 void TcpSocket::InitSSLServer()
1201 Handler().LogError(this, "InitSSLServer", 0, "You MUST implement your own InitSSLServer method", LOG_LEVEL_FATAL
);
1202 SetCloseAndDelete();
1206 void TcpSocket::InitializeContext(const std::string
& context
, SSL_METHOD
*meth_in
)
1208 /* Create our context*/
1209 static std::map
<std::string
, SSL_CTX
*> client_contexts
;
1210 if (client_contexts
.find(context
) == client_contexts
.end())
1212 SSL_METHOD
*meth
= meth_in
? meth_in
: SSLv3_method();
1213 m_ssl_ctx
= client_contexts
[context
] = SSL_CTX_new(meth
);
1214 SSL_CTX_set_mode(m_ssl_ctx
, SSL_MODE_AUTO_RETRY
);
1218 m_ssl_ctx
= client_contexts
[context
];
1223 void TcpSocket::InitializeContext(const std::string
& context
,const std::string
& keyfile
,const std::string
& password
,SSL_METHOD
*meth_in
)
1225 /* Create our context*/
1226 static std::map
<std::string
, SSL_CTX
*> server_contexts
;
1227 if (server_contexts
.find(context
) == server_contexts
.end())
1229 SSL_METHOD
*meth
= meth_in
? meth_in
: SSLv3_method();
1230 m_ssl_ctx
= server_contexts
[context
] = SSL_CTX_new(meth
);
1231 SSL_CTX_set_mode(m_ssl_ctx
, SSL_MODE_AUTO_RETRY
);
1234 SSL_CTX_set_session_id_context(m_ssl_ctx
, (const unsigned char *)context
.c_str(), (unsigned int)context
.size());
1236 SSL_CTX_set_session_id_context(m_ssl_ctx
, (const unsigned char *)"--empty--", 9);
1240 m_ssl_ctx
= server_contexts
[context
];
1243 /* Load our keys and certificates*/
1244 if (!(SSL_CTX_use_certificate_file(m_ssl_ctx
, keyfile
.c_str(), SSL_FILETYPE_PEM
)))
1246 Handler().LogError(this, "TcpSocket InitializeContext", 0, "Couldn't read certificate file " + keyfile
, LOG_LEVEL_FATAL
);
1249 m_password
= password
;
1250 SSL_CTX_set_default_passwd_cb(m_ssl_ctx
, SSL_password_cb
);
1251 SSL_CTX_set_default_passwd_cb_userdata(m_ssl_ctx
, this);
1252 if (!(SSL_CTX_use_PrivateKey_file(m_ssl_ctx
, keyfile
.c_str(), SSL_FILETYPE_PEM
)))
1254 Handler().LogError(this, "TcpSocket InitializeContext", 0, "Couldn't read private key file " + keyfile
, LOG_LEVEL_FATAL
);
1259 int TcpSocket::SSL_password_cb(char *buf
,int num
,int rwflag
,void *userdata
)
1261 Socket
*p0
= static_cast<Socket
*>(userdata
);
1262 TcpSocket
*p
= dynamic_cast<TcpSocket
*>(p0
);
1263 std::string pw
= p
? p
-> GetPassword() : "";
1264 if ( (size_t)num
< pw
.size() + 1)
1268 strcpy(buf
,pw
.c_str());
1269 return (int)pw
.size();
1271 #endif // HAVE_OPENSSL
1274 int TcpSocket::Close()
1276 if (GetSocket() == INVALID_SOCKET
) // this could happen
1278 Handler().LogError(this, "Socket::Close", 0, "file descriptor invalid", LOG_LEVEL_WARNING
);
1282 SetNonblocking(true);
1283 if (IsConnected() && !(GetShutdown() & SHUT_WR
))
1285 if (shutdown(GetSocket(), SHUT_WR
) == -1)
1288 Handler().LogError(this, "shutdown", Errno
, StrError(Errno
), LOG_LEVEL_ERROR
);
1293 if ((n
= recv(GetSocket(),tmp
,1000,0)) >= 0)
1297 Handler().LogError(this, "read() after shutdown", n
, "bytes read", LOG_LEVEL_WARNING
);
1301 if (IsSSL() && m_ssl
)
1302 SSL_shutdown(m_ssl
);
1309 return Socket::Close();
1314 SSL_CTX
*TcpSocket::GetSslContext()
1317 Handler().LogError(this, "GetSslContext", 0, "SSL Context is NULL; check InitSSLServer/InitSSLClient", LOG_LEVEL_WARNING
);
1321 SSL
*TcpSocket::GetSsl()
1324 Handler().LogError(this, "GetSsl", 0, "SSL is NULL; check InitSSLServer/InitSSLClient", LOG_LEVEL_WARNING
);
1330 #ifdef ENABLE_RECONNECT
1331 void TcpSocket::SetReconnect(bool x
)
1338 void TcpSocket::OnRawData(const char *buf_in
,size_t len
)
1343 size_t TcpSocket::GetInputLength()
1345 return ibuf
.GetLength();
1349 size_t TcpSocket::GetOutputLength()
1352 for (output_l::iterator it
= m_obuf
.begin(); it
!= m_obuf
.end(); it
++)
1353 len
+= (*it
) -> Len();
1358 uint64_t TcpSocket::GetBytesReceived(bool clear
)
1360 uint64_t z
= m_bytes_received
;
1362 m_bytes_received
= 0;
1367 uint64_t TcpSocket::GetBytesSent(bool clear
)
1369 uint64_t z
= m_bytes_sent
;
1376 #ifdef ENABLE_RECONNECT
1377 bool TcpSocket::Reconnect()
1379 return m_b_reconnect
;
1383 void TcpSocket::SetIsReconnect(bool x
)
1385 m_b_is_reconnect
= x
;
1389 bool TcpSocket::IsReconnect()
1391 return m_b_is_reconnect
;
1397 const std::string
& TcpSocket::GetPassword()
1404 void TcpSocket::DisableInputBuffer(bool x
)
1406 m_b_input_buffer_disabled
= x
;
1410 void TcpSocket::OnOptions(int family
,int type
,int protocol
,SOCKET s
)
1412 DEB( fprintf(stderr
, "Socket::OnOptions()\n");)
1414 SetSoNosigpipe(true);
1416 SetSoReuseaddr(true);
1417 SetSoKeepalive(true);
1421 void TcpSocket::SetLineProtocol(bool x
)
1423 StreamSocket::SetLineProtocol(x
);
1424 DisableInputBuffer(x
);
1428 bool TcpSocket::SetTcpNodelay(bool x
)
1431 int optval
= x
? 1 : 0;
1432 if (setsockopt(GetSocket(), IPPROTO_TCP
, TCP_NODELAY
, (char *)&optval
, sizeof(optval
)) == -1)
1434 Handler().LogError(this, "setsockopt(IPPROTO_TCP, TCP_NODELAY)", Errno
, StrError(Errno
), LOG_LEVEL_FATAL
);
1439 Handler().LogError(this, "socket option not available", 0, "TCP_NODELAY", LOG_LEVEL_INFO
);
1445 TcpSocket::CircularBuffer::CircularBuffer(size_t size
)
1446 :buf(new char[2 * size
])
1456 TcpSocket::CircularBuffer::~CircularBuffer()
1462 bool TcpSocket::CircularBuffer::Write(const char *s
,size_t l
)
1464 if (m_q
+ l
> m_max
)
1466 return false; // overflow
1468 m_count
+= (unsigned long)l
;
1469 if (m_t
+ l
> m_max
) // block crosses circular border
1471 size_t l1
= m_max
- m_t
; // size left until circular border crossing
1472 // always copy full block to buffer(buf) + top pointer(m_t)
1473 // because we have doubled the buffer size for performance reasons
1474 memcpy(buf
+ m_t
, s
, l
);
1475 memcpy(buf
, s
+ l1
, l
- l1
);
1481 memcpy(buf
+ m_t
, s
, l
);
1482 memcpy(buf
+ m_max
+ m_t
, s
, l
);
1492 bool TcpSocket::CircularBuffer::Read(char *s
,size_t l
)
1496 return false; // not enough chars
1498 if (m_b
+ l
> m_max
) // block crosses circular border
1500 size_t l1
= m_max
- m_b
;
1503 memcpy(s
, buf
+ m_b
, l1
);
1504 memcpy(s
+ l1
, buf
, l
- l1
);
1513 memcpy(s
, buf
+ m_b
, l
);
1528 bool TcpSocket::CircularBuffer::Remove(size_t l
)
1530 return Read(NULL
, l
);
1534 size_t TcpSocket::CircularBuffer::GetLength()
1540 const char *TcpSocket::CircularBuffer::GetStart()
1546 size_t TcpSocket::CircularBuffer::GetL()
1548 return (m_b
+ m_q
> m_max
) ? m_max
- m_b
: m_q
;
1552 size_t TcpSocket::CircularBuffer::Space()
1558 unsigned long TcpSocket::CircularBuffer::ByteCounter(bool clear
)
1562 unsigned long x
= m_count
;
1570 std::string
TcpSocket::CircularBuffer::ReadString(size_t l
)
1572 char *sz
= new char[l
+ 1];
1573 if (!Read(sz
, l
)) // failed, debug printout in Read() method
1579 std::string tmp
= sz
;
1585 void TcpSocket::OnConnectTimeout()
1587 Handler().LogError(this, "connect", -1, "connect timeout", LOG_LEVEL_FATAL
);
1588 #ifdef ENABLE_SOCKS4
1591 OnSocks4ConnectFailed();
1592 // retry direct connection
1596 if (GetConnectionRetry() == -1 ||
1597 (GetConnectionRetry() && GetConnectionRetries() < GetConnectionRetry()) )
1599 IncreaseConnectionRetries();
1600 // ask socket via OnConnectRetry callback if we should continue trying
1601 if (OnConnectRetry())
1603 SetRetryClientConnect();
1607 SetCloseAndDelete( true );
1608 /// \todo state reason why connect failed
1614 SetCloseAndDelete(true);
1615 /// \todo state reason why connect failed
1619 SetConnecting(false);
1624 void TcpSocket::OnException()
1628 #ifdef ENABLE_SOCKS4
1630 OnSocks4ConnectFailed();
1633 if (GetConnectionRetry() == -1 ||
1634 (GetConnectionRetry() &&
1635 GetConnectionRetries() < GetConnectionRetry() ))
1637 // even though the connection failed at once, only retry after
1638 // the connection timeout
1639 // should we even try to connect again, when CheckConnect returns
1640 // false it's because of a connection error - not a timeout...
1644 SetConnecting(false); // tnx snibbe
1645 SetCloseAndDelete();
1650 // %! exception doesn't always mean something bad happened, this code should be reworked
1651 // errno valid here?
1652 int err
= SoError();
1653 Handler().LogError(this, "exception on select", err
, StrError(err
), LOG_LEVEL_FATAL
);
1654 SetCloseAndDelete();
1659 int TcpSocket::Protocol()
1665 #ifdef SOCKETS_NAMESPACE