source: filezilla/trunk/fuentes/src/engine/transfersocket.cpp @ 130

Last change on this file since 130 was 130, checked in by jrpelegrina, 3 years ago

First release to xenial

File size: 21.5 KB
Line 
1#include <filezilla.h>
2#include "directorylistingparser.h"
3#include "engineprivate.h"
4#include "ftpcontrolsocket.h"
5#include "iothread.h"
6#include "optionsbase.h"
7#include "tlssocket.h"
8#include "transfersocket.h"
9#include "proxy.h"
10#include "servercapabilities.h"
11
12CTransferSocket::CTransferSocket(CFileZillaEnginePrivate & engine, CFtpControlSocket & controlSocket, TransferMode transferMode)
13: CEventHandler(controlSocket.event_loop_)
14, engine_(engine)
15, controlSocket_(controlSocket)
16, m_transferMode(transferMode)
17{
18}
19
20CTransferSocket::~CTransferSocket()
21{
22        RemoveHandler();
23        if (m_transferEndReason == TransferEndReason::none)
24                m_transferEndReason = TransferEndReason::successful;
25        ResetSocket();
26
27        if (m_transferMode == TransferMode::upload || m_transferMode == TransferMode::download) {
28                if (ioThread_) {
29                        if (m_transferMode == TransferMode::download)
30                                FinalizeWrite();
31                        ioThread_->SetEventHandler(0);
32                }
33        }
34}
35
36void CTransferSocket::ResetSocket()
37{
38        delete m_pProxyBackend;
39        if( m_pBackend == m_pTlsSocket ) {
40                m_pBackend = 0;
41        }
42        delete m_pTlsSocket;
43        delete m_pBackend;
44        delete m_pSocketServer;
45        delete m_pSocket;
46        m_pProxyBackend = 0;
47        m_pTlsSocket = 0;
48        m_pBackend = 0;
49        m_pSocketServer = 0;
50        m_pSocket = 0;
51
52}
53
54wxString CTransferSocket::SetupActiveTransfer(const wxString& ip)
55{
56        ResetSocket();
57        m_pSocketServer = CreateSocketServer();
58
59        if (!m_pSocketServer) {
60                controlSocket_.LogMessage(MessageType::Debug_Warning, _T("CreateSocketServer failed"));
61                return wxString();
62        }
63
64        int error;
65        int port = m_pSocketServer->GetLocalPort(error);
66        if (port == -1) {
67                ResetSocket();
68
69                controlSocket_.LogMessage(MessageType::Debug_Warning, _T("GetLocalPort failed: %s"), CSocket::GetErrorDescription(error));
70                return wxString();
71        }
72
73        if (engine_.GetOptions().GetOptionVal(OPTION_LIMITPORTS)) {
74                port += static_cast<int>(engine_.GetOptions().GetOptionVal(OPTION_LIMITPORTS_OFFSET));
75                if (port <= 0 || port >= 65536) {
76                        controlSocket_.LogMessage(MessageType::Debug_Warning, _T("Port outside valid range"));
77                        return wxString();
78                }
79        }
80
81        wxString portArguments;
82        if (m_pSocketServer->GetAddressFamily() == CSocket::ipv6) {
83                portArguments = wxString::Format(_T("|2|%s|%d|"), ip, port);
84        }
85        else {
86                portArguments = ip;
87                portArguments += wxString::Format(_T(",%d,%d"), port / 256, port % 256);
88                portArguments.Replace(_T("."), _T(","));
89        }
90
91        return portArguments;
92}
93
94void CTransferSocket::OnSocketEvent(CSocketEventSource*, SocketEventType t, int error)
95{
96        if (m_pProxyBackend)
97        {
98                switch (t)
99                {
100                case SocketEventType::connection:
101                        {
102                                if (error) {
103                                        controlSocket_.LogMessage(MessageType::Error, _("Proxy handshake failed: %s"), CSocket::GetErrorDescription(error));
104                                        TransferEnd(TransferEndReason::failure);
105                                }
106                                else {
107                                        delete m_pProxyBackend;
108                                        m_pProxyBackend = 0;
109                                        OnConnect();
110                                }
111                        }
112                        return;
113                case SocketEventType::close:
114                        {
115                                controlSocket_.LogMessage(MessageType::Error, _("Proxy handshake failed: %s"), CSocket::GetErrorDescription(error));
116                                TransferEnd(TransferEndReason::failure);
117                        }
118                        return;
119                default:
120                        // Uninteresting
121                        break;
122                }
123                return;
124        }
125
126        if (m_pSocketServer) {
127                if (t == SocketEventType::connection)
128                        OnAccept(error);
129                else
130                        controlSocket_.LogMessage(MessageType::Debug_Info, _T("Unhandled socket event %d from listening socket"), t);
131                return;
132        }
133
134        switch (t)
135        {
136        case SocketEventType::connection:
137                if (error) {
138                        if (m_transferEndReason == TransferEndReason::none) {
139                                controlSocket_.LogMessage(MessageType::Error, _("The data connection could not be established: %s"), CSocket::GetErrorDescription(error));
140                                TransferEnd(TransferEndReason::transfer_failure);
141                        }
142                }
143                else
144                        OnConnect();
145                break;
146        case SocketEventType::read:
147                OnReceive();
148                break;
149        case SocketEventType::write:
150                OnSend();
151                break;
152        case SocketEventType::close:
153                OnClose(error);
154                break;
155        default:
156                // Uninteresting
157                break;
158        }
159}
160
161void CTransferSocket::OnAccept(int error)
162{
163        controlSocket_.SetAlive();
164        controlSocket_.LogMessage(MessageType::Debug_Verbose, _T("CTransferSocket::OnAccept(%d)"), error);
165
166        if (!m_pSocketServer)
167        {
168                controlSocket_.LogMessage(MessageType::Debug_Warning, _T("No socket server in OnAccept"), error);
169                return;
170        }
171
172        m_pSocket = m_pSocketServer->Accept(error);
173        if (!m_pSocket)
174        {
175                if (error == EAGAIN)
176                        controlSocket_.LogMessage(MessageType::Debug_Verbose, _T("No pending connection"));
177                else {
178                        controlSocket_.LogMessage(MessageType::Status, _("Could not accept connection: %s"), CSocket::GetErrorDescription(error));
179                        TransferEnd(TransferEndReason::transfer_failure);
180                }
181                return;
182        }
183        delete m_pSocketServer;
184        m_pSocketServer = 0;
185
186        OnConnect();
187}
188
189void CTransferSocket::OnConnect()
190{
191        controlSocket_.SetAlive();
192        controlSocket_.LogMessage(MessageType::Debug_Verbose, _T("CTransferSocket::OnConnect"));
193
194        if (!m_pSocket)
195        {
196                controlSocket_.LogMessage(MessageType::Debug_Verbose, _T("CTransferSocket::OnConnect called without socket"));
197                return;
198        }
199
200        if (!m_pBackend)
201        {
202                if (!InitBackend())
203                {
204                        TransferEnd(TransferEndReason::transfer_failure);
205                        return;
206                }
207        }
208        else if (m_pTlsSocket) {
209                // Re-enable Nagle algorithm
210                m_pSocket->SetFlags(m_pSocket->GetFlags() & (~CSocket::flag_nodelay));
211                if (CServerCapabilities::GetCapability(*controlSocket_.m_pCurrentServer, tls_resume) == unknown)        {
212                        CServerCapabilities::SetCapability(*controlSocket_.m_pCurrentServer, tls_resume, m_pTlsSocket->ResumedSession() ? yes : no);
213                }
214        }
215
216        if (m_bActive)
217                TriggerPostponedEvents();
218}
219
220void CTransferSocket::OnReceive()
221{
222        controlSocket_.LogMessage(MessageType::Debug_Debug, _T("CTransferSocket::OnReceive(), m_transferMode=%d"), m_transferMode);
223
224        if (!m_pBackend) {
225                controlSocket_.LogMessage(MessageType::Debug_Verbose, _T("Postponing receive, m_pBackend was false."));
226                m_postponedReceive = true;
227                return;
228        }
229
230        if (!m_bActive) {
231                controlSocket_.LogMessage(MessageType::Debug_Verbose, _T("Postponing receive, m_bActive was false."));
232                m_postponedReceive = true;
233                return;
234        }
235
236        if (m_transferMode == TransferMode::list) {
237                for (;;) {
238                        char *pBuffer = new char[4096];
239                        int error;
240                        int numread = m_pBackend->Read(pBuffer, 4096, error);
241                        if (numread < 0) {
242                                delete [] pBuffer;
243                                if (error != EAGAIN) {
244                                        controlSocket_.LogMessage(MessageType::Error, _T("Could not read from transfer socket: %s"), CSocket::GetErrorDescription(error));
245                                        TransferEnd(TransferEndReason::transfer_failure);
246                                }
247                                else if (m_onCloseCalled && !m_pBackend->IsWaiting(CRateLimiter::inbound))
248                                        TransferEnd(TransferEndReason::successful);
249                                return;
250                        }
251
252                        if (numread > 0) {
253                                if (!m_pDirectoryListingParser->AddData(pBuffer, numread))
254                                {
255                                        TransferEnd(TransferEndReason::transfer_failure);
256                                        return;
257                                }
258
259                                controlSocket_.SetActive(CFileZillaEngine::recv);
260                                if (!m_madeProgress) {
261                                        m_madeProgress = 2;
262                                        engine_.transfer_status_.SetMadeProgress();
263                                }
264                                engine_.transfer_status_.Update(numread);
265                        }
266                        else {
267                                delete [] pBuffer;
268                                TransferEnd(TransferEndReason::successful);
269                                return;
270                        }
271                }
272        }
273        else if (m_transferMode == TransferMode::download) {
274                int error;
275                int numread;
276
277                // Only do a certain number of iterations in one go to keep the event loop going.
278                // Otherwise this behaves like a livelock on very large files written to a very fast
279                // SSD downloaded from a very fast server.
280                for (int i = 0; i < 100; ++i) {
281                        if (!CheckGetNextWriteBuffer())
282                                return;
283
284                        numread = m_pBackend->Read(m_pTransferBuffer, m_transferBufferLen, error);
285                        if (numread <= 0) {
286                                break;
287                        }
288
289                        controlSocket_.SetActive(CFileZillaEngine::recv);
290                        if (!m_madeProgress) {
291                                m_madeProgress = 2;
292                                engine_.transfer_status_.SetMadeProgress();
293                        }
294                        engine_.transfer_status_.Update(numread);
295
296                        m_pTransferBuffer += numread;
297                        m_transferBufferLen -= numread;
298                }
299
300                if (numread < 0) {
301                        if (error != EAGAIN) {
302                                controlSocket_.LogMessage(MessageType::Error, _T("Could not read from transfer socket: %s"), CSocket::GetErrorDescription(error));
303                                TransferEnd(TransferEndReason::transfer_failure);
304                        }
305                        else if (m_onCloseCalled && !m_pBackend->IsWaiting(CRateLimiter::inbound)) {
306                                FinalizeWrite();
307                        }
308                }
309                else if (!numread) {
310                        FinalizeWrite();
311                }
312                else {
313                        SendEvent<CSocketEvent>(m_pBackend, SocketEventType::read, 0);
314                }
315        }
316        else if (m_transferMode == TransferMode::resumetest) {
317                for (;;) {
318                        char buffer[2];
319                        int error;
320                        int numread = m_pBackend->Read(buffer, 2, error);
321                        if (numread < 0) {
322                                if (error != EAGAIN) {
323                                        controlSocket_.LogMessage(MessageType::Error, _T("Could not read from transfer socket: %s"), CSocket::GetErrorDescription(error));
324                                        TransferEnd(TransferEndReason::transfer_failure);
325                                }
326                                else if (m_onCloseCalled && !m_pBackend->IsWaiting(CRateLimiter::inbound)) {
327                                        if (m_transferBufferLen == 1)
328                                                TransferEnd(TransferEndReason::successful);
329                                        else
330                                        {
331                                                controlSocket_.LogMessage(MessageType::Debug_Warning, _T("Server incorrectly sent %d bytes"), m_transferBufferLen);
332                                                TransferEnd(TransferEndReason::failed_resumetest);
333                                        }
334                                }
335                                return;
336                        }
337
338                        if (!numread) {
339                                if (m_transferBufferLen == 1)
340                                        TransferEnd(TransferEndReason::successful);
341                                else {
342                                        controlSocket_.LogMessage(MessageType::Debug_Warning, _T("Server incorrectly sent %d bytes"), m_transferBufferLen);
343                                        TransferEnd(TransferEndReason::failed_resumetest);
344                                }
345                                return;
346                        }
347                        m_transferBufferLen += numread;
348
349                        if (m_transferBufferLen > 1) {
350                                controlSocket_.LogMessage(MessageType::Debug_Warning, _T("Server incorrectly sent %d bytes"), m_transferBufferLen);
351                                TransferEnd(TransferEndReason::failed_resumetest);
352                                return;
353                        }
354                }
355        }
356}
357
358void CTransferSocket::OnSend()
359{
360        if (!m_pBackend) {
361                controlSocket_.LogMessage(MessageType::Debug_Verbose, _T("OnSend called without backend. Ignoring event."));
362                return;
363        }
364
365        if (!m_bActive) {
366                controlSocket_.LogMessage(MessageType::Debug_Verbose, _T("Postponing send"));
367                m_postponedSend = true;
368                return;
369        }
370
371        if (m_transferMode != TransferMode::upload)
372                return;
373
374        int error;
375        int written;
376
377        // Only do a certain number of iterations in one go to keep the event loop going.
378        // Otherwise this behaves like a livelock on very large files read from a very fast
379        // SSD uploaded to a very fast server.
380        for (int i = 0; i < 100; ++i) {
381                if (!CheckGetNextReadBuffer())
382                        return;
383
384                written = m_pBackend->Write(m_pTransferBuffer, m_transferBufferLen, error);
385                if (written <= 0)
386                        break;
387
388                controlSocket_.SetActive(CFileZillaEngine::send);
389                if (m_madeProgress == 1) {
390                        controlSocket_.LogMessage(MessageType::Debug_Debug, _T("Made progress in CTransferSocket::OnSend()"));
391                        m_madeProgress = 2;
392                        engine_.transfer_status_.SetMadeProgress();
393                }
394                engine_.transfer_status_.Update(written);
395
396                m_pTransferBuffer += written;
397                m_transferBufferLen -= written;
398        }
399
400        if (written < 0) {
401                if (error == EAGAIN) {
402                        if (!m_madeProgress) {
403                                controlSocket_.LogMessage(MessageType::Debug_Debug, _T("First EAGAIN in CTransferSocket::OnSend()"));
404                                m_madeProgress = 1;
405                                engine_.transfer_status_.SetMadeProgress();
406                        }
407                }
408                else {
409                        controlSocket_.LogMessage(MessageType::Error, _T("Could not write to transfer socket: %s"), CSocket::GetErrorDescription(error));
410                        TransferEnd(TransferEndReason::transfer_failure);
411                }
412        }
413        else if (written > 0) {
414                SendEvent<CSocketEvent>(m_pBackend, SocketEventType::write, 0);
415        }
416}
417
418void CTransferSocket::OnClose(int error)
419{
420        controlSocket_.LogMessage(MessageType::Debug_Verbose, _T("CTransferSocket::OnClose(%d)"), error);
421        m_onCloseCalled = true;
422
423        if (m_transferEndReason != TransferEndReason::none)
424                return;
425
426        if (!m_pBackend) {
427                if (!InitBackend()) {
428                        TransferEnd(TransferEndReason::transfer_failure);
429                        return;
430                }
431        }
432
433        if (m_transferMode == TransferMode::upload) {
434                if (m_shutdown && m_pTlsSocket) {
435                        if (m_pTlsSocket->Shutdown() != 0)
436                                TransferEnd(TransferEndReason::transfer_failure);
437                        else
438                                TransferEnd(TransferEndReason::successful);
439                }
440                else
441                        TransferEnd(TransferEndReason::transfer_failure);
442                return;
443        }
444
445        if (error) {
446                controlSocket_.LogMessage(MessageType::Error, _("Transfer connection interrupted: %s"), CSocket::GetErrorDescription(error));
447                TransferEnd(TransferEndReason::transfer_failure);
448                return;
449        }
450
451        char buffer[100];
452        int numread = m_pBackend->Peek(&buffer, 100, error);
453        if (numread > 0) {
454#ifndef __WXMSW__
455                wxFAIL_MSG(_T("Peek isn't supposed to return data after close notification"));
456#endif
457
458                // MSDN says this:
459                //   FD_CLOSE being posted after all data is read from a socket.
460                //   An application should check for remaining data upon receipt
461                //   of FD_CLOSE to avoid any possibility of losing data.
462                // First half is actually plain wrong.
463                OnReceive();
464
465                return;
466        }
467        else if (numread < 0 && error != EAGAIN) {
468                controlSocket_.LogMessage(MessageType::Error, _("Transfer connection interrupted: %s"), CSocket::GetErrorDescription(error));
469                TransferEnd(TransferEndReason::transfer_failure);
470                return;
471        }
472
473        if (m_transferMode == TransferMode::resumetest) {
474                if (m_transferBufferLen != 1) {
475                        TransferEnd(TransferEndReason::failed_resumetest);
476                        return;
477                }
478        }
479        if (m_transferMode == TransferMode::download) {
480                FinalizeWrite();
481        }
482        else {
483                TransferEnd(TransferEndReason::successful);
484        }
485}
486
487bool CTransferSocket::SetupPassiveTransfer(wxString host, int port)
488{
489        ResetSocket();
490
491        m_pSocket = new CSocket(this);
492
493        if (controlSocket_.m_pProxyBackend) {
494                m_pProxyBackend = new CProxySocket(this, m_pSocket, &controlSocket_);
495
496                int res = m_pProxyBackend->Handshake(controlSocket_.m_pProxyBackend->GetProxyType(),
497                                                                                         host, port,
498                                                                                         controlSocket_.m_pProxyBackend->GetUser(), controlSocket_.m_pProxyBackend->GetPass());
499
500                if (res != EINPROGRESS) {
501                        ResetSocket();
502                        return false;
503                }
504                int error;
505                host = controlSocket_.m_pSocket->GetPeerIP();
506                port = controlSocket_.m_pSocket->GetRemotePort(error);
507                if (host.empty() || port < 1) {
508                        controlSocket_.LogMessage(MessageType::Debug_Warning, _T("Could not get peer address of control connection."));
509                        ResetSocket();
510                        return false;
511                }
512        }
513
514        SetSocketBufferSizes(m_pSocket);
515
516        // Try to bind the source IP of the data connection to the same IP as the control connection.
517        // We can do so either if
518        // 1) the destination IP of the data connection matches peer IP of the control connection or
519        // 2) we are using a proxy.
520        //
521        // In case destination IPs of control and data connection are different, do not bind to the
522        // same source.
523
524        wxString bindAddress;
525        if (m_pProxyBackend) {
526                bindAddress = controlSocket_.m_pSocket->GetLocalIP();
527                controlSocket_.LogMessage(MessageType::Debug_Info, _T("Binding data connection source IP to control connection source IP %s"), bindAddress);
528        }
529        else {
530                if (controlSocket_.m_pSocket->GetPeerIP(true) == host || controlSocket_.m_pSocket->GetPeerIP(false) == host) {
531                        bindAddress = controlSocket_.m_pSocket->GetLocalIP();
532                        controlSocket_.LogMessage(MessageType::Debug_Info, _T("Binding data connection source IP to control connection source IP %s"), bindAddress);
533                }
534                else {
535                        controlSocket_.LogMessage(MessageType::Debug_Warning, _T("Destination IP of data connection does not match peer IP of control connection. Not binding source address of data connection."));
536                }
537        }
538
539        int res = m_pSocket->Connect(host, port, CSocket::unspec, bindAddress);
540        if (res && res != EINPROGRESS) {
541                ResetSocket();
542                return false;
543        }
544
545        return true;
546}
547
548void CTransferSocket::SetActive()
549{
550        if (m_transferEndReason != TransferEndReason::none)
551                return;
552        if (m_transferMode == TransferMode::download || m_transferMode == TransferMode::upload) {
553                if (ioThread_) {
554                        ioThread_->SetEventHandler(this);
555                }
556        }
557
558        m_bActive = true;
559        if (!m_pSocket)
560                return;
561
562        if (m_pSocket->GetState() == CSocket::connected || m_pSocket->GetState() == CSocket::closing)
563                TriggerPostponedEvents();
564}
565
566void CTransferSocket::TransferEnd(TransferEndReason reason)
567{
568        controlSocket_.LogMessage(MessageType::Debug_Verbose, _T("CTransferSocket::TransferEnd(%d)"), reason);
569
570        if (m_transferEndReason != TransferEndReason::none)
571                return;
572        m_transferEndReason = reason;
573
574        ResetSocket();
575
576        engine_.SendEvent<CFileZillaEngineEvent>(engineTransferEnd);
577}
578
579CSocket* CTransferSocket::CreateSocketServer(int port)
580{
581        CSocket* pServer = new CSocket(this);
582        int res = pServer->Listen(controlSocket_.m_pSocket->GetAddressFamily(), port);
583        if (res) {
584                controlSocket_.LogMessage(MessageType::Debug_Verbose, _T("Could not listen on port %d: %s"), port, CSocket::GetErrorDescription(res));
585                delete pServer;
586                return 0;
587        }
588
589        SetSocketBufferSizes(pServer);
590
591        return pServer;
592}
593
594CSocket* CTransferSocket::CreateSocketServer()
595{
596        if (!engine_.GetOptions().GetOptionVal(OPTION_LIMITPORTS)) {
597                // Ask the systen for a port
598                CSocket* pServer = CreateSocketServer(0);
599                return pServer;
600        }
601
602        // Try out all ports in the port range.
603        // Upon first call, we try to use a random port fist, after that
604        // increase the port step by step
605
606        // Windows only: I think there's a bug in the socket implementation of
607        // Windows: Even if using SO_REUSEADDR, using the same local address
608        // twice will fail unless there are a couple of minutes between the
609        // connection attempts. This may cause problems if transferring lots of
610        // files with a narrow port range.
611
612        static int start = 0;
613
614        int low = engine_.GetOptions().GetOptionVal(OPTION_LIMITPORTS_LOW);
615        int high = engine_.GetOptions().GetOptionVal(OPTION_LIMITPORTS_HIGH);
616        if (low > high)
617                low = high;
618
619        if (start < low || start > high) {
620                start = GetRandomNumber(low, high);
621                wxASSERT(start >= low && start <= high);
622        }
623
624        CSocket* pServer = 0;
625
626        int count = high - low + 1;
627        while (count--) {
628                pServer = CreateSocketServer(start++);
629                if (pServer)
630                        break;
631                if (start > high)
632                        start = low;
633        }
634
635        return pServer;
636}
637
638bool CTransferSocket::CheckGetNextWriteBuffer()
639{
640        if (!m_transferBufferLen) {
641                int res = ioThread_->GetNextWriteBuffer(&m_pTransferBuffer);
642
643                if (res == IO_Again)
644                        return false;
645                else if (res == IO_Error) {
646                        wxString error = ioThread_->GetError();
647                        if (error.empty() )
648                                controlSocket_.LogMessage(MessageType::Error, _("Can't write data to file."));
649                        else
650                                controlSocket_.LogMessage(MessageType::Error, _("Can't write data to file: %s"), error);
651                        TransferEnd(TransferEndReason::transfer_failure_critical);
652                        return false;
653                }
654
655                m_transferBufferLen = BUFFERSIZE;
656        }
657
658        return true;
659}
660
661bool CTransferSocket::CheckGetNextReadBuffer()
662{
663        if (!m_transferBufferLen) {
664                int res = ioThread_->GetNextReadBuffer(&m_pTransferBuffer);
665                if (res == IO_Again)
666                        return false;
667                else if (res == IO_Error) {
668                        controlSocket_.LogMessage(MessageType::Error, _("Can't read from file"));
669                        TransferEnd(TransferEndReason::transfer_failure);
670                        return false;
671                }
672                else if (res == IO_Success) {
673                        if (m_pTlsSocket) {
674                                m_shutdown = true;
675
676                                int error = m_pTlsSocket->Shutdown();
677                                if (error != 0) {
678                                        if (error != EAGAIN)
679                                                TransferEnd(TransferEndReason::transfer_failure);
680                                        return false;
681                                }
682                        }
683                        TransferEnd(TransferEndReason::successful);
684                        return false;
685                }
686                m_transferBufferLen = res;
687        }
688
689        return true;
690}
691
692void CTransferSocket::OnIOThreadEvent()
693{
694        if (!m_bActive || m_transferEndReason != TransferEndReason::none)
695                return;
696
697        if (m_transferMode == TransferMode::download)
698                OnReceive();
699        else if (m_transferMode == TransferMode::upload)
700                OnSend();
701}
702
703void CTransferSocket::FinalizeWrite()
704{
705        bool res = ioThread_->Finalize(BUFFERSIZE - m_transferBufferLen);
706        if (m_transferEndReason != TransferEndReason::none)
707                return;
708
709        if (res)
710                TransferEnd(TransferEndReason::successful);
711        else {
712                wxString error = ioThread_->GetError();
713                if (error.empty())
714                        controlSocket_.LogMessage(MessageType::Error, _("Can't write data to file."));
715                else
716                        controlSocket_.LogMessage(MessageType::Error, _("Can't write data to file: %s"), error);
717                TransferEnd(TransferEndReason::transfer_failure_critical);
718        }
719}
720
721bool CTransferSocket::InitTls(const CTlsSocket* pPrimaryTlsSocket)
722{
723        // Disable Nagle algorithm during TlS handshake
724        m_pSocket->SetFlags(m_pSocket->GetFlags() | CSocket::flag_nodelay);
725
726        wxASSERT(!m_pBackend);
727        m_pTlsSocket = new CTlsSocket(this, *m_pSocket, &controlSocket_);
728
729        if (!m_pTlsSocket->Init()) {
730                delete m_pTlsSocket;
731                m_pTlsSocket = 0;
732                return false;
733        }
734
735        bool try_resume = CServerCapabilities::GetCapability(*controlSocket_.m_pCurrentServer, tls_resume) != no;
736
737        int res = m_pTlsSocket->Handshake(pPrimaryTlsSocket, try_resume);
738        if (res && res != FZ_REPLY_WOULDBLOCK)
739        {
740                delete m_pTlsSocket;
741                m_pTlsSocket = 0;
742                return false;
743        }
744
745        m_pBackend = m_pTlsSocket;
746
747        return true;
748}
749
750void CTransferSocket::TriggerPostponedEvents()
751{
752        wxASSERT(m_bActive);
753
754        if (m_postponedReceive) {
755                controlSocket_.LogMessage(MessageType::Debug_Verbose, _T("Executing postponed receive"));
756                m_postponedReceive = false;
757                OnReceive();
758                if (m_transferEndReason != TransferEndReason::none)
759                        return;
760        }
761        if (m_postponedSend) {
762                controlSocket_.LogMessage(MessageType::Debug_Verbose, _T("Executing postponed send"));
763                m_postponedSend = false;
764                OnSend();
765                if (m_transferEndReason != TransferEndReason::none)
766                        return;
767        }
768        if (m_onCloseCalled)
769                OnClose(0);
770}
771
772bool CTransferSocket::InitBackend()
773{
774        if (m_pBackend)
775                return true;
776
777        if (controlSocket_.m_protectDataChannel) {
778                if (!InitTls(controlSocket_.m_pTlsSocket))
779                        return false;
780        }
781        else
782                m_pBackend = new CSocketBackend(this, *m_pSocket, engine_.GetRateLimiter());
783
784        return true;
785}
786
787void CTransferSocket::SetSocketBufferSizes(CSocket* pSocket)
788{
789        wxCHECK_RET(pSocket, _("SetSocketBufferSize called without socket"));
790
791        const int size_read = engine_.GetOptions().GetOptionVal(OPTION_SOCKET_BUFFERSIZE_RECV);
792        const int size_write = engine_.GetOptions().GetOptionVal(OPTION_SOCKET_BUFFERSIZE_SEND);
793        pSocket->SetBufferSizes(size_read, size_write);
794}
795
796void CTransferSocket::operator()(CEventBase const& ev)
797{
798        Dispatch<CSocketEvent, CIOThreadEvent>(ev, this,
799                &CTransferSocket::OnSocketEvent,
800                &CTransferSocket::OnIOThreadEvent);
801}
Note: See TracBrowser for help on using the repository browser.