2016-12-13 62 views
0

予編譯使用如何處理由套接字服務器中的select()引起的「錯誤文件描述符」?

all: 
    gcc server.c -o server 
    gcc file_reader.c -o file_reader 

我的程序編譯後總輸入 「./server [port_num]」 在終端中。

初始化服務器後,我可以在這樣的瀏覽器中鍵入了一句:「http://127.0.0.1:[port_num]/cgi_program?filename=[filename]

然後我的CGI(file_reader)將正確轉儲命名爲「名」,以I型瀏覽器中的文件的內容。

我將所有的代碼發佈在這裏,很抱歉,由於有很多函數需要調用,因此可以跳過並假設以下功能是正確的。

問題仍然存在:錯誤消息「select:Bad file descriptor」,只能從一個人讀取。

#include <unistd.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <errno.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <netdb.h> 
#include <fcntl.h> 

#define TIMEOUT_SEC 5  // timeout in seconds for wait for a connection 
#define MAXBUFSIZE 1024 // timeout in seconds for wait for a connection 
#define NO_USE  0  // status of a http request 
#define ERROR  -1 
#define READING  1 
#define WRITING  2 
#define ERR_EXIT(a) { perror(a); exit(1); } 

typedef struct { 
    char hostname[512];  // hostname 
    unsigned short port; // port to listen 
    int listen_fd;   // fd to wait for a new connection 
} http_server; 

typedef struct { 
    int conn_fd;    // fd to talk with client 
    int status;    // not used, error, reading (from client), writing (to client) 

    char file[MAXBUFSIZE];  // requested file 
    char query[MAXBUFSIZE]; // requested query 
    char host[MAXBUFSIZE];  // client host 
    char* buf;     // data sent by/to client 
    size_t buf_len;   // bytes used by buf 
    size_t buf_size;   // bytes allocated for buf 
    size_t buf_idx;   // offset for reading and writing 
} http_request; 

static char* logfilenameP; // log file name 

static void init_http_server(http_server *svrP, unsigned short port); // initailize a http_request instance, exit for error 
static void init_request(http_request* reqP);       // initailize a http_request instance 
static void free_request(http_request* reqP);       // free resources used by a http_request instance 
static int read_header_and_file(http_request* reqP, int *errP); 
// return 0: success, file is buffered in retP->buf with retP->buf_len bytes 
// return -1: error, check error code (*errP) 
// return 1: continue to it until return -1 or 0 
// error code: 
// 1: client connection error 
// 2: bad request, cannot parse request 
// 3: method not implemented 
// 4: illegal filename 
// 5: illegal query 
// 6: file not found 
// 7: file is protected 

static void set_ndelay(int fd); 
// Set NDELAY mode on a socket. 

