Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 09:18:47

0001 /*
0002  * Copyright (c) 2002, 2025, Oracle and/or its affiliates.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice (including the next
0012  * paragraph) shall be included in all copies or substantial portions of the
0013  * Software.
0014  *
0015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0016  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0017  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0018  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0019  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
0020  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
0021  * DEALINGS IN THE SOFTWARE.
0022  */
0023 /*
0024 
0025 Copyright 1993, 1994, 1998  The Open Group
0026 
0027 Permission to use, copy, modify, distribute, and sell this software and its
0028 documentation for any purpose is hereby granted without fee, provided that
0029 the above copyright notice appear in all copies and that both that
0030 copyright notice and this permission notice appear in supporting
0031 documentation.
0032 
0033 The above copyright notice and this permission notice shall be included
0034 in all copies or substantial portions of the Software.
0035 
0036 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
0037 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0038 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
0039 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
0040 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0041 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0042 OTHER DEALINGS IN THE SOFTWARE.
0043 
0044 Except as contained in this notice, the name of the copyright holders shall
0045 not be used in advertising or otherwise to promote the sale, use or
0046 other dealings in this Software without prior written authorization
0047 from the copyright holders.
0048 
0049  * Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA
0050  *
0051  * All Rights Reserved
0052  *
0053  * Permission to use, copy, modify, and distribute this software and its
0054  * documentation for any purpose and without fee is hereby granted, provided
0055  * that the above copyright notice appear in all copies and that both that
0056  * copyright notice and this permission notice appear in supporting
0057  * documentation, and that the name NCR not be used in advertising
0058  * or publicity pertaining to distribution of the software without specific,
0059  * written prior permission.  NCR makes no representations about the
0060  * suitability of this software for any purpose.  It is provided "as is"
0061  * without express or implied warranty.
0062  *
0063  * NCR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
0064  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
0065  * NO EVENT SHALL NCR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
0066  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
0067  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
0068  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
0069  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0070  */
0071 
0072 #include <ctype.h>
0073 #ifdef XTHREADS
0074 #include <X11/Xthreads.h>
0075 #endif
0076 
0077 #ifndef WIN32
0078 
0079 #if defined(TCPCONN) || defined(UNIXCONN)
0080 #include <sys/socket.h>
0081 #include <netinet/in.h>
0082 #include <arpa/inet.h>
0083 #endif
0084 
0085 #if defined(TCPCONN) || defined(UNIXCONN)
0086 #define X_INCLUDE_NETDB_H
0087 #define XOS_USE_NO_LOCKING
0088 #include <X11/Xos_r.h>
0089 #endif
0090 
0091 #ifdef UNIXCONN
0092 #ifndef X_NO_SYS_UN
0093 #include <sys/un.h>
0094 #endif
0095 #include <sys/stat.h>
0096 #endif
0097 
0098 
0099 #ifndef NO_TCP_H
0100 #if defined(linux) || defined(__GLIBC__)
0101 #include <sys/param.h>
0102 #endif /* osf */
0103 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
0104 #include <sys/param.h>
0105 #include <machine/endian.h>
0106 #endif /* __NetBSD__ || __OpenBSD__ || __FreeBSD__ || __DragonFly__ */
0107 #include <netinet/tcp.h>
0108 #endif /* !NO_TCP_H */
0109 
0110 #include <sys/ioctl.h>
0111 #if defined(SVR4) || defined(__SVR4)
0112 #include <sys/filio.h>
0113 #endif
0114 
0115 #include <unistd.h>
0116 
0117 #else /* !WIN32 */
0118 
0119 #include <X11/Xwinsock.h>
0120 #include <X11/Xwindows.h>
0121 #include <X11/Xw32defs.h>
0122 #undef close
0123 #define close closesocket
0124 #define ECONNREFUSED WSAECONNREFUSED
0125 #define EADDRINUSE WSAEADDRINUSE
0126 #define EPROTOTYPE WSAEPROTOTYPE
0127 #undef EWOULDBLOCK
0128 #define EWOULDBLOCK WSAEWOULDBLOCK
0129 #define EINPROGRESS WSAEINPROGRESS
0130 #undef EINTR
0131 #define EINTR WSAEINTR
0132 #define X_INCLUDE_NETDB_H
0133 #define XOS_USE_MTSAFE_NETDBAPI
0134 #include <X11/Xos_r.h>
0135 #endif /* WIN32 */
0136 
0137 #if defined(SO_DONTLINGER) && defined(SO_LINGER)
0138 #undef SO_DONTLINGER
0139 #endif
0140 
0141 /* others don't need this */
0142 #define SocketInitOnce() /**/
0143 
0144 #ifdef __linux__
0145 #define HAVE_ABSTRACT_SOCKETS
0146 #endif
0147 
0148 #define MIN_BACKLOG 128
0149 #ifdef SOMAXCONN
0150 #if SOMAXCONN > MIN_BACKLOG
0151 #define BACKLOG SOMAXCONN
0152 #endif
0153 #endif
0154 #ifndef BACKLOG
0155 #define BACKLOG MIN_BACKLOG
0156 #endif
0157 
0158 #if defined(IPv6) && !defined(AF_INET6)
0159 #error "Cannot build IPv6 support without AF_INET6"
0160 #endif
0161 
0162 /* Temporary workaround for consumers whose configure scripts were
0163    generated with pre-1.6 versions of xtrans.m4 */
0164 #if defined(IPv6) && !defined(HAVE_GETADDRINFO)
0165 #define HAVE_GETADDRINFO
0166 #endif
0167 
0168 /*
0169  * This is the Socket implementation of the X Transport service layer
0170  *
0171  * This file contains the implementation for both the UNIX and INET domains,
0172  * and can be built for either one, or both.
0173  *
0174  */
0175 
0176 typedef struct _Sockettrans2dev {
0177     const char  *transname;
0178     int     family;
0179     int     devcotsname;
0180     int     devcltsname;
0181     int     protocol;
0182 } Sockettrans2dev;
0183 
0184 /* As documented in the X(7) man page:
0185  *  tcp     TCP over IPv4 or IPv6
0186  *  inet    TCP over IPv4 only
0187  *  inet6   TCP over IPv6 only
0188  *  unix    UNIX Domain Sockets (same host only)
0189  *  local   Platform preferred local connection method
0190  */
0191 static Sockettrans2dev Sockettrans2devtab[] = {
0192 #ifdef TCPCONN
0193     {"inet",AF_INET,SOCK_STREAM,SOCK_DGRAM,0},
0194 #ifndef IPv6
0195     {"tcp",AF_INET,SOCK_STREAM,SOCK_DGRAM,0},
0196 #else /* IPv6 */
0197     {"tcp",AF_INET6,SOCK_STREAM,SOCK_DGRAM,0},
0198     {"tcp",AF_INET,SOCK_STREAM,SOCK_DGRAM,0}, /* fallback */
0199     {"inet6",AF_INET6,SOCK_STREAM,SOCK_DGRAM,0},
0200 #endif
0201 #endif /* TCPCONN */
0202 #ifdef UNIXCONN
0203     {"unix",AF_UNIX,SOCK_STREAM,SOCK_DGRAM,0},
0204 #if !defined(LOCALCONN)
0205     {"local",AF_UNIX,SOCK_STREAM,SOCK_DGRAM,0},
0206 #endif /* !LOCALCONN */
0207 #endif /* UNIXCONN */
0208 };
0209 
0210 #define NUMSOCKETFAMILIES (sizeof(Sockettrans2devtab)/sizeof(Sockettrans2dev))
0211 
0212 #ifdef TCPCONN
0213 static int TRANS(SocketINETClose) (XtransConnInfo ciptr);
0214 #endif
0215 
0216 #if (defined(TCPCONN) && \
0217      (defined(TRANS_SERVER) || defined(X11_t) || !defined(HAVE_GETADDRINFO))) \
0218     || defined(TRANS_REOPEN)
0219 static int
0220 is_numeric (const char *str)
0221 {
0222     int i;
0223 
0224     for (i = 0; i < (int) strlen (str); i++)
0225     if (!isdigit (str[i]))
0226         return (0);
0227 
0228     return (1);
0229 }
0230 #endif
0231 
0232 #ifdef UNIXCONN
0233 
0234 
0235 #if defined(X11_t)
0236 #define UNIX_PATH "/tmp/.X11-unix/X"
0237 #define UNIX_DIR "/tmp/.X11-unix"
0238 #endif /* X11_t */
0239 #if defined(XIM_t)
0240 #define UNIX_PATH "/tmp/.XIM-unix/XIM"
0241 #define UNIX_DIR "/tmp/.XIM-unix"
0242 #endif /* XIM_t */
0243 #if defined(FS_t) || defined(FONT_t)
0244 #define UNIX_PATH "/tmp/.font-unix/fs"
0245 #define UNIX_DIR "/tmp/.font-unix"
0246 #endif /* FS_t || FONT_t */
0247 #if defined(ICE_t)
0248 #define UNIX_PATH "/tmp/.ICE-unix/"
0249 #define UNIX_DIR "/tmp/.ICE-unix"
0250 #endif /* ICE_t */
0251 
0252 
0253 #endif /* UNIXCONN */
0254 
0255 #define PORTBUFSIZE 32
0256 
0257 #ifndef MAXHOSTNAMELEN
0258 #define MAXHOSTNAMELEN 255
0259 #endif
0260 
0261 #if defined(HAVE_SOCKLEN_T) || defined(IPv6)
0262 # define SOCKLEN_T socklen_t
0263 #elif defined(SVR4) || defined(__SVR4)
0264 # define SOCKLEN_T size_t
0265 #else
0266 # define SOCKLEN_T int
0267 #endif
0268 
0269 /*
0270  * These are some utility function used by the real interface function below.
0271  */
0272 
0273 static int
0274 TRANS(SocketSelectFamily) (int first, const char *family)
0275 
0276 {
0277     int     i;
0278 
0279     prmsg (3,"SocketSelectFamily(%s)\n", family);
0280 
0281     for (i = first + 1; i < (int)NUMSOCKETFAMILIES; i++)
0282     {
0283         if (!strcmp (family, Sockettrans2devtab[i].transname))
0284         return i;
0285     }
0286 
0287     return (first == -1 ? -2 : -1);
0288 }
0289 
0290 
0291 /*
0292  * This function gets the local address of the socket and stores it in the
0293  * XtransConnInfo structure for the connection.
0294  */
0295 
0296 static int
0297 TRANS(SocketINETGetAddr) (XtransConnInfo ciptr)
0298 
0299 {
0300 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE
0301     struct sockaddr_storage sockname;
0302 #else
0303     struct sockaddr_in sockname;
0304 #endif
0305     void *socknamePtr = &sockname;
0306     SOCKLEN_T namelen = sizeof(sockname);
0307 
0308     prmsg (3,"SocketINETGetAddr(%p)\n", (void *) ciptr);
0309 
0310     bzero(socknamePtr, namelen);
0311 
0312     if (getsockname (ciptr->fd,(struct sockaddr *) socknamePtr,
0313              (void *)&namelen) < 0)
0314     {
0315 #ifdef WIN32
0316     errno = WSAGetLastError();
0317 #endif
0318     prmsg (1,"SocketINETGetAddr: getsockname() failed: %d\n",
0319         EGET());
0320     return -1;
0321     }
0322 
0323     /*
0324      * Everything looks good: fill in the XtransConnInfo structure.
0325      */
0326 
0327     if ((ciptr->addr = malloc (namelen)) == NULL)
0328     {
0329         prmsg (1,
0330         "SocketINETGetAddr: Can't allocate space for the addr\n");
0331         return -1;
0332     }
0333 
0334     ciptr->family = ((struct sockaddr *)socknamePtr)->sa_family;
0335     ciptr->addrlen = namelen;
0336     memcpy (ciptr->addr, socknamePtr, ciptr->addrlen);
0337 
0338     return 0;
0339 }
0340 
0341 
0342 /*
0343  * This function gets the remote address of the socket and stores it in the
0344  * XtransConnInfo structure for the connection.
0345  */
0346 
0347 static int
0348 TRANS(SocketINETGetPeerAddr) (XtransConnInfo ciptr)
0349 
0350 {
0351 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE
0352     struct sockaddr_storage sockname;
0353 #else
0354     struct sockaddr_in  sockname;
0355 #endif
0356     void *socknamePtr = &sockname;
0357     SOCKLEN_T namelen = sizeof(sockname);
0358 
0359     bzero(socknamePtr, namelen);
0360 
0361     prmsg (3,"SocketINETGetPeerAddr(%p)\n", (void *) ciptr);
0362 
0363     if (getpeername (ciptr->fd, (struct sockaddr *) socknamePtr,
0364              (void *)&namelen) < 0)
0365     {
0366 #ifdef WIN32
0367     errno = WSAGetLastError();
0368 #endif
0369     prmsg (1,"SocketINETGetPeerAddr: getpeername() failed: %d\n",
0370         EGET());
0371     return -1;
0372     }
0373 
0374     /*
0375      * Everything looks good: fill in the XtransConnInfo structure.
0376      */
0377 
0378     if ((ciptr->peeraddr = malloc (namelen)) == NULL)
0379     {
0380         prmsg (1,
0381        "SocketINETGetPeerAddr: Can't allocate space for the addr\n");
0382         return -1;
0383     }
0384 
0385     ciptr->peeraddrlen = namelen;
0386     memcpy (ciptr->peeraddr, socknamePtr, ciptr->peeraddrlen);
0387 
0388     return 0;
0389 }
0390 
0391 
0392 static XtransConnInfo
0393 TRANS(SocketOpen) (int i, int type)
0394 
0395 {
0396     XtransConnInfo  ciptr;
0397 
0398     prmsg (3,"SocketOpen(%d,%d)\n", i, type);
0399 
0400     if ((ciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
0401     {
0402     prmsg (1, "SocketOpen: malloc failed\n");
0403     return NULL;
0404     }
0405 
0406     ciptr->fd = socket(Sockettrans2devtab[i].family, type,
0407                        Sockettrans2devtab[i].protocol);
0408 
0409 #ifndef WIN32
0410 #if (defined(X11_t) && !defined(USE_POLL)) || defined(FS_t) || defined(FONT_t)
0411     if (ciptr->fd >= sysconf(_SC_OPEN_MAX))
0412     {
0413     prmsg (2, "SocketOpen: socket() returned out of range fd %d\n",
0414            ciptr->fd);
0415     close (ciptr->fd);
0416     ciptr->fd = -1;
0417     }
0418 #endif
0419 #endif
0420 
0421     if (ciptr->fd < 0) {
0422 #ifdef WIN32
0423     errno = WSAGetLastError();
0424 #endif
0425     prmsg (2, "SocketOpen: socket() failed for %s\n",
0426         Sockettrans2devtab[i].transname);
0427 
0428     free (ciptr);
0429     return NULL;
0430     }
0431 
0432 #ifdef TCP_NODELAY
0433     if (Sockettrans2devtab[i].family == AF_INET
0434 #ifdef IPv6
0435       || Sockettrans2devtab[i].family == AF_INET6
0436 #endif
0437     )
0438     {
0439     /*
0440      * turn off TCP coalescence for INET sockets
0441      */
0442 
0443     int tmp = 1;
0444     setsockopt (ciptr->fd, IPPROTO_TCP, TCP_NODELAY,
0445         (char *) &tmp, sizeof (int));
0446     }
0447 #endif
0448 
0449     /*
0450      * Some systems provide a really small default buffer size for
0451      * UNIX sockets.  Bump it up a bit such that large transfers don't
0452      * proceed at glacial speed.
0453      */
0454 #ifdef SO_SNDBUF
0455     if (Sockettrans2devtab[i].family == AF_UNIX)
0456     {
0457     SOCKLEN_T len = sizeof (int);
0458     int val;
0459 
0460     if (getsockopt (ciptr->fd, SOL_SOCKET, SO_SNDBUF,
0461         (char *) &val, &len) == 0 && val < 64 * 1024)
0462     {
0463         val = 64 * 1024;
0464         setsockopt (ciptr->fd, SOL_SOCKET, SO_SNDBUF,
0465             (char *) &val, sizeof (int));
0466     }
0467     }
0468 #endif
0469 
0470     return ciptr;
0471 }
0472 
0473 
0474 #ifdef TRANS_REOPEN
0475 
0476 static XtransConnInfo
0477 TRANS(SocketReopen) (int i _X_UNUSED, int type, int fd, const char *port)
0478 
0479 {
0480     XtransConnInfo  ciptr;
0481     int portlen;
0482     struct sockaddr *addr;
0483     size_t addrlen;
0484 
0485     prmsg (3,"SocketReopen(%d,%d,%s)\n", type, fd, port);
0486 
0487     if (port == NULL) {
0488       prmsg (1, "SocketReopen: port was null!\n");
0489       return NULL;
0490     }
0491 
0492     portlen = strlen(port) + 1; // include space for trailing null
0493 #ifdef SOCK_MAXADDRLEN
0494     if (portlen < 0 || portlen > (SOCK_MAXADDRLEN + 2)) {
0495       prmsg (1, "SocketReopen: invalid portlen %d\n", portlen);
0496       return NULL;
0497     }
0498     if (portlen < 14) portlen = 14;
0499 #else
0500     if (portlen < 0 || portlen > 14) {
0501       prmsg (1, "SocketReopen: invalid portlen %d\n", portlen);
0502       return NULL;
0503     }
0504 #endif /*SOCK_MAXADDRLEN*/
0505 
0506     if ((ciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
0507     {
0508     prmsg (1, "SocketReopen: malloc(ciptr) failed\n");
0509     return NULL;
0510     }
0511 
0512     ciptr->fd = fd;
0513 
0514     addrlen = portlen + offsetof(struct sockaddr, sa_data);
0515     if ((addr = calloc (1, addrlen)) == NULL) {
0516     prmsg (1, "SocketReopen: malloc(addr) failed\n");
0517     free (ciptr);
0518     return NULL;
0519     }
0520     ciptr->addr = (char *) addr;
0521     ciptr->addrlen = addrlen;
0522 
0523     if ((ciptr->peeraddr = calloc (1, addrlen)) == NULL) {
0524     prmsg (1, "SocketReopen: malloc(portaddr) failed\n");
0525     free (addr);
0526     free (ciptr);
0527     return NULL;
0528     }
0529     ciptr->peeraddrlen = addrlen;
0530 
0531     /* Initialize ciptr structure as if it were a normally-opened unix socket */
0532     ciptr->flags = TRANS_LOCAL | TRANS_NOUNLINK;
0533 #ifdef BSD44SOCKETS
0534     addr->sa_len = addrlen;
0535 #endif
0536     addr->sa_family = AF_UNIX;
0537 #if defined(HAVE_STRLCPY) || defined(HAS_STRLCPY)
0538     strlcpy(addr->sa_data, port, portlen);
0539 #else
0540     strncpy(addr->sa_data, port, portlen);
0541 #endif
0542     ciptr->family = AF_UNIX;
0543     memcpy(ciptr->peeraddr, ciptr->addr, addrlen);
0544     ciptr->port = rindex(addr->sa_data, ':');
0545     if (ciptr->port == NULL) {
0546     if (is_numeric(addr->sa_data)) {
0547         ciptr->port = addr->sa_data;
0548     }
0549     } else if (ciptr->port[0] == ':') {
0550     ciptr->port++;
0551     }
0552     /* port should now point to portnum or NULL */
0553     return ciptr;
0554 }
0555 
0556 #endif /* TRANS_REOPEN */
0557 
0558 
0559 /*
0560  * These functions are the interface supplied in the Xtransport structure
0561  */
0562 
0563 #ifdef TRANS_CLIENT
0564 
0565 static XtransConnInfo
0566 TRANS(SocketOpenCOTSClientBase) (const char *transname, const char *protocol,
0567                const char *host, const char *port, int previndex)
0568 {
0569     XtransConnInfo  ciptr = NULL;
0570     int         i = previndex;
0571 
0572     prmsg (2, "SocketOpenCOTSClient(%s,%s,%s)\n",
0573     protocol, host, port);
0574 
0575     SocketInitOnce();
0576 
0577     while ((i = TRANS(SocketSelectFamily) (i, transname)) >= 0) {
0578     if ((ciptr = TRANS(SocketOpen) (
0579         i, Sockettrans2devtab[i].devcotsname)) != NULL) {
0580         /* Save the index for later use */
0581 
0582         ciptr->index = i;
0583         break;
0584     }
0585     }
0586     if (i < 0) {
0587     if (i == -1)
0588         prmsg (1,"SocketOpenCOTSClient: Unable to open socket for %s\n",
0589            transname);
0590     else
0591         prmsg (1,"SocketOpenCOTSClient: Unable to determine socket type for %s\n",
0592            transname);
0593     return NULL;
0594     }
0595 
0596     return ciptr;
0597 }
0598 
0599 static XtransConnInfo
0600 TRANS(SocketOpenCOTSClient) (Xtransport *thistrans, const char *protocol,
0601                  const char *host, const char *port)
0602 {
0603     return TRANS(SocketOpenCOTSClientBase)(
0604             thistrans->TransName, protocol, host, port, -1);
0605 }
0606 
0607 
0608 #endif /* TRANS_CLIENT */
0609 
0610 
0611 #ifdef TRANS_SERVER
0612 
0613 static XtransConnInfo
0614 TRANS(SocketOpenCOTSServer) (Xtransport *thistrans, const char *protocol,
0615                  const char *host, const char *port)
0616 
0617 {
0618     XtransConnInfo  ciptr = NULL;
0619     int i = -1;
0620 
0621     prmsg (2,"SocketOpenCOTSServer(%s,%s,%s)\n", protocol, host, port);
0622 
0623     SocketInitOnce();
0624 
0625     while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
0626     if ((ciptr = TRANS(SocketOpen) (
0627          i, Sockettrans2devtab[i].devcotsname)) != NULL)
0628         break;
0629     }
0630     if (i < 0) {
0631     if (i == -1) {
0632         if (errno == EAFNOSUPPORT) {
0633             thistrans->flags |= TRANS_NOLISTEN;
0634             prmsg (1,"SocketOpenCOTSServer: Socket for %s unsupported on this system.\n",
0635                    thistrans->TransName);
0636         } else {
0637             prmsg (1,"SocketOpenCOTSServer: Unable to open socket for %s\n",
0638                    thistrans->TransName);
0639         }
0640     } else {
0641         prmsg (1,"SocketOpenCOTSServer: Unable to determine socket type for %s\n",
0642            thistrans->TransName);
0643     }
0644     return NULL;
0645     }
0646 
0647     /*
0648      * Using this prevents the bind() check for an existing server listening
0649      * on the same port, but it is required for other reasons.
0650      */
0651 #ifdef SO_REUSEADDR
0652 
0653     /*
0654      * SO_REUSEADDR only applied to AF_INET && AF_INET6
0655      */
0656 
0657     if (Sockettrans2devtab[i].family == AF_INET
0658 #ifdef IPv6
0659       || Sockettrans2devtab[i].family == AF_INET6
0660 #endif
0661     )
0662     {
0663     int one = 1;
0664     setsockopt (ciptr->fd, SOL_SOCKET, SO_REUSEADDR,
0665             (char *) &one, sizeof (int));
0666     }
0667 #endif
0668 #ifdef IPV6_V6ONLY
0669     if (Sockettrans2devtab[i].family == AF_INET6)
0670     {
0671     int one = 1;
0672     setsockopt(ciptr->fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(int));
0673     }
0674 #endif
0675     /* Save the index for later use */
0676 
0677     ciptr->index = i;
0678 
0679     return ciptr;
0680 }
0681 
0682 #endif /* TRANS_SERVER */
0683 
0684 
0685 #ifdef TRANS_REOPEN
0686 
0687 static XtransConnInfo
0688 TRANS(SocketReopenCOTSServer) (Xtransport *thistrans, int fd, const char *port)
0689 
0690 {
0691     XtransConnInfo  ciptr;
0692     int         i = -1;
0693 
0694     prmsg (2,
0695     "SocketReopenCOTSServer(%d, %s)\n", fd, port);
0696 
0697     SocketInitOnce();
0698 
0699     while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
0700     if ((ciptr = TRANS(SocketReopen) (
0701          i, Sockettrans2devtab[i].devcotsname, fd, port)) != NULL)
0702         break;
0703     }
0704     if (i < 0) {
0705     if (i == -1)
0706         prmsg (1,"SocketReopenCOTSServer: Unable to open socket for %s\n",
0707            thistrans->TransName);
0708     else
0709         prmsg (1,"SocketReopenCOTSServer: Unable to determine socket type for %s\n",
0710            thistrans->TransName);
0711     return NULL;
0712     }
0713 
0714     /* Save the index for later use */
0715 
0716     ciptr->index = i;
0717 
0718     return ciptr;
0719 }
0720 
0721 #endif /* TRANS_REOPEN */
0722 
0723 
0724 static int
0725 TRANS(SocketSetOption) (XtransConnInfo ciptr, int option, int arg)
0726 
0727 {
0728     prmsg (2,"SocketSetOption(%d,%d,%d)\n", ciptr->fd, option, arg);
0729 
0730     return -1;
0731 }
0732 
0733 #ifdef UNIXCONN
0734 static int
0735 set_sun_path(const char *port, const char *upath, char *path, int abstract)
0736 {
0737     struct sockaddr_un s;
0738     ssize_t maxlen = sizeof(s.sun_path) - 1;
0739     const char *at = "";
0740 
0741     if (!port || !*port || !path)
0742     return -1;
0743 
0744 #ifdef HAVE_ABSTRACT_SOCKETS
0745     if (port[0] == '@')
0746     upath = "";
0747     else if (abstract)
0748     at = "@";
0749 #endif
0750 
0751     if (*port == '/') /* a full pathname */
0752     upath = "";
0753 
0754     if ((ssize_t)(strlen(at) + strlen(upath) + strlen(port)) > maxlen)
0755     return -1;
0756     snprintf(path, sizeof(s.sun_path), "%s%s%s", at, upath, port);
0757     return 0;
0758 }
0759 #endif
0760 
0761 #ifdef TRANS_SERVER
0762 
0763 static int
0764 TRANS(SocketCreateListener) (XtransConnInfo ciptr,
0765                  struct sockaddr *sockname,
0766                  int socknamelen, unsigned int flags)
0767 
0768 {
0769     SOCKLEN_T namelen = socknamelen;
0770     int fd = ciptr->fd;
0771     int retry;
0772 
0773     prmsg (3, "SocketCreateListener(%p,%d)\n", (void *) ciptr, fd);
0774 
0775     if (Sockettrans2devtab[ciptr->index].family == AF_INET
0776 #ifdef IPv6
0777       || Sockettrans2devtab[ciptr->index].family == AF_INET6
0778 #endif
0779     )
0780     retry = 20;
0781     else
0782     retry = 0;
0783 
0784     while (bind (fd, sockname, namelen) < 0)
0785     {
0786     if (errno == EADDRINUSE) {
0787         if (flags & ADDR_IN_USE_ALLOWED)
0788         break;
0789         else
0790         return TRANS_ADDR_IN_USE;
0791     }
0792 
0793     if (retry-- == 0) {
0794         prmsg (1, "SocketCreateListener: failed to bind listener\n");
0795         close (fd);
0796         return TRANS_CREATE_LISTENER_FAILED;
0797     }
0798 #ifdef SO_REUSEADDR
0799     sleep (1);
0800 #else
0801     sleep (10);
0802 #endif /* SO_REUSEDADDR */
0803     }
0804 
0805     if (Sockettrans2devtab[ciptr->index].family == AF_INET
0806 #ifdef IPv6
0807       || Sockettrans2devtab[ciptr->index].family == AF_INET6
0808 #endif
0809     ) {
0810 #ifdef SO_DONTLINGER
0811     setsockopt (fd, SOL_SOCKET, SO_DONTLINGER, (char *) NULL, 0);
0812 #else
0813 #ifdef SO_LINGER
0814     {
0815     static int linger[2] = { 0, 0 };
0816     setsockopt (fd, SOL_SOCKET, SO_LINGER,
0817         (char *) linger, sizeof (linger));
0818     }
0819 #endif
0820 #endif
0821 }
0822 
0823     if (listen (fd, BACKLOG) < 0)
0824     {
0825     prmsg (1, "SocketCreateListener: listen() failed\n");
0826     close (fd);
0827     return TRANS_CREATE_LISTENER_FAILED;
0828     }
0829 
0830     /* Set a flag to indicate that this connection is a listener */
0831 
0832     ciptr->flags = 1 | (ciptr->flags & TRANS_KEEPFLAGS);
0833 
0834     return 0;
0835 }
0836 
0837 #ifdef TCPCONN
0838 static int
0839 TRANS(SocketINETCreateListener) (XtransConnInfo ciptr, const char *port,
0840                                  unsigned int flags)
0841 
0842 {
0843 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE
0844     struct sockaddr_storage sockname;
0845 #else
0846     struct sockaddr_in      sockname;
0847 #endif
0848     unsigned short      sport;
0849     SOCKLEN_T   namelen = sizeof(sockname);
0850     int     status;
0851     long    tmpport;
0852 #ifdef XTHREADS_NEEDS_BYNAMEPARAMS
0853     _Xgetservbynameparams sparams;
0854 #endif
0855     struct servent *servp;
0856 
0857 #ifdef X11_t
0858     char    portbuf[PORTBUFSIZE];
0859 #endif
0860 
0861     prmsg (2, "SocketINETCreateListener(%s)\n", port);
0862 
0863 #ifdef X11_t
0864     /*
0865      * X has a well known port, that is transport dependent. It is easier
0866      * to handle it here, than try and come up with a transport independent
0867      * representation that can be passed in and resolved the usual way.
0868      *
0869      * The port that is passed here is really a string containing the idisplay
0870      * from ConnectDisplay().
0871      */
0872 
0873     if (is_numeric (port))
0874     {
0875     /* fixup the server port address */
0876     tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10);
0877     snprintf (portbuf, sizeof(portbuf), "%lu", tmpport);
0878     port = portbuf;
0879     }
0880 #endif
0881 
0882     if (port && *port)
0883     {
0884     /* Check to see if the port string is just a number (handles X11) */
0885 
0886     if (!is_numeric (port))
0887     {
0888         if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL)
0889         {
0890         prmsg (1,
0891          "SocketINETCreateListener: Unable to get service for %s\n",
0892               port);
0893         return TRANS_CREATE_LISTENER_FAILED;
0894         }
0895         /* we trust getservbyname to return a valid number */
0896         sport = servp->s_port;
0897     }
0898     else
0899     {
0900         tmpport = strtol (port, (char**)NULL, 10);
0901         /*
0902          * check that somehow the port address isn't negative or in
0903          * the range of reserved port addresses. This can happen and
0904          * be very bad if the server is suid-root and the user does
0905          * something (dumb) like `X :60049`.
0906          */
0907         if (tmpport < 1024 || tmpport > USHRT_MAX)
0908         return TRANS_CREATE_LISTENER_FAILED;
0909 
0910         sport = (unsigned short) tmpport;
0911     }
0912     }
0913     else
0914     sport = 0;
0915 
0916     bzero(&sockname, sizeof(sockname));
0917     if (Sockettrans2devtab[ciptr->index].family == AF_INET) {
0918     namelen = sizeof (struct sockaddr_in);
0919 #ifdef BSD44SOCKETS
0920     ((struct sockaddr_in *)&sockname)->sin_len = namelen;
0921 #endif
0922     ((struct sockaddr_in *)&sockname)->sin_family = AF_INET;
0923     ((struct sockaddr_in *)&sockname)->sin_port = htons(sport);
0924     ((struct sockaddr_in *)&sockname)->sin_addr.s_addr = htonl(INADDR_ANY);
0925     } else {
0926 #ifdef IPv6
0927     namelen = sizeof (struct sockaddr_in6);
0928 #ifdef SIN6_LEN
0929     ((struct sockaddr_in6 *)&sockname)->sin6_len = sizeof(sockname);
0930 #endif
0931     ((struct sockaddr_in6 *)&sockname)->sin6_family = AF_INET6;
0932     ((struct sockaddr_in6 *)&sockname)->sin6_port = htons(sport);
0933     ((struct sockaddr_in6 *)&sockname)->sin6_addr = in6addr_any;
0934 #else
0935         prmsg (1,
0936                "SocketINETCreateListener: unsupported address family %d\n",
0937                Sockettrans2devtab[ciptr->index].family);
0938         return TRANS_CREATE_LISTENER_FAILED;
0939 #endif
0940     }
0941 
0942     if ((status = TRANS(SocketCreateListener) (ciptr,
0943     (struct sockaddr *) &sockname, namelen, flags)) < 0)
0944     {
0945     prmsg (1,
0946     "SocketINETCreateListener: ...SocketCreateListener() failed\n");
0947     return status;
0948     }
0949 
0950     if (TRANS(SocketINETGetAddr) (ciptr) < 0)
0951     {
0952     prmsg (1,
0953        "SocketINETCreateListener: ...SocketINETGetAddr() failed\n");
0954     return TRANS_CREATE_LISTENER_FAILED;
0955     }
0956 
0957     return 0;
0958 }
0959 
0960 #endif /* TCPCONN */
0961 
0962 
0963 #ifdef UNIXCONN
0964 
0965 static int
0966 TRANS(SocketUNIXCreateListener) (XtransConnInfo ciptr, const char *port,
0967                  unsigned int flags)
0968 
0969 {
0970     struct sockaddr_un  sockname;
0971     int         namelen;
0972     int         oldUmask;
0973     int         status;
0974     unsigned int    mode;
0975     char        tmpport[108];
0976 
0977     int         abstract = 0;
0978 #ifdef HAVE_ABSTRACT_SOCKETS
0979     abstract = ciptr->transptr->flags & TRANS_ABSTRACT;
0980 #endif
0981 
0982     prmsg (2, "SocketUNIXCreateListener(%s)\n",
0983     port ? port : "NULL");
0984 
0985     /* Make sure the directory is created */
0986 
0987     oldUmask = umask (0);
0988 
0989 #ifdef UNIX_DIR
0990 #ifdef HAS_STICKY_DIR_BIT
0991     mode = 01777;
0992 #else
0993     mode = 0777;
0994 #endif
0995     if (!abstract && trans_mkdir(UNIX_DIR, mode) == -1) {
0996     prmsg (1, "SocketUNIXCreateListener: mkdir(%s) failed, errno = %d\n",
0997            UNIX_DIR, errno);
0998     (void) umask (oldUmask);
0999     return TRANS_CREATE_LISTENER_FAILED;
1000     }
1001 #endif
1002 
1003     memset(&sockname, 0, sizeof(sockname));
1004     sockname.sun_family = AF_UNIX;
1005 
1006     if (!(port && *port)) {
1007     snprintf (tmpport, sizeof(tmpport), "%s%ld", UNIX_PATH, (long)getpid());
1008     port = tmpport;
1009     }
1010     if (set_sun_path(port, UNIX_PATH, sockname.sun_path, abstract) != 0) {
1011     prmsg (1, "SocketUNIXCreateListener: path too long\n");
1012     return TRANS_CREATE_LISTENER_FAILED;
1013     }
1014 
1015 #if defined(BSD44SOCKETS)
1016     sockname.sun_len = strlen(sockname.sun_path);
1017 #endif
1018 
1019 #if defined(BSD44SOCKETS) || defined(SUN_LEN)
1020     namelen = SUN_LEN(&sockname);
1021 #else
1022     namelen = strlen(sockname.sun_path) + offsetof(struct sockaddr_un, sun_path);
1023 #endif
1024 
1025     if (abstract) {
1026     sockname.sun_path[0] = '\0';
1027     namelen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&sockname.sun_path[1]);
1028     }
1029     else
1030     unlink (sockname.sun_path);
1031 
1032     if ((status = TRANS(SocketCreateListener) (ciptr,
1033     (struct sockaddr *) &sockname, namelen, flags)) < 0)
1034     {
1035     prmsg (1,
1036     "SocketUNIXCreateListener: ...SocketCreateListener() failed\n");
1037     (void) umask (oldUmask);
1038     return status;
1039     }
1040 
1041     /*
1042      * Now that the listener is esablished, create the addr info for
1043      * this connection. getpeername() doesn't work for UNIX Domain Sockets
1044      * on some systems (hpux at least), so we will just do it manually, instead
1045      * of calling something like TRANS(SocketUNIXGetAddr).
1046      */
1047 
1048     namelen = sizeof (sockname); /* this will always make it the same size */
1049 
1050     if ((ciptr->addr = malloc (namelen)) == NULL)
1051     {
1052         prmsg (1,
1053         "SocketUNIXCreateListener: Can't allocate space for the addr\n");
1054     (void) umask (oldUmask);
1055         return TRANS_CREATE_LISTENER_FAILED;
1056     }
1057 
1058     if (abstract)
1059     sockname.sun_path[0] = '@';
1060 
1061     ciptr->family = sockname.sun_family;
1062     ciptr->addrlen = namelen;
1063     memcpy (ciptr->addr, &sockname, ciptr->addrlen);
1064 
1065     (void) umask (oldUmask);
1066 
1067     return 0;
1068 }
1069 
1070 
1071 static int
1072 TRANS(SocketUNIXResetListener) (XtransConnInfo ciptr)
1073 
1074 {
1075     /*
1076      * See if the unix domain socket has disappeared.  If it has, recreate it.
1077      */
1078 
1079     struct sockaddr_un  *unsock = (struct sockaddr_un *) ciptr->addr;
1080     struct stat     statb;
1081     int         status = TRANS_RESET_NOOP;
1082     unsigned int    mode;
1083     int abstract = 0;
1084 #ifdef HAVE_ABSTRACT_SOCKETS
1085     abstract = ciptr->transptr->flags & TRANS_ABSTRACT;
1086 #endif
1087 
1088     prmsg (3, "SocketUNIXResetListener(%p,%d)\n", (void *) ciptr, ciptr->fd);
1089 
1090     if (!abstract && (
1091     stat (unsock->sun_path, &statb) == -1 ||
1092         ((statb.st_mode & S_IFMT) !=
1093 #if !defined(S_IFSOCK)
1094             S_IFIFO
1095 #else
1096             S_IFSOCK
1097 #endif
1098                 )))
1099     {
1100     int oldUmask = umask (0);
1101 
1102 #ifdef UNIX_DIR
1103 #ifdef HAS_STICKY_DIR_BIT
1104     mode = 01777;
1105 #else
1106     mode = 0777;
1107 #endif
1108         if (trans_mkdir(UNIX_DIR, mode) == -1) {
1109             prmsg (1, "SocketUNIXResetListener: mkdir(%s) failed, errno = %d\n",
1110         UNIX_DIR, errno);
1111         (void) umask (oldUmask);
1112         return TRANS_RESET_FAILURE;
1113         }
1114 #endif
1115 
1116     close (ciptr->fd);
1117     unlink (unsock->sun_path);
1118 
1119     if ((ciptr->fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
1120     {
1121         TRANS(FreeConnInfo) (ciptr);
1122         (void) umask (oldUmask);
1123         return TRANS_RESET_FAILURE;
1124     }
1125 
1126     if (bind (ciptr->fd, (struct sockaddr *) unsock, ciptr->addrlen) < 0)
1127     {
1128         close (ciptr->fd);
1129         TRANS(FreeConnInfo) (ciptr);
1130         return TRANS_RESET_FAILURE;
1131     }
1132 
1133     if (listen (ciptr->fd, BACKLOG) < 0)
1134     {
1135         close (ciptr->fd);
1136         TRANS(FreeConnInfo) (ciptr);
1137         (void) umask (oldUmask);
1138         return TRANS_RESET_FAILURE;
1139     }
1140 
1141     umask (oldUmask);
1142 
1143     status = TRANS_RESET_NEW_FD;
1144     }
1145 
1146     return status;
1147 }
1148 
1149 #endif /* UNIXCONN */
1150 
1151 
1152 #ifdef TCPCONN
1153 
1154 static XtransConnInfo
1155 TRANS(SocketINETAccept) (XtransConnInfo ciptr, int *status)
1156 
1157 {
1158     XtransConnInfo  newciptr;
1159     struct sockaddr_in  sockname;
1160     SOCKLEN_T       namelen = sizeof(sockname);
1161 
1162     prmsg (2, "SocketINETAccept(%p,%d)\n", (void *) ciptr, ciptr->fd);
1163 
1164     if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
1165     {
1166     prmsg (1, "SocketINETAccept: malloc failed\n");
1167     *status = TRANS_ACCEPT_BAD_MALLOC;
1168     return NULL;
1169     }
1170 
1171     if ((newciptr->fd = accept (ciptr->fd,
1172     (struct sockaddr *) &sockname, (void *)&namelen)) < 0)
1173     {
1174 #ifdef WIN32
1175     errno = WSAGetLastError();
1176 #endif
1177     prmsg (1, "SocketINETAccept: accept() failed\n");
1178     free (newciptr);
1179     *status = TRANS_ACCEPT_FAILED;
1180     return NULL;
1181     }
1182 
1183 #ifdef TCP_NODELAY
1184     {
1185     /*
1186      * turn off TCP coalescence for INET sockets
1187      */
1188 
1189     int tmp = 1;
1190     setsockopt (newciptr->fd, IPPROTO_TCP, TCP_NODELAY,
1191         (char *) &tmp, sizeof (int));
1192     }
1193 #endif
1194 
1195     /*
1196      * Get this address again because the transport may give a more
1197      * specific address now that a connection is established.
1198      */
1199 
1200     if (TRANS(SocketINETGetAddr) (newciptr) < 0)
1201     {
1202     prmsg (1,
1203         "SocketINETAccept: ...SocketINETGetAddr() failed:\n");
1204     close (newciptr->fd);
1205     free (newciptr);
1206     *status = TRANS_ACCEPT_MISC_ERROR;
1207         return NULL;
1208     }
1209 
1210     if (TRANS(SocketINETGetPeerAddr) (newciptr) < 0)
1211     {
1212     prmsg (1,
1213       "SocketINETAccept: ...SocketINETGetPeerAddr() failed:\n");
1214     close (newciptr->fd);
1215     if (newciptr->addr) free (newciptr->addr);
1216     free (newciptr);
1217     *status = TRANS_ACCEPT_MISC_ERROR;
1218         return NULL;
1219     }
1220 
1221     *status = 0;
1222 
1223     return newciptr;
1224 }
1225 
1226 #endif /* TCPCONN */
1227 
1228 
1229 #ifdef UNIXCONN
1230 static XtransConnInfo
1231 TRANS(SocketUNIXAccept) (XtransConnInfo ciptr, int *status)
1232 
1233 {
1234     XtransConnInfo  newciptr;
1235     struct sockaddr_un  sockname;
1236     SOCKLEN_T       namelen = sizeof sockname;
1237 
1238     prmsg (2, "SocketUNIXAccept(%p,%d)\n", (void *) ciptr, ciptr->fd);
1239 
1240     if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
1241     {
1242     prmsg (1, "SocketUNIXAccept: malloc() failed\n");
1243     *status = TRANS_ACCEPT_BAD_MALLOC;
1244     return NULL;
1245     }
1246 
1247     if ((newciptr->fd = accept (ciptr->fd,
1248     (struct sockaddr *) &sockname, (void *)&namelen)) < 0)
1249     {
1250     prmsg (1, "SocketUNIXAccept: accept() failed\n");
1251     free (newciptr);
1252     *status = TRANS_ACCEPT_FAILED;
1253     return NULL;
1254     }
1255 
1256     ciptr->addrlen = namelen;
1257     /*
1258      * Get the socket name and the peer name from the listener socket,
1259      * since this is unix domain.
1260      */
1261 
1262     if ((newciptr->addr = malloc (ciptr->addrlen)) == NULL)
1263     {
1264         prmsg (1,
1265         "SocketUNIXAccept: Can't allocate space for the addr\n");
1266     close (newciptr->fd);
1267     free (newciptr);
1268     *status = TRANS_ACCEPT_BAD_MALLOC;
1269         return NULL;
1270     }
1271 
1272     /*
1273      * if the socket is abstract, we already modified the address to have a
1274      * @ instead of the initial NUL, so no need to do that again here.
1275      */
1276 
1277     newciptr->addrlen = ciptr->addrlen;
1278     memcpy (newciptr->addr, ciptr->addr, newciptr->addrlen);
1279 
1280     if ((newciptr->peeraddr = malloc (ciptr->addrlen)) == NULL)
1281     {
1282         prmsg (1,
1283           "SocketUNIXAccept: Can't allocate space for the addr\n");
1284     close (newciptr->fd);
1285     if (newciptr->addr) free (newciptr->addr);
1286     free (newciptr);
1287     *status = TRANS_ACCEPT_BAD_MALLOC;
1288         return NULL;
1289     }
1290 
1291     newciptr->peeraddrlen = ciptr->addrlen;
1292     memcpy (newciptr->peeraddr, ciptr->addr, newciptr->addrlen);
1293 
1294     newciptr->family = AF_UNIX;
1295 
1296     *status = 0;
1297 
1298     return newciptr;
1299 }
1300 
1301 #endif /* UNIXCONN */
1302 
1303 #endif /* TRANS_SERVER */
1304 
1305 
1306 #ifdef TRANS_CLIENT
1307 
1308 #ifdef TCPCONN
1309 
1310 #ifdef HAVE_GETADDRINFO
1311 struct addrlist {
1312     struct addrinfo *   addr;
1313     struct addrinfo *   firstaddr;
1314     char        port[PORTBUFSIZE];
1315     char        host[MAXHOSTNAMELEN];
1316 };
1317 static struct addrlist  *addrlist = NULL;
1318 #endif
1319 
1320 
1321 static int
1322 TRANS(SocketINETConnect) (XtransConnInfo ciptr,
1323                           const char *host, const char *port)
1324 
1325 {
1326     struct sockaddr *   socketaddr = NULL;
1327     int         socketaddrlen = 0;
1328     int         res;
1329 #ifdef HAVE_GETADDRINFO
1330     struct addrinfo     hints;
1331     char        ntopbuf[INET6_ADDRSTRLEN];
1332     int         resetonce = 0;
1333 #else
1334     struct sockaddr_in  sockname;
1335     struct hostent  *hostp;
1336     struct servent  *servp;
1337     unsigned long   tmpaddr;
1338 #endif
1339 #ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1340     _Xgethostbynameparams hparams;
1341     _Xgetservbynameparams sparams;
1342 #endif
1343 #ifdef X11_t
1344     char    portbuf[PORTBUFSIZE];
1345 #endif
1346 
1347     char        hostnamebuf[256];       /* tmp space */
1348 
1349     prmsg (2,"SocketINETConnect(%d,%s,%s)\n", ciptr->fd, host, port);
1350 
1351     if (!host)
1352     {
1353     hostnamebuf[0] = '\0';
1354     (void) TRANS(GetHostname) (hostnamebuf, sizeof hostnamebuf);
1355     host = hostnamebuf;
1356     }
1357 
1358 #ifdef X11_t
1359     /*
1360      * X has a well known port, that is transport dependent. It is easier
1361      * to handle it here, than try and come up with a transport independent
1362      * representation that can be passed in and resolved the usual way.
1363      *
1364      * The port that is passed here is really a string containing the idisplay
1365      * from ConnectDisplay().
1366      */
1367 
1368     if (is_numeric (port))
1369     {
1370     long tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10);
1371     snprintf (portbuf, sizeof(portbuf), "%lu", tmpport);
1372     port = portbuf;
1373     }
1374 #endif
1375 
1376 #ifdef HAVE_GETADDRINFO
1377     {
1378     if (addrlist != NULL) {
1379         if (strcmp(host,addrlist->host) || strcmp(port,addrlist->port)) {
1380         if (addrlist->firstaddr)
1381             freeaddrinfo(addrlist->firstaddr);
1382         addrlist->firstaddr = NULL;
1383         }
1384     } else {
1385         addrlist = malloc(sizeof(struct addrlist));
1386         if (addrlist == NULL) {
1387         prmsg (1, "SocketINETConnect() can't allocate memory "
1388             "for addrlist: %s\n", strerror(errno));
1389         return TRANS_CONNECT_FAILED;
1390         }
1391         addrlist->firstaddr = NULL;
1392     }
1393 
1394     if (addrlist->firstaddr == NULL) {
1395         strncpy(addrlist->port, port, sizeof(addrlist->port));
1396         addrlist->port[sizeof(addrlist->port) - 1] = '\0';
1397         strncpy(addrlist->host, host, sizeof(addrlist->host));
1398         addrlist->host[sizeof(addrlist->host) - 1] = '\0';
1399 
1400         bzero(&hints,sizeof(hints));
1401 #ifdef IPv6
1402         if (strcmp(Sockettrans2devtab[ciptr->index].transname, "tcp") == 0)
1403         hints.ai_family = AF_UNSPEC;
1404         else
1405 #endif
1406         hints.ai_family = Sockettrans2devtab[ciptr->index].family;
1407         hints.ai_socktype = Sockettrans2devtab[ciptr->index].devcotsname;
1408 
1409         res = getaddrinfo(host,port,&hints,&addrlist->firstaddr);
1410         if (res != 0) {
1411         prmsg (1, "SocketINETConnect() can't get address "
1412             "for %s:%s: %s\n", host, port, gai_strerror(res));
1413         ESET(EINVAL);
1414         return TRANS_CONNECT_FAILED;
1415         }
1416         for (res = 0, addrlist->addr = addrlist->firstaddr;
1417          addrlist->addr ; res++) {
1418         addrlist->addr = addrlist->addr->ai_next;
1419         }
1420         prmsg(4,"Got New Address list with %d addresses\n", res);
1421         res = 0;
1422         addrlist->addr = NULL;
1423     }
1424 
1425     while (socketaddr == NULL) {
1426         if (addrlist->addr == NULL) {
1427         if (resetonce) {
1428             /* Already checked entire list - no usable addresses */
1429             prmsg (1, "SocketINETConnect() no usable address "
1430                "for %s:%s\n", host, port);
1431             return TRANS_CONNECT_FAILED;
1432         } else {
1433             /* Go back to beginning of list */
1434             resetonce = 1;
1435             addrlist->addr = addrlist->firstaddr;
1436         }
1437         }
1438 
1439         socketaddr = addrlist->addr->ai_addr;
1440         socketaddrlen = addrlist->addr->ai_addrlen;
1441 
1442         if (addrlist->addr->ai_family == AF_INET) {
1443         struct sockaddr_in *sin = (struct sockaddr_in *) socketaddr;
1444 
1445         prmsg (4,"SocketINETConnect() sockname.sin_addr = %s\n",
1446             inet_ntop(addrlist->addr->ai_family,&sin->sin_addr,
1447             ntopbuf,sizeof(ntopbuf)));
1448 
1449         prmsg (4,"SocketINETConnect() sockname.sin_port = %d\n",
1450             ntohs(sin->sin_port));
1451 
1452 #ifdef IPv6
1453         if (Sockettrans2devtab[ciptr->index].family == AF_INET6) {
1454             if (strcmp(Sockettrans2devtab[ciptr->index].transname,
1455                 "tcp") == 0) {
1456             XtransConnInfo newciptr;
1457 
1458             /*
1459              * Our socket is an IPv6 socket, but the address is
1460              * IPv4.  Close it and get an IPv4 socket.  This is
1461              * needed for IPv4 connections to work on platforms
1462              * that don't allow IPv4 over IPv6 sockets.
1463              */
1464             TRANS(SocketINETClose)(ciptr);
1465             newciptr = TRANS(SocketOpenCOTSClientBase)(
1466                     "tcp", "tcp", host, port, ciptr->index);
1467             if (newciptr)
1468                 ciptr->fd = newciptr->fd;
1469             if (!newciptr ||
1470                 Sockettrans2devtab[newciptr->index].family !=
1471                 AF_INET) {
1472                 socketaddr = NULL;
1473                 prmsg (4,"SocketINETConnect() Cannot get IPv4 "
1474                     " socketfor IPv4 address\n");
1475             }
1476             if (newciptr)
1477                 free(newciptr);
1478             } else {
1479             socketaddr = NULL;
1480             prmsg (4,"SocketINETConnect Skipping IPv4 address\n");
1481             }
1482         }
1483         } else if (addrlist->addr->ai_family == AF_INET6) {
1484         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) socketaddr;
1485 
1486         prmsg (4,"SocketINETConnect() sockname.sin6_addr = %s\n",
1487             inet_ntop(addrlist->addr->ai_family,
1488                   &sin6->sin6_addr,ntopbuf,sizeof(ntopbuf)));
1489         prmsg (4,"SocketINETConnect() sockname.sin6_port = %d\n",
1490             ntohs(sin6->sin6_port));
1491 
1492         if (Sockettrans2devtab[ciptr->index].family == AF_INET) {
1493             if (strcmp(Sockettrans2devtab[ciptr->index].transname,
1494                 "tcp") == 0) {
1495             XtransConnInfo newciptr;
1496 
1497             /*
1498              * Close the IPv4 socket and try to open an IPv6 socket.
1499              */
1500             TRANS(SocketINETClose)(ciptr);
1501             newciptr = TRANS(SocketOpenCOTSClientBase)(
1502                     "tcp", "tcp", host, port, -1);
1503             if (newciptr)
1504                 ciptr->fd = newciptr->fd;
1505             if (!newciptr ||
1506                 Sockettrans2devtab[newciptr->index].family !=
1507                     AF_INET6) {
1508                 socketaddr = NULL;
1509                 prmsg (4,"SocketINETConnect() Cannot get IPv6 "
1510                    "socket for IPv6 address\n");
1511             }
1512             if (newciptr)
1513                 free(newciptr);
1514             }
1515             else
1516             {
1517             socketaddr = NULL;
1518             prmsg (4,"SocketINETConnect() Skipping IPv6 address\n");
1519             }
1520         }
1521 #endif /* IPv6 */
1522         } else {
1523         socketaddr = NULL; /* Unsupported address type */
1524         }
1525         if (socketaddr == NULL) {
1526         addrlist->addr = addrlist->addr->ai_next;
1527         }
1528     }
1529     }
1530 #else /* !HAVE_GETADDRINFO */
1531     {
1532     /*
1533      * Build the socket name.
1534      */
1535 
1536 #ifdef BSD44SOCKETS
1537     sockname.sin_len = sizeof (struct sockaddr_in);
1538 #endif
1539     sockname.sin_family = AF_INET;
1540 
1541     /*
1542      * fill in sin_addr
1543      */
1544 
1545 #ifndef INADDR_NONE
1546 #define INADDR_NONE ((in_addr_t) 0xffffffff)
1547 #endif
1548 
1549     /* check for ww.xx.yy.zz host string */
1550 
1551     if (isascii (host[0]) && isdigit (host[0])) {
1552         tmpaddr = inet_addr (host); /* returns network byte order */
1553     } else {
1554         tmpaddr = INADDR_NONE;
1555     }
1556 
1557     prmsg (4,"SocketINETConnect() inet_addr(%s) = %lx\n", host, tmpaddr);
1558 
1559     if (tmpaddr == INADDR_NONE) {
1560         if ((hostp = _XGethostbyname(host,hparams)) == NULL) {
1561         prmsg (1,"SocketINETConnect: Can't get address for %s\n",
1562             host);
1563         ESET(EINVAL);
1564         return TRANS_CONNECT_FAILED;
1565         }
1566         if (hostp->h_addrtype != AF_INET) {  /* is IP host? */
1567         prmsg (1,"SocketINETConnect: not INET host%s\n", host);
1568         ESET(EPROTOTYPE);
1569         return TRANS_CONNECT_FAILED;
1570         }
1571 
1572         memcpy ((char *) &sockname.sin_addr, (char *) hostp->h_addr,
1573             sizeof (sockname.sin_addr));
1574 
1575     } else {
1576         sockname.sin_addr.s_addr = tmpaddr;
1577         }
1578 
1579     /*
1580      * fill in sin_port
1581      */
1582 
1583     /* Check for number in the port string */
1584 
1585     if (!is_numeric (port)) {
1586         if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL) {
1587         prmsg (1,"SocketINETConnect: can't get service for %s\n",
1588             port);
1589         return TRANS_CONNECT_FAILED;
1590         }
1591         sockname.sin_port = htons (servp->s_port);
1592     } else {
1593         long tmpport = strtol (port, (char**)NULL, 10);
1594         if (tmpport < 1024 || tmpport > USHRT_MAX)
1595         return TRANS_CONNECT_FAILED;
1596         sockname.sin_port = htons (((unsigned short) tmpport));
1597     }
1598 
1599     prmsg (4,"SocketINETConnect: sockname.sin_port = %d\n",
1600         ntohs(sockname.sin_port));
1601     socketaddr = (struct sockaddr *) &sockname;
1602     socketaddrlen = sizeof(sockname);
1603     }
1604 #endif
1605 
1606     /*
1607      * Turn on socket keepalive so the client process will eventually
1608      * be notified with a SIGPIPE signal if the display server fails
1609      * to respond to a periodic transmission of messages
1610      * on the connected socket.
1611      * This is useful to avoid hung application processes when the
1612      * processes are not spawned from the xdm session and
1613      * the display server terminates abnormally.
1614      * (Someone turned off the power switch.)
1615      */
1616 
1617     {
1618     int tmp = 1;
1619     setsockopt (ciptr->fd, SOL_SOCKET, SO_KEEPALIVE,
1620         (char *) &tmp, sizeof (int));
1621     }
1622 
1623     /*
1624      * Do the connect()
1625      */
1626 
1627     if (connect (ciptr->fd, socketaddr, socketaddrlen ) < 0)
1628     {
1629 #ifdef WIN32
1630     int olderrno = WSAGetLastError();
1631 #else
1632     int olderrno = errno;
1633 #endif
1634 
1635     /*
1636      * If the error was ECONNREFUSED, the server may be overloaded
1637      * and we should try again.
1638      *
1639      * If the error was EWOULDBLOCK or EINPROGRESS then the socket
1640      * was non-blocking and we should poll using select
1641      *
1642      * If the error was EINTR, the connect was interrupted and we
1643      * should try again.
1644      *
1645      * If multiple addresses are found for a host then we should
1646      * try to connect again with a different address for a larger
1647      * number of errors that made us quit before, since those
1648      * could be caused by trying to use an IPv6 address to contact
1649      * a machine with an IPv4-only server or other reasons that
1650      * only affect one of a set of addresses.
1651      */
1652 
1653     if (olderrno == ECONNREFUSED || olderrno == EINTR
1654 #ifdef HAVE_GETADDRINFO
1655       || (((addrlist->addr->ai_next != NULL) ||
1656             (addrlist->addr != addrlist->firstaddr)) &&
1657                (olderrno == ENETUNREACH || olderrno == EAFNOSUPPORT ||
1658          olderrno == EADDRNOTAVAIL || olderrno == ETIMEDOUT
1659 #if defined(EHOSTDOWN)
1660            || olderrno == EHOSTDOWN
1661 #endif
1662            ))
1663 #endif
1664         )
1665         res = TRANS_TRY_CONNECT_AGAIN;
1666     else if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS)
1667         res = TRANS_IN_PROGRESS;
1668     else
1669     {
1670         prmsg (2,"SocketINETConnect: Can't connect: errno = %d\n",
1671            olderrno);
1672 
1673         res = TRANS_CONNECT_FAILED;
1674     }
1675     } else {
1676     res = 0;
1677 
1678 
1679     /*
1680      * Sync up the address fields of ciptr.
1681      */
1682 
1683     if (TRANS(SocketINETGetAddr) (ciptr) < 0)
1684     {
1685         prmsg (1,
1686          "SocketINETConnect: ...SocketINETGetAddr() failed:\n");
1687         res = TRANS_CONNECT_FAILED;
1688     }
1689 
1690     else if (TRANS(SocketINETGetPeerAddr) (ciptr) < 0)
1691     {
1692         prmsg (1,
1693           "SocketINETConnect: ...SocketINETGetPeerAddr() failed:\n");
1694         res = TRANS_CONNECT_FAILED;
1695     }
1696     }
1697 
1698 #ifdef HAVE_GETADDRINFO
1699    if (res != 0) {
1700     addrlist->addr = addrlist->addr->ai_next;
1701    }
1702 #endif
1703 
1704     return res;
1705 }
1706 
1707 #endif /* TCPCONN */
1708 
1709 
1710 
1711 #ifdef UNIXCONN
1712 
1713 /*
1714  * Make sure 'host' is really local.
1715  */
1716 
1717 static int
1718 UnixHostReallyLocal (const char *host)
1719 
1720 {
1721     char hostnamebuf[256];
1722 
1723     TRANS(GetHostname) (hostnamebuf, sizeof (hostnamebuf));
1724 
1725     if (strcmp (hostnamebuf, host) == 0)
1726     {
1727     return (1);
1728     } else {
1729 #ifdef HAVE_GETADDRINFO
1730     struct addrinfo *localhostaddr;
1731     struct addrinfo *otherhostaddr;
1732     struct addrinfo *i, *j;
1733     int equiv = 0;
1734 
1735     if (getaddrinfo(hostnamebuf, NULL, NULL, &localhostaddr) != 0)
1736         return 0;
1737     if (getaddrinfo(host, NULL, NULL, &otherhostaddr) != 0) {
1738         freeaddrinfo(localhostaddr);
1739         return 0;
1740     }
1741 
1742     for (i = localhostaddr; i != NULL && equiv == 0; i = i->ai_next) {
1743         for (j = otherhostaddr; j != NULL && equiv == 0; j = j->ai_next) {
1744         if (i->ai_family == j->ai_family) {
1745             if (i->ai_family == AF_INET) {
1746             struct sockaddr_in *sinA
1747               = (struct sockaddr_in *) i->ai_addr;
1748             struct sockaddr_in *sinB
1749               = (struct sockaddr_in *) j->ai_addr;
1750             struct in_addr *A = &sinA->sin_addr;
1751             struct in_addr *B = &sinB->sin_addr;
1752 
1753             if (memcmp(A,B,sizeof(struct in_addr)) == 0) {
1754                 equiv = 1;
1755             }
1756 #ifdef IPv6
1757             } else if (i->ai_family == AF_INET6) {
1758             struct sockaddr_in6 *sinA
1759               = (struct sockaddr_in6 *) i->ai_addr;
1760             struct sockaddr_in6 *sinB
1761               = (struct sockaddr_in6 *) j->ai_addr;
1762             struct in6_addr *A = &sinA->sin6_addr;
1763             struct in6_addr *B = &sinB->sin6_addr;
1764 
1765             if (memcmp(A,B,sizeof(struct in6_addr)) == 0) {
1766                 equiv = 1;
1767             }
1768 #endif /* IPv6 */
1769             }
1770         }
1771         }
1772     }
1773 
1774     freeaddrinfo(localhostaddr);
1775     freeaddrinfo(otherhostaddr);
1776     return equiv;
1777 #else /* !HAVE_GETADDRINFO */
1778     /*
1779      * A host may have more than one network address.  If any of the
1780      * network addresses of 'host' (specified to the connect call)
1781      * match any of the network addresses of 'hostname' (determined
1782      * by TRANS(GetHostname)), then the two hostnames are equivalent,
1783      * and we know that 'host' is really a local host.
1784      */
1785     char specified_local_addr_list[10][4];
1786     int scount, equiv, i, j;
1787 #ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1788     _Xgethostbynameparams hparams;
1789 #endif
1790     struct hostent *hostp;
1791 
1792     if ((hostp = _XGethostbyname (host,hparams)) == NULL)
1793         return (0);
1794 
1795     scount = 0;
1796     while (hostp->h_addr_list[scount] && scount <= 8)
1797     {
1798         /*
1799          * The 2nd call to gethostname() overrides the data
1800          * from the 1st call, so we must save the address list.
1801          */
1802 
1803         specified_local_addr_list[scount][0] =
1804                 hostp->h_addr_list[scount][0];
1805         specified_local_addr_list[scount][1] =
1806                 hostp->h_addr_list[scount][1];
1807         specified_local_addr_list[scount][2] =
1808                 hostp->h_addr_list[scount][2];
1809         specified_local_addr_list[scount][3] =
1810                 hostp->h_addr_list[scount][3];
1811         scount++;
1812     }
1813     if ((hostp = _XGethostbyname (hostnamebuf,hparams)) == NULL)
1814         return (0);
1815 
1816     equiv = 0;
1817     i = 0;
1818 
1819     while (i < scount && !equiv)
1820     {
1821         j = 0;
1822 
1823         while (hostp->h_addr_list[j])
1824         {
1825         if ((specified_local_addr_list[i][0] ==
1826                     hostp->h_addr_list[j][0]) &&
1827             (specified_local_addr_list[i][1] ==
1828                     hostp->h_addr_list[j][1]) &&
1829             (specified_local_addr_list[i][2] ==
1830                     hostp->h_addr_list[j][2]) &&
1831             (specified_local_addr_list[i][3] ==
1832                     hostp->h_addr_list[j][3]))
1833         {
1834             /* They're equal, so we're done */
1835 
1836             equiv = 1;
1837             break;
1838         }
1839 
1840         j++;
1841         }
1842 
1843         i++;
1844     }
1845     return (equiv);
1846 #endif
1847     }
1848 }
1849 
1850 static int
1851 TRANS(SocketUNIXConnect) (XtransConnInfo ciptr,
1852                           const char *host, const char *port)
1853 
1854 {
1855     struct sockaddr_un  sockname;
1856     SOCKLEN_T       namelen;
1857 
1858     prmsg (2,"SocketUNIXConnect(%d,%s,%s)\n", ciptr->fd, host, port);
1859 
1860     /*
1861      * Make sure 'host' is really local.  If not, we return failure.
1862      * The reason we make this check is because a process may advertise
1863      * a "local" network ID for which it can accept connections, but if
1864      * a process on a remote machine tries to connect to this network ID,
1865      * we know for sure it will fail.
1866      */
1867 
1868     if (host && *host && host[0]!='/' && strcmp (host, "unix") != 0 && !UnixHostReallyLocal (host))
1869     {
1870     prmsg (1,
1871        "SocketUNIXConnect: Cannot connect to non-local host %s\n",
1872            host);
1873     return TRANS_CONNECT_FAILED;
1874     }
1875 
1876 
1877     /*
1878      * Check the port.
1879      */
1880 
1881     if (!port || !*port)
1882     {
1883     prmsg (1,"SocketUNIXConnect: Missing port specification\n");
1884     return TRANS_CONNECT_FAILED;
1885     }
1886 
1887     /*
1888      * Build the socket name.
1889      */
1890 
1891     sockname.sun_family = AF_UNIX;
1892 
1893     if (set_sun_path(port, UNIX_PATH, sockname.sun_path, 0) != 0) {
1894     prmsg (1, "SocketUNIXConnect: path too long\n");
1895     return TRANS_CONNECT_FAILED;
1896     }
1897 
1898 #if defined(BSD44SOCKETS)
1899     sockname.sun_len = strlen (sockname.sun_path);
1900 #endif
1901 
1902 #if defined(BSD44SOCKETS) || defined(SUN_LEN)
1903     namelen = SUN_LEN (&sockname);
1904 #else
1905     namelen = strlen (sockname.sun_path) + offsetof(struct sockaddr_un, sun_path);
1906 #endif
1907 
1908 
1909     /*
1910      * Do the connect()
1911      */
1912 
1913     if (connect (ciptr->fd, (struct sockaddr *) &sockname, namelen) < 0)
1914     {
1915     int olderrno = errno;
1916     int connected = 0;
1917 
1918     if (!connected)
1919     {
1920         errno = olderrno;
1921 
1922         /*
1923          * If the error was ENOENT, the server may be starting up; we used
1924          * to suggest to try again in this case with
1925          * TRANS_TRY_CONNECT_AGAIN, but this introduced problems for
1926          * processes still referencing stale sockets in their environment.
1927          * Hence, we now return a hard error, TRANS_CONNECT_FAILED, and it
1928          * is suggested that higher level stacks handle retries on their
1929          * level when they face a slow starting server.
1930          *
1931          * If the error was EWOULDBLOCK or EINPROGRESS then the socket
1932          * was non-blocking and we should poll using select
1933          *
1934          * If the error was EINTR, the connect was interrupted and we
1935          * should try again.
1936          */
1937 
1938         if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS)
1939         return TRANS_IN_PROGRESS;
1940         else if (olderrno == EINTR)
1941         return TRANS_TRY_CONNECT_AGAIN;
1942         else {
1943         prmsg (2,"SocketUNIXConnect: Can't connect: errno = %d\n",
1944                EGET());
1945 
1946         return TRANS_CONNECT_FAILED;
1947         }
1948     }
1949     }
1950 
1951     /*
1952      * Get the socket name and the peer name from the connect socket,
1953      * since this is unix domain.
1954      */
1955 
1956     if ((ciptr->addr = malloc(namelen)) == NULL ||
1957        (ciptr->peeraddr = malloc(namelen)) == NULL)
1958     {
1959         prmsg (1,
1960     "SocketUNIXCreateListener: Can't allocate space for the addr\n");
1961         return TRANS_CONNECT_FAILED;
1962     }
1963 
1964     ciptr->family = AF_UNIX;
1965     ciptr->addrlen = namelen;
1966     ciptr->peeraddrlen = namelen;
1967     memcpy (ciptr->addr, &sockname, ciptr->addrlen);
1968     memcpy (ciptr->peeraddr, &sockname, ciptr->peeraddrlen);
1969 
1970     return 0;
1971 }
1972 
1973 #endif /* UNIXCONN */
1974 
1975 #endif /* TRANS_CLIENT */
1976 
1977 
1978 static int
1979 TRANS(SocketBytesReadable) (XtransConnInfo ciptr, BytesReadable_t *pend)
1980 
1981 {
1982     prmsg (2,"SocketBytesReadable(%p,%d,%p)\n",
1983     (void *) ciptr, ciptr->fd, (void *) pend);
1984 #ifdef WIN32
1985     {
1986     int ret = ioctlsocket ((SOCKET) ciptr->fd, FIONREAD, (u_long *) pend);
1987     if (ret == SOCKET_ERROR) errno = WSAGetLastError();
1988     return ret;
1989     }
1990 #else
1991     return ioctl (ciptr->fd, FIONREAD, (char *) pend);
1992 #endif /* WIN32 */
1993 }
1994 
1995 #if XTRANS_SEND_FDS
1996 
1997 static void
1998 appendFd(struct _XtransConnFd **prev, int fd, int do_close)
1999 {
2000     struct _XtransConnFd *cf, *new;
2001 
2002     new = malloc (sizeof (struct _XtransConnFd));
2003     if (!new) {
2004         /* XXX mark connection as broken */
2005         close(fd);
2006         return;
2007     }
2008     new->next = 0;
2009     new->fd = fd;
2010     new->do_close = do_close;
2011     /* search to end of list */
2012     for (; (cf = *prev); prev = &(cf->next));
2013     *prev = new;
2014 }
2015 
2016 static int
2017 removeFd(struct _XtransConnFd **prev)
2018 {
2019     struct _XtransConnFd *cf;
2020     int fd;
2021 
2022     if ((cf = *prev)) {
2023         *prev = cf->next;
2024         fd = cf->fd;
2025         free(cf);
2026     } else
2027         fd = -1;
2028     return fd;
2029 }
2030 
2031 static void
2032 discardFd(struct _XtransConnFd **prev, struct _XtransConnFd *upto, int do_close)
2033 {
2034     struct _XtransConnFd *cf, *next;
2035 
2036     for (cf = *prev; cf != upto; cf = next) {
2037         next = cf->next;
2038         if (do_close || cf->do_close)
2039             close(cf->fd);
2040         free(cf);
2041     }
2042     *prev = upto;
2043 }
2044 
2045 static void
2046 cleanupFds(XtransConnInfo ciptr)
2047 {
2048     /* Clean up the send list but don't close the fds */
2049     discardFd(&ciptr->send_fds, NULL, 0);
2050     /* Clean up the recv list and *do* close the fds */
2051     discardFd(&ciptr->recv_fds, NULL, 1);
2052 }
2053 
2054 static int
2055 nFd(struct _XtransConnFd **prev)
2056 {
2057     struct _XtransConnFd *cf;
2058     int n = 0;
2059 
2060     for (cf = *prev; cf; cf = cf->next)
2061         n++;
2062     return n;
2063 }
2064 
2065 static int
2066 TRANS(SocketRecvFd) (XtransConnInfo ciptr)
2067 {
2068     prmsg (2, "SocketRecvFd(%d)\n", ciptr->fd);
2069     return removeFd(&ciptr->recv_fds);
2070 }
2071 
2072 static int
2073 TRANS(SocketSendFd) (XtransConnInfo ciptr, int fd, int do_close)
2074 {
2075     appendFd(&ciptr->send_fds, fd, do_close);
2076     return 0;
2077 }
2078 
2079 static int
2080 TRANS(SocketRecvFdInvalid)(XtransConnInfo ciptr)
2081 {
2082     errno = EINVAL;
2083     return -1;
2084 }
2085 
2086 static int
2087 TRANS(SocketSendFdInvalid)(XtransConnInfo ciptr, int fd, int do_close)
2088 {
2089     errno = EINVAL;
2090     return -1;
2091 }
2092 
2093 #define MAX_FDS     128
2094 
2095 union fd_pass {
2096     struct cmsghdr  cmsghdr;
2097     char        buf[CMSG_SPACE(MAX_FDS * sizeof(int))];
2098 };
2099 
2100 #endif /* XTRANS_SEND_FDS */
2101 
2102 static int
2103 TRANS(SocketRead) (XtransConnInfo ciptr, char *buf, int size)
2104 
2105 {
2106     prmsg (2,"SocketRead(%d,%p,%d)\n", ciptr->fd, (void *) buf, size);
2107 
2108 #if defined(WIN32)
2109     {
2110     int ret = recv ((SOCKET)ciptr->fd, buf, size, 0);
2111 #ifdef WIN32
2112     if (ret == SOCKET_ERROR) errno = WSAGetLastError();
2113 #endif
2114     return ret;
2115     }
2116 #else
2117 #if XTRANS_SEND_FDS
2118     {
2119         struct iovec    iov = {
2120             .iov_base = buf,
2121             .iov_len = size
2122         };
2123         union fd_pass   cmsgbuf;
2124         struct msghdr   msg = {
2125             .msg_name = NULL,
2126             .msg_namelen = 0,
2127             .msg_iov = &iov,
2128             .msg_iovlen = 1,
2129             .msg_control = cmsgbuf.buf,
2130             .msg_controllen = CMSG_LEN(MAX_FDS * sizeof(int))
2131         };
2132 
2133         size = recvmsg(ciptr->fd, &msg, 0);
2134         if (size >= 0) {
2135             struct cmsghdr *hdr;
2136 
2137             for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) {
2138                 if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) {
2139                     int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int);
2140                     int i;
2141                     int *fd = (int *) CMSG_DATA(hdr);
2142 
2143                     for (i = 0; i < nfd; i++)
2144                         appendFd(&ciptr->recv_fds, fd[i], 0);
2145                 }
2146             }
2147         }
2148         return size;
2149     }
2150 #else
2151     return read(ciptr->fd, buf, size);
2152 #endif /* XTRANS_SEND_FDS */
2153 #endif /* WIN32 */
2154 }
2155 
2156 static int
2157 TRANS(SocketReadv) (XtransConnInfo ciptr, struct iovec *buf, int size)
2158 
2159 {
2160     prmsg (2,"SocketReadv(%d,%p,%d)\n", ciptr->fd, (void *) buf, size);
2161 
2162 #if XTRANS_SEND_FDS
2163     {
2164         union fd_pass   cmsgbuf;
2165         struct msghdr   msg = {
2166             .msg_name = NULL,
2167             .msg_namelen = 0,
2168             .msg_iov = buf,
2169             .msg_iovlen = size,
2170             .msg_control = cmsgbuf.buf,
2171             .msg_controllen = CMSG_LEN(MAX_FDS * sizeof(int))
2172         };
2173 
2174         size = recvmsg(ciptr->fd, &msg, 0);
2175         if (size >= 0) {
2176             struct cmsghdr *hdr;
2177 
2178             for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) {
2179                 if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) {
2180                     int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int);
2181                     int i;
2182                     int *fd = (int *) CMSG_DATA(hdr);
2183 
2184                     for (i = 0; i < nfd; i++)
2185                         appendFd(&ciptr->recv_fds, fd[i], 0);
2186                 }
2187             }
2188         }
2189         return size;
2190     }
2191 #else
2192     return READV (ciptr, buf, size);
2193 #endif
2194 }
2195 
2196 
2197 static int
2198 TRANS(SocketWritev) (XtransConnInfo ciptr, struct iovec *buf, int size)
2199 
2200 {
2201     prmsg (2,"SocketWritev(%d,%p,%d)\n", ciptr->fd, (void *) buf, size);
2202 
2203 #if XTRANS_SEND_FDS
2204     if (ciptr->send_fds)
2205     {
2206         union fd_pass           cmsgbuf;
2207         int                     nfd = nFd(&ciptr->send_fds);
2208         struct _XtransConnFd    *cf = ciptr->send_fds;
2209         struct msghdr           msg = {
2210             .msg_name = NULL,
2211             .msg_namelen = 0,
2212             .msg_iov = buf,
2213             .msg_iovlen = size,
2214             .msg_control = cmsgbuf.buf,
2215             .msg_controllen = CMSG_LEN(nfd * sizeof(int))
2216         };
2217         struct cmsghdr          *hdr = CMSG_FIRSTHDR(&msg);
2218         int                     i;
2219         int                     *fds;
2220 
2221         hdr->cmsg_len = msg.msg_controllen;
2222         hdr->cmsg_level = SOL_SOCKET;
2223         hdr->cmsg_type = SCM_RIGHTS;
2224 
2225         fds = (int *) CMSG_DATA(hdr);
2226         /* Set up fds */
2227         for (i = 0; i < nfd; i++) {
2228             fds[i] = cf->fd;
2229             cf = cf->next;
2230         }
2231 
2232         i = sendmsg(ciptr->fd, &msg, 0);
2233         if (i > 0)
2234             discardFd(&ciptr->send_fds, cf, 0);
2235         return i;
2236     }
2237 #endif
2238     return WRITEV (ciptr, buf, size);
2239 }
2240 
2241 
2242 static int
2243 TRANS(SocketWrite) (XtransConnInfo ciptr, const char *buf, int size)
2244 
2245 {
2246     prmsg (2,"SocketWrite(%d,%p,%d)\n", ciptr->fd, (const void *) buf, size);
2247 
2248 #if defined(WIN32)
2249     {
2250     int ret = send ((SOCKET)ciptr->fd, buf, size, 0);
2251 #ifdef WIN32
2252     if (ret == SOCKET_ERROR) errno = WSAGetLastError();
2253 #endif
2254     return ret;
2255     }
2256 #else
2257 #if XTRANS_SEND_FDS
2258     if (ciptr->send_fds)
2259     {
2260         struct iovec            iov;
2261 
2262         iov.iov_base = (void *) buf;
2263         iov.iov_len = size;
2264         return TRANS(SocketWritev)(ciptr, &iov, 1);
2265     }
2266 #endif /* XTRANS_SEND_FDS */
2267     return write (ciptr->fd, buf, size);
2268 #endif /* WIN32 */
2269 }
2270 
2271 static int
2272 TRANS(SocketDisconnect) (XtransConnInfo ciptr)
2273 
2274 {
2275     prmsg (2,"SocketDisconnect(%p,%d)\n", (void *) ciptr, ciptr->fd);
2276 
2277 #ifdef WIN32
2278     {
2279     int ret = shutdown (ciptr->fd, 2);
2280     if (ret == SOCKET_ERROR) errno = WSAGetLastError();
2281     return ret;
2282     }
2283 #else
2284     return shutdown (ciptr->fd, 2); /* disallow further sends and receives */
2285 #endif
2286 }
2287 
2288 
2289 #ifdef TCPCONN
2290 static int
2291 TRANS(SocketINETClose) (XtransConnInfo ciptr)
2292 
2293 {
2294     prmsg (2,"SocketINETClose(%p,%d)\n", (void *) ciptr, ciptr->fd);
2295 
2296 #ifdef WIN32
2297     {
2298     int ret = close (ciptr->fd);
2299     if (ret == SOCKET_ERROR) errno = WSAGetLastError();
2300     return ret;
2301     }
2302 #else
2303     return close (ciptr->fd);
2304 #endif
2305 }
2306 
2307 #endif /* TCPCONN */
2308 
2309 
2310 #ifdef UNIXCONN
2311 static int
2312 TRANS(SocketUNIXClose) (XtransConnInfo ciptr)
2313 {
2314     /*
2315      * If this is the server side, then once the socket is closed,
2316      * it must be unlinked to completely close it
2317      */
2318 
2319     struct sockaddr_un  *sockname = (struct sockaddr_un *) ciptr->addr;
2320     int ret;
2321 
2322     prmsg (2,"SocketUNIXClose(%p,%d)\n", (void *) ciptr, ciptr->fd);
2323 
2324 #if XTRANS_SEND_FDS
2325     cleanupFds(ciptr);
2326 #endif
2327     ret = close(ciptr->fd);
2328 
2329     if (ciptr->flags
2330        && sockname
2331        && sockname->sun_family == AF_UNIX
2332        && sockname->sun_path[0])
2333     {
2334     if (!(ciptr->flags & TRANS_NOUNLINK
2335         || ciptr->transptr->flags & TRANS_ABSTRACT))
2336         unlink (sockname->sun_path);
2337     }
2338 
2339     return ret;
2340 }
2341 
2342 static int
2343 TRANS(SocketUNIXCloseForCloning) (XtransConnInfo ciptr)
2344 
2345 {
2346     /*
2347      * Don't unlink path.
2348      */
2349 
2350     int ret;
2351 
2352     prmsg (2,"SocketUNIXCloseForCloning(%p,%d)\n",
2353     (void *) ciptr, ciptr->fd);
2354 
2355 #if XTRANS_SEND_FDS
2356     cleanupFds(ciptr);
2357 #endif
2358     ret = close(ciptr->fd);
2359 
2360     return ret;
2361 }
2362 
2363 #endif /* UNIXCONN */
2364 
2365 
2366 #ifdef TCPCONN
2367 # ifdef TRANS_SERVER
2368 static const char* tcp_nolisten[] = {
2369     "inet",
2370 #ifdef IPv6
2371     "inet6",
2372 #endif
2373     NULL
2374 };
2375 # endif
2376 
2377 static Xtransport   TRANS(SocketTCPFuncs) = {
2378     /* Socket Interface */
2379     "tcp",
2380         TRANS_ALIAS,
2381 #ifdef TRANS_CLIENT
2382     TRANS(SocketOpenCOTSClient),
2383 #endif /* TRANS_CLIENT */
2384 #ifdef TRANS_SERVER
2385     tcp_nolisten,
2386     TRANS(SocketOpenCOTSServer),
2387 #endif /* TRANS_SERVER */
2388 #ifdef TRANS_REOPEN
2389     TRANS(SocketReopenCOTSServer),
2390 #endif
2391     TRANS(SocketSetOption),
2392 #ifdef TRANS_SERVER
2393     TRANS(SocketINETCreateListener),
2394     NULL,                       /* ResetListener */
2395     TRANS(SocketINETAccept),
2396 #endif /* TRANS_SERVER */
2397 #ifdef TRANS_CLIENT
2398     TRANS(SocketINETConnect),
2399 #endif /* TRANS_CLIENT */
2400     TRANS(SocketBytesReadable),
2401     TRANS(SocketRead),
2402     TRANS(SocketWrite),
2403     TRANS(SocketReadv),
2404     TRANS(SocketWritev),
2405 #if XTRANS_SEND_FDS
2406         TRANS(SocketSendFdInvalid),
2407         TRANS(SocketRecvFdInvalid),
2408 #endif
2409     TRANS(SocketDisconnect),
2410     TRANS(SocketINETClose),
2411     TRANS(SocketINETClose),
2412     };
2413 
2414 static Xtransport   TRANS(SocketINETFuncs) = {
2415     /* Socket Interface */
2416     "inet",
2417     0,
2418 #ifdef TRANS_CLIENT
2419     TRANS(SocketOpenCOTSClient),
2420 #endif /* TRANS_CLIENT */
2421 #ifdef TRANS_SERVER
2422     NULL,
2423     TRANS(SocketOpenCOTSServer),
2424 #endif /* TRANS_SERVER */
2425 #ifdef TRANS_REOPEN
2426     TRANS(SocketReopenCOTSServer),
2427 #endif
2428     TRANS(SocketSetOption),
2429 #ifdef TRANS_SERVER
2430     TRANS(SocketINETCreateListener),
2431     NULL,                       /* ResetListener */
2432     TRANS(SocketINETAccept),
2433 #endif /* TRANS_SERVER */
2434 #ifdef TRANS_CLIENT
2435     TRANS(SocketINETConnect),
2436 #endif /* TRANS_CLIENT */
2437     TRANS(SocketBytesReadable),
2438     TRANS(SocketRead),
2439     TRANS(SocketWrite),
2440     TRANS(SocketReadv),
2441     TRANS(SocketWritev),
2442 #if XTRANS_SEND_FDS
2443         TRANS(SocketSendFdInvalid),
2444         TRANS(SocketRecvFdInvalid),
2445 #endif
2446     TRANS(SocketDisconnect),
2447     TRANS(SocketINETClose),
2448     TRANS(SocketINETClose),
2449     };
2450 
2451 #ifdef IPv6
2452 static Xtransport     TRANS(SocketINET6Funcs) = {
2453     /* Socket Interface */
2454     "inet6",
2455     0,
2456 #ifdef TRANS_CLIENT
2457     TRANS(SocketOpenCOTSClient),
2458 #endif /* TRANS_CLIENT */
2459 #ifdef TRANS_SERVER
2460     NULL,
2461     TRANS(SocketOpenCOTSServer),
2462 #endif /* TRANS_SERVER */
2463 #ifdef TRANS_REOPEN
2464     TRANS(SocketReopenCOTSServer),
2465 #endif
2466     TRANS(SocketSetOption),
2467 #ifdef TRANS_SERVER
2468     TRANS(SocketINETCreateListener),
2469     NULL,                   /* ResetListener */
2470     TRANS(SocketINETAccept),
2471 #endif /* TRANS_SERVER */
2472 #ifdef TRANS_CLIENT
2473     TRANS(SocketINETConnect),
2474 #endif /* TRANS_CLIENT */
2475     TRANS(SocketBytesReadable),
2476     TRANS(SocketRead),
2477     TRANS(SocketWrite),
2478     TRANS(SocketReadv),
2479     TRANS(SocketWritev),
2480 #if XTRANS_SEND_FDS
2481         TRANS(SocketSendFdInvalid),
2482         TRANS(SocketRecvFdInvalid),
2483 #endif
2484     TRANS(SocketDisconnect),
2485     TRANS(SocketINETClose),
2486     TRANS(SocketINETClose),
2487     };
2488 #endif /* IPv6 */
2489 #endif /* TCPCONN */
2490 
2491 #ifdef UNIXCONN
2492 #if !defined(LOCALCONN)
2493 static Xtransport   TRANS(SocketLocalFuncs) = {
2494     /* Socket Interface */
2495     "local",
2496 #ifdef HAVE_ABSTRACT_SOCKETS
2497     TRANS_ABSTRACT,
2498 #else
2499     0,
2500 #endif
2501 #ifdef TRANS_CLIENT
2502     TRANS(SocketOpenCOTSClient),
2503 #endif /* TRANS_CLIENT */
2504 #ifdef TRANS_SERVER
2505     NULL,
2506     TRANS(SocketOpenCOTSServer),
2507 #endif /* TRANS_SERVER */
2508 #ifdef TRANS_REOPEN
2509     TRANS(SocketReopenCOTSServer),
2510 #endif
2511     TRANS(SocketSetOption),
2512 #ifdef TRANS_SERVER
2513     TRANS(SocketUNIXCreateListener),
2514     TRANS(SocketUNIXResetListener),
2515     TRANS(SocketUNIXAccept),
2516 #endif /* TRANS_SERVER */
2517 #ifdef TRANS_CLIENT
2518     TRANS(SocketUNIXConnect),
2519 #endif /* TRANS_CLIENT */
2520     TRANS(SocketBytesReadable),
2521     TRANS(SocketRead),
2522     TRANS(SocketWrite),
2523     TRANS(SocketReadv),
2524     TRANS(SocketWritev),
2525 #if XTRANS_SEND_FDS
2526         TRANS(SocketSendFd),
2527         TRANS(SocketRecvFd),
2528 #endif
2529     TRANS(SocketDisconnect),
2530     TRANS(SocketUNIXClose),
2531     TRANS(SocketUNIXCloseForCloning),
2532     };
2533 #endif /* !LOCALCONN */
2534 # ifdef TRANS_SERVER
2535 #  if !defined(LOCALCONN)
2536 static const char* unix_nolisten[] = { "local" , NULL };
2537 #  endif
2538 # endif
2539 
2540 static Xtransport   TRANS(SocketUNIXFuncs) = {
2541     /* Socket Interface */
2542     "unix",
2543 #if !defined(LOCALCONN) && !defined(HAVE_ABSTRACT_SOCKETS)
2544         TRANS_ALIAS,
2545 #else
2546     0,
2547 #endif
2548 #ifdef TRANS_CLIENT
2549     TRANS(SocketOpenCOTSClient),
2550 #endif /* TRANS_CLIENT */
2551 #ifdef TRANS_SERVER
2552 #if !defined(LOCALCONN)
2553     unix_nolisten,
2554 #else
2555     NULL,
2556 #endif
2557     TRANS(SocketOpenCOTSServer),
2558 #endif /* TRANS_SERVER */
2559 #ifdef TRANS_REOPEN
2560     TRANS(SocketReopenCOTSServer),
2561 #endif
2562     TRANS(SocketSetOption),
2563 #ifdef TRANS_SERVER
2564     TRANS(SocketUNIXCreateListener),
2565     TRANS(SocketUNIXResetListener),
2566     TRANS(SocketUNIXAccept),
2567 #endif /* TRANS_SERVER */
2568 #ifdef TRANS_CLIENT
2569     TRANS(SocketUNIXConnect),
2570 #endif /* TRANS_CLIENT */
2571     TRANS(SocketBytesReadable),
2572     TRANS(SocketRead),
2573     TRANS(SocketWrite),
2574     TRANS(SocketReadv),
2575     TRANS(SocketWritev),
2576 #if XTRANS_SEND_FDS
2577         TRANS(SocketSendFd),
2578         TRANS(SocketRecvFd),
2579 #endif
2580     TRANS(SocketDisconnect),
2581     TRANS(SocketUNIXClose),
2582     TRANS(SocketUNIXCloseForCloning),
2583     };
2584 
2585 #endif /* UNIXCONN */