1af928962Smrg/*
2ac57ed83Smrg * Copyright (c) 2002, 2025, Oracle and/or its affiliates.
3af928962Smrg *
4af928962Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5af928962Smrg * copy of this software and associated documentation files (the "Software"),
6af928962Smrg * to deal in the Software without restriction, including without limitation
7af928962Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8af928962Smrg * and/or sell copies of the Software, and to permit persons to whom the
9af928962Smrg * Software is furnished to do so, subject to the following conditions:
10af928962Smrg *
11af928962Smrg * The above copyright notice and this permission notice (including the next
12af928962Smrg * paragraph) shall be included in all copies or substantial portions of the
13af928962Smrg * Software.
14af928962Smrg *
15af928962Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16af928962Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17af928962Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18af928962Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19af928962Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20af928962Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21af928962Smrg * DEALINGS IN THE SOFTWARE.
22af928962Smrg */
2373143b9aSmrg/*
2473143b9aSmrg
2573143b9aSmrgCopyright 1993, 1994, 1998  The Open Group
2673143b9aSmrg
2773143b9aSmrgPermission to use, copy, modify, distribute, and sell this software and its
2873143b9aSmrgdocumentation for any purpose is hereby granted without fee, provided that
2973143b9aSmrgthe above copyright notice appear in all copies and that both that
3073143b9aSmrgcopyright notice and this permission notice appear in supporting
3173143b9aSmrgdocumentation.
3273143b9aSmrg
3373143b9aSmrgThe above copyright notice and this permission notice shall be included
3473143b9aSmrgin all copies or substantial portions of the Software.
3573143b9aSmrg
3673143b9aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
3773143b9aSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
3873143b9aSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
3973143b9aSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
4073143b9aSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
4173143b9aSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
4273143b9aSmrgOTHER DEALINGS IN THE SOFTWARE.
4373143b9aSmrg
4473143b9aSmrgExcept as contained in this notice, the name of the copyright holders shall
4573143b9aSmrgnot be used in advertising or otherwise to promote the sale, use or
4673143b9aSmrgother dealings in this Software without prior written authorization
4773143b9aSmrgfrom the copyright holders.
4873143b9aSmrg
4973143b9aSmrg * Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA
5073143b9aSmrg *
5173143b9aSmrg * All Rights Reserved
5273143b9aSmrg *
5373143b9aSmrg * Permission to use, copy, modify, and distribute this software and its
5473143b9aSmrg * documentation for any purpose and without fee is hereby granted, provided
5573143b9aSmrg * that the above copyright notice appear in all copies and that both that
5673143b9aSmrg * copyright notice and this permission notice appear in supporting
5773143b9aSmrg * documentation, and that the name NCR not be used in advertising
5873143b9aSmrg * or publicity pertaining to distribution of the software without specific,
5973143b9aSmrg * written prior permission.  NCR makes no representations about the
6073143b9aSmrg * suitability of this software for any purpose.  It is provided "as is"
6173143b9aSmrg * without express or implied warranty.
6273143b9aSmrg *
6373143b9aSmrg * NCR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
6473143b9aSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
6573143b9aSmrg * NO EVENT SHALL NCR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
6673143b9aSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
6773143b9aSmrg * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
6873143b9aSmrg * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
6973143b9aSmrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
7073143b9aSmrg */
7173143b9aSmrg
7273143b9aSmrg#include <ctype.h>
7373143b9aSmrg#ifdef XTHREADS
7473143b9aSmrg#include <X11/Xthreads.h>
7573143b9aSmrg#endif
7673143b9aSmrg
7773143b9aSmrg#ifndef WIN32
7873143b9aSmrg
7973143b9aSmrg#if defined(TCPCONN) || defined(UNIXCONN)
8073143b9aSmrg#include <sys/socket.h>
8173143b9aSmrg#include <netinet/in.h>
8273143b9aSmrg#include <arpa/inet.h>
8373143b9aSmrg#endif
8473143b9aSmrg
8573143b9aSmrg#if defined(TCPCONN) || defined(UNIXCONN)
8673143b9aSmrg#define X_INCLUDE_NETDB_H
8773143b9aSmrg#define XOS_USE_NO_LOCKING
8873143b9aSmrg#include <X11/Xos_r.h>
8973143b9aSmrg#endif
9073143b9aSmrg
9173143b9aSmrg#ifdef UNIXCONN
9273143b9aSmrg#ifndef X_NO_SYS_UN
9373143b9aSmrg#include <sys/un.h>
9473143b9aSmrg#endif
9573143b9aSmrg#include <sys/stat.h>
9673143b9aSmrg#endif
9773143b9aSmrg
9873143b9aSmrg
9973143b9aSmrg#ifndef NO_TCP_H
100fe567363Smrg#if defined(linux) || defined(__GLIBC__)
10173143b9aSmrg#include <sys/param.h>
10273143b9aSmrg#endif /* osf */
10373143b9aSmrg#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
10473143b9aSmrg#include <sys/param.h>
10573143b9aSmrg#include <machine/endian.h>
10673143b9aSmrg#endif /* __NetBSD__ || __OpenBSD__ || __FreeBSD__ || __DragonFly__ */
10773143b9aSmrg#include <netinet/tcp.h>
10873143b9aSmrg#endif /* !NO_TCP_H */
10973143b9aSmrg
11073143b9aSmrg#include <sys/ioctl.h>
111e8a71cdfSmrg#if defined(SVR4) || defined(__SVR4)
11273143b9aSmrg#include <sys/filio.h>
11373143b9aSmrg#endif
11473143b9aSmrg
1158d4c0f7bSmrg#include <unistd.h>
1168d4c0f7bSmrg
11773143b9aSmrg#else /* !WIN32 */
11873143b9aSmrg
11973143b9aSmrg#include <X11/Xwinsock.h>
12073143b9aSmrg#include <X11/Xwindows.h>
12173143b9aSmrg#include <X11/Xw32defs.h>
12273143b9aSmrg#undef close
12373143b9aSmrg#define close closesocket
12473143b9aSmrg#define ECONNREFUSED WSAECONNREFUSED
12573143b9aSmrg#define EADDRINUSE WSAEADDRINUSE
12673143b9aSmrg#define EPROTOTYPE WSAEPROTOTYPE
12773143b9aSmrg#undef EWOULDBLOCK
12873143b9aSmrg#define EWOULDBLOCK WSAEWOULDBLOCK
12973143b9aSmrg#define EINPROGRESS WSAEINPROGRESS
13073143b9aSmrg#undef EINTR
13173143b9aSmrg#define EINTR WSAEINTR
13273143b9aSmrg#define X_INCLUDE_NETDB_H
13373143b9aSmrg#define XOS_USE_MTSAFE_NETDBAPI
13473143b9aSmrg#include <X11/Xos_r.h>
13573143b9aSmrg#endif /* WIN32 */
13673143b9aSmrg
13773143b9aSmrg#if defined(SO_DONTLINGER) && defined(SO_LINGER)
13873143b9aSmrg#undef SO_DONTLINGER
13973143b9aSmrg#endif
14073143b9aSmrg
14173143b9aSmrg/* others don't need this */
14273143b9aSmrg#define SocketInitOnce() /**/
14373143b9aSmrg
144a773ec55Smrg#ifdef __linux__
14573143b9aSmrg#define HAVE_ABSTRACT_SOCKETS
14673143b9aSmrg#endif
14773143b9aSmrg
14873143b9aSmrg#define MIN_BACKLOG 128
14973143b9aSmrg#ifdef SOMAXCONN
15073143b9aSmrg#if SOMAXCONN > MIN_BACKLOG
15173143b9aSmrg#define BACKLOG SOMAXCONN
15273143b9aSmrg#endif
15373143b9aSmrg#endif
15473143b9aSmrg#ifndef BACKLOG
15573143b9aSmrg#define BACKLOG MIN_BACKLOG
15673143b9aSmrg#endif
15773143b9aSmrg
158ac57ed83Smrg#if defined(IPv6) && !defined(AF_INET6)
159ac57ed83Smrg#error "Cannot build IPv6 support without AF_INET6"
160ac57ed83Smrg#endif
161ac57ed83Smrg
162ac57ed83Smrg/* Temporary workaround for consumers whose configure scripts were
163ac57ed83Smrg   generated with pre-1.6 versions of xtrans.m4 */
164ac57ed83Smrg#if defined(IPv6) && !defined(HAVE_GETADDRINFO)
165ac57ed83Smrg#define HAVE_GETADDRINFO
166ac57ed83Smrg#endif
167ac57ed83Smrg
16873143b9aSmrg/*
16973143b9aSmrg * This is the Socket implementation of the X Transport service layer
17073143b9aSmrg *
17173143b9aSmrg * This file contains the implementation for both the UNIX and INET domains,
17273143b9aSmrg * and can be built for either one, or both.
17373143b9aSmrg *
17473143b9aSmrg */
17573143b9aSmrg
176fe567363Smrgtypedef struct _Sockettrans2dev {
177fe567363Smrg    const char	*transname;
17873143b9aSmrg    int		family;
17973143b9aSmrg    int		devcotsname;
18073143b9aSmrg    int		devcltsname;
18173143b9aSmrg    int		protocol;
18273143b9aSmrg} Sockettrans2dev;
18373143b9aSmrg
184ac57ed83Smrg/* As documented in the X(7) man page:
185ac57ed83Smrg *  tcp     TCP over IPv4 or IPv6
186ac57ed83Smrg *  inet    TCP over IPv4 only
187ac57ed83Smrg *  inet6   TCP over IPv6 only
188ac57ed83Smrg *  unix    UNIX Domain Sockets (same host only)
189ac57ed83Smrg *  local   Platform preferred local connection method
190ac57ed83Smrg */
19173143b9aSmrgstatic Sockettrans2dev Sockettrans2devtab[] = {
19273143b9aSmrg#ifdef TCPCONN
19373143b9aSmrg    {"inet",AF_INET,SOCK_STREAM,SOCK_DGRAM,0},
194ac57ed83Smrg#ifndef IPv6
19573143b9aSmrg    {"tcp",AF_INET,SOCK_STREAM,SOCK_DGRAM,0},
19673143b9aSmrg#else /* IPv6 */
19773143b9aSmrg    {"tcp",AF_INET6,SOCK_STREAM,SOCK_DGRAM,0},
19873143b9aSmrg    {"tcp",AF_INET,SOCK_STREAM,SOCK_DGRAM,0}, /* fallback */
19973143b9aSmrg    {"inet6",AF_INET6,SOCK_STREAM,SOCK_DGRAM,0},
20073143b9aSmrg#endif
20173143b9aSmrg#endif /* TCPCONN */
20273143b9aSmrg#ifdef UNIXCONN
20373143b9aSmrg    {"unix",AF_UNIX,SOCK_STREAM,SOCK_DGRAM,0},
20473143b9aSmrg#if !defined(LOCALCONN)
20573143b9aSmrg    {"local",AF_UNIX,SOCK_STREAM,SOCK_DGRAM,0},
20673143b9aSmrg#endif /* !LOCALCONN */
20773143b9aSmrg#endif /* UNIXCONN */
20873143b9aSmrg};
20973143b9aSmrg
21073143b9aSmrg#define NUMSOCKETFAMILIES (sizeof(Sockettrans2devtab)/sizeof(Sockettrans2dev))
21173143b9aSmrg
21273143b9aSmrg#ifdef TCPCONN
21373143b9aSmrgstatic int TRANS(SocketINETClose) (XtransConnInfo ciptr);
21473143b9aSmrg#endif
21573143b9aSmrg
216ac57ed83Smrg#if (defined(TCPCONN) && \
217ac57ed83Smrg     (defined(TRANS_SERVER) || defined(X11_t) || !defined(HAVE_GETADDRINFO))) \
218ac57ed83Smrg    || defined(TRANS_REOPEN)
219a773ec55Smrgstatic int
220a773ec55Smrgis_numeric (const char *str)
221a773ec55Smrg{
222a773ec55Smrg    int i;
223a773ec55Smrg
224a773ec55Smrg    for (i = 0; i < (int) strlen (str); i++)
225a773ec55Smrg	if (!isdigit (str[i]))
226a773ec55Smrg	    return (0);
227a773ec55Smrg
228a773ec55Smrg    return (1);
229a773ec55Smrg}
230a773ec55Smrg#endif
231a773ec55Smrg
23273143b9aSmrg#ifdef UNIXCONN
23373143b9aSmrg
23473143b9aSmrg
23573143b9aSmrg#if defined(X11_t)
23673143b9aSmrg#define UNIX_PATH "/tmp/.X11-unix/X"
23773143b9aSmrg#define UNIX_DIR "/tmp/.X11-unix"
23873143b9aSmrg#endif /* X11_t */
23973143b9aSmrg#if defined(XIM_t)
24073143b9aSmrg#define UNIX_PATH "/tmp/.XIM-unix/XIM"
24173143b9aSmrg#define UNIX_DIR "/tmp/.XIM-unix"
24273143b9aSmrg#endif /* XIM_t */
24373143b9aSmrg#if defined(FS_t) || defined(FONT_t)
24473143b9aSmrg#define UNIX_PATH "/tmp/.font-unix/fs"
24573143b9aSmrg#define UNIX_DIR "/tmp/.font-unix"
24673143b9aSmrg#endif /* FS_t || FONT_t */
24773143b9aSmrg#if defined(ICE_t)
24873143b9aSmrg#define UNIX_PATH "/tmp/.ICE-unix/"
24973143b9aSmrg#define UNIX_DIR "/tmp/.ICE-unix"
25073143b9aSmrg#endif /* ICE_t */
25173143b9aSmrg
25273143b9aSmrg
25373143b9aSmrg#endif /* UNIXCONN */
25473143b9aSmrg
25573143b9aSmrg#define PORTBUFSIZE	32
25673143b9aSmrg
25773143b9aSmrg#ifndef MAXHOSTNAMELEN
25873143b9aSmrg#define MAXHOSTNAMELEN 255
25973143b9aSmrg#endif
26073143b9aSmrg
261ac57ed83Smrg#if defined(HAVE_SOCKLEN_T) || defined(IPv6)
26273143b9aSmrg# define SOCKLEN_T socklen_t
263a773ec55Smrg#elif defined(SVR4) || defined(__SVR4)
264fe567363Smrg# define SOCKLEN_T size_t
26573143b9aSmrg#else
26673143b9aSmrg# define SOCKLEN_T int
26773143b9aSmrg#endif
26873143b9aSmrg
26973143b9aSmrg/*
27073143b9aSmrg * These are some utility function used by the real interface function below.
27173143b9aSmrg */
27273143b9aSmrg
27373143b9aSmrgstatic int
274fe567363SmrgTRANS(SocketSelectFamily) (int first, const char *family)
27573143b9aSmrg
27673143b9aSmrg{
27773143b9aSmrg    int     i;
27873143b9aSmrg
279fe567363Smrg    prmsg (3,"SocketSelectFamily(%s)\n", family);
28073143b9aSmrg
28194f982dbSmrg    for (i = first + 1; i < (int)NUMSOCKETFAMILIES; i++)
28273143b9aSmrg    {
28373143b9aSmrg        if (!strcmp (family, Sockettrans2devtab[i].transname))
28473143b9aSmrg	    return i;
28573143b9aSmrg    }
28673143b9aSmrg
28773143b9aSmrg    return (first == -1 ? -2 : -1);
28873143b9aSmrg}
28973143b9aSmrg
29073143b9aSmrg
29173143b9aSmrg/*
29273143b9aSmrg * This function gets the local address of the socket and stores it in the
29373143b9aSmrg * XtransConnInfo structure for the connection.
29473143b9aSmrg */
29573143b9aSmrg
29673143b9aSmrgstatic int
29773143b9aSmrgTRANS(SocketINETGetAddr) (XtransConnInfo ciptr)
29873143b9aSmrg
29973143b9aSmrg{
300ac57ed83Smrg#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
301ac57ed83Smrg    struct sockaddr_storage sockname;
302b53e5eeaSmrg#else
303ac57ed83Smrg    struct sockaddr_in sockname;
304b53e5eeaSmrg#endif
305ac57ed83Smrg    void *socknamePtr = &sockname;
306ac57ed83Smrg    SOCKLEN_T namelen = sizeof(sockname);
30773143b9aSmrg
308ac57ed83Smrg    prmsg (3,"SocketINETGetAddr(%p)\n", (void *) ciptr);
30973143b9aSmrg
31073143b9aSmrg    bzero(socknamePtr, namelen);
311fe567363Smrg
31273143b9aSmrg    if (getsockname (ciptr->fd,(struct sockaddr *) socknamePtr,
31373143b9aSmrg		     (void *)&namelen) < 0)
31473143b9aSmrg    {
31573143b9aSmrg#ifdef WIN32
31673143b9aSmrg	errno = WSAGetLastError();
31773143b9aSmrg#endif
318fe567363Smrg	prmsg (1,"SocketINETGetAddr: getsockname() failed: %d\n",
319fe567363Smrg	    EGET());
32073143b9aSmrg	return -1;
32173143b9aSmrg    }
32273143b9aSmrg
32373143b9aSmrg    /*
32473143b9aSmrg     * Everything looks good: fill in the XtransConnInfo structure.
32573143b9aSmrg     */
32673143b9aSmrg
327fe567363Smrg    if ((ciptr->addr = malloc (namelen)) == NULL)
32873143b9aSmrg    {
329fe567363Smrg        prmsg (1,
330fe567363Smrg	    "SocketINETGetAddr: Can't allocate space for the addr\n");
33173143b9aSmrg        return -1;
33273143b9aSmrg    }
33373143b9aSmrg
334b53e5eeaSmrg    ciptr->family = ((struct sockaddr *)socknamePtr)->sa_family;
33573143b9aSmrg    ciptr->addrlen = namelen;
33673143b9aSmrg    memcpy (ciptr->addr, socknamePtr, ciptr->addrlen);
33773143b9aSmrg
33873143b9aSmrg    return 0;
33973143b9aSmrg}
34073143b9aSmrg
34173143b9aSmrg
34273143b9aSmrg/*
34373143b9aSmrg * This function gets the remote address of the socket and stores it in the
34473143b9aSmrg * XtransConnInfo structure for the connection.
34573143b9aSmrg */
34673143b9aSmrg
34773143b9aSmrgstatic int
34873143b9aSmrgTRANS(SocketINETGetPeerAddr) (XtransConnInfo ciptr)
34973143b9aSmrg
35073143b9aSmrg{
351ac57ed83Smrg#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
352ac57ed83Smrg    struct sockaddr_storage sockname;
353ac57ed83Smrg#else
354ac57ed83Smrg    struct sockaddr_in 	sockname;
35573143b9aSmrg#endif
356ac57ed83Smrg    void *socknamePtr = &sockname;
357ac57ed83Smrg    SOCKLEN_T namelen = sizeof(sockname);
35873143b9aSmrg
35973143b9aSmrg    bzero(socknamePtr, namelen);
360fe567363Smrg
361ac57ed83Smrg    prmsg (3,"SocketINETGetPeerAddr(%p)\n", (void *) ciptr);
36273143b9aSmrg
36373143b9aSmrg    if (getpeername (ciptr->fd, (struct sockaddr *) socknamePtr,
36473143b9aSmrg		     (void *)&namelen) < 0)
36573143b9aSmrg    {
36673143b9aSmrg#ifdef WIN32
36773143b9aSmrg	errno = WSAGetLastError();
36873143b9aSmrg#endif
369fe567363Smrg	prmsg (1,"SocketINETGetPeerAddr: getpeername() failed: %d\n",
370fe567363Smrg	    EGET());
37173143b9aSmrg	return -1;
37273143b9aSmrg    }
37373143b9aSmrg
37473143b9aSmrg    /*
37573143b9aSmrg     * Everything looks good: fill in the XtransConnInfo structure.
37673143b9aSmrg     */
37773143b9aSmrg
378fe567363Smrg    if ((ciptr->peeraddr = malloc (namelen)) == NULL)
37973143b9aSmrg    {
380fe567363Smrg        prmsg (1,
381fe567363Smrg	   "SocketINETGetPeerAddr: Can't allocate space for the addr\n");
38273143b9aSmrg        return -1;
38373143b9aSmrg    }
38473143b9aSmrg
38573143b9aSmrg    ciptr->peeraddrlen = namelen;
38673143b9aSmrg    memcpy (ciptr->peeraddr, socknamePtr, ciptr->peeraddrlen);
38773143b9aSmrg
38873143b9aSmrg    return 0;
38973143b9aSmrg}
39073143b9aSmrg
39173143b9aSmrg
39273143b9aSmrgstatic XtransConnInfo
39373143b9aSmrgTRANS(SocketOpen) (int i, int type)
39473143b9aSmrg
39573143b9aSmrg{
39673143b9aSmrg    XtransConnInfo	ciptr;
39773143b9aSmrg
398fe567363Smrg    prmsg (3,"SocketOpen(%d,%d)\n", i, type);
39973143b9aSmrg
400fe567363Smrg    if ((ciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
40173143b9aSmrg    {
402fe567363Smrg	prmsg (1, "SocketOpen: malloc failed\n");
40373143b9aSmrg	return NULL;
40473143b9aSmrg    }
40573143b9aSmrg
40694f982dbSmrg    ciptr->fd = socket(Sockettrans2devtab[i].family, type,
40794f982dbSmrg                       Sockettrans2devtab[i].protocol);
40894f982dbSmrg
40973143b9aSmrg#ifndef WIN32
41073143b9aSmrg#if (defined(X11_t) && !defined(USE_POLL)) || defined(FS_t) || defined(FONT_t)
41194f982dbSmrg    if (ciptr->fd >= sysconf(_SC_OPEN_MAX))
41294f982dbSmrg    {
41394f982dbSmrg	prmsg (2, "SocketOpen: socket() returned out of range fd %d\n",
41494f982dbSmrg	       ciptr->fd);
41594f982dbSmrg	close (ciptr->fd);
41694f982dbSmrg	ciptr->fd = -1;
41794f982dbSmrg    }
41873143b9aSmrg#endif
41973143b9aSmrg#endif
42094f982dbSmrg
42194f982dbSmrg    if (ciptr->fd < 0) {
42273143b9aSmrg#ifdef WIN32
42373143b9aSmrg	errno = WSAGetLastError();
42473143b9aSmrg#endif
425fe567363Smrg	prmsg (2, "SocketOpen: socket() failed for %s\n",
426fe567363Smrg	    Sockettrans2devtab[i].transname);
42773143b9aSmrg
428fe567363Smrg	free (ciptr);
42973143b9aSmrg	return NULL;
43073143b9aSmrg    }
43173143b9aSmrg
43273143b9aSmrg#ifdef TCP_NODELAY
43373143b9aSmrg    if (Sockettrans2devtab[i].family == AF_INET
434ac57ed83Smrg#ifdef IPv6
43573143b9aSmrg      || Sockettrans2devtab[i].family == AF_INET6
43673143b9aSmrg#endif
43773143b9aSmrg    )
43873143b9aSmrg    {
43973143b9aSmrg	/*
44073143b9aSmrg	 * turn off TCP coalescence for INET sockets
44173143b9aSmrg	 */
44273143b9aSmrg
44373143b9aSmrg	int tmp = 1;
44473143b9aSmrg	setsockopt (ciptr->fd, IPPROTO_TCP, TCP_NODELAY,
44573143b9aSmrg	    (char *) &tmp, sizeof (int));
44673143b9aSmrg    }
44773143b9aSmrg#endif
44873143b9aSmrg
4498a0d9095Smrg    /*
4508a0d9095Smrg     * Some systems provide a really small default buffer size for
4518a0d9095Smrg     * UNIX sockets.  Bump it up a bit such that large transfers don't
4528a0d9095Smrg     * proceed at glacial speed.
4538a0d9095Smrg     */
4548a0d9095Smrg#ifdef SO_SNDBUF
4558a0d9095Smrg    if (Sockettrans2devtab[i].family == AF_UNIX)
4568a0d9095Smrg    {
4578a0d9095Smrg	SOCKLEN_T len = sizeof (int);
4588a0d9095Smrg	int val;
4598a0d9095Smrg
4608a0d9095Smrg	if (getsockopt (ciptr->fd, SOL_SOCKET, SO_SNDBUF,
4618a0d9095Smrg	    (char *) &val, &len) == 0 && val < 64 * 1024)
4628a0d9095Smrg	{
4638a0d9095Smrg	    val = 64 * 1024;
4648a0d9095Smrg	    setsockopt (ciptr->fd, SOL_SOCKET, SO_SNDBUF,
4658a0d9095Smrg	        (char *) &val, sizeof (int));
4668a0d9095Smrg	}
4678a0d9095Smrg    }
4688a0d9095Smrg#endif
4698a0d9095Smrg
47073143b9aSmrg    return ciptr;
47173143b9aSmrg}
47273143b9aSmrg
47373143b9aSmrg
47473143b9aSmrg#ifdef TRANS_REOPEN
47573143b9aSmrg
47673143b9aSmrgstatic XtransConnInfo
4776a3641a6SsnjTRANS(SocketReopen) (int i _X_UNUSED, int type, int fd, const char *port)
47873143b9aSmrg
47973143b9aSmrg{
48073143b9aSmrg    XtransConnInfo	ciptr;
48173143b9aSmrg    int portlen;
48273143b9aSmrg    struct sockaddr *addr;
483fe567363Smrg    size_t addrlen;
48473143b9aSmrg
485fe567363Smrg    prmsg (3,"SocketReopen(%d,%d,%s)\n", type, fd, port);
48673143b9aSmrg
48773143b9aSmrg    if (port == NULL) {
488fe567363Smrg      prmsg (1, "SocketReopen: port was null!\n");
48973143b9aSmrg      return NULL;
49073143b9aSmrg    }
49173143b9aSmrg
49273143b9aSmrg    portlen = strlen(port) + 1; // include space for trailing null
49373143b9aSmrg#ifdef SOCK_MAXADDRLEN
49473143b9aSmrg    if (portlen < 0 || portlen > (SOCK_MAXADDRLEN + 2)) {
495fe567363Smrg      prmsg (1, "SocketReopen: invalid portlen %d\n", portlen);
49673143b9aSmrg      return NULL;
49773143b9aSmrg    }
49873143b9aSmrg    if (portlen < 14) portlen = 14;
49973143b9aSmrg#else
50073143b9aSmrg    if (portlen < 0 || portlen > 14) {
501fe567363Smrg      prmsg (1, "SocketReopen: invalid portlen %d\n", portlen);
50273143b9aSmrg      return NULL;
50373143b9aSmrg    }
50473143b9aSmrg#endif /*SOCK_MAXADDRLEN*/
50573143b9aSmrg
506fe567363Smrg    if ((ciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
50773143b9aSmrg    {
508fe567363Smrg	prmsg (1, "SocketReopen: malloc(ciptr) failed\n");
50973143b9aSmrg	return NULL;
51073143b9aSmrg    }
51173143b9aSmrg
51273143b9aSmrg    ciptr->fd = fd;
51373143b9aSmrg
514fe567363Smrg    addrlen = portlen + offsetof(struct sockaddr, sa_data);
515fe567363Smrg    if ((addr = calloc (1, addrlen)) == NULL) {
516fe567363Smrg	prmsg (1, "SocketReopen: malloc(addr) failed\n");
517fe567363Smrg	free (ciptr);
51873143b9aSmrg	return NULL;
51973143b9aSmrg    }
5208d4c0f7bSmrg    ciptr->addr = (char *) addr;
521fe567363Smrg    ciptr->addrlen = addrlen;
52273143b9aSmrg
523fe567363Smrg    if ((ciptr->peeraddr = calloc (1, addrlen)) == NULL) {
524fe567363Smrg	prmsg (1, "SocketReopen: malloc(portaddr) failed\n");
525fe567363Smrg	free (addr);
526fe567363Smrg	free (ciptr);
52773143b9aSmrg	return NULL;
52873143b9aSmrg    }
529fe567363Smrg    ciptr->peeraddrlen = addrlen;
53073143b9aSmrg
53173143b9aSmrg    /* Initialize ciptr structure as if it were a normally-opened unix socket */
53273143b9aSmrg    ciptr->flags = TRANS_LOCAL | TRANS_NOUNLINK;
53373143b9aSmrg#ifdef BSD44SOCKETS
534fe567363Smrg    addr->sa_len = addrlen;
53573143b9aSmrg#endif
53673143b9aSmrg    addr->sa_family = AF_UNIX;
5377448d6e9Smrg#if defined(HAVE_STRLCPY) || defined(HAS_STRLCPY)
53873143b9aSmrg    strlcpy(addr->sa_data, port, portlen);
53973143b9aSmrg#else
54073143b9aSmrg    strncpy(addr->sa_data, port, portlen);
54173143b9aSmrg#endif
54273143b9aSmrg    ciptr->family = AF_UNIX;
543fe567363Smrg    memcpy(ciptr->peeraddr, ciptr->addr, addrlen);
54473143b9aSmrg    ciptr->port = rindex(addr->sa_data, ':');
545e8a71cdfSmrg    if (ciptr->port == NULL) {
546e8a71cdfSmrg	if (is_numeric(addr->sa_data)) {
547e8a71cdfSmrg	    ciptr->port = addr->sa_data;
548e8a71cdfSmrg	}
549e8a71cdfSmrg    } else if (ciptr->port[0] == ':') {
550e8a71cdfSmrg	ciptr->port++;
551e8a71cdfSmrg    }
552e8a71cdfSmrg    /* port should now point to portnum or NULL */
55373143b9aSmrg    return ciptr;
55473143b9aSmrg}
55573143b9aSmrg
55673143b9aSmrg#endif /* TRANS_REOPEN */
55773143b9aSmrg
55873143b9aSmrg
55973143b9aSmrg/*
56073143b9aSmrg * These functions are the interface supplied in the Xtransport structure
56173143b9aSmrg */
56273143b9aSmrg
56373143b9aSmrg#ifdef TRANS_CLIENT
56473143b9aSmrg
56573143b9aSmrgstatic XtransConnInfo
566fe567363SmrgTRANS(SocketOpenCOTSClientBase) (const char *transname, const char *protocol,
567fe567363Smrg			   const char *host, const char *port, int previndex)
56873143b9aSmrg{
569ac57ed83Smrg    XtransConnInfo	ciptr = NULL;
57073143b9aSmrg    int			i = previndex;
57173143b9aSmrg
572fe567363Smrg    prmsg (2, "SocketOpenCOTSClient(%s,%s,%s)\n",
57373143b9aSmrg	protocol, host, port);
57473143b9aSmrg
57573143b9aSmrg    SocketInitOnce();
57673143b9aSmrg
57773143b9aSmrg    while ((i = TRANS(SocketSelectFamily) (i, transname)) >= 0) {
57873143b9aSmrg	if ((ciptr = TRANS(SocketOpen) (
579e8a71cdfSmrg		i, Sockettrans2devtab[i].devcotsname)) != NULL) {
580e8a71cdfSmrg	    /* Save the index for later use */
581e8a71cdfSmrg
582e8a71cdfSmrg	    ciptr->index = i;
58373143b9aSmrg	    break;
584e8a71cdfSmrg	}
58573143b9aSmrg    }
58673143b9aSmrg    if (i < 0) {
58773143b9aSmrg	if (i == -1)
588fe567363Smrg	    prmsg (1,"SocketOpenCOTSClient: Unable to open socket for %s\n",
589fe567363Smrg		   transname);
59073143b9aSmrg	else
591fe567363Smrg	    prmsg (1,"SocketOpenCOTSClient: Unable to determine socket type for %s\n",
592fe567363Smrg		   transname);
59373143b9aSmrg	return NULL;
59473143b9aSmrg    }
59573143b9aSmrg
59673143b9aSmrg    return ciptr;
59773143b9aSmrg}
59873143b9aSmrg
59973143b9aSmrgstatic XtransConnInfo
6006a3641a6SsnjTRANS(SocketOpenCOTSClient) (Xtransport *thistrans, const char *protocol,
6016a3641a6Ssnj			     const char *host, const char *port)
60273143b9aSmrg{
60373143b9aSmrg    return TRANS(SocketOpenCOTSClientBase)(
60473143b9aSmrg			thistrans->TransName, protocol, host, port, -1);
60573143b9aSmrg}
60673143b9aSmrg
60773143b9aSmrg
60873143b9aSmrg#endif /* TRANS_CLIENT */
60973143b9aSmrg
61073143b9aSmrg
61173143b9aSmrg#ifdef TRANS_SERVER
61273143b9aSmrg
61373143b9aSmrgstatic XtransConnInfo
6146a3641a6SsnjTRANS(SocketOpenCOTSServer) (Xtransport *thistrans, const char *protocol,
6156a3641a6Ssnj			     const char *host, const char *port)
61673143b9aSmrg
61773143b9aSmrg{
618ac57ed83Smrg    XtransConnInfo	ciptr = NULL;
61973143b9aSmrg    int	i = -1;
62073143b9aSmrg
621fe567363Smrg    prmsg (2,"SocketOpenCOTSServer(%s,%s,%s)\n", protocol, host, port);
62273143b9aSmrg
62373143b9aSmrg    SocketInitOnce();
62473143b9aSmrg
62573143b9aSmrg    while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
62673143b9aSmrg	if ((ciptr = TRANS(SocketOpen) (
62773143b9aSmrg		 i, Sockettrans2devtab[i].devcotsname)) != NULL)
62873143b9aSmrg	    break;
62973143b9aSmrg    }
63073143b9aSmrg    if (i < 0) {
631a773ec55Smrg	if (i == -1) {
632a773ec55Smrg		if (errno == EAFNOSUPPORT) {
633a773ec55Smrg			thistrans->flags |= TRANS_NOLISTEN;
634a773ec55Smrg			prmsg (1,"SocketOpenCOTSServer: Socket for %s unsupported on this system.\n",
635a773ec55Smrg			       thistrans->TransName);
636a773ec55Smrg		} else {
637a773ec55Smrg			prmsg (1,"SocketOpenCOTSServer: Unable to open socket for %s\n",
638a773ec55Smrg			       thistrans->TransName);
639a773ec55Smrg		}
640a773ec55Smrg	} else {
641fe567363Smrg	    prmsg (1,"SocketOpenCOTSServer: Unable to determine socket type for %s\n",
642fe567363Smrg		   thistrans->TransName);
643a773ec55Smrg	}
64473143b9aSmrg	return NULL;
64573143b9aSmrg    }
64673143b9aSmrg
64773143b9aSmrg    /*
64873143b9aSmrg     * Using this prevents the bind() check for an existing server listening
64973143b9aSmrg     * on the same port, but it is required for other reasons.
65073143b9aSmrg     */
65173143b9aSmrg#ifdef SO_REUSEADDR
65273143b9aSmrg
65373143b9aSmrg    /*
65473143b9aSmrg     * SO_REUSEADDR only applied to AF_INET && AF_INET6
65573143b9aSmrg     */
65673143b9aSmrg
65773143b9aSmrg    if (Sockettrans2devtab[i].family == AF_INET
658ac57ed83Smrg#ifdef IPv6
65973143b9aSmrg      || Sockettrans2devtab[i].family == AF_INET6
66073143b9aSmrg#endif
66173143b9aSmrg    )
66273143b9aSmrg    {
66373143b9aSmrg	int one = 1;
66473143b9aSmrg	setsockopt (ciptr->fd, SOL_SOCKET, SO_REUSEADDR,
66573143b9aSmrg		    (char *) &one, sizeof (int));
66673143b9aSmrg    }
66773143b9aSmrg#endif
66873143b9aSmrg#ifdef IPV6_V6ONLY
66973143b9aSmrg    if (Sockettrans2devtab[i].family == AF_INET6)
67073143b9aSmrg    {
67173143b9aSmrg	int one = 1;
67273143b9aSmrg	setsockopt(ciptr->fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(int));
67373143b9aSmrg    }
67473143b9aSmrg#endif
67573143b9aSmrg    /* Save the index for later use */
67673143b9aSmrg
67773143b9aSmrg    ciptr->index = i;
67873143b9aSmrg
67973143b9aSmrg    return ciptr;
68073143b9aSmrg}
68173143b9aSmrg
68273143b9aSmrg#endif /* TRANS_SERVER */
68373143b9aSmrg
68473143b9aSmrg
68573143b9aSmrg#ifdef TRANS_REOPEN
68673143b9aSmrg
68773143b9aSmrgstatic XtransConnInfo
6886a3641a6SsnjTRANS(SocketReopenCOTSServer) (Xtransport *thistrans, int fd, const char *port)
68973143b9aSmrg
69073143b9aSmrg{
69173143b9aSmrg    XtransConnInfo	ciptr;
69273143b9aSmrg    int			i = -1;
69373143b9aSmrg
694fe567363Smrg    prmsg (2,
695fe567363Smrg	"SocketReopenCOTSServer(%d, %s)\n", fd, port);
69673143b9aSmrg
69773143b9aSmrg    SocketInitOnce();
69873143b9aSmrg
69973143b9aSmrg    while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
70073143b9aSmrg	if ((ciptr = TRANS(SocketReopen) (
70173143b9aSmrg		 i, Sockettrans2devtab[i].devcotsname, fd, port)) != NULL)
70273143b9aSmrg	    break;
70373143b9aSmrg    }
70473143b9aSmrg    if (i < 0) {
70573143b9aSmrg	if (i == -1)
706fe567363Smrg	    prmsg (1,"SocketReopenCOTSServer: Unable to open socket for %s\n",
707fe567363Smrg		   thistrans->TransName);
70873143b9aSmrg	else
709fe567363Smrg	    prmsg (1,"SocketReopenCOTSServer: Unable to determine socket type for %s\n",
710fe567363Smrg		   thistrans->TransName);
71173143b9aSmrg	return NULL;
71273143b9aSmrg    }
71373143b9aSmrg
71473143b9aSmrg    /* Save the index for later use */
71573143b9aSmrg
71673143b9aSmrg    ciptr->index = i;
71773143b9aSmrg
71873143b9aSmrg    return ciptr;
71973143b9aSmrg}
72073143b9aSmrg
72173143b9aSmrg#endif /* TRANS_REOPEN */
72273143b9aSmrg
72373143b9aSmrg
72473143b9aSmrgstatic int
72573143b9aSmrgTRANS(SocketSetOption) (XtransConnInfo ciptr, int option, int arg)
72673143b9aSmrg
72773143b9aSmrg{
728fe567363Smrg    prmsg (2,"SocketSetOption(%d,%d,%d)\n", ciptr->fd, option, arg);
72973143b9aSmrg
73073143b9aSmrg    return -1;
73173143b9aSmrg}
73273143b9aSmrg
73373143b9aSmrg#ifdef UNIXCONN
73473143b9aSmrgstatic int
73573143b9aSmrgset_sun_path(const char *port, const char *upath, char *path, int abstract)
73673143b9aSmrg{
73773143b9aSmrg    struct sockaddr_un s;
73894f982dbSmrg    ssize_t maxlen = sizeof(s.sun_path) - 1;
73973143b9aSmrg    const char *at = "";
74073143b9aSmrg
74173143b9aSmrg    if (!port || !*port || !path)
74273143b9aSmrg	return -1;
74373143b9aSmrg
74473143b9aSmrg#ifdef HAVE_ABSTRACT_SOCKETS
74573143b9aSmrg    if (port[0] == '@')
74673143b9aSmrg	upath = "";
74773143b9aSmrg    else if (abstract)
74873143b9aSmrg	at = "@";
74973143b9aSmrg#endif
75073143b9aSmrg
75173143b9aSmrg    if (*port == '/') /* a full pathname */
75273143b9aSmrg	upath = "";
75373143b9aSmrg
75494f982dbSmrg    if ((ssize_t)(strlen(at) + strlen(upath) + strlen(port)) > maxlen)
75573143b9aSmrg	return -1;
756fe567363Smrg    snprintf(path, sizeof(s.sun_path), "%s%s%s", at, upath, port);
75773143b9aSmrg    return 0;
75873143b9aSmrg}
75973143b9aSmrg#endif
76073143b9aSmrg
76173143b9aSmrg#ifdef TRANS_SERVER
76273143b9aSmrg
76373143b9aSmrgstatic int
764fe567363SmrgTRANS(SocketCreateListener) (XtransConnInfo ciptr,
76573143b9aSmrg			     struct sockaddr *sockname,
76673143b9aSmrg			     int socknamelen, unsigned int flags)
76773143b9aSmrg
76873143b9aSmrg{
76973143b9aSmrg    SOCKLEN_T namelen = socknamelen;
77073143b9aSmrg    int	fd = ciptr->fd;
77173143b9aSmrg    int	retry;
77273143b9aSmrg
773ac57ed83Smrg    prmsg (3, "SocketCreateListener(%p,%d)\n", (void *) ciptr, fd);
77473143b9aSmrg
77573143b9aSmrg    if (Sockettrans2devtab[ciptr->index].family == AF_INET
776ac57ed83Smrg#ifdef IPv6
77773143b9aSmrg      || Sockettrans2devtab[ciptr->index].family == AF_INET6
77873143b9aSmrg#endif
77973143b9aSmrg	)
78073143b9aSmrg	retry = 20;
78173143b9aSmrg    else
78273143b9aSmrg	retry = 0;
78373143b9aSmrg
78494f982dbSmrg    while (bind (fd, sockname, namelen) < 0)
78573143b9aSmrg    {
78673143b9aSmrg	if (errno == EADDRINUSE) {
78773143b9aSmrg	    if (flags & ADDR_IN_USE_ALLOWED)
78873143b9aSmrg		break;
78973143b9aSmrg	    else
79073143b9aSmrg		return TRANS_ADDR_IN_USE;
79173143b9aSmrg	}
792fe567363Smrg
79373143b9aSmrg	if (retry-- == 0) {
794fe567363Smrg	    prmsg (1, "SocketCreateListener: failed to bind listener\n");
79573143b9aSmrg	    close (fd);
79673143b9aSmrg	    return TRANS_CREATE_LISTENER_FAILED;
79773143b9aSmrg	}
79873143b9aSmrg#ifdef SO_REUSEADDR
79973143b9aSmrg	sleep (1);
80073143b9aSmrg#else
80173143b9aSmrg	sleep (10);
80273143b9aSmrg#endif /* SO_REUSEDADDR */
80373143b9aSmrg    }
80473143b9aSmrg
80573143b9aSmrg    if (Sockettrans2devtab[ciptr->index].family == AF_INET
806ac57ed83Smrg#ifdef IPv6
80773143b9aSmrg      || Sockettrans2devtab[ciptr->index].family == AF_INET6
80873143b9aSmrg#endif
80973143b9aSmrg	) {
81073143b9aSmrg#ifdef SO_DONTLINGER
81173143b9aSmrg	setsockopt (fd, SOL_SOCKET, SO_DONTLINGER, (char *) NULL, 0);
81273143b9aSmrg#else
81373143b9aSmrg#ifdef SO_LINGER
81473143b9aSmrg    {
81573143b9aSmrg	static int linger[2] = { 0, 0 };
81673143b9aSmrg	setsockopt (fd, SOL_SOCKET, SO_LINGER,
81773143b9aSmrg		(char *) linger, sizeof (linger));
81873143b9aSmrg    }
81973143b9aSmrg#endif
82073143b9aSmrg#endif
82173143b9aSmrg}
82273143b9aSmrg
82373143b9aSmrg    if (listen (fd, BACKLOG) < 0)
82473143b9aSmrg    {
825fe567363Smrg	prmsg (1, "SocketCreateListener: listen() failed\n");
82673143b9aSmrg	close (fd);
82773143b9aSmrg	return TRANS_CREATE_LISTENER_FAILED;
82873143b9aSmrg    }
829fe567363Smrg
83073143b9aSmrg    /* Set a flag to indicate that this connection is a listener */
83173143b9aSmrg
83273143b9aSmrg    ciptr->flags = 1 | (ciptr->flags & TRANS_KEEPFLAGS);
83373143b9aSmrg
83473143b9aSmrg    return 0;
83573143b9aSmrg}
83673143b9aSmrg
83773143b9aSmrg#ifdef TCPCONN
83873143b9aSmrgstatic int
8396a3641a6SsnjTRANS(SocketINETCreateListener) (XtransConnInfo ciptr, const char *port,
8406a3641a6Ssnj                                 unsigned int flags)
84173143b9aSmrg
84273143b9aSmrg{
843ac57ed83Smrg#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
84473143b9aSmrg    struct sockaddr_storage sockname;
84573143b9aSmrg#else
84673143b9aSmrg    struct sockaddr_in	    sockname;
84773143b9aSmrg#endif
84873143b9aSmrg    unsigned short	    sport;
84973143b9aSmrg    SOCKLEN_T	namelen = sizeof(sockname);
85073143b9aSmrg    int		status;
85173143b9aSmrg    long	tmpport;
85273143b9aSmrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
85373143b9aSmrg    _Xgetservbynameparams sparams;
85473143b9aSmrg#endif
85573143b9aSmrg    struct servent *servp;
85673143b9aSmrg
85773143b9aSmrg#ifdef X11_t
85873143b9aSmrg    char	portbuf[PORTBUFSIZE];
85973143b9aSmrg#endif
860fe567363Smrg
861fe567363Smrg    prmsg (2, "SocketINETCreateListener(%s)\n", port);
86273143b9aSmrg
86373143b9aSmrg#ifdef X11_t
86473143b9aSmrg    /*
86573143b9aSmrg     * X has a well known port, that is transport dependent. It is easier
86673143b9aSmrg     * to handle it here, than try and come up with a transport independent
86773143b9aSmrg     * representation that can be passed in and resolved the usual way.
86873143b9aSmrg     *
86973143b9aSmrg     * The port that is passed here is really a string containing the idisplay
87073143b9aSmrg     * from ConnectDisplay().
87173143b9aSmrg     */
87273143b9aSmrg
87373143b9aSmrg    if (is_numeric (port))
87473143b9aSmrg    {
87573143b9aSmrg	/* fixup the server port address */
87673143b9aSmrg	tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10);
877fe567363Smrg	snprintf (portbuf, sizeof(portbuf), "%lu", tmpport);
87873143b9aSmrg	port = portbuf;
87973143b9aSmrg    }
88073143b9aSmrg#endif
88173143b9aSmrg
88273143b9aSmrg    if (port && *port)
88373143b9aSmrg    {
88473143b9aSmrg	/* Check to see if the port string is just a number (handles X11) */
88573143b9aSmrg
88673143b9aSmrg	if (!is_numeric (port))
88773143b9aSmrg	{
88873143b9aSmrg	    if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL)
88973143b9aSmrg	    {
890fe567363Smrg		prmsg (1,
89173143b9aSmrg	     "SocketINETCreateListener: Unable to get service for %s\n",
892fe567363Smrg		      port);
89373143b9aSmrg		return TRANS_CREATE_LISTENER_FAILED;
89473143b9aSmrg	    }
89573143b9aSmrg	    /* we trust getservbyname to return a valid number */
89673143b9aSmrg	    sport = servp->s_port;
89773143b9aSmrg	}
89873143b9aSmrg	else
89973143b9aSmrg	{
90073143b9aSmrg	    tmpport = strtol (port, (char**)NULL, 10);
901fe567363Smrg	    /*
90273143b9aSmrg	     * check that somehow the port address isn't negative or in
90373143b9aSmrg	     * the range of reserved port addresses. This can happen and
904fe567363Smrg	     * be very bad if the server is suid-root and the user does
905fe567363Smrg	     * something (dumb) like `X :60049`.
90673143b9aSmrg	     */
90773143b9aSmrg	    if (tmpport < 1024 || tmpport > USHRT_MAX)
90873143b9aSmrg		return TRANS_CREATE_LISTENER_FAILED;
90973143b9aSmrg
91073143b9aSmrg	    sport = (unsigned short) tmpport;
91173143b9aSmrg	}
91273143b9aSmrg    }
91373143b9aSmrg    else
91473143b9aSmrg	sport = 0;
91573143b9aSmrg
91673143b9aSmrg    bzero(&sockname, sizeof(sockname));
91773143b9aSmrg    if (Sockettrans2devtab[ciptr->index].family == AF_INET) {
91873143b9aSmrg	namelen = sizeof (struct sockaddr_in);
91973143b9aSmrg#ifdef BSD44SOCKETS
92073143b9aSmrg	((struct sockaddr_in *)&sockname)->sin_len = namelen;
92173143b9aSmrg#endif
92273143b9aSmrg	((struct sockaddr_in *)&sockname)->sin_family = AF_INET;
92373143b9aSmrg	((struct sockaddr_in *)&sockname)->sin_port = htons(sport);
92473143b9aSmrg	((struct sockaddr_in *)&sockname)->sin_addr.s_addr = htonl(INADDR_ANY);
92573143b9aSmrg    } else {
926ac57ed83Smrg#ifdef IPv6
92773143b9aSmrg	namelen = sizeof (struct sockaddr_in6);
92873143b9aSmrg#ifdef SIN6_LEN
92973143b9aSmrg	((struct sockaddr_in6 *)&sockname)->sin6_len = sizeof(sockname);
93073143b9aSmrg#endif
93173143b9aSmrg	((struct sockaddr_in6 *)&sockname)->sin6_family = AF_INET6;
93273143b9aSmrg	((struct sockaddr_in6 *)&sockname)->sin6_port = htons(sport);
93373143b9aSmrg	((struct sockaddr_in6 *)&sockname)->sin6_addr = in6addr_any;
93473143b9aSmrg#else
935ac57ed83Smrg        prmsg (1,
936ac57ed83Smrg               "SocketINETCreateListener: unsupported address family %d\n",
937ac57ed83Smrg               Sockettrans2devtab[ciptr->index].family);
938ac57ed83Smrg        return TRANS_CREATE_LISTENER_FAILED;
93973143b9aSmrg#endif
940ac57ed83Smrg    }
94173143b9aSmrg
94273143b9aSmrg    if ((status = TRANS(SocketCreateListener) (ciptr,
94373143b9aSmrg	(struct sockaddr *) &sockname, namelen, flags)) < 0)
94473143b9aSmrg    {
945fe567363Smrg	prmsg (1,
946fe567363Smrg    "SocketINETCreateListener: ...SocketCreateListener() failed\n");
94773143b9aSmrg	return status;
94873143b9aSmrg    }
94973143b9aSmrg
95073143b9aSmrg    if (TRANS(SocketINETGetAddr) (ciptr) < 0)
95173143b9aSmrg    {
952fe567363Smrg	prmsg (1,
953fe567363Smrg       "SocketINETCreateListener: ...SocketINETGetAddr() failed\n");
95473143b9aSmrg	return TRANS_CREATE_LISTENER_FAILED;
95573143b9aSmrg    }
95673143b9aSmrg
95773143b9aSmrg    return 0;
95873143b9aSmrg}
95973143b9aSmrg
96073143b9aSmrg#endif /* TCPCONN */
96173143b9aSmrg
96273143b9aSmrg
96373143b9aSmrg#ifdef UNIXCONN
96473143b9aSmrg
96573143b9aSmrgstatic int
9666a3641a6SsnjTRANS(SocketUNIXCreateListener) (XtransConnInfo ciptr, const char *port,
96773143b9aSmrg				 unsigned int flags)
96873143b9aSmrg
96973143b9aSmrg{
97073143b9aSmrg    struct sockaddr_un	sockname;
97173143b9aSmrg    int			namelen;
97273143b9aSmrg    int			oldUmask;
97373143b9aSmrg    int			status;
97473143b9aSmrg    unsigned int	mode;
97573143b9aSmrg    char		tmpport[108];
97673143b9aSmrg
97773143b9aSmrg    int			abstract = 0;
97873143b9aSmrg#ifdef HAVE_ABSTRACT_SOCKETS
97973143b9aSmrg    abstract = ciptr->transptr->flags & TRANS_ABSTRACT;
98073143b9aSmrg#endif
98173143b9aSmrg
982fe567363Smrg    prmsg (2, "SocketUNIXCreateListener(%s)\n",
983fe567363Smrg	port ? port : "NULL");
98473143b9aSmrg
98573143b9aSmrg    /* Make sure the directory is created */
98673143b9aSmrg
98773143b9aSmrg    oldUmask = umask (0);
98873143b9aSmrg
98973143b9aSmrg#ifdef UNIX_DIR
99073143b9aSmrg#ifdef HAS_STICKY_DIR_BIT
99173143b9aSmrg    mode = 01777;
99273143b9aSmrg#else
99373143b9aSmrg    mode = 0777;
99473143b9aSmrg#endif
9958d4c0f7bSmrg    if (!abstract && trans_mkdir(UNIX_DIR, mode) == -1) {
996fe567363Smrg	prmsg (1, "SocketUNIXCreateListener: mkdir(%s) failed, errno = %d\n",
997fe567363Smrg	       UNIX_DIR, errno);
99873143b9aSmrg	(void) umask (oldUmask);
99973143b9aSmrg	return TRANS_CREATE_LISTENER_FAILED;
100073143b9aSmrg    }
100173143b9aSmrg#endif
100273143b9aSmrg
100373143b9aSmrg    memset(&sockname, 0, sizeof(sockname));
100473143b9aSmrg    sockname.sun_family = AF_UNIX;
100573143b9aSmrg
100673143b9aSmrg    if (!(port && *port)) {
100773143b9aSmrg	snprintf (tmpport, sizeof(tmpport), "%s%ld", UNIX_PATH, (long)getpid());
100873143b9aSmrg	port = tmpport;
100973143b9aSmrg    }
101073143b9aSmrg    if (set_sun_path(port, UNIX_PATH, sockname.sun_path, abstract) != 0) {
1011fe567363Smrg	prmsg (1, "SocketUNIXCreateListener: path too long\n");
101273143b9aSmrg	return TRANS_CREATE_LISTENER_FAILED;
101373143b9aSmrg    }
101473143b9aSmrg
1015a773ec55Smrg#if defined(BSD44SOCKETS)
101673143b9aSmrg    sockname.sun_len = strlen(sockname.sun_path);
101773143b9aSmrg#endif
101873143b9aSmrg
101973143b9aSmrg#if defined(BSD44SOCKETS) || defined(SUN_LEN)
102073143b9aSmrg    namelen = SUN_LEN(&sockname);
102173143b9aSmrg#else
102273143b9aSmrg    namelen = strlen(sockname.sun_path) + offsetof(struct sockaddr_un, sun_path);
102373143b9aSmrg#endif
102473143b9aSmrg
102573143b9aSmrg    if (abstract) {
102673143b9aSmrg	sockname.sun_path[0] = '\0';
102773143b9aSmrg	namelen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&sockname.sun_path[1]);
102873143b9aSmrg    }
102973143b9aSmrg    else
103073143b9aSmrg	unlink (sockname.sun_path);
103173143b9aSmrg
103273143b9aSmrg    if ((status = TRANS(SocketCreateListener) (ciptr,
103373143b9aSmrg	(struct sockaddr *) &sockname, namelen, flags)) < 0)
103473143b9aSmrg    {
1035fe567363Smrg	prmsg (1,
1036fe567363Smrg    "SocketUNIXCreateListener: ...SocketCreateListener() failed\n");
103773143b9aSmrg	(void) umask (oldUmask);
103873143b9aSmrg	return status;
103973143b9aSmrg    }
104073143b9aSmrg
104173143b9aSmrg    /*
104273143b9aSmrg     * Now that the listener is esablished, create the addr info for
104373143b9aSmrg     * this connection. getpeername() doesn't work for UNIX Domain Sockets
104473143b9aSmrg     * on some systems (hpux at least), so we will just do it manually, instead
104573143b9aSmrg     * of calling something like TRANS(SocketUNIXGetAddr).
104673143b9aSmrg     */
104773143b9aSmrg
104873143b9aSmrg    namelen = sizeof (sockname); /* this will always make it the same size */
104973143b9aSmrg
1050fe567363Smrg    if ((ciptr->addr = malloc (namelen)) == NULL)
105173143b9aSmrg    {
1052fe567363Smrg        prmsg (1,
1053fe567363Smrg        "SocketUNIXCreateListener: Can't allocate space for the addr\n");
105473143b9aSmrg	(void) umask (oldUmask);
105573143b9aSmrg        return TRANS_CREATE_LISTENER_FAILED;
105673143b9aSmrg    }
105773143b9aSmrg
105873143b9aSmrg    if (abstract)
105973143b9aSmrg	sockname.sun_path[0] = '@';
106073143b9aSmrg
106173143b9aSmrg    ciptr->family = sockname.sun_family;
106273143b9aSmrg    ciptr->addrlen = namelen;
106373143b9aSmrg    memcpy (ciptr->addr, &sockname, ciptr->addrlen);
106473143b9aSmrg
106573143b9aSmrg    (void) umask (oldUmask);
106673143b9aSmrg
106773143b9aSmrg    return 0;
106873143b9aSmrg}
106973143b9aSmrg
107073143b9aSmrg
107173143b9aSmrgstatic int
107273143b9aSmrgTRANS(SocketUNIXResetListener) (XtransConnInfo ciptr)
107373143b9aSmrg
107473143b9aSmrg{
107573143b9aSmrg    /*
107673143b9aSmrg     * See if the unix domain socket has disappeared.  If it has, recreate it.
107773143b9aSmrg     */
107873143b9aSmrg
107973143b9aSmrg    struct sockaddr_un 	*unsock = (struct sockaddr_un *) ciptr->addr;
108073143b9aSmrg    struct stat		statb;
108173143b9aSmrg    int 		status = TRANS_RESET_NOOP;
108273143b9aSmrg    unsigned int	mode;
108373143b9aSmrg    int abstract = 0;
108473143b9aSmrg#ifdef HAVE_ABSTRACT_SOCKETS
108573143b9aSmrg    abstract = ciptr->transptr->flags & TRANS_ABSTRACT;
108673143b9aSmrg#endif
108773143b9aSmrg
1088ac57ed83Smrg    prmsg (3, "SocketUNIXResetListener(%p,%d)\n", (void *) ciptr, ciptr->fd);
108973143b9aSmrg
109073143b9aSmrg    if (!abstract && (
109173143b9aSmrg	stat (unsock->sun_path, &statb) == -1 ||
109273143b9aSmrg        ((statb.st_mode & S_IFMT) !=
1093a773ec55Smrg#if !defined(S_IFSOCK)
109473143b9aSmrg	  		S_IFIFO
109573143b9aSmrg#else
109673143b9aSmrg			S_IFSOCK
109773143b9aSmrg#endif
109873143b9aSmrg				)))
109973143b9aSmrg    {
110073143b9aSmrg	int oldUmask = umask (0);
110173143b9aSmrg
110273143b9aSmrg#ifdef UNIX_DIR
110373143b9aSmrg#ifdef HAS_STICKY_DIR_BIT
110473143b9aSmrg	mode = 01777;
110573143b9aSmrg#else
110673143b9aSmrg	mode = 0777;
110773143b9aSmrg#endif
110873143b9aSmrg        if (trans_mkdir(UNIX_DIR, mode) == -1) {
1109fe567363Smrg            prmsg (1, "SocketUNIXResetListener: mkdir(%s) failed, errno = %d\n",
1110fe567363Smrg	    UNIX_DIR, errno);
111173143b9aSmrg	    (void) umask (oldUmask);
111273143b9aSmrg	    return TRANS_RESET_FAILURE;
111373143b9aSmrg        }
111473143b9aSmrg#endif
111573143b9aSmrg
111673143b9aSmrg	close (ciptr->fd);
111773143b9aSmrg	unlink (unsock->sun_path);
111873143b9aSmrg
111973143b9aSmrg	if ((ciptr->fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
112073143b9aSmrg	{
112173143b9aSmrg	    TRANS(FreeConnInfo) (ciptr);
112273143b9aSmrg	    (void) umask (oldUmask);
112373143b9aSmrg	    return TRANS_RESET_FAILURE;
112473143b9aSmrg	}
112573143b9aSmrg
112673143b9aSmrg	if (bind (ciptr->fd, (struct sockaddr *) unsock, ciptr->addrlen) < 0)
112773143b9aSmrg	{
112873143b9aSmrg	    close (ciptr->fd);
112973143b9aSmrg	    TRANS(FreeConnInfo) (ciptr);
113073143b9aSmrg	    return TRANS_RESET_FAILURE;
113173143b9aSmrg	}
113273143b9aSmrg
113373143b9aSmrg	if (listen (ciptr->fd, BACKLOG) < 0)
113473143b9aSmrg	{
113573143b9aSmrg	    close (ciptr->fd);
113673143b9aSmrg	    TRANS(FreeConnInfo) (ciptr);
113773143b9aSmrg	    (void) umask (oldUmask);
113873143b9aSmrg	    return TRANS_RESET_FAILURE;
113973143b9aSmrg	}
114073143b9aSmrg
114173143b9aSmrg	umask (oldUmask);
114273143b9aSmrg
114373143b9aSmrg	status = TRANS_RESET_NEW_FD;
114473143b9aSmrg    }
114573143b9aSmrg
114673143b9aSmrg    return status;
114773143b9aSmrg}
114873143b9aSmrg
114973143b9aSmrg#endif /* UNIXCONN */
115073143b9aSmrg
115173143b9aSmrg
115273143b9aSmrg#ifdef TCPCONN
115373143b9aSmrg
115473143b9aSmrgstatic XtransConnInfo
115573143b9aSmrgTRANS(SocketINETAccept) (XtransConnInfo ciptr, int *status)
115673143b9aSmrg
115773143b9aSmrg{
115873143b9aSmrg    XtransConnInfo	newciptr;
115973143b9aSmrg    struct sockaddr_in	sockname;
116073143b9aSmrg    SOCKLEN_T		namelen = sizeof(sockname);
116173143b9aSmrg
1162ac57ed83Smrg    prmsg (2, "SocketINETAccept(%p,%d)\n", (void *) ciptr, ciptr->fd);
116373143b9aSmrg
1164fe567363Smrg    if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
116573143b9aSmrg    {
1166fe567363Smrg	prmsg (1, "SocketINETAccept: malloc failed\n");
116773143b9aSmrg	*status = TRANS_ACCEPT_BAD_MALLOC;
116873143b9aSmrg	return NULL;
116973143b9aSmrg    }
117073143b9aSmrg
117173143b9aSmrg    if ((newciptr->fd = accept (ciptr->fd,
117273143b9aSmrg	(struct sockaddr *) &sockname, (void *)&namelen)) < 0)
117373143b9aSmrg    {
117473143b9aSmrg#ifdef WIN32
117573143b9aSmrg	errno = WSAGetLastError();
117673143b9aSmrg#endif
1177fe567363Smrg	prmsg (1, "SocketINETAccept: accept() failed\n");
1178fe567363Smrg	free (newciptr);
117973143b9aSmrg	*status = TRANS_ACCEPT_FAILED;
118073143b9aSmrg	return NULL;
118173143b9aSmrg    }
118273143b9aSmrg
118373143b9aSmrg#ifdef TCP_NODELAY
118473143b9aSmrg    {
118573143b9aSmrg	/*
118673143b9aSmrg	 * turn off TCP coalescence for INET sockets
118773143b9aSmrg	 */
118873143b9aSmrg
118973143b9aSmrg	int tmp = 1;
119073143b9aSmrg	setsockopt (newciptr->fd, IPPROTO_TCP, TCP_NODELAY,
119173143b9aSmrg	    (char *) &tmp, sizeof (int));
119273143b9aSmrg    }
119373143b9aSmrg#endif
119473143b9aSmrg
119573143b9aSmrg    /*
1196fe567363Smrg     * Get this address again because the transport may give a more
119773143b9aSmrg     * specific address now that a connection is established.
119873143b9aSmrg     */
119973143b9aSmrg
120073143b9aSmrg    if (TRANS(SocketINETGetAddr) (newciptr) < 0)
120173143b9aSmrg    {
1202fe567363Smrg	prmsg (1,
1203fe567363Smrg	    "SocketINETAccept: ...SocketINETGetAddr() failed:\n");
120473143b9aSmrg	close (newciptr->fd);
1205fe567363Smrg	free (newciptr);
120673143b9aSmrg	*status = TRANS_ACCEPT_MISC_ERROR;
120773143b9aSmrg        return NULL;
120873143b9aSmrg    }
120973143b9aSmrg
121073143b9aSmrg    if (TRANS(SocketINETGetPeerAddr) (newciptr) < 0)
121173143b9aSmrg    {
1212fe567363Smrg	prmsg (1,
1213fe567363Smrg	  "SocketINETAccept: ...SocketINETGetPeerAddr() failed:\n");
121473143b9aSmrg	close (newciptr->fd);
1215fe567363Smrg	if (newciptr->addr) free (newciptr->addr);
1216fe567363Smrg	free (newciptr);
121773143b9aSmrg	*status = TRANS_ACCEPT_MISC_ERROR;
121873143b9aSmrg        return NULL;
121973143b9aSmrg    }
122073143b9aSmrg
122173143b9aSmrg    *status = 0;
122273143b9aSmrg
122373143b9aSmrg    return newciptr;
122473143b9aSmrg}
122573143b9aSmrg
122673143b9aSmrg#endif /* TCPCONN */
122773143b9aSmrg
122873143b9aSmrg
122973143b9aSmrg#ifdef UNIXCONN
123073143b9aSmrgstatic XtransConnInfo
123173143b9aSmrgTRANS(SocketUNIXAccept) (XtransConnInfo ciptr, int *status)
123273143b9aSmrg
123373143b9aSmrg{
123473143b9aSmrg    XtransConnInfo	newciptr;
123573143b9aSmrg    struct sockaddr_un	sockname;
123673143b9aSmrg    SOCKLEN_T 		namelen = sizeof sockname;
123773143b9aSmrg
1238ac57ed83Smrg    prmsg (2, "SocketUNIXAccept(%p,%d)\n", (void *) ciptr, ciptr->fd);
123973143b9aSmrg
1240fe567363Smrg    if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
124173143b9aSmrg    {
1242fe567363Smrg	prmsg (1, "SocketUNIXAccept: malloc() failed\n");
124373143b9aSmrg	*status = TRANS_ACCEPT_BAD_MALLOC;
124473143b9aSmrg	return NULL;
124573143b9aSmrg    }
124673143b9aSmrg
124773143b9aSmrg    if ((newciptr->fd = accept (ciptr->fd,
124873143b9aSmrg	(struct sockaddr *) &sockname, (void *)&namelen)) < 0)
124973143b9aSmrg    {
1250fe567363Smrg	prmsg (1, "SocketUNIXAccept: accept() failed\n");
1251fe567363Smrg	free (newciptr);
125273143b9aSmrg	*status = TRANS_ACCEPT_FAILED;
125373143b9aSmrg	return NULL;
125473143b9aSmrg    }
125573143b9aSmrg
125673143b9aSmrg	ciptr->addrlen = namelen;
125773143b9aSmrg    /*
125873143b9aSmrg     * Get the socket name and the peer name from the listener socket,
125973143b9aSmrg     * since this is unix domain.
126073143b9aSmrg     */
126173143b9aSmrg
1262fe567363Smrg    if ((newciptr->addr = malloc (ciptr->addrlen)) == NULL)
126373143b9aSmrg    {
1264fe567363Smrg        prmsg (1,
1265fe567363Smrg        "SocketUNIXAccept: Can't allocate space for the addr\n");
126673143b9aSmrg	close (newciptr->fd);
1267fe567363Smrg	free (newciptr);
126873143b9aSmrg	*status = TRANS_ACCEPT_BAD_MALLOC;
126973143b9aSmrg        return NULL;
127073143b9aSmrg    }
127173143b9aSmrg
127273143b9aSmrg    /*
127373143b9aSmrg     * if the socket is abstract, we already modified the address to have a
127473143b9aSmrg     * @ instead of the initial NUL, so no need to do that again here.
127573143b9aSmrg     */
127673143b9aSmrg
127773143b9aSmrg    newciptr->addrlen = ciptr->addrlen;
127873143b9aSmrg    memcpy (newciptr->addr, ciptr->addr, newciptr->addrlen);
127973143b9aSmrg
1280fe567363Smrg    if ((newciptr->peeraddr = malloc (ciptr->addrlen)) == NULL)
128173143b9aSmrg    {
1282fe567363Smrg        prmsg (1,
1283fe567363Smrg	      "SocketUNIXAccept: Can't allocate space for the addr\n");
128473143b9aSmrg	close (newciptr->fd);
1285fe567363Smrg	if (newciptr->addr) free (newciptr->addr);
1286fe567363Smrg	free (newciptr);
128773143b9aSmrg	*status = TRANS_ACCEPT_BAD_MALLOC;
128873143b9aSmrg        return NULL;
128973143b9aSmrg    }
1290fe567363Smrg
129173143b9aSmrg    newciptr->peeraddrlen = ciptr->addrlen;
129273143b9aSmrg    memcpy (newciptr->peeraddr, ciptr->addr, newciptr->addrlen);
129373143b9aSmrg
129473143b9aSmrg    newciptr->family = AF_UNIX;
129573143b9aSmrg
129673143b9aSmrg    *status = 0;
129773143b9aSmrg
129873143b9aSmrg    return newciptr;
129973143b9aSmrg}
130073143b9aSmrg
130173143b9aSmrg#endif /* UNIXCONN */
130273143b9aSmrg
130373143b9aSmrg#endif /* TRANS_SERVER */
130473143b9aSmrg
130573143b9aSmrg
130673143b9aSmrg#ifdef TRANS_CLIENT
130773143b9aSmrg
130873143b9aSmrg#ifdef TCPCONN
130973143b9aSmrg
1310ac57ed83Smrg#ifdef HAVE_GETADDRINFO
131173143b9aSmrgstruct addrlist {
131273143b9aSmrg    struct addrinfo *	addr;
1313fe567363Smrg    struct addrinfo *	firstaddr;
131473143b9aSmrg    char 		port[PORTBUFSIZE];
131573143b9aSmrg    char 		host[MAXHOSTNAMELEN];
131673143b9aSmrg};
131773143b9aSmrgstatic struct addrlist  *addrlist = NULL;
131873143b9aSmrg#endif
131973143b9aSmrg
132073143b9aSmrg
132173143b9aSmrgstatic int
13226a3641a6SsnjTRANS(SocketINETConnect) (XtransConnInfo ciptr,
13236a3641a6Ssnj                          const char *host, const char *port)
132473143b9aSmrg
132573143b9aSmrg{
132673143b9aSmrg    struct sockaddr *	socketaddr = NULL;
132773143b9aSmrg    int			socketaddrlen = 0;
132873143b9aSmrg    int			res;
1329ac57ed83Smrg#ifdef HAVE_GETADDRINFO
133073143b9aSmrg    struct addrinfo 	hints;
133173143b9aSmrg    char		ntopbuf[INET6_ADDRSTRLEN];
133273143b9aSmrg    int			resetonce = 0;
1333fe567363Smrg#else
133473143b9aSmrg    struct sockaddr_in	sockname;
1335fe567363Smrg    struct hostent	*hostp;
1336fe567363Smrg    struct servent	*servp;
1337fe567363Smrg    unsigned long 	tmpaddr;
1338fe567363Smrg#endif
133973143b9aSmrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
134073143b9aSmrg    _Xgethostbynameparams hparams;
134173143b9aSmrg    _Xgetservbynameparams sparams;
134273143b9aSmrg#endif
134373143b9aSmrg#ifdef X11_t
134473143b9aSmrg    char	portbuf[PORTBUFSIZE];
134573143b9aSmrg#endif
134673143b9aSmrg
134773143b9aSmrg    char 		hostnamebuf[256];		/* tmp space */
134873143b9aSmrg
1349fe567363Smrg    prmsg (2,"SocketINETConnect(%d,%s,%s)\n", ciptr->fd, host, port);
135073143b9aSmrg
135173143b9aSmrg    if (!host)
135273143b9aSmrg    {
135373143b9aSmrg	hostnamebuf[0] = '\0';
135473143b9aSmrg	(void) TRANS(GetHostname) (hostnamebuf, sizeof hostnamebuf);
135573143b9aSmrg	host = hostnamebuf;
135673143b9aSmrg    }
135773143b9aSmrg
135873143b9aSmrg#ifdef X11_t
135973143b9aSmrg    /*
136073143b9aSmrg     * X has a well known port, that is transport dependent. It is easier
136173143b9aSmrg     * to handle it here, than try and come up with a transport independent
136273143b9aSmrg     * representation that can be passed in and resolved the usual way.
136373143b9aSmrg     *
136473143b9aSmrg     * The port that is passed here is really a string containing the idisplay
136573143b9aSmrg     * from ConnectDisplay().
136673143b9aSmrg     */
136773143b9aSmrg
136873143b9aSmrg    if (is_numeric (port))
136973143b9aSmrg    {
1370fe567363Smrg	long tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10);
1371fe567363Smrg	snprintf (portbuf, sizeof(portbuf), "%lu", tmpport);
137273143b9aSmrg	port = portbuf;
137373143b9aSmrg    }
137473143b9aSmrg#endif
137573143b9aSmrg
1376ac57ed83Smrg#ifdef HAVE_GETADDRINFO
1377b53e5eeaSmrg    {
137873143b9aSmrg	if (addrlist != NULL) {
137973143b9aSmrg	    if (strcmp(host,addrlist->host) || strcmp(port,addrlist->port)) {
138073143b9aSmrg		if (addrlist->firstaddr)
138173143b9aSmrg		    freeaddrinfo(addrlist->firstaddr);
138273143b9aSmrg		addrlist->firstaddr = NULL;
138373143b9aSmrg	    }
138473143b9aSmrg	} else {
138573143b9aSmrg	    addrlist = malloc(sizeof(struct addrlist));
138694f982dbSmrg	    if (addrlist == NULL) {
138794f982dbSmrg		prmsg (1, "SocketINETConnect() can't allocate memory "
138894f982dbSmrg			"for addrlist: %s\n", strerror(errno));
138994f982dbSmrg		return TRANS_CONNECT_FAILED;
139094f982dbSmrg	    }
139173143b9aSmrg	    addrlist->firstaddr = NULL;
139273143b9aSmrg	}
139373143b9aSmrg
139473143b9aSmrg	if (addrlist->firstaddr == NULL) {
139573143b9aSmrg	    strncpy(addrlist->port, port, sizeof(addrlist->port));
139673143b9aSmrg	    addrlist->port[sizeof(addrlist->port) - 1] = '\0';
139773143b9aSmrg	    strncpy(addrlist->host, host, sizeof(addrlist->host));
139873143b9aSmrg	    addrlist->host[sizeof(addrlist->host) - 1] = '\0';
139973143b9aSmrg
140073143b9aSmrg	    bzero(&hints,sizeof(hints));
1401ac57ed83Smrg#ifdef IPv6
1402ac57ed83Smrg	    if (strcmp(Sockettrans2devtab[ciptr->index].transname, "tcp") == 0)
1403ac57ed83Smrg		hints.ai_family = AF_UNSPEC;
1404ac57ed83Smrg	    else
1405ac57ed83Smrg#endif
1406ac57ed83Smrg		hints.ai_family = Sockettrans2devtab[ciptr->index].family;
140773143b9aSmrg	    hints.ai_socktype = Sockettrans2devtab[ciptr->index].devcotsname;
140873143b9aSmrg
140973143b9aSmrg	    res = getaddrinfo(host,port,&hints,&addrlist->firstaddr);
141073143b9aSmrg	    if (res != 0) {
1411fe567363Smrg		prmsg (1, "SocketINETConnect() can't get address "
141273143b9aSmrg			"for %s:%s: %s\n", host, port, gai_strerror(res));
141373143b9aSmrg		ESET(EINVAL);
141473143b9aSmrg		return TRANS_CONNECT_FAILED;
141573143b9aSmrg	    }
141673143b9aSmrg	    for (res = 0, addrlist->addr = addrlist->firstaddr;
141773143b9aSmrg		 addrlist->addr ; res++) {
141873143b9aSmrg		addrlist->addr = addrlist->addr->ai_next;
141973143b9aSmrg	    }
1420fe567363Smrg	    prmsg(4,"Got New Address list with %d addresses\n", res);
142173143b9aSmrg	    res = 0;
142273143b9aSmrg	    addrlist->addr = NULL;
142373143b9aSmrg	}
142473143b9aSmrg
142573143b9aSmrg	while (socketaddr == NULL) {
142673143b9aSmrg	    if (addrlist->addr == NULL) {
1427fe567363Smrg		if (resetonce) {
142873143b9aSmrg		    /* Already checked entire list - no usable addresses */
1429fe567363Smrg		    prmsg (1, "SocketINETConnect() no usable address "
1430fe567363Smrg			   "for %s:%s\n", host, port);
143173143b9aSmrg		    return TRANS_CONNECT_FAILED;
143273143b9aSmrg		} else {
143373143b9aSmrg		    /* Go back to beginning of list */
143473143b9aSmrg		    resetonce = 1;
143573143b9aSmrg		    addrlist->addr = addrlist->firstaddr;
143673143b9aSmrg		}
1437fe567363Smrg	    }
143873143b9aSmrg
143973143b9aSmrg	    socketaddr = addrlist->addr->ai_addr;
144073143b9aSmrg	    socketaddrlen = addrlist->addr->ai_addrlen;
144173143b9aSmrg
144273143b9aSmrg	    if (addrlist->addr->ai_family == AF_INET) {
144373143b9aSmrg		struct sockaddr_in *sin = (struct sockaddr_in *) socketaddr;
144473143b9aSmrg
1445fe567363Smrg		prmsg (4,"SocketINETConnect() sockname.sin_addr = %s\n",
144673143b9aSmrg			inet_ntop(addrlist->addr->ai_family,&sin->sin_addr,
1447fe567363Smrg			ntopbuf,sizeof(ntopbuf)));
144873143b9aSmrg
1449fe567363Smrg		prmsg (4,"SocketINETConnect() sockname.sin_port = %d\n",
1450fe567363Smrg			ntohs(sin->sin_port));
145173143b9aSmrg
1452ac57ed83Smrg#ifdef IPv6
145373143b9aSmrg		if (Sockettrans2devtab[ciptr->index].family == AF_INET6) {
145473143b9aSmrg		    if (strcmp(Sockettrans2devtab[ciptr->index].transname,
145573143b9aSmrg				"tcp") == 0) {
145673143b9aSmrg			XtransConnInfo newciptr;
145773143b9aSmrg
145873143b9aSmrg			/*
145973143b9aSmrg			 * Our socket is an IPv6 socket, but the address is
146073143b9aSmrg			 * IPv4.  Close it and get an IPv4 socket.  This is
146173143b9aSmrg			 * needed for IPv4 connections to work on platforms
146273143b9aSmrg			 * that don't allow IPv4 over IPv6 sockets.
146373143b9aSmrg			 */
146473143b9aSmrg			TRANS(SocketINETClose)(ciptr);
146573143b9aSmrg			newciptr = TRANS(SocketOpenCOTSClientBase)(
146673143b9aSmrg					"tcp", "tcp", host, port, ciptr->index);
146773143b9aSmrg			if (newciptr)
146873143b9aSmrg			    ciptr->fd = newciptr->fd;
146973143b9aSmrg			if (!newciptr ||
147073143b9aSmrg			    Sockettrans2devtab[newciptr->index].family !=
147173143b9aSmrg				AF_INET) {
147273143b9aSmrg			    socketaddr = NULL;
1473fe567363Smrg			    prmsg (4,"SocketINETConnect() Cannot get IPv4 "
1474fe567363Smrg					" socketfor IPv4 address\n");
147573143b9aSmrg			}
147673143b9aSmrg			if (newciptr)
1477fe567363Smrg			    free(newciptr);
147873143b9aSmrg		    } else {
147973143b9aSmrg			socketaddr = NULL;
1480fe567363Smrg			prmsg (4,"SocketINETConnect Skipping IPv4 address\n");
148173143b9aSmrg		    }
148273143b9aSmrg		}
148373143b9aSmrg	    } else if (addrlist->addr->ai_family == AF_INET6) {
148473143b9aSmrg		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) socketaddr;
1485fe567363Smrg
1486fe567363Smrg		prmsg (4,"SocketINETConnect() sockname.sin6_addr = %s\n",
148773143b9aSmrg			inet_ntop(addrlist->addr->ai_family,
1488fe567363Smrg				  &sin6->sin6_addr,ntopbuf,sizeof(ntopbuf)));
1489fe567363Smrg		prmsg (4,"SocketINETConnect() sockname.sin6_port = %d\n",
1490fe567363Smrg			ntohs(sin6->sin6_port));
149173143b9aSmrg
149273143b9aSmrg		if (Sockettrans2devtab[ciptr->index].family == AF_INET) {
149373143b9aSmrg		    if (strcmp(Sockettrans2devtab[ciptr->index].transname,
149473143b9aSmrg				"tcp") == 0) {
149573143b9aSmrg			XtransConnInfo newciptr;
149673143b9aSmrg
149773143b9aSmrg			/*
149873143b9aSmrg			 * Close the IPv4 socket and try to open an IPv6 socket.
149973143b9aSmrg			 */
150073143b9aSmrg			TRANS(SocketINETClose)(ciptr);
150173143b9aSmrg			newciptr = TRANS(SocketOpenCOTSClientBase)(
150273143b9aSmrg					"tcp", "tcp", host, port, -1);
150373143b9aSmrg			if (newciptr)
150473143b9aSmrg			    ciptr->fd = newciptr->fd;
150573143b9aSmrg			if (!newciptr ||
150673143b9aSmrg			    Sockettrans2devtab[newciptr->index].family !=
150773143b9aSmrg					AF_INET6) {
150873143b9aSmrg			    socketaddr = NULL;
1509fe567363Smrg			    prmsg (4,"SocketINETConnect() Cannot get IPv6 "
1510fe567363Smrg				   "socket for IPv6 address\n");
151173143b9aSmrg			}
151273143b9aSmrg			if (newciptr)
1513fe567363Smrg			    free(newciptr);
151473143b9aSmrg		    }
151573143b9aSmrg		    else
151673143b9aSmrg		    {
151773143b9aSmrg			socketaddr = NULL;
1518fe567363Smrg			prmsg (4,"SocketINETConnect() Skipping IPv6 address\n");
151973143b9aSmrg		    }
152073143b9aSmrg		}
1521ac57ed83Smrg#endif /* IPv6 */
152273143b9aSmrg	    } else {
152373143b9aSmrg		socketaddr = NULL; /* Unsupported address type */
152473143b9aSmrg	    }
152573143b9aSmrg	    if (socketaddr == NULL) {
152673143b9aSmrg		addrlist->addr = addrlist->addr->ai_next;
152773143b9aSmrg	    }
1528fe567363Smrg	}
1529b53e5eeaSmrg    }
1530ac57ed83Smrg#else /* !HAVE_GETADDRINFO */
153173143b9aSmrg    {
153273143b9aSmrg	/*
153373143b9aSmrg	 * Build the socket name.
153473143b9aSmrg	 */
153573143b9aSmrg
153673143b9aSmrg#ifdef BSD44SOCKETS
153773143b9aSmrg	sockname.sin_len = sizeof (struct sockaddr_in);
153873143b9aSmrg#endif
153973143b9aSmrg	sockname.sin_family = AF_INET;
154073143b9aSmrg
154173143b9aSmrg	/*
154273143b9aSmrg	 * fill in sin_addr
154373143b9aSmrg	 */
154473143b9aSmrg
154573143b9aSmrg#ifndef INADDR_NONE
154673143b9aSmrg#define INADDR_NONE ((in_addr_t) 0xffffffff)
154773143b9aSmrg#endif
154873143b9aSmrg
154973143b9aSmrg	/* check for ww.xx.yy.zz host string */
155073143b9aSmrg
155173143b9aSmrg	if (isascii (host[0]) && isdigit (host[0])) {
155273143b9aSmrg	    tmpaddr = inet_addr (host); /* returns network byte order */
155373143b9aSmrg	} else {
155473143b9aSmrg	    tmpaddr = INADDR_NONE;
155573143b9aSmrg	}
155673143b9aSmrg
155781d6fa61Srin	prmsg (4,"SocketINETConnect() inet_addr(%s) = %lx\n", host, tmpaddr);
155873143b9aSmrg
155973143b9aSmrg	if (tmpaddr == INADDR_NONE) {
156073143b9aSmrg	    if ((hostp = _XGethostbyname(host,hparams)) == NULL) {
1561fe567363Smrg		prmsg (1,"SocketINETConnect: Can't get address for %s\n",
1562fe567363Smrg			host);
156373143b9aSmrg		ESET(EINVAL);
156473143b9aSmrg		return TRANS_CONNECT_FAILED;
156573143b9aSmrg	    }
156673143b9aSmrg	    if (hostp->h_addrtype != AF_INET) {  /* is IP host? */
1567fe567363Smrg		prmsg (1,"SocketINETConnect: not INET host%s\n", host);
156873143b9aSmrg		ESET(EPROTOTYPE);
156973143b9aSmrg		return TRANS_CONNECT_FAILED;
157073143b9aSmrg	    }
1571fe567363Smrg
157273143b9aSmrg	    memcpy ((char *) &sockname.sin_addr, (char *) hostp->h_addr,
157373143b9aSmrg		    sizeof (sockname.sin_addr));
157473143b9aSmrg
157573143b9aSmrg	} else {
157673143b9aSmrg	    sockname.sin_addr.s_addr = tmpaddr;
157773143b9aSmrg        }
157873143b9aSmrg
157973143b9aSmrg	/*
158073143b9aSmrg	 * fill in sin_port
158173143b9aSmrg	 */
158273143b9aSmrg
158373143b9aSmrg	/* Check for number in the port string */
158473143b9aSmrg
158573143b9aSmrg	if (!is_numeric (port)) {
158673143b9aSmrg	    if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL) {
1587fe567363Smrg		prmsg (1,"SocketINETConnect: can't get service for %s\n",
1588fe567363Smrg			port);
158973143b9aSmrg		return TRANS_CONNECT_FAILED;
159073143b9aSmrg	    }
159173143b9aSmrg	    sockname.sin_port = htons (servp->s_port);
159273143b9aSmrg	} else {
1593fe567363Smrg	    long tmpport = strtol (port, (char**)NULL, 10);
159473143b9aSmrg	    if (tmpport < 1024 || tmpport > USHRT_MAX)
159573143b9aSmrg		return TRANS_CONNECT_FAILED;
159673143b9aSmrg	    sockname.sin_port = htons (((unsigned short) tmpport));
159773143b9aSmrg	}
159873143b9aSmrg
1599fe567363Smrg	prmsg (4,"SocketINETConnect: sockname.sin_port = %d\n",
1600fe567363Smrg		ntohs(sockname.sin_port));
160173143b9aSmrg	socketaddr = (struct sockaddr *) &sockname;
160273143b9aSmrg	socketaddrlen = sizeof(sockname);
160373143b9aSmrg    }
1604b53e5eeaSmrg#endif
160573143b9aSmrg
160673143b9aSmrg    /*
160773143b9aSmrg     * Turn on socket keepalive so the client process will eventually
160873143b9aSmrg     * be notified with a SIGPIPE signal if the display server fails
160973143b9aSmrg     * to respond to a periodic transmission of messages
161073143b9aSmrg     * on the connected socket.
161173143b9aSmrg     * This is useful to avoid hung application processes when the
161273143b9aSmrg     * processes are not spawned from the xdm session and
161373143b9aSmrg     * the display server terminates abnormally.
161473143b9aSmrg     * (Someone turned off the power switch.)
161573143b9aSmrg     */
161673143b9aSmrg
161773143b9aSmrg    {
161873143b9aSmrg	int tmp = 1;
161973143b9aSmrg	setsockopt (ciptr->fd, SOL_SOCKET, SO_KEEPALIVE,
162073143b9aSmrg		(char *) &tmp, sizeof (int));
162173143b9aSmrg    }
162273143b9aSmrg
162373143b9aSmrg    /*
162473143b9aSmrg     * Do the connect()
162573143b9aSmrg     */
162673143b9aSmrg
162773143b9aSmrg    if (connect (ciptr->fd, socketaddr, socketaddrlen ) < 0)
162873143b9aSmrg    {
162973143b9aSmrg#ifdef WIN32
163073143b9aSmrg	int olderrno = WSAGetLastError();
163173143b9aSmrg#else
163273143b9aSmrg	int olderrno = errno;
163373143b9aSmrg#endif
163473143b9aSmrg
163573143b9aSmrg	/*
163673143b9aSmrg	 * If the error was ECONNREFUSED, the server may be overloaded
163773143b9aSmrg	 * and we should try again.
163873143b9aSmrg	 *
163973143b9aSmrg	 * If the error was EWOULDBLOCK or EINPROGRESS then the socket
164073143b9aSmrg	 * was non-blocking and we should poll using select
164173143b9aSmrg	 *
164273143b9aSmrg	 * If the error was EINTR, the connect was interrupted and we
164373143b9aSmrg	 * should try again.
164473143b9aSmrg	 *
164573143b9aSmrg	 * If multiple addresses are found for a host then we should
164673143b9aSmrg	 * try to connect again with a different address for a larger
164773143b9aSmrg	 * number of errors that made us quit before, since those
164873143b9aSmrg	 * could be caused by trying to use an IPv6 address to contact
164973143b9aSmrg	 * a machine with an IPv4-only server or other reasons that
1650fe567363Smrg	 * only affect one of a set of addresses.
165173143b9aSmrg	 */
165273143b9aSmrg
165373143b9aSmrg	if (olderrno == ECONNREFUSED || olderrno == EINTR
1654ac57ed83Smrg#ifdef HAVE_GETADDRINFO
1655b53e5eeaSmrg	  || (((addrlist->addr->ai_next != NULL) ||
165673143b9aSmrg	        (addrlist->addr != addrlist->firstaddr)) &&
165773143b9aSmrg               (olderrno == ENETUNREACH || olderrno == EAFNOSUPPORT ||
165873143b9aSmrg		 olderrno == EADDRNOTAVAIL || olderrno == ETIMEDOUT
165973143b9aSmrg#if defined(EHOSTDOWN)
166073143b9aSmrg		   || olderrno == EHOSTDOWN
166173143b9aSmrg#endif
166273143b9aSmrg	       ))
166373143b9aSmrg#endif
166473143b9aSmrg	    )
166573143b9aSmrg	    res = TRANS_TRY_CONNECT_AGAIN;
166673143b9aSmrg	else if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS)
166773143b9aSmrg	    res = TRANS_IN_PROGRESS;
166873143b9aSmrg	else
166973143b9aSmrg	{
1670fe567363Smrg	    prmsg (2,"SocketINETConnect: Can't connect: errno = %d\n",
1671fe567363Smrg		   olderrno);
167273143b9aSmrg
1673fe567363Smrg	    res = TRANS_CONNECT_FAILED;
167473143b9aSmrg	}
167573143b9aSmrg    } else {
167673143b9aSmrg	res = 0;
1677fe567363Smrg
167873143b9aSmrg
167973143b9aSmrg	/*
168073143b9aSmrg	 * Sync up the address fields of ciptr.
168173143b9aSmrg	 */
1682fe567363Smrg
168373143b9aSmrg	if (TRANS(SocketINETGetAddr) (ciptr) < 0)
168473143b9aSmrg	{
1685fe567363Smrg	    prmsg (1,
1686fe567363Smrg	     "SocketINETConnect: ...SocketINETGetAddr() failed:\n");
168773143b9aSmrg	    res = TRANS_CONNECT_FAILED;
168873143b9aSmrg	}
168973143b9aSmrg
169073143b9aSmrg	else if (TRANS(SocketINETGetPeerAddr) (ciptr) < 0)
169173143b9aSmrg	{
1692fe567363Smrg	    prmsg (1,
1693fe567363Smrg	      "SocketINETConnect: ...SocketINETGetPeerAddr() failed:\n");
169473143b9aSmrg	    res = TRANS_CONNECT_FAILED;
169573143b9aSmrg	}
169673143b9aSmrg    }
169773143b9aSmrg
1698ac57ed83Smrg#ifdef HAVE_GETADDRINFO
1699b53e5eeaSmrg   if (res != 0) {
170073143b9aSmrg	addrlist->addr = addrlist->addr->ai_next;
170173143b9aSmrg   }
170273143b9aSmrg#endif
170373143b9aSmrg
170473143b9aSmrg    return res;
170573143b9aSmrg}
170673143b9aSmrg
170773143b9aSmrg#endif /* TCPCONN */
170873143b9aSmrg
170973143b9aSmrg
171073143b9aSmrg
171173143b9aSmrg#ifdef UNIXCONN
171273143b9aSmrg
171373143b9aSmrg/*
171473143b9aSmrg * Make sure 'host' is really local.
171573143b9aSmrg */
171673143b9aSmrg
171773143b9aSmrgstatic int
17186a3641a6SsnjUnixHostReallyLocal (const char *host)
171973143b9aSmrg
172073143b9aSmrg{
172173143b9aSmrg    char hostnamebuf[256];
172273143b9aSmrg
172373143b9aSmrg    TRANS(GetHostname) (hostnamebuf, sizeof (hostnamebuf));
172473143b9aSmrg
172573143b9aSmrg    if (strcmp (hostnamebuf, host) == 0)
172673143b9aSmrg    {
172773143b9aSmrg	return (1);
1728b53e5eeaSmrg    } else {
1729ac57ed83Smrg#ifdef HAVE_GETADDRINFO
173073143b9aSmrg	struct addrinfo *localhostaddr;
173173143b9aSmrg	struct addrinfo *otherhostaddr;
173273143b9aSmrg	struct addrinfo *i, *j;
173373143b9aSmrg	int equiv = 0;
173473143b9aSmrg
173573143b9aSmrg	if (getaddrinfo(hostnamebuf, NULL, NULL, &localhostaddr) != 0)
173673143b9aSmrg	    return 0;
173773143b9aSmrg	if (getaddrinfo(host, NULL, NULL, &otherhostaddr) != 0) {
173873143b9aSmrg	    freeaddrinfo(localhostaddr);
173973143b9aSmrg	    return 0;
174073143b9aSmrg	}
174173143b9aSmrg
174273143b9aSmrg	for (i = localhostaddr; i != NULL && equiv == 0; i = i->ai_next) {
174373143b9aSmrg	    for (j = otherhostaddr; j != NULL && equiv == 0; j = j->ai_next) {
174473143b9aSmrg		if (i->ai_family == j->ai_family) {
174573143b9aSmrg		    if (i->ai_family == AF_INET) {
1746fe567363Smrg			struct sockaddr_in *sinA
174773143b9aSmrg			  = (struct sockaddr_in *) i->ai_addr;
174873143b9aSmrg			struct sockaddr_in *sinB
174973143b9aSmrg			  = (struct sockaddr_in *) j->ai_addr;
175073143b9aSmrg			struct in_addr *A = &sinA->sin_addr;
175173143b9aSmrg			struct in_addr *B = &sinB->sin_addr;
175273143b9aSmrg
175373143b9aSmrg			if (memcmp(A,B,sizeof(struct in_addr)) == 0) {
175473143b9aSmrg			    equiv = 1;
175573143b9aSmrg			}
1756ac57ed83Smrg#ifdef IPv6
175773143b9aSmrg		    } else if (i->ai_family == AF_INET6) {
1758fe567363Smrg			struct sockaddr_in6 *sinA
175973143b9aSmrg			  = (struct sockaddr_in6 *) i->ai_addr;
1760fe567363Smrg			struct sockaddr_in6 *sinB
176173143b9aSmrg			  = (struct sockaddr_in6 *) j->ai_addr;
176273143b9aSmrg			struct in6_addr *A = &sinA->sin6_addr;
176373143b9aSmrg			struct in6_addr *B = &sinB->sin6_addr;
176473143b9aSmrg
176573143b9aSmrg			if (memcmp(A,B,sizeof(struct in6_addr)) == 0) {
176673143b9aSmrg			    equiv = 1;
176773143b9aSmrg			}
1768ac57ed83Smrg#endif /* IPv6 */
176973143b9aSmrg		    }
177073143b9aSmrg		}
177173143b9aSmrg	    }
177273143b9aSmrg	}
1773fe567363Smrg
177473143b9aSmrg	freeaddrinfo(localhostaddr);
177573143b9aSmrg	freeaddrinfo(otherhostaddr);
177673143b9aSmrg	return equiv;
1777ac57ed83Smrg#else /* !HAVE_GETADDRINFO */
177873143b9aSmrg	/*
177973143b9aSmrg	 * A host may have more than one network address.  If any of the
178073143b9aSmrg	 * network addresses of 'host' (specified to the connect call)
178173143b9aSmrg	 * match any of the network addresses of 'hostname' (determined
178273143b9aSmrg	 * by TRANS(GetHostname)), then the two hostnames are equivalent,
178373143b9aSmrg	 * and we know that 'host' is really a local host.
178473143b9aSmrg	 */
178573143b9aSmrg	char specified_local_addr_list[10][4];
178673143b9aSmrg	int scount, equiv, i, j;
178773143b9aSmrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
178873143b9aSmrg	_Xgethostbynameparams hparams;
178973143b9aSmrg#endif
179073143b9aSmrg	struct hostent *hostp;
179173143b9aSmrg
179273143b9aSmrg	if ((hostp = _XGethostbyname (host,hparams)) == NULL)
179373143b9aSmrg	    return (0);
179473143b9aSmrg
179573143b9aSmrg	scount = 0;
179673143b9aSmrg	while (hostp->h_addr_list[scount] && scount <= 8)
179773143b9aSmrg	{
179873143b9aSmrg	    /*
179973143b9aSmrg	     * The 2nd call to gethostname() overrides the data
180073143b9aSmrg	     * from the 1st call, so we must save the address list.
180173143b9aSmrg	     */
180273143b9aSmrg
1803fe567363Smrg	    specified_local_addr_list[scount][0] =
180473143b9aSmrg				hostp->h_addr_list[scount][0];
1805fe567363Smrg	    specified_local_addr_list[scount][1] =
180673143b9aSmrg				hostp->h_addr_list[scount][1];
1807fe567363Smrg	    specified_local_addr_list[scount][2] =
180873143b9aSmrg				hostp->h_addr_list[scount][2];
1809fe567363Smrg	    specified_local_addr_list[scount][3] =
181073143b9aSmrg				hostp->h_addr_list[scount][3];
181173143b9aSmrg	    scount++;
181273143b9aSmrg	}
181373143b9aSmrg	if ((hostp = _XGethostbyname (hostnamebuf,hparams)) == NULL)
181473143b9aSmrg	    return (0);
181573143b9aSmrg
181673143b9aSmrg	equiv = 0;
181773143b9aSmrg	i = 0;
181873143b9aSmrg
181973143b9aSmrg	while (i < scount && !equiv)
182073143b9aSmrg	{
182173143b9aSmrg	    j = 0;
182273143b9aSmrg
182373143b9aSmrg	    while (hostp->h_addr_list[j])
182473143b9aSmrg	    {
1825fe567363Smrg		if ((specified_local_addr_list[i][0] ==
182673143b9aSmrg					hostp->h_addr_list[j][0]) &&
1827fe567363Smrg		    (specified_local_addr_list[i][1] ==
182873143b9aSmrg					hostp->h_addr_list[j][1]) &&
1829fe567363Smrg		    (specified_local_addr_list[i][2] ==
183073143b9aSmrg					hostp->h_addr_list[j][2]) &&
1831fe567363Smrg		    (specified_local_addr_list[i][3] ==
183273143b9aSmrg					hostp->h_addr_list[j][3]))
183373143b9aSmrg		{
183473143b9aSmrg		    /* They're equal, so we're done */
1835fe567363Smrg
183673143b9aSmrg		    equiv = 1;
183773143b9aSmrg		    break;
183873143b9aSmrg		}
183973143b9aSmrg
184073143b9aSmrg		j++;
184173143b9aSmrg	    }
184273143b9aSmrg
184373143b9aSmrg	    i++;
184473143b9aSmrg	}
184573143b9aSmrg	return (equiv);
1846b53e5eeaSmrg#endif
184773143b9aSmrg    }
184873143b9aSmrg}
184973143b9aSmrg
185073143b9aSmrgstatic int
18516a3641a6SsnjTRANS(SocketUNIXConnect) (XtransConnInfo ciptr,
18526a3641a6Ssnj                          const char *host, const char *port)
185373143b9aSmrg
185473143b9aSmrg{
185573143b9aSmrg    struct sockaddr_un	sockname;
185673143b9aSmrg    SOCKLEN_T		namelen;
185773143b9aSmrg
1858fe567363Smrg    prmsg (2,"SocketUNIXConnect(%d,%s,%s)\n", ciptr->fd, host, port);
1859fe567363Smrg
186073143b9aSmrg    /*
186173143b9aSmrg     * Make sure 'host' is really local.  If not, we return failure.
186273143b9aSmrg     * The reason we make this check is because a process may advertise
186373143b9aSmrg     * a "local" network ID for which it can accept connections, but if
186473143b9aSmrg     * a process on a remote machine tries to connect to this network ID,
186573143b9aSmrg     * we know for sure it will fail.
186673143b9aSmrg     */
186773143b9aSmrg
186873143b9aSmrg    if (host && *host && host[0]!='/' && strcmp (host, "unix") != 0 && !UnixHostReallyLocal (host))
186973143b9aSmrg    {
1870fe567363Smrg	prmsg (1,
187173143b9aSmrg	   "SocketUNIXConnect: Cannot connect to non-local host %s\n",
1872fe567363Smrg	       host);
187373143b9aSmrg	return TRANS_CONNECT_FAILED;
187473143b9aSmrg    }
187573143b9aSmrg
187673143b9aSmrg
187773143b9aSmrg    /*
187873143b9aSmrg     * Check the port.
187973143b9aSmrg     */
188073143b9aSmrg
188173143b9aSmrg    if (!port || !*port)
188273143b9aSmrg    {
1883fe567363Smrg	prmsg (1,"SocketUNIXConnect: Missing port specification\n");
188473143b9aSmrg	return TRANS_CONNECT_FAILED;
188573143b9aSmrg    }
188673143b9aSmrg
188773143b9aSmrg    /*
188873143b9aSmrg     * Build the socket name.
188973143b9aSmrg     */
1890fe567363Smrg
189173143b9aSmrg    sockname.sun_family = AF_UNIX;
189273143b9aSmrg
1893a773ec55Smrg    if (set_sun_path(port, UNIX_PATH, sockname.sun_path, 0) != 0) {
1894fe567363Smrg	prmsg (1, "SocketUNIXConnect: path too long\n");
189573143b9aSmrg	return TRANS_CONNECT_FAILED;
189673143b9aSmrg    }
189773143b9aSmrg
1898a773ec55Smrg#if defined(BSD44SOCKETS)
189973143b9aSmrg    sockname.sun_len = strlen (sockname.sun_path);
190073143b9aSmrg#endif
190173143b9aSmrg
190273143b9aSmrg#if defined(BSD44SOCKETS) || defined(SUN_LEN)
190373143b9aSmrg    namelen = SUN_LEN (&sockname);
190473143b9aSmrg#else
190573143b9aSmrg    namelen = strlen (sockname.sun_path) + offsetof(struct sockaddr_un, sun_path);
190673143b9aSmrg#endif
190773143b9aSmrg
190873143b9aSmrg
190973143b9aSmrg    /*
191073143b9aSmrg     * Do the connect()
191173143b9aSmrg     */
191273143b9aSmrg
191373143b9aSmrg    if (connect (ciptr->fd, (struct sockaddr *) &sockname, namelen) < 0)
191473143b9aSmrg    {
191573143b9aSmrg	int olderrno = errno;
191673143b9aSmrg	int connected = 0;
1917fe567363Smrg
191873143b9aSmrg	if (!connected)
191973143b9aSmrg	{
192073143b9aSmrg	    errno = olderrno;
1921fe567363Smrg
192273143b9aSmrg	    /*
192373143b9aSmrg	     * If the error was ENOENT, the server may be starting up; we used
192473143b9aSmrg	     * to suggest to try again in this case with
192573143b9aSmrg	     * TRANS_TRY_CONNECT_AGAIN, but this introduced problems for
192673143b9aSmrg	     * processes still referencing stale sockets in their environment.
192773143b9aSmrg	     * Hence, we now return a hard error, TRANS_CONNECT_FAILED, and it
192873143b9aSmrg	     * is suggested that higher level stacks handle retries on their
192973143b9aSmrg	     * level when they face a slow starting server.
193073143b9aSmrg	     *
193173143b9aSmrg	     * If the error was EWOULDBLOCK or EINPROGRESS then the socket
193273143b9aSmrg	     * was non-blocking and we should poll using select
193373143b9aSmrg	     *
193473143b9aSmrg	     * If the error was EINTR, the connect was interrupted and we
193573143b9aSmrg	     * should try again.
193673143b9aSmrg	     */
193773143b9aSmrg
193873143b9aSmrg	    if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS)
193973143b9aSmrg		return TRANS_IN_PROGRESS;
194073143b9aSmrg	    else if (olderrno == EINTR)
194173143b9aSmrg		return TRANS_TRY_CONNECT_AGAIN;
1942a773ec55Smrg	    else {
1943fe567363Smrg		prmsg (2,"SocketUNIXConnect: Can't connect: errno = %d\n",
1944fe567363Smrg		       EGET());
194573143b9aSmrg
194673143b9aSmrg		return TRANS_CONNECT_FAILED;
194773143b9aSmrg	    }
194873143b9aSmrg	}
194973143b9aSmrg    }
195073143b9aSmrg
195173143b9aSmrg    /*
195273143b9aSmrg     * Get the socket name and the peer name from the connect socket,
195373143b9aSmrg     * since this is unix domain.
195473143b9aSmrg     */
195573143b9aSmrg
1956fe567363Smrg    if ((ciptr->addr = malloc(namelen)) == NULL ||
1957fe567363Smrg       (ciptr->peeraddr = malloc(namelen)) == NULL)
195873143b9aSmrg    {
1959fe567363Smrg        prmsg (1,
1960fe567363Smrg	"SocketUNIXCreateListener: Can't allocate space for the addr\n");
196173143b9aSmrg        return TRANS_CONNECT_FAILED;
196273143b9aSmrg    }
196373143b9aSmrg
196473143b9aSmrg    ciptr->family = AF_UNIX;
196573143b9aSmrg    ciptr->addrlen = namelen;
196673143b9aSmrg    ciptr->peeraddrlen = namelen;
196773143b9aSmrg    memcpy (ciptr->addr, &sockname, ciptr->addrlen);
196873143b9aSmrg    memcpy (ciptr->peeraddr, &sockname, ciptr->peeraddrlen);
196973143b9aSmrg
197073143b9aSmrg    return 0;
197173143b9aSmrg}
197273143b9aSmrg
197373143b9aSmrg#endif /* UNIXCONN */
197473143b9aSmrg
197573143b9aSmrg#endif /* TRANS_CLIENT */
197673143b9aSmrg
197773143b9aSmrg
197873143b9aSmrgstatic int
197973143b9aSmrgTRANS(SocketBytesReadable) (XtransConnInfo ciptr, BytesReadable_t *pend)
198073143b9aSmrg
198173143b9aSmrg{
1982fe567363Smrg    prmsg (2,"SocketBytesReadable(%p,%d,%p)\n",
1983ac57ed83Smrg	(void *) ciptr, ciptr->fd, (void *) pend);
198473143b9aSmrg#ifdef WIN32
198573143b9aSmrg    {
198673143b9aSmrg	int ret = ioctlsocket ((SOCKET) ciptr->fd, FIONREAD, (u_long *) pend);
198773143b9aSmrg	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
198873143b9aSmrg	return ret;
198973143b9aSmrg    }
199073143b9aSmrg#else
199173143b9aSmrg    return ioctl (ciptr->fd, FIONREAD, (char *) pend);
199273143b9aSmrg#endif /* WIN32 */
199373143b9aSmrg}
199473143b9aSmrg
199575ebec6dSmrg#if XTRANS_SEND_FDS
199675ebec6dSmrg
199775ebec6dSmrgstatic void
199875ebec6dSmrgappendFd(struct _XtransConnFd **prev, int fd, int do_close)
199975ebec6dSmrg{
200075ebec6dSmrg    struct _XtransConnFd *cf, *new;
200175ebec6dSmrg
200275ebec6dSmrg    new = malloc (sizeof (struct _XtransConnFd));
200375ebec6dSmrg    if (!new) {
200475ebec6dSmrg        /* XXX mark connection as broken */
200575ebec6dSmrg        close(fd);
200675ebec6dSmrg        return;
200775ebec6dSmrg    }
200875ebec6dSmrg    new->next = 0;
200975ebec6dSmrg    new->fd = fd;
201075ebec6dSmrg    new->do_close = do_close;
201175ebec6dSmrg    /* search to end of list */
201275ebec6dSmrg    for (; (cf = *prev); prev = &(cf->next));
201375ebec6dSmrg    *prev = new;
201475ebec6dSmrg}
201573143b9aSmrg
201673143b9aSmrgstatic int
201775ebec6dSmrgremoveFd(struct _XtransConnFd **prev)
201875ebec6dSmrg{
201975ebec6dSmrg    struct _XtransConnFd *cf;
202075ebec6dSmrg    int fd;
202175ebec6dSmrg
202275ebec6dSmrg    if ((cf = *prev)) {
202375ebec6dSmrg        *prev = cf->next;
202475ebec6dSmrg        fd = cf->fd;
202575ebec6dSmrg        free(cf);
202675ebec6dSmrg    } else
202775ebec6dSmrg        fd = -1;
202875ebec6dSmrg    return fd;
202975ebec6dSmrg}
203073143b9aSmrg
203175ebec6dSmrgstatic void
203275ebec6dSmrgdiscardFd(struct _XtransConnFd **prev, struct _XtransConnFd *upto, int do_close)
203373143b9aSmrg{
203475ebec6dSmrg    struct _XtransConnFd *cf, *next;
203573143b9aSmrg
203675ebec6dSmrg    for (cf = *prev; cf != upto; cf = next) {
203775ebec6dSmrg        next = cf->next;
203875ebec6dSmrg        if (do_close || cf->do_close)
203975ebec6dSmrg            close(cf->fd);
204075ebec6dSmrg        free(cf);
204173143b9aSmrg    }
204275ebec6dSmrg    *prev = upto;
204373143b9aSmrg}
204473143b9aSmrg
204575ebec6dSmrgstatic void
204675ebec6dSmrgcleanupFds(XtransConnInfo ciptr)
204775ebec6dSmrg{
204875ebec6dSmrg    /* Clean up the send list but don't close the fds */
204975ebec6dSmrg    discardFd(&ciptr->send_fds, NULL, 0);
205075ebec6dSmrg    /* Clean up the recv list and *do* close the fds */
205175ebec6dSmrg    discardFd(&ciptr->recv_fds, NULL, 1);
205275ebec6dSmrg}
205373143b9aSmrg
205473143b9aSmrgstatic int
205575ebec6dSmrgnFd(struct _XtransConnFd **prev)
205675ebec6dSmrg{
205775ebec6dSmrg    struct _XtransConnFd *cf;
205875ebec6dSmrg    int n = 0;
205975ebec6dSmrg
206075ebec6dSmrg    for (cf = *prev; cf; cf = cf->next)
206175ebec6dSmrg        n++;
206275ebec6dSmrg    return n;
206375ebec6dSmrg}
206473143b9aSmrg
206575ebec6dSmrgstatic int
206675ebec6dSmrgTRANS(SocketRecvFd) (XtransConnInfo ciptr)
206773143b9aSmrg{
206875ebec6dSmrg    prmsg (2, "SocketRecvFd(%d)\n", ciptr->fd);
206975ebec6dSmrg    return removeFd(&ciptr->recv_fds);
207075ebec6dSmrg}
207175ebec6dSmrg
207275ebec6dSmrgstatic int
207375ebec6dSmrgTRANS(SocketSendFd) (XtransConnInfo ciptr, int fd, int do_close)
207475ebec6dSmrg{
207575ebec6dSmrg    appendFd(&ciptr->send_fds, fd, do_close);
207675ebec6dSmrg    return 0;
207775ebec6dSmrg}
207875ebec6dSmrg
207975ebec6dSmrgstatic int
208075ebec6dSmrgTRANS(SocketRecvFdInvalid)(XtransConnInfo ciptr)
208175ebec6dSmrg{
208275ebec6dSmrg    errno = EINVAL;
208375ebec6dSmrg    return -1;
208475ebec6dSmrg}
208575ebec6dSmrg
208675ebec6dSmrgstatic int
208775ebec6dSmrgTRANS(SocketSendFdInvalid)(XtransConnInfo ciptr, int fd, int do_close)
208875ebec6dSmrg{
208975ebec6dSmrg    errno = EINVAL;
209075ebec6dSmrg    return -1;
209175ebec6dSmrg}
209275ebec6dSmrg
209375ebec6dSmrg#define MAX_FDS		128
209475ebec6dSmrg
209575ebec6dSmrgunion fd_pass {
209675ebec6dSmrg	struct cmsghdr	cmsghdr;
209775ebec6dSmrg	char		buf[CMSG_SPACE(MAX_FDS * sizeof(int))];
209875ebec6dSmrg};
209975ebec6dSmrg
210075ebec6dSmrg#endif /* XTRANS_SEND_FDS */
210175ebec6dSmrg
210275ebec6dSmrgstatic int
210375ebec6dSmrgTRANS(SocketRead) (XtransConnInfo ciptr, char *buf, int size)
210475ebec6dSmrg
210575ebec6dSmrg{
2106ac57ed83Smrg    prmsg (2,"SocketRead(%d,%p,%d)\n", ciptr->fd, (void *) buf, size);
210773143b9aSmrg
2108fe567363Smrg#if defined(WIN32)
210973143b9aSmrg    {
211075ebec6dSmrg	int ret = recv ((SOCKET)ciptr->fd, buf, size, 0);
211173143b9aSmrg#ifdef WIN32
211273143b9aSmrg	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
211373143b9aSmrg#endif
211473143b9aSmrg	return ret;
211573143b9aSmrg    }
211673143b9aSmrg#else
211775ebec6dSmrg#if XTRANS_SEND_FDS
211875ebec6dSmrg    {
211975ebec6dSmrg        struct iovec    iov = {
212075ebec6dSmrg            .iov_base = buf,
212175ebec6dSmrg            .iov_len = size
212275ebec6dSmrg        };
212375ebec6dSmrg        union fd_pass   cmsgbuf;
212475ebec6dSmrg        struct msghdr   msg = {
212575ebec6dSmrg            .msg_name = NULL,
212675ebec6dSmrg            .msg_namelen = 0,
212775ebec6dSmrg            .msg_iov = &iov,
212875ebec6dSmrg            .msg_iovlen = 1,
212975ebec6dSmrg            .msg_control = cmsgbuf.buf,
213075ebec6dSmrg            .msg_controllen = CMSG_LEN(MAX_FDS * sizeof(int))
213175ebec6dSmrg        };
213275ebec6dSmrg
213375ebec6dSmrg        size = recvmsg(ciptr->fd, &msg, 0);
213475ebec6dSmrg        if (size >= 0) {
213575ebec6dSmrg            struct cmsghdr *hdr;
213675ebec6dSmrg
213775ebec6dSmrg            for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) {
213875ebec6dSmrg                if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) {
213975ebec6dSmrg                    int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int);
214075ebec6dSmrg                    int i;
214175ebec6dSmrg                    int *fd = (int *) CMSG_DATA(hdr);
214275ebec6dSmrg
214375ebec6dSmrg                    for (i = 0; i < nfd; i++)
214475ebec6dSmrg                        appendFd(&ciptr->recv_fds, fd[i], 0);
214575ebec6dSmrg                }
214675ebec6dSmrg            }
214775ebec6dSmrg        }
214875ebec6dSmrg        return size;
214975ebec6dSmrg    }
215075ebec6dSmrg#else
215175ebec6dSmrg    return read(ciptr->fd, buf, size);
215275ebec6dSmrg#endif /* XTRANS_SEND_FDS */
215373143b9aSmrg#endif /* WIN32 */
215473143b9aSmrg}
215573143b9aSmrg
215673143b9aSmrgstatic int
215773143b9aSmrgTRANS(SocketReadv) (XtransConnInfo ciptr, struct iovec *buf, int size)
215873143b9aSmrg
215973143b9aSmrg{
2160ac57ed83Smrg    prmsg (2,"SocketReadv(%d,%p,%d)\n", ciptr->fd, (void *) buf, size);
216173143b9aSmrg
216275ebec6dSmrg#if XTRANS_SEND_FDS
216375ebec6dSmrg    {
216475ebec6dSmrg        union fd_pass   cmsgbuf;
216575ebec6dSmrg        struct msghdr   msg = {
216675ebec6dSmrg            .msg_name = NULL,
216775ebec6dSmrg            .msg_namelen = 0,
216875ebec6dSmrg            .msg_iov = buf,
216975ebec6dSmrg            .msg_iovlen = size,
217075ebec6dSmrg            .msg_control = cmsgbuf.buf,
217175ebec6dSmrg            .msg_controllen = CMSG_LEN(MAX_FDS * sizeof(int))
217275ebec6dSmrg        };
217375ebec6dSmrg
217475ebec6dSmrg        size = recvmsg(ciptr->fd, &msg, 0);
217575ebec6dSmrg        if (size >= 0) {
217675ebec6dSmrg            struct cmsghdr *hdr;
217775ebec6dSmrg
217875ebec6dSmrg            for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) {
217975ebec6dSmrg                if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) {
218075ebec6dSmrg                    int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int);
218175ebec6dSmrg                    int i;
218275ebec6dSmrg                    int *fd = (int *) CMSG_DATA(hdr);
218375ebec6dSmrg
218475ebec6dSmrg                    for (i = 0; i < nfd; i++)
218575ebec6dSmrg                        appendFd(&ciptr->recv_fds, fd[i], 0);
218675ebec6dSmrg                }
218775ebec6dSmrg            }
218875ebec6dSmrg        }
218975ebec6dSmrg        return size;
219075ebec6dSmrg    }
219175ebec6dSmrg#else
219273143b9aSmrg    return READV (ciptr, buf, size);
219375ebec6dSmrg#endif
219473143b9aSmrg}
219573143b9aSmrg
219673143b9aSmrg
219773143b9aSmrgstatic int
219873143b9aSmrgTRANS(SocketWritev) (XtransConnInfo ciptr, struct iovec *buf, int size)
219973143b9aSmrg
220073143b9aSmrg{
2201ac57ed83Smrg    prmsg (2,"SocketWritev(%d,%p,%d)\n", ciptr->fd, (void *) buf, size);
220273143b9aSmrg
220375ebec6dSmrg#if XTRANS_SEND_FDS
220475ebec6dSmrg    if (ciptr->send_fds)
220575ebec6dSmrg    {
220675ebec6dSmrg        union fd_pass           cmsgbuf;
220775ebec6dSmrg        int                     nfd = nFd(&ciptr->send_fds);
220875ebec6dSmrg        struct _XtransConnFd    *cf = ciptr->send_fds;
220975ebec6dSmrg        struct msghdr           msg = {
221075ebec6dSmrg            .msg_name = NULL,
221175ebec6dSmrg            .msg_namelen = 0,
221275ebec6dSmrg            .msg_iov = buf,
221375ebec6dSmrg            .msg_iovlen = size,
221475ebec6dSmrg            .msg_control = cmsgbuf.buf,
221575ebec6dSmrg            .msg_controllen = CMSG_LEN(nfd * sizeof(int))
221675ebec6dSmrg        };
221775ebec6dSmrg        struct cmsghdr          *hdr = CMSG_FIRSTHDR(&msg);
221875ebec6dSmrg        int                     i;
221975ebec6dSmrg        int                     *fds;
222075ebec6dSmrg
222175ebec6dSmrg        hdr->cmsg_len = msg.msg_controllen;
222275ebec6dSmrg        hdr->cmsg_level = SOL_SOCKET;
222375ebec6dSmrg        hdr->cmsg_type = SCM_RIGHTS;
222475ebec6dSmrg
222575ebec6dSmrg        fds = (int *) CMSG_DATA(hdr);
222675ebec6dSmrg        /* Set up fds */
222775ebec6dSmrg        for (i = 0; i < nfd; i++) {
222875ebec6dSmrg            fds[i] = cf->fd;
222975ebec6dSmrg            cf = cf->next;
223075ebec6dSmrg        }
223175ebec6dSmrg
223275ebec6dSmrg        i = sendmsg(ciptr->fd, &msg, 0);
223375ebec6dSmrg        if (i > 0)
223475ebec6dSmrg            discardFd(&ciptr->send_fds, cf, 0);
223575ebec6dSmrg        return i;
223675ebec6dSmrg    }
223775ebec6dSmrg#endif
223873143b9aSmrg    return WRITEV (ciptr, buf, size);
223973143b9aSmrg}
224073143b9aSmrg
224173143b9aSmrg
224275ebec6dSmrgstatic int
2243ac57ed83SmrgTRANS(SocketWrite) (XtransConnInfo ciptr, const char *buf, int size)
224475ebec6dSmrg
224575ebec6dSmrg{
2246ac57ed83Smrg    prmsg (2,"SocketWrite(%d,%p,%d)\n", ciptr->fd, (const void *) buf, size);
224775ebec6dSmrg
224875ebec6dSmrg#if defined(WIN32)
224975ebec6dSmrg    {
225075ebec6dSmrg	int ret = send ((SOCKET)ciptr->fd, buf, size, 0);
225175ebec6dSmrg#ifdef WIN32
225275ebec6dSmrg	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
225375ebec6dSmrg#endif
225475ebec6dSmrg	return ret;
225575ebec6dSmrg    }
225675ebec6dSmrg#else
225775ebec6dSmrg#if XTRANS_SEND_FDS
225875ebec6dSmrg    if (ciptr->send_fds)
225975ebec6dSmrg    {
226075ebec6dSmrg        struct iovec            iov;
226175ebec6dSmrg
2262ac57ed83Smrg        iov.iov_base = (void *) buf;
226375ebec6dSmrg        iov.iov_len = size;
226475ebec6dSmrg        return TRANS(SocketWritev)(ciptr, &iov, 1);
226575ebec6dSmrg    }
226675ebec6dSmrg#endif /* XTRANS_SEND_FDS */
226775ebec6dSmrg    return write (ciptr->fd, buf, size);
226875ebec6dSmrg#endif /* WIN32 */
226975ebec6dSmrg}
227075ebec6dSmrg
227173143b9aSmrgstatic int
227273143b9aSmrgTRANS(SocketDisconnect) (XtransConnInfo ciptr)
227373143b9aSmrg
227473143b9aSmrg{
2275ac57ed83Smrg    prmsg (2,"SocketDisconnect(%p,%d)\n", (void *) ciptr, ciptr->fd);
227673143b9aSmrg
227773143b9aSmrg#ifdef WIN32
2278fe567363Smrg    {
227973143b9aSmrg	int ret = shutdown (ciptr->fd, 2);
228073143b9aSmrg	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
228173143b9aSmrg	return ret;
228273143b9aSmrg    }
228373143b9aSmrg#else
228473143b9aSmrg    return shutdown (ciptr->fd, 2); /* disallow further sends and receives */
228573143b9aSmrg#endif
228673143b9aSmrg}
228773143b9aSmrg
228873143b9aSmrg
228973143b9aSmrg#ifdef TCPCONN
229073143b9aSmrgstatic int
229173143b9aSmrgTRANS(SocketINETClose) (XtransConnInfo ciptr)
229273143b9aSmrg
229373143b9aSmrg{
2294ac57ed83Smrg    prmsg (2,"SocketINETClose(%p,%d)\n", (void *) ciptr, ciptr->fd);
229573143b9aSmrg
229673143b9aSmrg#ifdef WIN32
229773143b9aSmrg    {
229873143b9aSmrg	int ret = close (ciptr->fd);
229973143b9aSmrg	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
230073143b9aSmrg	return ret;
230173143b9aSmrg    }
230273143b9aSmrg#else
230373143b9aSmrg    return close (ciptr->fd);
230473143b9aSmrg#endif
230573143b9aSmrg}
230673143b9aSmrg
230773143b9aSmrg#endif /* TCPCONN */
230873143b9aSmrg
230973143b9aSmrg
231073143b9aSmrg#ifdef UNIXCONN
231173143b9aSmrgstatic int
231273143b9aSmrgTRANS(SocketUNIXClose) (XtransConnInfo ciptr)
231373143b9aSmrg{
231473143b9aSmrg    /*
231573143b9aSmrg     * If this is the server side, then once the socket is closed,
231673143b9aSmrg     * it must be unlinked to completely close it
231773143b9aSmrg     */
231873143b9aSmrg
231973143b9aSmrg    struct sockaddr_un	*sockname = (struct sockaddr_un *) ciptr->addr;
232073143b9aSmrg    int ret;
232173143b9aSmrg
2322ac57ed83Smrg    prmsg (2,"SocketUNIXClose(%p,%d)\n", (void *) ciptr, ciptr->fd);
232373143b9aSmrg
232475ebec6dSmrg#if XTRANS_SEND_FDS
232575ebec6dSmrg    cleanupFds(ciptr);
232675ebec6dSmrg#endif
232773143b9aSmrg    ret = close(ciptr->fd);
232873143b9aSmrg
232973143b9aSmrg    if (ciptr->flags
233073143b9aSmrg       && sockname
233173143b9aSmrg       && sockname->sun_family == AF_UNIX
233273143b9aSmrg       && sockname->sun_path[0])
233373143b9aSmrg    {
233473143b9aSmrg	if (!(ciptr->flags & TRANS_NOUNLINK
233573143b9aSmrg	    || ciptr->transptr->flags & TRANS_ABSTRACT))
233673143b9aSmrg		unlink (sockname->sun_path);
233773143b9aSmrg    }
233873143b9aSmrg
233973143b9aSmrg    return ret;
234073143b9aSmrg}
234173143b9aSmrg
234273143b9aSmrgstatic int
234373143b9aSmrgTRANS(SocketUNIXCloseForCloning) (XtransConnInfo ciptr)
234473143b9aSmrg
234573143b9aSmrg{
234673143b9aSmrg    /*
234773143b9aSmrg     * Don't unlink path.
234873143b9aSmrg     */
234973143b9aSmrg
235073143b9aSmrg    int ret;
235173143b9aSmrg
2352fe567363Smrg    prmsg (2,"SocketUNIXCloseForCloning(%p,%d)\n",
2353ac57ed83Smrg	(void *) ciptr, ciptr->fd);
235473143b9aSmrg
235575ebec6dSmrg#if XTRANS_SEND_FDS
235675ebec6dSmrg    cleanupFds(ciptr);
235775ebec6dSmrg#endif
235873143b9aSmrg    ret = close(ciptr->fd);
235973143b9aSmrg
236073143b9aSmrg    return ret;
236173143b9aSmrg}
236273143b9aSmrg
236373143b9aSmrg#endif /* UNIXCONN */
236473143b9aSmrg
236573143b9aSmrg
236673143b9aSmrg#ifdef TCPCONN
236773143b9aSmrg# ifdef TRANS_SERVER
2368fe567363Smrgstatic const char* tcp_nolisten[] = {
236973143b9aSmrg	"inet",
2370ac57ed83Smrg#ifdef IPv6
237173143b9aSmrg	"inet6",
237273143b9aSmrg#endif
237373143b9aSmrg	NULL
237473143b9aSmrg};
237573143b9aSmrg# endif
237673143b9aSmrg
2377ac57ed83Smrgstatic Xtransport	TRANS(SocketTCPFuncs) = {
237873143b9aSmrg	/* Socket Interface */
237973143b9aSmrg	"tcp",
238073143b9aSmrg        TRANS_ALIAS,
238173143b9aSmrg#ifdef TRANS_CLIENT
238273143b9aSmrg	TRANS(SocketOpenCOTSClient),
238373143b9aSmrg#endif /* TRANS_CLIENT */
238473143b9aSmrg#ifdef TRANS_SERVER
238573143b9aSmrg	tcp_nolisten,
238673143b9aSmrg	TRANS(SocketOpenCOTSServer),
238773143b9aSmrg#endif /* TRANS_SERVER */
238873143b9aSmrg#ifdef TRANS_REOPEN
238973143b9aSmrg	TRANS(SocketReopenCOTSServer),
239073143b9aSmrg#endif
239173143b9aSmrg	TRANS(SocketSetOption),
239273143b9aSmrg#ifdef TRANS_SERVER
239373143b9aSmrg	TRANS(SocketINETCreateListener),
239473143b9aSmrg	NULL,		       			/* ResetListener */
239573143b9aSmrg	TRANS(SocketINETAccept),
239673143b9aSmrg#endif /* TRANS_SERVER */
239773143b9aSmrg#ifdef TRANS_CLIENT
239873143b9aSmrg	TRANS(SocketINETConnect),
239973143b9aSmrg#endif /* TRANS_CLIENT */
240073143b9aSmrg	TRANS(SocketBytesReadable),
240173143b9aSmrg	TRANS(SocketRead),
240273143b9aSmrg	TRANS(SocketWrite),
240373143b9aSmrg	TRANS(SocketReadv),
240473143b9aSmrg	TRANS(SocketWritev),
240575ebec6dSmrg#if XTRANS_SEND_FDS
240675ebec6dSmrg        TRANS(SocketSendFdInvalid),
240775ebec6dSmrg        TRANS(SocketRecvFdInvalid),
240875ebec6dSmrg#endif
240973143b9aSmrg	TRANS(SocketDisconnect),
241073143b9aSmrg	TRANS(SocketINETClose),
241173143b9aSmrg	TRANS(SocketINETClose),
241273143b9aSmrg	};
241373143b9aSmrg
2414ac57ed83Smrgstatic Xtransport	TRANS(SocketINETFuncs) = {
241573143b9aSmrg	/* Socket Interface */
241673143b9aSmrg	"inet",
241773143b9aSmrg	0,
241873143b9aSmrg#ifdef TRANS_CLIENT
241973143b9aSmrg	TRANS(SocketOpenCOTSClient),
242073143b9aSmrg#endif /* TRANS_CLIENT */
242173143b9aSmrg#ifdef TRANS_SERVER
242273143b9aSmrg	NULL,
242373143b9aSmrg	TRANS(SocketOpenCOTSServer),
242473143b9aSmrg#endif /* TRANS_SERVER */
242573143b9aSmrg#ifdef TRANS_REOPEN
242673143b9aSmrg	TRANS(SocketReopenCOTSServer),
242773143b9aSmrg#endif
242873143b9aSmrg	TRANS(SocketSetOption),
242973143b9aSmrg#ifdef TRANS_SERVER
243073143b9aSmrg	TRANS(SocketINETCreateListener),
243173143b9aSmrg	NULL,		       			/* ResetListener */
243273143b9aSmrg	TRANS(SocketINETAccept),
243373143b9aSmrg#endif /* TRANS_SERVER */
243473143b9aSmrg#ifdef TRANS_CLIENT
243573143b9aSmrg	TRANS(SocketINETConnect),
243673143b9aSmrg#endif /* TRANS_CLIENT */
243773143b9aSmrg	TRANS(SocketBytesReadable),
243873143b9aSmrg	TRANS(SocketRead),
243973143b9aSmrg	TRANS(SocketWrite),
244073143b9aSmrg	TRANS(SocketReadv),
244173143b9aSmrg	TRANS(SocketWritev),
244275ebec6dSmrg#if XTRANS_SEND_FDS
244375ebec6dSmrg        TRANS(SocketSendFdInvalid),
244475ebec6dSmrg        TRANS(SocketRecvFdInvalid),
244575ebec6dSmrg#endif
244673143b9aSmrg	TRANS(SocketDisconnect),
244773143b9aSmrg	TRANS(SocketINETClose),
244873143b9aSmrg	TRANS(SocketINETClose),
244973143b9aSmrg	};
245073143b9aSmrg
2451ac57ed83Smrg#ifdef IPv6
2452ac57ed83Smrgstatic Xtransport     TRANS(SocketINET6Funcs) = {
245373143b9aSmrg	/* Socket Interface */
245473143b9aSmrg	"inet6",
245573143b9aSmrg	0,
245673143b9aSmrg#ifdef TRANS_CLIENT
245773143b9aSmrg	TRANS(SocketOpenCOTSClient),
245873143b9aSmrg#endif /* TRANS_CLIENT */
245973143b9aSmrg#ifdef TRANS_SERVER
246073143b9aSmrg	NULL,
246173143b9aSmrg	TRANS(SocketOpenCOTSServer),
246273143b9aSmrg#endif /* TRANS_SERVER */
246373143b9aSmrg#ifdef TRANS_REOPEN
246473143b9aSmrg	TRANS(SocketReopenCOTSServer),
246573143b9aSmrg#endif
246673143b9aSmrg	TRANS(SocketSetOption),
246773143b9aSmrg#ifdef TRANS_SERVER
246873143b9aSmrg	TRANS(SocketINETCreateListener),
246973143b9aSmrg	NULL,					/* ResetListener */
247073143b9aSmrg	TRANS(SocketINETAccept),
247173143b9aSmrg#endif /* TRANS_SERVER */
247273143b9aSmrg#ifdef TRANS_CLIENT
247373143b9aSmrg	TRANS(SocketINETConnect),
247473143b9aSmrg#endif /* TRANS_CLIENT */
247573143b9aSmrg	TRANS(SocketBytesReadable),
247673143b9aSmrg	TRANS(SocketRead),
247773143b9aSmrg	TRANS(SocketWrite),
247873143b9aSmrg	TRANS(SocketReadv),
247973143b9aSmrg	TRANS(SocketWritev),
248075ebec6dSmrg#if XTRANS_SEND_FDS
248175ebec6dSmrg        TRANS(SocketSendFdInvalid),
248275ebec6dSmrg        TRANS(SocketRecvFdInvalid),
248375ebec6dSmrg#endif
248473143b9aSmrg	TRANS(SocketDisconnect),
248573143b9aSmrg	TRANS(SocketINETClose),
248673143b9aSmrg	TRANS(SocketINETClose),
248773143b9aSmrg	};
248873143b9aSmrg#endif /* IPv6 */
248973143b9aSmrg#endif /* TCPCONN */
249073143b9aSmrg
249173143b9aSmrg#ifdef UNIXCONN
249273143b9aSmrg#if !defined(LOCALCONN)
2493ac57ed83Smrgstatic Xtransport	TRANS(SocketLocalFuncs) = {
249473143b9aSmrg	/* Socket Interface */
249573143b9aSmrg	"local",
249673143b9aSmrg#ifdef HAVE_ABSTRACT_SOCKETS
249773143b9aSmrg	TRANS_ABSTRACT,
249873143b9aSmrg#else
249973143b9aSmrg	0,
250073143b9aSmrg#endif
250173143b9aSmrg#ifdef TRANS_CLIENT
250273143b9aSmrg	TRANS(SocketOpenCOTSClient),
250373143b9aSmrg#endif /* TRANS_CLIENT */
250473143b9aSmrg#ifdef TRANS_SERVER
250573143b9aSmrg	NULL,
250673143b9aSmrg	TRANS(SocketOpenCOTSServer),
250773143b9aSmrg#endif /* TRANS_SERVER */
250873143b9aSmrg#ifdef TRANS_REOPEN
250973143b9aSmrg	TRANS(SocketReopenCOTSServer),
251073143b9aSmrg#endif
251173143b9aSmrg	TRANS(SocketSetOption),
251273143b9aSmrg#ifdef TRANS_SERVER
251373143b9aSmrg	TRANS(SocketUNIXCreateListener),
251473143b9aSmrg	TRANS(SocketUNIXResetListener),
251573143b9aSmrg	TRANS(SocketUNIXAccept),
251673143b9aSmrg#endif /* TRANS_SERVER */
251773143b9aSmrg#ifdef TRANS_CLIENT
251873143b9aSmrg	TRANS(SocketUNIXConnect),
251973143b9aSmrg#endif /* TRANS_CLIENT */
252073143b9aSmrg	TRANS(SocketBytesReadable),
252173143b9aSmrg	TRANS(SocketRead),
252273143b9aSmrg	TRANS(SocketWrite),
252373143b9aSmrg	TRANS(SocketReadv),
252473143b9aSmrg	TRANS(SocketWritev),
252575ebec6dSmrg#if XTRANS_SEND_FDS
252675ebec6dSmrg        TRANS(SocketSendFd),
252775ebec6dSmrg        TRANS(SocketRecvFd),
252875ebec6dSmrg#endif
252973143b9aSmrg	TRANS(SocketDisconnect),
253073143b9aSmrg	TRANS(SocketUNIXClose),
253173143b9aSmrg	TRANS(SocketUNIXCloseForCloning),
253273143b9aSmrg	};
253373143b9aSmrg#endif /* !LOCALCONN */
253473143b9aSmrg# ifdef TRANS_SERVER
253573143b9aSmrg#  if !defined(LOCALCONN)
253675ebec6dSmrgstatic const char* unix_nolisten[] = { "local" , NULL };
253773143b9aSmrg#  endif
253873143b9aSmrg# endif
2539fe567363Smrg
2540ac57ed83Smrgstatic Xtransport	TRANS(SocketUNIXFuncs) = {
254173143b9aSmrg	/* Socket Interface */
254273143b9aSmrg	"unix",
254373143b9aSmrg#if !defined(LOCALCONN) && !defined(HAVE_ABSTRACT_SOCKETS)
254473143b9aSmrg        TRANS_ALIAS,
254573143b9aSmrg#else
254673143b9aSmrg	0,
254773143b9aSmrg#endif
254873143b9aSmrg#ifdef TRANS_CLIENT
254973143b9aSmrg	TRANS(SocketOpenCOTSClient),
255073143b9aSmrg#endif /* TRANS_CLIENT */
255173143b9aSmrg#ifdef TRANS_SERVER
255273143b9aSmrg#if !defined(LOCALCONN)
255373143b9aSmrg	unix_nolisten,
255473143b9aSmrg#else
255573143b9aSmrg	NULL,
255673143b9aSmrg#endif
255773143b9aSmrg	TRANS(SocketOpenCOTSServer),
255873143b9aSmrg#endif /* TRANS_SERVER */
255973143b9aSmrg#ifdef TRANS_REOPEN
256073143b9aSmrg	TRANS(SocketReopenCOTSServer),
256173143b9aSmrg#endif
256273143b9aSmrg	TRANS(SocketSetOption),
256373143b9aSmrg#ifdef TRANS_SERVER
256473143b9aSmrg	TRANS(SocketUNIXCreateListener),
256573143b9aSmrg	TRANS(SocketUNIXResetListener),
256673143b9aSmrg	TRANS(SocketUNIXAccept),
256773143b9aSmrg#endif /* TRANS_SERVER */
256873143b9aSmrg#ifdef TRANS_CLIENT
256973143b9aSmrg	TRANS(SocketUNIXConnect),
257073143b9aSmrg#endif /* TRANS_CLIENT */
257173143b9aSmrg	TRANS(SocketBytesReadable),
257273143b9aSmrg	TRANS(SocketRead),
257373143b9aSmrg	TRANS(SocketWrite),
257473143b9aSmrg	TRANS(SocketReadv),
257573143b9aSmrg	TRANS(SocketWritev),
257675ebec6dSmrg#if XTRANS_SEND_FDS
257775ebec6dSmrg        TRANS(SocketSendFd),
257875ebec6dSmrg        TRANS(SocketRecvFd),
257975ebec6dSmrg#endif
258073143b9aSmrg	TRANS(SocketDisconnect),
258173143b9aSmrg	TRANS(SocketUNIXClose),
258273143b9aSmrg	TRANS(SocketUNIXCloseForCloning),
258373143b9aSmrg	};
258473143b9aSmrg
258573143b9aSmrg#endif /* UNIXCONN */
2586