int main(int argc, char **argv) { 
    http_server server;   // http server 
    http_request* requestP = NULL; // pointer to http requests from client 

    int maxfd;      // size of open file descriptor table 

    struct sockaddr_in cliaddr; // used by accept() 
    int clilen; 

    int conn_fd;  // fd for a new connection with client 
    int err;   // used by read_header_and_file() 
    int i, ret, nwritten; 

    // Initialize http server 
    init_http_server(&server, (unsigned short) atoi(argv[1])); 

    maxfd = getdtablesize(); 
    requestP = (http_request*) malloc(sizeof(http_request) * maxfd); 
    if (requestP == (http_request*) 0) { 
     fprintf(stderr, "out of memory allocating all http requests\n"); 
     exit(1); 
    } 
    for (i = 0; i < maxfd; i ++) 
     init_request(&requestP[i]); 
    requestP[server.listen_fd].conn_fd = server.listen_fd; 
    requestP[server.listen_fd].status = READING; 

    fprintf(stderr, "\nstarting on %.80s, port %d, fd %d, maxconn %d, logfile %s...\n", server.hostname, server.port, server.listen_fd, maxfd, logfilenameP); 

    fd_set master;   /* master file descriptor list */ 
    fd_set read_fds;  /* temp file descriptor list for select() */ 
    FD_SET(server.listen_fd, &master); 

    int fdmax = server.listen_fd; 
    while (1) {        /* Main loop */ 
     read_fds = master; 

     if (select(fdmax + 1, &read_fds, NULL, NULL, NULL) == -1) 
      ERR_EXIT("select") 
      printf("server select() is OK!\n"); 

     for (i = 0; i < fdmax + 1; i++) { 
      if (FD_ISSET(i, &read_fds)) { 
       if (i == server.listen_fd) { 
        clilen = sizeof(cliaddr); 
        conn_fd = accept(server.listen_fd, (struct sockaddr *) &cliaddr, (socklen_t *) &clilen); 
        if (conn_fd < 0) { 
         if (errno == EINTR || errno == EAGAIN) continue; // try again 
         if (errno == ENFILE) { 
          (void) fprintf(stderr, "out of file descriptor table ... (maxconn %d)\n", maxfd); 
          continue; 
         } 
         ERR_EXIT("accept") 
        } 
        requestP[conn_fd].conn_fd = conn_fd; 
        requestP[conn_fd].status = READING; 
        strcpy(requestP[conn_fd].host, inet_ntoa(cliaddr.sin_addr)); 
        set_ndelay(conn_fd); 
        FD_SET(conn_fd, &master); 
        if (conn_fd > fdmax) 
         fdmax = conn_fd; 
        fprintf(stderr, "getting a new request... fd %d from %s\n", conn_fd, requestP[conn_fd].host); 
       } 
       else {  /* Handle data from a client */ 
        ret = read_header_and_file(&requestP[i], &err); 
        if (ret == 1) continue; 
        else if (ret < 0) { 
         fprintf(stderr, "error on fd %d, code %d\n", requestP[i].conn_fd, err); 
         requestP[i].status = ERROR; 
         close(requestP[i].conn_fd); 
         free_request(&requestP[i]); 
         break; 
        } 
        else if (ret == 0) { 
         fprintf(stderr, "writing (buf %s, idx %d) %d bytes to request fd %d\n", requestP[conn_fd].buf, (int) requestP[conn_fd].buf_idx, (int) requestP[conn_fd].buf_len, requestP[conn_fd].conn_fd); 
         nwritten = write(requestP[conn_fd].conn_fd, requestP[conn_fd].buf, requestP[conn_fd].buf_len); 
         fprintf(stderr, "complete writing %d bytes on fd %d\n", nwritten, requestP[conn_fd].conn_fd); 
         fprintf(stderr, "=============================================\n"); 

         // char *m = strchr(requestP[conn_fd].query, '=') + 1; 
         // char *filename = strncpy(requestP[conn_fd].query, m, sizeof(requestP[conn_fd].query)); 

         int fd[2]; 
         if (pipe(fd) == -1) 
          ERR_EXIT("pipe") 

          pid_t pid; 
         if ((pid = fork()) < 0) { 
          ERR_EXIT("fork") 
         } 
         else if (pid == 0) {  /* In Child Process */ 
          close(fd[0]); 
          dup2(fd[1], STDOUT_FILENO); 
          close(fd[1]); 

          execl("file_reader", "./file_reader", requestP[i].query, (char *)0); 
          fprintf(stderr, "Error: Unexpect flow of control.\n"); 
          exit(EXIT_FAILURE); 
         } 
         else {  /* In Parent Process */ 
          close(fd[1]); 
          char recv[1024]; 
          read(fd[0], recv, sizeof(recv)); 
          printf("The file content is:\n%s\n", recv); 
         } 
         close(conn_fd);    // I forgot to close the listen conn_fd! 
         free_request(&requestP[i]); 
         FD_CLR(conn_fd, &master); // I forgot to FD_CLR the conn_fd! 
        } 
       } 
      } 
     } 
    } 
    free(requestP); 
    return 0; 
} 
//========================= 
//The following are some APIs 

#include <time.h> 
#include <fcntl.h> 
#include <ctype.h> 
#include <sys/stat.h> 
#include <sys/mman.h> 

