Chinaunix首页 | 论坛 | 博客
  • 博客访问: 363529
  • 博文数量: 105
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 826
  • 用 户 组: 普通用户
  • 注册时间: 2013-02-16 13:58
个人简介

记录有意义的东西

文章分类

全部博文(105)

文章存档

2013年(105)

我的朋友

分类: C/C++

2013-04-18 20:03:20

http://blog.csdn.net/jemofh159/article/details/7913120

  1. 1  boa.c  
  2.   
  3. 主程序:  
  4.   
  5. ----1)  关闭文件     
  6. for(i=3;i<=1024;i++)    
  7.       close(i);  
  8.   
  9. ----2)  设置进程权限掩码   
  10. umask(~0600);    rw- --- ---;  
  11.   
  12. ----3)  打开黑洞,并将标准输入输出指向它,    
  13. open("/dev/null", 0);  
  14. dup2(devnullfd, STDIN_FILENO);  
  15. dup2(devnullfd, STDOUT_FILENO);  
  16.   
  17.  ----4)  更新时间戳,日志要用到。  
  18. time(¤t_time);  
  19.   
  20. ----5)解析命令行  
  21. -f  
  22. server_root = strdup(optaarg);  
  23. -r    
  24. chdir(optarg);     
  25. chroot(optarg);  
  26. chdir("/");  
  27. -d   
  28. do_fork=0;  
  29.   
  30. ----6)//确保服务器根目录是有效的。  
  31. fixup_server_root();  
  32.   
  33. ----7)//读取配置文件通过yyparse 确保必要的变量设置正确。  
  34. read_config_files();  
  35.   
  36. ----8)//打开access log,error log, [cgi log] ;并设置 close-on-exec为真,即在exec调用后,关闭文件描述符。  
  37. open_logs();  
  38.   
  39. ----9)//创建TCP socket,设置为nonblock ,同样设置 close-on-exec为真,这样,EXEC调用时,cgi不能向它写入。。。  
  40. server_s = create_server_socket();    //打开了地址复用功能 详见 unix网络编程。  
  41.   
  42. ---10)//指定各信号的handle  
  43. init_signals();  
  44.   
  45. ---11)//设置用户ID和进程组ID。  
  46. drop_privs();//降 特权  
  47.   
  48. ---12) Set up the environment variables that are common to all CGI scripts  
  49.  create_common_env();  
  50.   
  51. ---13)  fork子进程,父进程退出。之后子进程成为守护进程  
  52. if(do_fork)   switch(fork())  
  53.   
  54. ---14) 得到PID,用于产生独一无二的临时文件名或路径。  
  55. int pid = getpid();  
  56.   
  57. ---15)  更新时间戳,然后进入主循环。  
  58. timestamp();  
  59. select_loop(server_s)  
  60. {  
  61.   1)清空,block_read_fdset、block_write_fdset;  
  62.   2)设置server_s和请求超时时间。  
  63.   3)进入while(1)  
  64.   {  
  65.      1)   处理sighup 、  sigchld 、 sigalrm、 sigterm等信号。  
  66.       2)重设max_fd = -1;  
  67.      3)   将合适的request从block链表里移到ready链表里。  
  68.            if(reques_block)     fdset_update(); //  
  69.   
  70.      4)  process_requests(server_s);  
  71.   
  72.      5)  if (!sigterm_flag && total_connections < (max_connections - 10))          BOA_FD_SET(server_s, &block_read_fdset); /* server always set */  
  73.   
  74.     6)   reset  timeout  
  75.   
  76.      7)   select 调 用,select(max_fd + 1, &block_read_fdset, &block_write_fdset, NULL, (request_ready || request_block ? &req_timeout : NULL))  
  77.   
  78.     8)更新当前时间,time(&curent_time);  
  79.     9)  if (FD_ISSET(server_s, &block_read_fdset))   pending_requests = 1;  
  80.   
  81.   }  
  82.   
  83. }  


 一、先来看看 fdset_update()

boa里边有三个请求链表

