[Gluster-devel] Reintroduce IPv6 support

Anders Blomdell anders.blomdell at control.lth.se
Tue Sep 2 15:22:59 UTC 2014


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 at control.lth.se
Department of Automatic Control
Lund University                  Phone:    +46 46 222 4625
P.O. Box 118                     Fax:      +46 46 138118
SE-221 00 Lund, Sweden



More information about the Gluster-devel mailing list