Tommy 碎碎念

Tommy Wu's blog

« 上一篇 | 下一篇 »

KeepAlive patch for FileZilla3
post by tommy @ 15 八月, 2007 22:21

FileZilla 3 rc1 裡頭, sftp 似乎原本就有 keepalive 的功能, 但是在 FTP 裡頭, 這個功能並不存在. 所以當 FTP 連線過一段時間後, 會發現目前的連線就因為 timeout 而中斷了. 如果要使用就必須重新連線. 不知道為什麼作者一直不把這個在 FileZilla 2 就提供的功能, 實作到 FileZilla 3? 這兩天因為看了 FileZilla 3 的 source code, 就順便加上這個功能.

這個 patch 內容如下:

diff -Nur Filezilla3/src/engine/ControlSocket.h Filezilla3.patch/src/engine/ControlSocket.h
--- Filezilla3/src/engine/ControlSocket.h Wed Aug 15 21:15:50 2007
+++ Filezilla3.patch/src/engine/ControlSocket.h Wed Aug 15 21:34:19 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 Wed Aug 15 21:15:52 2007
+++ Filezilla3.patch/src/engine/FileZillaEngine.cpp Wed Aug 15 21:34:45 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/engineprivate.cpp Filezilla3.patch/src/engine/engineprivate.cpp
--- Filezilla3/src/engine/engineprivate.cpp Wed Aug 15 21:15:52 2007
+++ Filezilla3.patch/src/engine/engineprivate.cpp Wed Aug 15 21:35:14 2007
@@ -525,6 +525,18 @@
return m_pControlSocket->Chmod(command);
}
 
+int CFileZillaEnginePrivate::KeepAlive(const CKeepAliveCommand& command)
+{
+ if (!IsConnected())
+ return FZ_REPLY_NOTCONNECTED;
+
+ if (IsBusy())
+ return FZ_REPLY_BUSY;
+
+ 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 Wed Aug 15 21:15:52 2007
+++ Filezilla3.patch/src/engine/ftpcontrolsocket.cpp Wed Aug 15 21:38:08 2007
@@ -147,6 +147,8 @@
{
LogMessage(Debug_Verbose, _T("CFtpControlSocket::OnReceive()"));
 
+ m_stopWatch.Start();
+
m_pBackend->Read(m_receiveBuffer + m_bufferLen, RECVBUFFERSIZE - m_bufferLen);

if (m_pBackend->Error())
@@ -386,6 +388,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 +803,7 @@
LogMessage(::Error, _T("Failed to convert command to 8 bit charset"));
return false;
}
+ m_stopWatch.Start();
unsigned int len = (unsigned int)strlen(buffer);
bool res = CRealControlSocket::Send(buffer, len);
if (res)
@@ -1254,6 +1260,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);
@@ -3007,6 +3015,74 @@
 
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, _("CFtpControlSocket::KeepAlive"));
+
+ // ignore keepalive for last I/O for socket less than 15 seconds
+ if (m_stopWatch.Time() < 15000)
+ return FZ_REPLY_OK;
+ // choose any command
+ wxString commands[4] = {_T("PWD"),_T("REST 0"), _T("TYPE A"), _T("TYPE I") };
+ int choice=(rand()*4)/(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)
+ {
+ ResetOperation(FZ_REPLY_OK);
+ return FZ_REPLY_OK;
+ }
+ else
+ {
+ ResetOperation(FZ_REPLY_ERROR);
+ return FZ_REPLY_ERROR;
+ }
+}
+
 
bool CFtpControlSocket::IsMisleadingListResponse() const
{
diff -Nur Filezilla3/src/engine/ftpcontrolsocket.h Filezilla3.patch/src/engine/ftpcontrolsocket.h
--- Filezilla3/src/engine/ftpcontrolsocket.h Wed Aug 15 21:15:50 2007
+++ Filezilla3.patch/src/engine/ftpcontrolsocket.h Wed Aug 15 21:30:14 2007
@@ -24,6 +24,11 @@
 
protected:

+ wxStopWatch m_stopWatch;
+ virtual int KeepAlive(const CKeepAliveCommand& command);
+ int KeepAliveParseResponse();
+ int KeepAliveSend();
+
virtual int ResetOperation(int nErrorCode);
 
virtual int Connect(const CServer &server);
diff -Nur Filezilla3/src/include/commands.h Filezilla3.patch/src/include/commands.h
--- Filezilla3/src/include/commands.h Wed Aug 15 21:15:37 2007
+++ Filezilla3.patch/src/include/commands.h Wed Aug 15 21:15:07 2007
@@ -19,6 +19,7 @@
cmd_rename,
cmd_chmod,
cmd_raw,
+ cmd_keepalive,
 
// Only used internally
cmd_cwd,
@@ -76,6 +77,8 @@
CServer m_Server;
};
 
+DECLARE_COMMAND(CKeepAliveCommand, cmd_keepalive)
+};
DECLARE_COMMAND(CDisconnectCommand, cmd_disconnect)
};
 