request *request_ready = NULL;  /* ready list head */
request *request_block = NULL;   /* blocked list head */
request *request_free = NULL;      /* free list head */

  1. struct request {                /* pending requests */  
  2.     int fd;                     /* client's socket fd */  
  3.     int status;                 /* see #defines.h */  
  4.     time_t time_last;           /* time of last succ. op. */  
  5.     char *pathname;             /* pathname of requested file */  
  6.     int simple;                 /* simple request? */  
  7.     int keepalive;              /* keepalive status */  
  8.     int kacount;                /* keepalive count */  
  9.   
  10.     int data_fd;                /* fd of data */  
  11.     unsigned long filesize;     /* filesize */  
  12.     unsigned long filepos;      /* position in file */  
  13.     char *data_mem;             /* mmapped/malloced char array */  
  14.     int method;                 /* M_GET, M_POST, etc. */  
  15.   
  16.     char *logline;              /* line to log file */  
  17.   
  18.     char *header_line;          /* beginning of un or incompletely processed header line */  
  19.     char *header_end;           /* last known end of header, or end of processed data */  
  20.     int parse_pos;              /* how much have we parsed */  
  21.     int client_stream_pos;      /* how much have we read... */  
  22.   
  23.     int buffer_start;           /* where the buffer starts */  
  24.     int buffer_end;             /* where the buffer ends */  
  25.   
  26.     char *http_version;         /* HTTP/?.? of req */  
  27.     int response_status;        /* R_NOT_FOUND etc. */  
  28.   
  29.     char *if_modified_since;    /* If-Modified-Since */  
  30.     time_t last_modified;       /* Last-modified: */  
  31.   
  32.     char local_ip_addr[NI_MAXHOST]; /* for virtualhost */  
  33.   
  34.     /* CGI vars */  
  35.   
  36.     int remote_port;            /* could be used for ident */  
  37.   
  38.     char remote_ip_addr[NI_MAXHOST]; /* after inet_ntoa */  
  39.   
  40.     int is_cgi;                 /* true if CGI/NPH */  
  41.     int cgi_status;  
  42.     int cgi_env_index;          /* index into array */  
  43.   
  44.     /* Agent and referer for logfiles */  
  45.     char *header_user_agent;  
  46.     char *header_referer;  
  47.   
  48.     int post_data_fd;           /* fd for post data tmpfile */  
  49.   
  50.     char *path_info;            /* env variable */  
  51.     char *path_translated;      /* env variable */  
  52.     char *script_name;          /* env variable */  
  53.     char *query_string;         /* env variable */  
  54.     char *content_type;         /* env variable */  
  55.     char *content_length;       /* env variable */  
  56.   
  57.     struct mmap_entry *mmap_entry_var;  
  58.   
  59.     struct request *next;       /* next */  
  60.     struct request *prev;       /* previous */  
  61.   
  62.     /* everything below this line is kept regardless */  
  63.     char buffer[BUFFER_SIZE + 1]; /* generic I/O buffer */  
  64.     char request_uri[MAX_HEADER_LENGTH + 1]; /* uri */  
  65.     char client_stream[CLIENT_STREAM_SIZE]; /* data from client - fit or be hosed */  
  66.     char *cgi_env[CGI_ENV_MAX + 4];             /* CGI environment */  
  67.   
  68. #ifdef ACCEPT_ON  
  69.     char accept[MAX_ACCEPT_LENGTH]; /* Accept: fields */  
  70. #endif  
  71. };  
  72.   
  73. typedef struct request request;  


 

  1. static void fdset_update(void)  
  2. {  
  3.     request *current, *next;  
  4.   
  5.     for (current = request_block; current; current = next)  
  6.     {  
  7.         time_t time_since = current_time - current->time_last;  
  8.         next = current->next;  
  9.           
  10.         /* hmm, what if we are in "the middle" of a request and not 
  11.          * just waiting for a new one... perhaps check to see if anything 
  12.          * has been read via header position, etc... */  
  13.         if (current->kacount < ka_max && /* we *are* in a keepalive */  
  14.         (time_since >= ka_timeout) && /* ka timeout */  
  15.         !current->logline) /* haven't read anything yet */  
  16.             current->status = DEAD; /* connection keepalive timed out */  
  17.         else if (time_since > REQUEST_TIMEOUT)  
  18.         {  
  19.             log_error_doc(current);  
  20.             fputs("connection timed out\n", stderr);  
  21.             current->status = DEAD;  
  22.         }  
  23.         if (current->buffer_end && current->status < DEAD)  
  24.         {  
  25.             if (FD_ISSET(current->fd, &block_write_fdset))  
  26.                 ready_request(current);  
  27.             else  
  28.             {  
  29.                 BOA_FD_SET(current->fd, &block_write_fdset);  
  30.             }  
  31.         } else  
  32.         {  
  33.             switch (current->status)  
  34.             {  
  35.             case WRITE:  
  36.             case PIPE_WRITE:  
  37.                 if (FD_ISSET(current->fd, &block_write_fdset))  
  38.                     ready_request(current);  
  39.                 else  
  40.                 {  
  41.                     BOA_FD_SET(current->fd, &block_write_fdset);  
  42.                 }  
  43.                 break;  
  44.             case BODY_WRITE:  
  45.                 if (FD_ISSET(current->post_data_fd, &block_write_fdset))  
  46.                     ready_request(current);  
  47.                 else  
  48.                 {  
  49.                     BOA_FD_SET(current->post_data_fd, &block_write_fdset);  
  50.                 }  
  51.                 break;  
  52.             case PIPE_READ:  
  53.                 if (FD_ISSET(current->data_fd, &block_read_fdset))  
  54.                     ready_request(current);  
  55.                 else  
  56.                 {  
  57.                     BOA_FD_SET(current->data_fd, &block_read_fdset);  
  58.                 }  
  59.                 break;  
  60.             case DONE:  
  61.                 if (FD_ISSET(current->fd, &block_write_fdset))  
  62.                     ready_request(current);  
  63.                 else  
  64.                 {  
  65.                     BOA_FD_SET(current->fd, &block_write_fdset);  
  66.                 }  
  67.                 break;  
  68.             case DEAD:  
  69.                 ready_request(current);  
  70.                 break;  
  71.             default:  
  72.                 if (FD_ISSET(current->fd, &block_read_fdset))  
  73.                     ready_request(current);  
  74.                 else  
  75.                 {  
  76.                     BOA_FD_SET(current->fd, &block_read_fdset);  
  77.                 }  
  78.                 break;  
  79.             }  
  80.         }  
  81.         current = next;  
  82.     }  
  83. }  


