IPv6 with Apache on tru64 has been broken for a while now, and I finally got round to figuring out what it was. It appears that Tru64's getaddrinfo returns ai_addrlen of 32 for AF_INET6 address, but that sizeof(struct sockaddr_in6) is 28.
This meant that apr_sockaddr_vars_set() was blindly setting salen to 28, and then later when Apache called bind( , , 28) Tru64 bombed out in unpleasant error land. Patch attached. Since preserving the value for addrlen returned by getaddrinfo is a good idea in any event I havn't made this #ifdef OSF1, there may be more systems which rely on this behaviour and there's nothing in the standards prohibiting it. Also attached is a C prog to test which systems behave in this manner; bash-2.05a$ uname -a OSF1 athene.heanet.ie V5.1 732 alpha bash-2.05a$ gcc -o madness madness.c bash-2.05a$ ./madness sizeof(struct sockaddr_in6) = 28 addrinfo->ai_addrlen = 32 -- Colm MacCárthaigh Public Key: [EMAIL PROTECTED] [EMAIL PROTECTED] http://www.stdlib.net/
Index: srclib/apr/network_io/unix/sockaddr.c =================================================================== RCS file: /home/cvspublic/apr/network_io/unix/sockaddr.c,v retrieving revision 1.42 diff -u -r1.42 sockaddr.c --- srclib/apr/network_io/unix/sockaddr.c 15 Aug 2003 02:21:55 -0000 1.42 +++ srclib/apr/network_io/unix/sockaddr.c 25 Aug 2003 15:27:53 -0000 @@ -429,6 +429,14 @@ new_sa->pool = p; memcpy(&new_sa->sa, ai->ai_addr, ai->ai_addrlen); apr_sockaddr_vars_set(new_sa, ai->ai_family, port); + + /* Over-rule the value set by apr_sockaddr_vars_set; + * sizeof(struct sockaddr_in6) != ai_addrlen for + * AF_INET6 on some systems (Tru64). This would lead + * to an error when we try to bind() without the right + * Address Length. + */ + new_sa->salen = ai->ai_addrlen; if (!prev_sa) { /* first element in new list */ if (hostname) {
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <string.h> #include <stdio.h> int main(int argc, char **argv) { struct addrinfo hints; struct addrinfo * res; int error; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET6; hints.ai_flags = AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; if ((error = getaddrinfo(NULL, "80", &hints, &res)) < 0) { fprintf(stderr, "%s: error in getaddrinfo: %s\n", argv[0], gai_strerror(error)); exit(1); } printf("sizeof(struct sockaddr_in6) = %d\n", sizeof(struct sockaddr_in6)); printf("addrinfo->ai_addrlen = %d\n", res->ai_addrlen); return 0; }