diff -Nur Filezilla3/src/include/engineprivate.h Filezilla3.patch/src/include/engineprivate.h
--- Filezilla3/src/include/engineprivate.h Wed Aug 15 21:15:37 2007
+++ Filezilla3.patch/src/include/engineprivate.h Wed Aug 15 21:15:07 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 Wed Aug 15 21:15:58 2007
+++ Filezilla3.patch/src/interface/Mainfrm.cpp Wed Aug 15 21:33:21 2007
@@ -43,6 +43,7 @@
#endif
 
#define TRANSFERSTATUS_TIMER_ID wxID_HIGHEST + 3
+#define KEEPALIVE_TIMER_ID TRANSFERSTATUS_TIMER_ID + 1
 
static const int statbarWidths[6] = {
#ifdef __WXMSW__
@@ -159,6 +160,7 @@
}
 
m_transferStatusTimer.SetOwner(this, TRANSFERSTATUS_TIMER_ID);
+ m_keepAliveTimer.SetOwner(this, KEEPALIVE_TIMER_ID);
 
CreateMenus();
CreateToolBar();
@@ -696,6 +698,7 @@
if (!m_pState->m_pCommandQueue->Idle())
return;
 
+ m_keepAliveTimer.Stop();
m_pState->m_pCommandQueue->ProcessCommand(new CDisconnectCommand());
}
 
@@ -769,6 +772,8 @@
m_pSendLed = 0;
m_pRecvLed = 0;
 
+ m_keepAliveTimer.Stop();
+
m_transferStatusTimer.Stop();
 
bool res = true;
@@ -826,6 +831,9 @@
CServerPath path;
path.SetSafePath(COptions::Get()->GetOption(OPTION_LASTSERVERPATH));
m_pState->Connect(server, false, path);
+ // FIXME:
+ // need to read from options, do this only for KeepAlive enabled
+ m_keepAliveTimer.Start(1000);
}
 
void CMainFrame::OnRefresh(wxCommandEvent &event)
@@ -898,6 +906,39 @@
else
m_transferStatusTimer.Stop();
}
+ else if (event.GetId() == KEEPALIVE_TIMER_ID && m_keepAliveTimer.IsRunning())
+ {
+ // make sure engine and commandqueue exist
+ if (!m_pState && !m_pState->m_pEngine && !m_pState->m_pCommandQueue)
+ {
+ m_keepAliveTimer.Stop();
+ return;
+ }
+ // just do this for idle, wait for next timer
+ if (!m_pState->m_pCommandQueue->Idle())
+ return;
+ // if not connected, stop keepalive timer
+ if (!m_pState->m_pEngine->IsConnected())
+ {
+ m_keepAliveTimer.Stop();
+ return;
+ }
+ // FIXME:
+ // need to read the values from options...
+ int min_wait = 30;
+ int max_wait = 60;
+
+ // if just connected, the interval will be 1000
+ bool first_time = (m_keepAliveTimer.GetInterval() == 1000);
+
+ int waitsecond = min_wait + (int)(rand()*(max_wait - min_wait)/(RAND_MAX+1));
+ m_keepAliveTimer.Stop();
+ m_keepAliveTimer.Start(waitsecond * 1000);
+ // skip keepalive for just connected
+ if (first_time)
+ return;
+ m_pState->m_pCommandQueue->ProcessCommand(new CKeepAliveCommand());
+ }
}
 
void CMainFrame::SetProgress(const CTransferStatus *pStatus)
@@ -1342,6 +1383,9 @@
}
 
m_pState->Connect(pData->m_server, true, pData->m_remoteDir);
+ // FIXME:
+ // need to read from options, do this only for KeepAlive enabled
+ m_keepAliveTimer.Start(1000);
 
if (pData->m_localDir != _T(""))
m_pState->SetLocalDir(pData->m_localDir);
diff -Nur Filezilla3/src/interface/Mainfrm.h Filezilla3.patch/src/interface/Mainfrm.h
--- Filezilla3/src/interface/Mainfrm.h Wed Aug 15 21:15:56 2007
+++ Filezilla3.patch/src/interface/Mainfrm.h Wed Aug 15 21:15:21 2007
@@ -84,6 +84,9 @@
CLed* m_pRecvLed;
CLed* m_pSendLed;
wxTimer m_transferStatusTimer;
+
+ wxTimer m_keepAliveTimer;
+
CThemeProvider* m_pThemeProvider;
#if FZ_MANUALUPDATECHECK && FZ_AUTOUPDATECHECK
CUpdateWizard* m_pUpdateWizard;

Patch 可以由這兒抓取: http://www.teatime.com.tw/~tommy/mypatch/filezilla3_rc1_keepalive.patch
製作出來的 Windows 執行檔可以由這兒抓: http://www.teatime.com.tw/~tommy/files/filezilla/filezilla3_rc1.7z
Patch 已送給作者: http://sourceforge.net/tracker/index.php?func=detail&aid=1774714&group_id=21558&atid=372243

由於不知道怎麼處理設定的部份,  所以這個版本一定會啟用 keepalive 的功能, 目前是 30-60 秒會送出一個指令, 設定的部份如果作者接受這個 patch 的話, 就應該會加上吧.

如果有需要可以先抓上頭的版本回去使用吧. 如果這個版本執行時, 使用某些 dialog (如 About ...) 會當掉的話, 可以抓 nightly builds 裡頭的 zip, 把裡面的 resources 目錄的檔案覆蓋掉你目前的版本就可以了.

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

迴響

  

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