static void add_to_buf(http_request *reqP, char* str, size_t len); 
static void strdecode(char* to, char* from); 
static int hexit(char c); 
static char* get_request_line(http_request *reqP); 
static void* e_malloc(size_t size); 
static void* e_realloc(void* optr, size_t size); 

static void init_request(http_request* reqP) { 
    reqP->conn_fd = -1; 
    reqP->status = 0;  // not used 
    reqP->file[0] = (char) 0; 
    reqP->query[0] = (char) 0; 
    reqP->host[0] = (char) 0; 
    reqP->buf = NULL; 
    reqP->buf_size = 0; 
    reqP->buf_len = 0; 
    reqP->buf_idx = 0; 
} 

static void free_request(http_request* reqP) { 
    if (reqP->buf != NULL) { 
     free(reqP->buf); 
     reqP->buf = NULL; 
    } 
    init_request(reqP); 
} 


#define ERR_RET(error) { *errP = error; return -1; } 
// return 0: success, file is buffered in retP->buf with retP->buf_len bytes 
// return -1: error, check error code (*errP) 
// return 1: read more, continue until return -1 or 0 
// error code: 
// 1: client connection error 
// 2: bad request, cannot parse request 
// 3: method not implemented 
// 4: illegal filename 
// 5: illegal query 
// 6: file not found 
// 7: file is protected 
// 
static int read_header_and_file(http_request* reqP, int *errP) { 
    // Request variables 
    char* file = (char *) 0; 
    char* path = (char *) 0; 
    char* query = (char *) 0; 
    char* protocol = (char *) 0; 
    char* method_str = (char *) 0; 
    int r, fd; 
    struct stat sb; 
    char timebuf[100]; 
    int buflen; 
    char buf[10000]; 
    time_t now; 
    void *ptr; 

    // Read in request from client 
    while (1) { 
     r = read(reqP->conn_fd, buf, sizeof(buf)); 
     if (r < 0 && (errno == EINTR || errno == EAGAIN)) return 1; 
     if (r <= 0) ERR_RET(1) 
      add_to_buf(reqP, buf, r); 
     if (strstr(reqP->buf, "\015\012\015\012") != (char*) 0 || 
      strstr(reqP->buf, "\012\012") != (char*) 0) break; 
    } 

    fprintf(stderr, "=============================================\n"); 
    fprintf(stderr, "header: %s", reqP->buf); 
    fprintf(stderr, "=============================================\n"); 

    // Parse the first line of the request. 
    method_str = get_request_line(reqP); 
    if (method_str == (char*) 0) ERR_RET(2) 
     path = strpbrk(method_str, " \t\012\015"); 
    if (path == (char*) 0) ERR_RET(2) 
     *path++ = '\0'; 
    path += strspn(path, " \t\012\015"); 
    protocol = strpbrk(path, " \t\012\015"); 
    if (protocol == (char*) 0) ERR_RET(2) 
     *protocol++ = '\0'; 
    protocol += strspn(protocol, " \t\012\015"); 
    query = strchr(path, '?'); 
    if (query == (char*) 0) 
     query = ""; 
    else 
     *query++ = '\0'; 

    if (strcasecmp(method_str, "GET") != 0) ERR_RET(3) 
     else { 
      strdecode(path, path); 
      if (path[0] != '/') ERR_RET(4) 
       else file = &(path[1]); 
     } 

    if (strlen(file) >= MAXBUFSIZE-1) ERR_RET(4) 
     if (strlen(query) >= MAXBUFSIZE-1) ERR_RET(5) 
      strcpy(reqP->file, file); 
    strcpy(reqP->query, query); 

    char *m = strchr(reqP->query, '=') + 1; 
    char *filename = strncpy(reqP->query, m, sizeof(reqP->query)); 

    fprintf(stderr, "filename = %s\n", filename); 
    fprintf(stderr, "reqP.conn_fd = %d\n", reqP->conn_fd); 
    fprintf(stderr, "reqP.status = %d\n", reqP->status); 
    fprintf(stderr, "reqP.file = %s\n", reqP->file); 
    fprintf(stderr, "reqP.query = %s\n", reqP->query); 
    fprintf(stderr, "reqP.host = %s\n", reqP->host); 
    fprintf(stderr, "reqP.buf = %s\n", reqP->buf); 
    fprintf(stderr, "reqP.buf_len = %zu\n", reqP->buf_len); 
    fprintf(stderr, "reqP.buf_size = %zu\n", reqP->buf_size); 
    fprintf(stderr, "reqP.buf_idx = %zu\n", reqP->buf_idx); 
    fprintf(stderr, "=============================================\n"); 

    // if (query[0] == (char) 0) { 
    if (query[0] == 'f') { 
     fprintf(stderr, "query[0] = %c\n", query[0]); 
     // for file request, read it in buf 

     r = stat(filename, &sb); 
     // r = stat(reqP->file, &sb); 
     if (r < 0) ERR_RET(6) 
      fd = open(filename, O_RDONLY); 
     // fd = open(reqP->file, O_RDONLY); 
     if (fd < 0) ERR_RET(7) 
      reqP->buf_len = 0; 

     buflen = snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\015\012Server: SP TOY\015\012"); 
     add_to_buf(reqP, buf, buflen); 
     now = time((time_t*) 0); 
     (void) strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now)); 
     buflen = snprintf(buf, sizeof(buf), "Date: %s\015\012", timebuf); 
     add_to_buf(reqP, buf, buflen); 
     buflen = snprintf(
          buf, sizeof(buf), "Content-Length: %lld\015\012", (int64_t) sb.st_size); 
     add_to_buf(reqP, buf, buflen); 
     buflen = snprintf(buf, sizeof(buf), "Connection: close\015\012\015\012"); 
     add_to_buf(reqP, buf, buflen); 

     ptr = mmap(0, (size_t) sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 
     if (ptr == (void*) -1) ERR_RET(8) 
      add_to_buf(reqP, ptr, sb.st_size); 
     (void) munmap(ptr, sb.st_size); 
     close(fd); 
     // printf("%s\n", reqP->buf); 
     // fflush(stdout); 
     reqP->buf_idx = 0; // writing from offset 0 
     return 0; 
    } 
    return 0; 
} 

