青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

大漠落日

while(!dead) study++;
posts - 46, comments - 126, trackbacks - 0, articles - 0
  C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

FileZilla Server源碼分析(3)

Posted on 2010-06-10 13:38 亂78糟 閱讀(2357) 評論(1)  編輯 收藏 引用 所屬分類: 開源
這是分析的第三節,上一節主要講了一些和socket基礎操作相關的代碼,本節將分析核心代碼。

Service.cpp   系統服務程序

FileZillaServer可以選擇是否注冊成windows的服務程序,而這個服務程序的代碼就是由service.cpp文件實現的。
WinMain是它的入口函數,在WinMain里依次完成了下面幾項任務:
  1. 參數解析
  2. 初始化某些數據比如端口
  3. 由SCM(服務控制管理器)啟動服務,入口為ServiceMain函數;如果服務不存在,進入步驟4
  4. 根據參數設置服務,例如安裝、啟動、卸載等。
ServiceMain注冊ServiceCtrlHandler來處理服務的控制代碼,在回調函數ServiceCtrlHandler中自定義了128號控制碼,用于向窗口"FileZilla Server Helper Window"發送重新讀取配置的自定義消息WM_FILEZILLA_RELOADCONFIG
serviceMain注冊Handler成功之后,就啟動自己的工作線程ServiceExecutionThread,線程里創建了CServer對象,然后實際流程交由CServer。之后進入線程的消息循環并等待killServiceEvent信號以退出線程終止服務。
Service.cpp中KillService函數中有一個變量hMainWnd,它是在stdafx.h中聲明的,它具體是哪個窗口的句柄,干什么用,現在還是一無所知。


Server.*  真正的帶頭大哥

打開Server.h文件,開頭就可以看到許多類的前置聲明,類中聲明了眾多上一節提到的相關類對象(或集合如list),CServer類把所有核心類(線程和socket)集中起來使用。
上面已經提到Service的工作線程中調用了CServer的Create函數,我們就先從這里入手吧。
Create一開始就創建了一個窗口,標題為"FileZilla Server Helper Window",呵呵,是不是很熟悉?然后將這個窗口的句柄賦給全局變量hMainWnd,至此,終于大致了解了服務的框架骨骼。
之后又是一大堆初始化操作,包括兩個定時器,需要特別注意的是創建服務線程CServerThread時候的提供的參數WM_FILEZILLA_SERVERMSG + index,這個參數用以線程間通信,再上一節已經有過描述,稍后再具體分析。
在往下調用了CreateListenSocket函數,這個函數根據Options類中獲取的port、bindip、enablessl等參數創建監聽ftp客戶端連接的CListenSocket對象指針,并保存到m_ListenSocketList中。這里有一個很重要的函數ShowStatus,它的任務是將信息發送給admin窗口和記錄到log中。
最后調用CreateAdminListenSocket函數創建監聽admin客戶端的socket,并存入m_AdminListenSocketList中。

CServer類的分析暫時中斷一下,我們來分析上面涉及到的幾個相關類:CServerThread,CListenSocket,CControlSocket,CTransferSocket。

CServerThread繼承自CThread,構造函數有個int型參數,用來標識具體哪個線程的消息。注意,CThread本身并不是一個直接繼承于任何線程類的類,它只是負責創建并管理線程的類。m_sInstanceList是static的成員變量,被所有的CServerThread對象共享,而且這個list存儲的第一個值用于管理SL,為了標識它,作者又添加了一個BOOL成員變量m_bIsMaster,同樣還有一個static臨界區變量m_GlobalThreadsync用來同步它。如果當前對象是master,那么它還擁有一個用于實現PASV模式的CExternalIpCheck的類對象m_pExternalIpCheck,缺省值是不采用PASV的。

對CServerThread的重要的幾個Public成員函數分析一下功能:
  • GetExternalIP : 調用m_pExternalIpCheck獲取PASV的ip
  • AddSocket:給自己發送一個線程消息,該消息在OnThreadMessage函數中被處理,用來添加(SSL)socket連接

對CServerThread重要的幾個非public成員函數分析一下功能:
  • AddNewSocket:將sokcet handle綁定到新new的CControlSocket對象socket上,并為當前socket分配一個唯一的用戶ID。分配函數CalcUserID不算高效,尤其是連接用戶數量比較大的時候再分配尤其明顯。之后調用SendNotification準備發送包含連接用戶的信息的消息給CServer,最后向連接的用戶發送歡迎信息。
  • SendNotification:這個函數將需要發送的數據加入待發送list中,最牛的是它可以自動調節發送的效率。不過我發現一處小BUG,可能作者自己也沒有注意到,這兩處設置線程優先級貌似反了:
