GoAhead2.5源代码分析

harleyli

贡献于2013-03-26

字数:0 关键词: Go

GoAhead2.5 源代码分析 作者:soqsoq asp.c Active server page support cgi.c Standard CGI support ejlex.c Embedded JavaScript lexical analyser ejparse.c Embedded JavaScript parser and API emfdb.c WebServer database form.c In-memory forms processor with GCI support handler.c URL handler support main.c Main program and startup for operating system rom.c ROM Web pages access module when not using a file system. security.c Security URL handler. Implements a basic security policy sock.c Generic socket support sockGen.c platform-independent socket support um.c user management webs.c primary GoAhead WebServer code. Includes state machine. 一一一一....Um.c ((((用户管理用户管理用户管理用户管理)))) umconfig.txt ---------------------------------------- TABLE=users ROW=0 name=admin password=Uz group=Administrator prot=1 disable=0 TABLE=groups ROW=0 name=Administrator priv=4 method=3 prot=1 disable=0 TABLE=access ROW=0 name=/main.html method=3 secure=0 group=Administrator ------------------------------------- GoAhead 提供了认证功能:主要是两种认证基本认证和摘要认证。摘要认证比基本认证更 安全些,所以选择摘要认证。 认证功能其实是用户管理功能的一部分。要配置认证功能,需要修改 umconfig.txt 文件, GoAhead 在启动时会读取该文件,实现认证功能。 文件大概情况如下: TABLE=users/* 用户配置*/ ROW=0 name=raise/* 用户名*/ password=Uz/* 密码,加密的*/ group=RS/* 用户所属的组*/ prot=1/*为 1 表示这个用户受保护不能被删除,0 表示可以删除*/ disable=0/*0 为使能*/ TABLE=groups/* 组配置*/ ROW=0 name=RS/* 组名*/ priv=4/* 用 户 组 的 访 问 权 限 , 可 以 是 0 , 1 , 2 , 4 分 别 代 表 AM_NONE,AM_READ,AM_WRITE,AM_ADMIN. 这之间没有权限大小之分*/ method=3/*密码认证方法,可以是 0,1,2,3。0 什么你都没权访问,1 什么你都有权限。 2 密码与用户名简单加密传输(基本认证),3 密码和用户名经过更安全的加密(摘要认证)。 typedef enum { AM_NONE = 0, AM_FULL, AM_BASIC, AM_DIGEST, AM_INVALID } accessMeth_t; */ prot=1/* 为 1 表示这个用户受保护不能被删除,0 表示可以删除*/ disable=0/*0 为使能*/ TABLE=access/* 访问控制*/ ROW=0 name=/ /* 要访问 index.htm ,需要输入用户名、密码*/ method=3/* 摘要认证*/ secure=0/* 页面传输时,是否要加密,0 为不加密,如果不使用 SSL,这项是忽略的*/ group=RS/* 可访问该文件的组*/ int umOpen() 功能:在数据库中注册 UM 表 说明: 1. 如果 didUM== -1,注册数据库,包括三个表:用户表、用户组表、访问控制表 2. 如果 saveFilename == NULL ,分配一段内存,内存中存放文件名 umconfig.txt 。 ----------------------------------------------------------------------------------------------------------------- void umClose() 功能:释放数据库中的 UM 表 说明: ----------------------------------------------------------------------------------------------------------------- int umCommit(char_t *filename) 功能:将数据库中的 table 保存到文件中 说明: ----------------------------------------------------------------------------------------------------------------- int umRestore(char_t *filename) 功能:将文件中 table 存放到数据库中 说明: ----------------------------------------------------------------------------------------------------------------- static int umEncryptString(char_t *textString) 功能:将字符串进行简单加密 说明: ----------------------------------------------------------------------------------------------------------------- static char_t *umGetFirstRowData(char_t *tableName, char_t *columnName) 功能:获得 table 名字为 tableName ,列名为 columnName 的数据 说明:例如,前面的 umconfig.txt, password=Uz 的获得就是 tableName= users ,columnName= password 。 ----------------------------------------------------------------------------------------------------------------- static char_t *umGetNextRowData(char_t *tableName, char_t *columnName, char_t *keyLast) 功能:获得指定的 table 项的下一项。 说明: ----------------------------------------------------------------------------------------------------------------- int umAddUser(char_t *user, char_t *pass, char_t *group, bool_t prot, bool_t disabled) 功能:向用户 table 中添加一个用户。 说明:必须确保用户名不重复,用户组是存在的。 ----------------------------------------------------------------------------------------------------------------- int umDeleteUser(char_t *user) 功能:删除一个用户 说明: ----------------------------------------------------------------------------------------------------------------- char_t *umGetFirstUser() 功能:获得第一个用户名 说明: ----------------------------------------------------------------------------------------------------------------- char_t *umGetNextUser(char_t *userLast) 功能:获得下一个用户名 说明: ----------------------------------------------------------------------------------------------------------------- bool_t umUserExists(char_t *user) 功能:判断指定用户是否存在 说明: ----------------------------------------------------------------------------------------------------------------- char_t *umGetUserPassword(char_t *user) 功能:获得指定用户的密码 说明: ----------------------------------------------------------------------------------------------------------------- int umSetUserPassword(char_t *user, char_t *pass) 功能:设置用户的密码 说明: ----------------------------------------------------------------------------------------------------------------- char_t *umGetUserGroup(char_t *user) 功能:获得该用户所在的用户组 说明: ----------------------------------------------------------------------------------------------------------------- int umSetUserGroup(char_t *user, char_t *group) 功能:设置这个用户的用户组 说明: ----------------------------------------------------------------------------------------------------------------- bool_t umGetUserEnabled(char_t *user) 功能:该用是否使能 说明: ----------------------------------------------------------------------------------------------------------------- int umSetUserEnabled(char_t *user, bool_t enabled) 功能:设置该用户使能 说明: ----------------------------------------------------------------------------------------------------------------- bool_t umGetUserProtected(char_t *user) 功能:该用户是否被保护,不能删除 说明: ----------------------------------------------------------------------------------------------------------------- int umSetUserProtected(char_t *user, bool_t protect) 功能:设置该用户被保护 说明: ----------------------------------------------------------------------------------------------------------------- int umAddGroup(char_t *group, short priv, accessMeth_t am, bool_t prot, bool_t disabled) 功能:添加一个组 table 说明: ----------------------------------------------------------------------------------------------------------------- int umDeleteGroup(char_t *group) 功能:删除一个组 说明: ----------------------------------------------------------------------------------------------------------------- bool_t umGroupExists(char_t *group) 功能:该组是否存在 说明: ----------------------------------------------------------------------------------------------------------------- bool_t umGetGroupInUse(char_t *group) 功能:该用户是否使能 说明: ----------------------------------------------------------------------------------------------------------------- char_t *umGetFirstGroup() 功能:获得第一个用户组 说明: ----------------------------------------------------------------------------------------------------------------- char_t *umGetNextGroup(char_t *groupLast) 功能:获得下一个用户组 说明: ----------------------------------------------------------------------------------------------------------------- accessMeth_t umGetGroupAccessMethod(char_t *group) 功能:获得用户组的方法 说明: ----------------------------------------------------------------------------------------------------------------- int umSetGroupAccessMethod(char_t *group, accessMeth_t am) 功能:设置用户组的方法 说明: ----------------------------------------------------------------------------------------------------------------- short umGetGroupPrivilege(char_t *group) 功能:获得用户组的访问权限 说明: ----------------------------------------------------------------------------------------------------------------- int umSetGroupPrivilege(char_t *group, short privilege) 功能:设置用户组的访问权限 说明: ----------------------------------------------------------------------------------------------------------------- bool_t umGetGroupEnabled(char_t *group) 功能:获得用户组是否使能 说明: ----------------------------------------------------------------------------------------------------------------- int umSetGroupEnabled(char_t *group, bool_t enabled) 功能:设置用户组使能 说明: ----------------------------------------------------------------------------------------------------------------- bool_t umGetGroupProtected(char_t *group) 功能:获得用户组是否被保护 说明: ----------------------------------------------------------------------------------------------------------------- int umSetGroupProtected(char_t *group, bool_t protect) 功能:设置用户组被保护 说明: ----------------------------------------------------------------------------------------------------------------- int umAddAccessLimit(char_t *url, accessMeth_t am, short secure, char_t *group) 功能:添加访问限制,能访问哪个目录或文件 说明: ----------------------------------------------------------------------------------------------------------------- int umDeleteAccessLimit(char_t *url) 功能:删除访问限制 说明: ----------------------------------------------------------------------------------------------------------------- char_t *umGetFirstAccessLimit() 功能:获得第一个用户的访问限制路径 说明: ----------------------------------------------------------------------------------------------------------------- char_t *umGetNextAccessLimit(char_t *urlLast) 功能:获得指定访问限制路径的下一个访问限制路径 说明: ----------------------------------------------------------------------------------------------------------------- bool_t umAccessLimitExists(char_t *url) 功能:这个访问限制路径是否存在 说明: ----------------------------------------------------------------------------------------------------------------- accessMeth_t umGetAccessLimitMethod(char_t *url) 功能:获得这个路径的访问方法 说明:typedef enum { AM_NONE = 0, AM_FULL, AM_BASIC, AM_DIGEST, AM_INVALID } accessMeth_t; ----------------------------------------------------------------------------------------------------------------- int umSetAccessLimitMethod(char_t *url, accessMeth_t am) 功能:设置这个访问路径的方法 说明: ----------------------------------------------------------------------------------------------------------------- short umGetAccessLimitSecure(char_t *url) 功能:获得这个访问路径的安全设置 说明:加密还是不加密 ----------------------------------------------------------------------------------------------------------------- int umSetAccessLimitSecure(char_t *url, short secure) 功能:设置访问路径的安全标志 说明: ----------------------------------------------------------------------------------------------------------------- char_t *umGetAccessLimitGroup(char_t *url) 功能:获得这个访问路径的组 说明: ----------------------------------------------------------------------------------------------------------------- int umSetAccessLimitGroup(char_t *url, char_t *group) 功能:设置访问路径的组 说明: ----------------------------------------------------------------------------------------------------------------- char_t *umGetAccessLimit(char_t *url) 功能:获得给定路径的所在的访问限制路径 说明: ----------------------------------------------------------------------------------------------------------------- accessMeth_t umGetAccessMethodForURL(char_t *url) 功能:获得给定路径的所在的访问限制方法 说明: ----------------------------------------------------------------------------------------------------------------- bool_t umUserCanAccessURL(char_t *user, char_t *url) 功能:判断这个路径用户是否能够访问 说明:1. 用户要在 2.用户要能 3.用户组的权限要足够大,AM_READ,AM_WRITE,AM_ADMIN 都可 4. 用户组要使能 5. 用户组访问限制的方法必须是 AM_FULL、 AM_BASIC 、AM_DIGEST 之一 6. 在判断 url 是否属于访问限制路径,如果是,获得这个路径的访问方法和组,然后这个访 问方法不能是 AM_NONE,组必须和 user 的组一样。 ----------------------------------------------------------------------------------------------------------------- static bool_t umCheckName(char_t *name) 功能:检查字符串是否是有效的 说明: ----------------------------------------------------------------------------------------------------------------- 二二二二....Emfdb.c( 文件数据库文件数据库文件数据库文件数据库) 数据库按照下面结构体存放 typedef struct dbTable_s { char_t *name; int nColumns; char_t **columnNames; int *columnTypes; int nRows; int **rows; } dbTable_t; 每个 table 对应上面结构的一个变量。 Name 是 table 的名字 nColumns 是 table 有多少列 columnNames 是各个列的名字 columnTypes 是各个列中内容的类型,是字符串,还是整数 nRows 是 table 有多少行 rows 是:rows[n] 指向各个行的指针,rows[n][m] 是该行某个列整数的值或字符串的指针。 ----------------------------------------------------------------------------------------------------------------- int dbRegisterDBSchema(dbTable_t *pTableRegister) 功能:创建一个 table 框架 说明: ----------------------------------------------------------------------------------------------------------------- int dbOpen(char_t *tablename, char_t *filename, int (*gettime)(int did), int flags) 功能: 一些初始化 说明: ----------------------------------------------------------------------------------------------------------------- void dbClose(int did) 功能: 释放 tables 所在的内存 说明: ----------------------------------------------------------------------------------------------------------------- void dbZero(int did) 功能: 清空 tables 中的所有数据,释放内存。 说明: ----------------------------------------------------------------------------------------------------------------- int dbSearchStr(int did, char_t *tablename, char_t *colName, char_t *value, int flags) 功能:根据表单名字、列名、列值,找到对应的 row 说明: ----------------------------------------------------------------------------------------------------------------- int dbAddRow(int did, char_t *tablename) 功能:向名字为 tablename 中添加一 row 说明: ----------------------------------------------------------------------------------------------------------------- int dbDeleteRow(int did, char_t *tablename, int row) 功能: 删除名字为 tablename 的 table 的一 row 说明: ----------------------------------------------------------------------------------------------------------------- int dbSetTableNrow(int did, char_t *tablename, int nNewRows) 功能: 添加 row ,使其行数为 nNewRows 说明: ----------------------------------------------------------------------------------------------------------------- int dbGetTableNrow(int did, char_t *tablename) 功能: 获得这个 table 的行数 说明: ----------------------------------------------------------------------------------------------------------------- int dbReadInt(int did, char_t *table, char_t *column, int row, int *returnValue) 功能:读取指定行、列的值,读取的值是整数值 说明: ----------------------------------------------------------------------------------------------------------------- int dbReadStr(int did, char_t *table, char_t *column, int row, char_t **returnValue) 功能: 读取指定行、列的值,读取的值是字符串 说明: ----------------------------------------------------------------------------------------------------------------- int dbWriteInt(int did, char_t *table, char_t *column, int row, int iData) 功能: 向指定行、列写整数 说明: ----------------------------------------------------------------------------------------------------------------- int dbWriteStr(int did, char_t *table, char_t *column, int row, char_t *s) 功能: 向指定行列写字符串 说明: ----------------------------------------------------------------------------------------------------------------- static int dbWriteKeyValue(int fd, char_t *key, char_t *value) 功能: 向文件中些 key=value 说明: ----------------------------------------------------------------------------------------------------------------- int dbSave(int did, char_t *filename, int flags) 功能:将数据库(动态分配的内存)中值存放到文件中 说明: ----------------------------------------------------------------------------------------------------------------- static int crack(char_t *buf, char_t **key, char_t **val) 功能: 获得 key=value 字符串中的 key 和 value 说明: ----------------------------------------------------------------------------------------------------------------- int dbLoad(int did, char_t *filename, int flags) 功能: 将文件中的数据存到数据库中 说明: ----------------------------------------------------------------------------------------------------------------- int dbGetTableId(int did, char_t *tablename) 功能: 获取 table 的 id 说明: ----------------------------------------------------------------------------------------------------------------- char_t *dbGetTableName(int did, int tid) 功能: 获取 table 的名字 说明: ----------------------------------------------------------------------------------------------------------------- static char_t *trim(char_t *str) 功能: 去掉字符串中的空格 说明: ----------------------------------------------------------------------------------------------------------------- static int GetColumnIndex(int tid, char_t *colName) 功能: 获得指定名字的列的索引 说明: ----------------------------------------------------------------------------------------------------------------- void basicSetProductDir(char_t *proddir) 功能: 设置数据库文件的路径 说明: ----------------------------------------------------------------------------------------------------------------- char_t *basicGetProductDir() 功能: 获得数据库文件的路径 说明: ----------------------------------------------------------------------------------------------------------------- 三三三三....Umui.c( 用户管理实例用户管理实例用户管理实例用户管理实例) 文件中代码与 webs-2-5\wwwdemo\um 中的页面对应, (addgroup.asp 、addlimit.asp 、adduser.asp 、delgroup.asp 、dellimit.asp 、deluser.asp 、dspuser.asp 、 loadcfg.asp 、savecfg.asp 、um.htm ) 是这些页面调用的 form 、asp 函数,通过这些实例,有助于对用户管理的理解。 ----------------------------------------------------------------------------------------------------------------- void formDefineUserMgmt(void) 功能:定义页面要使用的 form 、asp 函数 说明: ----------------------------------------------------------------------------------------------------------------- static void formAddUser(webs_t wp, char_t *path, char_t *query) 功能:添加一个用户 说明: ----------------------------------------------------------------------------------------------------------------- static void formDeleteUser(webs_t wp, char_t *path, char_t *query) 功能:删除一个用户 说明: ----------------------------------------------------------------------------------------------------------------- static void formDisplayUser(webs_t wp, char_t *path, char_t *query) 功能:显示用户的信息 说明: ----------------------------------------------------------------------------------------------------------------- static int aspGenerateUserList(int eid, webs_t wp, int argc, char_t **argv) 功能:列出所用的用户 说明: ----------------------------------------------------------------------------------------------------------------- static void formAddGroup(webs_t wp, char_t *path, char_t *query) 功能:添加一个组 说明: ----------------------------------------------------------------------------------------------------------------- static void formDeleteGroup(webs_t wp, char_t *path, char_t *query) 功能:删除一个组 说明:组在用时,不能删除,所以,只有将在这个组的所有用户删除之后,才能删除这个组。 ----------------------------------------------------------------------------------------------------------------- static int aspGenerateGroupList(int eid, webs_t wp, int argc, char_t **argv) 功能:列出所有的组 说明: ----------------------------------------------------------------------------------------------------------------- static void formAddAccessLimit(webs_t wp, char_t *path, char_t *query) 功能:添加组对应的访问限制路径 说明: ----------------------------------------------------------------------------------------------------------------- static void formDeleteAccessLimit(webs_t wp, char_t *path, char_t *query) 功能:删除组对应的访问限制路径 说明: ----------------------------------------------------------------------------------------------------------------- static int aspGenerateAccessLimitList(int eid, webs_t wp, int argc, char_t **argv) 功能:显示所有的访问限制的列表 说明: ----------------------------------------------------------------------------------------------------------------- static int aspGenerateAccessMethodList(int eid, webs_t wp, int argc, char_t **argv) 功能:显示访问方法的列表 说明:FULL ACCESS 、BASIC ACCESS 、DIGEST ACCESS 、NO ACCESS ----------------------------------------------------------------------------------------------------------------- static int aspGeneratePrivilegeList(int eid, webs_t wp, int argc, char_t **argv) 功能:显示访问权限的列表 说明:READ、EXECUTE、ADMINISTRATE ----------------------------------------------------------------------------------------------------------------- static void formSaveUserManagement(webs_t wp, char_t *path, char_t *query) 功能:保存配置到 umconfig.txt 说明: ----------------------------------------------------------------------------------------------------------------- static void formLoadUserManagement(webs_t wp, char_t *path, char_t *query) 功能:将 umconfig.txt 文件中配置数据恢复到数据库中 说明: ----------------------------------------------------------------------------------------------------------------- static void websMsgStart(webs_t wp) 功能:向浏览器中输出

