Back from vacation, and would like to make a new version of http://review.gluster.org/#/c/8292/. If I understand Emmanuel Dreyfus and some scattered mails on the internet, the reason for IPv6 to be removed was that the code using getaddrinfo is written in such a way that it (often incorrectly) assumes that the first address returned by getaddrinfo is the one we are interested in. As I said in private to Emmanuel: On 2014-07-31 19:55, Anders Blomdell wrote: > On 2014-07-31 14:49, Emmanuel Dreyfus wrote: >> Hi >> >> Here is a test case that shows the problem: AF_UNSPEC really means either >> AF_INET or AF_INET6, you have to choose for a given socket. I wonder >> what is Linux output. > > It actually means all: > > > #include <stdio.h> > #include <unistd.h> > #include <err.h> > #include <netdb.h> > #include <sysexits.h> > #include <sys/socket.h> > #include <string.h> > #include <arpa/inet.h> > > int > main(void) > { > struct addrinfo hints, *res, *res0; > int error; > char buf[128]; > > memset(&hints, 0, sizeof(hints)); > hints.ai_family = AF_UNSPEC; > hints.ai_socktype = SOCK_STREAM; > error = getaddrinfo("google.com", "http", &hints, &res0); > if (error) { > errx(1, "%s", gai_strerror(error)); > /*NOTREACHED*/ > } > for (res = res0; res; res = res->ai_next) { > void *p; > > if (res->ai_family == AF_INET) { > p = &((struct sockaddr_in *)(res->ai_addr))->sin_addr; > } else if (res->ai_family == AF_INET6) { > p = &((struct sockaddr_in6 *)(res->ai_addr))->sin6_addr; > } > printf("family = %d, addr = %s\n", > res->ai_family, > inet_ntop(res->ai_family, p, buf, 128)); > } > return 0; > } > > Which returns: > > family = 10, addr = 2a00:1450:400f:805::1005 > family = 2, addr = 74.125.232.227 > family = 2, addr = 74.125.232.228 > family = 2, addr = 74.125.232.229 > family = 2, addr = 74.125.232.230 > family = 2, addr = 74.125.232.231 > family = 2, addr = 74.125.232.232 > family = 2, addr = 74.125.232.233 > family = 2, addr = 74.125.232.238 > family = 2, addr = 74.125.232.224 > family = 2, addr = 74.125.232.225 > family = 2, addr = 74.125.232.226 > > Which means that the logic has to be something like (at least on Linux): > > * Listen: > if wildcard > bind/listen IPv6 > else > bind/listen to all returned addresses, > it's OK if some of them fails (then we > probably don't have that address on any of > our interfaces) > * Connect: > connect to any of the given addresses (to speed > things up we could try all in parallell and take the > first that responds). > AFAICT this means that all code where only the first result from getaddrinfo is used, the code should be re-factored along these lines: int f(char *host, int (*cb_start)(void *cb_context), int (*cb_each)(struct addrinfo *a, void *cb_context), int (*cb_end)(void *cb_context), void *cb_context) { struct addrinfo *addr, *p; ... ret = getaddrinfo (..., &addr); if (ret == 0) { cb_start(context); for (p = addr; p != NULL; p = p->ai_next) { cb_each(p, context); } cb_end(context); freeaddrinfo (addr); } ... } Any thoughts? -- Anders Blomdell Email: anders.blomdell@xxxxxxxxxxxxxx Department of Automatic Control Lund University Phone: +46 46 222 4625 P.O. Box 118 Fax: +46 46 138118 SE-221 00 Lund, Sweden _______________________________________________ Gluster-devel mailing list Gluster-devel@xxxxxxxxxxx http://supercolony.gluster.org/mailman/listinfo/gluster-devel