FileZilla Server源码分析

2024-04-28 00:32
文章标签 分析 源码 server filezilla

本文主要是介绍FileZilla Server源码分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

FileZilla Server源码分析(1)


之所以有本系列的分析,是因为两点:
  1. FileZilla 是目前非常火爆的开源ftp项目,整个项目采用C++代码编写,代码紧凑可读性高,值得学习(缺陷是注释太少)。
  2. 网络上已有的对该源码的分析基于的版本是0.9.18,分析比较粗略,无论是框架还是细节。
这里仅仅是我个人对FileZilla Server源码 0.9.34 版本的分析,能力有限,不足和错误之处还希望大家不吝斧正。
本片作为开篇,略过如何编译(该源码源码用VS2010编译),如何配置,如何使用。 FileZilla官网提供了程序和源码下载(源码包含在程序中,安装时默认为不安装),以及编译步骤和注意事项,感兴趣的朋友可以自行去官网寻找或google。

感谢:分析时参考了网友的系列文章《 FileZilla FTP服务器源代码分析》,大家可以参照比对。

首先预览一下源码目录source文件夹下的大致文件布局。



6个子目录,核心的代码(线程、socket、命令等)都放在当前目录下。6个子目录及对应代码功能:

子目录功能
includes当前版本下只有一个子目录openssl,看名识意,不多解释
install安装脚本和资源
interface界面UI实现类
misc混杂类,比较重要的如md5,StdString等
res程序编译资源,目前只有一个icon
tinyxml著名的一款基于DOM模型小巧开源的xml解析器

当前source目录下源码按实现功能大致又分为以下几种类型:

功能分类包括的文件
网络全体文件名含socket的,Server.*,
线程文件名包含Thread的文件
辅助version.*,MFC64bitFix.*,conversion.*,config.h,service.cpp等除去网络和线程的文件

文件目录结构分析完了,面对众多.h.cpp文件,需要做一些去繁取精的操作。从无关紧要的地方开始,例如version.*。

version.*中声明定义了一个函数 CStdString GetVersionString(),需要注意的就是CStdString这个类,它的实现在misc/stdString.h文件中,这个类文件较大,功能稍后部分再分析。说句实话,这个函数是很值得收藏的。

Thread.*定义了线程类CThread,只需要注意那个Run函数中对线程消息做了处理,有用的消息交由虚函数 OnThreadMessage处理。

作为Visual Studio生成的C++代码中最常出现的两个文件stdafx.h和stdafx.cpp,我们势必需要首先弄清楚它们到底包含了哪些头文件,定义了哪些宏,什么了哪些函数以及结构体。

stdafx.h中包含了自己的config.h这个文件,顺便看一下这个文件的作用,代码很少目的有两个,强制使用unicode编译和检测是否安装了最新SDK。还包含了MFC64bitFix.h这个文件,也跟进去看看。定义了一个存储文件属性的结构体 CFileStatus64,以及操作它的若干全局函数,这个文件名有点怪,和包含的功能不匹配。
第55行遇到了条件宏 #ifdef MMGR,编译条件中有定义,包含misc/mmgr.h文件。mmgr是用于管理和跟踪内存的代码,之后会重点详细分析。
conversion.h中声明的函数用于ANSI和UTF8字符的互相转换,不多解释。
AsyncSocketEx.h中实现了异步socket,之后的ControlSocket,AdminListenSocket等文件中什么的socket都是由CAsyncSocketEx类派生来的,之后分析。
至此,stdafx.h中头文件包含全部结束,下面就是宏定义了。

先补充一个知识点,各消息的值范围和作用见下图:


注册了 WM_FILEZILLA_THREADMSG消息用来线程之 间通信,定义了 WM_FILEZILLA_SERVERMSG用于进 程间通信,即FileZilla server.exe和FileZilla Server Interface.exe。
这里仅贴出两处源码中调用这两个消息的例子,便可得知后面定义的几个常数宏的用处。
// ControlSocket.cpp第400行
SendStatus(_T( " could not send reply, disconnected. " ),  0 );
m_pOwner
-> PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_DELSOCKET, m_userid);

//Server.cpp第813行器
int index = GetNextThreadNotificationID();
CServerThread *pThread = new CServerThread(WM_FILEZILLA_SERVERMSG + index);
m_ThreadNotificationIDs[index] = pThread;

从上面代码可以看出 PostThreadMessage的第二个参数wParam就是定义的数字宏,第三个参数是结构t_statusmsg,这些宏功能分别是:

FSM_STATUSMESSAGE:在管理窗口或log中显示并记录状态信息
FSM_CONNECTIONDATA:和连接相关的信息,如新用户连接,登录,退出等
FSM_THREADCANQUIT:退出线程
FSM_SEND:发送数据时用于管理窗口统计发送字节数
FSM_RECV:接受数据时用于管理窗口统计接收字节数
其余的就不多写了,宏名比较直观的显示出意思。

在往下定义了一系列的结构如 t_statusmsg,之后用到的地方在详述,知道这些结构在哪个文件中定义的就行了。
接着就是extern HWND hMainWnd; 这个外联的句柄就是下一节将要提到的CServer的窗口类句柄。
最后定义了一个CCriticalSectionWrapper类和两个帮助检测临界区死锁的函数,尤其是前者,DEBUG版本时错误的使用将导致当前线程挂起。

SpeedLimit.*:  速度限制(包括时间段限制)

这里针对UI性比较强,FillBuffer这个函数将所有限制条件格式化成一个char字符串,ParseBuffer则是解析这个字符串,采用这个 类,可以轻松实现强大的自定义限速功能。

defs.h: 这个类定义了服务器的状态,如在线、离线、锁住 等。


Options.*,OptionTypes.h

OptionTypes.h中定义了一个结构数组 m_Optinons,保存所有配置项信息,如是否使用SSL,同时在线最大用户数量,上传下载限速等等,所有这些大部分都被使用在Option那个对话框UI上。
t_option结构中有一个BOOL bOnlyLocal成员用于标示该项是否可以仅能够被本地连接修改,数组中只有最后两项Server name 和 server display name为TRUE,Options类就是操作配置文件的实体类(注意,它使用了tinyXML),服务器的配置文件存储在exe同级目录下,叫FileZilla Srver.xml。Options的主要操作是针对内存中的配置,只有与默认值不同的项才会存入配置文件中。
Options还有一个隐藏的friend窗体类 COptionsHelperWindow,定义在cpp文件中,这个类用于通过用post WM_USER给窗体消息这种异步的方式去更新option实例,而不是options类自身。
有了Options类和OptionTypes.h中定义的配置类型,就可以通过诸如 m_pOptions->GetOptionVal(OPTION_ENABLELOGGING)这样的方法方便的获取到配置。

FileLogger.*  日志

这个类中包含Options类的一个对象指针,用来读取日志文件的相关配置。

iputils.* 判断IP合法性以及是否处于某个过滤范围

它采用了大名鼎鼎的boost库的regex来判断,这个库之后有时间一定要好好研究一下。

autobanmanager.*  阻止用户继续登录的方法类文件

AutoBan这个设置项是一个非常浪费资源的,因为它对每一个失败的ip都要记录查询内存中的两个map。

Accounts.* 账户

Accounts.h中声明了3个类,t_directory,t_group,还有继承于t_group的t_user。
t_directory仅仅含有一些权限声明,相当于一个struct,被t_group和t_user使用。
剩余两个类主要做的事是对配置的读取分析,所有的数据都是基于字符串的。

permission.* 对用户、群组访问资源进行鉴权

权限配置信息记录在FileZilla Server.xml中。
服务器对每一个group和user都有权限限制,group权限优先于user权限,在 CheckFilePermissions 函数中可以看出。

conversion.* utf8和ansi字符的相互转化


ExternalIpCheck.*  PASV模式

根据配置获取ip。

所有辅助文件已经分析完毕,下级节开始分析socket和线程类。

这篇关于FileZilla Server源码分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/941905

相关文章

Python 迭代器和生成器概念及场景分析

《Python迭代器和生成器概念及场景分析》yield是Python中实现惰性计算和协程的核心工具,结合send()、throw()、close()等方法,能够构建高效、灵活的数据流和控制流模型,这... 目录迭代器的介绍自定义迭代器省略的迭代器生产器的介绍yield的普通用法yield的高级用法yidle

C++ Sort函数使用场景分析

《C++Sort函数使用场景分析》sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变,如果某些场景需要保持相同元素间的相对顺序,可使... 目录C++ Sort函数详解一、sort函数调用的两种方式二、sort函数使用场景三、sort函数排序

python连接本地SQL server详细图文教程

《python连接本地SQLserver详细图文教程》在数据分析领域,经常需要从数据库中获取数据进行分析和处理,下面:本文主要介绍python连接本地SQLserver的相关资料,文中通过代码... 目录一.设置本地账号1.新建用户2.开启双重验证3,开启TCP/IP本地服务二js.python连接实例1.

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

kotlin中const 和val的区别及使用场景分析

《kotlin中const和val的区别及使用场景分析》在Kotlin中,const和val都是用来声明常量的,但它们的使用场景和功能有所不同,下面给大家介绍kotlin中const和val的区别,... 目录kotlin中const 和val的区别1. val:2. const:二 代码示例1 Java

Go标准库常见错误分析和解决办法

《Go标准库常见错误分析和解决办法》Go语言的标准库为开发者提供了丰富且高效的工具,涵盖了从网络编程到文件操作等各个方面,然而,标准库虽好,使用不当却可能适得其反,正所谓工欲善其事,必先利其器,本文将... 目录1. 使用了错误的time.Duration2. time.After导致的内存泄漏3. jsO

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

Spring事务中@Transactional注解不生效的原因分析与解决

《Spring事务中@Transactional注解不生效的原因分析与解决》在Spring框架中,@Transactional注解是管理数据库事务的核心方式,本文将深入分析事务自调用的底层原理,解释为... 目录1. 引言2. 事务自调用问题重现2.1 示例代码2.2 问题现象3. 为什么事务自调用会失效3

mysql出现ERROR 2003 (HY000): Can‘t connect to MySQL server on ‘localhost‘ (10061)的解决方法

《mysql出现ERROR2003(HY000):Can‘tconnecttoMySQLserveron‘localhost‘(10061)的解决方法》本文主要介绍了mysql出现... 目录前言:第一步:第二步:第三步:总结:前言:当你想通过命令窗口想打开mysql时候发现提http://www.cpp

找不到Anaconda prompt终端的原因分析及解决方案

《找不到Anacondaprompt终端的原因分析及解决方案》因为anaconda还没有初始化,在安装anaconda的过程中,有一行是否要添加anaconda到菜单目录中,由于没有勾选,导致没有菜... 目录问题原因问http://www.chinasem.cn题解决安装了 Anaconda 却找不到 An