Tommy 碎碎念

Tommy Wu's blog

« 上一篇 | 下一篇 »

KeepAlive patch (version 2) for FileZilla 3
post by tommy @ 16 八月, 2007 13:17

昨天的 patch 被作者給 reject 了. 因為他認為把 timer 放到主視窗中,  在執行 keepalive 指令時, 會 block UI 的操作 (不過, 就算不放在這兒, 本來在送出指令時, 一定會影響到其他指令的執行啊?), 另外就是送出 TYPE I 與 TYPE A 指令, 因為原本的程式內有記錄目前的狀態, 可能會造成錯誤. 所以就暫時不接受這個 patch. 所以改了一下, 做了第二版的 patch, 把 timer 移出 MainFrm, 放到 CFtpControlSocket 裡頭, 並修改 keepalive 會送出的指令, 去除 TYPE I/TYPE A, 然後加上 NOOP/STAT/MKD/RMD 等指令. 因為 MKD/RMD 等指令沒有參數, 會回傳 5xx 的錯誤 (其他的指令如果 server 沒支援, 也應該是回傳 5xx), 所以在處理 keepalive 時, 也順便忽略所有的 5xx 錯誤碼.

這個修正如下:

diff -Nur Filezilla3/src/engine/ControlSocket.h Filezilla3.patch/src/engine/ControlSocket.h
--- Filezilla3/src/engine/ControlSocket.h Thu Aug 16 12:54:33 2007
+++ Filezilla3.patch/src/engine/ControlSocket.h Thu Aug 16 12:55:42 2007
@@ -115,6 +115,8 @@
virtual int Chmod(const CChmodCommand& command) { return FZ_REPLY_NOTSUPPORTED; }
virtual bool Connected() const = 0;
 
+ virtual int KeepAlive(const CKeepAliveCommand& command) { return FZ_REPLY_OK; }
+
// If m_pCurrentOpData is zero, this function returns the current command
// from the engine.
enum Command GetCurrentCommandId() const;
diff -Nur Filezilla3/src/engine/FileZillaEngine.cpp Filezilla3.patch/src/engine/FileZillaEngine.cpp
--- Filezilla3/src/engine/FileZillaEngine.cpp Thu Aug 16 12:54:35 2007
+++ Filezilla3.patch/src/engine/FileZillaEngine.cpp Thu Aug 16 12:55:50 2007
@@ -70,6 +70,9 @@
case cmd_chmod:
res = Chmod(reinterpret_cast<const CChmodCommand&>(command));
break;
+ case cmd_keepalive:
+ res = KeepAlive(reinterpret_cast<const CKeepAliveCommand &>(command));
+ break;
default:
return FZ_REPLY_SYNTAXERROR;
}
diff -Nur Filezilla3/src/engine/commands.cpp Filezilla3.patch/src/engine/commands.cpp
--- Filezilla3/src/engine/commands.cpp Thu Aug 16 12:54:35 2007
+++ Filezilla3.patch/src/engine/commands.cpp Thu Aug 16 12:55:57 2007
@@ -10,6 +10,16 @@
return m_Server;
}
 
+CKeepAliveCommand::CKeepAliveCommand(bool keepAlive /*=true*/)
+ : m_keepAlive(keepAlive)
+{
+}
+
+bool CKeepAliveCommand::IsKeepAlive() const
+{
+ return m_keepAlive;
+}
+
CListCommand::CListCommand(bool refresh /*=false*/)
: m_refresh(refresh)
{
diff -Nur Filezilla3/src/engine/engineprivate.cpp Filezilla3.patch/src/engine/engineprivate.cpp
--- Filezilla3/src/engine/engineprivate.cpp Thu Aug 16 12:54:35 2007
+++ Filezilla3.patch/src/engine/engineprivate.cpp Thu Aug 16 12:56:05 2007
@@ -525,6 +525,12 @@
return m_pControlSocket->Chmod(command);
}
 
