FileZilla兼容FtpAnywhere
圖-FileZilla
FileZilla FTP是一個(gè)著名的開源標(biāo)準(zhǔn)FTP客戶端軟件,但是它的目前版本與FtpAnywhere提供的網(wǎng)格FTP有兼容問題,而且,目前無法通過它提供的那些設(shè)置模塊來實(shí)現(xiàn)兼容,因此,我特地下載了它的源代碼快照 [2009.4.16] ,看看是否有可能通過修改源代碼來讓它兼容.
解壓縮它的源代碼,轉(zhuǎn)到子目錄\src\engine下,打開ftpcontrolsocket.cpp文件,這個(gè)文件就是FileZilla用來支持標(biāo)準(zhǔn)FTP指令的核心,需要改造的是它的列表模式以及對(duì)PASV反饋的分析代碼 [包括IPV6下的EPSV指令,但是暫時(shí)因?yàn)闆]有IPV6,所以沒必要?jiǎng)铀黓,改造它的PASV解析代碼
讓FileZilla兼容FtpAnywhere
- bool CFtpControlSocket::ParsePasvResponse(CRawTransferOpData* pData)
- {
- // Validate ip address
- wxString digit = _T("0*[0-9]{1,3}");
- const wxChar* dot = _T(",");
- wxString exp = _T("( |\\()(") + digit + dot + digit + dot + digit + dot + digit + dot + digit + dot + digit + _T(")( |\\)|$)");
- wxRegEx regex;
- regex.Compile(exp);
- if (!regex.Matches(m_Response))
- return false;
- pData->host = regex.GetMatch(m_Response, 2);
- int i = pData->host.Find(',', true);
- long number;
- if (i == -1 || !pData->host.Mid(i + 1).ToLong(&number))
- return false;
- pData->port = number; //get ls byte of server socket
- pData->host = pData->host.Left(i);
- i = pData->host.Find(',', true);
- if (i == -1 || !pData->host.Mid(i + 1).ToLong(&number))
- return false;
- pData->port += 256 * number; //add ms byte of server socket
- pData->host = pData-> host.Left(i);
- pData->host.Replace(_T(","), _T("."));
- if (m_pProxyBackend)
- {
- // We do not have any information about the proxy's inner workings
- return true;
- }
//注意,把下面的代碼注銷,就可以支持P2P PASV模式下的連接傳輸了
- //const wxString peerIP = m_pSocket->GetPeerIP();
- //if (!IsRoutableAddress(pData->host, m_pSocket->GetAddressFamily()) && IsRoutableAddress(peerIP, m_pSocket->GetAddressFamily()))
- //{
- //if (!m_pEngine->GetOptions()->GetOptionVal(OPTION_PASVREPLYFALLBACKMODE) || pData->bTriedActive)
- //{
- //LogMessage(Status, _("Server sent passive reply with unroutable address. Using server address instead."));
- //LogMessage(Debug_Info, _T(" Reply: %s, peer: %s"), pData->host.c_str(), peerIP.c_str());
- //pData->host = peerIP;
- //}
- //else
- //{
- //LogMessage(Status, _("Server sent passive reply with unroutable address. Passive mode failed."));
- //LogMessage(Debug_Info, _T(" Reply: %s, peer: %s"), pData->host.c_str(), peerIP.c_str());
- //return false;
- //}
- //}
- return true;
- }
那么現(xiàn)在的代碼,只要在站點(diǎn)屬性的連接模式里,指定PORT為優(yōu)先,在PORT模式連接失敗后,設(shè)置自動(dòng)切換到PASV模式,已經(jīng)可以有條件兼容,只是第一次下載會(huì)失敗而已,下面我們改造它的列表模式,讓它具備更好的兼容性. 當(dāng)然,你可以在FtpAnywhere服務(wù)器里,設(shè)置禁止根目錄下PASV列表,來讓FileZilla自動(dòng)判斷連接模式,但是從它的代碼看,它的判斷還是存在一點(diǎn)兼容問題.因此,將LIST改造成主動(dòng)模式優(yōu)先,是最好的選擇.
問題在這里
- CRawTransferOpData::CRawTransferOpData()
- : COpData(cmd_rawtransfer)
- {
- bTriedPasv = bTriedActive = false;
- bPasv = true;
- }
它的初始化是被動(dòng)模式優(yōu)先,這樣,列表的時(shí)候?qū)l(fā)生問題,但是下載可以成功,但是我閱讀代碼,發(fā)現(xiàn)除非額外指定一個(gè)列表時(shí)優(yōu)先使用的模式變量,否則很難修改代碼,因?yàn)樗拇a中列表和文件傳輸?shù)膬?yōu)先模式是一致的,還要適應(yīng)其他標(biāo)準(zhǔn)FTP站點(diǎn),畢竟我不可以能讓它為我的FtpAnywhere進(jìn)行優(yōu)化,方法是,在FtpControlSocket.h里定義的類
- class CRawTransferOpData : public COpData
- {
- public:
- CRawTransferOpData();
- wxString cmd;
- CFtpTransferOpData* pOldData;
- bool bPasv;
- bool bTriedPasv;
- bool bTriedActive;
- wxString host;
- int port;
- };
給它加個(gè)額外的變量,例如 bool bFtpAnywhere;然后,在List指令前,確定首先采用PASV或者PORT前,判斷 bFtpAnywhere是否為真,如果為真,那么列表應(yīng)該優(yōu)先采用PORT模式,否則繼續(xù)執(zhí)行默認(rèn)的動(dòng)作;而bFtpAnywhere的初始化應(yīng)該從給服務(wù)器發(fā)送 VDSI指令是否返回2XX來判斷,是否是一個(gè)FtpAnywhere服務(wù)器,因?yàn)檫@里涉及的修改太多,除非FileZilla代碼維護(hù)人員同意,否則沒有意義,因此,最簡單最快的方法還是直接注銷我上面給出的代碼,雖然無法獲得100%兼容,但是基本可以兼容,而且通過設(shè)置項(xiàng)目,可以做到手動(dòng)兼容.
通過文章描寫和代碼的分析,我們可以清楚的知道:FileZilla是兼容FtpAnywhere,希望對(duì)大家有用!
【編輯推薦】