summaryrefslogtreecommitdiff
path: root/Xtranssock.c
diff options
context:
space:
mode:
Diffstat (limited to 'Xtranssock.c')
-rw-r--r--Xtranssock.c647
1 files changed, 495 insertions, 152 deletions
diff --git a/Xtranssock.c b/Xtranssock.c
index 50098f5..bacb8da 100644
--- a/Xtranssock.c
+++ b/Xtranssock.c
@@ -2,6 +2,7 @@
/*
Copyright 1993, 1994, 1998 The Open Group
+Copyright 2002 Sun Microsystems, Inc. All rights reserved.
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
@@ -20,13 +21,13 @@ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
-Except as contained in this notice, the name of The Open Group shall
+Except as contained in this notice, the name of the copyright holders shall
not be used in advertising or otherwise to promote the sale, use or
other dealings in this Software without prior written authorization
-from The Open Group.
+from the copyright holders.
*/
-/* $XFree86: xc/lib/xtrans/Xtranssock.c,v 3.56 2002/11/26 01:12:30 dawes Exp $ */
+/* $XFree86: xc/lib/xtrans/Xtranssock.c,v 3.65 2003/11/20 00:41:37 dawes Exp $ */
/* Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA
*
@@ -59,7 +60,9 @@ from The Open Group.
#ifndef WIN32
#if defined(TCPCONN) || defined(UNIXCONN)
+#include <sys/socket.h>
#include <netinet/in.h>
+#include <arpa/inet.h>
#endif
#if defined(TCPCONN) || defined(UNIXCONN)
@@ -84,10 +87,11 @@ from The Open Group.
#endif
#ifndef NO_TCP_H
-#ifdef __osf__
+#if defined(__osf__) || defined(linux)
#include <sys/param.h>
#endif /* osf */
#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
+#include <sys/param.h>
#include <machine/endian.h>
#endif /* __NetBSD__ || __OpenBSD__ || __FreeBSD__ */
#include <netinet/tcp.h>
@@ -98,7 +102,7 @@ from The Open Group.
#include <sys/filio.h>
#endif
-#if (defined(i386) && defined(SYSV)) && !defined(sco)
+#if (defined(i386) && defined(SYSV)) && !defined(sco) && !defined(sun)
#include <net/errno.h>
#endif
@@ -184,7 +188,13 @@ typedef struct _Sockettrans2dev {
static Sockettrans2dev Sockettrans2devtab[] = {
#ifdef TCPCONN
{"inet",AF_INET,SOCK_STREAM,SOCK_DGRAM,0},
+#if !defined(IPv6) || !defined(AF_INET6)
{"tcp",AF_INET,SOCK_STREAM,SOCK_DGRAM,0},
+#else /* IPv6 */
+ {"tcp",AF_INET6,SOCK_STREAM,SOCK_DGRAM,0},
+ {"tcp",AF_INET,SOCK_STREAM,SOCK_DGRAM,0}, /* fallback */
+ {"inet6",AF_INET6,SOCK_STREAM,SOCK_DGRAM,0},
+#endif
#endif /* TCPCONN */
#ifdef UNIXCONN
{"unix",AF_UNIX,SOCK_STREAM,SOCK_DGRAM,0},
@@ -262,24 +272,33 @@ static Sockettrans2dev Sockettrans2devtab[] = {
#define PORTBUFSIZE 32
/*
+ * This provides compatibility for apps linked against system libraries
+ * that don't have IPv6 support.
+ */
+#if defined(IPv6) && defined(AF_INET6)
+static const struct in6_addr local_in6addr_any = IN6ADDR_ANY_INIT;
+#pragma weak in6addr_any = local_in6addr_any
+#endif
+
+/*
* These are some utility function used by the real interface function below.
*/
static int
-TRANS(SocketSelectFamily) (char *family)
+TRANS(SocketSelectFamily) (int first, char *family)
{
int i;
PRMSG (3,"SocketSelectFamily(%s)\n", family, 0, 0);
- for (i = 0; i < NUMSOCKETFAMILIES;i++)
+ for (i = first + 1; i < NUMSOCKETFAMILIES;i++)
{
if (!strcmp (family, Sockettrans2devtab[i].transname))
return i;
}
- return -1;
+ return (first == -1 ? -2 : -1);
}
@@ -292,14 +311,18 @@ static int
TRANS(SocketINETGetAddr) (XtransConnInfo ciptr)
{
+#if defined(IPv6) && defined(AF_INET6)
+ struct sockaddr_storage sockname;
+#else
struct sockaddr_in sockname;
+#endif
#if defined(SVR4) || defined(SCO325)
size_t namelen = sizeof sockname;
#else
int namelen = sizeof sockname;
#endif
- PRMSG (3,"SocketINETGetAddr(%x)\n", ciptr, 0, 0);
+ PRMSG (3,"SocketINETGetAddr(%p)\n", ciptr, 0, 0);
if (getsockname (ciptr->fd,(struct sockaddr *) &sockname,
(void *)&namelen) < 0)
@@ -321,7 +344,11 @@ TRANS(SocketINETGetAddr) (XtransConnInfo ciptr)
return -1;
}
+#if defined(IPv6) && defined(AF_INET6)
+ ciptr->family = ((struct sockaddr *)&sockname)->sa_family;
+#else
ciptr->family = sockname.sin_family;
+#endif
ciptr->addrlen = namelen;
memcpy (ciptr->addr, &sockname, ciptr->addrlen);
@@ -338,14 +365,18 @@ static int
TRANS(SocketINETGetPeerAddr) (XtransConnInfo ciptr)
{
+#if defined(IPv6) && defined(AF_INET6)
+ struct sockaddr_storage sockname;
+#else
struct sockaddr_in sockname;
+#endif
#if defined(SVR4) || defined(SCO325)
size_t namelen = sizeof sockname;
#else
int namelen = sizeof sockname;
#endif
- PRMSG (3,"SocketINETGetPeerAddr(%x)\n", ciptr, 0, 0);
+ PRMSG (3,"SocketINETGetPeerAddr(%p)\n", ciptr, 0, 0);
if (getpeername (ciptr->fd, (struct sockaddr *) &sockname,
(void *)&namelen) < 0)
@@ -397,7 +428,7 @@ TRANS(SocketOpen) (int i, int type)
#endif
#endif
) {
- PRMSG (1, "SocketOpen: socket() failed for %s\n",
+ PRMSG (2, "SocketOpen: socket() failed for %s\n",
Sockettrans2devtab[i].transname, 0, 0);
xfree ((char *) ciptr);
@@ -405,7 +436,11 @@ TRANS(SocketOpen) (int i, int type)
}
#ifdef TCP_NODELAY
- if (Sockettrans2devtab[i].family == AF_INET)
+ if (Sockettrans2devtab[i].family == AF_INET
+#if defined(IPv6) && defined(AF_INET6)
+ || Sockettrans2devtab[i].family == AF_INET6
+#endif
+ )
{
/*
* turn off TCP coalescence for INET sockets
@@ -458,26 +493,25 @@ TRANS(SocketOpenCOTSClient) (Xtransport *thistrans, char *protocol,
{
XtransConnInfo ciptr;
- int i;
+ int i = -1;
PRMSG (2, "SocketOpenCOTSClient(%s,%s,%s)\n",
protocol, host, port);
SocketInitOnce();
- if ((i = TRANS(SocketSelectFamily) (thistrans->TransName)) < 0)
- {
- PRMSG (1,
- "SocketOpenCOTSClient: Unable to determine socket type for %s\n",
- thistrans->TransName, 0, 0);
- return NULL;
+ while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
+ if ((ciptr = TRANS(SocketOpen) (
+ i, Sockettrans2devtab[i].devcotsname)) != NULL)
+ break;
}
-
- if ((ciptr = TRANS(SocketOpen) (
- i, Sockettrans2devtab[i].devcotsname)) == NULL)
- {
- PRMSG (1,"SocketOpenCOTSClient: Unable to open socket for %s\n",
- thistrans->TransName, 0, 0);
+ if (i < 0) {
+ if (i == -1)
+ PRMSG (1,"SocketOpenCOTSClient: Unable to open socket for %s\n",
+ thistrans->TransName, 0, 0);
+ else
+ PRMSG (1,"SocketOpenCOTSClient: Unable to determine socket type for %s\n",
+ thistrans->TransName, 0, 0);
return NULL;
}
@@ -499,25 +533,24 @@ TRANS(SocketOpenCOTSServer) (Xtransport *thistrans, char *protocol,
{
XtransConnInfo ciptr;
- int i;
+ int i = -1;
PRMSG (2,"SocketOpenCOTSServer(%s,%s,%s)\n", protocol, host, port);
SocketInitOnce();
- if ((i = TRANS(SocketSelectFamily) (thistrans->TransName)) < 0)
- {
- PRMSG (1,
- "SocketOpenCOTSServer: Unable to determine socket type for %s\n",
- thistrans->TransName, 0, 0);
- return NULL;
+ while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
+ if ((ciptr = TRANS(SocketOpen) (
+ i, Sockettrans2devtab[i].devcotsname)) != NULL)
+ break;
}
-
- if ((ciptr = TRANS(SocketOpen) (
- i, Sockettrans2devtab[i].devcotsname)) == NULL)
- {
- PRMSG (1,"SocketOpenCOTSServer: Unable to open socket for %s\n",
- thistrans->TransName, 0, 0);
+ if (i < 0) {
+ if (i == -1)
+ PRMSG (1,"SocketOpenCOTSServer: Unable to open socket for %s\n",
+ thistrans->TransName, 0, 0);
+ else
+ PRMSG (1,"SocketOpenCOTSServer: Unable to determine socket type for %s\n",
+ thistrans->TransName, 0, 0);
return NULL;
}
@@ -528,17 +561,27 @@ TRANS(SocketOpenCOTSServer) (Xtransport *thistrans, char *protocol,
#ifdef SO_REUSEADDR
/*
- * SO_REUSEADDR only applied to AF_INET
+ * SO_REUSEADDR only applied to AF_INET && AF_INET6
*/
- if (Sockettrans2devtab[i].family == AF_INET)
+ if (Sockettrans2devtab[i].family == AF_INET
+#if defined(IPv6) && defined(AF_INET6)
+ || Sockettrans2devtab[i].family == AF_INET6
+#endif
+ )
{
int one = 1;
setsockopt (ciptr->fd, SOL_SOCKET, SO_REUSEADDR,
(char *) &one, sizeof (int));
}
#endif
-
+#ifdef IPV6_V6ONLY
+ if (Sockettrans2devtab[i].family == AF_INET6)
+ {
+ int one = 1;
+ setsockopt(ciptr->fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(int));
+ }
+#endif
/* Save the index for later use */
ciptr->index = i;
@@ -557,25 +600,24 @@ TRANS(SocketOpenCLTSClient) (Xtransport *thistrans, char *protocol,
{
XtransConnInfo ciptr;
- int i;
+ int i = -1;
PRMSG (2,"SocketOpenCLTSClient(%s,%s,%s)\n", protocol, host, port);
SocketInitOnce();
- if ((i = TRANS(SocketSelectFamily) (thistrans->TransName)) < 0)
- {
- PRMSG (1,
- "SocketOpenCLTSClient: Unable to determine socket type for %s\n",
- thistrans->TransName, 0, 0);
- return NULL;
+ while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
+ if ((ciptr = TRANS(SocketOpen) (
+ i, Sockettrans2devtab[i].devcotsname)) != NULL)
+ break;
}
-
- if ((ciptr = TRANS(SocketOpen) (
- i, Sockettrans2devtab[i].devcotsname)) == NULL)
- {
- PRMSG (1,"SocketOpenCLTSClient: Unable to open socket for %s\n",
- thistrans->TransName, 0, 0);
+ if (i < 0) {
+ if (i == -1)
+ PRMSG (1,"SocketOpenCLTSClient: Unable to open socket for %s\n",
+ thistrans->TransName, 0, 0);
+ else
+ PRMSG (1,"SocketOpenCLTSClient: Unable to determine socket type for %s\n",
+ thistrans->TransName, 0, 0);
return NULL;
}
@@ -597,28 +639,34 @@ TRANS(SocketOpenCLTSServer) (Xtransport *thistrans, char *protocol,
{
XtransConnInfo ciptr;
- int i;
+ int i = -1;
PRMSG (2,"SocketOpenCLTSServer(%s,%s,%s)\n", protocol, host, port);
SocketInitOnce();
- if ((i = TRANS(SocketSelectFamily) (thistrans->TransName)) < 0)
- {
- PRMSG (1,
- "SocketOpenCLTSServer: Unable to determine socket type for %s\n",
- thistrans->TransName, 0, 0);
+ while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
+ if ((ciptr = TRANS(SocketOpen) (
+ i, Sockettrans2devtab[i].devcotsname)) != NULL)
+ break;
+ }
+ if (i < 0) {
+ if (i == -1)
+ PRMSG (1,"SocketOpenCLTSServer: Unable to open socket for %s\n",
+ thistrans->TransName, 0, 0);
+ else
+ PRMSG (1,"SocketOpenCLTSServer: Unable to determine socket type for %s\n",
+ thistrans->TransName, 0, 0);
return NULL;
}
- if ((ciptr = TRANS(SocketOpen) (
- i, Sockettrans2devtab[i].devcotsname)) == NULL)
+#ifdef IPV6_V6ONLY
+ if (Sockettrans2devtab[i].family == AF_INET6)
{
- PRMSG (1,"SocketOpenCLTSServer: Unable to open socket for %s\n",
- thistrans->TransName, 0, 0);
- return NULL;
+ int one = 1;
+ setsockopt(ciptr->fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(int));
}
-
+#endif
/* Save the index for later use */
ciptr->index = i;
@@ -636,27 +684,25 @@ TRANS(SocketReopenCOTSServer) (Xtransport *thistrans, int fd, char *port)
{
XtransConnInfo ciptr;
- int i;
+ int i = -1;
PRMSG (2,
"SocketReopenCOTSServer(%d, %s)\n", fd, port, 0);
SocketInitOnce();
- if ((i = TRANS(SocketSelectFamily) (thistrans->TransName)) < 0)
- {
- PRMSG (1,
- "SocketReopenCOTSServer: Unable to determine socket type for %s\n",
- thistrans->TransName, 0, 0);
- return NULL;
+ while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
+ if ((ciptr = TRANS(SocketReopen) (
+ i, Sockettrans2devtab[i].devcotsname, fd, port)) != NULL)
+ break;
}
-
- if ((ciptr = TRANS(SocketReopen) (
- i, Sockettrans2devtab[i].devcotsname, fd, port)) == NULL)
- {
- PRMSG (1,
- "SocketReopenCOTSServer: Unable to reopen socket for %s\n",
- thistrans->TransName, 0, 0);
+ if (i < 0) {
+ if (i == -1)
+ PRMSG (1,"SocketReopenCOTSServer: Unable to open socket for %s\n",
+ thistrans->TransName, 0, 0);
+ else
+ PRMSG (1,"SocketReopenCOTSServer: Unable to determine socket type for %s\n",
+ thistrans->TransName, 0, 0);
return NULL;
}
@@ -672,27 +718,25 @@ TRANS(SocketReopenCLTSServer) (Xtransport *thistrans, int fd, char *port)
{
XtransConnInfo ciptr;
- int i;
+ int i = -1;
PRMSG (2,
"SocketReopenCLTSServer(%d, %s)\n", fd, port, 0);
SocketInitOnce();
- if ((i = TRANS(SocketSelectFamily) (thistrans->TransName)) < 0)
- {
- PRMSG (1,
- "SocketReopenCLTSServer: Unable to determine socket type for %s\n",
- thistrans->TransName, 0, 0);
- return NULL;
+ while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
+ if ((ciptr = TRANS(SocketReopen) (
+ i, Sockettrans2devtab[i].devcotsname, fd, port)) != NULL)
+ break;
}
-
- if ((ciptr = TRANS(SocketReopen) (
- i, Sockettrans2devtab[i].devcotsname, fd, port)) == NULL)
- {
- PRMSG (1,
- "SocketReopenCLTSServer: Unable to reopen socket for %s\n",
- thistrans->TransName, 0, 0);
+ if (i < 0) {
+ if (i == -1)
+ PRMSG (1,"SocketReopenCLTSServer: Unable to open socket for %s\n",
+ thistrans->TransName, 0, 0);
+ else
+ PRMSG (1,"SocketReopenCLTSServer: Unable to determine socket type for %s\n",
+ thistrans->TransName, 0, 0);
return NULL;
}
@@ -742,23 +786,31 @@ set_sun_path(const char *port, const char *upath, char *path)
static int
TRANS(SocketCreateListener) (XtransConnInfo ciptr,
- struct sockaddr *sockname, int socknamelen)
+ struct sockaddr *sockname,
+ int socknamelen, unsigned int flags)
{
int namelen = socknamelen;
int fd = ciptr->fd;
int retry;
- PRMSG (3, "SocketCreateListener(%x,%d)\n", ciptr, fd, 0);
+ PRMSG (3, "SocketCreateListener(%x,%p)\n", ciptr, fd, 0);
- if (Sockettrans2devtab[ciptr->index].family == AF_INET)
+ if (Sockettrans2devtab[ciptr->index].family == AF_INET
+#if defined(IPv6) && defined(AF_INET6)
+ || Sockettrans2devtab[ciptr->index].family == AF_INET6
+#endif
+ )
retry = 20;
else
retry = 0;
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) {
@@ -774,7 +826,11 @@ TRANS(SocketCreateListener) (XtransConnInfo ciptr,
#endif /* SO_REUSEDADDR */
}
- if (Sockettrans2devtab[ciptr->index].family == AF_INET) {
+ if (Sockettrans2devtab[ciptr->index].family == AF_INET
+#if defined(IPv6) && defined(AF_INET6)
+ || Sockettrans2devtab[ciptr->index].family == AF_INET6
+#endif
+ ) {
#ifdef SO_DONTLINGER
setsockopt (fd, SOL_SOCKET, SO_DONTLINGER, (char *) NULL, 0);
#else
@@ -804,10 +860,15 @@ TRANS(SocketCreateListener) (XtransConnInfo ciptr,
#ifdef TCPCONN
static int
-TRANS(SocketINETCreateListener) (XtransConnInfo ciptr, char *port)
+TRANS(SocketINETCreateListener) (XtransConnInfo ciptr, char *port, unsigned int flags)
{
- struct sockaddr_in sockname;
+#if defined(IPv6) && defined(AF_INET6)
+ struct sockaddr_storage sockname;
+#else
+ struct sockaddr_in sockname;
+#endif
+ unsigned short sport;
int namelen = sizeof(sockname);
int status;
long tmpport;
@@ -855,7 +916,7 @@ TRANS(SocketINETCreateListener) (XtransConnInfo ciptr, char *port)
return TRANS_CREATE_LISTENER_FAILED;
}
/* we trust getservbyname to return a valid number */
- sockname.sin_port = htons (servp->s_port);
+ sport = servp->s_port;
}
else
{
@@ -869,20 +930,42 @@ TRANS(SocketINETCreateListener) (XtransConnInfo ciptr, char *port)
if (tmpport < 1024 || tmpport > USHRT_MAX)
return TRANS_CREATE_LISTENER_FAILED;
- sockname.sin_port = htons (((unsigned short) tmpport));
+ sport = (unsigned short) tmpport;
}
}
else
- sockname.sin_port = htons (0);
+ sport = 0;
+ bzero(&sockname, sizeof(sockname));
+#if defined(IPv6) && defined(AF_INET6)
+ if (Sockettrans2devtab[ciptr->index].family == AF_INET) {
+ namelen = sizeof (struct sockaddr_in);
+#ifdef BSD44SOCKETS
+ ((struct sockaddr_in *)&sockname)->sin_len = namelen;
+#endif
+ ((struct sockaddr_in *)&sockname)->sin_family = AF_INET;
+ ((struct sockaddr_in *)&sockname)->sin_port = htons(sport);
+ ((struct sockaddr_in *)&sockname)->sin_addr.s_addr = htonl(INADDR_ANY);
+ } else {
+ namelen = sizeof (struct sockaddr_in6);
+#ifdef SIN6_LEN
+ ((struct sockaddr_in6 *)&sockname)->sin6_len = sizeof(sockname);
+#endif
+ ((struct sockaddr_in6 *)&sockname)->sin6_family = AF_INET6;
+ ((struct sockaddr_in6 *)&sockname)->sin6_port = htons(sport);
+ ((struct sockaddr_in6 *)&sockname)->sin6_addr = in6addr_any;
+ }
+#else
#ifdef BSD44SOCKETS
sockname.sin_len = sizeof (sockname);
#endif
sockname.sin_family = AF_INET;
+ sockname.sin_port = htons (sport);
sockname.sin_addr.s_addr = htonl (INADDR_ANY);
+#endif
if ((status = TRANS(SocketCreateListener) (ciptr,
- (struct sockaddr *) &sockname, namelen)) < 0)
+ (struct sockaddr *) &sockname, namelen, flags)) < 0)
{
PRMSG (1,
"SocketINETCreateListener: ...SocketCreateListener() failed\n",
@@ -907,7 +990,8 @@ TRANS(SocketINETCreateListener) (XtransConnInfo ciptr, char *port)
#ifdef UNIXCONN
static int
-TRANS(SocketUNIXCreateListener) (XtransConnInfo ciptr, char *port)
+TRANS(SocketUNIXCreateListener) (XtransConnInfo ciptr, char *port,
+ unsigned int flags)
{
struct sockaddr_un sockname;
@@ -958,7 +1042,7 @@ TRANS(SocketUNIXCreateListener) (XtransConnInfo ciptr, char *port)
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",
@@ -1008,7 +1092,7 @@ TRANS(SocketUNIXResetListener) (XtransConnInfo ciptr)
int status = TRANS_RESET_NOOP;
unsigned int mode;
- PRMSG (3, "SocketUNIXResetListener(%x,%d)\n", ciptr, ciptr->fd, 0);
+ PRMSG (3, "SocketUNIXResetListener(%p,%d)\n", ciptr, ciptr->fd, 0);
if (stat (unsock->sun_path, &statb) == -1 ||
((statb.st_mode & S_IFMT) !=
@@ -1080,7 +1164,7 @@ TRANS(SocketINETAccept) (XtransConnInfo ciptr, int *status)
struct sockaddr_in sockname;
int namelen = sizeof(sockname);
- PRMSG (2, "SocketINETAccept(%x,%d)\n", ciptr, ciptr->fd, 0);
+ PRMSG (2, "SocketINETAccept(%p,%d)\n", ciptr, ciptr->fd, 0);
if ((newciptr = (XtransConnInfo) xcalloc (
1, sizeof(struct _XtransConnInfo))) == NULL)
@@ -1160,7 +1244,7 @@ TRANS(SocketUNIXAccept) (XtransConnInfo ciptr, int *status)
int namelen = sizeof sockname;
#endif
- PRMSG (2, "SocketUNIXAccept(%x,%d)\n", ciptr, ciptr->fd, 0);
+ PRMSG (2, "SocketUNIXAccept(%p,%d)\n", ciptr, ciptr->fd, 0);
if ((newciptr = (XtransConnInfo) xcalloc (
1, sizeof(struct _XtransConnInfo))) == NULL)
@@ -1229,29 +1313,47 @@ TRANS(SocketUNIXAccept) (XtransConnInfo ciptr, int *status)
#ifdef TRANS_CLIENT
#ifdef TCPCONN
+
+#if defined(IPv6) && defined(AF_INET6)
+struct addrlist {
+ struct addrinfo * addr;
+ struct addrinfo * firstaddr;
+ char port[PORTBUFSIZE];
+ char host[MAXHOSTNAMELEN];
+};
+static struct addrlist *addrlist = NULL;
+#endif
+
+
static int
TRANS(SocketINETConnect) (XtransConnInfo ciptr, char *host, char *port)
{
- struct sockaddr_in sockname;
-#if defined(SVR4) || defined(SCO325)
- size_t namelen = sizeof sockname;
+ struct sockaddr * socketaddr = NULL;
+ int socketaddrlen = 0;
+ int res;
+#if defined(IPv6) && defined(AF_INET6)
+ struct addrinfo hints;
+ char ntopbuf[INET6_ADDRSTRLEN];
+ struct sockaddr_in6 tmpsin6;
+ int resetonce = 0;
#else
- int namelen = sizeof sockname;
-#endif
+ struct sockaddr_in sockname;
#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
_Xgethostbynameparams hparams;
_Xgetservbynameparams sparams;
#endif
struct hostent *hostp;
struct servent *servp;
-
+ unsigned long tmpaddr;
+#endif
#ifdef X11_t
char portbuf[PORTBUFSIZE];
#endif
+#if defined(X11_t) || !defined(IPv6) || !defined(AF_INET6)
long tmpport;
- unsigned long tmpaddr;
+#endif
char hostnamebuf[256]; /* tmp space */
PRMSG (2,"SocketINETConnect(%d,%s,%s)\n", ciptr->fd, host, port);
@@ -1281,6 +1383,116 @@ TRANS(SocketINETConnect) (XtransConnInfo ciptr, char *host, char *port)
}
#endif
+#if defined(IPv6) && defined(AF_INET6)
+ if (addrlist != NULL) {
+ if (strcmp(host,addrlist->host) || strcmp(port,addrlist->port)) {
+ if (addrlist->firstaddr)
+ freeaddrinfo(addrlist->firstaddr);
+ addrlist->firstaddr = NULL;
+ }
+ } else {
+ addrlist = malloc(sizeof(struct addrlist));
+ addrlist->firstaddr = NULL;
+ }
+
+ if (addrlist->firstaddr == NULL) {
+ strncpy(addrlist->port, port, sizeof(addrlist->port));
+ addrlist->port[sizeof(addrlist->port) - 1] = '\0';
+ strncpy(addrlist->host, host, sizeof(addrlist->host));
+ addrlist->host[sizeof(addrlist->host) - 1] = '\0';
+
+ bzero(&hints,sizeof(hints));
+ hints.ai_socktype = Sockettrans2devtab[ciptr->index].devcotsname;
+
+ res = getaddrinfo(host,port,&hints,&addrlist->firstaddr);
+ if (res != 0) {
+ PRMSG (1,
+ "TRANS(SocketINETConnect) () can't get address for %s:%s: %s\n",
+ host, port, gai_strerror(res));
+ ESET(EINVAL);
+ return TRANS_CONNECT_FAILED;
+ }
+ for (res = 0, addrlist->addr = addrlist->firstaddr; addrlist->addr ; res++) {
+ addrlist->addr = addrlist->addr->ai_next;
+ }
+ PRMSG(4,"Got New Address list with %d addresses\n", res, 0, 0);
+ res = 0;
+ addrlist->addr = NULL;
+ }
+
+ while ( socketaddr == NULL ) {
+ if (addrlist->addr == NULL) {
+ if (resetonce) {
+ /* Already checked entire list - no usable addresses */
+ PRMSG (1,
+ "TRANS(SocketINETConnect) () no usable address for %s:%s\n",
+ host, port, 0);
+ return TRANS_CONNECT_FAILED;
+ } else {
+ /* Go back to beginning of list */
+ resetonce = 1;
+ addrlist->addr = addrlist->firstaddr;
+ }
+ }
+
+
+ socketaddr = addrlist->addr->ai_addr;
+ socketaddrlen = addrlist->addr->ai_addrlen;
+
+ if (addrlist->addr->ai_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in *) socketaddr;
+
+ PRMSG (4,"TRANS(SocketINETConnect) sockname.sin_addr = %s\n",
+ inet_ntop(addrlist->addr->ai_family,&sin->sin_addr,
+ ntopbuf,sizeof(ntopbuf)), 0, 0);
+
+ PRMSG (4,"TRANS(SocketINETConnect) sockname.sin_port = %d\n",
+ ntohs(sin->sin_port), 0, 0);
+
+ if (Sockettrans2devtab[ciptr->index].family == AF_INET6) {
+ /* We have IPv6 socket, need to map IPv4 address to IPv6 */
+ char *v4addr = (char *) &sin->sin_addr.s_addr;
+ bzero(&tmpsin6, sizeof(tmpsin6));
+#ifdef SIN6_LEN
+ tmpsin6.sin6_len = sizeof(tmpsin6);
+#endif
+ tmpsin6.sin6_family = AF_INET6;
+ tmpsin6.sin6_port = sin->sin_port;
+ tmpsin6.sin6_addr.s6_addr[10] = 0xff;
+ tmpsin6.sin6_addr.s6_addr[11] = 0xff;
+ tmpsin6.sin6_addr.s6_addr[12] = v4addr[0];
+ tmpsin6.sin6_addr.s6_addr[13] = v4addr[1];
+ tmpsin6.sin6_addr.s6_addr[14] = v4addr[2];
+ tmpsin6.sin6_addr.s6_addr[15] = v4addr[3];
+
+ socketaddr = (struct sockaddr *) &tmpsin6;
+ socketaddrlen = sizeof(tmpsin6);
+ PRMSG (4,"TRANS(SocketINETConnect) sockname.sin6_addr = %s\n",
+ inet_ntop(AF_INET6, &tmpsin6.sin6_addr, ntopbuf,
+ sizeof(ntopbuf)), 0, 0);
+ }
+ } else if (addrlist->addr->ai_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) socketaddr;
+
+ PRMSG (4,"TRANS(SocketINETConnect) sockname.sin6_addr = %s\n",
+ inet_ntop(addrlist->addr->ai_family, &sin6->sin6_addr,ntopbuf,sizeof(ntopbuf)),
+ 0, 0);
+ PRMSG (4,"TRANS(SocketINETConnect) sockname.sin6_port = %d\n",
+ ntohs(sin6->sin6_port), 0, 0);
+
+ if (Sockettrans2devtab[ciptr->index].family == AF_INET) {
+ PRMSG (4,"TRANS(SocketINETConnect) Skipping IPv6 address\n",
+ 0,0,0);
+ socketaddr = NULL;
+ }
+ } else {
+ socketaddr = NULL; /* Unsupported address type */
+ }
+ if (socketaddr == NULL) {
+ addrlist->addr = addrlist->addr->ai_next;
+ }
+ }
+#else
/*
* Build the socket name.
*/
@@ -1305,7 +1517,7 @@ TRANS(SocketINETConnect) (XtransConnInfo ciptr, char *host, char *port)
PRMSG (4,"SocketINETConnect: inet_addr(%s) = %x\n",
host, tmpaddr, 0);
- if (tmpaddr == -1)
+ if ((long)tmpaddr == -1L)
{
if ((hostp = _XGethostbyname(host,hparams)) == NULL)
{
@@ -1371,6 +1583,9 @@ else
PRMSG (4,"SocketINETConnect: sockname.sin_port = %d\n",
ntohs(sockname.sin_port), 0, 0);
+ socketaddr = (struct sockaddr *) &sockname;
+ socketaddrlen = sizeof(sockname);
+#endif /* IPv6 */
/*
* Turn on socket keepalive so the client process will eventually
@@ -1393,7 +1608,7 @@ else
* Do the connect()
*/
- if (connect (ciptr->fd, (struct sockaddr *) &sockname, namelen) < 0)
+ if (connect (ciptr->fd, socketaddr, socketaddrlen ) < 0)
{
#ifdef WIN32
int olderrno = WSAGetLastError();
@@ -1410,43 +1625,65 @@ else
*
* If the error was EINTR, the connect was interrupted and we
* should try again.
+ *
+ * If multiple addresses are found for a host then we should
+ * try to connect again with a different address for a larger
+ * number of errors that made us quit before, since those
+ * could be caused by trying to use an IPv6 address to contact
+ * a machine with an IPv4-only server or other reasons that
+ * only affect one of a set of addresses.
*/
- if (olderrno == ECONNREFUSED || olderrno == EINTR)
- return TRANS_TRY_CONNECT_AGAIN;
+ if (olderrno == ECONNREFUSED || olderrno == EINTR
+#if defined(IPv6) && defined(AF_INET6)
+ || ( ((addrlist->addr->ai_next != NULL) ||
+ (addrlist->addr != addrlist->firstaddr)) &&
+ (olderrno == ENETUNREACH || olderrno == EAFNOSUPPORT ||
+ olderrno == EADDRNOTAVAIL || olderrno == ETIMEDOUT))
+#endif
+ )
+ res = TRANS_TRY_CONNECT_AGAIN;
else if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS)
- return TRANS_IN_PROGRESS;
+ res = TRANS_IN_PROGRESS;
else
{
PRMSG (2,"SocketINETConnect: Can't connect: errno = %d\n",
olderrno,0, 0);
- return TRANS_CONNECT_FAILED;
+ res = TRANS_CONNECT_FAILED;
}
- }
+ } else {
+ res = 0;
- /*
- * Sync up the address fields of ciptr.
- */
+ /*
+ * Sync up the address fields of ciptr.
+ */
- if (TRANS(SocketINETGetAddr) (ciptr) < 0)
- {
- PRMSG (1,
- "SocketINETConnect: ...SocketINETGetAddr() failed:\n",
- 0, 0, 0);
- return TRANS_CONNECT_FAILED;
- }
+ if (TRANS(SocketINETGetAddr) (ciptr) < 0)
+ {
+ PRMSG (1,
+ "SocketINETConnect: ...SocketINETGetAddr() failed:\n",
+ 0, 0, 0);
+ res = TRANS_CONNECT_FAILED;
+ }
- if (TRANS(SocketINETGetPeerAddr) (ciptr) < 0)
- {
- PRMSG (1,
- "SocketINETConnect: ...SocketINETGetPeerAddr() failed:\n",
+ else if (TRANS(SocketINETGetPeerAddr) (ciptr) < 0)
+ {
+ PRMSG (1,
+ "SocketINETConnect: ...SocketINETGetPeerAddr() failed:\n",
0, 0, 0);
- return TRANS_CONNECT_FAILED;
+ res = TRANS_CONNECT_FAILED;
+ }
}
- return 0;
+#if defined(IPv6) && defined(AF_INET6)
+ if (res != 0) {
+ addrlist->addr = addrlist->addr->ai_next;
+ }
+#endif
+
+ return res;
}
#endif /* TCPCONN */
@@ -1473,6 +1710,53 @@ UnixHostReallyLocal (char *host)
}
else
{
+#if defined(IPv6) && defined(AF_INET6)
+ struct addrinfo *localhostaddr;
+ struct addrinfo *otherhostaddr;
+ struct addrinfo *i, *j;
+ int equiv = 0;
+
+ if (getaddrinfo(hostnamebuf, NULL, NULL, &localhostaddr) != 0)
+ return 0;
+ if (getaddrinfo(host, NULL, NULL, &otherhostaddr) != 0) {
+ freeaddrinfo(localhostaddr);
+ return 0;
+ }
+
+ for (i = localhostaddr; i != NULL && equiv == 0; i = i->ai_next) {
+ for (j = otherhostaddr; j != NULL && equiv == 0; j = j->ai_next) {
+ if (i->ai_family == j->ai_family) {
+ if (i->ai_family == AF_INET) {
+ struct sockaddr_in *sinA
+ = (struct sockaddr_in *) i->ai_addr;
+ struct sockaddr_in *sinB
+ = (struct sockaddr_in *) j->ai_addr;
+ struct in_addr *A = &sinA->sin_addr;
+ struct in_addr *B = &sinB->sin_addr;
+
+ if (memcmp(A,B,sizeof(struct in_addr)) == 0) {
+ equiv = 1;
+ }
+ } else if (i->ai_family == AF_INET6) {
+ struct sockaddr_in6 *sinA
+ = (struct sockaddr_in6 *) i->ai_addr;
+ struct sockaddr_in6 *sinB
+ = (struct sockaddr_in6 *) j->ai_addr;
+ struct in6_addr *A = &sinA->sin6_addr;
+ struct in6_addr *B = &sinB->sin6_addr;
+
+ if (memcmp(A,B,sizeof(struct in6_addr)) == 0) {
+ equiv = 1;
+ }
+ }
+ }
+ }
+ }
+
+ freeaddrinfo(localhostaddr);
+ freeaddrinfo(otherhostaddr);
+ return equiv;
+#else
/*
* A host may have more than one network address. If any of the
* network addresses of 'host' (specified to the connect call)
@@ -1542,6 +1826,7 @@ UnixHostReallyLocal (char *host)
}
return (equiv);
+#endif
}
}
@@ -1703,7 +1988,7 @@ static int
TRANS(SocketBytesReadable) (XtransConnInfo ciptr, BytesReadable_t *pend)
{
- PRMSG (2,"SocketBytesReadable(%x,%d,%x)\n",
+ PRMSG (2,"SocketBytesReadable(%p,%d,%p)\n",
ciptr, ciptr->fd, pend);
#if defined(QNX4)
*pend = 0L; /* FIONREAD only returns a short. Zero out upper bits */
@@ -1728,7 +2013,7 @@ static int
TRANS(SocketRead) (XtransConnInfo ciptr, char *buf, int size)
{
- PRMSG (2,"SocketRead(%d,%x,%d)\n", ciptr->fd, buf, size);
+ PRMSG (2,"SocketRead(%d,%p,%d)\n", ciptr->fd, buf, size);
#if defined(WIN32) || defined(__UNIXOS2__)
return recv ((SOCKET)ciptr->fd, buf, size, 0);
@@ -1742,7 +2027,7 @@ static int
TRANS(SocketWrite) (XtransConnInfo ciptr, char *buf, int size)
{
- PRMSG (2,"SocketWrite(%d,%x,%d)\n", ciptr->fd, buf, size);
+ PRMSG (2,"SocketWrite(%d,%p,%d)\n", ciptr->fd, buf, size);
#if defined(WIN32) || defined(__UNIXOS2__)
return send ((SOCKET)ciptr->fd, buf, size, 0);
@@ -1756,7 +2041,7 @@ static int
TRANS(SocketReadv) (XtransConnInfo ciptr, struct iovec *buf, int size)
{
- PRMSG (2,"SocketReadv(%d,%x,%d)\n", ciptr->fd, buf, size);
+ PRMSG (2,"SocketReadv(%d,%p,%d)\n", ciptr->fd, buf, size);
return READV (ciptr, buf, size);
}
@@ -1766,7 +2051,7 @@ static int
TRANS(SocketWritev) (XtransConnInfo ciptr, struct iovec *buf, int size)
{
- PRMSG (2,"SocketWritev(%d,%x,%d)\n", ciptr->fd, buf, size);
+ PRMSG (2,"SocketWritev(%d,%p,%d)\n", ciptr->fd, buf, size);
return WRITEV (ciptr, buf, size);
}
@@ -1776,7 +2061,7 @@ static int
TRANS(SocketDisconnect) (XtransConnInfo ciptr)
{
- PRMSG (2,"SocketDisconnect(%x,%d)\n", ciptr, ciptr->fd, 0);
+ PRMSG (2,"SocketDisconnect(%p,%d)\n", ciptr, ciptr->fd, 0);
return shutdown (ciptr->fd, 2); /* disallow further sends and receives */
}
@@ -1787,7 +2072,7 @@ static int
TRANS(SocketINETClose) (XtransConnInfo ciptr)
{
- PRMSG (2,"SocketINETClose(%x,%d)\n", ciptr, ciptr->fd, 0);
+ PRMSG (2,"SocketINETClose(%p,%d)\n", ciptr, ciptr->fd, 0);
return close (ciptr->fd);
}
@@ -1809,7 +2094,7 @@ TRANS(SocketUNIXClose) (XtransConnInfo ciptr)
char path[200]; /* > sizeof sun_path +1 */
int ret;
- PRMSG (2,"SocketUNIXClose(%x,%d)\n", ciptr, ciptr->fd, 0);
+ PRMSG (2,"SocketUNIXClose(%p,%d)\n", ciptr, ciptr->fd, 0);
ret = close(ciptr->fd);
@@ -1837,7 +2122,7 @@ TRANS(SocketUNIXCloseForCloning) (XtransConnInfo ciptr)
int ret;
- PRMSG (2,"SocketUNIXCloseForCloning(%x,%d)\n",
+ PRMSG (2,"SocketUNIXCloseForCloning(%p,%d)\n",
ciptr, ciptr->fd, 0);
ret = close(ciptr->fd);
@@ -1849,14 +2134,19 @@ TRANS(SocketUNIXCloseForCloning) (XtransConnInfo ciptr)
#ifdef TCPCONN
+# ifdef TRANS_SERVER
+static char* tcp_nolisten[] = { "inet", "inet6", NULL };
+# endif
+
Xtransport TRANS(SocketTCPFuncs) = {
/* Socket Interface */
"tcp",
- 0,
+ TRANS_ALIAS,
#ifdef TRANS_CLIENT
TRANS(SocketOpenCOTSClient),
#endif /* TRANS_CLIENT */
#ifdef TRANS_SERVER
+ tcp_nolisten,
TRANS(SocketOpenCOTSServer),
#endif /* TRANS_SERVER */
#ifdef TRANS_CLIENT
@@ -1891,11 +2181,12 @@ Xtransport TRANS(SocketTCPFuncs) = {
Xtransport TRANS(SocketINETFuncs) = {
/* Socket Interface */
"inet",
- TRANS_ALIAS,
+ 0,
#ifdef TRANS_CLIENT
TRANS(SocketOpenCOTSClient),
#endif /* TRANS_CLIENT */
#ifdef TRANS_SERVER
+ NULL,
TRANS(SocketOpenCOTSServer),
#endif /* TRANS_SERVER */
#ifdef TRANS_CLIENT
@@ -1927,6 +2218,47 @@ Xtransport TRANS(SocketINETFuncs) = {
TRANS(SocketINETClose),
};
+#if defined(IPv6) && defined(AF_INET6)
+Xtransport TRANS(SocketINET6Funcs) = {
+ /* Socket Interface */
+ "inet6",
+ 0,
+#ifdef TRANS_CLIENT
+ TRANS(SocketOpenCOTSClient),
+#endif /* TRANS_CLIENT */
+#ifdef TRANS_SERVER
+ NULL,
+ TRANS(SocketOpenCOTSServer),
+#endif /* TRANS_SERVER */
+#ifdef TRANS_CLIENT
+ TRANS(SocketOpenCLTSClient),
+#endif /* TRANS_CLIENT */
+#ifdef TRANS_SERVER
+ TRANS(SocketOpenCLTSServer),
+#endif /* TRANS_SERVER */
+#ifdef TRANS_REOPEN
+ TRANS(SocketReopenCOTSServer),
+ TRANS(SocketReopenCLTSServer),
+#endif
+ TRANS(SocketSetOption),
+#ifdef TRANS_SERVER
+ TRANS(SocketINETCreateListener),
+ NULL, /* ResetListener */
+ TRANS(SocketINETAccept),
+#endif /* TRANS_SERVER */
+#ifdef TRANS_CLIENT
+ TRANS(SocketINETConnect),
+#endif /* TRANS_CLIENT */
+ TRANS(SocketBytesReadable),
+ TRANS(SocketRead),
+ TRANS(SocketWrite),
+ TRANS(SocketReadv),
+ TRANS(SocketWritev),
+ TRANS(SocketDisconnect),
+ TRANS(SocketINETClose),
+ TRANS(SocketINETClose),
+ };
+#endif /* IPv6 */
#endif /* TCPCONN */
#ifdef UNIXCONN
@@ -1939,6 +2271,7 @@ Xtransport TRANS(SocketLocalFuncs) = {
TRANS(SocketOpenCOTSClient),
#endif /* TRANS_CLIENT */
#ifdef TRANS_SERVER
+ NULL,
TRANS(SocketOpenCOTSServer),
#endif /* TRANS_SERVER */
#ifdef TRANS_CLIENT
@@ -1970,7 +2303,12 @@ Xtransport TRANS(SocketLocalFuncs) = {
TRANS(SocketUNIXCloseForCloning),
};
#endif /* !LOCALCONN */
-
+# ifdef TRANS_SERVER
+# if !defined(LOCALCONN)
+static char* unix_nolisten[] = { "local" , NULL };
+# endif
+# endif
+
Xtransport TRANS(SocketUNIXFuncs) = {
/* Socket Interface */
"unix",
@@ -1983,6 +2321,11 @@ Xtransport TRANS(SocketUNIXFuncs) = {
TRANS(SocketOpenCOTSClient),
#endif /* TRANS_CLIENT */
#ifdef TRANS_SERVER
+#if !defined(LOCALCONN)
+ unix_nolisten,
+#else
+ NULL,
+#endif
TRANS(SocketOpenCOTSServer),
#endif /* TRANS_SERVER */
#ifdef TRANS_CLIENT