else if (m_pendingNotifications.size() > 150 && m_throttled < 2)
{
    SetPriority(THREAD_PRIORITY_LOWEST);
    m_throttled 
= 2;
}
else if (m_pendingNotifications.size() > 100 && !m_throttled)
{
    SetPriority(THREAD_PRIORITY_BELOW_NORMAL);
    m_throttled 
= 1;
}

  • OnThreadMessage:線程消息處理函數,如添加刪除用戶,解析命令,傳輸,控制,計時器等。

CListenSocket類功能很簡單,如果一個連接被accept,那么從服務線程CServerThread列表中找到負載最小的線程,然后調用的AddSocket函數,將這個連接交給這個CServerTread管理。

CControlSocket類負責與客戶端交互。
它有一個int型成員變量m_antiHammeringWaitTime,用來防止用戶攻擊(即無限次嘗試登錄),例如某用戶在60秒內連續嘗試登錄10次失敗,那么就把這個用戶加入ban列表中,比如3000秒內拒絕再次登錄等。AntiHammerIncrease 函數中對這個變量的算法沒看明白
if (m_status.hammerValue > 2000)
    m_antiHammeringWaitTime 
+= 1000 * (int)pow(1.3, (m_status.hammerValue / 400- 5);
在用戶登錄的時候就去檢測是否是“攻擊”,代碼如下:
    BOOL bResult = GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen);
        
if (bResult)
            m_pOwner
->AntiHammerIncrease(sockAddr.sin_addr.s_addr);

        
if (m_pOwner->m_pAutoBanManager->RegisterAttempt(htonl(sockAddr.sin_addr.s_addr)))
        {
            Send(_T(
"421 Temporarily banned for too many failed login attempts"));
            ForceClose(
-1);
            
return FALSE;
        }

PassCommand函數處理所有的命令,如USER、LIST、PASV、STOR等。當收到STOR命令時,如果是PASV模式,那么調用m_transferstatus.socket->PasvTransfer(),否則新建一個CTransferSocket套接字賦給m_transferstatus.socket,然后調用SendTransferinfoNotification發送TRANSFERMODE_RECEIVE消息。不管哪種方式,最后還是通過調用CTransferSocket的InitTransfer函數實現文件傳輸。


好了,現在讓我們恢復現場。
CServer類的消息處理函數WindowProc,處理了各種消息,其中重要的是WM_DESTROYWM_FILEZILLA_SERVERMSG。前者通知并等待所有線程退出,關閉socket,銷毀資源,殺死定時器,做的都是清理工作。后者根據服務線程發送來的消息進入函數OnServerMessage中,這個函數處理了所有服務管理的消息。可以看到,很多消息最后都是通過m_pAdminInterface->SendCommand(2, 3, buffer, len)這句發送出去。CAdminInterface類管理CAdminSocket類的指針列表,SendCommand其實是調用CAdminSocket的SendCommand將消息發送出去。函數中對admin socket做了自動管理,如果操作失敗,就自動移除該socket。
CheckForTimeout每10秒由CServer的定時器調用一次,檢測admin socket是否超時,如果超時,自動移除。CAdminSocket收到數據并解析成功之后,最終交由CServer的ProcessCommand處理,該函數再一次根據Options里的設置對線程、socket進行一次校驗和調整。

我個人對ProcessCommand和SendCommand函數參數中的type或nID為int型有微議,因為這兩個參數實際只占用了不到8個字節,寫為int不利于理解,如果改成int8一眼就能看出來這個參數具體占用幾個字節。
BOOL CAdminSocket::SendCommand(int nType, int nID, const void *pData, int nDataLength)
{
    
/**/
    t_data data;
    data.pData 
= new unsigned char[nDataLength + 5];
    
*data.pData = nType;     //nType目前版本只要不為0就是合法的協議類型,代碼中用到了1和2
    
*data.pData |= nID << 2//nType和nID合用一個8字節
    data.dwOffset = 0;
    memcpy(data.pData 
+ 1&nDataLength, 4);
    
/**/
}

