***************************************************************************************************************************
作者:EasyWave 时间:2015.01.11
类别:路由器类-基于RTL819X实现的Router/AP的源码分析[一] 声明:转载,请保留链接
注意:如有错误,欢迎指正。这些是我学习的日志文章...... [交流群 : 27016614]
***************************************************************************************************************************
一:基于RT819X平台的深度定制化BOA简介详细的关于BOA的介绍,请参考我的博文:嵌入式Linux下BOA网页服务器的移植的详细介绍,BOA WebServer是一款单任务的HTTP服务器,与其他网页服务器不同之处,是当有连接请求到来是,它既不是为每个连接都单独创建进程,也不是采用复制自身进程处理多链接,而是通过建立HTTP请求列表来处理多路HTTP连接请求,同时它只为CGI程序创建新的简称,在最大程度上节省了系统资源,这对于资源受限的嵌入式系统来说非常重要,同时它还自动生成目录、自动解压文件等功能,因此BOA具有很高的HTTP请求处理速度和效率,应用在嵌入式系统中具有很高的价值。
基于RT819x平台的Router/AP是构建在开源的BOA Web服务器上的,通过进入BOA的目录中,可以发现RT819x平台的Router/AP是在BOA开源代码上深度定制化的,具体的情况如下所示:
跟开源的BOA Web服务器多了很多文件夹,这是因为基于RT819x实现的Router/AP在开源的BOA基础上增加了一个ASP服务器,同时也实现了一个微型的小网站服务器,微型网站的代码如下所示:
这个是整个Router/AP前台的设置页面配置微型网站,这个跟我们自己家里用的Router,比如需要输入http://192.168.1.1这样进入页面设置的作用是一样的,所有的设置都是在html文件夹中实现的,由于开源的BOA并不支持ASP服务器,因此需要对BOA代码进行深度定制化,我们来看看RT819X是如何实现的呢?我们还是先来分析BOA的入口main函数吧,在users/boa/src/boa.c文件中,如下所示:
int main(int argc, char *argv[]) { int server_s; /* boa socket */ pid_t pid; /* set umask to u+rw, u-x, go-rwx */ /* according to the man page, umask always succeeds */ umask(077); /* but first, update timestamp, because log_error_time uses it */ (void) time(¤t_time); /* set timezone right away */ tzset(); { int devnullfd = -1; devnullfd = open("/dev/null", 0); /* make STDIN point to /dev/null */ if (devnullfd == -1) { DIE("can't open /dev/null"); } if (dup2(devnullfd, STDIN_FILENO) == -1) { DIE("can't dup2 /dev/null to STDIN_FILENO"); } (void) close(devnullfd); } parse_commandline(argc, argv); fixup_server_root(); #ifdef SUPPORT_ASP extern void asp_init(int argc,char **argv); // davidhsu asp_init(argc,argv); #ifdef VOIP_SUPPORT web_voip_init(); #endif #endif read_config_files(); create_common_env(); open_logs(); server_s = create_server_socket(); //init_signals(); //Brad comment out, move to later build_needs_escape(); /* background ourself */ if (do_fork) { pid = fork(); } else { pid = getpid(); } switch (pid) { case -1: /* error */ perror("fork/getpid"); exit(EXIT_FAILURE); case 0: /* child, success */ break; default: /* parent, success */ if (pid_file != NULL) { FILE *PID_FILE = fopen(pid_file, "w"); if (PID_FILE != NULL) { fprintf(PID_FILE, "%d\n", pid); fclose(PID_FILE); } else { perror("fopen pid file"); } } if (do_fork) exit(EXIT_SUCCESS); break; } boa_start = 1; init_signals(); //Brad move here drop_privs(); /* main loop */ timestamp(); status.requests = 0; status.errors = 0; start_time = current_time; alarm(1); loop(server_s); return 0; }我们把上面中的宏定义SUPPORT_ASP单独拿出来看看,如下所示:
#ifdef SUPPORT_ASP
extern void asp_init(int argc,char **argv); // davidhsu
asp_init(argc,argv);
#ifdef VOIP_SUPPORT
web_voip_init();
#endif
#endif
这样我们看到,RT819X实现的Router/AP是在开源BOA的基础上定制化了一个ASP的服务器,进入asp_init(argc,argv)函数中去看看,在users/boa/src/asp_page.c中,如下所示:
void asp_init(int argc,char **argv) { int i, num; char interface[10]; extern int getWlStaNum(char *interface, int *num); root_temp.next=NULL; root_temp.str=NULL; // david ---- queury number of wlan interface ---------------- wlan_num = 0; for (i=0; i<NUM_WLAN_INTERFACE; i++) { sprintf(interface, "wlan%d", i); if (getWlStaNum(interface, &num) < 0) break; wlan_num++; } #if defined(VOIP_SUPPORT) && defined(ATA867x) // no wlan interface in ATA867x #else if (wlan_num==0) wlan_num = 1; // set 1 as default #endif #ifdef MBSSID vwlan_num = NUM_VWLAN_INTERFACE; #endif //--------------------------------------------------------- //conti: root_temp.next = NULL; root_temp.str = NULL; if (apmib_init() == 0) { printf("Initialize AP MIB failed!\n"); return; } save_cs_to_file(); apmib_get(MIB_WAN_DHCP, (void *)&last_wantype); /* determine interface name by mib value */ WAN_IF = "eth1"; BRIDGE_IF = "br0"; ELAN_IF = "eth0"; ELAN2_IF = "eth2"; ELAN3_IF = "eth3"; ELAN4_IF = "eth4"; #ifdef HOME_GATEWAY PPPOE_IF = "ppp0"; #elif defined(VOIP_SUPPORT) && defined(ATA867x) BRIDGE_IF = "eth0"; ELAN_IF = "eth0"; #else BRIDGE_IF = "br0"; ELAN_IF = "eth0"; #endif strcpy(WLAN_IF,"wlan0"); //--------------------------- query_temp_var = (char *)malloc(MAX_QUERY_TEMP_VAL_SIZE); if (query_temp_var==NULL) exit(0); return; //main_end: //shmdt(pRomeCfgParam); exit(0); }这个函数是asp服务器的核心代码,注意这是一个深度定制化的ASP服务器,整个ASP服务器的分发和处理是在void handleForm(request *req)处理的,这个void handleForm(request *req)函数是由get.c中的int init_form(request * req)函数调用,而int init_form(request * req)函数是被read.c中的int write_body(request * req)函数调用的,而int write_body(request * req)函数是被request.c中的void process_requests(int server_sock)函数调用的,而void process_requests(int server_sock)函数是被poll.c或者select.c中的void loop(int server_s)函数调用的,而void loop(int server_s)函数是被boa.c中调用的。如下所示:
图一:asp_page.c中的void handleForm(request *req)函数
图二:void handleForm(request *req)函数是由get.c中的int init_form(request * req)函数调用
图三:int init_form(request * req)函数是被read.c中的int write_body(request * req)
图四:int write_body(request * req)函数是被request.c中的void process_requests(int server_sock)函数调用
图五:void process_requests(int server_sock)函数是被poll.c或者select.c中的void loop(int server_s)函数调用
而在boa.c中的main函数中就会调用void loop(int server_s)函数,如下所示:
分析到这里大概知道BOA对于ASP命令的解析的基本流程了,那么我们采用一个实例命令来分析一下void handleForm(request *req)是如何处理html页面中的命令的,在boa/html/syscmd.htm中打开syscmd.htm的代码,如下所示:
在上述代码中可以看到<form action=/boafrm/formSysCmd method=POST name="formSysCmd">这行代码,我们就从这行代码来分析吧,我们先来看看void handleForm(request *req)函数吧,如下所示:
从中我们可以看到root_form这个table,而#define SCRIPT_ALIAS "/boafrm/"被定义为boafrm,那么从刚刚的那行代码中我们可以看到在/boafrm/formSysCmd中会执行formSysCmd函数的,而这个函数就在root_form这个table中,如下所示:
这篇博文简单的分析深度定制化的BOA下的ASP服务器命令的处理流程,详细的介绍后续会继续更新到博客上,这是本人学习的一些总结,在学习过程中肯定会有这样那样的错误,但是这就是一个学习的过程。