程序员眼中的qmail(qmail源代码分析)//FMT_ULONG 40 /* enough space to hold 2^128 - 1 in decimal, plus \0 */ char unique[FMT_ULONG + FMT_ULONG + 3]; char *hostname; stralloc username = {0}; int seenuser = 0; char **childargs; substdio ssup; char upbuf[128]; void doanddie(user,userlen,pass) char *user; unsigned int userlen; /* including 0 byte */ char *pass; { int child; int wstat; int pi[2]; if (fd_copy(2,1) == -1) die_pipe();//关闭出错(fd2),将标准输出(fd1),定向到标准出错(fd2) close(3); if (pipe(pi) == -1) die_pipe(); if (pi[0] != 3) die_pipe(); //确保向子进程能够读到硬编码的fd 3 switch(child = fork()) { //建立子进程执行subprogram给出的程式,一般是一个检验用户名和密码的程式 case -1: die_fork(); case 0: close(pi[1]); sig_pipedefault();//子进程执行checkpassword或vchkpw之类的程式,检验密码,如果认证通过 execvp(*childargs,childargs);//这些再调用qmail-pop3d _exit(1); } //父进程向子进程的fd3传送用户名及密码,这是一个约定。如果你要写自已的检验密码的程式,记得 //从fd3读密码哦。 close(pi[0]); substdio_fdbuf(&ssup,write,pi[1],upbuf,sizeof upbuf); if (substdio_put(&ssup,user,userlen) == -1) die_write(); if (substdio_put(&ssup,pass,str_len(pass) + 1) == -1) die_write(); //父进程向子进程传送<进程ID.当前时间@主机名> if (substdio_puts(&ssup,"<") == -1) die_write(); if (substdio_puts(&ssup,unique) == -1) die_write(); if (substdio_puts(&ssup,hostname) == -1) die_write(); if (substdio_put(&ssup,">",2) == -1) die_write(); if (substdio_flush(&ssup) == -1) die_write(); close(pi[1]); //清除密码及用户名缓冲区 byte_zero(pass,str_len(pass)); byte_zero(upbuf,sizeof upbuf); if (wait_pid(&wstat,child) == -1) die();//等待子进程结束 if (wait_crashed(wstat)) die_childcrashed(); if (wait_exitcode(wstat)) die_badauth(); //完成一次pop3对话退出 die(); } //显示欢迎信息 void pop3_greet() { char *s; s = unique; s += fmt_uint(s,getpid()); *s++ = '.'; s += fmt_ulong(s,(unsigned long) now()); *s++ = '@'; *s++ = 0; puts("+OK <"); puts(unique); puts(hostname); puts(">\r\n"); flush(); } //设置标志,初始化用户名变量 void pop3_user(arg) char *arg; { if (!*arg) { err_syntax(); return; } okay(); seenuser = 1; //user命令已经执行的标志 if (!stralloc_copys(&username,arg)) die_nomem(); //将参数存入username if (!stralloc_0(&username)) die_nomem(); } void pop3_pass(arg) char *arg; { if (!seenuser) { err_wantuser(); return; }//如果没有执行user命令,返回 if (!*arg) { err_syntax(); return; } doanddie(username.s,username.len,arg);//调用子进程验正密码并等待它完成 } void pop3_apop(arg) char *arg;//用户名及密码在一个命令中给出的情况,见user,pass { char *space; space = arg + str_chr(arg,' '); if (!*space) { err_syntax(); return; } *space++ = 0; doanddie(arg,space - arg,space); } struct commands pop3commands[] = {//命令及相应的处理函数表 { "user", pop3_user, 0 } , { "pass", pop3_pass, 0 } , { "apop", pop3_apop, 0 } , { "quit", pop3_quit, 0 } , { "noop", okay, 0 } , { 0, err_authoriz, 0 } } ; void main(argc,argv) int argc; char **argv; { sig_alarmcatch(die);//捕获sigalrm信号 sig_pipeignore();//忽略pipe信号 hostname = argv[1]; //hostname 指向 程式的第一个参数 if (!hostname) die_usage(); childargs = argv + 2; if (!*childargs) die_usage(); pop3_greet();//显示欢迎信息后进入命令循环,等待用户命令 commands(&ssin,pop3commands); die(); } qmail-start.c 分析 Programmer:夜未眠 Comefrom:ChongQing Gearbox co.,ltd qmail-start 是很简单的一个程式,他完成qmail-send,qmail-clean,qmail-lspawn,qmail-rspawn,splogger的启动,并通过管道将他们联系在一起,当然不是网状连接.具体如下 代码: ===================================== 上一篇:使用 Flex 和 Bison 更好地进行错误处理 下一篇:GNU 线性编程工具包(线性优化简介) 更多相关文章
|
推荐文章
精彩文章
|