/* B01902062 藍ĉŒşç‘‹ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "common.h" #include "proc.h" #include #include #include #include #include #include #include #include #include #include #include #include #include void procconn(server* svr, request* req, int maxfd, struct timeval timeout) { fd_set rset = svr->readfds; fd_set wset = svr->writefds; fd_set eset = svr->exceptfds; struct timeval select_timeout = timeout; int rval; rval = select (maxfd, &rset, &wset, &eset, &select_timeout); if (rval < 0) { if (errno != EINTR) perror ("select"); return; } for (int i = 0; i < maxfd; i++) { if (!FD_ISSET (i, &rset)) continue; if (i == svr->listen_fd) { struct sockaddr_in client_addr; int client_len = sizeof (client_addr); int conn_fd = accept (i, (struct sockaddr*)&client_addr, (socklen_t*)&client_len); if (conn_fd < 0) { switch (errno) { case EINTR: case EAGAIN: continue; case EMFILE: case ENFILE: fprintf (stderr, "Too many open file ... " "(maxfd %d)\n", maxfd); continue; default: perror ("accept"); continue; } } else { req[conn_fd].conn_fd = conn_fd; req[conn_fd].active = true; strcpy(req[conn_fd].host, inet_ntoa(client_addr.sin_addr)); request_msg (&req[conn_fd], "accepted, waiting for filename"); FD_SET (conn_fd, &(svr->readfds)); } } else { rval = request_read(&req[i]); if (rval <= 0) { request_msg (&req[i], "socket read: %s", rval ? strerror (errno) : "connection closed"); request_free (&req[i], svr); } else { if (req[i].header_done) { // ignore remaining chars in the buffer req[i].buf_len = 0; FD_CLR (req[i].conn_fd, &(svr->readfds)); FD_SET (req[i].conn_fd, &(svr->writefds)); } } } } for (int i = 0; i < maxfd; i++) { if (!FD_ISSET (i, &wset)) continue; if (i == svr->listen_fd) continue; if (req[i].header_done) { if (!req[i].header_accept) { req[i].file_fd = open (req[i].filename, O_RDONLY); request_err (&req[i], "open", req[i].file_fd); if (req[i].file_fd < 0) { write (req[i].conn_fd, svr->reject_hdr, SVR_REJECT_HDR_LEN); request_msg (&req[i], "REJECT sent"); request_free (&req[i], svr); continue; } struct stat file_stat; rval = fstat (req[i].file_fd, &file_stat); request_msg (&req[i], "fstat", rval); if (req[i].file_fd < 0) { write (req[i].conn_fd, svr->reject_hdr, SVR_REJECT_HDR_LEN); request_msg (&req[i], "REJECT sent"); request_free (&req[i], svr); continue; } req[i].file_info = ftab_insert ( svr->file_table, file_stat.st_dev, file_stat.st_ino, req[i].file_fd); struct flock lock_info = { .l_type = F_RDLCK, .l_whence = SEEK_SET, .l_start = 0, .l_len = 0 }; rval = fcntl (req[i].file_fd, F_SETLK, &lock_info); request_msg (&req[i], "lock", rval); if (rval < 0) { write (req[i].conn_fd, svr->reject_hdr, SVR_REJECT_HDR_LEN); request_msg (&req[i], "REJECT sent"); request_free (&req[i], svr); continue; } request_msg (&req[i], "ACCEPT sent"); write (req[i].conn_fd, svr->accept_hdr, SVR_ACCEPT_HDR_LEN); req[i].header_accept = true; } else { if (!req[i].buf_len) { rval = read (req[i].file_fd, req[i].buf, SVR_BUFFER_SIZE); if (rval < 0) { if (errno != EINTR && errno != EAGAIN) { // fatal error, close the connection request_msg (&req[i], "read: %s", strerror (errno)); request_free (&req[i], svr); } continue; } else if (rval == 0) { request_msg (&req[i], "transfer done, closing connection"); request_free (&req[i], svr); continue; } req[i].buf_set = 0; req[i].buf_len = rval; } rval = write (req[i].conn_fd, req[i].buf + req[i].buf_set, req[i].buf_len); if (rval < 0) { request_msg (&req[i], "socket write: %s", strerror (errno)); request_free (&req[i], svr); continue; } req[i].buf_set += rval; req[i].buf_len -= rval; } } } return; }