下面重點分析一下ProcessCommand這個函數,用偽代碼比較直觀。
BOOL CServer::ProcessCommand(CAdminSocket *pAdminSocket, int nID, unsigned char *pData, int nDataLength)
{
    
switch(nID)
    { 
    
case 2:
       
if (!nDataLength)
           
//獲取服務器狀態
       else
           
//設置服務器狀態并獲取
       else
           
//send error:wrong protocol type
       break;
     
case 3:
        
if (!nDataLength)
           
//send error
        else if (*pData == USERCONTROL_GETLIST)
           
//計算并格式化所有已連接用戶的信息到unsigned char *buffer中并發送給admin
           
//這些數據顯示在admin UI下方的user list中
        else if (*pData == USERCONTROL_KICK || *pData == USERCONTROL_BAN)
            
//*pData共5個字節,第一個為具體協議類型,后四個為userID。
            
//根據協議對userID進行操作,kick或者Ban掉。
        else
             
//send error: wrong protocol type
         break;
    
case 5:
         
if (!nDataLength)
            
//讀取基本配置然后發送給admin
         else if (*m_pOptions)
            
//解析配置字符串,創建初始化或調整CServerThread
            
//CreateListenSocket
            
//創建admin監聽sockets
          break;
     
case 6:
          
if (!nDataLength)
              
//讀取user和group的權限配置
          else
              
//解析權限配置發送給admin
          break;
     
case 8:
          pAdminSocket
->SendCommand(18, NULL, 0);
          
break;
      
default:
          
//send error: unknow command
    }
    
return true;
}

這一節涵蓋了眾多核心代碼,上面的分析相對來說還是比較粗略,所以,后面幾節在對這些粗略和遺漏部分在做更為詳細深入的挖掘,本節到這里就結束了。
因為都是看代碼時臨時寫入筆記的,所有的分析都很雜亂,希望以后我有時間可以畫一些圖,重新做一次整理。
2010-7-22補充
圖隨便畫了幾張,鏈接在此

PS: 本來上周就可以貼出來了,可是因為安裝MAC系統造成C盤WINDOWS系統數據破壞無法啟動,重裝系統導致筆記丟失,這里只能補上,拖后了一周左右。

Feedback

# re: FileZilla Server源碼分析(3) [未登錄]  回復  更多評論   

2012-03-19 16:34 by ww
SendNotification:這個函數將需要發送的數據加入待發送list中,最牛的是它可以自動調節發送的效率。不過我發現一處小BUG,可能作者自己也沒有注意到,這兩處設置線程優先級貌似反了

這個他在注釋中已經寫了
// Check if main thread can't handle number of notifications fast enough, throttle thread if neccessary


