/* Wait for and accept a TCP connection request: */
int tcp_accept(int sock, int timeout) {
- int pr, conn = -1;
+ int r;
struct pollfd pfd;
- uint8_t a_[128];
- struct sockaddr *addr = (void *)a_;
- socklen_t addrlen = sizeof a_;
pfd.fd = sock;
pfd.events = POLLIN;
- pr = poll(&pfd, 1, timeout);
- if (pr == 1 && pfd.revents == POLLIN) {
- conn = accept(sock, addr, &addrlen);
- GET_STRADDR(straddr_, addr, addrlen);
- if (conn < 0) {
- NETLOG_ERR(EAI_SYSTEM, "accept(%d, %s)", sock, straddr_);
- } else {
- NETLOG_DBG("accept(%d) -> (%d, %s): Ok", sock, conn, straddr_);
+ r = poll(&pfd, 1, timeout);
+ if (r == 1 && pfd.revents & (POLLIN | POLLERR | POLLHUP)) {
+ /* In case of POLLERR or POLLHUP we let accept() catch the error! */
+ unsigned char a_[128];
+ struct sockaddr *addr = (void *)a_;
+ socklen_t addrlen = sizeof a_;
+ r = accept(sock, addr, &addrlen);
+ if (r < 0) {
+ r = EAI_SYSTEM;
+ }
+ else {
+ GET_STRADDR(straddr_, addr, addrlen);
+ NETLOG_DBG("accept(%d) -> (%d, %s): Ok", sock, r, straddr_);
+ FREE_STRADDR(straddr_);
}
- FREE_STRADDR(straddr_);
- }
- else if (pr < 0) {
- NETLOG_ERR(EAI_SYSTEM, "poll(%d, %d)", sock, timeout);
- return EAI_SYSTEM;
}
- else if (pr == 0) {
- NETLOG_DBG("poll(%d, %d): Timeout", sock, timeout);
+ else if (r == 0) {
errno = ETIMEDOUT;
- return EAI_SYSTEM;
+ r = EAI_SYSTEM;
+ }
+ else if (r < 0) {
+ r = EAI_SYSTEM;
+ }
+ else if (pfd.revents & POLLNVAL) {
+ errno = EBADF;
+ r = EAI_SYSTEM;
+ }
+ else {
+ NETLOG_DBG("This should never happen! (r=%d, revents=%hd)", r, pfd.revents);
+ errno = EIO;
+ r = EAI_SYSTEM;
+ }
+ if (r < 0) {
+ NETLOG_ERR(r, "tcp_accept(%d)", sock);
}
- return conn < 0 ? EAI_SYSTEM : conn;
+ return r;
}
/* Copy textual description of last error to user supplied buffer: */