Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:14:28

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