I've made the patch below which takes care of the problem for me. I have tried several different versions, I didn't really like any of them. This code is one of the rare pieces of code that is rather well structured and relatively free of any ugly hacks. This fix makes it a lot uglier, what I particularly don't like is that it now depends on the order in which the listeners for the different protocols are created.
I've tried several different solutions including the use if getaddrinfo(), everything made this code more ugly. Any better solutions are welcome. If there are none, I'll commit this code. Egbert.
Index: Xtrans.c =================================================================== RCS file: /home/x-cvs/xc/lib/xtrans/Xtrans.c,v retrieving revision 3.31 diff -u -w -r3.31 Xtrans.c --- Xtrans.c 20 Jul 2003 16:12:15 -0000 3.31 +++ Xtrans.c 23 Jul 2003 13:35:40 -0000 @@ -90,10 +90,10 @@ #endif /* STREAMSCONN */ #if defined(TCPCONN) { &TRANS(SocketTCPFuncs), TRANS_SOCKET_TCP_INDEX }, - { &TRANS(SocketINETFuncs), TRANS_SOCKET_INET_INDEX }, #if defined(IPv6) && defined(AF_INET6) { &TRANS(SocketINET6Funcs), TRANS_SOCKET_INET6_INDEX }, #endif /* IPv6 */ + { &TRANS(SocketINETFuncs), TRANS_SOCKET_INET_INDEX }, #endif /* TCPCONN */ #if defined(DNETCONN) { &TRANS(DNETFuncs), TRANS_DNET_INDEX }, @@ -768,10 +768,10 @@ #ifdef TRANS_SERVER int -TRANS(CreateListener) (XtransConnInfo ciptr, char *port) +TRANS(CreateListener) (XtransConnInfo ciptr, char *port, unsigned int flags) { - return ciptr->transptr->CreateListener (ciptr, port); + return ciptr->transptr->CreateListener (ciptr, port, flags); } int @@ -1037,6 +1037,9 @@ char buffer[256]; /* ??? What size ?? */ XtransConnInfo ciptr, temp_ciptrs[NUMTRANS]; int status, i, j; +#if defined (linux) && defined(IPv6) && defined(AF_INET6) + Bool ipv6_succ = FALSE; +#endif PRMSG (2,"MakeAllCOTSServerListeners(%s,%p)\n", port ? port : "NULL", ciptrs_ret, 0); @@ -1046,6 +1049,7 @@ for (i = 0; i < NUMTRANS; i++) { Xtransport *trans = Xtransports[i].transport; + unsigned int flags = 0; if (trans->flags&TRANS_ALIAS || trans->flags&TRANS_NOLISTEN) continue; @@ -1065,8 +1069,13 @@ trans->TransName, 0, 0); continue; } +#if defined (linux) && defined(IPv6) && defined(AF_INET6) + if ((Xtransports[i].transport_id == TRANS_SOCKET_INET_INDEX + && ipv6_succ)) + flags |= ADDR_IN_USE_ALLOWED; +#endif - if ((status = TRANS(CreateListener (ciptr, port))) < 0) + if ((status = TRANS(CreateListener (ciptr, port, flags))) < 0) { if (status == TRANS_ADDR_IN_USE) { @@ -1098,6 +1107,11 @@ } } +#if defined (linux) && defined(IPv6) && defined(AF_INET6) + if (Xtransports[i].transport_id == TRANS_SOCKET_INET6_INDEX) + ipv6_succ = TRUE; +#endif + PRMSG (5, "MakeAllCOTSServerListeners: opened listener for %s, %d\n", trans->TransName, ciptr->fd, 0); @@ -1165,7 +1179,7 @@ continue; } - if ((status = TRANS(CreateListener (ciptr, port))) < 0) + if ((status = TRANS(CreateListener (ciptr, port, 0))) < 0) { if (status == TRANS_ADDR_IN_USE) { Index: Xtrans.h =================================================================== RCS file: /home/x-cvs/xc/lib/xtrans/Xtrans.h,v retrieving revision 3.21 diff -u -w -r3.21 Xtrans.h --- Xtrans.h 20 Jul 2003 16:12:15 -0000 3.21 +++ Xtrans.h 23 Jul 2003 13:35:41 -0000 @@ -339,7 +339,8 @@ int TRANS(CreateListener)( XtransConnInfo, /* ciptr */ - char * /* port */ + char *, /* port */ + unsigned int /* flags */ ); int TRANS(NoListen) ( Index: Xtransint.h =================================================================== RCS file: /home/x-cvs/xc/lib/xtrans/Xtransint.h,v retrieving revision 3.35 diff -u -w -r3.35 Xtransint.h --- Xtransint.h 26 Nov 2002 01:12:30 -0000 3.35 +++ Xtransint.h 23 Jul 2003 13:35:41 -0000 @@ -26,7 +26,7 @@ from The Open Group. */ -/* $XFree86: xc/lib/xtrans/Xtransint.h,v 3.35 2002/11/26 01:12:30 dawes Exp $ */ +/* $XFree86: xc/lib/xtrans/Xtransint.h,v 3.34 2002/11/20 23:00:36 dawes Exp $ */ /* Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA * @@ -283,10 +283,13 @@ ); #ifdef TRANS_SERVER +/* Flags */ +# define ADDR_IN_USE_ALLOWED 1 int (*CreateListener)( XtransConnInfo, /* connection */ - char * /* port */ + char *, /* port */ + unsigned int /* flags */ ); int (*ResetListener)( Index: Xtranssock.c =================================================================== RCS file: /home/x-cvs/xc/lib/xtrans/Xtranssock.c,v retrieving revision 3.59 diff -u -w -r3.59 Xtranssock.c --- Xtranssock.c 18 Jul 2003 15:39:48 -0000 3.59 +++ Xtranssock.c 23 Jul 2003 13:35:41 -0000 @@ -783,7 +783,8 @@ static int TRANS(SocketCreateListener) (XtransConnInfo ciptr, - struct sockaddr *sockname, int socknamelen) + struct sockaddr *sockname, + int socknamelen, unsigned int flags) { int namelen = socknamelen; @@ -803,7 +804,10 @@ while (bind (fd, (struct sockaddr *) sockname, namelen) < 0) { - if (errno == EADDRINUSE) + if (errno == EADDRINUSE) { + if (flags & ADDR_IN_USE_ALLOWED) + break; + } else return TRANS_ADDR_IN_USE; if (retry-- == 0) { @@ -853,7 +857,7 @@ #ifdef TCPCONN static int -TRANS(SocketINETCreateListener) (XtransConnInfo ciptr, char *port) +TRANS(SocketINETCreateListener) (XtransConnInfo ciptr, char *port, unsigned int flags) { #if defined(IPv6) && defined(AF_INET6) @@ -958,7 +962,7 @@ #endif if ((status = TRANS(SocketCreateListener) (ciptr, - (struct sockaddr *) &sockname, namelen)) < 0) + (struct sockaddr *) &sockname, namelen, flags)) < 0) { PRMSG (1, "SocketINETCreateListener: ...SocketCreateListener() failed\n", @@ -983,7 +987,8 @@ #ifdef UNIXCONN static int -TRANS(SocketUNIXCreateListener) (XtransConnInfo ciptr, char *port) +TRANS(SocketUNIXCreateListener) (XtransConnInfo ciptr, char *port, + unsigned int flags) { struct sockaddr_un sockname; @@ -1034,7 +1039,7 @@ unlink (sockname.sun_path); if ((status = TRANS(SocketCreateListener) (ciptr, - (struct sockaddr *) &sockname, namelen)) < 0) + (struct sockaddr *) &sockname, namelen, flags)) < 0) { PRMSG (1, "SocketUNIXCreateListener: ...SocketCreateListener() failed\n",