说明: ----------------------------------------------------------------------------------------------------------------- static void websMsgEnd(webs_t wp) 功能:向浏览器中输出

说明: ----------------------------------------------------------------------------------------------------------------- 四四四四....Uemf.c 和和和和 misc.c(用户管理用到的一些用户管理用到的一些用户管理用到的一些用户管理用到的一些 函数函数函数函数) void error(E_ARGS_DEC, int etype, char_t *fmt, ...) 功能:将出现的错误根据错误类型,输出对应字符串 说明:函数中使用了 var_start,var_end, var_arg 等宏 下面我们来探讨如何写一个简单的可变参数的 C 函数。写可变参数的 C 函数要在程序中用到以下这些宏: void va_start( va_list arg_ptr, prev_param ); type va_arg( va_list arg_ptr, type ); void va_end( va_list arg_ptr ); va 在这里是 variable-argument( 可变参数)的意思。 这些宏定义在 stdarg.h 中,所以用到可变参数的程序应该包含这个 头文件。下面我们写一个简单的可变参 数的函数,改函数至少有一个整数 参数,第二个参数也是整数,是可选的.函数只是打印这两个参数的值.。 void simple_va_fun(int i, ...) { va_list arg_ptr; int j=0; va_start(arg_ptr, i); j=va_arg(arg_ptr, int); va_end(arg_ptr); printf("%d %d\n", i, j); return; } 我们可以在我们的头文件中这样声明我们的函数: extern void simple_va_fun(int i, ...); 我们在程序中可以这样调用: simple_va_fun(100); simple_va_fun(100,200); 从这个函数的实现可以看到,我们使用可变参数应该有以下步骤: 1) 首先在函数里定义一个 va_list 型的变量,这里是 arg_ptr, 这个变 量是指向参数的指针; 2) 然后用 va_start 宏初始化变量 arg_ptr ,这个宏的第二个参数是第 一个可变参数的前一个参数,是一个固 定的参数.; 3) 然后用 va_arg 返回可变的参数,并赋值给整数 j. va_arg 的第二个 参数是你要返回的参数的类型,这里是 int 型; 4) 最后用 va_end 宏结束可变参数的获取.然后你就可以在函数里使 用第二个参数了。如果函数有多个可变 参数的,依次调用 va_arg 获 取各个参数。 ----------------------------------------------------------------------------------------------------------------- void (*errorSetHandler(void (*function)(int etype, char_t *msg))) (int etype, char_t *msg) 功能:重新赋予错误处理函数 说明: ----------------------------------------------------------------------------------------------------------------- void trace(int level, char_t *fmt, ...) 功能:向日志文件 trace.txt 中输出踪迹 说明: ----------------------------------------------------------------------------------------------------------------- void traceRaw(char_t *buf) 功能:向日志文件 trace.txt 中输出踪迹 说明: ----------------------------------------------------------------------------------------------------------------- void (*traceSetHandler(void (*function)(int level, char_t *buf))) (int level, char *buf) 功能:赋予新的 trace 函数 说明: ----------------------------------------------------------------------------------------------------------------- char_t *strlower(char_t *string) 功能:将字符串转换为小写的 说明: ----------------------------------------------------------------------------------------------------------------- char_t *strupper(char_t *string) 功能:将字符串转换为大写的 说明: ----------------------------------------------------------------------------------------------------------------- char_t *stritoa(int n, char_t *string, int width) 功能:将整数转换为字符串 说明: ----------------------------------------------------------------------------------------------------------------- void defaultErrorHandler(int etype, char_t *msg) 功能:默认的错误处理 handler 说明: ----------------------------------------------------------------------------------------------------------------- void defaultTraceHandler(int level, char_t *buf) 功能:默认的 trace 处理 handler 说明: ----------------------------------------------------------------------------------------------------------------- char_t *basicGetProduct() 功能:返回 uemf 说明: ----------------------------------------------------------------------------------------------------------------- char_t *basicGetAddress() 功能:返回 localhost 说明: ----------------------------------------------------------------------------------------------------------------- =========================================================== ----------------------------------------------------------------------------------------------------------------- int fmtAlloc(char_t **s, int n, char_t *fmt, ...) 功能:分配一段按照 fmt 形式的内存,里面存放字符串 fmt 说明: ----------------------------------------------------------------------------------------------------------------- int fmtStatic(char_t *s, int n, char_t *fmt, ...) 功能:分配一段按照 fmt 形式的内存,里面存放字符串 fmt 说明: ----------------------------------------------------------------------------------------------------------------- int fmtRealloc(char_t **s, int n, int msize, char_t *fmt, ...) 功能:分配一段按照 fmt 形式的内存,里面存放字符串 fmt 说明: ----------------------------------------------------------------------------------------------------------------- int fmtValloc(char_t **s, int n, char_t *fmt, va_list arg) 功能:分配一段按照 fmt 形式的内存,里面存放字符串 fmt 说明: ----------------------------------------------------------------------------------------------------------------- static int dsnprintf(char_t **s, int size, char_t *fmt, va_list arg, int msize) 功能:输出一段字符 说明:这个函数比较复杂,需要认真看。 ----------------------------------------------------------------------------------------------------------------- static int gstrnlen(char_t *s, unsigned int n) 功能:获得字符串的长度 说明: ----------------------------------------------------------------------------------------------------------------- static void put_char(strbuf_t *buf, char_t c) 功能:向 buf 中输出一个字符 说明: ----------------------------------------------------------------------------------------------------------------- static void put_string(strbuf_t *buf, char_t *s, int len, int width, int prec, enum flag f) 功能:向 buf 中输出字符串 说明: ----------------------------------------------------------------------------------------------------------------- static void put_ulong(strbuf_t *buf, unsigned long int value, int base, int upper, char_t *prefix, int width, int prec, enum flag f) 功能:向 buf 中输出 long 数 说明: ----------------------------------------------------------------------------------------------------------------- char_t *ascToUni(char_t *ubuf, char *str, int nBytes) 功能:将 asc 字符串转换为 uni 字符串 说明: ----------------------------------------------------------------------------------------------------------------- char *uniToAsc(char *buf, char_t *ustr, int nBytes) 功能:将 uni 字符串转换为 asc 字符串 说明: ----------------------------------------------------------------------------------------------------------------- char_t *ballocAscToUni(char *cp, int alen) 功能:将 asc 字符串转换为 uni 字符串 说明: ----------------------------------------------------------------------------------------------------------------- char *ballocUniToAsc(char_t *unip, int ulen) 功能:将 uni 字符串转换为 asc 字符串 说明: ----------------------------------------------------------------------------------------------------------------- unsigned int hextoi(char_t *hexstring) 功能:将 16 进制字符串转换整数 说明: ----------------------------------------------------------------------------------------------------------------- unsigned int gstrtoi(char_t *s) 功能:将字符串转换为整数,可以是 16 、10 进制数 说明: ----------------------------------------------------------------------------------------------------------------- 五五五五....h.c 和和和和 balloc.c int hAlloc(void ***map) 功能:分配使用的 map 数组 说明: ----------------------------------------------------------------------------------------------------------------- int hFree(void ***map, int handle) 功能:释放使用的 map 数组 说明: ----------------------------------------------------------------------------------------------------------------- int hAllocEntry(void ***list, int *max, int size) 功能:Allocate an entry in the halloc array. 说明: ----------------------------------------------------------------------------------------------------------------- int bopen(void *buf, int bufsize, int flags) 功能:初始化 balloc 模块,分配 64k 内存 说明: ----------------------------------------------------------------------------------------------------------------- void bclose() 功能:关闭 balloc 模块,释放内存 说明: ----------------------------------------------------------------------------------------------------------------- void *balloc(B_ARGS_DEC, int size) 功能:分配能容下 size 大小的最小的块, 说明: ----------------------------------------------------------------------------------------------------------------- void bfree(B_ARGS_DEC, void *mp) 功能:释放 balloc 分配的内存空间 说明: ----------------------------------------------------------------------------------------------------------------- void bfreeSafe(B_ARGS_DEC, void *mp) 功能:没啥用 说明: ----------------------------------------------------------------------------------------------------------------- char *bstrdupA(B_ARGS_DEC, char *s) 功能:没啥用 说明: ----------------------------------------------------------------------------------------------------------------- char_t *bstrdup(B_ARGS_DEC, char_t *s) 功能:分配内存,拷贝字符串 说明: ----------------------------------------------------------------------------------------------------------------- void *brealloc(B_ARGS_DEC, void *mp, int newsize) 功能:扩大分配的内存空间 说明: ----------------------------------------------------------------------------------------------------------------- static int ballocGetSize(int size, int *q) 功能:获得能容下 size 的最小的块的大小 说明: Block classes are: 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 ----------------------------------------------------------------------------------------------------------------- static void bFillBlock(void *buf, int bufsize) 功能:没啥用 说明: ----------------------------------------------------------------------------------------------------------------- void bstats(int handle, void (*writefn)(int handle, char_t *fmt, ...)) 功能:输出内存的统计信息 说明: ----------------------------------------------------------------------------------------------------------------- static int bStatsFileSort(const void *cp1, const void *cp2) 功能:比较大小 说明: ----------------------------------------------------------------------------------------------------------------- static void bStatsAlloc(B_ARGS_DEC, void *ptr, int q, int size) 功能:计算分配的统计信息 说明: ----------------------------------------------------------------------------------------------------------------- static void bStatsFree(B_ARGS_DEC, void *ptr, int q, int size) 功能:释放统计信息 说明: ----------------------------------------------------------------------------------------------------------------- static void bstatsWrite(int handle, char_t *fmt, ...) 功能:输出 说明: ----------------------------------------------------------------------------------------------------------------- static void verifyUsedBlock(bType *bp, int q) 功能:校验使用中的块 说明: ----------------------------------------------------------------------------------------------------------------- static void verifyFreeBlock(bType *bp, int q) 功能:校验未使用的块 说明: ----------------------------------------------------------------------------------------------------------------- void verifyBallocSpace() 功能:校验分配的空间 说明: ----------------------------------------------------------------------------------------------------------------- char_t *bstrdupNoBalloc(char_t *s) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- 六六六六、、、、security.c ((((用户验证用户验证用户验证用户验证)))) 主要功能是:验证登陆用户的信息,会在页面上显示对应的信息,不成功,显示错误页面, 成功时,会验证用户名和密码。 ----------------------------------------------------------------------------------------------------------------- int websSecurityHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, char_t *url, char_t *path, char_t *query) 功能:验证用户的登陆信息,显示对应的页面 说明: 首先判断是否支持 ssl ,如果支持,先获取该路径是否是加密处理的,如果所获得值与 flag 的不一致,会向浏览器报告状态码 405 (禁用请求中所指定的方法) 然后获得访问方法; 如果是调试,且 flag 是 WEBS_LOCAL_REQUEST,可以顺利访问; 如果访问方法是 AM_NONE,会输出状态码 404 ,Page Not Found (服务器找不到请求的网 页) 如果不存在这样的用户,输出 401 (要求进行身份验证) 判断该用户是否能访问该路径,不能则输出 403 (服务器拒绝请求) 获取用户密码,如果不匹配,输出 401 (要求进行身份验证) 获取摘要认证字符串,如果不匹配,输出 401 (要求进行身份验证) 如果认证方法不为 AM_FULL,输出 401 (要求进行身份验证) 401 就是在浏览器上弹出窗口,要求输入用户名、密码 ----------------------------------------------------------------------------------------------------------------- 备注:经常使用的 http 状态码 HTTP 状态代码 以下提供了 HTTP 状态代码的完整列表。 1xx (临时响应) 用于表示临时响应并需要请求者执行操作才能继续的状态代码。 代码 说明 100 (继续) 请求者应当继续提出请求。服务器返回此代码则意味着,服务器已收到了请求 的第一部分,现正在等待接收其余部分。 101 (切换协 议) 请求者已要求服务器切换协议,服务器已确认并准备进行切换。 2xx (成功) 用于表示服务器已成功处理了请求的状态代码。 代码 说明 200 (成功) 服务器已成功处理了请求。通常,这表示服务器提供了请求的网页。如果您的 robots.txt 文件显示为此状态,那么,这表示已成功检索到该文件。 201 ( 已 创 建) 请求成功且服务器已创建了新的资源。 202 ( 已 接 受) 服务器已接受了请求,但尚未对其进行处理。 203 (非授权 信息) 服务器已成功处理了请求,但返回了可能来自另一来源的信息。 204 ( 无 内 容) 服务器成功处理了请求,但未返回任何内容。 205 (重置内 容) 服务器成功处理了请求,但未返回任何内容。与 204 响应不同,此响应要求 请求者重置文档视图(例如清除表单内容以输入新内容)。 206 (部分内 容) 服务器成功处理了部分 GET 请求。 3xx (已重定向) 要完成请求,您需要进一步进行操作。通常,这些状态代码是永远重定向的。Google 建议 您在每次请求时使用的重定向要少于 5 个。您可以使用网站管理员工具来查看 Googlebot 在抓取您已重定向的网页时是否会遇到问题。诊断下的抓取错误页中列出了 Googlebot 由 于重定向错误而无法抓取的网址。 代码 说明 300 (多 种选择) 服务器根据请求可执行多种操作。服务器可根据请求者 (User agent) 来选择一项操 作,或提供操作列表供请求者选择。 301 (永 久移动) 请求的网页已被永久移动到新位置。服务器返回此响应(作为对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。您应使用此代码通知 Googlebot 某 个网页或网站已被永久移动到新位置。 302 (临 时移动) 服务器目前正从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以 后的请求。此代码与响应 GET 和 HEAD 请求的 301 代码类似,会自动将请求 者转到不同的位置。但由于 Googlebot 会继续抓取原有位置并将其编入索引,因 此您不应使用此代码来通知 Googlebot 某个页面或网站已被移动。 303 (查 看 其 他 位置) 当请求者应对不同的位置进行单独的 GET 请求以检索响应时,服务器会返回此代 码。对于除 HEAD 请求之外的所有请求,服务器会自动转到其他位置。 304 (未 修改) 自从上次请求后,请求的网页未被修改过。服务器返回此响应时,不会返回网页内 容。 如果网页自请求者上次请求后再也没有更改过,您应当将服务器配置为返回此响应 (称为 If-Modified-Since HTTP 标头)。由于服务器可以告诉 Googlebot 自从上次 抓取后网页没有更改过,因此可节省带宽和开销 。 305 (使 用代理) 请求者只能使用代理访问请求的网页。如果服务器返回此响应,那么,服务器还会 指明请求者应当使用的代理。 307 (临 时 重 定 向) 服务器目前正从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以 后的请求。此代码与响应 GET 和 HEAD 请求的 301 代码类似,会自动将请求 者转到不同的位置。但由于 Googlebot 会继续抓取原有位置并将其编入索引,因 此您不应使用此代码来通知 Googlebot 某个页面或网站已被移动。 4xx (请求错误) 这些状态代码表示,请求可能出错,已妨碍了服务器对请求的处理。 代码 说明 400 (错误 请求) 服务器不理解请求的语法。 401 (未授 权) 请求要求进行身份验证。登录后,服务器可能会返回对页面的此响应。 403 (已禁 止) 服务器拒绝请求。如果在 Googlebot 尝试抓取您网站上的有效网页时显示此状态 代码(您可在 Google 网站管理员工具中诊断下的网络抓取页面上看到此状态代 码),那么,这可能是您的服务器或主机拒绝 Googlebot 对其进行访问。 404 (未找 到) 服务器找不到请求的网页。例如,如果请求是针对服务器上不存在的网页进行的, 那么,服务器通常会返回此代码。 如果您的网站上没有 robots.txt 文件,而您在 Google 网站管理员工具"诊断"标 签的 robots.txt 页上发现此状态,那么,这是正确的状态。然而,如果您有 robots.txt 文件而又发现了此状态,那么,这说明您的 robots.txt 文件可能是命名 错误或位于错误的位置。(该文件应当位于顶级域名上,且应当名为 robots.txt )。 如果您在 Googlebot 尝试抓取的网址上发现此状态(位于"诊断"标签的 HTTP 错误页上),那么,这表示 Googlebot 所追踪的可能是另一网页中的无效链接(旧 链接或输入有误的链接)。 405 (方法 禁用) 禁用请求中所指定的方法。 406 (不接 受) 无法使用请求的内容特性来响应请求的网页。 407 (需要 代 理 授 权) 此状态代码与 401 (未授权)类似,但却指定了请求者应当使用代理进行授权。 如果服务器返回此响应,那么,服务器还会指明请求者应当使用的代理。 408 (请求 超时) 服务器等候请求时超时。 409 ( 冲 突) 服务器在完成请求时发生冲突。服务器必须包含有关响应中所发生的冲突的信 息。服务器在响应与前一个请求相冲突的 PUT 请求时可能会返回此代码,同时 会提供两个请求的差异列表。 410 (已删 除) 如果请求的资源已被永久删除,那么,服务器会返回此响应。该代码与 404 (未 找到)代码类似,但在资源以前有但现在已经不复存在的情况下,有时会替代 404 代码出现。如果资源已被永久删除,那么,您应当使用 301 代码指定该资源的 新位置。 411 (需要 有 效 长 度) 服务器不会接受包含无效内容长度标头字段的请求。 412 (未满 足前提条 件) 服务器未满足请求者在请求中设置的其中一个前提条件。 413 (请求 实 体 过 大) 服务器无法处理请求,因为请求实体过大,已超出服务器的处理能力。 414 (请求 的 URI 过长) 请求的 URI (通常为网址)过长,服务器无法进行处理。 415 (不支 持的媒体 类型) 请求的格式不受请求页面的支持。 416 (请求 范围不符 合要求) 如果请求是针对网页的无效范围进行的,那么,服务器会返回此状态代码。 417 (未满 足 期 望 值) 服务器未满足"期望"请求标头字段的要求。 5xx (服务器错误) 这些状态代码表示,服务器在尝试处理请求时发生内部错误。这些错误可能是服务器本身的 错误,而不是请求出错。 代码 说明 500(服务器内部错误) 服务器遇到错误,无法完成请求。 501 (尚未实施) 服务器不具备完成请求的功能。例如,当服务器无法识别请求方法时, 服务器可能会返回此代码。 502 (错误网关) 服务器作为网关或代理,从上游服务器收到了无效的响应。 503 (服务不可用) 目前无法使用服务器(由于超载或进行停机维护)。通常,这只是一 种暂时的状态。 504 (网关超时) 服务器作为网关或代理,未及时从上游服务器接收请求。 505 (HTTP 版本不受 支持) 服务器不支持请求中所使用的 HTTP 协议版本。 七七七七、、、、form.c(form 请求处理请求处理请求处理请求处理) ----------------------------------------------------------------------------------------------------------------- int websFormHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, char_t *url, char_t *path, char_t *query) 功能:处理 form 请求 说明: 1. 根据 form 的路径 path ,分离出 form 程序名,例如/goform/my ,就是分离出 goform ,路 径中必须要/开头; 2. 然后根据找到的 form 程序名,在 formSymtab 中查找 form 程序,然后执行它。 ----------------------------------------------------------------------------------------------------------------- int websFormDefine(char_t *name, void (*fn)(webs_t wp, char_t *path, char_t *query)) 功能:注册一个 form 程序 说明:name 是名字,就是/goform/my 中的 my ,fn 是参数,是注册在了 formSystab 中了。 ----------------------------------------------------------------------------------------------------------------- void websFormOpen() 功能:打开 sys table 说明: ----------------------------------------------------------------------------------------------------------------- void websFormClose() 功能:关闭 sys table 说明: ----------------------------------------------------------------------------------------------------------------- void websHeader(webs_t wp) 功能:输出 web 的头消息和页面的 说明:包括 HTTP/1.0 200 OK\n、Server: GoAhead/2.5.0\r\n 、Pragma: no-cache\n、Cache-control: no-cache\n、Content-Type: text/html\n、\n、\n 备注:头部消息和 html 实体之间有\n 分割。 这些消息的主要作用是禁止页面缓存,对于 ie6 浏览器,没啥作用,还是缓存! ----------------------------------------------------------------------------------------------------------------- void websMsgHeader(webs_t wp) 功能:输出 web 的头消息 说明:包括 HTTP/1.0 200 OK\n、Server: GoAhead\r\n 、Pragma: no-cache\n、Cache-control: no-cache\n、Content-Type: text/html\n、\n。 ----------------------------------------------------------------------------------------------------------------- void websFooter(webs_t wp) 功能:输出 说明: ----------------------------------------------------------------------------------------------------------------- 八八八八、、、、sym.c ((((symbol hash table )))) typedef struct { /* Symbol table descriptor */ int inuse; /* Is this entry in use */ int hash_size; /* Size of the table below */ sym_t **hash_table; /* Allocated at run time */ } sym_tabent_t; typedef struct sym_t { struct sym_t *forw; /* Pointer to next hash list */ value_t name; /* Name of symbol */ value_t content; /* Value of symbol */ int arg; /* Parameter value */ } sym_t; sym_tabent_t 结构表示一个 hash 表,hash_table[n] 指向 hash 表中的分支 n,每个分支 n 有结 构体 sym_t 表示,每个分支中,有多个 sym_t 组成,它们组成了一个单向链表,每个 sym_t 代表一个名、值对。 ----------------------------------------------------------------------------------------------------------------- int symSubOpen() 功能:打开 symbol table ,初始化。 说明: ----------------------------------------------------------------------------------------------------------------- void symSubClose() 功能:关闭 sysbol table 。 说明: ----------------------------------------------------------------------------------------------------------------- sym_fd_t symOpen(int hash_size) 功能:创建一个 sysbol table 说明: ----------------------------------------------------------------------------------------------------------------- void symClose(sym_fd_t sd) 功能:关闭 sysbol table ,释放分配的内存。 说明: ----------------------------------------------------------------------------------------------------------------- sym_t* symFirst(sym_fd_t sd) 功能:找到指定 sd 的 hash table 中第一个 symbol 说明: ----------------------------------------------------------------------------------------------------------------- sym_t* symNext(sym_fd_t sd) 功能:找到下一个 symbol 说明: ----------------------------------------------------------------------------------------------------------------- sym_t *symLookup(sym_fd_t sd, char_t *name) 功能:在 sd hash table 中找到名字为 name 的 hash 值 说明: ----------------------------------------------------------------------------------------------------------------- sym_t *symEnter(sym_fd_t sd, char_t *name, value_t v, int arg) 功能:进入 hash 表中,更新值 说明: ----------------------------------------------------------------------------------------------------------------- int symDelete(sym_fd_t sd, char_t *name) 功能:删除 hash 表中对应的值。 说明: ----------------------------------------------------------------------------------------------------------------- static sym_t *hash(sym_tabent_t *tp, char_t *name) 功能:根据 name 找到 hash 表中对应的值 说明: ----------------------------------------------------------------------------------------------------------------- static int hashIndex(sym_tabent_t *tp, char_t *name) 功能:计算 hash 索引。一种计算方法而已! 说明: ----------------------------------------------------------------------------------------------------------------- static int isPrime(int n) 功能:核实 n 是否是素数 说明: ----------------------------------------------------------------------------------------------------------------- static int calcPrime(int size) 功能:找到小于 size 的最大的素数 说明: ----------------------------------------------------------------------------------------------------------------- 九九九九、、、、cgi.c ((((cgi )))) int websCgiHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, char_t *url, char_t *path, char_t* query) 功能:处理 cgi 请求。 说明: 1. 抽出页面上 form 中调用的 cgi 程序的名字,构建完整的路径/ata0/webs/www/* 2. 进入到 cgi 程序所在的目录,即/ata0/webs/www 3. 分配内存,建立 cgi 程序的参数,主要是从也空格分割的 qurey 中提取出来 4. 从 cgi 的环境变量中,构建名、值对。 5. 确定标准输入、输出。标准输出是个临时文件。 6. 调用 websLaunchCgiProc ,建立 cgi 处理程序。 ----------------------------------------------------------------------------------------------------------------- void websCgiGatherOutput (cgiRec *cgip) 功能:将临时文件中的内容输出到浏览器上。 说明:也就是将 cgi 程序 prinf 出的内存到临时文件,然后读取临时文件中的内容到浏览器 上。 ----------------------------------------------------------------------------------------------------------------- void websCgiCleanup() 功能:调用 websCgiGatherOutput 处理输出,清空 cgi 所占用的资源 说明: ----------------------------------------------------------------------------------------------------------------- char_t *websGetCgiCommName() 功能:临时文件名 说明: ----------------------------------------------------------------------------------------------------------------- int websLaunchCgiProc(char_t *cgiPath, char_t **argp, char_t **envp, char_t *stdIn, char_t *stdOut) 功能:cgi 处理程序。 说明: 1. 根据 cgiPath ,卸载已有的 module 2. 查找_www_cgientry 的对应值,找到就将值赋给 entryAddr ,生成任务 vxWebsCgiEntry 3. 如果找不到,就加载 cgiPath ,生成任务 vxWebsCgiEntry ----------------------------------------------------------------------------------------------------------------- static void vxWebsCgiEntry(void *entryAddr(int argc, char_t **argv), char_t **argp, char_t **envp, char_t *stdIn, char_t *stdOut) 功能:cgi 程序的外壳,都是通过调用它,来调用 cgi 程序 说明:设置该任务的标准输入、输出为 stdIn 、stdOut ,创建环境变量,用 envp 对环境变量 赋值,调用 cgi 处理函数 entryAddr 。 ----------------------------------------------------------------------------------------------------------------- int websCheckCgiProc(int handle) 功能:检查 cgi 任务是否存在 说明: ----------------------------------------------------------------------------------------------------------------- 十十十十、、、、main.c ((((主程序主程序主程序主程序)))) 是 web 服务器的主要,也就是启动函数。 int websvxmain(int argc, char **argv) 功能:goahead web 服务器的启动的第一个函数。 说明: 1. 判断命令中有没有-demo ,有则,代码中包含/wwwdemo/ 目录下的页面对应的 cgi 程序, 该目录下是一些例子程序。 2. 分配一个 60k 的内存空间。 3. 初始化 web 服务器。 4. 然后进入 while 循环,在打开的 socket 数组中寻找是否有一个 socket 需要处理 (socketReady );如果没有,则等待 2 秒,发现有可读、可写 socket (socketSelect )。如 果有则进行处理(socketProcess )。对于 cgi 程序需要进行输出数据到浏览器,释放内存 (websCgiCleanup ),还进行 emfSchedProcess (以后再说) 5. while 循环之外,umclose 、关闭 web 服务器、关闭 socket ,这些主要是释放分配的内存。 ----------------------------------------------------------------------------------------------------------------- static int initWebs(int demo) 功能:初始化 web 服务器。 说明: 1. 用到的全局变量的初始化,打开 sym hash table 、打开用户管理,注册 UM tables 。 2. 从配置文件 umconfig.txt 中恢复 um 的数据。 3. 获得 web 服务器所在主机上的 ip 地址等信息。 4. 确定 web 服务器的根目录,对于例子程序,根目录是/ata0/webs/wwwdemo ,这个只是例 子,真正的根目录是/ata0/webs/www. 5. 设置默认的目录为/ata0/webs/www. 6. 设 置 默 认 的 页 面 和 密 码 ( websSetDefaultPage(T("default.asp")); websSetPassword(password); ),默认页面有用,密码没有用到,没啥用。默认页面主要 是当 websDefaultHandler 处理的 url 请求时,如果 url 只是路径,没有页面时,就调用这 个页面。 7. 然后建立 socket ,listen 。(websOpenServer ) 8. 创 建 几 个 处 理 句 柄 , 分 别 对 应 认 证 ( websSecurityHandler ), gofrom 处 理 (websFormHandler ),标准 cgi 处理(websCgiHandler ),page (html 、css 、image )、asp 处理(websDefaultHandler )。 9. 然后是两个例子程序,分别对应 goform 、asp ,移植 web 服务器时,将其注释掉。 10. 然后是用户管理对应的页面的 asp 、goform 程序,移植 web 服务器时不需要这些。 11. 然后定义一个默认主页面,也就是当用户登陆到 web 服务器是,输入 ip 地址,能够自 动跳到的页面,也就是更目录“/”时,例如 193168.12.12 或 192.168.12.12/ 。移植时, 根据具体情况自己修改。 12. 然后是 SIGTERM、SIGKILL 两个信号的处理程序。 ----------------------------------------------------------------------------------------------------------------- static int aspTest(int eid, webs_t wp, int argc, char_t **argv) 功能:一个 asp 的例子。 说明:也就是/wwwdemo/asptest.asp 上对应的 asp 处理函数。 ----------------------------------------------------------------------------------------------------------------- static void formTest(webs_t wp, char_t *path, char_t *query) 功能:一个 form 例子。 说明:也就是/wwwdemo/ formtest.htm 上对应的 goform 处理函数 ----------------------------------------------------------------------------------------------------------------- static int websHomePageHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, char_t *url, char_t *path, char_t *query) 功能:主页面处理函数 说明:当输入的只是 ip 地址,或者有 ip 地址和根路径“/”,跳到该函数定义的页面去。 ----------------------------------------------------------------------------------------------------------------- static void websTermSigHandler(int signo) 功能:SIGTERM、SIGKILL 信号处理函数 说明:主要释放内存。 ----------------------------------------------------------------------------------------------------------------- 十一十一十一十一、、、、handler.c ((((url 处理函数处理函数处理函数处理函数)))) int websUrlHandlerOpen() 功能:主要是初始化 url hander 处理模块 说明: ----------------------------------------------------------------------------------------------------------------- void websUrlHandlerClose() 功能:关闭 url hander 处理模块 说明: ----------------------------------------------------------------------------------------------------------------- int websUrlHandlerDefine(char_t *urlPrefix, char_t *webDir, int arg, int (*handler)(webs_t wp, char_t *urlPrefix, char_t *webdir, int arg, char_t *url, char_t *path, char_t *query), int flags) 功能:定义一个 url hander 处理函数,该函数主要是添加到结构体数组 websUrlHandlerType 中。 说明:security 、cgi 、goform 、defaultpage 都是有他来定义对应的处理函数的。 ----------------------------------------------------------------------------------------------------------------- int websUrlHandlerDelete(int (*handler)(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, char_t *url, char_t *path, char_t *query)) 功能:删除一个 url 处理函数 说明: ----------------------------------------------------------------------------------------------------------------- static int websUrlHandlerSort(const void *p1, const void *p2) 功能:整理 url 处理函数,供 qsort 使用。 说明: ----------------------------------------------------------------------------------------------------------------- int websPublish(char_t *urlPrefix, char_t *path) 功能:没用到 说明: ----------------------------------------------------------------------------------------------------------------- char_t *websGetPublishDir(char_t *path, char_t **urlPrefix) 功能:没用到 说明: ----------------------------------------------------------------------------------------------------------------- static int websPublishHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int sid, char_t *url, char_t *path, char_t *query) 功能:没用到 说明: ----------------------------------------------------------------------------------------------------------------- int websUrlHandlerRequest(webs_t wp) 功能:很重要的一个函数,对于一个请求,查找是否有相应的处理函数,主要是根据请求的 url 的 前 缀 来 查 找 , 例 如 /goform/myform , 则 根 据 /goform 找 到 了 对 应 的 处 理 函 数 websFormHandler 。 说明: ----------------------------------------------------------------------------------------------------------------- static char_t *websCondenseMultipleChars(char_t *strToCondense, char_t cCondense) 功能:被 websUrlHandlerRequest 调用,将重复的字符"/" 去掉。 说明: ----------------------------------------------------------------------------------------------------------------- 十二十二十二十二、、、、default.c ((((page 、、、、asp 请求请求请求请求处理程序处理程序处理程序处理程序)))) int websDefaultHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, char_t *url, char_t *path, char_t *query) 功能:处理一个默认的 url 请求。 说明:是处理除了/goform,/cgi-bin,/ 的所有 page (html 、css 、image )、asp 请求的处理。 1. 判断请求的路径是否正确。 2. 如果路径中没有包含页面,则调用默认的页面,例如 url 为/my/ ,则认为/my/default.asp 。 3. 打开请求的 page 和查询 page 的状态信息 4. 输出 HTTP response header 5. 如果是 asp 文件,则需要添加一些 HTTP response header 6. 如果是 asp 请求,由 websAspRequest 处理。 7. 建立输出 page 数据到浏览器的处理句柄。这个输出是在 web 服务器主循环 while 中,看 到 有 SOCKET_WRITABLE, 才 把 page 数 据 输 出 去 。处理输出数据的函数是 websDefaultWriteEvent 。 ----------------------------------------------------------------------------------------------------------------- int websValidateUrl(webs_t wp, char_t *path) 功能:判断路径是否有效的函数。 说明:这个函数在 2.1.8 中曾经有 bug ,现在已经修改过来了。 1. 首先将“\”转换为“/” 2. 然后将路径按照“/”,分成一块块。 3. 对于“..”要越到上一层,最后生成的路径是个没有“..”、“.”的绝对路径,以“/”开 始。 ----------------------------------------------------------------------------------------------------------------- static void websDefaultWriteEvent(webs_t wp) 功能:将 page 输出到浏览器的函数。 说明:该函数只处理 page ,不处理 asp 。 ----------------------------------------------------------------------------------------------------------------- void websDefaultOpen() 功能:初始化变量 说明: ----------------------------------------------------------------------------------------------------------------- void websDefaultClose() 功能:清空变量 说明: ----------------------------------------------------------------------------------------------------------------- char_t *websGetDefaultPage() 功能:获得默认页面。 说明: 这个对应有路径,但没有具体页面的 url 。不包括更目录/,即主页面。 ----------------------------------------------------------------------------------------------------------------- char_t *websGetDefaultDir() 功能:获得默认的路径 说明: 就是/ata0/webs/www ,即主路径“/” ----------------------------------------------------------------------------------------------------------------- void websSetDefaultPage(char_t *page) 功能:设置默认的页面 说明: ----------------------------------------------------------------------------------------------------------------- void websSetDefaultDir(char_t *dir) 功能:设置默认的路径 说明: ----------------------------------------------------------------------------------------------------------------- 十三十三十三十三、、、、page.c ((((页面处理函数页面处理函数页面处理函数页面处理函数)))) int websPageOpen(webs_t wp, char_t *lpath, char_t *path, int mode, int perm) 功能:打开一个 web 页面,页面有两种存放模式,一种是存放在文件系统中,另一种是 rom 方式(WEBS_PAGE_ROM),是将页面、js 、image 、css 等通过工具 webcomp 转换为数组, 然后将其编译到最后的可执行代码中,所以这种方式占用内存较多。 说明: ----------------------------------------------------------------------------------------------------------------- void websPageClose(webs_t wp) 功能:关闭一个 web 页面 说明: ----------------------------------------------------------------------------------------------------------------- int websPageStat(webs_t wp, char_t *lpath, char_t *path, websStatType* sbuf) 功能:查询页面的 stat 。 说明: ----------------------------------------------------------------------------------------------------------------- int websPageIsDirectory(char_t *lpath) 功能:判断这个 lpath 是页面还是路径。 说明: ----------------------------------------------------------------------------------------------------------------- int websPageReadData(webs_t wp, char *buf, int nBytes) 功能:从页面中的内容到 buf 中。 说明: ----------------------------------------------------------------------------------------------------------------- void websPageSeek(webs_t wp, long offset) 功能:移动到文件的某个位置。 说明: ----------------------------------------------------------------------------------------------------------------- 十四十四十四十四、、、、rom.c 和和和和 webcomp.c(页面页面页面页面 rom 处理程处理程处理程处理程 序序序序) Rom.c 中的程序主要是对 rom 方式存放的 web page 进行处理。 Webcomp.c 主要是对将 web page 转换为 rom 形式,转换后的 web page 为 webrom.c Webrom.c 文件中存放着各个页面。 websRomPageIndexType websRomPageIndex[] 是一个数组,结构体为: typedef struct { char_t *path; /* Web page URL path */ unsigned char *page; /* Web page data */ int size; /* Size of web page in bytes */ int pos; /* Current read position */ } websRomPageIndexType; 例如: websRomPageIndexType websRomPageIndex[] = { { T("/css/style.css"), page_0 , 3578 }, { T("/css/tree.css"), page_1, 300 }, { T("/eth.asp"), page_2, 6404 }, { T("/ethglobal.asp"), page_3, 2927 }, { T("/global.asp"), page_4, 868 }, { T("/images/empty.gif"), page_5, 834 }, { T("/images/join.gif"), page_6, 870 }, { T("/images/joinbottom.gif"), page_7, 856 }, { T("/images/line.gif"), page_8, 856 }, { T("/images/logo.gif"), page_9, 1545 }, { T("/images/minus.gif"), page_10, 872 }, { T("/images/minusbottom.gif"), page_11, 868 }, { T("/images/nolines_minus.gif"), page_12, 859 }, { T("/images/nolines_plus.gif"), page_13, 862 }, { T("/images/plus.gif"), page_14, 873 }, { T("/images/plusbottom.gif"), page_15, 869 }, { T("/index.asp"), page_16, 2965 }, { T("/index.htm"), page_17, 3119 }, { T("/js/common.js"), page_18, 1103 }, ….. { 0, 0, 0 }, } 分别对应 page 的路径、page 数据的字符数组、page 中字符数量。 static unsigned char page_0 [] = { 98,111,100,121, 44, 32,116, 97, 98,108,101, 44, 32,116, 97, 98, 108,101, 32,116,100, 32,123, 10, 32, 32, 32, 32,102,111,110,116, 45,102, 97,109,105,108,121, 58, 32, 34, 72,101,108,118,101,116, 105, 99, 97, 34, 59, 10,125, 10, 10, 98,111,100,121, 32,123, 10, 32, 32, 32, 32,102,111,110,116, 45,115,105,122,101, 58, 32, 57, 112,116, 59, 10, 32, 32, 32, 32, 98, 97, 99,107,103,114,111,117, 110,100, 45, 99,111,108,111,114, 58, 32, 35, 68, 65, 69, 56, 70, 。。。。 } Page_0 就是"/css/style.css" 的数据。 int websRomOpen() 功能:打开 rom 模块 说明: ----------------------------------------------------------------------------------------------------------------- void websRomClose() 功能:关闭 rom 模块。 说明: ----------------------------------------------------------------------------------------------------------------- int websRomPageOpen(webs_t wp, char_t *path, int mode, int perm) 功能:打开一个 page 说明: ----------------------------------------------------------------------------------------------------------------- int websRomPageStat(char_t *path, websStatType *sbuf) 功能:查询 page 的 stat 信息。 说明: ----------------------------------------------------------------------------------------------------------------- int websRomPageReadData(webs_t wp, char *buf, int nBytes) 功能:读取 rom 中 page 到 buf 中。 说明: ----------------------------------------------------------------------------------------------------------------- long websRomPageSeek(webs_t wp, long offset, int origin) 功能:移动到 page 中的某个位置 说明: ----------------------------------------------------------------------------------------------------------------- Webcomp.c 中的程序在 linux 下能编译通过、跑起来。 int main(int argc, char* argv[]) 功能:主程序 说明:输入命令时需要两个参数,./webcomp prefix filelist >webrom.c ,prefix 是 page 所在的 目录,filelist 是 page 目录名称文件,>webrom.c 是生成的 rom 文件。 一般可以这样 find ../web1 –name "*.*" > websfile ./webcomp ../web1 websfile > ../webrom.c websfile 中的内容是: web1/css/style.css web1/css/tree.css web1/eth.asp web1/ethglobal.asp web1/global.asp web1/images/empty.gif …. ----------------------------------------------------------------------------------------------------------------- static void usage() 功能:说明语句。 说明: ----------------------------------------------------------------------------------------------------------------- static int compile(char *fileList, char *prefix) 功能:转换生成 rom 文件的主程序。 说明:生成 webrom.c 文件 ----------------------------------------------------------------------------------------------------------------- 由于感觉 webcomp.c 只是 linux 下程序,所以修改了一下,转换成 windows 下的程序。 /********************************* Includes ***********************************/ #include #include #include #include #include #include #include #include #include #include #include /**************************** Forward Declarations ****************************/ typedef char char_t; typedef struct stat gstat_t; #define FNAMESIZE 254 /* Max length of file names */ #define gctime ctime #define gstat stat #define gopen open #define gstrlen strlen #define MAX_FILENAME 500 static int compile(char_t *fileList, char_t *prefix); static void usage(); int searchFile(char *pathname, FILE *fp); int makeFile(char *pathname, char *filename); /*********************************** Code *************************************/ /* * Main program for webpack test harness */ int searchFile(char *pathname, FILE *fp) { struct _finddata_t data; char path[MAX_FILENAME]; long handle = 0; char subpath[MAX_FILENAME]; int length = 0; /******************************************************/ strcpy(path, pathname); strcat(path, "\\*"); handle = _findfirst(path,&data); if (-1 == handle) { _findclose(handle); return 0; } if ((0 != strcmp(data.name, ".")) && (0 != strcmp(data.name, "..")) && (0 != strcmp(data.name,"thumbs.db"))) { strcpy(subpath, pathname); length = strlen(pathname); if (pathname[length-1] != '\\') { strcat(subpath,"\\"); } strcat(subpath, data.name); if (_A_SUBDIR == (data.attrib&_A_SUBDIR)) { searchFile(subpath, fp); } else { fprintf(fp,subpath, strlen(subpath)); fprintf(fp, "\n", strlen("\n")); } } while(0 == _findnext(handle, &data)) { if ((0 != strcmp(data.name, ".")) && (0 != strcmp(data.name, "..")) && (0 != strcmp(data.name,"thumbs.db"))) { strcpy(subpath, pathname); length = strlen(pathname); if (pathname[length-1] != '\\') { strcat(subpath,"\\"); } strcat(subpath, data.name); if (_A_SUBDIR == data.attrib) { searchFile(subpath, fp); } else { fprintf(fp,subpath, strlen(subpath)); fprintf(fp, "\n", strlen("\n")); } } } _findclose(handle); return 0; } int makeFile(char *pathname, char *filename) { FILE *fp = NULL; fp = fopen("websfile", "w+"); searchFile(pathname, fp); fclose(fp); strcpy(filename, "websfile"); return 0; } int main(int argc, char_t* argv[]) { char_t *fileList, *prefix; char_t fileName[MAX_FILENAME]; fileList = NULL; if (argc != 2) { usage(); } memset(fileName, 0, sizeof(fileName)); prefix = argv[1];//dir makeFile(prefix, fileName); if (compile(fileName, prefix) < 0) { return -1; } return 0; } /****************************************************************************** / /* * Output usage message */ static void usage() { fprintf(stderr, "usage: webcomp path >output.c\n"); exit(2); } /****************************************************************************** / /* * Compile the web pages */ static int compile(char_t *fileList, char_t *prefix) { gstat_t sbuf; FILE *lp; time_t now; char_t file[FNAMESIZE]; char_t *cp, *sl; char buf[512]; unsigned char *p; int j, i, len, fd, nFile; //printf("fileList:%s\r\n", fileList); /* * Open list of files */ if ((lp = fopen(fileList, "r")) == NULL) { fprintf(stderr, "Can't open file list %s\n", fileList); return -1; } time(&now); fprintf(stdout, "/*\n * webrom.c -- Compiled Web Pages\n *\n"); fprintf(stdout, " * Compiled by GoAhead WebCompile: %s */\n\n", gctime(&now)); fprintf(stdout, "#include \"wsIntrn.h\"\n\n"); fprintf(stdout, "#ifndef WEBS_PAGE_ROM\n"); fprintf(stdout, "websRomPageIndexType websRomPageIndex[] = {\n"); fprintf(stdout, " { 0, 0, 0 },\n};\n"); fprintf(stdout, "#else\n"); /* * Open each input file and compile each web page */ nFile = 0; while (fgets(file, sizeof(file), lp) != NULL) { if ((p = strchr(file, '\n')) || (p = strchr(file, '\r'))) { *p = '\0'; } if (*file == '\0') { continue; } if (gstat(file, &sbuf) == 0 && sbuf.st_mode & S_IFDIR) { continue; } errno = 0; if ((fd = gopen(file, O_RDONLY | O_BINARY)) < 0) { fprintf(stderr, "Can't open file %s\n", file); return -1; } fprintf(stdout, "static unsigned char page_%d[] = {\n", nFile); while ((len = read(fd, buf, sizeof(buf))) > 0) { p = buf; for (i = 0; i < len; ) { fprintf(stdout, " "); for (j = 0; p < &buf[len] && j < 16; j++, p++) { fprintf(stdout, "%3d,", *p); } i += j; fprintf(stdout, "\n"); } } fprintf(stdout, " 0 };\n\n"); close(fd); nFile++; } fclose(lp); /* * Now output the page index */ fprintf(stdout, "websRomPageIndexType websRomPageIndex[] = {\n"); if ((lp = fopen(fileList, "r")) == NULL) { fprintf(stderr, "Can't open file list %s\n", fileList); return -1; } nFile = 0; while (fgets(file, sizeof(file), lp) != NULL) { if ((p = strchr(file, '\n')) || (p = strchr(file, '\r'))) { *p = '\0'; } if (*file == '\0') { continue; } /* * Remove the prefix and add a leading "/" when we print the path */ if (strncmp(file, prefix, gstrlen(prefix)) == 0) { cp = &file[gstrlen(prefix)]; } else { cp = file; } while((sl = strchr(file, '\\')) != NULL) { *sl = '/'; } if (*cp == '/') { cp++; } if (gstat(file, &sbuf) == 0 && sbuf.st_mode & S_IFDIR) { fprintf(stdout, " { T(\"/%s\"), 0, 0 },\n", cp); continue; } fprintf(stdout, " { T(\"/%s\"), page_%d, %d },\n", cp, nFile, sbuf.st_size); nFile++; } fclose(lp); fprintf(stdout, " { 0, 0, 0 },\n"); fprintf(stdout, "};\n"); fprintf(stdout, "#endif /* WEBS_PAGE_ROM */\n"); fclose(lp); fflush(stdout); return 0; } /****************************************************************************** / 然后编写了 bat 文件,内容是: webcomp.exe web1 > src\webrom.c 即将 web1 目录下 page 转换成 webrom.c 了。 十五十五十五十五、、、、ringq.c(环回队列环回队列环回队列环回队列) 这个模块是一个环回的队列存储模块。 /* * Ring queue buffer structure */ typedef struct { unsigned char *buf; /* Holding buffer for data */ unsigned char *servp; /* Pointer to start of data */ unsigned char *endp; /* Pointer to end of data */ unsigned char *endbuf; /* Pointer to end of buffer */ int buflen; /* Length of ring queue */ int maxsize; /* Maximum size */ int increment; /* Growth increment */ } ringq_t; Servp :指向数据开始。 Endp :指向数据的结束的后一个字节。 Buf :指向 buf 开始 Endbuf :指向 buf 的结束的后一个字节。 这个模块就是一个 buf 环,当 servp 等于 endp 时,代表 buf 是空的,没有数据。 int ringqOpen(ringq_t *rq, int initSize, int maxsize) 功能:建立一个环形 buf 说明:大小是 initSize ,最大可扩展为 maxsize 。 ----------------------------------------------------------------------------------------------------------------- void ringqClose(ringq_t *rq) 功能:关闭 buf 环,释放内存。 说明: ----------------------------------------------------------------------------------------------------------------- int ringqLen(ringq_t *rq) 功能:计算 buf 环中有多少数据 说明: 由于是 buf 环,所以数据开始的地址 servp 可能大于数据结束的地址 endp ,所以需要加上一 个 buf 环的长度。 ----------------------------------------------------------------------------------------------------------------- int ringqGetc(ringq_t *rq) 功能:从 buf 环中数据头部移走一个字符。 说明:是从 servp 开始移走的,所以 servp 要加 1. ----------------------------------------------------------------------------------------------------------------- int ringqPutc(ringq_t *rq, char_t c) 功能:向 buf 环中数据尾部添加一个字符 说明:endp 要加 1. ----------------------------------------------------------------------------------------------------------------- int ringqInsertc(ringq_t *rq, char_t c) 功能:在数据头部插入一个字符 说明: ----------------------------------------------------------------------------------------------------------------- int ringqPutStr(ringq_t *rq, char_t *str) 功能:向 buf 中添加一字符串。 说明: ----------------------------------------------------------------------------------------------------------------- int ringqPutBlk(ringq_t *rq, unsigned char *buf, int size) 功能:向 buf 拷贝一块数据,使用的是 memcpy ,所以只能是直线拷贝,不能打环了。 说明:使用 ringqPutBlkMax 来获得能拷贝多少直线拷贝数据,不够的话,扩展 buf ----------------------------------------------------------------------------------------------------------------- int ringqGetBlk(ringq_t *rq, unsigned char *buf, int size) 功能:从 buf 拷贝一块数据,也是 memcpy ,直线拷贝。 说明:使用 ringqGetBlkMax 来获得能拷贝多少直线拷贝数据 ----------------------------------------------------------------------------------------------------------------- int ringqPutBlkMax(ringq_t *rq) 功能:也是返回两个值中的最小值。 说明:rq->buflen - RINGQ_LEN(rq) – 1 与 rq->endbuf - rq->endp ----------------------------------------------------------------------------------------------------------------- int ringqGetBlkMax(ringq_t *rq) 功能:范围 endp-servp 与 endbuf-servp 的最小值 说明: ----------------------------------------------------------------------------------------------------------------- void ringqPutBlkAdj(ringq_t *rq, int size) 功能:向 buf 添加数据,调整 endp 。 说明:endp 是加的方向。 ----------------------------------------------------------------------------------------------------------------- void ringqGetBlkAdj(ringq_t *rq, int size) 功能:从 buf 中考走数据后,调整 servp 说明:servp 是加的方向。 ----------------------------------------------------------------------------------------------------------------- void ringqFlush(ringq_t *rq) 功能:清除环回 buf 中的数据 说明:即 servp 等于 endp ----------------------------------------------------------------------------------------------------------------- static int ringqGrow(ringq_t *rq) 功能:扩展环回 buf 的大小 说明: ----------------------------------------------------------------------------------------------------------------- static int getBinBlockSize(int size) 功能:获得 size 的块的大小 说明:块的大小必须是 2 的多少次幂 ----------------------------------------------------------------------------------------------------------------- 十六十六十六十六、、、、mime.c 、、、、mime64.c 、、、、url.c 、、、、value.c Mime.c 中定义了 mime 的类型和对应的扩展名。 MIME 类型就是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件 被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文 件名,以及一些媒体文件打开方式。 下面列出常用的文件对应的 MIME 类型: MimeMimeMimeMime----Types(mimeTypes(mimeTypes(mimeTypes(mime 类型类型类型类型)))) Dateiendung(Dateiendung(Dateiendung(Dateiendung(扩展名扩展名扩展名扩展名)))) BedeutungBedeutungBedeutungBedeutung application/msexcel *.xls *.xla Microsoft Excel Dateien application/mshelp *.hlp *.chm Microsoft Windows Hilfe Dateien application/mspowerpoint *.ppt *.ppz *.pps *.pot Microsoft Powerpoint Dateien application/msword *.doc *.dot Microsoft Word Dateien application/octet-stream *.exe exe application/pdf *.pdf Adobe PDF-Dateien application/post****** *.ai *.eps *.ps Adobe Post******-Dateien application/rtf *.rtf Microsoft RTF-Dateien application/x-httpd-php *.php *.phtml PHP-Dateien application/x-java****** *.js serverseitige Java******-Dateien application/x-shockwave-flash *.swf *.cab Flash Shockwave-Dateien application/zip *.zip ZIP-Archivdateien audio/basic *.au *.snd Sound-Dateien audio/mpeg *.mp3 MPEG-Dateien audio/x-midi *.mid *.midi MIDI-Dateien audio/x-mpeg *.mp2 MPEG-Dateien audio/x-wav *.wav Wav-Dateien image/gif *.gif GIF-Dateien image/jpeg *.jpeg *.jpg *.jpe JPEG-Dateien image/x-windowdump *.xwd X-Windows Dump text/css *.css CSS Stylesheet-Dateien text/html *.htm *.html *.shtml -Dateien text/java****** *.js Java******-Dateien text/plain *.txt reine Textdateien video/mpeg *.mpeg *.mpg *.mpe MPEG-Dateien video/vnd.rn-realvideo *.rmvb realplay-Dateien video/quicktime *.qt *.mov Quicktime-Dateien video/vnd.vivo *viv *.vivo Vivo-Dateien MIME 类型大全 application/vnd.lotus-1-2-3 3gp video/3gpp aab application/x-authoware-bin aam application/x-authoware-map aas application/x-authoware-seg ai application/post****** aif audio/x-aiff aifc audio/x-aiff aiff audio/x-aiff als audio/X-Alpha5 amc application/x-mpeg ani application/octet-stream asc text/plain asd application/astound asf video/x-ms-asf asn application/astound asp application/x-asap asx video/x-ms-asf au audio/basic avb application/octet-stream avi video/x-msvideo awb audio/amr-wb bcpio application/x-bcpio bin application/octet-stream bld application/bld bld2 application/bld2 bmp application/x-MS-bmp bpk application/octet-stream bz2 application/x-bzip2 cal image/x-cals ccn application/x-cnc cco application/x-cocoa cdf application/x-netcdf cgi magnus-internal/cgi chat application/x-chat class application/octet-stream clp application/x-msclip cmx application/x-cmx co application/x-cult3d-object cod image/cis-cod cpio application/x-cpio cpt application/mac-compactpro crd application/x-mscardfile csh application/x-csh csm chemical/x-csml csml chemical/x-csml css text/css cur application/octet-stream dcm x-lml/x-evm dcr application/x-director dcx image/x-dcx dhtml text/html dir application/x-director dll application/octet-stream dmg application/octet-stream dms application/octet-stream doc application/msword dot application/x-dot dvi application/x-dvi dwf drawing/x-dwf dwg application/x-autocad dxf application/x-autocad dxr application/x-director ebk application/x-expandedbook emb chemical/x-embl-dl-nucleotide embl chemical/x-embl-dl-nucleotide eps application/post****** eri image/x-eri es audio/echospeech esl audio/echospeech etc application/x-earthtime etx text/x-setext evm x-lml/x-evm evy application/x-envoy exe application/octet-stream fh4 image/x-freehand fh5 image/x-freehand fhc image/x-freehand fif image/fif fm application/x-maker fpx image/x-fpx fvi video/isivideo gau chemical/x-gaussian-input gca application/x-gca-compressed gdb x-lml/x-gdb gif image/gif gps application/x-gps gtar application/x-gtar gz application/x-gzip hdf application/x-hdf hdm text/x-hdml hdml text/x-hdml hlp application/winhlp hqx application/mac-binhex40 htm text/html html text/html hts text/html ice x-conference/x-cooltalk ico application/octet-stream ief image/ief ifm image/gif ifs image/ifs imy audio/melody ins application/x-NET-Install ips application/x-ip****** ipx application/x-ipix it audio/x-mod itz audio/x-mod ivr i-world/i-vrml j2k image/j2k jad text/vnd.sun.j2me.app-de******or jam application/x-jam jar application/java-archive jnlp application/x-java-jnlp-file jpe image/jpeg jpeg image/jpeg jpg image/jpeg jpz image/jpeg js application/x-java****** jwc application/jwc kjx application/x-kjx lak x-lml/x-lak latex application/x-latex lcc application/fastman lcl application/x-digitalloca lcr application/x-digitalloca lgh application/lgh lha application/octet-stream lml x-lml/x-lml lmlpack x-lml/x-lmlpack lsf video/x-ms-asf lsx video/x-ms-asf lzh application/x-lzh m13 application/x-msmediaview m14 application/x-msmediaview m15 audio/x-mod m3u audio/x-mpegurl m3url audio/x-mpegurl ma1 audio/ma1 ma2 audio/ma2 ma3 audio/ma3 ma5 audio/ma5 man application/x-troff-man map magnus-internal/imagemap mbd application/mbedlet mct application/x-mascot mdb application/x-msaccess mdz audio/x-mod me application/x-troff-me mel text/x-vmel mi application/x-mif mid audio/midi midi audio/midi mif application/x-mif mil image/x-cals mio audio/x-mio mmf application/x-skt-lbs mng video/x-mng mny application/x-msmoney moc application/x-mocha mocha application/x-mocha mod audio/x-mod mof application/x-yumekara mol chemical/x-mdl-molfile mop chemical/x-mopac-input mov video/quicktime movie video/x-sgi-movie mp2 audio/x-mpeg mp3 audio/x-mpeg mp4 video/mp4 mpc application/vnd.mpohun.certificate mpe video/mpeg mpeg video/mpeg mpg video/mpeg mpg4 video/mp4 mpga audio/mpeg mpn application/vnd.mophun.application mpp application/vnd.ms-project mps application/x-mapserver mrl text/x-mrml mrm application/x-mrm ms application/x-troff-ms mts application/metastream mtx application/metastream mtz application/metastream mzv application/metastream nar application/zip nbmp image/nbmp nc application/x-netcdf ndb x-lml/x-ndb ndwn application/ndwn nif application/x-nif nmz application/x-scream nokia-op-logo image/vnd.nok-oplogo-color npx application/x-netfpx nsnd audio/nsnd nva application/x-neva1 oda application/oda oom application/x-AtlasMate-Plugin pac audio/x-pac pae audio/x-epac pan application/x-pan pbm image/x-portable-bitmap pcx image/x-pcx pda image/x-pda pdb chemical/x-pdb pdf application/pdf pfr application/font-tdpfr pgm image/x-portable-graymap pict image/x-pict pm application/x-perl pmd application/x-pmd png image/png pnm image/x-portable-anymap pnz image/png pot application/vnd.ms-powerpoint ppm image/x-portable-pixmap pps application/vnd.ms-powerpoint ppt application/vnd.ms-powerpoint pqf application/x-cprplayer pqi application/cprplayer prc application/x-prc proxy application/x-ns-proxy-autoconfig ps application/post****** ptlk application/listenup pub application/x-mspublisher pvx video/x-pv-pvx qcp audio/vnd.qcelp qt video/quicktime qti image/x-quicktime qtif image/x-quicktime r3t text/vnd.rn-realtext3d ra audio/x-pn-realaudio ram audio/x-pn-realaudio rar application/x-rar-compressed ras image/x-cmu-raster rdf application/rdf+xml rf image/vnd.rn-realflash rgb image/x-rgb rlf application/x-richlink rm audio/x-pn-realaudio rmf audio/x-rmf rmm audio/x-pn-realaudio rmvb audio/x-pn-realaudio rnx application/vnd.rn-realplayer roff application/x-troff rp image/vnd.rn-realpix rpm audio/x-pn-realaudio-plugin rt text/vnd.rn-realtext rte x-lml/x-gps rtf application/rtf rtg application/metastream rtx text/richtext rv video/vnd.rn-realvideo rwc application/x-rogerwilco s3m audio/x-mod s3z audio/x-mod sca application/x-supercard scd application/x-msschedule sdf application/e-score sea application/x-stuffit sgm text/x-sgml sgml text/x-sgml sh application/x-sh shar application/x-shar shtml magnus-internal/parsed-html shw application/presentations si6 image/si6 si7 image/vnd.stiwap.sis si9 image/vnd.lgtwap.sis sis application/vnd.symbian.install sit application/x-stuffit skd application/x-Koan skm application/x-Koan skp application/x-Koan skt application/x-Koan slc application/x-salsa smd audio/x-smd smi application/smil smil application/smil smp application/studiom smz audio/x-smd snd audio/basic spc text/x-speech spl application/futuresplash spr application/x-sprite sprite application/x-sprite spt application/x-spt src application/x-wais-source stk application/hyperstudio stm audio/x-mod sv4cpio application/x-sv4cpio sv4crc application/x-sv4crc svf image/vnd svg image/svg-xml svh image/svh svr x-world/x-svr swf application/x-shockwave-flash swfl application/x-shockwave-flash t application/x-troff tad application/octet-stream talk text/x-speech tar application/x-tar taz application/x-tar tbp application/x-timbuktu tbt application/x-timbuktu tcl application/x-tcl tex application/x-tex texi application/x-texinfo texinfo application/x-texinfo tgz application/x-tar thm application/vnd.eri.thm tif image/tiff tiff image/tiff tki application/x-tkined tkined application/x-tkined toc application/toc toy image/toy tr application/x-troff trk x-lml/x-gps trm application/x-msterminal tsi audio/tsplayer tsp application/dsptype tsv text/tab-separated-values tsv text/tab-separated-values ttf application/octet-stream ttz application/t-time txt text/plain ult audio/x-mod ustar application/x-ustar uu application/x-uuencode uue application/x-uuencode vcd application/x-cdlink vcf text/x-vcard vdo video/vdo vib audio/vib viv video/vivo vivo video/vivo vmd application/vocaltec-media-desc vmf application/vocaltec-media-file vmi application/x-dreamcast-vms-info vms application/x-dreamcast-vms vox audio/voxware vqe audio/x-twinvq-plugin vqf audio/x-twinvq vql audio/x-twinvq vre x-world/x-vream vrml x-world/x-vrml vrt x-world/x-vrt vrw x-world/x-vream vts workbook/formulaone wav audio/x-wav wax audio/x-ms-wax wbmp image/vnd.wap.wbmp web application/vnd.xara wi image/wavelet wis application/x-InstallShield wm video/x-ms-wm wma audio/x-ms-wma wmd application/x-ms-wmd wmf application/x-msmetafile wml text/vnd.wap.wml wmlc application/vnd.wap.wmlc wmls text/vnd.wap.wml****** wmlsc application/vnd.wap.wml******c wml****** text/vnd.wap.wml****** wmv audio/x-ms-wmv wmx video/x-ms-wmx wmz application/x-ms-wmz wpng image/x-up-wpng wpt x-lml/x-gps wri application/x-mswrite wrl x-world/x-vrml wrz x-world/x-vrml ws text/vnd.wap.wml****** wsc application/vnd.wap.wml******c wv video/wavelet wvx video/x-ms-wvx wxl application/x-wxl x-gzip application/x-gzip xar application/vnd.xara xbm image/x-xbitmap xdm application/x-xdma xdma application/x-xdma xdw application/vnd.fujixerox.docuworks xht application/xhtml+xml xhtm application/xhtml+xml xhtml application/xhtml+xml xla application/vnd.ms-excel xlc application/vnd.ms-excel xll application/x-excel xlm application/vnd.ms-excel xls application/vnd.ms-excel xlt application/vnd.ms-excel xlw application/vnd.ms-excel xm audio/x-mod xml text/xml xmz audio/x-mod xpi application/x-xpinstall xpm image/x-xpixmap xsit text/xml xsl text/xml xul text/xul xwd image/x-xwindowdump xyz chemical/x-pdb yz1 application/x-yz1 z application/x-compress zac application/x-zaurus-zac zip application/zip int websDecode64(char_t *outbuf, char_t *string, int outlen) 功能:base64 Mime 解码函数。 说明: 具体是怎么回事,没看。 ----------------------------------------------------------------------------------------------------------------- char_t *websUrlType(char_t *url, char_t *buf, int charCnt) 功能:确定 url 的 mime 类型。 说明: 具体是怎么回事,没看。 ----------------------------------------------------------------------------------------------------------------- int websUrlParse(char_t *url, char_t **pbuf, char_t **phost, char_t **ppath, char_t **pport, char_t **pquery, char_t **pproto, char_t **ptag, char_t **pext) 功能:从 url 中分析出信息,放到其他变量中。 说明:返回 host 、path 、port 、qurey 、proto 、tag 、pext ----------------------------------------------------------------------------------------------------------------- URL 的一般格式为(带方括号[] 的为可选项): protocol :// hostname[:port] / path / [;parameters][?query]#fragment 与 FQDN 区别在于多了协议头即"http://" URL 的组成 URL 由三部分组成:协议类型,主机名和路径及文件名。通过 URL 可以指定的主要 有以下几种:http 、ftp 、gopher 、telnet 、file 等。 URL 的组成 协议 1、protocol (协议):指定使用的传输协议,下表列出 protocol 属性的有效方案名称。 最常用的是 HTTP 协议,它也是目前 WWW 中应用最广的协议。 file 资源是本地计算机上的文件。格式 file:/// ftp 通过 FTP 访问资源。格式 FTP:// gopher 通过 Gopher 协议访问该资源。 http 通过 HTTP 访问该资源。 格式 HTTP:// https 通过安全的 HTTPS 访问该资源。 格式 HTTPS:// mailto 资源为电子邮件地址,通过 SMTP 访问。 格式 mailto: mms 通过 支持 MMS(流媒体)协议的播放该资源。(代表软件:Windows Media Player ) 格式 MMS:// ed2k 通过 支持 ed2k (专用下载链接)协议的 P2P 软件访问该资源。(代表软件:电驴) 格式 ed2k:// flashget 通过 支持 Flashget: (专用下载链接)协议的 P2P 软件访问该资源。(代表 软件:快车) 格式 Flashget:// thunder 通过 支持 thunder (专用下载链接)协议的 P2P 软件访问该资源。(代表软件: 迅雷) 格式 thunder:// news 通过 NNTP 访问该资源。 tencent 通过支持 tencent( 专用聊天连接) 协议和用户对话。(代表软件:QQ、TM) 格式 tencent://message/?uin= 号码&Site=&Menu=yes msnim 通过支持 msnim( 专用聊天连接) 协议和用户对话。(代表软件:MSN、WLM) 格 式 msnim:chat?contact= 邮箱地址 主机名 2、hostname (主机名):是指存放资源的服务器的域名系统 (DNS) 主机名或 IP 地址。 有时,在主机名前也可以包含连接到服务器所需的用户名和密码(格式:username:password )。 端口号 3、port (端口号):整数,可选,省略时使用方案的默认端口,各种传输协议都有默认的端 口号,如 http 的默认端口为 80 。如果输入时省略,则使用默认端口号。有时候出于安全或 其他考虑,可以在服务器上对端口进行重定义,即采用非标准端口号,此时,URL 中就不 能省略端口号这一项。 路径 4、path (路径):由零或多个“/”符号隔开的字符串,一般用来表示主机上的一个目录 或文件地址。 参数 5、;parameters (参数):这是用于指定特殊参数的可选项。 查询 6、?query( 查询):可选,用于给动态网页(如使用 CGI、ISAPI、PHP/JSP/ASP/ASP.NET 等技术制作的网页)传递参数,可有多个参数,用“&”符号隔开,每个参数的名和值用“=” 符号隔开。 fragment 7、fragment ,信息片断,字符串,用于指定网络资源中的片断。例如一个网页中有多 个名词解释,可使用 fragment 直接定位到某一名词解释。 注意,Windows 主机不区分 URL 大小写,但是,Unix/Linux 主机区分大小写。 编辑本段 URL 定位标识说明 value_t valueInteger(long value) 功能:初始化一个 int value 说明: ----------------------------------------------------------------------------------------------------------------- value_t valueString(char_t* value, int flags) 功能:初始化一个 string value 说明: ----------------------------------------------------------------------------------------------------------------- void valueFree(value_t* v) 功能:释放分配的。 说明: ----------------------------------------------------------------------------------------------------------------- 十七十七十七十七、、、、asp.c 、、、、ejlex.c 、、、、ejparse.c int websAspOpen() 功能:主要是创建 asp symbol table 和 write 命令 说明:定义了一个 write 命令,对应的实现函数为 websAspWrite ----------------------------------------------------------------------------------------------------------------- void websAspClose() 功能:关闭 Asp symbol table. 说明: ----------------------------------------------------------------------------------------------------------------- int websAspRequest(webs_t wp, char_t *lpath) 功能:处理 asp 请求。就是输出一个 asp 页面,并且将 asp 页面中的 script 解析出来,输出 到 asp 页面中。 说明: 1. 标识,头部信息已经向浏览器输出完成 2. 将 asp 页面读入到内存 buf 中; 3. 然后在 buf 中查找<% language=javascript %> 4. 在查找到<% 时,将 buf 中此位置前的页面输出到浏览器; 5. asp 中可能存在<% language=javascript %> ,也可能不存在<% language=javascript %> ,而 是存在<% ……. %> 。所以需要区分,是<% language=javascript %> 时,不向浏览器输出。 6. 然 后 调 用 <% %> 中 的 处 理 程 序 , 输 出 数 据 到 浏 览 器 , 是 有 区 分 的 ( 有 无 EMF_SCRIPT_EJSCRIPT) 7. 最后输出%> 位置后的 asp 页面数据到浏览器中。 ----------------------------------------------------------------------------------------------------------------- int websAspDefine(char_t *name, int (*fn)(int ejid, webs_t wp, int argc, char_t **argv)) 功能:定义一个 asp 函数 script 说明:就是<% %> 中对应的处理函数。 ----------------------------------------------------------------------------------------------------------------- int websAspWrite(int ejid, webs_t wp, int argc, char_t **argv) 功能:write 命令的实现函数 说明:<%write()%> ----------------------------------------------------------------------------------------------------------------- static char_t *strtokcmp(char_t *s1, char_t *s2) 功能:在字符 s1 中查找 s2 ,掠过 s1 中的空格。 说明: ----------------------------------------------------------------------------------------------------------------- static char_t *skipWhite(char_t *s) 功能:跳过空格 说明: <% language=javascript write("Query String: " + QUERY_STRING) %> <% write("JavaScript is still the selected language"): %>

Today is <% write("Hello World"); %>

例子: ASP Test Page <% language=javascript %>

ASP / JavaScript™ Test

Expanded ASP data: <% aspTest("Peter Smith", "112 Merry Way"); %>

<% var z; \ for (z=0; z<5; z=z+1) \ { \ if (z<=2) \ write(z+" is less than 3
"); \ else if (z==3) \ write(z+" is equal to 3
"); \ else \ write(z+" is greater than 3
"); \ } \ %>

int ejLexOpen(ej_t* ep) void ejLexClose(ej_t* ep) int ejLexOpenScript(ej_t* ep, char_t *script) void ejLexCloseScript(ej_t* ep) void ejLexSaveInputState(ej_t* ep, ejinput_t* state) void ejLexRestoreInputState(ej_t* ep, ejinput_t* state) void ejLexFreeInputState(ej_t* ep, ejinput_t* state) int ejLexGetToken(ej_t* ep, int state) static int getLexicalToken(ej_t* ep, int state) void ejLexPutbackToken(ej_t* ep, int tid, char_t *string) static int tokenAddChar(ej_t *ep, int c) static int inputGetc(ej_t* ep) static void inputPutback(ej_t* ep, int c) static int charConvert(ej_t* ep, int base, int maxDig) int ejOpenEngine(sym_fd_t variables, sym_fd_t functions) void ejCloseEngine(int eid) char_t *ejEvalFile(int eid, char_t *path, char_t **emsg) int ejOpenBlock(int eid) int ejCloseBlock(int eid, int vid) char_t *ejEvalBlock(int eid, char_t *script, char_t **emsg) char_t *ejEval(int eid, char_t *script, char_t **emsg) static int parse(ej_t *ep, int state, int flags) static int parseStmt(ej_t *ep, int state, int flags) static int parseDeclaration(ej_t *ep, int state, int flags) static int parseArgs(ej_t *ep, int state, int flags) static int parseCond(ej_t *ep, int state, int flags) static int parseExpr(ej_t *ep, int state, int flags) static int evalCond(ej_t *ep, char_t *lhs, int rel, char_t *rhs) static int evalExpr(ej_t *ep, char_t *lhs, int rel, char_t *rhs) static int evalFunction(ej_t *ep) void ejError(ej_t* ep, char_t* fmt, ...) static void clearString(char_t **ptr) static void setString(B_ARGS_DEC, char_t **ptr, char_t *s) static void appendString(char_t **ptr, char_t *s) int ejSetGlobalFunction(int eid, char_t *name, int (*fn)(int eid, void *handle, int argc, char_t **argv)) int ejSetGlobalFunctionDirect(sym_fd_t functions, char_t *name, int (*fn)(int eid, void *handle, int argc, char_t **argv)) int ejRemoveGlobalFunction(int eid, char_t *name) void *ejGetGlobalFunction(int eid, char_t *name) int ejArgs(int argc, char_t **argv, char_t *fmt, ...) void ejSetUserHandle(int eid, void* handle) void* ejGetUserHandle(int eid) int ejGetLineNumber(int eid) void ejSetResult(int eid, char_t *s) char_t *ejGetResult(int eid) void ejSetVar(int eid, char_t *var, char_t *value) void ejSetLocalVar(int eid, char_t *var, char_t *value) void ejSetGlobalVar(int eid, char_t *var, char_t *value) int ejGetVar(int eid, char_t *var, char_t **value) sym_fd_t ejGetVariableTable(int eid) sym_fd_t ejGetFunctionTable(int eid) static void freeFunc(ejfunc_t *func) static ej_t *ejPtr(int eid) static void ejRemoveNewlines(ej_t *ep, int state) 十八十八十八十八、、、、sock.c 、、、、sockGen.c ((((socket 层层层层)))) socket_t 有两个 ring queue ,分别是 inBuf,outBuf ,分别对应输入、输出,在从 socket 读取数 据时,会将读取的数据存放在 inBuf 中,在向 socket 发送数据时,首先将数据存放在 outBuf 中,然后将 outBuf 中的数据发送给 socke 。 int socketWrite(int sid, char *buf, int bufsize) 功能:主要功能是向将要输出到 socket 的数据存放在 outBuf 的队列中,如果队列没有可以 存放的空间,就向 socket 输出,即输出到浏览器端 说明: ----------------------------------------------------------------------------------------------------------------- int socketWriteString(int sid, char_t *buf) 功能:输出一字符串到 socket 说明: ----------------------------------------------------------------------------------------------------------------- int socketRead(int sid, char *buf, int bufsize) 功能:从 socket 接收数据,这些数据首先存放在 inBuf 中,然后再将 inBuf 中数据拷贝到 buf 中 说明: ----------------------------------------------------------------------------------------------------------------- int socketGets(int sid, char_t **buf) 功能:从 socket 获取一个字符串,如果遇到 EOF 或者读取的超过了 2048 ,就会在 lineBuf 中添加换行符,从 socket 读取的字符存放在 lineBuf 中,然后将 lineBuf 中的数据拷贝到 buf 中 说明: ----------------------------------------------------------------------------------------------------------------- int socketFlush(int sid) 功能:将 outBuf 中的数据输出到 socket 中 说明: ----------------------------------------------------------------------------------------------------------------- int socketInputBuffered(int sid) 功能:获取 inBuf 中的字节数 说明: ----------------------------------------------------------------------------------------------------------------- int socketEof(int sid) 功能:判断是否是 eof 说明: ----------------------------------------------------------------------------------------------------------------- int socketCanWrite(int sid) 功能:outBuf 中还有多少空间可以使用,这样就可将输出到 socket 的数据输出到该 outBuf , 然后再将该 outBuf 中的数据输出到 socket 说明: ----------------------------------------------------------------------------------------------------------------- void socketSetBufferSize(int sid, int in, int line, int out) 功能:主要是设置 inBuf,outBuf,lineBuf 的大小 说明: ----------------------------------------------------------------------------------------------------------------- void socketCreateHandler(int sid, int handlerMask, socketHandler_t handler, void* data) 功能:就是添加一个钩子函数,在该 sid 的处于 handlerMask 状态(可读、可写)时,对应的 调用该钩子函数 说明: ----------------------------------------------------------------------------------------------------------------- void socketDeleteHandler(int sid) 功能:删除钩子函数 说明: ----------------------------------------------------------------------------------------------------------------- static int socketDoOutput(socket_t *sp, char *buf, int toWrite, int *errCode) 功能:向 socket 输出数据,输出广播或者 udp 或者 tcp 数据包 说明: ----------------------------------------------------------------------------------------------------------------- static int tryAlternateSendTo(int sock, char *buf, int toWrite, int i,struct sockaddr *server) 功能:发送一个 udp 数据包 说明: ----------------------------------------------------------------------------------------------------------------- int socketAlloc(char *host, int port, socketAccept_t accept, int flags) 功能:分配一个 socket_t 结构 说明: ----------------------------------------------------------------------------------------------------------------- void socketFree(int sid) 功能:释放一个 socket_t 结构,如果 sock 还有调用,则设置为非阻塞模式,然后 shutdown(SHUT_WR), recv(), 最后 close() ,释放内存。这里什么原因,还需学习 说明: ----------------------------------------------------------------------------------------------------------------- socket_t *socketPtr(int sid) 功能:有 sid 获得对应的 socketList[sid] 说明: ----------------------------------------------------------------------------------------------------------------- int socketGetError() 功能:获取 errno 说明: ----------------------------------------------------------------------------------------------------------------- int socketGetHandle(int sid) 功能:获取 socket handle 说明: ----------------------------------------------------------------------------------------------------------------- int socketGetBlock(int sid) 功能:获取是否是阻塞模式 说明: ----------------------------------------------------------------------------------------------------------------- int socketGetMode(int sid) 功能:获取 mode ,没用到 说明: ----------------------------------------------------------------------------------------------------------------- void socketSetMode(int sid, int mode) 功能:设置模式,没用到 说明: ----------------------------------------------------------------------------------------------------------------- int socketGetPort(int sid) 功能:由 sid 获取对应的端口 说明: ----------------------------------------------------------------------------------------------------------------- int socketOpen() 功能:打开 socket module 说明: ----------------------------------------------------------------------------------------------------------------- void socketClose() 功能:关闭 socket module ,关闭 socketList[] 中的所有连接的 socket 说明: ----------------------------------------------------------------------------------------------------------------- int socketOpenConnection(char *host, int port, socketAccept_t accept, int flags) 功能:打开 web 服务器的监听 socket ,设置为 SOCKET_LISTENING,非阻塞模式 说明: ----------------------------------------------------------------------------------------------------------------- static int tryAlternateConnect(int sock, struct sockaddr *sockaddr) 功能:尝试连接一个 socket ,服务器端没用 说明: ----------------------------------------------------------------------------------------------------------------- void socketCloseConnection(int sid) 功能:关闭一个 socket 说明: ----------------------------------------------------------------------------------------------------------------- static void socketAccept(socket_t *sp) 功能:web 服务器监听 socket ,等待接收访问,非阻塞方式 说明: ----------------------------------------------------------------------------------------------------------------- int socketGetInput(int sid, char *buf, int toRead, int *errCode) 功能:从 socket 中读取数据 说明: ----------------------------------------------------------------------------------------------------------------- void socketRegisterInterest(socket_t *sp, int handlerMask) 功能:设置 handlerMask ,可以是 SOCKET_WRITABLE、SOCKET_READABLE 或 0,用于 和事件钩子函数搭配 说明: ----------------------------------------------------------------------------------------------------------------- int socketWaitForEvent(socket_t *sp, int handlerMask, int *errCode) 功能:linux 、vxworks 没有调用该函数 说明: ----------------------------------------------------------------------------------------------------------------- int socketReady(int sid) 功能:判断这个 socket 是否有事件需要处理 说明: ----------------------------------------------------------------------------------------------------------------- int socketSelect(int sid, int timeout) 功能:判断是否有需要处理的事件,首先根据 socketList[] 中的 socket_t 的掩码添加到监控项 中,可读、可写,还是异常,并且设置等待时间,然后设置每个 socket_t 的 currentEvents, 留待函数 socketDoEvent() 处理 说明: ----------------------------------------------------------------------------------------------------------------- void socketProcess(int sid) 功能:在 socketList[] 中查找有发生事件的 socket ,然后进行处理 说明: ----------------------------------------------------------------------------------------------------------------- static int socketDoEvent(socket_t *sp) 功能:处理 socket 可读、可写,然后调用相应的钩子函数 说明: ----------------------------------------------------------------------------------------------------------------- int socketSetBlock(int sid, int on) 功能:设置 socket 的阻塞模式 说明: ----------------------------------------------------------------------------------------------------------------- int socketDontBlock() 功能:查看 socket 中是否有可读的数据 说明: ----------------------------------------------------------------------------------------------------------------- int socketSockBuffered(int sock) 功能:获取 inBuf 中的字节数 说明: ----------------------------------------------------------------------------------------------------------------- 十九十九十九十九、、、、webs.c ((((web 层层层层)))) Web 层主要功能是处理 http 协议,处理 web 服务器业务。可以说是整个 web 服务器的重点。 对于其的详细分析,以后再写。 一个基本认证例子的消息头: 请求。 POST /goform/cfgSdhifRsWeb HTTP/1.1 Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */* Referer: http://192.168.4.28/sdhifrs.asp?slot=0 Accept-Language: zh-cn User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; CIBA; .NET CLR 2.0.50727) Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip, deflate Host: 192.168.4.28 Content-Length: 137 Proxy-Connection: Keep-Alive Pragma: no-cache Authorization: Basic cmFpc2Vjb206cmFpc2Vjb20= portIndex=1&exc=3&sd=6&es=900&ses=900&msais_insert=2&j0_mode=2&j0_transmit=Raisec om-Opcom+&j0_expected=Raisecom-Opcom+&slot=0&apply=Apply 响应。 HTTP/1.0 302 Redirect Server: Webs/2.5.0 Date: THU JAN 01 00:06:48 1970 Pragma: no-cache Cache-Control: no-cache Content-Type: text/html Location: http://192.168.4.28/sdhifrs.asp?slot=0&&portIndex=1 This document has moved to a new location. Please update your documents to reflect the new location. 一个摘要认证例子的消息头: 请求。 POST /goform/cfgSdhifRsWeb HTTP/1.1 Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */* Referer: http://192.168.4.28/sdhifrs.asp?slot=0&&portIndex=1 Accept-Language: zh-cn User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; CIBA; .NET CLR 2.0.50727) Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip, deflate Host: 192.168.4.28 Content-Length: 137 Proxy-Connection: Keep-Alive Pragma: no-cache Authorization: Digest username="123",realm="123",nonce="0fabdfd5b279fadc2f0d9d72ed218c29",uri="/goform/ cfgSdhifRsWeb",cnonce="e5003c43b0ba085d63cd1e92021c6ecc",nc=00000019,algorithm=MD 5,response="a97274a2c9d6e8ccbb7e9200c1bc4e56",qop="auth",opaque="5ccc069c403ebaf9 f0171e9517f40e41" portIndex=1&exc=3&sd=6&es=900&ses=900&msais_insert=2&j0_mode=2&j0_transmit=Raisec om-Opcom+&j0_expected=Raisecom-Opcom+&slot=0&apply=Apply 响应。 HTTP/1.0 302 Redirect Server: Webs/2.5.0 Date: THU JAN 01 00:01:54 1970 Pragma: no-cache Cache-Control: no-cache Content-Type: text/html Location: http://192.168.4.28/sdhifrs.asp?slot=0&&portIndex=1 This document has moved to a new location. Please update your documents to reflect the new location. HTTP Keep-Alive Keep-Alive 功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时, Keep-Alive 功能避免了建立或者重新建立连接。市场上 的大部分Web 服务器,包括 iPlanet 、IIS 和Apache ,都支持HTTP Keep-Alive 。对于提供静态内容的网站来说, 这个功能通常很有用。但是,对于负担较重的网站来说,这里存在另外一个问题:虽然为客 户保留打开的连 接有一定的好处,但它同样影响了性能,因为在处理暂停期间,本来可以 释放的资源仍旧被占用。当Web 服务器和应用服务器在同一台机器上运行时,Keep- Alive 功能对资源利用的影响尤其突出。 此功能为HTTP 1.1 预设的功能,HTTP 1.0 加上 Keep-Alive header 也可以提供HTTP 的持续作用功能。 Keep-Alive: timeout=5, max=100 timeout :过期时间 5 秒(对应 httpd.conf 里的参数是:KeepAliveTimeout ),max 是最多一百次请求,强制断掉连接 就是在 timeout 时间内又有新的连接过来,同时 max 会自动减 1,直到为 0,强制断掉。 If-Modified-Since If-Modified-Since 是标准的HTTP 请求头标签,在发送HTTP 请求时,把浏览器端缓存 页面的最后修改时间一起发到服务器去,服务器会把这个时间与服务器上实际文件的最后修 改时间进行比较。 如果时间一致,那么返回HTTP 状态码304 (不返回文件内容),客户端接到之后,就直接 把本地缓存文件显示到浏览器中。 如果时间不一致,就返回HTTP 状态码200 和新的文件内容,客户端接到之后,会丢弃旧文 件,把新文件缓存起来,并显示到浏览器中。 HTTP 的If-Modified-Since 头标签与客户端缓存相互配合,大大节约了网络流量。 HTTP 的认证模式 Http 协议(RFC 2616 )规定可以采用Base 模式和摘要模式(Digest schema )。RFC 2617 专门对两种认证模式做了规定。RFC 1321 是MD5 标准。Digest 对现代密码破解来 说并不强壮,但比基本模式还是好很多。MD5 已经被山东大学教授找到方法可以仿冒(我的 理解),但现在还在广泛使用。 1. 最简单的攻击方式 如果网站要求认证,客户端发送明文的用户名密码,那网络上的窃听者可以轻而易举的 获得用户名密码,起不到安全作用。我上学时曾在科大实验室局域网内窃听别人的科大BBS 的密码,发现BBS 的用户名密码居然是明文传输的。那种做贼的心虚和做贼的兴奋让人激动 莫名。偷人钱财会受到道德谴责,偷人密码只会暗自得意忘形。比“窃书不算偷”还没有罪 恶感。因此你的用户名和密码明文传输的话,无异将一块肥肉放在嘴馋的人面前。现在很多 ASP 网站的认证都将用户名和密码用MD5 加密。MD5 是将任意长度的字符串和128 位的随机 数字运算后生成一个16byte 的加密字符串。因此窃听者抓住的是一团乱码。但是,这有一 个问题:如果窃听者就用这团乱码去认证,还是可以认证通过。因为服务器将用户名密码 MD5加密后得到的字符串就是那一团乱码,自然不能区别谁是合法用户。这叫重放攻击 (replay attack )。这和HTTP 的基本认证模式差不多。为了安全,不要让别人不劳而 获,自然要做基本的防范。下面是Http 协议规定的两种认证模式。 2. 基本认证模式 客户向服务器发送请求,服务器返回401 (未授权),要求认证。401 消息的头里面带 了挑战信息。realm 用以区分要不同认证的部分。客户端收到401 后,将用户名密码和挑战 信息用BASE64 加密形成证书,发送回服务器认证。语法如下: challenge = "Basic" realm credentials = "Basic" basic-credentials 示例: 认证头: WWW-Authenticate: Basic realm="zhouhh@mydomain.com" 证书:Authorization: Basic QsdfgWGHffuIcaNlc2FtZQ== 3. 摘要访问认证 为了防止重放攻击,采用摘要访问认证。在客户发送请求后,收到一个401 (未授权) 消息,包含一个Challenge 。消息里面有一个唯一的字符串:nonce ,每次请求都不一样。 客户将用户名密码和401 消息返回的挑战一起加密后传给服务器。这样即使有窃听,他也无 法通过每次认证,不能重放攻击。Http 并不是一个安全的协议。其内容都是明文传输。因 此不要指望Http 有多安全。 语法: challenge = "Digest" digest-challenge digest-challenge = 1#( realm | [ domain ] | nonce | [ opaque ] |[ stale ] | [ algorithm ] | [ qop-options ] | [auth-param] ) domain = "domain" "=" <"> URI ( 1*SP URI ) <"> URI = absoluteURI | abs_path nonce = "nonce" "=" nonce-value nonce-value = quoted-string opaque = "opaque" "=" quoted-string stale = "stale" "=" ( "true" | "false" ) algorithm = "algorithm" "=" ( "MD5" | "MD5-sess" | token ) qop-options = "qop" "=" <"> 1#qop-value <"> qop-value = "auth" | "auth-int" | token realm :让客户知道使用哪个用户名和密码的字符串。不同的领域可能密码不一样。至少告 诉用户是什么主机做认证,他可能会提示用哪个用户名登录,类似一个Email 。 domain :一个URI 列表,指示要保护的域。可能是一个列表。提示用户这些URI 采用一样 的认证。如果为空或忽略则为整个服务器。 nonce :随机字符串,每次401 都不一样。跟算法有关。算法类似Base64 加密:time-stamp H(time-stamp ":" ETag ":" private-key) 。time-stamp 为服务器时钟,ETag 为请求的Etag 头。private-key 为服务器知道的一个值。 opaque :服务器产生的由客户下去请求时原样返回。最好是Base64 串或十六进制字符串。 auth-param :为扩展用的,现阶段忽略。 其他域请参考RFC2617 。 授权头语法: credentials = "Digest" digest-response digest-response = 1#( username | realm | nonce | digest-uri | response | [ algorithm ] | [cnonce] | [opaque] | [message-qop] | [nonce-count] | [auth-param] ) username = "username" "=" username-value username-value = quoted-string digest-uri = "uri" "=" digest-uri-value digest-uri-value = request-uri ; As specified by HTTP/1.1 message-qop = "qop" "=" qop-value cnonce = "cnonce" "=" cnonce-value cnonce-value = nonce-value nonce-count = "nc" "=" nc-value nc-value = 8LHEX response = "response" "=" request-digest request-digest = <"> 32LHEX <"> LHEX = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "a" | "b" | "c" | "d" | "e" | "f" response :加密后的密码 digest-uri :拷贝Request-Line ,用于Proxy cnonce :如果qop 设置,才设置,用于双向认证,防止攻击。 nonce-count: 如果服务器看到同样的计数,就是一次重放。 示例: 401 响应: HTTP/1.1 401 Unauthorized WWW-Authenticate: Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41" 再次请求: Authorization: Digest username="Mufasa", realm="testrealm@host.com", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", uri="/dir/index.html", qop=auth, nc=00000001, cnonce="0a4f113b", response="6629fae49393a05397450978507c4ef1", opaque="5ccc069c403ebaf9f0171e9517f40e41" 4. 比较基本认证和摘要访问认证都是很脆弱的。基本认证可以让窃听者直接获得用户名和 密码,而摘要访问认证窃听者只能获得一次请求的文档。 int websOpenServer(int port, int retries) 功能:打开 web 服务器,打开 rom ,创建 mime table ,打开 url 处理模块打开 form 模块,打 开监听 socket 说明: ----------------------------------------------------------------------------------------------------------------- void websCloseServer() 功能:关闭 web 服务器,关闭监听 socket ,关闭已经连接的 socket 说明: ----------------------------------------------------------------------------------------------------------------- int websOpenListen(int port, int retries) 功能:打开监听 socket 说明: ----------------------------------------------------------------------------------------------------------------- void websCloseListen() 功能:关闭监听 socket 说明: ----------------------------------------------------------------------------------------------------------------- int websAccept(int sid, char *ipaddr, int port, int listenSid) 功能:接收一个连接,创建钩子函数 websSocketEvent ,对应于该 socket 可读,设置该 socket 挂起请求的超时处理函数 websTimeout 说明: ----------------------------------------------------------------------------------------------------------------- static void websSocketEvent(int sid, int mask, void* iwp) 功能:响应读写操作 说明: ----------------------------------------------------------------------------------------------------------------- void websReadEvent(webs_t wp) 功能:读操作响应函数,是 web 服务器读取从浏览器发来的数据,读取数据是分阶段的, WEBS_BEGIN、WEBS_HEADER、WEBS_POST_CLEN、WEBS_POST 说明: ----------------------------------------------------------------------------------------------------------------- static int websGetInput(webs_t wp, char_t **ptext, int *pnbytes) 功能:从浏览器获取数据 说明: ----------------------------------------------------------------------------------------------------------------- static int websParseFirst(webs_t wp, char_t *text) 功能:分析 http 请求的第一行 说明: ----------------------------------------------------------------------------------------------------------------- static void websParseRequest(webs_t wp) 功能:分析 head 全部请求 说明: ----------------------------------------------------------------------------------------------------------------- void websSetEnv(webs_t wp) 功能:设置环境变量 说明: ----------------------------------------------------------------------------------------------------------------- void websSetVar(webs_t wp, char_t *var, char_t *value) 功能:设置 web 变量 说明: ----------------------------------------------------------------------------------------------------------------- int websTestVar(webs_t wp, char_t *var) 功能:测试这个 cgi 变量是否存在 说明: ----------------------------------------------------------------------------------------------------------------- char_t *websGetVar(webs_t wp, char_t *var, char_t *defaultGetValue) 功能:获取 web 的变量,主要是 post 的表单数据或 query 数据 说明: ----------------------------------------------------------------------------------------------------------------- int websCompareVar(webs_t wp, char_t *var, char_t *value) 功能:是否这个 web 变量 说明: ----------------------------------------------------------------------------------------------------------------- void websTimeoutCancel(webs_t wp) 功能:超时处理取消函数 说明: ----------------------------------------------------------------------------------------------------------------- void websResponse(webs_t wp, int code, char_t *message, char_t *redirect) 功能:向浏览器输出 web 服务器的响应 说明: ----------------------------------------------------------------------------------------------------------------- void websRedirect(webs_t wp, char_t *url) 功能:web 重定向,定位到另一个页面 说明: ----------------------------------------------------------------------------------------------------------------- static int charCount(const char_t* str, char_t ch) 功能:统计字符 ch 在字符串 str 中出现的次数 说明: ----------------------------------------------------------------------------------------------------------------- static char_t* websSafeUrl(const char_t* url) 功能:主要是将<、>字符转换为< 、> 说明: ----------------------------------------------------------------------------------------------------------------- void websError(webs_t wp, int code, char_t *fmt, ...) 功能:向浏览器输出错误 说明: ----------------------------------------------------------------------------------------------------------------- char_t *websErrorMsg(int code) 功能:根据错误码输出对应的解释性字符 说明: ----------------------------------------------------------------------------------------------------------------- int websWrite(webs_t wp, char_t *fmt, ...) 功能:向浏览器输出字符串 说明: ----------------------------------------------------------------------------------------------------------------- int websWriteBlock(webs_t wp, char_t *buf, int nChars) 功能:向浏览器一段数据 说明: ----------------------------------------------------------------------------------------------------------------- int websWriteDataNonBlock(webs_t wp, char *buf, int nChars) 功能:向浏览器一段数据 说明: ----------------------------------------------------------------------------------------------------------------- void websDecodeUrl(char_t *decoded, char_t *token, int len) 功能:url 解码函数,主要是将+、%xx 等解码成空格、字符 说明: ----------------------------------------------------------------------------------------------------------------- void websTimeout(void *arg, int id) 功能:超时处理函数,如果超时,则释放内存,向浏览器输出结果,如果还未超时,重新启 动定时函数,定时的时间为剩余的时间 说明: ----------------------------------------------------------------------------------------------------------------- void websDone(webs_t wp, int code) 功能:一个请求处理完成的结束函数,向浏览器输出数据,释放内存 说明: ----------------------------------------------------------------------------------------------------------------- int websAlloc(int sid) 功能:分配一个 webs_t 结构 说明: ----------------------------------------------------------------------------------------------------------------- void websFree(webs_t wp) 功能:释放一个 webs_t 结构 说明: ----------------------------------------------------------------------------------------------------------------- char_t *websGetHost() 功能: 说明: ----------------------------------------------------------------------------------------------------------------- char_t *websGetIpaddrUrl() 功能: 说明: ----------------------------------------------------------------------------------------------------------------- char_t *websGetHostUrl() 功能: 说明: ----------------------------------------------------------------------------------------------------------------- int websGetPort() 功能: 说明: ----------------------------------------------------------------------------------------------------------------- int websGetRequestBytes(webs_t wp) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- char_t *websGetRequestDir(webs_t wp) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- int websGetRequestFlags(webs_t wp) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- char_t *websGetRequestIpaddr(webs_t wp) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- char_t *websGetRequestLpath(webs_t wp) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- char_t *websGetRequestPassword(webs_t wp) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- char_t *websGetRequestType(webs_t wp) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- char_t *websGetRequestUserName(webs_t wp) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- int websGetRequestWritten(webs_t wp) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- void websSetHost(char_t *host) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- void websSetHostUrl(char_t *url) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- void websSetIpaddr(char_t *ipaddr) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- void websSetRequestBytes(webs_t wp, int bytes) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- void websSetRequestFlags(webs_t wp, int flags) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- void websSetRequestLpath(webs_t wp, char_t *lpath) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- void websSetRequestPath(webs_t wp, char_t *dir, char_t *path) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- void websSetRequestSocketHandler(webs_t wp, int mask, void (*fn)(webs_t wp)) 功能:设置写处理的 handler 说明: ----------------------------------------------------------------------------------------------------------------- void websSetRequestWritten(webs_t wp, int written) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- int websValid(webs_t wp) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- char_t *websGetDateString(websStatType *sbuf) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- void websSetTimeMark(webs_t wp) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- static int websGetTimeSinceMark(webs_t wp) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- void websSetRealm(char_t *realmName) 功能: 说明: ----------------------------------------------------------------------------------------------------------------- char_t *websGetRealm() 功能: 说明: 二十二十二十二十、、、、websuemf.c 是 web 服务器的定时器模块,负责超时处理。 int scriptEval(int engine, char_t *cmd, char_t **result, void* chan) 功能:嵌入式 javascript 处理函数 说明: ----------------------------------------------------------------------------------------------------------------- int strcmpci(char_t *s1, char_t *s2) 功能:比较两个字符串的大小,忽略大小写 说明: ----------------------------------------------------------------------------------------------------------------- void TimerProc(int schedid) 功能:定时器处理函数,超时处理 说明: ----------------------------------------------------------------------------------------------------------------- int emfSchedCallback(int delay, emfSchedProc *proc, void *arg) 功能:注册一个定时器,添加超时处理函数 说明: ----------------------------------------------------------------------------------------------------------------- void emfReschedCallback(int schedid, int delay) 功能:刷新一下定时的时间 说明: ----------------------------------------------------------------------------------------------------------------- void emfUnschedCallback(int schedid) 功能:释放定时器 说明: ----------------------------------------------------------------------------------------------------------------- void emfSchedProcess() 功能:被 main 函数调用,是个定时器处理程序,判断各个定时器是否超时,超时,则调用 TimerProc 处理 说明: ----------------------------------------------------------------------------------------------------------------- websda.c 、、、、md5c.c 这个有关摘要认证需要加密的函数,省略。 websSLL.c 、、、、matrixSSLSocket.c 这个有关 SSL 的函数,就是安全套接层函数,主要是将网络中传输的数据加密。省略。 服务器主循环分析服务器主循环分析服务器主循环分析服务器主循环分析 socket sp->accept 对应的函数是 websAccpet() socket sp->handler 对应的函数是 websSocketEvent() ,该函数中 对于 SOCKET_READBLE( 读事件),对应的函数为 websReadEvent() , 对于 SOCKET_WRITEABLE(写事件)对应的函数为 websDefaultWriteEvent() 最让人难理解的是 web 服务器主循环 while (!finished) { if (socketReady(-1) || socketSelect(-1, 2000)) /*socketReady(-1) 处 理 已 有的连接 socket ,如果有事件就马上处理,不需要延时 socketSelect(sid, 0) (调用 socketSelect(sid, 0) 的 目的主要是判断这个已经连接的 sid ,是否有新的可读事件发生),优先处理已经连接的 socket 发生过的事件*/ {/*socketSelect(-1, 2000) 处理监听新连接*/ socketProcess(-1); } websCgiCleanup(); emfSchedProcess(); } socketReady(-1) 函数分析 socketReady 函数检查已建立连接的 socket 中是否有以下事件,如果检查到一个,就返 回 1,如果没有检查到,就返回零。 (1) sp->flags & SOCKET_CONNRESET ,如果该 socket 的 flag 标志为 SOCKET_CONNRESET,则调用函数 socketCloseConnection 关闭该 socket 连接,然后返回 0; (2) sp->currentEvents & sp->handlerMask ,如果该 socket 当前的事件和他要处 理的事件相同,就返回 1,告诉调用 socketReady 的函数有 socket 准备好被处理了;(说明: sp->handlerMask 用于表示 select 监听该 socket 的事件,sp->currentEvents 表示 select 监听该 socket 的事件发生后,会对其赋值) (3) sp->handlerMask & SOCKET_READABLE && socketInputBuffered(sid) > 0 , 如果该 socket 要处理的事件是 SOCKET_READABLE 并且该 socket 的缓存中有可读的数据, 则调用 socketSelect 函数(为什么在这里要调用这个函数,看了下 socketSelect ,应该是为了 设置 sp->currentEvents |= SOCKET_READABLE ),然后返回 1,告诉调用 socketReady 的函 数有 socket 准备好被处理了; socketInputBuffered(sid) > 0 说明 socket 中的数据已经拷贝到 queue 的 inBuf 中,但还没 有处理,所以这段程序主要是处理接收缓存中还没有处理的数据(见 socketRead 函数)。 if (sp->handlerMask & SOCKET_READABLE && socketInputBuffered(sid) > 0) { socketSelect(sid, 0); return 1; } 调用 socketSelect(sid, 0) 的目的主要是判断这个已经连接的 sid ,是否有新的可读事件发 生,如果有则设置 sp->currentEvents |= SOCKET_READABLE ,即使没有,也返回 1,这样 会调用 socketProcess(-1) ,在 socketProcess(-1) 里面继续调用 socketReady(sid) ,同样返回为 1, 这样就调用了 socketDoEvent (sp) ,在 socketDoEvent(sp) 中走到 if (sp->handlerMask & SOCKET_READABLE && socketInputBuffered(sid) > 0) { sp->currentEvents |= SOCKET_READABLE; } 这样,sp->currentEvents |= SOCKET_READABLE 。 随后调用 if (sp->handler && (sp->handlerMask & sp->currentEvents)) { (sp->handler)(sid, sp->handlerMask & sp->currentEvents, sp->handler_data); ….. } 这样会调用函数 websReadEvent() websGetInput() socketRead(), 在 socketRead() 中,由于 len = min(ringqLen(rq), bufsize); if (len <= 0) 不成立,就直接调用 memcpy(&buf[bytesRead], rq->servp, len); ringqGetBlkAdj(rq, len); bufsize -= len; bytesRead += len; (4) socketReady 函数根据传入的参数 sid 决定是检查 id 为 sid 的 socket(当 sid 大于 0),还是遍历整个 socketList (当 sid 小于 0),如果以上 3 个条件中没有一个满足, 则返回 0。 socketSelect ( -1, 2000 )函数分析 socketSelect ( -1, 2000 )是主要还是用在有新连接到来的时候,有新连接到来才会使这个 函数返回真。在等待时间内,也处理已经连接 socket 的读写事件。 1.监听 socket 在 socketOpenConnection() 设置为 sp->handleMask |= SOCKET_READBLE 2.accept() 之后,调用 websAccept(), 在里面利用 socketCreateHandler() 设置这个 accept 后的 socket 为 sp->handleMask = SOCKET_READBLE 3 . . 在 初 始 化 initWebs() , 定 义 钩 子 函 数 websDefaultHandler() , 在 该 函 数 中 , websSetRequestSocketHandler() 中 , 调 用 了 socketCreateHandler() , 定 义 sp->handleMask=SOCKET_WRITEABLE, 也 就 是 说 在 处 理 url 请 求 时 , 才 会 sp->handleMask=SOCKET_WRITEABLE 综上,socketSelect() 函数处理监听 socket ,监听是否有新的连接,同时监听已经连接的 socket , 只有在 accept 之后,socket 变成了已连接,socketSelect() 才会监听这些端口 socketProcess(-1) 函数分析 socketProcess 处理到达的 socket 事件,如果传入的参数是小于 0,则会处理所有的 socket 的事件,如果大于 0,则会处理指定的 socket 的事件。下面是主要过程: if (socketReady(sid)) { socketDoEvent(sp); } socketReady(int sid) 函数中,是 sp->currentEvents ,sp->handlerMask 这几个标志位来判 断是否有数据读写。socketDoEvent() 是对已连接的 socket ,通过改变 sp->currentEvents 和 sp->handlerMask 来分阶段的去处理数据, socketDoEvent() 中调用的 sp->handler() 为读写处理函数。 对于 SOCKET_READBLE( 读事件),websReadEvent() , 对于 SOCKET_WRITEABLE(写事件)websDefaultWriteEvent() int socketReady(int sid) { socket_t *sp; int all; all = 0; if (sid < 0) { sid = 0; all = 1; } for (; sid < socketMax; sid++) { if ((sp = socketList[sid]) == NULL) { if (! all) { break; } else { continue; } } if (sp->flags & SOCKET_CONNRESET) { socketCloseConnection(sid); return 0; } if (sp->currentEvents & sp->handlerMask) { return 1; } /* * If there is input data, also call select to test for new events */ if (sp->handlerMask & SOCKET_READABLE && socketInputBuffered(sid) > 0) { socketSelect(sid, 0); return 1; } if (! all) { break; } } return 0; } int socketSelect(int sid, int timeout) { socket_t *sp; struct timeval tv; fd_mask *readFds, *writeFds, *exceptFds; int all, len, nwords, index, bit, nEvents; /* * Allocate and zero the select masks */ nwords = (socketHighestFd + NFDBITS) / NFDBITS; len = nwords * sizeof(fd_mask); /*printf("len:%d\r\n", len);*/ readFds = balloc(B_L, len); memset(readFds, 0, len); writeFds = balloc(B_L, len); memset(writeFds, 0, len); exceptFds = balloc(B_L, len); memset(exceptFds, 0, len); tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; /* * Set the select event masks for events to watch */ all = nEvents = 0; if (sid < 0) { all++; sid = 0; } for (; sid < socketMax; sid++) { if ((sp = socketList[sid]) == NULL) { if (all == 0) { break; } else { continue; } } a_assert(sp); /* * Initialize the ready masks and compute the mask offsets. */ index = sp->sock / (NBBY * sizeof(fd_mask)); bit = 1 << (sp->sock % (NBBY * sizeof(fd_mask))); /* * Set the appropriate bit in the ready masks for the sp->sock. */ if (sp->handlerMask & SOCKET_READABLE) { readFds[index] |= bit; nEvents++; if (socketInputBuffered(sid) > 0) { tv.tv_sec = 0; tv.tv_usec = 0; } } if (sp->handlerMask & SOCKET_WRITABLE) { writeFds[index] |= bit; nEvents++; } if (sp->handlerMask & SOCKET_EXCEPTION) { exceptFds[index] |= bit; nEvents++; } if (! all) { break; } } /* * Wait for the event or a timeout. Reset nEvents to be the number of actual * events now. */ nEvents = select(socketHighestFd + 1, (fd_set *) readFds, (fd_set *) writeFds, (fd_set *) exceptFds, &tv); if (nEvents > 0) { if (all) { sid = 0; } for (; sid < socketMax; sid++) { if ((sp = socketList[sid]) == NULL) { if (all == 0) { break; } else { continue; } } index = sp->sock / (NBBY * sizeof(fd_mask)); bit = 1 << (sp->sock % (NBBY * sizeof(fd_mask))); if (readFds[index] & bit || socketInputBuffered(sid) > 0) { sp->currentEvents |= SOCKET_READABLE; } if (writeFds[index] & bit) { sp->currentEvents |= SOCKET_WRITABLE; } if (exceptFds[index] & bit) { sp->currentEvents |= SOCKET_EXCEPTION; } if (! all) { break; } } } /*add */ if (nEvents<0) { nEvents = 0; } bfree(B_L, readFds); bfree(B_L, writeFds); bfree(B_L, exceptFds); return nEvents; } void socketProcess(int sid) { socket_t *sp; int all; all = 0; if (sid < 0) { all = 1; sid = 0; } /* * Process each socket */ for (; sid < socketMax; sid++) { if ((sp = socketList[sid]) == NULL) { if (! all) { break; } else { continue; } } if (socketReady(sid)) { socketDoEvent(sp); } if (! all) { break; } } } static int socketDoEvent(socket_t *sp) { ringq_t *rq; int sid; a_assert(sp); sid = sp->sid; if (sp->currentEvents & SOCKET_READABLE) { if (sp->flags & SOCKET_LISTENING) { socketAccept(sp); sp->currentEvents = 0; return 1; } } else { /* * If there is still read data in the buffers, trigger the read handler * NOTE: this may busy spin if the read handler doesn't read the data */ if (sp->handlerMask & SOCKET_READABLE && socketInputBuffered(sid) > 0) { sp->currentEvents |= SOCKET_READABLE; } } /* * If now writable and flushing in the background, continue flushing */ if (sp->currentEvents & SOCKET_WRITABLE) { if (sp->flags & SOCKET_FLUSHING) { rq = &sp->outBuf; if (ringqLen(rq) > 0) { socketFlush(sp->sid); } else { sp->flags &= ~SOCKET_FLUSHING; } } } /* * Now invoke the users socket handler. NOTE: the handler may delete the * socket, so we must be very careful after calling the handler. */ if (sp->handler && (sp->handlerMask & sp->currentEvents)) { (sp->handler)(sid, sp->handlerMask & sp->currentEvents, sp->handler_data); /* * Make sure socket pointer is still valid, then reset the currentEvents. */ if (socketList && sid < socketMax && socketList[sid] == sp) { sp->currentEvents = 0; } } return 1; }

下载文档,方便阅读与编辑

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 8 金币 [ 分享文档获得金币 ] 0 人已下载

下载文档

相关文档