static void add_to_buf(http_request *reqP, char* str, size_t len) { 
    char** bufP = &(reqP->buf); 
    size_t* bufsizeP = &(reqP->buf_size); 
    size_t* buflenP = &(reqP->buf_len); 

    if (*bufsizeP == 0) { 
     *bufsizeP = len + 500; 
     *buflenP = 0; 
     *bufP = (char*) e_malloc(*bufsizeP); 
    } else if (*buflenP + len >= *bufsizeP) { 
     *bufsizeP = *buflenP + len + 500; 
     *bufP = (char*) e_realloc((void*) *bufP, *bufsizeP); 
    } 
    (void) memmove(&((*bufP)[*buflenP]), str, len); 
    *buflenP += len; 
    (*bufP)[*buflenP] = '\0'; 
} 

static char* get_request_line(http_request *reqP) { 
    int begin; 
    char c; 

    char *bufP = reqP->buf; 
    int buf_len = reqP->buf_len; 

    for (begin = reqP->buf_idx ; reqP->buf_idx < buf_len; ++reqP->buf_idx) { 
     c = bufP[reqP->buf_idx]; 
     if (c == '\012' || c == '\015') { 
      bufP[reqP->buf_idx] = '\0'; 
      ++reqP->buf_idx; 
      if (c == '\015' && reqP->buf_idx < buf_len && 
       bufP[reqP->buf_idx] == '\012') { 
       bufP[reqP->buf_idx] = '\0'; 
       ++reqP->buf_idx; 
      } 

      fprintf(stderr, "bufP = %s\n", bufP); 
      fprintf(stderr, "=============================================\n"); 
      return &(bufP[begin]); 
     } 
    } 
    fprintf(stderr, "http request format error\n"); 
    exit(1); 
} 

