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

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

Update new version: 3.15.02

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