root/trunk/dep/src/sockets/TcpSocket.cpp @ 2

Revision 2, 34.3 kB (checked in by yumileroy, 17 years ago)

[svn] * Proper SVN structure

Original author: Neo2003
Date: 2008-10-02 16:23:55-05:00

Line 
1/** \file TcpSocket.cpp
2 **     \date  2004-02-13
3 **     \author grymse@alhem.net
4**/
5/*
6Copyright (C) 2004-2007  Anders Hedstrom
7
8This library is made available under the terms of the GNU GPL.
9
10If you would like to use this library in a closed-source application,
11a separate license agreement is available. For information about
12the closed-source license agreement for the C++ sockets library,
13please visit http://www.alhem.net/Sockets/license.html and/or
14email license@alhem.net.
15
16This program is free software; you can redistribute it and/or
17modify it under the terms of the GNU General Public License
18as published by the Free Software Foundation; either version 2
19of the License, or (at your option) any later version.
20
21This program is distributed in the hope that it will be useful,
22but WITHOUT ANY WARRANTY; without even the implied warranty of
23MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24GNU General Public License for more details.
25
26You should have received a copy of the GNU General Public License
27along with this program; if not, write to the Free Software
28Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
29*/
30#ifdef _WIN32
31#ifdef _MSC_VER
32#pragma warning(disable:4786)
33#endif
34#include <stdlib.h>
35#else
36#include <errno.h>
37#endif
38#include "ISocketHandler.h"
39#include <fcntl.h>
40#include <assert.h>
41#include <stdarg.h>
42#ifdef HAVE_OPENSSL
43#include <openssl/rand.h>
44#include <openssl/err.h>
45#endif
46#include <map>
47
48#include "TcpSocket.h"
49#include "Utility.h"
50#include "Ipv4Address.h"
51#include "Ipv6Address.h"
52#include "Mutex.h"
53#include "IFile.h"
54
55#ifdef SOCKETS_NAMESPACE
56namespace SOCKETS_NAMESPACE {
57#endif
58
59
60//#ifdef _DEBUG
61//#define DEB(x) x
62//#else
63#define DEB(x)
64//#endif
65
66
67// statics
68#ifdef HAVE_OPENSSL
69SSLInitializer TcpSocket::m_ssl_init;
70#endif
71
72
73// thanks, q
74#ifdef _MSC_VER
75#pragma warning(disable:4355)
76#endif
77TcpSocket::TcpSocket(ISocketHandler& h) : StreamSocket(h)
78,ibuf(TCP_BUFSIZE_READ)
79,m_b_input_buffer_disabled(false)
80,m_bytes_sent(0)
81,m_bytes_received(0)
82,m_skip_c(false)
83#ifdef SOCKETS_DYNAMIC_TEMP
84,m_buf(new char[TCP_BUFSIZE_READ + 1])
85#endif
86,m_obuf_top(NULL)
87,m_transfer_limit(0)
88,m_output_length(0)
89#ifdef HAVE_OPENSSL
90,m_ssl_ctx(NULL)
91,m_ssl(NULL)
92,m_sbio(NULL)
93#endif
94#ifdef ENABLE_SOCKS4
95,m_socks4_state(0)
96#endif
97#ifdef ENABLE_RESOLVER
98,m_resolver_id(0)
99#endif
100#ifdef ENABLE_RECONNECT
101,m_b_reconnect(false)
102,m_b_is_reconnect(false)
103#endif
104{
105}
106#ifdef _MSC_VER
107#pragma warning(default:4355)
108#endif
109
110
111#ifdef _MSC_VER
112#pragma warning(disable:4355)
113#endif
114TcpSocket::TcpSocket(ISocketHandler& h,size_t isize,size_t osize) : StreamSocket(h)
115,ibuf(isize)
116,m_b_input_buffer_disabled(false)
117,m_bytes_sent(0)
118,m_bytes_received(0)
119,m_skip_c(false)
120#ifdef SOCKETS_DYNAMIC_TEMP
121,m_buf(new char[TCP_BUFSIZE_READ + 1])
122#endif
123,m_obuf_top(NULL)
124,m_transfer_limit(0)
125,m_output_length(0)
126#ifdef HAVE_OPENSSL
127,m_ssl_ctx(NULL)
128,m_ssl(NULL)
129,m_sbio(NULL)
130#endif
131#ifdef ENABLE_SOCKS4
132,m_socks4_state(0)
133#endif
134#ifdef ENABLE_RESOLVER
135,m_resolver_id(0)
136#endif
137#ifdef ENABLE_RECONNECT
138,m_b_reconnect(false)
139,m_b_is_reconnect(false)
140#endif
141{
142}
143#ifdef _MSC_VER
144#pragma warning(default:4355)
145#endif
146
147
148TcpSocket::~TcpSocket()
149{
150#ifdef SOCKETS_DYNAMIC_TEMP
151        delete[] m_buf;
152#endif
153        // %! empty m_obuf
154        while (m_obuf.size())
155        {
156                output_l::iterator it = m_obuf.begin();
157                OUTPUT *p = *it;
158                delete p;
159                m_obuf.erase(it);
160        }
161#ifdef HAVE_OPENSSL
162        if (m_ssl)
163        {
164                SSL_free(m_ssl);
165        }
166#endif
167}
168
169
170bool TcpSocket::Open(ipaddr_t ip,port_t port,bool skip_socks)
171{
172        Ipv4Address ad(ip, port);
173        Ipv4Address local;
174        return Open(ad, local, skip_socks);
175}
176
177
178#ifdef ENABLE_IPV6
179#ifdef IPPROTO_IPV6
180bool TcpSocket::Open(in6_addr ip,port_t port,bool skip_socks)
181{
182        Ipv6Address ad(ip, port);
183        return Open(ad, skip_socks);
184}
185#endif
186#endif
187
188
189bool TcpSocket::Open(SocketAddress& ad,bool skip_socks)
190{
191        Ipv4Address bind_ad("0.0.0.0", 0);
192        return Open(ad, bind_ad, skip_socks);
193}
194
195
196bool TcpSocket::Open(SocketAddress& ad,SocketAddress& bind_ad,bool skip_socks)
197{
198        if (!ad.IsValid())
199        {
200                Handler().LogError(this, "Open", 0, "Invalid SocketAddress", LOG_LEVEL_FATAL);
201                SetCloseAndDelete();
202                return false;
203        }
204        if (Handler().GetCount() >= FD_SETSIZE)
205        {
206                Handler().LogError(this, "Open", 0, "no space left in fd_set", LOG_LEVEL_FATAL);
207                SetCloseAndDelete();
208                return false;
209        }
210        SetConnecting(false);
211#ifdef ENABLE_SOCKS4
212        SetSocks4(false);
213#endif
214        // check for pooling
215#ifdef ENABLE_POOL
216        if (Handler().PoolEnabled())
217        {
218                ISocketHandler::PoolSocket *pools = Handler().FindConnection(SOCK_STREAM, "tcp", ad);
219                if (pools)
220                {
221                        CopyConnection( pools );
222                        delete pools;
223
224                        SetIsClient();
225                        SetCallOnConnect(); // ISocketHandler must call OnConnect
226                        Handler().LogError(this, "SetCallOnConnect", 0, "Found pooled connection", LOG_LEVEL_INFO);
227                        return true;
228                }
229        }
230#endif
231        // if not, create new connection
232        SOCKET s = CreateSocket(ad.GetFamily(), SOCK_STREAM, "tcp");
233        if (s == INVALID_SOCKET)
234        {
235                return false;
236        }
237        // socket must be nonblocking for async connect
238        if (!SetNonblocking(true, s))
239        {
240                SetCloseAndDelete();
241                closesocket(s);
242                return false;
243        }
244#ifdef ENABLE_POOL
245        SetIsClient(); // client because we connect
246#endif
247        SetClientRemoteAddress(ad);
248        int n = 0;
249        if (bind_ad.GetPort() != 0)
250        {
251                bind(s, bind_ad, bind_ad);
252        }
253#ifdef ENABLE_SOCKS4
254        if (!skip_socks && GetSocks4Host() && GetSocks4Port())
255        {
256                Ipv4Address sa(GetSocks4Host(), GetSocks4Port());
257                {
258                        std::string sockshost;
259                        Utility::l2ip(GetSocks4Host(), sockshost);
260                        Handler().LogError(this, "Open", 0, "Connecting to socks4 server @ " + sockshost + ":" +
261                                Utility::l2string(GetSocks4Port()), LOG_LEVEL_INFO);
262                }
263                SetSocks4();
264                n = connect(s, sa, sa);
265                SetRemoteAddress(sa);
266        }
267        else
268#endif
269        {
270                n = connect(s, ad, ad);
271                SetRemoteAddress(ad);
272        }
273        if (n == -1)
274        {
275                // check error code that means a connect is in progress
276#ifdef _WIN32
277                if (Errno == WSAEWOULDBLOCK)
278#else
279                if (Errno == EINPROGRESS)
280#endif
281                {
282                        Attach(s);
283                        SetConnecting( true ); // this flag will control fd_set's
284                }
285                else
286#ifdef ENABLE_SOCKS4
287                if (Socks4() && Handler().Socks4TryDirect() ) // retry
288                {
289                        closesocket(s);
290                        return Open(ad, true);
291                }
292                else
293#endif
294#ifdef ENABLE_RECONNECT
295                if (Reconnect())
296                {
297                        Handler().LogError(this, "connect: failed, reconnect pending", Errno, StrError(Errno), LOG_LEVEL_INFO);
298                        Attach(s);
299                        SetConnecting( true ); // this flag will control fd_set's
300                }
301                else
302#endif
303                {
304                        Handler().LogError(this, "connect: failed", Errno, StrError(Errno), LOG_LEVEL_FATAL);
305                        SetCloseAndDelete();
306                        closesocket(s);
307                        return false;
308                }
309        }
310        else
311        {
312                Attach(s);
313                SetCallOnConnect(); // ISocketHandler must call OnConnect
314        }
315
316        // 'true' means connected or connecting(not yet connected)
317        // 'false' means something failed
318        return true; //!Connecting();
319}
320
321
322bool TcpSocket::Open(const std::string &host,port_t port)
323{
324#ifdef ENABLE_IPV6
325#ifdef IPPROTO_IPV6
326        if (IsIpv6())
327        {
328#ifdef ENABLE_RESOLVER
329                if (!Handler().ResolverEnabled() || Utility::isipv6(host) )
330                {
331#endif
332                        in6_addr a;
333                        if (!Utility::u2ip(host, a))
334                        {
335                                SetCloseAndDelete();
336                                return false;
337                        }
338                        Ipv6Address ad(a, port);
339                        Ipv6Address local;
340                        return Open(ad, local);
341#ifdef ENABLE_RESOLVER
342                }
343                m_resolver_id = Resolve6(host, port);
344                return true;
345#endif
346        }
347#endif
348#endif
349#ifdef ENABLE_RESOLVER
350        if (!Handler().ResolverEnabled() || Utility::isipv4(host) )
351        {
352#endif
353                ipaddr_t l;
354                if (!Utility::u2ip(host,l))
355                {
356                        SetCloseAndDelete();
357                        return false;
358                }
359                Ipv4Address ad(l, port);
360                Ipv4Address local;
361                return Open(ad, local);
362#ifdef ENABLE_RESOLVER
363        }
364        // resolve using async resolver thread
365        m_resolver_id = Resolve(host, port);
366        return true;
367#endif
368}
369
370
371#ifdef ENABLE_RESOLVER
372void TcpSocket::OnResolved(int id,ipaddr_t a,port_t port)
373{
374DEB(    fprintf(stderr, "TcpSocket::OnResolved id %d addr %x port %d\n", id, a, port);)
375        if (id == m_resolver_id)
376        {
377                if (a && port)
378                {
379                        Ipv4Address ad(a, port);
380                        Ipv4Address local;
381                        if (Open(ad, local))
382                        {
383                                if (!Handler().Valid(this))
384                                {
385                                        Handler().Add(this);
386                                }
387                        }
388                }
389                else
390                {
391                        Handler().LogError(this, "OnResolved", 0, "Resolver failed", LOG_LEVEL_FATAL);
392                        SetCloseAndDelete();
393                }
394        }
395        else
396        {
397                Handler().LogError(this, "OnResolved", id, "Resolver returned wrong job id", LOG_LEVEL_FATAL);
398                SetCloseAndDelete();
399        }
400}
401
402
403#ifdef ENABLE_IPV6
404void TcpSocket::OnResolved(int id,in6_addr& a,port_t port)
405{
406        if (id == m_resolver_id)
407        {
408                Ipv6Address ad(a, port);
409                if (ad.IsValid())
410                {
411                        Ipv6Address local;
412                        if (Open(ad, local))
413                        {
414                                if (!Handler().Valid(this))
415                                {
416                                        Handler().Add(this);
417                                }
418                        }
419                }
420        }
421        else
422        {
423                Handler().LogError(this, "OnResolved", id, "Resolver returned wrong job id", LOG_LEVEL_FATAL);
424                SetCloseAndDelete();
425        }
426}
427#endif
428#endif
429
430
431void TcpSocket::OnRead()
432{
433        int n = 0;
434#ifdef SOCKETS_DYNAMIC_TEMP
435        char *buf = m_buf;
436#else
437        char buf[TCP_BUFSIZE_READ];
438#endif
439#ifdef HAVE_OPENSSL
440        if (IsSSL())
441        {
442                if (!Ready())
443                        return;
444                n = SSL_read(m_ssl, buf, TCP_BUFSIZE_READ);
445                if (n == -1)
446                {
447                        n = SSL_get_error(m_ssl, n);
448                        switch (n)
449                        {
450                        case SSL_ERROR_NONE:
451                        case SSL_ERROR_WANT_READ:
452                        case SSL_ERROR_WANT_WRITE:
453                                break;
454                        case SSL_ERROR_ZERO_RETURN:
455DEB(                            fprintf(stderr, "SSL_read() returns zero - closing socket\n");)
456                                OnDisconnect();
457                                SetCloseAndDelete(true);
458                                SetFlushBeforeClose(false);
459                                SetLost();
460                                break;
461                        default:
462DEB(                            fprintf(stderr, "SSL read problem, errcode = %d\n",n);)
463                                OnDisconnect();
464                                SetCloseAndDelete(true);
465                                SetFlushBeforeClose(false);
466                                SetLost();
467                        }
468                        return;
469                }
470                else
471                if (!n)
472                {
473                        OnDisconnect();
474                        SetCloseAndDelete(true);
475                        SetFlushBeforeClose(false);
476                        SetLost();
477                        SetShutdown(SHUT_WR);
478                        return;
479                }
480                else
481                if (n > 0 && n <= TCP_BUFSIZE_READ)
482                {
483                        m_bytes_received += n;
484                        if (GetTrafficMonitor())
485                        {
486                                GetTrafficMonitor() -> fwrite(buf, 1, n);
487                        }
488                        if (!m_b_input_buffer_disabled && !ibuf.Write(buf,n))
489                        {
490                                Handler().LogError(this, "OnRead(ssl)", 0, "ibuf overflow", LOG_LEVEL_WARNING);
491                        }
492                }
493                else
494                {
495                        Handler().LogError(this, "OnRead(ssl)", n, "abnormal value from SSL_read", LOG_LEVEL_ERROR);
496                }
497        }
498        else
499#endif // HAVE_OPENSSL
500        {
501                n = recv(GetSocket(), buf, TCP_BUFSIZE_READ, MSG_NOSIGNAL);
502                if (n == -1)
503                {
504                        Handler().LogError(this, "read", Errno, StrError(Errno), LOG_LEVEL_FATAL);
505                        OnDisconnect();
506                        SetCloseAndDelete(true);
507                        SetFlushBeforeClose(false);
508                        SetLost();
509                        return;
510                }
511                else
512                if (!n)
513                {
514                        OnDisconnect();
515                        SetCloseAndDelete(true);
516                        SetFlushBeforeClose(false);
517                        SetLost();
518                        SetShutdown(SHUT_WR);
519                        return;
520                }
521                else
522                if (n > 0 && n <= TCP_BUFSIZE_READ)
523                {
524                        m_bytes_received += n;
525                        if (GetTrafficMonitor())
526                        {
527                                GetTrafficMonitor() -> fwrite(buf, 1, n);
528                        }
529                        if (!m_b_input_buffer_disabled && !ibuf.Write(buf,n))
530                        {
531                                Handler().LogError(this, "OnRead", 0, "ibuf overflow", LOG_LEVEL_WARNING);
532                        }
533                }
534                else
535                {
536                        Handler().LogError(this, "OnRead", n, "abnormal value from recv", LOG_LEVEL_ERROR);
537                }
538        }
539        //
540        OnRead( buf, n );
541}
542
543
544void TcpSocket::OnRead( char *buf, size_t n )
545{
546        // unbuffered
547        if (n > 0 && n <= TCP_BUFSIZE_READ)
548        {
549                if (LineProtocol())
550                {
551                        buf[n] = 0;
552                        size_t i = 0;
553                        if (m_skip_c && (buf[i] == 13 || buf[i] == 10) && buf[i] != m_c)
554                        {
555                                m_skip_c = false;
556                                i++;
557                        }
558                        size_t x = i;
559                        for (; i < n && LineProtocol(); i++)
560                        {
561                                while ((buf[i] == 13 || buf[i] == 10) && LineProtocol())
562                                {
563                                        char c = buf[i];
564                                        buf[i] = 0;
565                                        if (buf[x])
566                                        {
567                                                m_line += (buf + x);
568                                        }
569                                        OnLine( m_line );
570                                        i++;
571                                        m_skip_c = true;
572                                        m_c = c;
573                                        if (i < n && (buf[i] == 13 || buf[i] == 10) && buf[i] != c)
574                                        {
575                                                m_skip_c = false;
576                                                i++;
577                                        }
578                                        x = i;
579                                        m_line = "";
580                                }
581                                if (!LineProtocol())
582                                {
583                                        break;
584                                }
585                        }
586                        if (!LineProtocol())
587                        {
588                                if (i < n)
589                                {
590                                        OnRawData(buf + i, n - i);
591                                }
592                        }
593                        else
594                        if (buf[x])
595                        {
596                                m_line += (buf + x);
597                        }
598                }
599                else
600                {
601                        OnRawData(buf, n);
602                }
603        }
604        if (m_b_input_buffer_disabled)
605        {
606                return;
607        }
608        // further processing: socks4
609#ifdef ENABLE_SOCKS4
610        if (Socks4())
611        {
612                bool need_more = false;
613                while (GetInputLength() && !need_more && !CloseAndDelete())
614                {
615                        need_more = OnSocks4Read();
616                }
617        }
618#endif
619}
620
621
622void TcpSocket::OnWriteComplete()
623{
624}
625
626
627void TcpSocket::OnWrite()
628{
629        if (Connecting())
630        {
631                int err = SoError();
632
633                // don't reset connecting flag on error here, we want the OnConnectFailed timeout later on
634                if (!err) // ok
635                {
636                        Set(!IsDisableRead(), false);
637                        SetConnecting(false);
638                        SetCallOnConnect();
639                        return;
640                }
641                Handler().LogError(this, "tcp: connect failed", err, StrError(err), LOG_LEVEL_FATAL);
642                Set(false, false); // no more monitoring because connection failed
643
644                // failed
645#ifdef ENABLE_SOCKS4
646                if (Socks4())
647                {
648                        // %! leave 'Connecting' flag set?
649                        OnSocks4ConnectFailed();
650                        return;
651                }
652#endif
653                if (GetConnectionRetry() == -1 ||
654                        (GetConnectionRetry() && GetConnectionRetries() < GetConnectionRetry()) )
655                {
656                        // even though the connection failed at once, only retry after
657                        // the connection timeout.
658                        // should we even try to connect again, when CheckConnect returns
659                        // false it's because of a connection error - not a timeout...
660                        return;
661                }
662                SetConnecting(false);
663                SetCloseAndDelete( true );
664                /// \todo state reason why connect failed
665                OnConnectFailed();
666                return;
667        }
668        // try send next block in buffer
669        // if full block is sent, repeat
670        // if all blocks are sent, reset m_wfds
671
672        bool repeat = false;
673        size_t sz = m_transfer_limit ? GetOutputLength() : 0;
674        do
675        {
676                output_l::iterator it = m_obuf.begin();
677                OUTPUT *p = *it;
678                repeat = false;
679                int n = TryWrite(p -> Buf(), p -> Len());
680                if (n > 0)
681                {
682                        size_t left = p -> Remove(n);
683                        m_output_length -= n;
684                        if (!left)
685                        {
686                                delete p;
687                                m_obuf.erase(it);
688                                if (!m_obuf.size())
689                                {
690                                        m_obuf_top = NULL;
691                                        OnWriteComplete();
692                                }
693                                else
694                                {
695                                        repeat = true;
696                                }
697                        }
698                }
699        } while (repeat);
700
701        if (m_transfer_limit && sz > m_transfer_limit && GetOutputLength() < m_transfer_limit)
702        {
703                OnTransferLimit();
704        }
705
706        // check output buffer set, set/reset m_wfds accordingly
707        {
708                bool br;
709                bool bw;
710                bool bx;
711                Handler().Get(GetSocket(), br, bw, bx);
712                if (m_obuf.size())
713                        Set(br, true);
714                else
715                        Set(br, false);
716        }
717}
718
719
720int TcpSocket::TryWrite(const char *buf, size_t len)
721{
722        int n = 0;
723#ifdef HAVE_OPENSSL
724        if (IsSSL())
725        {
726                n = SSL_write(m_ssl, buf, (int)len);
727                if (n == -1)
728                {
729                        int errnr = SSL_get_error(m_ssl, n);
730                        if ( errnr != SSL_ERROR_WANT_READ && errnr != SSL_ERROR_WANT_WRITE )
731                        {
732                                OnDisconnect();
733                                SetCloseAndDelete(true);
734                                SetFlushBeforeClose(false);
735                                SetLost();
736                                const char *errbuf = ERR_error_string(errnr, NULL);
737                                Handler().LogError(this, "OnWrite/SSL_write", errnr, errbuf, LOG_LEVEL_FATAL);
738                        }
739                        return 0;
740                }
741                else
742                if (!n)
743                {
744                        OnDisconnect();
745                        SetCloseAndDelete(true);
746                        SetFlushBeforeClose(false);
747                        SetLost();
748DEB(                    int errnr = SSL_get_error(m_ssl, n);
749                        const char *errbuf = ERR_error_string(errnr, NULL);
750                        fprintf(stderr, "SSL_write() returns 0: %d : %s\n",errnr, errbuf);)
751                }
752        }
753        else
754#endif // HAVE_OPENSSL
755        {
756                n = send(GetSocket(), buf, (int)len, MSG_NOSIGNAL);
757                if (n == -1)
758                {
759                // normal error codes:
760                // WSAEWOULDBLOCK
761                //       EAGAIN or EWOULDBLOCK
762#ifdef _WIN32
763                        if (Errno != WSAEWOULDBLOCK)
764#else
765                        if (Errno != EWOULDBLOCK)
766#endif
767                        {       
768                                Handler().LogError(this, "send", Errno, StrError(Errno), LOG_LEVEL_FATAL);
769                                OnDisconnect();
770                                SetCloseAndDelete(true);
771                                SetFlushBeforeClose(false);
772                                SetLost();
773                        }
774                        return 0;
775                }
776        }
777        if (n > 0)
778        {
779                m_bytes_sent += n;
780                if (GetTrafficMonitor())
781                {
782                        GetTrafficMonitor() -> fwrite(buf, 1, n);
783                }
784        }
785        return n;
786}
787
788
789void TcpSocket::Buffer(const char *buf, size_t len)
790{
791        size_t ptr = 0;
792        m_output_length += len;
793        while (ptr < len)
794        {
795                // buf/len => pbuf/sz
796                size_t space = 0;
797                if (m_obuf_top && (space = m_obuf_top -> Space()) > 0)
798                {
799                        const char *pbuf = buf + ptr;
800                        size_t sz = len - ptr;
801                        if (space >= sz)
802                        {
803                                m_obuf_top -> Add(pbuf, sz);
804                                ptr += sz;
805                        }
806                        else
807                        {
808                                m_obuf_top -> Add(pbuf, space);
809                                ptr += space;
810                        }
811                }
812                else
813                {
814                        m_obuf_top = new OUTPUT;
815                        m_obuf.push_back( m_obuf_top );
816                }
817        }
818}
819
820
821void TcpSocket::Send(const std::string &str,int i)
822{
823        SendBuf(str.c_str(),str.size(),i);
824}
825
826
827void TcpSocket::SendBuf(const char *buf,size_t len,int)
828{
829        if (!Ready() && !Connecting())
830        {
831                Handler().LogError(this, "SendBuf", -1, "Attempt to write to a non-ready socket" ); // warning
832                if (GetSocket() == INVALID_SOCKET)
833                        Handler().LogError(this, "SendBuf", 0, " * GetSocket() == INVALID_SOCKET", LOG_LEVEL_INFO);
834                if (Connecting())
835                        Handler().LogError(this, "SendBuf", 0, " * Connecting()", LOG_LEVEL_INFO);
836                if (CloseAndDelete())
837                        Handler().LogError(this, "SendBuf", 0, " * CloseAndDelete()", LOG_LEVEL_INFO);
838                return;
839        }
840        if (!IsConnected())
841        {
842                Handler().LogError(this, "SendBuf", -1, "Attempt to write to a non-connected socket, will be sent on connect" ); // warning
843                Buffer(buf, len);
844                return;
845        }
846        if (m_obuf_top)
847        {
848                Buffer(buf, len);
849                return;
850        }
851        int n = TryWrite(buf, len);
852        if (n >= 0 && n < (int)len)
853        {
854                Buffer(buf + n, len - n);
855        }
856        // if ( data in buffer || !IsConnected )
857        // {
858        //   add to buffer
859        // }
860        // else
861        // try_send
862        // if any data is unsent, buffer it and set m_wfds
863
864        // check output buffer set, set/reset m_wfds accordingly
865        {
866                bool br;
867                bool bw;
868                bool bx;
869                Handler().Get(GetSocket(), br, bw, bx);
870                if (m_obuf.size())
871                        Set(br, true);
872                else
873                        Set(br, false);
874        }
875}
876
877
878void TcpSocket::OnLine(const std::string& )
879{
880}
881
882
883#ifdef _MSC_VER
884#pragma warning(disable:4355)
885#endif
886TcpSocket::TcpSocket(const TcpSocket& s)
887:StreamSocket(s)
888,ibuf(0)
889{
890}
891#ifdef _MSC_VER
892#pragma warning(default:4355)
893#endif
894
895
896#ifdef ENABLE_SOCKS4
897void TcpSocket::OnSocks4Connect()
898{
899        char request[1000];
900        memset(request, 0, sizeof(request));
901        request[0] = 4; // socks v4
902        request[1] = 1; // command code: CONNECT
903        {
904                std::auto_ptr<SocketAddress> ad = GetClientRemoteAddress();
905                if (ad.get())
906                {
907                        struct sockaddr *p0 = (struct sockaddr *)*ad;
908                        struct sockaddr_in *p = (struct sockaddr_in *)p0;
909                        if (p -> sin_family == AF_INET)
910                        {
911                                memcpy(request + 2, &p -> sin_port, 2); // nwbo is ok here
912                                memcpy(request + 4, &p -> sin_addr, sizeof(struct in_addr));
913                        }
914                        else
915                        {
916                                /// \todo warn
917                        }
918                }
919                else
920                {
921                        /// \todo warn
922                }
923        }
924        strcpy(request + 8, GetSocks4Userid().c_str());
925        size_t length = GetSocks4Userid().size() + 8 + 1;
926        SendBuf(request, length);
927        m_socks4_state = 0;
928}
929
930
931void TcpSocket::OnSocks4ConnectFailed()
932{
933        Handler().LogError(this,"OnSocks4ConnectFailed",0,"connection to socks4 server failed, trying direct connection",LOG_LEVEL_WARNING);
934        if (!Handler().Socks4TryDirect())
935        {
936                SetConnecting(false);
937                SetCloseAndDelete();
938                OnConnectFailed(); // just in case
939        }
940        else
941        {
942                SetRetryClientConnect();
943        }
944}
945
946
947bool TcpSocket::OnSocks4Read()
948{
949        switch (m_socks4_state)
950        {
951        case 0:
952                ibuf.Read(&m_socks4_vn, 1);
953                m_socks4_state = 1;
954                break;
955        case 1:
956                ibuf.Read(&m_socks4_cd, 1);
957                m_socks4_state = 2;
958                break;
959        case 2:
960                if (GetInputLength() > 1)
961                {
962                        ibuf.Read( (char *)&m_socks4_dstport, 2);
963                        m_socks4_state = 3;
964                }
965                else
966                {
967                        return true;
968                }
969                break;
970        case 3:
971                if (GetInputLength() > 3)
972                {
973                        ibuf.Read( (char *)&m_socks4_dstip, 4);
974                        SetSocks4(false);
975                       
976                        switch (m_socks4_cd)
977                        {
978                        case 90:
979                                OnConnect();
980                                Handler().LogError(this, "OnSocks4Read", 0, "Connection established", LOG_LEVEL_INFO);
981                                break;
982                        case 91:
983                        case 92:
984                        case 93:
985                                Handler().LogError(this,"OnSocks4Read",m_socks4_cd,"socks4 server reports connect failed",LOG_LEVEL_FATAL);
986                                SetConnecting(false);
987                                SetCloseAndDelete();
988                                OnConnectFailed();
989                                break;
990                        default:
991                                Handler().LogError(this,"OnSocks4Read",m_socks4_cd,"socks4 server unrecognized response",LOG_LEVEL_FATAL);
992                                SetCloseAndDelete();
993                                break;
994                        }
995                }
996                else
997                {
998                        return true;
999                }
1000                break;
1001        }
1002        return false;
1003}
1004#endif
1005
1006
1007void TcpSocket::Sendf(const char *format, ...)
1008{
1009        va_list ap;
1010        va_start(ap, format);
1011        char slask[5000]; // vsprintf / vsnprintf temporary
1012#ifdef _WIN32
1013        vsprintf(slask, format, ap);
1014#else
1015        vsnprintf(slask, 5000, format, ap);
1016#endif
1017        va_end(ap);
1018        Send( slask );
1019}
1020
1021
1022#ifdef HAVE_OPENSSL
1023void TcpSocket::OnSSLConnect()
1024{
1025        SetNonblocking(true);
1026        {
1027                if (m_ssl_ctx)
1028                {
1029DEB(                    fprintf(stderr, "SSL Context already initialized - closing socket\n");)
1030                        SetCloseAndDelete(true);
1031                        return;
1032                }
1033                InitSSLClient();
1034        }
1035        if (m_ssl_ctx)
1036        {
1037                /* Connect the SSL socket */
1038                m_ssl = SSL_new(m_ssl_ctx);
1039                if (!m_ssl)
1040                {
1041DEB(                    fprintf(stderr, " m_ssl is NULL\n");)
1042                        SetCloseAndDelete(true);
1043                        return;
1044                }
1045                SSL_set_mode(m_ssl, SSL_MODE_AUTO_RETRY);
1046                m_sbio = BIO_new_socket((int)GetSocket(), BIO_NOCLOSE);
1047                if (!m_sbio)
1048                {
1049DEB(                    fprintf(stderr, " m_sbio is NULL\n");)
1050                        SetCloseAndDelete(true);
1051                        return;
1052                }
1053                SSL_set_bio(m_ssl, m_sbio, m_sbio);
1054                if (!SSLNegotiate())
1055                {
1056                        SetSSLNegotiate();
1057                }
1058        }
1059        else
1060        {
1061                SetCloseAndDelete();
1062        }
1063}
1064
1065
1066void TcpSocket::OnSSLAccept()
1067{
1068        SetNonblocking(true);
1069        {
1070                if (m_ssl_ctx)
1071                {
1072DEB(                    fprintf(stderr, "SSL Context already initialized - closing socket\n");)
1073                        SetCloseAndDelete(true);
1074                        return;
1075                }
1076                InitSSLServer();
1077                SetSSLServer();
1078        }
1079        if (m_ssl_ctx)
1080        {
1081                m_ssl = SSL_new(m_ssl_ctx);
1082                if (!m_ssl)
1083                {
1084DEB(                    fprintf(stderr, " m_ssl is NULL\n");)
1085                        SetCloseAndDelete(true);
1086                        return;
1087                }
1088                SSL_set_mode(m_ssl, SSL_MODE_AUTO_RETRY);
1089                m_sbio = BIO_new_socket((int)GetSocket(), BIO_NOCLOSE);
1090                if (!m_sbio)
1091                {
1092DEB(                    fprintf(stderr, " m_sbio is NULL\n");)
1093                        SetCloseAndDelete(true);
1094                        return;
1095                }
1096                SSL_set_bio(m_ssl, m_sbio, m_sbio);
1097//              if (!SSLNegotiate())
1098                {
1099                        SetSSLNegotiate();
1100                }
1101        }
1102}
1103
1104
1105bool TcpSocket::SSLNegotiate()
1106{
1107        if (!IsSSLServer()) // client
1108        {
1109                int r = SSL_connect(m_ssl);
1110                if (r > 0)
1111                {
1112                        SetSSLNegotiate(false);
1113                        /// \todo: resurrect certificate check... client
1114//                      CheckCertificateChain( "");//ServerHOST);
1115                        SetNonblocking(false);
1116                        //
1117                        {
1118                                SetConnected();
1119                                if (GetOutputLength())
1120                                {
1121                                        OnWrite();
1122                                }
1123                        }
1124#ifdef ENABLE_RECONNECT
1125                        if (IsReconnect())
1126                                OnReconnect();
1127                        else
1128#endif
1129                        {
1130                                OnConnect();
1131                        }
1132                        Handler().LogError(this, "SSLNegotiate/SSL_connect", 0, "Connection established", LOG_LEVEL_INFO);
1133                        return true;
1134                }
1135                else
1136                if (!r)
1137                {
1138                        Handler().LogError(this, "SSLNegotiate/SSL_connect", 0, "Connection failed", LOG_LEVEL_INFO);
1139                        SetSSLNegotiate(false);
1140                        SetCloseAndDelete();
1141                        OnSSLConnectFailed();
1142                }
1143                else
1144                {
1145                        r = SSL_get_error(m_ssl, r);
1146                        if (r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE)
1147                        {
1148                                Handler().LogError(this, "SSLNegotiate/SSL_connect", -1, "Connection failed", LOG_LEVEL_INFO);
1149DEB(                            fprintf(stderr, "SSL_connect() failed - closing socket, return code: %d\n",r);)
1150                                SetSSLNegotiate(false);
1151                                SetCloseAndDelete(true);
1152                                OnSSLConnectFailed();
1153                        }
1154                }
1155        }
1156        else // server
1157        {
1158                int r = SSL_accept(m_ssl);
1159                if (r > 0)
1160                {
1161                        SetSSLNegotiate(false);
1162                        /// \todo: resurrect certificate check... server
1163//                      CheckCertificateChain( "");//ClientHOST);
1164                        SetNonblocking(false);
1165                        //
1166                        {
1167                                SetConnected();
1168                                if (GetOutputLength())
1169                                {
1170                                        OnWrite();
1171                                }
1172                        }
1173                        OnAccept();
1174                        Handler().LogError(this, "SSLNegotiate/SSL_accept", 0, "Connection established", LOG_LEVEL_INFO);
1175                        return true;
1176                }
1177                else
1178                if (!r)
1179                {
1180                        Handler().LogError(this, "SSLNegotiate/SSL_accept", 0, "Connection failed", LOG_LEVEL_INFO);
1181                        SetSSLNegotiate(false);
1182                        SetCloseAndDelete();
1183                        OnSSLAcceptFailed();
1184                }
1185                else
1186                {
1187                        r = SSL_get_error(m_ssl, r);
1188                        if (r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE)
1189                        {
1190                                Handler().LogError(this, "SSLNegotiate/SSL_accept", -1, "Connection failed", LOG_LEVEL_INFO);
1191DEB(                            fprintf(stderr, "SSL_accept() failed - closing socket, return code: %d\n",r);)
1192                                SetSSLNegotiate(false);
1193                                SetCloseAndDelete(true);
1194                                OnSSLAcceptFailed();
1195                        }
1196                }
1197        }
1198        return false;
1199}
1200
1201
1202void TcpSocket::InitSSLClient()
1203{
1204        InitializeContext("", SSLv23_method());
1205}
1206
1207
1208void TcpSocket::InitSSLServer()
1209{
1210        Handler().LogError(this, "InitSSLServer", 0, "You MUST implement your own InitSSLServer method", LOG_LEVEL_FATAL);
1211        SetCloseAndDelete();
1212}
1213
1214
1215void TcpSocket::InitializeContext(const std::string& context, SSL_METHOD *meth_in)
1216{
1217        /* Create our context*/
1218        static std::map<std::string, SSL_CTX *> client_contexts;
1219        if (client_contexts.find(context) == client_contexts.end())
1220        {
1221                SSL_METHOD *meth = meth_in ? meth_in : SSLv3_method();
1222                m_ssl_ctx = client_contexts[context] = SSL_CTX_new(meth);
1223                SSL_CTX_set_mode(m_ssl_ctx, SSL_MODE_AUTO_RETRY);
1224        }
1225        else
1226        {
1227                m_ssl_ctx = client_contexts[context];
1228        }
1229}
1230
1231
1232void TcpSocket::InitializeContext(const std::string& context,const std::string& keyfile,const std::string& password,SSL_METHOD *meth_in)
1233{
1234        /* Create our context*/
1235        static std::map<std::string, SSL_CTX *> server_contexts;
1236        if (server_contexts.find(context) == server_contexts.end())
1237        {
1238                SSL_METHOD *meth = meth_in ? meth_in : SSLv3_method();
1239                m_ssl_ctx = server_contexts[context] = SSL_CTX_new(meth);
1240                SSL_CTX_set_mode(m_ssl_ctx, SSL_MODE_AUTO_RETRY);
1241                // session id
1242                if (!context.empty())
1243                        SSL_CTX_set_session_id_context(m_ssl_ctx, (const unsigned char *)context.c_str(), (unsigned int)context.size());
1244                else
1245                        SSL_CTX_set_session_id_context(m_ssl_ctx, (const unsigned char *)"--empty--", 9);
1246        }
1247        else
1248        {
1249                m_ssl_ctx = server_contexts[context];
1250        }
1251
1252        /* Load our keys and certificates*/
1253        if (!(SSL_CTX_use_certificate_file(m_ssl_ctx, keyfile.c_str(), SSL_FILETYPE_PEM)))
1254        {
1255                Handler().LogError(this, "TcpSocket InitializeContext", 0, "Couldn't read certificate file " + keyfile, LOG_LEVEL_FATAL);
1256        }
1257
1258        m_password = password;
1259        SSL_CTX_set_default_passwd_cb(m_ssl_ctx, SSL_password_cb);
1260        SSL_CTX_set_default_passwd_cb_userdata(m_ssl_ctx, this);
1261        if (!(SSL_CTX_use_PrivateKey_file(m_ssl_ctx, keyfile.c_str(), SSL_FILETYPE_PEM)))
1262        {
1263                Handler().LogError(this, "TcpSocket InitializeContext", 0, "Couldn't read private key file " + keyfile, LOG_LEVEL_FATAL);
1264        }
1265}
1266
1267
1268void TcpSocket::InitializeContext(const std::string& context,const std::string& certfile,const std::string& keyfile,const std::string& password,SSL_METHOD *meth_in)
1269{
1270        /* Create our context*/
1271        static std::map<std::string, SSL_CTX *> server_contexts;
1272        if (server_contexts.find(context) == server_contexts.end())
1273        {
1274                SSL_METHOD *meth = meth_in ? meth_in : SSLv3_method();
1275                m_ssl_ctx = server_contexts[context] = SSL_CTX_new(meth);
1276                SSL_CTX_set_mode(m_ssl_ctx, SSL_MODE_AUTO_RETRY);
1277                // session id
1278                if (context.size())
1279                        SSL_CTX_set_session_id_context(m_ssl_ctx, (const unsigned char *)context.c_str(), (unsigned int)context.size());
1280                else
1281                        SSL_CTX_set_session_id_context(m_ssl_ctx, (const unsigned char *)"--empty--", 9);
1282        }
1283        else
1284        {
1285                m_ssl_ctx = server_contexts[context];
1286        }
1287
1288        /* Load our keys and certificates*/
1289        if (!(SSL_CTX_use_certificate_file(m_ssl_ctx, certfile.c_str(), SSL_FILETYPE_PEM)))
1290        {
1291                Handler().LogError(this, "TcpSocket InitializeContext", 0, "Couldn't read certificate file " + keyfile, LOG_LEVEL_FATAL);
1292        }
1293
1294        m_password = password;
1295        SSL_CTX_set_default_passwd_cb(m_ssl_ctx, SSL_password_cb);
1296        SSL_CTX_set_default_passwd_cb_userdata(m_ssl_ctx, this);
1297        if (!(SSL_CTX_use_PrivateKey_file(m_ssl_ctx, keyfile.c_str(), SSL_FILETYPE_PEM)))
1298        {
1299                Handler().LogError(this, "TcpSocket InitializeContext", 0, "Couldn't read private key file " + keyfile, LOG_LEVEL_FATAL);
1300        }
1301}
1302
1303
1304int TcpSocket::SSL_password_cb(char *buf,int num,int rwflag,void *userdata)
1305{
1306        Socket *p0 = static_cast<Socket *>(userdata);
1307        TcpSocket *p = dynamic_cast<TcpSocket *>(p0);
1308        std::string pw = p ? p -> GetPassword() : "";
1309        if ( (size_t)num < pw.size() + 1)
1310        {
1311                return 0;
1312        }
1313        strcpy(buf,pw.c_str());
1314        return (int)pw.size();
1315}
1316#endif // HAVE_OPENSSL
1317
1318
1319int TcpSocket::Close()
1320{
1321        if (GetSocket() == INVALID_SOCKET) // this could happen
1322        {
1323                Handler().LogError(this, "Socket::Close", 0, "file descriptor invalid", LOG_LEVEL_WARNING);
1324                return 0;
1325        }
1326        int n;
1327        SetNonblocking(true);
1328        if (!Lost() && IsConnected() && !(GetShutdown() & SHUT_WR))
1329        {
1330                if (shutdown(GetSocket(), SHUT_WR) == -1)
1331                {
1332                        // failed...
1333                        Handler().LogError(this, "shutdown", Errno, StrError(Errno), LOG_LEVEL_ERROR);
1334                }
1335        }
1336        //
1337        char tmp[1000];
1338        if (!Lost() && (n = recv(GetSocket(),tmp,1000,0)) >= 0)
1339        {
1340                if (n)
1341                {
1342                        Handler().LogError(this, "read() after shutdown", n, "bytes read", LOG_LEVEL_WARNING);
1343                }
1344        }
1345#ifdef HAVE_OPENSSL
1346        if (IsSSL() && m_ssl)
1347                SSL_shutdown(m_ssl);
1348        if (m_ssl)
1349        {
1350                SSL_free(m_ssl);
1351                m_ssl = NULL;
1352        }
1353#endif
1354        return Socket::Close();
1355}
1356
1357
1358#ifdef HAVE_OPENSSL
1359SSL_CTX *TcpSocket::GetSslContext()
1360{
1361        if (!m_ssl_ctx)
1362                Handler().LogError(this, "GetSslContext", 0, "SSL Context is NULL; check InitSSLServer/InitSSLClient", LOG_LEVEL_WARNING);
1363        return m_ssl_ctx;
1364}
1365
1366SSL *TcpSocket::GetSsl()
1367{
1368        if (!m_ssl)
1369                Handler().LogError(this, "GetSsl", 0, "SSL is NULL; check InitSSLServer/InitSSLClient", LOG_LEVEL_WARNING);
1370        return m_ssl;
1371}
1372#endif
1373
1374
1375#ifdef ENABLE_RECONNECT
1376void TcpSocket::SetReconnect(bool x)
1377{
1378        m_b_reconnect = x;
1379}
1380#endif
1381
1382
1383void TcpSocket::OnRawData(const char *buf_in,size_t len)
1384{
1385}
1386
1387
1388size_t TcpSocket::GetInputLength()
1389{
1390        return ibuf.GetLength();
1391}
1392
1393
1394size_t TcpSocket::GetOutputLength()
1395{
1396        return m_output_length;
1397}
1398
1399
1400uint64_t TcpSocket::GetBytesReceived(bool clear)
1401{
1402        uint64_t z = m_bytes_received;
1403        if (clear)
1404                m_bytes_received = 0;
1405        return z;
1406}
1407
1408
1409uint64_t TcpSocket::GetBytesSent(bool clear)
1410{
1411        uint64_t z = m_bytes_sent;
1412        if (clear)
1413                m_bytes_sent = 0;
1414        return z;
1415}
1416
1417
1418#ifdef ENABLE_RECONNECT
1419bool TcpSocket::Reconnect()
1420{
1421        return m_b_reconnect;
1422}
1423
1424
1425void TcpSocket::SetIsReconnect(bool x)
1426{
1427        m_b_is_reconnect = x;
1428}
1429
1430
1431bool TcpSocket::IsReconnect()
1432{
1433        return m_b_is_reconnect;
1434}
1435#endif
1436
1437
1438#ifdef HAVE_OPENSSL
1439const std::string& TcpSocket::GetPassword()
1440{
1441        return m_password;
1442}
1443#endif
1444
1445
1446void TcpSocket::DisableInputBuffer(bool x)
1447{
1448        m_b_input_buffer_disabled = x;
1449}
1450
1451
1452void TcpSocket::OnOptions(int family,int type,int protocol,SOCKET s)
1453{
1454DEB(    fprintf(stderr, "Socket::OnOptions()\n");)
1455#ifdef SO_NOSIGPIPE
1456        SetSoNosigpipe(true);
1457#endif
1458        SetSoReuseaddr(true);
1459        SetSoKeepalive(true);
1460}
1461
1462
1463void TcpSocket::SetLineProtocol(bool x)
1464{
1465        StreamSocket::SetLineProtocol(x);
1466        DisableInputBuffer(x);
1467}
1468
1469
1470bool TcpSocket::SetTcpNodelay(bool x)
1471{
1472#ifdef TCP_NODELAY
1473        int optval = x ? 1 : 0;
1474        if (setsockopt(GetSocket(), IPPROTO_TCP, TCP_NODELAY, (char *)&optval, sizeof(optval)) == -1)
1475        {
1476                Handler().LogError(this, "setsockopt(IPPROTO_TCP, TCP_NODELAY)", Errno, StrError(Errno), LOG_LEVEL_FATAL);
1477                return false;
1478        }
1479        return true;
1480#else
1481        Handler().LogError(this, "socket option not available", 0, "TCP_NODELAY", LOG_LEVEL_INFO);
1482        return false;
1483#endif
1484}
1485
1486
1487TcpSocket::CircularBuffer::CircularBuffer(size_t size)
1488:buf(new char[2 * size])
1489,m_max(size)
1490,m_q(0)
1491,m_b(0)
1492,m_t(0)
1493,m_count(0)
1494{
1495}
1496
1497
1498TcpSocket::CircularBuffer::~CircularBuffer()
1499{
1500        delete[] buf;
1501}
1502
1503
1504bool TcpSocket::CircularBuffer::Write(const char *s,size_t l)
1505{
1506        if (m_q + l > m_max)
1507        {
1508                return false; // overflow
1509        }
1510        m_count += (unsigned long)l;
1511        if (m_t + l > m_max) // block crosses circular border
1512        {
1513                size_t l1 = m_max - m_t; // size left until circular border crossing
1514                // always copy full block to buffer(buf) + top pointer(m_t)
1515                // because we have doubled the buffer size for performance reasons
1516                memcpy(buf + m_t, s, l);
1517                memcpy(buf, s + l1, l - l1);
1518                m_t = l - l1;
1519                m_q += l;
1520        }
1521        else
1522        {
1523                memcpy(buf + m_t, s, l);
1524                memcpy(buf + m_max + m_t, s, l);
1525                m_t += l;
1526                if (m_t >= m_max)
1527                        m_t -= m_max;
1528                m_q += l;
1529        }
1530        return true;
1531}
1532
1533
1534bool TcpSocket::CircularBuffer::Read(char *s,size_t l)
1535{
1536        if (l > m_q)
1537        {
1538                return false; // not enough chars
1539        }
1540        if (m_b + l > m_max) // block crosses circular border
1541        {
1542                size_t l1 = m_max - m_b;
1543                if (s)
1544                {
1545                        memcpy(s, buf + m_b, l1);
1546                        memcpy(s + l1, buf, l - l1);
1547                }
1548                m_b = l - l1;
1549                m_q -= l;
1550        }
1551        else
1552        {
1553                if (s)
1554                {
1555                        memcpy(s, buf + m_b, l);
1556                }
1557                m_b += l;
1558                if (m_b >= m_max)
1559                        m_b -= m_max;
1560                m_q -= l;
1561        }
1562        if (!m_q)
1563        {
1564                m_b = m_t = 0;
1565        }
1566        return true;
1567}
1568
1569bool TcpSocket::CircularBuffer::SoftRead(char *s, size_t l)
1570{
1571    if (l > m_q)
1572    {
1573        return false;
1574    }
1575    if (m_b + l > m_max)                          // block crosses circular border
1576    {
1577        size_t l1 = m_max - m_b;
1578        if (s)
1579        {
1580            memcpy(s, buf + m_b, l1);
1581            memcpy(s + l1, buf, l - l1);
1582        }
1583    }
1584    else
1585    {
1586        if (s)
1587        {
1588            memcpy(s, buf + m_b, l);
1589        }
1590    }
1591    return true;
1592}
1593
1594bool TcpSocket::CircularBuffer::Remove(size_t l)
1595{
1596        return Read(NULL, l);
1597}
1598
1599
1600size_t TcpSocket::CircularBuffer::GetLength()
1601{
1602        return m_q;
1603}
1604
1605
1606const char *TcpSocket::CircularBuffer::GetStart()
1607{
1608        return buf + m_b;
1609}
1610
1611
1612size_t TcpSocket::CircularBuffer::GetL()
1613{
1614        return (m_b + m_q > m_max) ? m_max - m_b : m_q;
1615}
1616
1617
1618size_t TcpSocket::CircularBuffer::Space()
1619{
1620        return m_max - m_q;
1621}
1622
1623
1624unsigned long TcpSocket::CircularBuffer::ByteCounter(bool clear)
1625{
1626        if (clear)
1627        {
1628                unsigned long x = m_count;
1629                m_count = 0;
1630                return x;
1631        }
1632        return m_count;
1633}
1634
1635
1636std::string TcpSocket::CircularBuffer::ReadString(size_t l)
1637{
1638        char *sz = new char[l + 1];
1639        if (!Read(sz, l)) // failed, debug printout in Read() method
1640        {
1641                delete[] sz;
1642                return "";
1643        }
1644        sz[l] = 0;
1645        std::string tmp = sz;
1646        delete[] sz;
1647        return tmp;
1648}
1649
1650
1651void TcpSocket::OnConnectTimeout()
1652{
1653        Handler().LogError(this, "connect", -1, "connect timeout", LOG_LEVEL_FATAL);
1654#ifdef ENABLE_SOCKS4
1655        if (Socks4())
1656        {
1657                OnSocks4ConnectFailed();
1658                // retry direct connection
1659        }
1660        else
1661#endif
1662        if (GetConnectionRetry() == -1 ||
1663                (GetConnectionRetry() && GetConnectionRetries() < GetConnectionRetry()) )
1664        {
1665                IncreaseConnectionRetries();
1666                // ask socket via OnConnectRetry callback if we should continue trying
1667                if (OnConnectRetry())
1668                {
1669                        SetRetryClientConnect();
1670                }
1671                else
1672                {
1673                        SetCloseAndDelete( true );
1674                        /// \todo state reason why connect failed
1675                        OnConnectFailed();
1676                }
1677        }
1678        else
1679        {
1680                SetCloseAndDelete(true);
1681                /// \todo state reason why connect failed
1682                OnConnectFailed();
1683        }
1684        //
1685        SetConnecting(false);
1686}
1687
1688
1689#ifdef _WIN32
1690void TcpSocket::OnException()
1691{
1692        if (Connecting())
1693        {
1694#ifdef ENABLE_SOCKS4
1695                if (Socks4())
1696                        OnSocks4ConnectFailed();
1697                else
1698#endif
1699                if (GetConnectionRetry() == -1 ||
1700                        (GetConnectionRetry() &&
1701                         GetConnectionRetries() < GetConnectionRetry() ))
1702                {
1703                        // even though the connection failed at once, only retry after
1704                        // the connection timeout
1705                        // should we even try to connect again, when CheckConnect returns
1706                        // false it's because of a connection error - not a timeout...
1707                }
1708                else
1709                {
1710                        SetConnecting(false); // tnx snibbe
1711                        SetCloseAndDelete();
1712                        OnConnectFailed();
1713                }
1714                return;
1715        }
1716        // %! exception doesn't always mean something bad happened, this code should be reworked
1717        // errno valid here?
1718        int err = SoError();
1719        Handler().LogError(this, "exception on select", err, StrError(err), LOG_LEVEL_FATAL);
1720        SetCloseAndDelete();
1721}
1722#endif // _WIN32
1723
1724
1725int TcpSocket::Protocol()
1726{
1727        return IPPROTO_TCP;
1728}
1729
1730
1731void TcpSocket::SetTransferLimit(size_t sz)
1732{
1733        m_transfer_limit = sz;
1734}
1735
1736
1737void TcpSocket::OnTransferLimit()
1738{
1739}
1740
1741
1742#ifdef SOCKETS_NAMESPACE
1743}
1744#endif
1745
Note: See TracBrowser for help on using the browser.