+int CFileZillaEnginePrivate::KeepAlive(const CKeepAliveCommand& command)
+{
+ m_pCurrentCommand = command.Clone();
+ return m_pControlSocket->KeepAlive(command);
+}
+
void CFileZillaEnginePrivate::SendDirectoryListingNotification(const CServerPath& path, bool onList, bool modified, bool failed)
{
wxASSERT(m_pControlSocket);
diff -Nur Filezilla3/src/engine/ftpcontrolsocket.cpp Filezilla3.patch/src/engine/ftpcontrolsocket.cpp
--- Filezilla3/src/engine/ftpcontrolsocket.cpp Thu Aug 16 12:54:35 2007
+++ Filezilla3.patch/src/engine/ftpcontrolsocket.cpp Thu Aug 16 12:55:24 2007
@@ -24,8 +24,11 @@
#define LOGON_CUSTOMCOMMANDS 10
#define LOGON_DONE 11
 
+#define KEEPALIVE_TIMER_ID wxID_HIGHEST + 5
+
BEGIN_EVENT_TABLE(CFtpControlSocket, CRealControlSocket)
EVT_FZ_EXTERNALIPRESOLVE(wxID_ANY, CFtpControlSocket::OnExternalIPAddress)
+EVT_TIMER(wxID_ANY, CFtpControlSocket::OnTimer)
END_EVENT_TABLE();
 
CRawTransferOpData::CRawTransferOpData()
@@ -137,6 +140,8 @@
m_pTlsSocket = 0;
m_protectDataChannel = false;
m_lastTypeBinary = -1;
+ m_bEnableKeepAlive = false;
+ m_keepAliveTimer.SetOwner(this, KEEPALIVE_TIMER_ID);
}
 
CFtpControlSocket::~CFtpControlSocket()
@@ -147,12 +152,16 @@
{
LogMessage(Debug_Verbose, _T("CFtpControlSocket::OnReceive()"));
 
+ m_keepAliveStopWatch.Start();
+
m_pBackend->Read(m_receiveBuffer + m_bufferLen, RECVBUFFERSIZE - m_bufferLen);

if (m_pBackend->Error())
{
if (m_pBackend->LastError() != wxSOCKET_WOULDBLOCK)
{
+ m_bEnableKeepAlive = false;
+ m_keepAliveTimer.Stop();
LogMessage(::Error, _("Disconnected from server"));
DoClose();
}
@@ -386,6 +395,9 @@
case cmd_rawtransfer:
TransferParseResponse();
break;
+ case cmd_keepalive:
+ KeepAliveParseResponse();
+ break;
case cmd_none:
LogMessage(Debug_Verbose, _T("Out-of-order reply, ignoring."));
break;
@@ -798,6 +810,7 @@
LogMessage(::Error, _T("Failed to convert command to 8 bit charset"));
return false;
}
+ m_keepAliveStopWatch.Start();
unsigned int len = (unsigned int)strlen(buffer);
bool res = CRealControlSocket::Send(buffer, len);
if (res)
@@ -1254,6 +1267,8 @@
return DeleteSend(prevResult);
case cmd_removedir:
return RemoveDirSend(prevResult);
+ case cmd_keepalive:
+ return KeepAliveSend();
default:
LogMessage(__TFILE__, __LINE__, this, ::Debug_Warning, _T("Unknown opID (%d) in SendNextCommand"), m_pCurOpData->opId);
ResetOperation(FZ_REPLY_INTERNALERROR);
@@ -3006,6 +3021,126 @@
}
 
