38
40
CControlSocket::CControlSocket(CFileZillaEnginePrivate *pEngine)
39
: wxSocketClient(wxSOCKET_NOWAIT), CLogging(pEngine)
42
43
m_pEngine = pEngine;
46
45
m_pCurrentServer = 0;
47
46
m_pTransferStatus = 0;
48
47
m_transferStatusSendState = 0;
49
m_onConnectCalled = false;
51
SetEvtHandlerEnabled(true);
52
SetEventHandler(*this, m_socketId);
53
SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_OUTPUT_FLAG | wxSOCKET_CONNECTION_FLAG | wxSOCKET_LOST_FLAG);
59
52
m_timer.SetOwner(this);
56
m_invalidateCurrentPath = false;
62
59
CControlSocket::~CControlSocket()
69
void CControlSocket::OnConnect(wxSocketEvent &event)
73
void CControlSocket::OnReceive(wxSocketEvent &event)
77
void CControlSocket::OnSend(wxSocketEvent &event)
81
if (!m_nSendBufferLen)
83
delete [] m_pSendBuffer;
88
Write(m_pSendBuffer, m_nSendBufferLen);
91
if (LastError() != wxSOCKET_WOULDBLOCK)
96
int numsent = LastCount();
101
m_pEngine->SetActive(false);
104
if (numsent == m_nSendBufferLen)
106
m_nSendBufferLen = 0;
107
delete [] m_pSendBuffer;
112
memmove(m_pSendBuffer, m_pSendBuffer + numsent, m_nSendBufferLen - numsent);
113
m_nSendBufferLen -= numsent;
118
void CControlSocket::OnClose(wxSocketEvent &event)
120
LogMessage(Debug_Verbose, _T("CControlSocket::OnClose()"));
122
if (GetCurrentCommandId() != cmd_connect)
123
LogMessage(::Error, _("Disconnected from server"));
127
int CControlSocket::Connect(const CServer &server)
131
if (server.GetEncodingType() == ENCODING_CUSTOM)
132
m_pCSConv = new wxCSConv(server.GetCustomEncoding());
134
if (m_pCurrentServer)
135
delete m_pCurrentServer;
136
m_pCurrentServer = new CServer(server);
138
const wxString & host = server.GetHost();
139
if (!IsIpAddress(host))
141
LogMessage(Status, _("Resolving IP-Address for %s"), host.c_str());
142
CAsyncHostResolver *resolver = new CAsyncHostResolver(m_pEngine, ConvertDomainName(host));
143
m_pEngine->AddNewAsyncHostResolver(resolver);
152
return ContinueConnect(&addr);
155
return FZ_REPLY_WOULDBLOCK;
158
int CControlSocket::ContinueConnect(const wxIPV4address *address)
160
LogMessage(__TFILE__, __LINE__, this, Debug_Verbose, _T("CControlSocket::ContinueConnect(%p) m_pEngine=%p"), address, m_pEngine);
161
if (GetCurrentCommandId() != cmd_connect ||
164
LogMessage(Debug_Warning, _T("Invalid context for call to ContinueConnect(), cmd=%d, m_pCurrentServer=%p"), GetCurrentCommandId(), m_pCurrentServer);
165
return DoClose(FZ_REPLY_INTERNALERROR);
170
LogMessage(::Error, _("Invalid hostname or host not found"));
171
return ResetOperation(FZ_REPLY_ERROR | FZ_REPLY_CRITICALERROR);
174
const unsigned int port = m_pCurrentServer->GetPort();
175
LogMessage(Status, _("Connecting to %s:%d..."), address->IPAddress().c_str(), port);
177
wxIPV4address addr = *address;
180
bool res = wxSocketClient::Connect(addr, false);
182
if (!res && LastError() != wxSOCKET_WOULDBLOCK)
183
return ResetOperation(FZ_REPLY_ERROR);
185
return FZ_REPLY_WOULDBLOCK;
188
67
int CControlSocket::Disconnect()
238
89
LogMessage(::Debug_Warning, _T("ResetOperation with FZ_REPLY_WOULDBLOCK in nErrorCode (%d)"), nErrorCode);
241
if (m_pCurOpData && m_pCurOpData->opId != cmd_rawtransfer)
92
if (m_pCurOpData && m_pCurOpData->holdsLock)
246
if (m_pCurOpData && m_pCurOpData->pNextOpData && (nErrorCode & FZ_REPLY_INTERNALERROR) != FZ_REPLY_INTERNALERROR)
95
if (m_pCurOpData && m_pCurOpData->pNextOpData)
248
97
COpData *pNext = m_pCurOpData->pNextOpData;
249
98
m_pCurOpData->pNextOpData = 0;
250
99
delete m_pCurOpData;
251
100
m_pCurOpData = pNext;
252
return SendNextCommand(nErrorCode);
257
if (m_pCurOpData->opId == cmd_transfer)
101
if (nErrorCode == FZ_REPLY_OK ||
102
nErrorCode == FZ_REPLY_ERROR ||
103
nErrorCode == FZ_REPLY_CRITICALERROR)
259
CFileTransferOpData *pData = static_cast<CFileTransferOpData *>(m_pCurOpData);
260
if (!pData->download && pData->transferInitiated)
262
CDirectoryCache cache;
263
cache.InvalidateFile(*m_pCurrentServer, pData->remotePath, pData->remoteFile, true, CDirectoryCache::file, (nErrorCode == FZ_REPLY_OK) ? pData->localFileSize : -1);
265
m_pEngine->SendDirectoryListingNotification(pData->remotePath, false, true, false);
105
return ParseSubcommandResult(nErrorCode);
108
return ResetOperation(nErrorCode);
273
if (nErrorCode != FZ_REPLY_OK)
111
if ((nErrorCode & FZ_REPLY_CRITICALERROR) == FZ_REPLY_CRITICALERROR)
112
LogMessage(::Error, _("Critical error"));
275
if ((nErrorCode & FZ_REPLY_CRITICALERROR) == FZ_REPLY_CRITICALERROR)
276
LogMessage(::Error, _("Critical error"));
277
const enum Command commandId = GetCurrentCommandId();
116
const enum Command commandId = m_pCurOpData->opId;
278
117
switch (commandId)
280
121
case cmd_connect:
281
122
if ((nErrorCode & FZ_REPLY_CANCELED) == FZ_REPLY_CANCELED)
282
123
LogMessage(::Error, _("Connection attempt interrupted by user"));
124
else if (nErrorCode != FZ_REPLY_OK)
284
125
LogMessage(::Error, _("Could not connect to server"));
287
128
if ((nErrorCode & FZ_REPLY_CANCELED) == FZ_REPLY_CANCELED)
288
129
LogMessage(::Error, _("Directory listing aborted by user"));
130
else if (nErrorCode != FZ_REPLY_OK)
290
131
LogMessage(::Error, _("Failed to retrieve directory listing"));
133
LogMessage(Status, _("Directory listing successful"));
137
CFileTransferOpData *pData = static_cast<CFileTransferOpData *>(m_pCurOpData);
138
if (!pData->download && pData->transferInitiated)
140
if (!m_pCurrentServer)
141
LogMessage(__TFILE__, __LINE__, this, Debug_Warning, _T("m_pCurrentServer is 0"));
144
CDirectoryCache cache;
145
bool updated = cache.UpdateFile(*m_pCurrentServer, pData->remotePath, pData->remoteFile, true, CDirectoryCache::file, (nErrorCode == FZ_REPLY_OK) ? pData->localFileSize : -1);
148
m_pEngine->SendDirectoryListingNotification(pData->remotePath, false, true, false);
151
if ((nErrorCode & FZ_REPLY_CANCELED) == FZ_REPLY_CANCELED)
152
LogMessage(::Error, _("Transfer aborted by user"));
153
else if (nErrorCode == FZ_REPLY_OK)
154
LogMessage(Status, _("File transfer successful"));
295
158
if ((nErrorCode & FZ_REPLY_CANCELED) == FZ_REPLY_CANCELED)
296
159
LogMessage(::Error, _("Interrupted by user"));
302
switch (GetCurrentCommandId())
305
LogMessage(Status, _("Directory listing successful"));
308
LogMessage(Status, _("File transfer successful"));
315
167
ResetTransferStatus();
171
if (m_invalidateCurrentPath)
173
m_CurrentPath.Clear();
174
m_invalidateCurrentPath = false;
319
177
return m_pEngine->ResetOperation(nErrorCode);
322
180
int CControlSocket::DoClose(int nErrorCode /*=FZ_REPLY_DISCONNECTED*/)
184
wxASSERT(!m_pCurOpData);
324
190
nErrorCode = ResetOperation(FZ_REPLY_ERROR | FZ_REPLY_DISCONNECTED | nErrorCode);
328
192
delete m_pCurrentServer;
329
193
m_pCurrentServer = 0;
331
m_pEngine->SendDisconnectNotification();
333
195
return nErrorCode;
336
void CControlSocket::ResetSocket()
340
delete [] m_pSendBuffer;
342
m_nSendBufferLen = 0;
344
m_onConnectCalled = false;
346
SetEventHandler(*this, ++m_socketId);
349
bool CControlSocket::Send(const char *buffer, int len)
354
char *tmp = m_pSendBuffer;
355
m_pSendBuffer = new char[m_nSendBufferLen + len];
356
memcpy(m_pSendBuffer, tmp, m_nSendBufferLen);
357
memcpy(m_pSendBuffer + m_nSendBufferLen, buffer, len);
358
m_nSendBufferLen += len;
367
if (LastError() != wxSOCKET_WOULDBLOCK)
374
numsent = LastCount();
377
m_pEngine->SetActive(false);
381
char *tmp = m_pSendBuffer;
382
m_pSendBuffer = new char[m_nSendBufferLen + len - numsent];
383
memcpy(m_pSendBuffer, tmp, m_nSendBufferLen);
384
memcpy(m_pSendBuffer + m_nSendBufferLen, buffer, len - numsent);
385
m_nSendBufferLen += len - numsent;
393
198
wxString CControlSocket::ConvertDomainName(wxString domain)
395
200
const wxWCharBuffer buffer = wxConvCurrent->cWX2WC(domain);
508
323
int pos2 = reply.Find('"', true);
509
324
if (pos1 == -1 || pos1 >= pos2)
511
LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("No quoted path found in pwd reply, trying first token as path"));
326
pos1 = reply.Find('\'');
327
pos2 = reply.Find('\'', true);
329
if (pos1 != -1 && pos1 < pos2)
330
LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("Broken server sending single-quoted path instead of double-quoted path."));
332
if (pos1 == -1 || pos1 >= pos2)
334
LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("Broken server, no quoted path found in pwd reply, trying first token as path"));
512
335
pos1 = reply.Find(' ');
515
LogMessage(__TFILE__, __LINE__, this, Debug_Warning, _T("Can't parse path"));
338
reply = reply.Mid(pos1 + 1);
339
pos2 = reply.Find(' ');
341
reply = reply.Left(pos2);
519
pos2 = reply.Mid(pos1 + 1).Find(' ');
521
pos2 = (int)reply.Length();
523
reply = reply.Mid(pos1 + 1, pos2 - pos1 - 1);
347
reply = reply.Mid(pos1 + 1, pos2 - pos1 - 1);
526
350
m_CurrentPath.SetType(m_pCurrentServer->GetType());
527
if (!m_CurrentPath.SetPath(reply))
351
if (reply == _T("") || !m_CurrentPath.SetPath(reply))
529
LogMessage(__TFILE__, __LINE__, this, Debug_Warning, _T("Can't parse path"));
354
LogMessage(__TFILE__, __LINE__, this, Debug_Warning, _T("Failed to parse returned path."));
356
LogMessage(__TFILE__, __LINE__, this, Debug_Warning, _T("Server returned empty path."));
358
if (!defaultPath.IsEmpty())
360
LogMessage(Debug_Warning, _T("Assuming path is '%s'."), defaultPath.GetPath().c_str());
361
m_CurrentPath = defaultPath;
825
bool CControlSocket::TryLockCache(const CServerPath& directory)
662
bool CControlSocket::TryLockCache(enum locking_reason reason, const CServerPath& directory)
827
wxASSERT(GetLockStatus() == m_lockInfoList.end());
828
664
wxASSERT(m_pCurrentServer);
831
info.directory = directory;
832
info.pControlSocket = this;
833
info.waiting = false;
835
// Try to find other instance holding the lock
836
for (std::list<t_lockInfo>::const_iterator iter = m_lockInfoList.begin(); iter != m_lockInfoList.end(); iter++)
838
if (*m_pCurrentServer != *iter->pControlSocket->m_pCurrentServer)
841
if (directory == iter->directory)
665
wxASSERT(m_pCurOpData);
667
std::list<t_lockInfo>::iterator own = GetLockStatus();
668
if (own == m_lockInfoList.end())
671
info.directory = directory;
672
info.pControlSocket = this;
674
info.reason = reason;
676
m_lockInfoList.push_back(info);
677
own = --m_lockInfoList.end();
843
// Some other instance is holding the lock
683
if (!m_pCurOpData->holdsLock)
685
m_pCurOpData->holdsLock = true;
849
m_lockInfoList.push_back(info);
850
return !info.waiting;
690
wxASSERT(own->waiting);
691
wxASSERT(own->reason == reason);
694
// Needs to be set in any case so that ResetOperation
695
// unlocks or cancels the lock wait
696
m_pCurOpData->holdsLock = true;
698
// Try to find other instance holding the lock
699
for (std::list<t_lockInfo>::const_iterator iter = m_lockInfoList.begin(); iter != own; iter++)
701
if (*m_pCurrentServer != *iter->pControlSocket->m_pCurrentServer)
703
if (directory != iter->directory)
705
if (reason != iter->reason)
708
// Some other instance is holding the lock
713
own->waiting = false;
717
bool CControlSocket::IsLocked(enum locking_reason reason, const CServerPath& directory)
719
wxASSERT(m_pCurrentServer);
721
std::list<t_lockInfo>::iterator own = GetLockStatus();
722
if (own != m_lockInfoList.end())
725
// Try to find other instance holding the lock
726
for (std::list<t_lockInfo>::const_iterator iter = m_lockInfoList.begin(); iter != own; iter++)
728
if (*m_pCurrentServer != *iter->pControlSocket->m_pCurrentServer)
730
if (directory != iter->directory)
732
if (reason != iter->reason)
735
// Some instance is holding the lock
853
742
void CControlSocket::UnlockCache()
744
if (!m_pCurOpData || !m_pCurOpData->holdsLock)
746
m_pCurOpData->holdsLock = false;
855
748
std::list<t_lockInfo>::iterator iter = GetLockStatus();
856
749
if (iter == m_lockInfoList.end())
859
756
CServerPath directory = iter->directory;
757
enum locking_reason reason = iter->reason;
860
759
m_lockInfoList.erase(iter);
862
761
// Find other instance waiting for the lock
878
bool CControlSocket::ObtainLockFromEvent()
780
enum CControlSocket::locking_reason CControlSocket::ObtainLockFromEvent()
782
wxASSERT(m_pCurOpData);
880
784
std::list<t_lockInfo>::iterator own = GetLockStatus();
881
785
if (own == m_lockInfoList.end())
884
788
if (!own->waiting)
887
791
for (std::list<t_lockInfo>::const_iterator iter = m_lockInfoList.begin(); iter != own; iter++)
889
793
if (*m_pCurrentServer != *iter->pControlSocket->m_pCurrentServer)
892
if (iter->directory == own->directory)
796
if (iter->directory != own->directory)
799
if (iter->reason != own->reason)
802
// Another instance comes before us
896
806
own->waiting = false;
901
812
void CControlSocket::OnObtainLock(wxCommandEvent& event)
903
if (!ObtainLockFromEvent())
814
if (ObtainLockFromEvent() == lock_unknown)
906
817
SendNextCommand();
822
void CControlSocket::InvalidateCurrentWorkingDir(const CServerPath& path)
824
wxASSERT(!path.IsEmpty());
825
if (m_CurrentPath.IsEmpty())
828
if (m_CurrentPath == path || path.IsParentOf(m_CurrentPath, false))
831
m_invalidateCurrentPath = true;
833
m_CurrentPath.Clear();
837
wxTimeSpan CControlSocket::GetTimezoneOffset()
839
if (!m_pCurrentServer)
843
if (CServerCapabilities::GetCapability(*m_pCurrentServer, timezone_offset, &seconds) != yes)
846
return wxTimeSpan(0, 0, seconds);
849
void CControlSocket::SendAsyncRequest(CAsyncRequestNotification* pNotification)
851
wxASSERT(pNotification);
853
pNotification->requestNumber = m_pEngine->GetNextAsyncRequestNumber();
856
m_pCurOpData->waitForAsyncRequest = true;
857
m_pEngine->AddNotification(pNotification);
860
// ------------------
861
// CRealControlSocket
862
// ------------------
864
BEGIN_EVENT_TABLE(CRealControlSocket, CControlSocket)
865
EVT_SOCKET(wxID_ANY, CRealControlSocket::OnSocketEvent)
868
CRealControlSocket::CRealControlSocket(CFileZillaEnginePrivate *pEngine)
869
: CControlSocket(pEngine), wxSocketClient(wxSOCKET_NOWAIT)
871
m_pBackend = new CSocketBackend(this, this);
874
m_nSendBufferLen = 0;
875
m_onConnectCalled = false;
878
CRealControlSocket::~CRealControlSocket()
884
bool CRealControlSocket::Send(const char *buffer, int len)
889
char *tmp = m_pSendBuffer;
890
m_pSendBuffer = new char[m_nSendBufferLen + len];
891
memcpy(m_pSendBuffer, tmp, m_nSendBufferLen);
892
memcpy(m_pSendBuffer + m_nSendBufferLen, buffer, len);
893
m_nSendBufferLen += len;
898
m_pBackend->Write(buffer, len);
900
if (m_pBackend->Error())
902
if (m_pBackend->LastError() != wxSOCKET_WOULDBLOCK)
909
numsent = m_pBackend->LastCount();
912
m_pEngine->SetActive(false);
916
char *tmp = m_pSendBuffer;
917
m_pSendBuffer = new char[m_nSendBufferLen + len - numsent];
918
memcpy(m_pSendBuffer, tmp, m_nSendBufferLen);
919
memcpy(m_pSendBuffer + m_nSendBufferLen, buffer, len - numsent);
920
m_nSendBufferLen += len - numsent;
928
void CRealControlSocket::OnSocketEvent(wxSocketEvent &event)
933
if (event.GetId() != m_pBackend->GetId())
936
switch (event.GetSocketEvent())
938
case wxSOCKET_CONNECTION:
939
m_onConnectCalled = true;
943
if (!m_onConnectCalled)
945
m_onConnectCalled = true;
950
case wxSOCKET_OUTPUT:
959
void CRealControlSocket::OnConnect()
963
void CRealControlSocket::OnReceive()
967
void CRealControlSocket::OnSend()
971
if (!m_nSendBufferLen)
973
delete [] m_pSendBuffer;
978
m_pBackend->Write(m_pSendBuffer, m_nSendBufferLen);
979
if (m_pBackend->Error())
981
if (m_pBackend->LastError() != wxSOCKET_WOULDBLOCK)
986
int numsent = m_pBackend->LastCount();
991
m_pEngine->SetActive(false);
994
if (numsent == m_nSendBufferLen)
996
m_nSendBufferLen = 0;
997
delete [] m_pSendBuffer;
1002
memmove(m_pSendBuffer, m_pSendBuffer + numsent, m_nSendBufferLen - numsent);
1003
m_nSendBufferLen -= numsent;
1008
void CRealControlSocket::OnClose()
1010
LogMessage(Debug_Verbose, _T("CRealControlSocket::OnClose()"));
1012
if (GetCurrentCommandId() != cmd_connect)
1013
LogMessage(::Error, _("Disconnected from server"));
1017
int CRealControlSocket::Connect(const CServer &server)
1021
if (server.GetEncodingType() == ENCODING_CUSTOM)
1022
m_pCSConv = new wxCSConv(server.GetCustomEncoding());
1024
if (m_pCurrentServer)
1025
delete m_pCurrentServer;
1026
m_pCurrentServer = new CServer(server);
1028
CConnectOpData* pData;
1029
if (!m_pCurOpData || m_pCurOpData->opId != cmd_connect)
1032
pData = static_cast<CConnectOpData *>(m_pCurOpData);
1034
const wxString& host = pData ? pData->host : server.GetHost();
1035
if (!IsIpAddress(host))
1037
LogMessage(Status, _("Resolving IP-Address for %s"), host.c_str());
1038
CAsyncHostResolver *resolver = new CAsyncHostResolver(m_pEngine, ConvertDomainName(host));
1039
m_pEngine->AddNewAsyncHostResolver(resolver);
1047
addr.Hostname(host);
1048
return ContinueConnect(&addr);
1051
return FZ_REPLY_WOULDBLOCK;
1054
int CRealControlSocket::ContinueConnect(const wxIPV4address *address)
1056
LogMessage(__TFILE__, __LINE__, this, Debug_Verbose, _T("CRealControlSocket::ContinueConnect(%p) m_pEngine=%p"), address, m_pEngine);
1057
if (GetCurrentCommandId() != cmd_connect ||
1060
LogMessage(Debug_Warning, _T("Invalid context for call to ContinueConnect(), cmd=%d, m_pCurrentServer=%p"), GetCurrentCommandId(), m_pCurrentServer);
1061
return DoClose(FZ_REPLY_INTERNALERROR);
1066
LogMessage(::Error, _("Invalid hostname or host not found"));
1067
return DoClose(FZ_REPLY_ERROR | FZ_REPLY_CRITICALERROR);
1070
CConnectOpData* pData;
1071
if (!m_pCurOpData || m_pCurOpData->opId != cmd_connect)
1074
pData = static_cast<CConnectOpData *>(m_pCurOpData);
1076
const unsigned int port = pData ? pData->port : m_pCurrentServer->GetPort();
1077
LogMessage(Status, _("Connecting to %s:%d..."), address->IPAddress().c_str(), port);
1079
wxIPV4address addr = *address;
1082
bool res = wxSocketClient::Connect(addr, false);
1084
if (!res && LastError() != wxSOCKET_WOULDBLOCK)
1087
return FZ_REPLY_WOULDBLOCK;
1090
int CRealControlSocket::DoClose(int nErrorCode /*=FZ_REPLY_DISCONNECTED*/)
1094
return CControlSocket::DoClose(nErrorCode);
1097
void CRealControlSocket::ResetSocket()
1103
delete [] m_pSendBuffer;
1105
m_nSendBufferLen = 0;
1108
m_onConnectCalled = false;
1114
wxString CRealControlSocket::GetLocalIP() const
1117
if (!GetLocal(addr))
1120
return addr.IPAddress();
1123
wxString CRealControlSocket::GetPeerIP() const
1129
return addr.IPAddress();