1 #include <ccan/net/net.h>
3 #include <sys/socket.h>
13 struct addrinfo *net_client_lookup(const char *hostname,
18 struct addrinfo hints;
21 memset(&hints, 0, sizeof(hints));
22 hints.ai_family = family;
23 hints.ai_socktype = socktype;
25 hints.ai_protocol = 0;
27 if (getaddrinfo(hostname, service, &hints, &res) != 0)
33 static bool set_nonblock(int fd, bool nonblock)
37 flags = fcntl(fd, F_GETFL);
44 flags &= ~(long)O_NONBLOCK;
46 return (fcntl(fd, F_SETFL, flags) == 0);
49 /* We only handle IPv4 and IPv6 */
52 static void remove_fd(struct pollfd pfd[],
53 const struct addrinfo *addr[],
58 memmove(pfd + i, pfd + i + 1, (*num - i - 1) * sizeof(pfd[0]));
59 memmove(addr + i, addr + i + 1, (*num - i - 1) * sizeof(addr[0]));
60 memmove(slen + i, slen + i + 1, (*num - i - 1) * sizeof(slen[0]));
64 int net_connect(const struct addrinfo *addrinfo)
66 int sockfd = -1, saved_errno;
68 const struct addrinfo *ipv4 = NULL, *ipv6 = NULL;
69 const struct addrinfo *addr[MAX_PROTOS];
70 socklen_t slen[MAX_PROTOS];
71 struct pollfd pfd[MAX_PROTOS];
73 for (; addrinfo; addrinfo = addrinfo->ai_next) {
74 switch (addrinfo->ai_family) {
87 /* We give IPv6 a slight edge by connecting it first. */
90 slen[num] = sizeof(struct sockaddr_in6);
91 pfd[num].fd = socket(AF_INET6, ipv6->ai_socktype,
93 if (pfd[num].fd != -1)
98 slen[num] = sizeof(struct sockaddr_in);
99 pfd[num].fd = socket(AF_INET, ipv4->ai_socktype,
101 if (pfd[num].fd != -1)
105 for (i = 0; i < num; i++) {
106 if (!set_nonblock(pfd[i].fd, true)) {
107 remove_fd(pfd, addr, slen, &num, i--);
110 /* Connect *can* be instant. */
111 if (connect(pfd[i].fd, addr[i]->ai_addr, slen[i]) == 0)
113 if (errno != EINPROGRESS) {
114 /* Remove dead one. */
115 remove_fd(pfd, addr, slen, &num, i--);
117 pfd[i].events = POLLOUT;
120 while (num && poll(pfd, num, -1) != -1) {
121 for (i = 0; i < num; i++) {
123 socklen_t errlen = sizeof(err);
126 if (getsockopt(pfd[i].fd, SOL_SOCKET, SO_ERROR, &err,
132 /* Remove dead one. */
134 remove_fd(pfd, addr, slen, &num, i--);
139 /* We don't want to hand them a non-blocking socket! */
140 if (set_nonblock(pfd[i].fd, false))
145 for (i = 0; i < num; i++)
146 if (pfd[i].fd != sockfd)