return FZ_REPLY_WOULDBLOCK;
+}
+
+class CKeepAliveOpData : public COpData
+{
+public:
+ CKeepAliveOpData(const wxString& command)
+ : COpData(cmd_keepalive)
+ {
+ m_command = command;
+ }
+
+ wxString m_command;
+};
+
+int CFtpControlSocket::KeepAlive(const CKeepAliveCommand& command)
+{
+ LogMessage(Debug_Verbose, _T("CFtpControlSocket::KeepAlive"));
+
+ if (command.IsKeepAlive())
+ {
+ if (!m_bEnableKeepAlive)
+ {
+ m_bEnableKeepAlive = true;
+ // FIXME:
+ // read keepalive option here
+ int min_wait = 30;
+ int max_wait = 60;
+ int waitsecond = min_wait + (int)(rand()*(max_wait - min_wait)/(RAND_MAX+1));
+ m_keepAliveTimer.Start(waitsecond * 1000);
+ }
+ }
+ else
+ {
+ if (m_bEnableKeepAlive)
+ {
+ m_bEnableKeepAlive = false;
+ m_keepAliveTimer.Stop();
+ }
+ }
+
+ m_bEnableKeepAlive = true;
+ return FZ_REPLY_OK;
+}
+
+int CFtpControlSocket::DoKeepAlive()
+{
+ LogMessage(Debug_Verbose, _T("CFtpControlSocket::DoKeepAlive"));
+
+ // ignore keepalive for last I/O for socket less than 15 seconds
+ if (m_keepAliveStopWatch.Time() < 15000)
+ return FZ_REPLY_OK;
+ // choose any command
+ wxString commands[6] = {_T("PWD"),_T("REST 0"), _T("NOOP"), _T("STAT"), _T("RMD"), _T("MKD") };
+ int choice=(rand()*6)/(RAND_MAX+1);
+ m_pCurOpData = new CKeepAliveOpData(commands[choice]);
+
+ return SendNextCommand();
+}
+
+int CFtpControlSocket::KeepAliveSend()
+{
+ LogMessage(Debug_Verbose, _T("CFtpControlSocket::KeepAliveSend"));
+
+ if (!m_pCurOpData)
+ {
+ LogMessage(__TFILE__, __LINE__, this, Debug_Info, _T("Empty m_pCurOpData"));
+ ResetOperation(FZ_REPLY_INTERNALERROR);
+ return FZ_REPLY_ERROR;
+ }
+
+ CDirectoryCache cache;
+ cache.InvalidateServer(*m_pCurrentServer);
+ m_CurrentPath = CServerPath();
+
+ CKeepAliveOpData *pData = static_cast<CKeepAliveOpData *>(m_pCurOpData);
+
+ if (!Send(pData->m_command))
+ return FZ_REPLY_ERROR;
+
+ return FZ_REPLY_WOULDBLOCK;
+}
+
+int CFtpControlSocket::KeepAliveParseResponse()
+{
+ LogMessage(Debug_Verbose, _T("CFtpControlSocket::KeepAliveParseResponse"));
+
+ int code = GetReplyCode();
+ if (code == 2 || code == 3 || code == 5)
+ {
+ ResetOperation(FZ_REPLY_OK);
+ return FZ_REPLY_OK;
+ }
+ else
+ {
+ ResetOperation(FZ_REPLY_ERROR);
+ return FZ_REPLY_ERROR;
+ }
+}
+
+void CFtpControlSocket::OnTimer(wxTimerEvent& event)
+{
+ if (event.GetId() == KEEPALIVE_TIMER_ID)
+ {
+ if (m_keepAliveTimer.IsRunning())
+ {
+ m_keepAliveTimer.Stop();
+ if (m_bEnableKeepAlive) {
+ // FIXME:
+ // need to read the values from options...
+ int min_wait = 30;
+ int max_wait = 60;
+
+ int waitsecond = min_wait + (int)(rand()*(max_wait - min_wait)/(RAND_MAX+1));
+ m_keepAliveTimer.Start(waitsecond * 1000);
+ DoKeepAlive();
+ }
+ }
+ }
+ else
+ CControlSocket::OnTimer(event);
}
 
bool CFtpControlSocket::IsMisleadingListResponse() const
diff -Nur Filezilla3/src/engine/ftpcontrolsocket.h Filezilla3.patch/src/engine/ftpcontrolsocket.h
--- Filezilla3/src/engine/ftpcontrolsocket.h Thu Aug 16 12:54:33 2007
+++ Filezilla3.patch/src/engine/ftpcontrolsocket.h Thu Aug 16 12:55:33 2007
@@ -24,6 +24,14 @@
 
protected:

+ bool m_bEnableKeepAlive;
+ wxTimer m_keepAliveTimer;
+ wxStopWatch m_keepAliveStopWatch;
+ virtual int KeepAlive(const CKeepAliveCommand& command);
+ int DoKeepAlive();
+ int KeepAliveParseResponse();
+ int KeepAliveSend();
+
virtual int ResetOperation(int nErrorCode);
 
virtual int Connect(const CServer &server);
@@ -128,6 +136,7 @@
 
DECLARE_EVENT_TABLE();
void OnExternalIPAddress(fzExternalIPResolveEvent& event);
+ void OnTimer(wxTimerEvent& event);
};
 
class CIOThread;
diff -Nur Filezilla3/src/include/commands.h Filezilla3.patch/src/include/commands.h
--- Filezilla3/src/include/commands.h Thu Aug 16 12:54:39 2007
+++ Filezilla3.patch/src/include/commands.h Thu Aug 16 12:56:21 2007
@@ -19,6 +19,7 @@
cmd_rename,
cmd_chmod,
cmd_raw,
+ cmd_keepalive,
 
// Only used internally
cmd_cwd,
@@ -74,6 +75,15 @@
const CServer GetServer() const;
protected:
CServer m_Server;
+};
+
+DECLARE_COMMAND(CKeepAliveCommand, cmd_keepalive)
+ CKeepAliveCommand(bool keepAlive = true);
+
+ bool IsKeepAlive() const;
+
+protected:
+ bool m_keepAlive;
};
 
