1 #include <ccan/net/net.h>
3 #include <sys/socket.h>
12 #include <netinet/in.h>
14 struct addrinfo *net_client_lookup(const char *hostname,
19 struct addrinfo hints;
22 memset(&hints, 0, sizeof(hints));
23 hints.ai_family = family;
24 hints.ai_socktype = socktype;
26 hints.ai_protocol = 0;
28 if (getaddrinfo(hostname, service, &hints, &res) != 0)
34 static bool set_nonblock(int fd, bool nonblock)
38 flags = fcntl(fd, F_GETFL);
45 flags &= ~(long)O_NONBLOCK;
47 return (fcntl(fd, F_SETFL, flags) == 0);
50 /* We only handle IPv4 and IPv6 */
53 static void remove_fd(struct pollfd pfd[],
54 const struct addrinfo *addr[],
59 memmove(pfd + i, pfd + i + 1, (*num - i - 1) * sizeof(pfd[0]));
60 memmove(addr + i, addr + i + 1, (*num - i - 1) * sizeof(addr[0]));
61 memmove(slen + i, slen + i + 1, (*num - i - 1) * sizeof(slen[0]));
65 int net_connect(const struct addrinfo *addrinfo)
67 int sockfd = -1, saved_errno;
69 const struct addrinfo *ipv4 = NULL, *ipv6 = NULL;
70 const struct addrinfo *addr[MAX_PROTOS];
71 socklen_t slen[MAX_PROTOS];
72 struct pollfd pfd[MAX_PROTOS];
74 for (; addrinfo; addrinfo = addrinfo->ai_next) {
75 switch (addrinfo->ai_family) {
88 /* We give IPv6 a slight edge by connecting it first. */
91 slen[num] = sizeof(struct sockaddr_in6);
92 pfd[num].fd = socket(AF_INET6, ipv6->ai_socktype,
94 if (pfd[num].fd != -1)
99 slen[num] = sizeof(struct sockaddr_in);
100 pfd[num].fd = socket(AF_INET, ipv4->ai_socktype,
102 if (pfd[num].fd != -1)
106 for (i = 0; i < num; i++) {
107 if (!set_nonblock(pfd[i].fd, true)) {
108 remove_fd(pfd, addr, slen, &num, i--);
111 /* Connect *can* be instant. */
112 if (connect(pfd[i].fd, addr[i]->ai_addr, slen[i]) == 0)
114 if (errno != EINPROGRESS) {
115 /* Remove dead one. */
116 remove_fd(pfd, addr, slen, &num, i--);
118 pfd[i].events = POLLOUT;
121 while (num && poll(pfd, num, -1) != -1) {
122 for (i = 0; i < num; i++) {
124 socklen_t errlen = sizeof(err);
127 if (getsockopt(pfd[i].fd, SOL_SOCKET, SO_ERROR, &err,
133 /* Remove dead one. */
135 remove_fd(pfd, addr, slen, &num, i--);
140 /* We don't want to hand them a non-blocking socket! */
141 if (set_nonblock(pfd[i].fd, false))
146 for (i = 0; i < num; i++)
147 if (pfd[i].fd != sockfd)