FileZilla 源代碼分析7
FileZilla是一種快速、可信賴的FTP客戶端以及服務器端開放源代碼程式,具有多種特色、直覺的接口。本文就給大家分析下FileZilla的源代碼。
服務線程蘇醒后,調用OnThreadMessage來處理這個WM_FILEZILLA_THREADMSG消息,參數是FTM_NEWSOCKET, sockethandle,接著進入AddNewSocket方法,表示有一個新的客戶端需要連接上來。
void CServerThread::AddNewSocket(SOCKET sockethandle, bool ssl)
{
// 首先創建了新的CControlSocket類,這也是繼承于CAsyncSocketEx類的,從下面起經過一些初始化之后,就由這個CControlSocket類來接管這個客戶連接了。
CControlSocket *socket = new CControlSocket(this);
socket->Attach(sockethandle); // 加入到FileZilla消息機制中, 建立與分發線程等之間的關系
CStdString ip;
unsigned int port;
SOCKADDR_IN sockAddr;
memset(&sockAddr, 0, sizeof(sockAddr));
int nSockAddrLen = sizeof(sockAddr);
BOOL bResult = socket->GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen); // 獲取socket客戶端的信息
if (bResult)
{
port = ntohs(sockAddr.sin_port); // 端口
ip = inet_ntoa(sockAddr.sin_addr); // IP地址
}
else
{
socket->m_RemoteIP = _T("ip unknown");
socket->m_userid = 0;
socket->SendStatus(_T("Can't get remote IP, disconnected"), 1);
socket->Close();
delete socket;
return;
}
socket->m_RemoteIP= ip;
EnterCritSection(m_GlobalThreadsync);
int userid = CalcUserID(); // 自動為當前socket連接生成一個客戶號:userID
if (userid == -1)
{
LeaveCritSection(m_GlobalThreadsync);
socket->m_userid = 0;
socket->SendStatus(_T("Refusing connection, server too busy!"), 1);
socket->Send(_T("421 Server too busy, closing connection. Please retry later!"));
socket->Close();
delete socket;
return;
}
socket->m_userid = userid;
t_socketdata data;
data.pSocket = socket;
data.pThread = this;
m_userids[userid] = data; // m_userids是static的,定義為static std::map m_userids;
// hammering這塊可以先不管
// Check if remote IP is blocked due to hammering
std::map::iterator iter = m_antiHammerInfo.find(sockAddr.sin_addr.s_addr);
if (iter != m_antiHammerInfo.end())
{
if (iter->second > 10)
socket->AntiHammerIncrease(25); // ~6 secs delay
}
LeaveCritSection(m_GlobalThreadsync);
EnterCritSection(m_threadsync);
// 下面記錄這個服務線程所處理的CControlSocket
m_LocalUserIDs[userid] = socket;
LeaveCritSection(m_threadsync);
t_connectiondata_add *conndata = new t_connectiondata_add;
t_connop *op = new t_connop;
op->data = conndata;
op->op = USERCONTROL_CONNOP_ADD; // 新用戶連接即將連接,在CServer的OnServerMessage中要用過
op->userid = userid;
conndata->pThread = this;
memset(&sockAddr, 0, sizeof(sockAddr));
nSockAddrLen = sizeof(sockAddr);
bResult = socket->GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen);
if (bResult)
{
conndata->port = ntohs(sockAddr.sin_port);
#ifdef _UNICODE
_tcscpy(conndata->ip, ConvFromLocal(inet_ntoa(sockAddr.sin_addr))); // 拷貝字符串
#else
_tcscpy(conndata->ip, inet_ntoa(sockAddr.sin_addr));
#endif
}
// 這里往全局的hMainWnd發送消息,
// 消息的wParam類型為FSM_CONNECTIONDATA, 指示消息是跟connection相關的消息,參數是t_connop
// 這些在CServer的WindowProc中處理這個消息時用到,這個消息處理結束后,會在admin窗口的下邊顯示
// 類似000001 (not logged in) 127.0.0.1 的信息
SendNotification(FSM_CONNECTIONDATA, (LPARAM)op);
if (ssl) // SSL相關, 可以先跳過
if (!socket->InitImplicitSsl())
return;
socket->AsyncSelect(FD_READ|FD_WRITE|FD_CLOSE); // 對socket上這些event建立偵聽關系
// SendStatus最終還是調用SendNotification方法,不過發送的參數是FSM_STATUSMESSAGE,
// 因此在CServer中的處理并不一樣
socket->SendStatus(_T("Connected, sending welcome message..."), 0);
// 這時,admin窗口的下半部分會顯示類似(000003) 2006-8-24 3:26:47 - (not logged in) (127.0.0.1)> Connected, sending welcome message...
// 下面格式化歡迎信息
CStdString msg = m_pOptions->GetOption(OPTION_WELCOMEMESSAGE);
if (m_RawWelcomeMessage != msg)
{
m_RawWelcomeMessage = msg;
m_ParsedWelcomeMessage.clear();
msg.Replace(_T("%%"), _T("\001"));
msg.Replace(_T("%v"), GetVersionString());
msg.Replace(_T("\001"), _T("%"));
ASSERT(msg != _T(""));
int oldpos = 0;
msg.Replace(_T("\r\n"), _T("\n"));
int pos=msg.Find(_T("\n"));
CStdString line;
while (pos!=-1)
{
ASSERT(pos);
m_ParsedWelcomeMessage.push_back(_T("220-") + msg.Mid(oldpos, pos-oldpos) );
oldpos=pos + 1;
pos=msg.Find(_T("\n"), oldpos);
}
line = msg.Mid(oldpos);
if (line != _T(""))
m_ParsedWelcomeMessage.push_back(_T("220 ") + line);
else
{
m_ParsedWelcomeMessage.back()[3] = 0;
}
}
// hideStatus指示這個歡迎消息要不要發給admin port
bool hideStatus = m_pOptions->GetOptionVal(OPTION_WELCOMEMESSAGE_HIDE) != 0;
ASSERT(!m_ParsedWelcomeMessage.empty());
for (std::list
// 發送給socket客戶, 并且發送消息到admin port上,發送的參數是FSM_STATUSMESSAGE
if (!socket->Send(*iter, !hideStatus))
break;
// 運行到這里,客戶的登錄界面上、admin窗口上半部已經出現了welcome信息,類似:
// (000003) 2006-8-24 3:27:19 - (not logged in) (127.0.0.1)> 220-FileZilla Server version 0.9.18 beta
// ((000003) 2006-8-24 3:27:22 - (not logged in) (127.0.0.1)> 220-written by Tim Kosse (Tim.Kosse@gmx.de)
// ((000003) 2006-8-24 3:27:29 - (not logged in) (127.0.0.1)> 220 Please visit http://sourceforge.net/projects/filezilla/
通過文章完整的描述,大家應該知道了FileZilla 源代碼,希望對大家有幫助!
【編輯推薦】