diff -Naur man-pages-orig/man3/getaddrinfo.3 man-pages/man3/getaddrinfo.3 --- man-pages-orig/man3/getaddrinfo.3 2016-02-25 16:12:10.918563230 -0800 +++ man-pages/man3/getaddrinfo.3 2016-02-25 08:52:27.049057533 -0800 @@ -154,7 +154,20 @@ (either IPv4 or IPv6, for example) that can be used with .I node and -.IR service . +.IR service . +.I Programming Note: +in order to create a server socket that can be reached at +.I both +the server's IPv4 and IPv6 addresses, you should +.I preferentially +bind with AF_INET6 addresses returned by +.BR getaddrinfo () , +as binding with an AF_INET address will create a socket incapable +of accepting connections on the server's IPv6 addresses. In other words, +as you walk the list of candidate addresses, you should prefer +binding with those whose +.I ai_family +is AF_INET6, rather than AF_INET. .TP .I ai_socktype This field specifies the preferred socket type, for example @@ -675,6 +688,7 @@ socklen_t peer_addr_len; ssize_t nread; char buf[BUF_SIZE]; + int loops; if (argc != 2) { fprintf(stderr, "Usage: %s port\\n", argv[0]); @@ -697,22 +711,39 @@ } /* getaddrinfo() returns a list of address structures. - Try each address until we successfully bind(2). - If socket(2) (or bind(2)) fails, we (close the socket - and) try the next address. */ - - for (rp = result; rp != NULL; rp = rp\->ai_next) { - sfd = socket(rp\->ai_family, rp\->ai_socktype, - rp\->ai_protocol); - if (sfd == \-1) - continue; + Pass through the list UP TO twice. On the first pass, + SKIP addresses that are NOT AF_INET6. If socket(2) and + bind(2) both succeed on a candidate, we are done. Else, + close the socket and try the next address. If we didn't + find an IPv6 address on the first pass, try a second pass, + this time try ALL candidates in the list. If we get an + IPv6 address, the "hints" AF_UNSPEC and AI_PASSIVE will + ensure that the socket can be reached by all client programs + trying ANY of our IP addresses: v4 or v6, local or remote. + This is an useful and important property of network + programming called "protocol independence." See Richard + Stevens, "UNIX Network Programming, Vol. 1". */ + + for (loops = 0; loops < 2; loops++) { + for (rp = result; rp != NULL; rp = rp\->ai_next) { + + /* SKIP all but IPv6 candidates on 1st pass */ + if (loops == 0 && rp\->ai_family != AF_INET6) + continue; + + sfd = socket(rp\->ai_family, rp\->ai_socktype, + rp\->ai_protocol); + if (sfd == \-1) + continue; - if (bind(sfd, rp\->ai_addr, rp\->ai_addrlen) == 0) - break; /* Success */ + if (bind(sfd, rp\->ai_addr, rp\->ai_addrlen) == 0) + goto out; /* Success */ - close(sfd); + close(sfd); + } } +out: if (rp == NULL) { /* No address succeeded */ fprintf(stderr, "Could not bind\\n"); exit(EXIT_FAILURE);