for循环里面,

首先,获取time_since为距离上次成功操作经历的时间。

如果请求出于keepalive中,time_since已经大于ka_timeout(配置文件里可以配置),而且还没有读取到任何东西,那么request的status变为DEAD。

如果time_since大于REQUEST_TIMEOUT(60),那么status变为DEAD。

如果缓冲区有数据,而且status小于DEAD:

        如果不在block_write_fdset里,那么放到block_write_fdset里。

        如果fd已经在block_write_fdset里,调用ready_request,将request从block队列里转移到ready队列里,同时清除block_write_fdset里的标志

ready_request函数的功能是根据status,从fdset中清除对应fd。

其他情况:

        状态为WRITE,PIPE_WRITE,DONE的请求,如果没有那就放到block_write_fdset里,如果已经在了就调用ready_request。

        状态为BODY_WRITE,将request的post_data_fd做以上处理。post_data_fd注释为/* fd for post data tmpfile */,应该是客户端POST方法时的临时文件        

        状态为PIPE_READ,将request的data_fd做类似处理,不过检查的是block_read_fdset。

        状态为DEAD,直接调用ready_request。

        其他的,检查fd是否在block_read_fdset,并作相应处理。

 

 二、再看看process_erquests函数。

  1. void process_requests(int server_s)  
  2. {  
  3.     int retval = 0;  
  4.     request *current, *trailer;  
  5.   
  6.     if (pending_requests) {  
  7.         get_request(server_s);  
  8. #ifdef ORIGINAL_BEHAVIOR  
  9.         pending_requests = 0;  
  10. #endif  
  11.     }  
  12.   
  13.     current = request_ready;  
  14.   
  15.     while (current) {  
  16.         time(¤t_time);  
  17.         if (current->buffer_end && /* there is data in the buffer */  
  18.             current->status != DEAD && current->status != DONE) {  
  19.             retval = req_flush(current);  
  20.             /* 
  21.              * retval can be -2=error, -1=blocked, or bytes left 
  22.              */  
  23.             if (retval == -2) { /* error */  
  24.                 current->status = DEAD;  
  25.                 retval = 0;  
  26.             } else if (retval >= 0) {  
  27.                 /* notice the >= which is different from below? 
  28.                    Here, we may just be flushing headers. 
  29.                    We don't want to return 0 because we are not DONE 
  30.                    or DEAD */  
  31.   
  32.                 retval = 1;  
  33.             }  
  34.         } else {  
  35.             switch (current->status) {  
  36.             case READ_HEADER:  
  37.             case ONE_CR:  
  38.             case ONE_LF:  
  39.             case TWO_CR:  
  40.                 retval = read_header(current);  
  41.                 break;  
  42.             case BODY_READ:  
  43.                 retval = read_body(current);  
  44.                 break;  
  45.             case BODY_WRITE:  
  46.                 retval = write_body(current);  
  47.                 break;  
  48.             case WRITE:  
  49.                 retval = process_get(current);  
  50.                 break;  
  51.             case PIPE_READ:  
  52.                 retval = read_from_pipe(current);  
  53.                 break;  
  54.             case PIPE_WRITE:  
  55.                 retval = write_from_pipe(current);  
  56.                 break;  
  57.             case DONE:  
  58.                 /* a non-status that will terminate the request */  
  59.                 retval = req_flush(current);  
  60.                 /* 
  61.                  * retval can be -2=error, -1=blocked, or bytes left 
  62.                  */  
  63.                 if (retval == -2) { /* error */  
  64.                     current->status = DEAD;  
  65.                     retval = 0;  
  66.                 } else if (retval > 0) {  
  67.                     retval = 1;  
  68.                 }  
  69.                 break;  
  70.             case DEAD:  
  71.                 retval = 0;  
  72.                 current->buffer_end = 0;  
  73.                 SQUASH_KA(current);  
  74.                 break;  
  75.             default:  
  76.                 retval = 0;  
  77.                 fprintf(stderr, "Unknown status (%d), "  
  78.                         "closing!\n", current->status);  
  79.                 current->status = DEAD;  
  80.                 break;  
  81.             }  
  82.   
  83.         }  
  84.   
  85.         if (sigterm_flag)  
  86.             SQUASH_KA(current);  
  87.   
  88.         /* we put this here instead of after the switch so that 
  89.          * if we are on the last request, and get_request is successful, 
  90.          * current->next is valid! 
  91.          */  
  92.         if (pending_requests)  
  93.             get_request(server_s);  
  94.   
  95.         switch (retval) {  
  96.         case -1:               /* request blocked */  
  97.             trailer = current;  
  98.             current = current->next;  
  99.             block_request(trailer);  
  100.             break;  
  101.         case 0:                /* request complete */  
  102.             current->time_last = current_time;  
  103.             trailer = current;  
  104.             current = current->next;  
  105.             free_request(&request_ready, trailer);  
  106.             break;  
  107.         case 1:                /* more to do */  
  108.             current->time_last = current_time;  
  109.             current = current->next;  
  110.             break;  
  111.         default:  
  112.             log_error_time();  
  113.             fprintf(stderr, "Unknown retval in process.c - "  
  114.                     "Status: %d, retval: %d\n", current->status, retval);  
  115.             current = current->next;  
  116.             break;  
  117.         }  
  118.     }  
  119. }  

 

对于每一个ready queue里的请求遍历处理,返回值-1表示需要进入block queue;返回值0表示请求结束;返回值1表示还要在ready queue里,需进一步处理。

首先检查是否有pending_requests,如果有调用get_request(server_s);,接受一个connection,加入ready_queue。

get_request(server_s);大体功能是,接受一个请求,并做一些简单的初始化,加入ready_queue。

然后开始轮询ready链表:

如果有数据要写,状态不是DEAD或DONE,就调用req_flush(current)。

每一轮最后检查一次,是否还有pending_requests。有的话加入ready_queue。


阅读(2088) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~