DECLARE_COMMAND(CDisconnectCommand, cmd_disconnect)
diff -Nur Filezilla3/src/include/engineprivate.h Filezilla3.patch/src/include/engineprivate.h
--- Filezilla3/src/include/engineprivate.h Thu Aug 16 12:54:39 2007
+++ Filezilla3.patch/src/include/engineprivate.h Thu Aug 16 12:56:27 2007
@@ -69,6 +69,7 @@
int Mkdir(const CMkdirCommand& command);
int Rename(const CRenameCommand& command);
int Chmod(const CChmodCommand& command);
+ int KeepAlive(const CKeepAliveCommand& command);
 
int ContinueConnect();
 
diff -Nur Filezilla3/src/interface/Mainfrm.cpp Filezilla3.patch/src/interface/Mainfrm.cpp
--- Filezilla3/src/interface/Mainfrm.cpp Thu Aug 16 12:54:45 2007
+++ Filezilla3.patch/src/interface/Mainfrm.cpp Thu Aug 16 12:57:02 2007
@@ -825,7 +825,10 @@
 
CServerPath path;
path.SetSafePath(COptions::Get()->GetOption(OPTION_LASTSERVERPATH));
- m_pState->Connect(server, false, path);
+ // FIXME:
+ // read keepalive from option
+ bool keepAlive = true;
+ m_pState->Connect(server, false, path, keepAlive);
}
 
void CMainFrame::OnRefresh(wxCommandEvent &event)
@@ -1341,7 +1344,10 @@
return;
}
 
- m_pState->Connect(pData->m_server, true, pData->m_remoteDir);
+ // FIXME:
+ // read keepalive from option
+ bool keepAlive = true;
+ m_pState->Connect(pData->m_server, true, pData->m_remoteDir, keepAlive);
 
if (pData->m_localDir != _T(""))
m_pState->SetLocalDir(pData->m_localDir);
diff -Nur Filezilla3/src/interface/state.cpp Filezilla3.patch/src/interface/state.cpp
--- Filezilla3/src/interface/state.cpp Thu Aug 16 12:54:45 2007
+++ Filezilla3.patch/src/interface/state.cpp Thu Aug 16 12:57:13 2007
@@ -247,7 +247,7 @@
NotifyHandlers(STATECHANGE_APPLYFILTER);
}
 
-bool CState::Connect(const CServer& server, bool askBreak, const CServerPath& path /*=CServerPath()*/)
+bool CState::Connect(const CServer& server, bool askBreak, const CServerPath& path /*=CServerPath()*/, bool keepAlive)
{
if (!m_pEngine)
return false;
@@ -261,6 +261,8 @@
 
m_pCommandQueue->ProcessCommand(new CConnectCommand(server));
m_pCommandQueue->ProcessCommand(new CListCommand(path));
+ if (keepAlive)
+ m_pCommandQueue->ProcessCommand(new CKeepAliveCommand(true));

COptions::Get()->SetLastServer(server);
COptions::Get()->SetOption(OPTION_LASTSERVERPATH, path.GetSafePath());
diff -Nur Filezilla3/src/interface/state.h Filezilla3.patch/src/interface/state.h
--- Filezilla3/src/interface/state.h Thu Aug 16 12:54:43 2007
+++ Filezilla3.patch/src/interface/state.h Thu Aug 16 12:57:18 2007
@@ -40,7 +40,7 @@
static bool LocalDirHasParent(const wxString& dir);
static bool LocalDirIsWriteable(const wxString& dir);
 
- bool Connect(const CServer& server, bool askBreak, const CServerPath& path = CServerPath());
+ bool Connect(const CServer& server, bool askBreak, const CServerPath& path = CServerPath(), bool keepAlive = false);
 
bool SetRemoteDir(const CDirectoryListing *m_pDirectoryListing, bool modified = false);
const CDirectoryListing *GetRemoteDir() const;

Patch 可以由這兒抓取: http://www.teatime.com.tw/~tommy/mypatch/filezilla3_rc1_keepalive2.patch
製作出來的 Windows 執行檔可以由這兒抓: http://www.teatime.com.tw/~tommy/files/filezilla/filezilla3_rc1.7z

有需要的就自己抓回去用吧.

Del.icio.us Furl HEMiDEMi Technorati MyShare
迴響
暱稱:
標題:
個人網頁:
電子郵件:
迴響

  

Bad Behavior 已經阻擋了 133 個過去 7 天試圖闖關的垃圾迴響與引用。
Power by LifeType. Template design by JamesHuang. Valid XHTML and CSS