int net_connect_complete(struct pollfd pfds[2]) { unsigned int i; assert(pfds[0].fd != -1 || pfds[1].fd != -1); for (i = 0; i < 2; i++) { int err; socklen_t errlen = sizeof(err); if (pfds[i].fd == -1) continue; if (getsockopt(pfds[i].fd, SOL_SOCKET, SO_ERROR, &err, &errlen) != 0) { net_connect_abort(pfds); return -1; } if (err == 0) { /* Don't hand them non-blocking fd! */ if (!set_nonblock(pfds[i].fd, false)) { net_connect_abort(pfds); return -1; } /* Close other one. */ if (pfds[!i].fd != -1) close(pfds[!i].fd); return pfds[i].fd; } } /* Still going... */ errno = EINPROGRESS; return -1; }
int net_connect_complete(struct pollfd pfds[2]) { unsigned int i; assert(pfds[0].fd != -1 || pfds[1].fd != -1); for (i = 0; i < 2; i++) { int err; socklen_t errlen = sizeof(err); if (pfds[i].fd == -1) continue; if (pfds[i].revents & POLLHUP) { /* Linux gives this if connecting to local * non-listening port */ close(pfds[i].fd); pfds[i].fd = -1; if (pfds[!i].fd == -1) { errno = ECONNREFUSED; return -1; } continue; } if (!(pfds[i].revents & POLLOUT)) continue; if (getsockopt(pfds[i].fd, SOL_SOCKET, SO_ERROR, &err, &errlen) != 0) { net_connect_abort(pfds); return -1; } if (err == 0) { /* Don't hand them non-blocking fd! */ if (!set_nonblock(pfds[i].fd, false)) { net_connect_abort(pfds); return -1; } /* Close other one. */ if (pfds[!i].fd != -1) close(pfds[!i].fd); return pfds[i].fd; } } /* Still going... */ errno = EINPROGRESS; return -1; }
int net_connect(const struct addrinfo *addrinfo) { struct pollfd pfds[2]; int sockfd; sockfd = net_connect_async(addrinfo, pfds); /* Immediate connect or error is easy. */ if (sockfd >= 0 || errno != EINPROGRESS) return sockfd; while (poll(pfds, 2, -1) != -1) { sockfd = net_connect_complete(pfds); if (sockfd >= 0 || errno != EINPROGRESS) return sockfd; } net_connect_abort(pfds); return -1; }