Re: broken IPv6 code
In article <[🔎] 84n1dcqjnq.fsf@snoopy.apana.org.au> (at 01 Jan 2001 10:02:17 +1100), Brian May <bam@debian.org> says:
> Then again, what is the correct way of doing this on Linux?
:
> [...]
> for (i = 0, a = ai; a != NULL; a = a->ai_next) {
> fds[i] = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
> [...]
> socket_set_reuseaddr (fds[i], 1);
> [...]
> bind (fds[i], a->ai_addr, a->ai_addrlen);
> [...]
> listen (fds[i], SOMAXCONN);
> [...]
> }
If it ignores bind failure on ipv4 socket, it is one of the most common
way to make server socket(s).
> Is this wrong? If it is, then perhaps the link to the bad web page
> should be removed?
No.
I usually use codes like following ones for "loose" applications:
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
gai = getaddrinfo(host, port, &hints, &res0);
if (gai){
err(1, "getaddrinfo() for host %s serv %s: %s",
host ? host : "NULL", serv ? serv : "NULL,
gai_strerror(gai));
}
socklist = NULL;
socknum = 0;
for (res=res0; res; res=res->ai_next){
int s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (s < 0){
warn("socket()");
continue;
}
if (bind(s, res->ai_addr, res->ai_addrlen) < 0){
warn("bind()");
close(s);
continue;
}
if (listen(s, 5) < 0){
warn("listen()");
close(s);
continue;
}
newlist = realloc(sizeof(int) * (socknum+1));
if (!newlist){
warn("realloc()");
close(s);
continue;
}
socklist = newlist;
socklist[socknum++] = s;
}
if (!socknum){
err(1, "cannot bind/listen to any socket");
}
On systems whose ipv4 port number is separated from ipv6 one,
some "strict" application may want to exit bind failure because
it indicates "real" failure on binding; other process running
on the same port. They, such "strict" application, cannot be
portable and autoconf (or runtime option) is needed; to give them
knowledge of bind(2) behavior.
For strict applications, we must consider 3 things (at least):
A.bind behavior
1) bind for ipv6
2) bind for ipv4
3) bind for ipv6 -> bind for ipv4
4) bind for ipv4 -> bind for ipv6
5) others
B.traffic delivery for each A.
1) ipv4 traffic
2) ipv6 traffic
3) others
C.getaddrinfo behvior
1) ipv6->ipv4
2) ipv4->ipv6
3) others
One solution is that; first, do bind ipv6 to wildcard,
and next, bind ipv4 sockets to each ipv4 address assigned
to the node. This is the ISC bind's solution, but nasty... sigh.
--
Hideaki YOSHIFUJI @ USAGI Project <yoshfuji@linux-ipv6.org>
PGP5i FP: F731 6599 5EB2 BBA7 1515 1323 1806 A96F 5700 6B25
Reply to: