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;
}

Reply via email to