下面分析过程中函数先后次序,采用mod_xml_rpc.c文件内SWITCH_MODULE_RUNTIME_FUNCTION(mod_xml_rpc_runtime)函数里abyss库函数的出现顺序。
ServerCreate
abyss_bool
ServerCreate(TServer * const serverP,
const char * const name,
xmlrpc_uint16_t const portNumber,
const char * const filesPath,
const char * const logFileName)
这应该是使用abyss库的客户代码首要调用的函数。函数内代码很容易理解,首先调用createServer进行初始化操作,如果初始化成功则再调用setNamePathLog函数初始化主目录以及日志文件等信息。客户代码内的TServer定义其实没什么实质内容,内部只是一个指向_TServer的指针。这个结构体内部的信息都只由库代码访问。
typedef struct {
/* Before Xmlrpc-c 1.04, the internal server representation,
struct _TServer, was exposed to users and was the only way to
set certain parameters of the server. Now, use the (new)
ServerSet...() functions. Use the HAVE_ macros to determine
which method you have to use.
*/
struct _TServer * srvP;
} TServer;
createServer
在这个函数内,果然看到了为_TServer变量申请内存初始化变量的代码。创建完变量后,并没有做其他更多的处理,只是为三个函数指针赋上了相应的函数。HandlerCreate和HandlerDefaultBuiltin函数均在handler.c函数内定义。
setNamePathLog
ServerCreate函数内另一个被调用的函数是setNamePathLog。这个函数内一次调用了另三个函数:ServerSetName、ServerSetFilesPath和ServerSetLogFileName。第一个函数只是为_TServer变量的内部name属性赋值。ServerSetLogFileName函数的作用也只是给_TServer变量的logfilename赋值。ServerSetFilesPath函数是对另一个函数的封装:HandlerSetFilesPath。并且向HandlerSetFilesPath函数传递了_TServer的builtinHandlerP函数指针。这个函数指针值在createServer函数内被赋值,指向的是HandlerCreate。HandlerSetFilesPath也是在handler.c文件中定义。突然发现刚才分析代码时出错了,createServer函数内并不是将HandlerCreate函数赋给_TServer结构体内的属性,而是调用HandlerCreate函数创建一个BIHandler变量。这个被创建的BIHandler变量将赋给_TServer结构体内的builtinHandlerP属性。BIHandler结构体见下图:
struct BIHandler {
const char * filesPath;
TList defaultFileNames;
MIMEType * mimeTypeP;
/* NULL means to use the global MIMEType object */
};
HandlerCreate函数内会初始化这个结构体内部的TList。这个结构体在分析data.c代码时曾经研究过。HandlerSetFilesPath这个函数其实也不复杂,只是将主目录赋给BIHandler结构体的filesPath属性。
ServerInit
客户代码调用完ServerCreate函数后,就应该接着调用ServerInit函数了。第一步就是要创建一个TChanSwitch变量,并赋给_TServer的chanSwitchP属性。为了达到这个目的,最终调用的是ChanSwitchWinCreate函数,此函数在socket_win.c文件内,曾经研究过。这个函数不但创建了TChanSwitch变量,而且还生成了一个socket,并且与特定的port端口绑定成功。第一步完成后,接着就是调用ChanSwitchListen函数。
void
ChanSwitchListen(TChanSwitch * const chanSwitchP,
uint32_t const backlog,
const char ** const errorP) {
if (SwitchTraceIsActive)
fprintf(stderr, "Channel switch %p listening.\n", chanSwitchP);
(*chanSwitchP->vtbl.listen)(chanSwitchP, backlog, errorP);
}
代码显示最终访问了vtbl下