VALUE rsock_s_accept_nonblock(VALUE klass, rb_io_t *fptr, struct sockaddr *sockaddr, socklen_t *len) { int fd2; rb_secure(3); rb_io_set_nonblock(fptr); fd2 = cloexec_accept(fptr->fd, (struct sockaddr*)sockaddr, len); if (fd2 < 0) { switch (errno) { case EAGAIN: #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN case EWOULDBLOCK: #endif case ECONNABORTED: #if defined EPROTO case EPROTO: #endif rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "accept(2) would block"); } rb_sys_fail("accept(2)"); } rb_update_max_fd(fd2); make_fd_nonblock(fd2); return rsock_init_sock(rb_obj_alloc(klass), fd2); }
int main(int argc, char *argv[]) { int listenfd; struct sockaddr_in sin; if (argc < 2) { fprintf(stderr, "usage: %s <port>\n", argv[0]); exit(1); } listenfd = socket(AF_INET, SOCK_STREAM, 0); if (listenfd == -1) handle_error("socket"); make_fd_nonblock(listenfd); int one = 1; setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); sin.sin_family = AF_INET; sin.sin_port = htons(atoi(argv[1])); sin.sin_addr.s_addr = 0; if (bind(listenfd, (struct sockaddr *)&sin, sizeof(sin)) == -1) handle_error("bind"); if (listen(listenfd, 16) == -1) handle_error("listen"); int i, r, maxfd; fd_set fds; fd_set readset; FD_ZERO(&fds); for ( ;; ) { FD_ZERO(&readset); maxfd = listenfd; FD_SET(listenfd, &readset); for (i = 0; i < FD_SETSIZE; i++) { if (!FD_ISSET(i, &fds)) continue; FD_SET(i, &readset); if (maxfd < i) maxfd = i; } int result = select(maxfd+1, &readset, NULL, NULL, NULL); if (result == -1) continue; if (FD_ISSET(listenfd, &readset)) { struct sockaddr_storage ss; socklen_t slen = sizeof(ss); int connfd = accept(listenfd, (struct sockaddr *)&ss, &slen); if (connfd != -1) { make_fd_nonblock(connfd); if (connfd > FD_SETSIZE) close(connfd); FD_SET(connfd, &fds); } FD_CLR(listenfd, &readset); } for (i = 0; i <= maxfd; i++) { r = -1; if (FD_ISSET(i, &readset)) { r = do_read(i); } if (r == 0) FD_CLR(i, &fds); } } }
int main(int argc, char *argv[]) { struct epoll_event ev; struct epoll_event *evs; if (argc != 2) { fprintf(stderr, "Usage: epoll port\n"); exit(1); } int socketfd = create_socket_and_bind_port(argv[1]); if (socketfd == -1) { exit(EXIT_FAILURE); } if (make_fd_nonblock(socketfd) == -1) { exit(EXIT_FAILURE); } if (listen_socket(socketfd, MAXLISTEN) == -1) { exit(EXIT_FAILURE); } int epollfd; if ((epollfd = epoll_create1(0)) == -1) { perror("epoll_create1"); exit(EXIT_FAILURE); } ev.events = EPOLLIN | EPOLLET; ev.data.fd = socketfd; if (epoll_ctl(epollfd, EPOLL_CTL_ADD, socketfd, &ev) == -1) { perror("epoll_ctl"); exit(EXIT_FAILURE); } evs= calloc(sizeof (struct epoll_event), MAXEVENTS); if (!evs) { perror("calloc"); exit(EXIT_FAILURE); } for ( ; ;) { int nret; nret = epoll_wait(epollfd, evs, MAXEVENTS, -1); int i; for (i = 0; i < nret; ++i) { ev = evs[i]; if ((ev.events & EPOLLERR) || (ev.events & EPOLLHUP) || (!(ev.events & EPOLLIN))) { fprintf(stderr, "epoll error: %u\n", ev.events); epoll_ctl(epollfd, EPOLL_CTL_DEL, ev.data.fd, NULL); close(ev.data.fd); continue; } if (ev.data.fd == socketfd) { for (; ;) { int newfd; struct sockaddr sa; socklen_t sa_len = sizeof(struct sockaddr); newfd = accept(socketfd, &sa, &sa_len); if (newfd == -1) { if ( errno == EAGAIN || errno == EWOULDBLOCK) { break; } perror("accept"); break; } char ip[INET6_ADDRSTRLEN]; void *addr = get_in_addr(&sa); inet_ntop(sa.sa_family, addr, ip, sizeof(ip)); printf("Accept connection %s on descriptor %d\n", ip, newfd); if (make_fd_nonblock(newfd) == -1) { exit(EXIT_FAILURE); } struct epoll_event newev; newev.data.fd = newfd; newev.events = EPOLLIN | EPOLLET; if (epoll_ctl(epollfd, EPOLL_CTL_ADD, newfd, &newev) == -1) { perror("epoll_ctl"); exit(EXIT_FAILURE); } } // END FOR } // END IF else { int done = 0; for ( ; ;) { ssize_t count; char buf[BUFSIZ]; count = read(ev.data.fd, buf, BUFSIZ); if (count == -1) { if (errno != EAGAIN) { perror("read"); done = 1; } break; } else if (count == 0) { done = 1; break; } int nw = write(STDOUT_FILENO, buf, count); // write buf to standard output if (nw == -1) { perror("write"); exit(EXIT_FAILURE); } } // END FOR if (done == 1) { printf("Closed connection on descriptor %d\n", ev.data.fd); del_and_close_fd_from_epoll(epollfd, ev.data.fd); continue; } } // END ELSE } } }