static void init_http_server(http_server *svrP, unsigned short port) { 
    struct sockaddr_in servaddr; 
    int tmp; 

    gethostname(svrP->hostname, sizeof(svrP->hostname)); 
    svrP->port = port; 

    svrP->listen_fd = socket(AF_INET, SOCK_STREAM, 0); 
    if (svrP->listen_fd < 0) ERR_EXIT("socket") 

     bzero(&servaddr, sizeof(servaddr)); 
    servaddr.sin_family = AF_INET; 
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    servaddr.sin_port = htons(port); 
    tmp = 1; 
    if (setsockopt(svrP->listen_fd, SOL_SOCKET, SO_REUSEADDR, (void*) &tmp, sizeof(tmp)) < 0) ERR_EXIT ("setsockopt ") 
     if (bind(svrP->listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) ERR_EXIT("bind") 
      if (listen(svrP->listen_fd, 1024) < 0) ERR_EXIT("listen") 
       } 

// Set NDELAY mode on a socket. 
static void set_ndelay(int fd) { 
    int flags, newflags; 

    flags = fcntl(fd, F_GETFL, 0); 
    if (flags != -1) { 
     newflags = flags | (int) O_NDELAY; // nonblocking mode 
     if (newflags != flags) 
      (void) fcntl(fd, F_SETFL, newflags); 
    } 
} 

static void strdecode(char* to, char* from) { 
    for (; *from != '\0'; ++to, ++from) { 
     if (from[0] == '%' && isxdigit(from[1]) && isxdigit(from[2])) { 
      *to = hexit(from[1]) * 16 + hexit(from[2]); 
      from += 2; 
     } else { 
      *to = *from; 
     } 
    } 
    *to = '\0'; 
} 

static int hexit(char c) { 
    if (c >= '0' && c <= '9') 
     return c - '0'; 
    if (c >= 'a' && c <= 'f') 
     return c - 'a' + 10; 
    if (c >= 'A' && c <= 'F') 
     return c - 'A' + 10; 
    return 0;   // shouldn't happen 
} 

static void* e_malloc(size_t size) { 
    void* ptr; 

    ptr = malloc(size); 
    if (ptr == (void*) 0) { 
     (void) fprintf(stderr, "out of memory\n"); 
     exit(1); 
    } 
    return ptr; 
} 

static void* e_realloc(void* optr, size_t size) { 
    void* ptr; 

    ptr = realloc(optr, size); 
    if (ptr == (void*) 0) { 
     (void) fprintf(stderr, "out of memory\n"); 
     exit(1); 
    } 
    return ptr; 
} 

這裏是file_reader.c

#include <unistd.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 

#define ERR_EXIT(a) { perror(a); exit(1); } 

int main(int argc, char **argv) { 
    FILE *fp = fopen(argv[1], "r"); 
    char c; 
    char buf[1024]; 
    int i = 0; 
    fprintf(stderr, "filename = %s\n", argv[1]); 

    if (fp == NULL) 
     ERR_EXIT("ERROR open!\n") 
    while ((c = fgetc(fp)) != EOF) { 
     buf[i] = c; 
     i++; 
    } 
    buf[i] = '\0'; 
    write(STDOUT_FILENO, buf, sizeof(buf)); 
    fclose(fp); 
    return 0; 
} 
+1

請建立[最小,完全,可覈查示例]( http://stackoverflow.com/help/mcve) –

+0

顯然'select'認爲'readfs'中有一個無效的fd。但是你甚至沒有提供設置'master'的代碼,這使得診斷問題變得非常困難。請提供一個MCVE。 – kaylum

+0

是否有編譯警告?如果是這樣,請在報告任何問題之前解決它們你是否使用足夠的警告來確信自己?如果你使用GCC,你應該至少使用'-Werror -Wall'; ' - 錯誤'會阻止你忽略警告。你應該添加'-Wextra';個人而言,我使用了更多的警告。 –

回答

0

後關閉的FD是在readFDSwriteFDs你需要從那裏刪除它。

+1

當你仍然循環它們時,你不需要從'readFDS'或'writeFD​​S'中移除它。你只需要確保你不會把它傳遞給後續的select()調用。代碼已經在再次調用'select()'之前將它從'master'列表中移除。 –

+0

@RemyLebeau我沒有說任何關於刪除它的事情,但仍然循環着它們,儘管這當然是我該怎麼做的。而他的代碼不可能正確地「處理這些」。他唯一可以得到這個錯誤的方法是在'read/writeFD​​s'中有一個無效的FD,唯一的辦法是發明一個不明顯的,或者繼續使用封閉的FD。 – EJP

+0

看到我的答案,他甚至沒有正確管理'requestP'數組及其索引。 –

1

你,存儲多個連接的客戶端在同一requestP插槽,因爲你在呼喚accept()後使用監聽套接字描述作爲數組索引。如果一次只連接一個客戶端,那麼這將起作用,否則當一次連接多個客戶端時,您將會毀壞該插槽。

但是,您的讀/寫代碼使用客戶端套接字描述符作爲數組索引。由於客戶端套接字描述符與偵聽套接字描述符的值不同,因此在準備新的accept()'客戶端時,需要將requestP[i]更改爲requestP[conn_fd]

這也假設requestP是一個固定長度的數組,當用作索引時,各種套接字描述符從不超過數組邊界。

無論何時從master列表中刪除套接字描述符,您也不會重新計算maxfd。這也可能會導致你的錯誤。

您也沒有處理write()在非阻塞套接字上返回阻塞錯誤的情況。在這種情況下,您需要使用select()write_fds部分來檢測套接字何時可以接受更多數據,然後再次調用write()

更好的解決方案是改變requestP成動態陣列或鏈接的列表,並停止使用套接字描述符作爲數組索引完全,例如:

typedef struct http_request { 
    http_request *next; 

    int conn_fd;    // fd to talk with client 
    int status;    // not used, error, reading (from client), writing (to client) 

    char file[MAXBUFSIZE];  // requested file 
    char query[MAXBUFSIZE]; // requested query 
    char host[MAXBUFSIZE];  // client host 
    char* buf;     // data sent by/to client 
    size_t buf_len;   // bytes used by buf 
    size_t buf_size;   // bytes allocated for buf 
    size_t buf_idx;   // offset for reading and writing 
} http_request; 

http_request *requests_head = NULL; 
http_request *requests_tail = NULL; 

while (1) {        /* Main loop */ 
    FD_ZERO(&read_fds); 
    FD_ZERO(&write_fds); 

    FD_SET(server.listen_fd, &read_fds); 
    int maxfd = server.listen_fd; 

    http_request *request = requests_head; 
    while (request) { 
     FD_SET(request->conn_fd, &read_fds); 
     if (request->status == WRITING} { 
      FD_SET(request->conn_fd, &write_fds); 
     } 
     maxfd = max(request->conn_fd, maxfd); 
     request = request->next; 
    } 

    if (select(maxfd+1, &read_fds, &write_fds, NULL, NULL) < 0) 
     ERR_EXIT("select") 
    printf("server select() is OK!\n"); 

    if (FD_ISSET(server.listen_fd, &read_fds)) { 
     clilen = sizeof(cliaddr); 
     conn_fd = accept(server.listen_fd, (struct sockaddr *) &cliaddr, (socklen_t *) &clilen); 
     if (conn_fd < 0) { 
      if ((errno != EINTR) && (errno != EAGAIN)) { // try again later 
       if (errno != ENFILE) { 
        ERR_EXIT("accept") 
       } 
       fprintf(stderr, "out of file descriptor table ... (maxconn %d)\n", maxfd); 
      } 
     } 
     else 
     { 
      request = (http_request*) malloc(sizeof(http_request)); 
      if (!request) { 
       // error handling ... 
       close(conn_fd); 
      } 
      else 
      { 
       memset(request, 0, sizeof(http_request)); 

       request->conn_fd = conn_fd; 
       request->status = READING; 
       strcpy(request->host, inet_ntoa(cliaddr.sin_addr)); 
       set_ndelay(conn_fd); 

       fprintf(stderr, "getting a new request... fd %d from %s\n", conn_fd, request->host); 

       if (!requests_head) requests_head = request; 
       if (requests_tail) requests_tail->next = request; 
       requests_tail = request; 
      } 
     } 
    } 

    request = requests_head; 
    http_request *next, *prev = NULL; 
    while (request) { 
     if (FD_ISSET(request->conn_fd, &read_fds)) { 
      // Handle data from a client 
      if (request->state != READING) { 
       char recv[1024]; 
       if (read(request->conn_fd, recv, sizeof(recv)) <= 0) { 
        fprintf(stderr, "error on fd %d, code %d\n", request->conn_fd, err); 
        close(request->conn_fd); 
        free_request(request); 

        next = request->next; 
        if (request == requests_head) requests_head = next; 
        if (request == requests_tail) requests_tail = prev; 
        if (prev) prev->next = next; 
        free(request); 

        request = next; 
        continue; 
       } 
      } 
      else 
      { 
       fprintf(stderr, "reading from conn_fd %d\n", request->conn_fd); 
       ret = read_header_and_file(request, &err); 
       if (ret < 0) { 
        fprintf(stderr, "error on fd %d, code %d\n", request->conn_fd, err); 
        close(request->conn_fd); 
        free_request(request); 

        next = request->next; 
        if (request == requests_head) requests_head = next; 
        if (request == requests_tail) requests_tail = prev; 
        if (prev) prev->next = next; 
        free(request); 

        request = next; 
        continue; 
       } 

       if (ret == 0) { 
        request->status = WRITING; 
        FD_SET(request->conn_fd, &write_fds); 
       } 
      } 
     } 

     if (FD_ISSET(request->conn_fd, &write_fds)) { 
      // Handle data to a client 
      if (request->buf_idx < request->buf_len) { 
       fprintf(stderr, "writing (buf %s, idx %d) %d bytes to request fd %d\n", request->buf, (int) request->buf_idx, (int) request->buf_len, request->conn_fd); 
       nwritten = write(request->conn_fd, &request->buf[request->buf_idx], request->buf_len - request->buf_idx); 
       if (nwritten < 0) { 
        if ((errno != EINTR) && (errno != EAGAIN)) { 
         fprintf(stderr, "error on fd %d, code %d\n", request->conn_fd, errno); 
         close(request->conn_fd); 
         free_request(request); 

         next = request->next; 
         if (request == requests_head) requests_head = next; 
         if (request == requests_tail) requests_tail = prev; 
         if (prev) prev->next = next; 
         free(request); 

         request = next; 
         continue; 
        } 
       } 
       else 
       { 
        request->buf_idx += nwritten; 
       } 
      } 

      if (request->buf_idx == request->buf_len) { 
       fprintf(stderr, "complete writing %d bytes on fd %d\n", (int) request->buf_len, request->conn_fd); 
       fprintf(stderr, "=============================================\n"); 

       int fd[2]; 
       if (pipe(fd) == -1) 
        ERR_EXIT("pipe") 

       pid_t pid; 
       if ((pid = fork()) < 0) 
        ERR_EXIT("fork") 

       else if (pid == 0) {  /* In Child Process */ 
        close(fd[0]); 
        dup2(fd[1], STDOUT_FILENO); 
        close(fd[1]); 

        execl("file_reader", "./file_reader", request->query, (char *)0); 
        fprintf(stderr, "Error: Unexpect flow of control.\n"); 
        exit(EXIT_FAILURE); 
       } 
       else {  /* In Parent Process */ 
        close(fd[1]); 
        char recv[1024]; 
        read(fd[0], recv, sizeof(recv)); 
        printf("The file content is:\n%s\n", recv); 
       } 

       close(request->conn_fd); 
       free_request(request); 

       next = request->next; 
       if (request == requests_head) requests_head = next; 
       if (request == requests_tail) requests_tail = prev; 
       if (prev) prev->next = next; 
       free(request); 

       request = next; 
       continue; 
      } 
     } 

     request = request->next; 
    } 
}