是要讓主系程 降低優先級的 并沒有作者所說的反了
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美在线视频免费| 91久久夜色精品国产九色| 亚洲激情一区二区| 久久精品99久久香蕉国产色戒| 久久国产欧美日韩精品| 国产一区二区三区久久久久久久久| 亚洲综合成人在线| 免费成人av在线看| 亚洲天堂视频在线观看| 国产精品久久久久久久久久三级 | 亚洲视频综合在线| 午夜精品理论片| 亚洲成色777777女色窝| 欧美日韩中文字幕| 久久人人看视频| 亚洲国产综合视频在线观看| 亚洲九九爱视频| 免费人成精品欧美精品| 亚洲激情小视频| 中文精品视频| 久久久国产成人精品| 亚洲永久免费| 亚洲第一主播视频| 在线一区日本视频| 亚洲精品专区| 欧美一区二区三区四区在线| 亚洲人成毛片在线播放| 黄色一区二区三区四区| 欧美午夜在线一二页| 欧美国产日韩视频| 玖玖国产精品视频| 欧美在线视频观看| 欧美人牲a欧美精品| 蜜臀av一级做a爰片久久| 欧美一级午夜免费电影| 欧美一区二区观看视频| 欧美日本成人| 亚洲国产片色| 久久综合久久久| 免费欧美网站| 欧美一区二区三区日韩| 欧美精品午夜视频| 欧美偷拍一区二区| 亚洲激情视频网站| 久久综合亚州| 男女精品视频| 欧美激情第五页| 亚洲国产高清aⅴ视频| 欧美激情1区2区3区| 久久精品国产亚洲精品| 久久久精品一区二区三区| 欧美小视频在线| 一区二区动漫| 亚洲日本欧美天堂| 亚洲视频一二三| 一本一本a久久| 在线一区免费观看| 欧美日韩精品国产| 国产精品网站一区| 国产日韩一区在线| 在线精品福利| 噜噜噜91成人网| 久久视频在线免费观看| 欧美日韩激情网| 99re6热只有精品免费观看| 亚洲综合999| 在线午夜精品| 国产精品福利av| 加勒比av一区二区| 巨乳诱惑日韩免费av| 久久精品免费观看| 亚洲高清在线| 亚洲欧美在线磁力| 99国产精品99久久久久久粉嫩| 一色屋精品视频免费看| 亚洲精品男同| 午夜国产不卡在线观看视频| 99热这里只有成人精品国产| 亚洲欧美激情精品一区二区| 国产精品99免费看 | 日韩亚洲在线| 亚洲精品视频在线| 欧美一区二区三区免费在线看| 国产欧美日韩视频| 一本色道久久综合一区| 久久裸体艺术| 麻豆精品在线视频| 一区二区三区免费看| 亚洲午夜免费视频| 欧美激情第一页xxx| 亚洲私拍自拍| 久久成人免费网| 99精品国产热久久91蜜凸| 亚洲一级黄色| 亚洲国产美女精品久久久久∴| 亚洲欧洲在线视频| 国产日韩亚洲欧美综合| 亚洲国产精品久久久久秋霞蜜臀 | 欧美综合激情网| 亚洲人成7777| 国产九区一区在线| 午夜伦欧美伦电影理论片| 欧美一区二区三区播放老司机| 亚洲高清免费视频| 亚洲永久免费观看| 国产精品久久久久免费a∨大胸| 欧美一区永久视频免费观看| 欧美成人r级一区二区三区| 国内伊人久久久久久网站视频 | 六月婷婷一区| 午夜一区不卡| 亚洲深夜激情| 亚洲国产欧美日韩精品| 午夜精品久久久久久久蜜桃app| 欧美午夜电影在线| 欧美高清视频一区| 另类尿喷潮videofree| 午夜精品久久久久久久99樱桃| 欧美77777| 久久精品国产免费| 浪潮色综合久久天堂| 香蕉久久国产| 欧美视频国产精品| 亚洲精品美女久久7777777| 在线观看不卡av| 久久精品论坛| 久久一区二区视频| 国产一区二区剧情av在线| 亚洲在线网站| 欧美一区二视频在线免费观看| 欧美日韩亚洲综合一区| 亚洲欧美亚洲| 欧美日韩国产a| 最新国产成人在线观看| 亚洲欧洲精品一区二区三区 | 久久国产直播| 国产精品自拍视频| 亚洲午夜高清视频| 午夜一区二区三区在线观看| 国产精品久久久久久亚洲毛片| 一区二区三区日韩精品视频| 亚洲一区二区三区在线看 | 国产在线精品成人一区二区三区| 久久女同精品一区二区| 国产欧美日韩视频一区二区| 亚洲专区免费| 欧美在线视频网站| 国语自产偷拍精品视频偷 | 久久精品1区| 免费亚洲电影在线观看| 亚洲黄色三级| 欧美日韩国产小视频在线观看| 亚洲精品视频一区| 亚洲欧美精品中文字幕在线| 欧美一区二区三区男人的天堂| 久久岛国电影| 在线日韩成人| 欧美久久一级| 亚洲私拍自拍| 久久乐国产精品| 亚洲精品黄色| 国产精品日本精品| 久久久久免费视频| 性8sex亚洲区入口| 国产主播一区二区三区四区| 老司机精品视频一区二区三区| 亚洲激情一区二区| 亚洲欧美日韩一区二区三区在线| 国产日韩一区| 欧美精品国产精品日韩精品| 亚洲一区二区欧美| 欧美高清在线观看| 午夜影院日韩| 亚洲毛片视频| 黑人一区二区三区四区五区| 欧美喷潮久久久xxxxx| 欧美中文字幕不卡| 亚洲免费精品| 一区二区三区精密机械公司| 国产精品揄拍一区二区| 毛片一区二区| 亚洲欧美日本伦理| 欧美区在线观看| 欧美好骚综合网| 亚洲永久免费视频| 亚洲国产va精品久久久不卡综合| 国产精品sm| 欧美国产激情二区三区| 欧美一级片一区| 亚洲视频一区二区在线观看| 欧美88av| 久久蜜臀精品av| 欧美一区二区三区四区视频| 9l视频自拍蝌蚪9l视频成人| 精品二区久久| 国产人成精品一区二区三| 欧美日韩一卡二卡| 欧美国产日韩二区| 免费h精品视频在线播放| 久久成人国产精品|