Xtranssock.c revision 7448d6e9
1af928962Smrg/*
2af928962Smrg * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
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
14473143b9aSmrg#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
15873143b9aSmrg/*
15973143b9aSmrg * This is the Socket implementation of the X Transport service layer
16073143b9aSmrg *
16173143b9aSmrg * This file contains the implementation for both the UNIX and INET domains,
16273143b9aSmrg * and can be built for either one, or both.
16373143b9aSmrg *
16473143b9aSmrg */
16573143b9aSmrg
166fe567363Smrgtypedef struct _Sockettrans2dev {
167fe567363Smrg    const char	*transname;
16873143b9aSmrg    int		family;
16973143b9aSmrg    int		devcotsname;
17073143b9aSmrg    int		devcltsname;
17173143b9aSmrg    int		protocol;
17273143b9aSmrg} Sockettrans2dev;
17373143b9aSmrg
17473143b9aSmrgstatic Sockettrans2dev Sockettrans2devtab[] = {
17573143b9aSmrg#ifdef TCPCONN
17673143b9aSmrg    {"inet",AF_INET,SOCK_STREAM,SOCK_DGRAM,0},
17773143b9aSmrg#if !defined(IPv6) || !defined(AF_INET6)
17873143b9aSmrg    {"tcp",AF_INET,SOCK_STREAM,SOCK_DGRAM,0},
17973143b9aSmrg#else /* IPv6 */
18073143b9aSmrg    {"tcp",AF_INET6,SOCK_STREAM,SOCK_DGRAM,0},
18173143b9aSmrg    {"tcp",AF_INET,SOCK_STREAM,SOCK_DGRAM,0}, /* fallback */
18273143b9aSmrg    {"inet6",AF_INET6,SOCK_STREAM,SOCK_DGRAM,0},
18373143b9aSmrg#endif
18473143b9aSmrg#endif /* TCPCONN */
18573143b9aSmrg#ifdef UNIXCONN
18673143b9aSmrg    {"unix",AF_UNIX,SOCK_STREAM,SOCK_DGRAM,0},
18773143b9aSmrg#if !defined(LOCALCONN)
18873143b9aSmrg    {"local",AF_UNIX,SOCK_STREAM,SOCK_DGRAM,0},
18973143b9aSmrg#endif /* !LOCALCONN */
19073143b9aSmrg#endif /* UNIXCONN */
19173143b9aSmrg};
19273143b9aSmrg
19373143b9aSmrg#define NUMSOCKETFAMILIES (sizeof(Sockettrans2devtab)/sizeof(Sockettrans2dev))
19473143b9aSmrg
19573143b9aSmrg#ifdef TCPCONN
19673143b9aSmrgstatic int TRANS(SocketINETClose) (XtransConnInfo ciptr);
19773143b9aSmrg#endif
19873143b9aSmrg
19973143b9aSmrg#ifdef UNIXCONN
20073143b9aSmrg
20173143b9aSmrg
20273143b9aSmrg#if defined(X11_t)
20373143b9aSmrg#define UNIX_PATH "/tmp/.X11-unix/X"
20473143b9aSmrg#define UNIX_DIR "/tmp/.X11-unix"
20573143b9aSmrg#endif /* X11_t */
20673143b9aSmrg#if defined(XIM_t)
20773143b9aSmrg#define UNIX_PATH "/tmp/.XIM-unix/XIM"
20873143b9aSmrg#define UNIX_DIR "/tmp/.XIM-unix"
20973143b9aSmrg#endif /* XIM_t */
21073143b9aSmrg#if defined(FS_t) || defined(FONT_t)
21173143b9aSmrg#define UNIX_PATH "/tmp/.font-unix/fs"
21273143b9aSmrg#define UNIX_DIR "/tmp/.font-unix"
21373143b9aSmrg#endif /* FS_t || FONT_t */
21473143b9aSmrg#if defined(ICE_t)
21573143b9aSmrg#define UNIX_PATH "/tmp/.ICE-unix/"
21673143b9aSmrg#define UNIX_DIR "/tmp/.ICE-unix"
21773143b9aSmrg#endif /* ICE_t */
21873143b9aSmrg
21973143b9aSmrg
22073143b9aSmrg#endif /* UNIXCONN */
22173143b9aSmrg
22273143b9aSmrg#define PORTBUFSIZE	32
22373143b9aSmrg
22473143b9aSmrg#ifndef MAXHOSTNAMELEN
22573143b9aSmrg#define MAXHOSTNAMELEN 255
22673143b9aSmrg#endif
22773143b9aSmrg
22873143b9aSmrg#if defined HAVE_SOCKLEN_T || (defined(IPv6) && defined(AF_INET6))
22973143b9aSmrg# define SOCKLEN_T socklen_t
230e8a71cdfSmrg#elif defined(SVR4) || defined(__SVR4) || defined(__SCO__)
231fe567363Smrg# define SOCKLEN_T size_t
23273143b9aSmrg#else
23373143b9aSmrg# define SOCKLEN_T int
23473143b9aSmrg#endif
23573143b9aSmrg
23673143b9aSmrg/*
23773143b9aSmrg * These are some utility function used by the real interface function below.
23873143b9aSmrg */
23973143b9aSmrg
24073143b9aSmrgstatic int
241fe567363SmrgTRANS(SocketSelectFamily) (int first, const char *family)
24273143b9aSmrg
24373143b9aSmrg{
24473143b9aSmrg    int     i;
24573143b9aSmrg
246fe567363Smrg    prmsg (3,"SocketSelectFamily(%s)\n", family);
24773143b9aSmrg
24873143b9aSmrg    for (i = first + 1; i < NUMSOCKETFAMILIES;i++)
24973143b9aSmrg    {
25073143b9aSmrg        if (!strcmp (family, Sockettrans2devtab[i].transname))
25173143b9aSmrg	    return i;
25273143b9aSmrg    }
25373143b9aSmrg
25473143b9aSmrg    return (first == -1 ? -2 : -1);
25573143b9aSmrg}
25673143b9aSmrg
25773143b9aSmrg
25873143b9aSmrg/*
25973143b9aSmrg * This function gets the local address of the socket and stores it in the
26073143b9aSmrg * XtransConnInfo structure for the connection.
26173143b9aSmrg */
26273143b9aSmrg
26373143b9aSmrgstatic int
26473143b9aSmrgTRANS(SocketINETGetAddr) (XtransConnInfo ciptr)
26573143b9aSmrg
26673143b9aSmrg{
26773143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
26873143b9aSmrg    struct sockaddr_storage socknamev6;
269b53e5eeaSmrg#else
27073143b9aSmrg    struct sockaddr_in socknamev4;
271b53e5eeaSmrg#endif
27273143b9aSmrg    void *socknamePtr;
27373143b9aSmrg    SOCKLEN_T namelen;
27473143b9aSmrg
275fe567363Smrg    prmsg (3,"SocketINETGetAddr(%p)\n", ciptr);
27673143b9aSmrg
27773143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
278b53e5eeaSmrg    namelen = sizeof(socknamev6);
279b53e5eeaSmrg    socknamePtr = &socknamev6;
280b53e5eeaSmrg#else
281b53e5eeaSmrg    namelen = sizeof(socknamev4);
282b53e5eeaSmrg    socknamePtr = &socknamev4;
28373143b9aSmrg#endif
28473143b9aSmrg
28573143b9aSmrg    bzero(socknamePtr, namelen);
286fe567363Smrg
28773143b9aSmrg    if (getsockname (ciptr->fd,(struct sockaddr *) socknamePtr,
28873143b9aSmrg		     (void *)&namelen) < 0)
28973143b9aSmrg    {
29073143b9aSmrg#ifdef WIN32
29173143b9aSmrg	errno = WSAGetLastError();
29273143b9aSmrg#endif
293fe567363Smrg	prmsg (1,"SocketINETGetAddr: getsockname() failed: %d\n",
294fe567363Smrg	    EGET());
29573143b9aSmrg	return -1;
29673143b9aSmrg    }
29773143b9aSmrg
29873143b9aSmrg    /*
29973143b9aSmrg     * Everything looks good: fill in the XtransConnInfo structure.
30073143b9aSmrg     */
30173143b9aSmrg
302fe567363Smrg    if ((ciptr->addr = malloc (namelen)) == NULL)
30373143b9aSmrg    {
304fe567363Smrg        prmsg (1,
305fe567363Smrg	    "SocketINETGetAddr: Can't allocate space for the addr\n");
30673143b9aSmrg        return -1;
30773143b9aSmrg    }
30873143b9aSmrg
30973143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
310b53e5eeaSmrg    ciptr->family = ((struct sockaddr *)socknamePtr)->sa_family;
311b53e5eeaSmrg#else
312b53e5eeaSmrg    ciptr->family = socknamev4.sin_family;
31373143b9aSmrg#endif
31473143b9aSmrg    ciptr->addrlen = namelen;
31573143b9aSmrg    memcpy (ciptr->addr, socknamePtr, ciptr->addrlen);
31673143b9aSmrg
31773143b9aSmrg    return 0;
31873143b9aSmrg}
31973143b9aSmrg
32073143b9aSmrg
32173143b9aSmrg/*
32273143b9aSmrg * This function gets the remote address of the socket and stores it in the
32373143b9aSmrg * XtransConnInfo structure for the connection.
32473143b9aSmrg */
32573143b9aSmrg
32673143b9aSmrgstatic int
32773143b9aSmrgTRANS(SocketINETGetPeerAddr) (XtransConnInfo ciptr)
32873143b9aSmrg
32973143b9aSmrg{
33073143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
33173143b9aSmrg    struct sockaddr_storage socknamev6;
33273143b9aSmrg#endif
33373143b9aSmrg    struct sockaddr_in 	socknamev4;
33473143b9aSmrg    void *socknamePtr;
33573143b9aSmrg    SOCKLEN_T namelen;
33673143b9aSmrg
33773143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
338b53e5eeaSmrg    if (ciptr->family == AF_INET6)
33973143b9aSmrg    {
34073143b9aSmrg	namelen = sizeof(socknamev6);
34173143b9aSmrg	socknamePtr = &socknamev6;
34273143b9aSmrg    }
34373143b9aSmrg    else
34473143b9aSmrg#endif
34573143b9aSmrg    {
34673143b9aSmrg	namelen = sizeof(socknamev4);
34773143b9aSmrg	socknamePtr = &socknamev4;
34873143b9aSmrg    }
34973143b9aSmrg
35073143b9aSmrg    bzero(socknamePtr, namelen);
351fe567363Smrg
352fe567363Smrg    prmsg (3,"SocketINETGetPeerAddr(%p)\n", ciptr);
35373143b9aSmrg
35473143b9aSmrg    if (getpeername (ciptr->fd, (struct sockaddr *) socknamePtr,
35573143b9aSmrg		     (void *)&namelen) < 0)
35673143b9aSmrg    {
35773143b9aSmrg#ifdef WIN32
35873143b9aSmrg	errno = WSAGetLastError();
35973143b9aSmrg#endif
360fe567363Smrg	prmsg (1,"SocketINETGetPeerAddr: getpeername() failed: %d\n",
361fe567363Smrg	    EGET());
36273143b9aSmrg	return -1;
36373143b9aSmrg    }
36473143b9aSmrg
36573143b9aSmrg    /*
36673143b9aSmrg     * Everything looks good: fill in the XtransConnInfo structure.
36773143b9aSmrg     */
36873143b9aSmrg
369fe567363Smrg    if ((ciptr->peeraddr = malloc (namelen)) == NULL)
37073143b9aSmrg    {
371fe567363Smrg        prmsg (1,
372fe567363Smrg	   "SocketINETGetPeerAddr: Can't allocate space for the addr\n");
37373143b9aSmrg        return -1;
37473143b9aSmrg    }
37573143b9aSmrg
37673143b9aSmrg    ciptr->peeraddrlen = namelen;
37773143b9aSmrg    memcpy (ciptr->peeraddr, socknamePtr, ciptr->peeraddrlen);
37873143b9aSmrg
37973143b9aSmrg    return 0;
38073143b9aSmrg}
38173143b9aSmrg
38273143b9aSmrg
38373143b9aSmrgstatic XtransConnInfo
38473143b9aSmrgTRANS(SocketOpen) (int i, int type)
38573143b9aSmrg
38673143b9aSmrg{
38773143b9aSmrg    XtransConnInfo	ciptr;
38873143b9aSmrg
389fe567363Smrg    prmsg (3,"SocketOpen(%d,%d)\n", i, type);
39073143b9aSmrg
391fe567363Smrg    if ((ciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
39273143b9aSmrg    {
393fe567363Smrg	prmsg (1, "SocketOpen: malloc failed\n");
39473143b9aSmrg	return NULL;
39573143b9aSmrg    }
39673143b9aSmrg
39773143b9aSmrg    if ((ciptr->fd = socket(Sockettrans2devtab[i].family, type,
39873143b9aSmrg	Sockettrans2devtab[i].protocol)) < 0
39973143b9aSmrg#ifndef WIN32
40073143b9aSmrg#if (defined(X11_t) && !defined(USE_POLL)) || defined(FS_t) || defined(FONT_t)
4018d4c0f7bSmrg       || ciptr->fd >= sysconf(_SC_OPEN_MAX)
40273143b9aSmrg#endif
40373143b9aSmrg#endif
40473143b9aSmrg      ) {
40573143b9aSmrg#ifdef WIN32
40673143b9aSmrg	errno = WSAGetLastError();
40773143b9aSmrg#endif
408fe567363Smrg	prmsg (2, "SocketOpen: socket() failed for %s\n",
409fe567363Smrg	    Sockettrans2devtab[i].transname);
41073143b9aSmrg
411fe567363Smrg	free (ciptr);
41273143b9aSmrg	return NULL;
41373143b9aSmrg    }
41473143b9aSmrg
41573143b9aSmrg#ifdef TCP_NODELAY
41673143b9aSmrg    if (Sockettrans2devtab[i].family == AF_INET
41773143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
41873143b9aSmrg      || Sockettrans2devtab[i].family == AF_INET6
41973143b9aSmrg#endif
42073143b9aSmrg    )
42173143b9aSmrg    {
42273143b9aSmrg	/*
42373143b9aSmrg	 * turn off TCP coalescence for INET sockets
42473143b9aSmrg	 */
42573143b9aSmrg
42673143b9aSmrg	int tmp = 1;
42773143b9aSmrg	setsockopt (ciptr->fd, IPPROTO_TCP, TCP_NODELAY,
42873143b9aSmrg	    (char *) &tmp, sizeof (int));
42973143b9aSmrg    }
43073143b9aSmrg#endif
43173143b9aSmrg
4328a0d9095Smrg    /*
4338a0d9095Smrg     * Some systems provide a really small default buffer size for
4348a0d9095Smrg     * UNIX sockets.  Bump it up a bit such that large transfers don't
4358a0d9095Smrg     * proceed at glacial speed.
4368a0d9095Smrg     */
4378a0d9095Smrg#ifdef SO_SNDBUF
4388a0d9095Smrg    if (Sockettrans2devtab[i].family == AF_UNIX)
4398a0d9095Smrg    {
4408a0d9095Smrg	SOCKLEN_T len = sizeof (int);
4418a0d9095Smrg	int val;
4428a0d9095Smrg
4438a0d9095Smrg	if (getsockopt (ciptr->fd, SOL_SOCKET, SO_SNDBUF,
4448a0d9095Smrg	    (char *) &val, &len) == 0 && val < 64 * 1024)
4458a0d9095Smrg	{
4468a0d9095Smrg	    val = 64 * 1024;
4478a0d9095Smrg	    setsockopt (ciptr->fd, SOL_SOCKET, SO_SNDBUF,
4488a0d9095Smrg	        (char *) &val, sizeof (int));
4498a0d9095Smrg	}
4508a0d9095Smrg    }
4518a0d9095Smrg#endif
4528a0d9095Smrg
45373143b9aSmrg    return ciptr;
45473143b9aSmrg}
45573143b9aSmrg
45673143b9aSmrg
45773143b9aSmrg#ifdef TRANS_REOPEN
45873143b9aSmrg
45973143b9aSmrgstatic XtransConnInfo
4606a3641a6SsnjTRANS(SocketReopen) (int i _X_UNUSED, int type, int fd, const char *port)
46173143b9aSmrg
46273143b9aSmrg{
46373143b9aSmrg    XtransConnInfo	ciptr;
46473143b9aSmrg    int portlen;
46573143b9aSmrg    struct sockaddr *addr;
466fe567363Smrg    size_t addrlen;
46773143b9aSmrg
468fe567363Smrg    prmsg (3,"SocketReopen(%d,%d,%s)\n", type, fd, port);
46973143b9aSmrg
47073143b9aSmrg    if (port == NULL) {
471fe567363Smrg      prmsg (1, "SocketReopen: port was null!\n");
47273143b9aSmrg      return NULL;
47373143b9aSmrg    }
47473143b9aSmrg
47573143b9aSmrg    portlen = strlen(port) + 1; // include space for trailing null
47673143b9aSmrg#ifdef SOCK_MAXADDRLEN
47773143b9aSmrg    if (portlen < 0 || portlen > (SOCK_MAXADDRLEN + 2)) {
478fe567363Smrg      prmsg (1, "SocketReopen: invalid portlen %d\n", portlen);
47973143b9aSmrg      return NULL;
48073143b9aSmrg    }
48173143b9aSmrg    if (portlen < 14) portlen = 14;
48273143b9aSmrg#else
48373143b9aSmrg    if (portlen < 0 || portlen > 14) {
484fe567363Smrg      prmsg (1, "SocketReopen: invalid portlen %d\n", portlen);
48573143b9aSmrg      return NULL;
48673143b9aSmrg    }
48773143b9aSmrg#endif /*SOCK_MAXADDRLEN*/
48873143b9aSmrg
489fe567363Smrg    if ((ciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
49073143b9aSmrg    {
491fe567363Smrg	prmsg (1, "SocketReopen: malloc(ciptr) failed\n");
49273143b9aSmrg	return NULL;
49373143b9aSmrg    }
49473143b9aSmrg
49573143b9aSmrg    ciptr->fd = fd;
49673143b9aSmrg
497fe567363Smrg    addrlen = portlen + offsetof(struct sockaddr, sa_data);
498fe567363Smrg    if ((addr = calloc (1, addrlen)) == NULL) {
499fe567363Smrg	prmsg (1, "SocketReopen: malloc(addr) failed\n");
500fe567363Smrg	free (ciptr);
50173143b9aSmrg	return NULL;
50273143b9aSmrg    }
5038d4c0f7bSmrg    ciptr->addr = (char *) addr;
504fe567363Smrg    ciptr->addrlen = addrlen;
50573143b9aSmrg
506fe567363Smrg    if ((ciptr->peeraddr = calloc (1, addrlen)) == NULL) {
507fe567363Smrg	prmsg (1, "SocketReopen: malloc(portaddr) failed\n");
508fe567363Smrg	free (addr);
509fe567363Smrg	free (ciptr);
51073143b9aSmrg	return NULL;
51173143b9aSmrg    }
512fe567363Smrg    ciptr->peeraddrlen = addrlen;
51373143b9aSmrg
51473143b9aSmrg    /* Initialize ciptr structure as if it were a normally-opened unix socket */
51573143b9aSmrg    ciptr->flags = TRANS_LOCAL | TRANS_NOUNLINK;
51673143b9aSmrg#ifdef BSD44SOCKETS
517fe567363Smrg    addr->sa_len = addrlen;
51873143b9aSmrg#endif
51973143b9aSmrg    addr->sa_family = AF_UNIX;
5207448d6e9Smrg#if defined(HAVE_STRLCPY) || defined(HAS_STRLCPY)
52173143b9aSmrg    strlcpy(addr->sa_data, port, portlen);
52273143b9aSmrg#else
52373143b9aSmrg    strncpy(addr->sa_data, port, portlen);
52473143b9aSmrg#endif
52573143b9aSmrg    ciptr->family = AF_UNIX;
526fe567363Smrg    memcpy(ciptr->peeraddr, ciptr->addr, addrlen);
52773143b9aSmrg    ciptr->port = rindex(addr->sa_data, ':');
528e8a71cdfSmrg    if (ciptr->port == NULL) {
529e8a71cdfSmrg	if (is_numeric(addr->sa_data)) {
530e8a71cdfSmrg	    ciptr->port = addr->sa_data;
531e8a71cdfSmrg	}
532e8a71cdfSmrg    } else if (ciptr->port[0] == ':') {
533e8a71cdfSmrg	ciptr->port++;
534e8a71cdfSmrg    }
535e8a71cdfSmrg    /* port should now point to portnum or NULL */
53673143b9aSmrg    return ciptr;
53773143b9aSmrg}
53873143b9aSmrg
53973143b9aSmrg#endif /* TRANS_REOPEN */
54073143b9aSmrg
54173143b9aSmrg
54273143b9aSmrg/*
54373143b9aSmrg * These functions are the interface supplied in the Xtransport structure
54473143b9aSmrg */
54573143b9aSmrg
54673143b9aSmrg#ifdef TRANS_CLIENT
54773143b9aSmrg
54873143b9aSmrgstatic XtransConnInfo
549fe567363SmrgTRANS(SocketOpenCOTSClientBase) (const char *transname, const char *protocol,
550fe567363Smrg			   const char *host, const char *port, int previndex)
55173143b9aSmrg{
55273143b9aSmrg    XtransConnInfo	ciptr;
55373143b9aSmrg    int			i = previndex;
55473143b9aSmrg
555fe567363Smrg    prmsg (2, "SocketOpenCOTSClient(%s,%s,%s)\n",
55673143b9aSmrg	protocol, host, port);
55773143b9aSmrg
55873143b9aSmrg    SocketInitOnce();
55973143b9aSmrg
56073143b9aSmrg    while ((i = TRANS(SocketSelectFamily) (i, transname)) >= 0) {
56173143b9aSmrg	if ((ciptr = TRANS(SocketOpen) (
562e8a71cdfSmrg		i, Sockettrans2devtab[i].devcotsname)) != NULL) {
563e8a71cdfSmrg	    /* Save the index for later use */
564e8a71cdfSmrg
565e8a71cdfSmrg	    ciptr->index = i;
56673143b9aSmrg	    break;
567e8a71cdfSmrg	}
56873143b9aSmrg    }
56973143b9aSmrg    if (i < 0) {
57073143b9aSmrg	if (i == -1)
571fe567363Smrg	    prmsg (1,"SocketOpenCOTSClient: Unable to open socket for %s\n",
572fe567363Smrg		   transname);
57373143b9aSmrg	else
574fe567363Smrg	    prmsg (1,"SocketOpenCOTSClient: Unable to determine socket type for %s\n",
575fe567363Smrg		   transname);
57673143b9aSmrg	return NULL;
57773143b9aSmrg    }
57873143b9aSmrg
57973143b9aSmrg    return ciptr;
58073143b9aSmrg}
58173143b9aSmrg
58273143b9aSmrgstatic XtransConnInfo
5836a3641a6SsnjTRANS(SocketOpenCOTSClient) (Xtransport *thistrans, const char *protocol,
5846a3641a6Ssnj			     const char *host, const char *port)
58573143b9aSmrg{
58673143b9aSmrg    return TRANS(SocketOpenCOTSClientBase)(
58773143b9aSmrg			thistrans->TransName, protocol, host, port, -1);
58873143b9aSmrg}
58973143b9aSmrg
59073143b9aSmrg
59173143b9aSmrg#endif /* TRANS_CLIENT */
59273143b9aSmrg
59373143b9aSmrg
59473143b9aSmrg#ifdef TRANS_SERVER
59573143b9aSmrg
59673143b9aSmrgstatic XtransConnInfo
5976a3641a6SsnjTRANS(SocketOpenCOTSServer) (Xtransport *thistrans, const char *protocol,
5986a3641a6Ssnj			     const char *host, const char *port)
59973143b9aSmrg
60073143b9aSmrg{
60173143b9aSmrg    XtransConnInfo	ciptr;
60273143b9aSmrg    int	i = -1;
60373143b9aSmrg
604fe567363Smrg    prmsg (2,"SocketOpenCOTSServer(%s,%s,%s)\n", protocol, host, port);
60573143b9aSmrg
60673143b9aSmrg    SocketInitOnce();
60773143b9aSmrg
60873143b9aSmrg    while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
60973143b9aSmrg	if ((ciptr = TRANS(SocketOpen) (
61073143b9aSmrg		 i, Sockettrans2devtab[i].devcotsname)) != NULL)
61173143b9aSmrg	    break;
61273143b9aSmrg    }
61373143b9aSmrg    if (i < 0) {
61473143b9aSmrg	if (i == -1)
615fe567363Smrg	    prmsg (1,"SocketOpenCOTSServer: Unable to open socket for %s\n",
616fe567363Smrg		   thistrans->TransName);
61773143b9aSmrg	else
618fe567363Smrg	    prmsg (1,"SocketOpenCOTSServer: Unable to determine socket type for %s\n",
619fe567363Smrg		   thistrans->TransName);
62073143b9aSmrg	return NULL;
62173143b9aSmrg    }
62273143b9aSmrg
62373143b9aSmrg    /*
62473143b9aSmrg     * Using this prevents the bind() check for an existing server listening
62573143b9aSmrg     * on the same port, but it is required for other reasons.
62673143b9aSmrg     */
62773143b9aSmrg#ifdef SO_REUSEADDR
62873143b9aSmrg
62973143b9aSmrg    /*
63073143b9aSmrg     * SO_REUSEADDR only applied to AF_INET && AF_INET6
63173143b9aSmrg     */
63273143b9aSmrg
63373143b9aSmrg    if (Sockettrans2devtab[i].family == AF_INET
63473143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
63573143b9aSmrg      || Sockettrans2devtab[i].family == AF_INET6
63673143b9aSmrg#endif
63773143b9aSmrg    )
63873143b9aSmrg    {
63973143b9aSmrg	int one = 1;
64073143b9aSmrg	setsockopt (ciptr->fd, SOL_SOCKET, SO_REUSEADDR,
64173143b9aSmrg		    (char *) &one, sizeof (int));
64273143b9aSmrg    }
64373143b9aSmrg#endif
64473143b9aSmrg#ifdef IPV6_V6ONLY
64573143b9aSmrg    if (Sockettrans2devtab[i].family == AF_INET6)
64673143b9aSmrg    {
64773143b9aSmrg	int one = 1;
64873143b9aSmrg	setsockopt(ciptr->fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(int));
64973143b9aSmrg    }
65073143b9aSmrg#endif
65173143b9aSmrg    /* Save the index for later use */
65273143b9aSmrg
65373143b9aSmrg    ciptr->index = i;
65473143b9aSmrg
65573143b9aSmrg    return ciptr;
65673143b9aSmrg}
65773143b9aSmrg
65873143b9aSmrg#endif /* TRANS_SERVER */
65973143b9aSmrg
66073143b9aSmrg
66173143b9aSmrg#ifdef TRANS_REOPEN
66273143b9aSmrg
66373143b9aSmrgstatic XtransConnInfo
6646a3641a6SsnjTRANS(SocketReopenCOTSServer) (Xtransport *thistrans, int fd, const char *port)
66573143b9aSmrg
66673143b9aSmrg{
66773143b9aSmrg    XtransConnInfo	ciptr;
66873143b9aSmrg    int			i = -1;
66973143b9aSmrg
670fe567363Smrg    prmsg (2,
671fe567363Smrg	"SocketReopenCOTSServer(%d, %s)\n", fd, port);
67273143b9aSmrg
67373143b9aSmrg    SocketInitOnce();
67473143b9aSmrg
67573143b9aSmrg    while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
67673143b9aSmrg	if ((ciptr = TRANS(SocketReopen) (
67773143b9aSmrg		 i, Sockettrans2devtab[i].devcotsname, fd, port)) != NULL)
67873143b9aSmrg	    break;
67973143b9aSmrg    }
68073143b9aSmrg    if (i < 0) {
68173143b9aSmrg	if (i == -1)
682fe567363Smrg	    prmsg (1,"SocketReopenCOTSServer: Unable to open socket for %s\n",
683fe567363Smrg		   thistrans->TransName);
68473143b9aSmrg	else
685fe567363Smrg	    prmsg (1,"SocketReopenCOTSServer: Unable to determine socket type for %s\n",
686fe567363Smrg		   thistrans->TransName);
68773143b9aSmrg	return NULL;
68873143b9aSmrg    }
68973143b9aSmrg
69073143b9aSmrg    /* Save the index for later use */
69173143b9aSmrg
69273143b9aSmrg    ciptr->index = i;
69373143b9aSmrg
69473143b9aSmrg    return ciptr;
69573143b9aSmrg}
69673143b9aSmrg
69773143b9aSmrg#endif /* TRANS_REOPEN */
69873143b9aSmrg
69973143b9aSmrg
70073143b9aSmrgstatic int
70173143b9aSmrgTRANS(SocketSetOption) (XtransConnInfo ciptr, int option, int arg)
70273143b9aSmrg
70373143b9aSmrg{
704fe567363Smrg    prmsg (2,"SocketSetOption(%d,%d,%d)\n", ciptr->fd, option, arg);
70573143b9aSmrg
70673143b9aSmrg    return -1;
70773143b9aSmrg}
70873143b9aSmrg
70973143b9aSmrg#ifdef UNIXCONN
71073143b9aSmrgstatic int
71173143b9aSmrgset_sun_path(const char *port, const char *upath, char *path, int abstract)
71273143b9aSmrg{
71373143b9aSmrg    struct sockaddr_un s;
71473143b9aSmrg    int maxlen = sizeof(s.sun_path) - 1;
71573143b9aSmrg    const char *at = "";
71673143b9aSmrg
71773143b9aSmrg    if (!port || !*port || !path)
71873143b9aSmrg	return -1;
71973143b9aSmrg
72073143b9aSmrg#ifdef HAVE_ABSTRACT_SOCKETS
72173143b9aSmrg    if (port[0] == '@')
72273143b9aSmrg	upath = "";
72373143b9aSmrg    else if (abstract)
72473143b9aSmrg	at = "@";
72573143b9aSmrg#endif
72673143b9aSmrg
72773143b9aSmrg    if (*port == '/') /* a full pathname */
72873143b9aSmrg	upath = "";
72973143b9aSmrg
73073143b9aSmrg    if (strlen(port) + strlen(upath) > maxlen)
73173143b9aSmrg	return -1;
732fe567363Smrg    snprintf(path, sizeof(s.sun_path), "%s%s%s", at, upath, port);
73373143b9aSmrg    return 0;
73473143b9aSmrg}
73573143b9aSmrg#endif
73673143b9aSmrg
73773143b9aSmrg#ifdef TRANS_SERVER
73873143b9aSmrg
73973143b9aSmrgstatic int
740fe567363SmrgTRANS(SocketCreateListener) (XtransConnInfo ciptr,
74173143b9aSmrg			     struct sockaddr *sockname,
74273143b9aSmrg			     int socknamelen, unsigned int flags)
74373143b9aSmrg
74473143b9aSmrg{
74573143b9aSmrg    SOCKLEN_T namelen = socknamelen;
74673143b9aSmrg    int	fd = ciptr->fd;
74773143b9aSmrg    int	retry;
74873143b9aSmrg
749fe567363Smrg    prmsg (3, "SocketCreateListener(%p,%d)\n", ciptr, fd);
75073143b9aSmrg
75173143b9aSmrg    if (Sockettrans2devtab[ciptr->index].family == AF_INET
75273143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
75373143b9aSmrg      || Sockettrans2devtab[ciptr->index].family == AF_INET6
75473143b9aSmrg#endif
75573143b9aSmrg	)
75673143b9aSmrg	retry = 20;
75773143b9aSmrg    else
75873143b9aSmrg	retry = 0;
75973143b9aSmrg
76073143b9aSmrg    while (bind (fd, (struct sockaddr *) sockname, namelen) < 0)
76173143b9aSmrg    {
76273143b9aSmrg	if (errno == EADDRINUSE) {
76373143b9aSmrg	    if (flags & ADDR_IN_USE_ALLOWED)
76473143b9aSmrg		break;
76573143b9aSmrg	    else
76673143b9aSmrg		return TRANS_ADDR_IN_USE;
76773143b9aSmrg	}
768fe567363Smrg
76973143b9aSmrg	if (retry-- == 0) {
770fe567363Smrg	    prmsg (1, "SocketCreateListener: failed to bind listener\n");
77173143b9aSmrg	    close (fd);
77273143b9aSmrg	    return TRANS_CREATE_LISTENER_FAILED;
77373143b9aSmrg	}
77473143b9aSmrg#ifdef SO_REUSEADDR
77573143b9aSmrg	sleep (1);
77673143b9aSmrg#else
77773143b9aSmrg	sleep (10);
77873143b9aSmrg#endif /* SO_REUSEDADDR */
77973143b9aSmrg    }
78073143b9aSmrg
78173143b9aSmrg    if (Sockettrans2devtab[ciptr->index].family == AF_INET
78273143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
78373143b9aSmrg      || Sockettrans2devtab[ciptr->index].family == AF_INET6
78473143b9aSmrg#endif
78573143b9aSmrg	) {
78673143b9aSmrg#ifdef SO_DONTLINGER
78773143b9aSmrg	setsockopt (fd, SOL_SOCKET, SO_DONTLINGER, (char *) NULL, 0);
78873143b9aSmrg#else
78973143b9aSmrg#ifdef SO_LINGER
79073143b9aSmrg    {
79173143b9aSmrg	static int linger[2] = { 0, 0 };
79273143b9aSmrg	setsockopt (fd, SOL_SOCKET, SO_LINGER,
79373143b9aSmrg		(char *) linger, sizeof (linger));
79473143b9aSmrg    }
79573143b9aSmrg#endif
79673143b9aSmrg#endif
79773143b9aSmrg}
79873143b9aSmrg
79973143b9aSmrg    if (listen (fd, BACKLOG) < 0)
80073143b9aSmrg    {
801fe567363Smrg	prmsg (1, "SocketCreateListener: listen() failed\n");
80273143b9aSmrg	close (fd);
80373143b9aSmrg	return TRANS_CREATE_LISTENER_FAILED;
80473143b9aSmrg    }
805fe567363Smrg
80673143b9aSmrg    /* Set a flag to indicate that this connection is a listener */
80773143b9aSmrg
80873143b9aSmrg    ciptr->flags = 1 | (ciptr->flags & TRANS_KEEPFLAGS);
80973143b9aSmrg
81073143b9aSmrg    return 0;
81173143b9aSmrg}
81273143b9aSmrg
81373143b9aSmrg#ifdef TCPCONN
81473143b9aSmrgstatic int
8156a3641a6SsnjTRANS(SocketINETCreateListener) (XtransConnInfo ciptr, const char *port,
8166a3641a6Ssnj                                 unsigned int flags)
81773143b9aSmrg
81873143b9aSmrg{
81973143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
82073143b9aSmrg    struct sockaddr_storage sockname;
82173143b9aSmrg#else
82273143b9aSmrg    struct sockaddr_in	    sockname;
82373143b9aSmrg#endif
82473143b9aSmrg    unsigned short	    sport;
82573143b9aSmrg    SOCKLEN_T	namelen = sizeof(sockname);
82673143b9aSmrg    int		status;
82773143b9aSmrg    long	tmpport;
82873143b9aSmrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
82973143b9aSmrg    _Xgetservbynameparams sparams;
83073143b9aSmrg#endif
83173143b9aSmrg    struct servent *servp;
83273143b9aSmrg
83373143b9aSmrg#ifdef X11_t
83473143b9aSmrg    char	portbuf[PORTBUFSIZE];
83573143b9aSmrg#endif
836fe567363Smrg
837fe567363Smrg    prmsg (2, "SocketINETCreateListener(%s)\n", port);
83873143b9aSmrg
83973143b9aSmrg#ifdef X11_t
84073143b9aSmrg    /*
84173143b9aSmrg     * X has a well known port, that is transport dependent. It is easier
84273143b9aSmrg     * to handle it here, than try and come up with a transport independent
84373143b9aSmrg     * representation that can be passed in and resolved the usual way.
84473143b9aSmrg     *
84573143b9aSmrg     * The port that is passed here is really a string containing the idisplay
84673143b9aSmrg     * from ConnectDisplay().
84773143b9aSmrg     */
84873143b9aSmrg
84973143b9aSmrg    if (is_numeric (port))
85073143b9aSmrg    {
85173143b9aSmrg	/* fixup the server port address */
85273143b9aSmrg	tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10);
853fe567363Smrg	snprintf (portbuf, sizeof(portbuf), "%lu", tmpport);
85473143b9aSmrg	port = portbuf;
85573143b9aSmrg    }
85673143b9aSmrg#endif
85773143b9aSmrg
85873143b9aSmrg    if (port && *port)
85973143b9aSmrg    {
86073143b9aSmrg	/* Check to see if the port string is just a number (handles X11) */
86173143b9aSmrg
86273143b9aSmrg	if (!is_numeric (port))
86373143b9aSmrg	{
86473143b9aSmrg	    if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL)
86573143b9aSmrg	    {
866fe567363Smrg		prmsg (1,
86773143b9aSmrg	     "SocketINETCreateListener: Unable to get service for %s\n",
868fe567363Smrg		      port);
86973143b9aSmrg		return TRANS_CREATE_LISTENER_FAILED;
87073143b9aSmrg	    }
87173143b9aSmrg	    /* we trust getservbyname to return a valid number */
87273143b9aSmrg	    sport = servp->s_port;
87373143b9aSmrg	}
87473143b9aSmrg	else
87573143b9aSmrg	{
87673143b9aSmrg	    tmpport = strtol (port, (char**)NULL, 10);
877fe567363Smrg	    /*
87873143b9aSmrg	     * check that somehow the port address isn't negative or in
87973143b9aSmrg	     * the range of reserved port addresses. This can happen and
880fe567363Smrg	     * be very bad if the server is suid-root and the user does
881fe567363Smrg	     * something (dumb) like `X :60049`.
88273143b9aSmrg	     */
88373143b9aSmrg	    if (tmpport < 1024 || tmpport > USHRT_MAX)
88473143b9aSmrg		return TRANS_CREATE_LISTENER_FAILED;
88573143b9aSmrg
88673143b9aSmrg	    sport = (unsigned short) tmpport;
88773143b9aSmrg	}
88873143b9aSmrg    }
88973143b9aSmrg    else
89073143b9aSmrg	sport = 0;
89173143b9aSmrg
89273143b9aSmrg    bzero(&sockname, sizeof(sockname));
89373143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
89473143b9aSmrg    if (Sockettrans2devtab[ciptr->index].family == AF_INET) {
89573143b9aSmrg	namelen = sizeof (struct sockaddr_in);
89673143b9aSmrg#ifdef BSD44SOCKETS
89773143b9aSmrg	((struct sockaddr_in *)&sockname)->sin_len = namelen;
89873143b9aSmrg#endif
89973143b9aSmrg	((struct sockaddr_in *)&sockname)->sin_family = AF_INET;
90073143b9aSmrg	((struct sockaddr_in *)&sockname)->sin_port = htons(sport);
90173143b9aSmrg	((struct sockaddr_in *)&sockname)->sin_addr.s_addr = htonl(INADDR_ANY);
90273143b9aSmrg    } else {
90373143b9aSmrg	namelen = sizeof (struct sockaddr_in6);
90473143b9aSmrg#ifdef SIN6_LEN
90573143b9aSmrg	((struct sockaddr_in6 *)&sockname)->sin6_len = sizeof(sockname);
90673143b9aSmrg#endif
90773143b9aSmrg	((struct sockaddr_in6 *)&sockname)->sin6_family = AF_INET6;
90873143b9aSmrg	((struct sockaddr_in6 *)&sockname)->sin6_port = htons(sport);
90973143b9aSmrg	((struct sockaddr_in6 *)&sockname)->sin6_addr = in6addr_any;
91073143b9aSmrg    }
91173143b9aSmrg#else
91273143b9aSmrg#ifdef BSD44SOCKETS
91373143b9aSmrg    sockname.sin_len = sizeof (sockname);
91473143b9aSmrg#endif
91573143b9aSmrg    sockname.sin_family = AF_INET;
91673143b9aSmrg    sockname.sin_port = htons (sport);
91773143b9aSmrg    sockname.sin_addr.s_addr = htonl (INADDR_ANY);
91873143b9aSmrg#endif
91973143b9aSmrg
92073143b9aSmrg    if ((status = TRANS(SocketCreateListener) (ciptr,
92173143b9aSmrg	(struct sockaddr *) &sockname, namelen, flags)) < 0)
92273143b9aSmrg    {
923fe567363Smrg	prmsg (1,
924fe567363Smrg    "SocketINETCreateListener: ...SocketCreateListener() failed\n");
92573143b9aSmrg	return status;
92673143b9aSmrg    }
92773143b9aSmrg
92873143b9aSmrg    if (TRANS(SocketINETGetAddr) (ciptr) < 0)
92973143b9aSmrg    {
930fe567363Smrg	prmsg (1,
931fe567363Smrg       "SocketINETCreateListener: ...SocketINETGetAddr() failed\n");
93273143b9aSmrg	return TRANS_CREATE_LISTENER_FAILED;
93373143b9aSmrg    }
93473143b9aSmrg
93573143b9aSmrg    return 0;
93673143b9aSmrg}
93773143b9aSmrg
93873143b9aSmrg#endif /* TCPCONN */
93973143b9aSmrg
94073143b9aSmrg
94173143b9aSmrg#ifdef UNIXCONN
94273143b9aSmrg
94373143b9aSmrgstatic int
9446a3641a6SsnjTRANS(SocketUNIXCreateListener) (XtransConnInfo ciptr, const char *port,
94573143b9aSmrg				 unsigned int flags)
94673143b9aSmrg
94773143b9aSmrg{
94873143b9aSmrg    struct sockaddr_un	sockname;
94973143b9aSmrg    int			namelen;
95073143b9aSmrg    int			oldUmask;
95173143b9aSmrg    int			status;
95273143b9aSmrg    unsigned int	mode;
95373143b9aSmrg    char		tmpport[108];
95473143b9aSmrg
95573143b9aSmrg    int			abstract = 0;
95673143b9aSmrg#ifdef HAVE_ABSTRACT_SOCKETS
95773143b9aSmrg    abstract = ciptr->transptr->flags & TRANS_ABSTRACT;
95873143b9aSmrg#endif
95973143b9aSmrg
960fe567363Smrg    prmsg (2, "SocketUNIXCreateListener(%s)\n",
961fe567363Smrg	port ? port : "NULL");
96273143b9aSmrg
96373143b9aSmrg    /* Make sure the directory is created */
96473143b9aSmrg
96573143b9aSmrg    oldUmask = umask (0);
96673143b9aSmrg
96773143b9aSmrg#ifdef UNIX_DIR
96873143b9aSmrg#ifdef HAS_STICKY_DIR_BIT
96973143b9aSmrg    mode = 01777;
97073143b9aSmrg#else
97173143b9aSmrg    mode = 0777;
97273143b9aSmrg#endif
9738d4c0f7bSmrg    if (!abstract && trans_mkdir(UNIX_DIR, mode) == -1) {
974fe567363Smrg	prmsg (1, "SocketUNIXCreateListener: mkdir(%s) failed, errno = %d\n",
975fe567363Smrg	       UNIX_DIR, errno);
97673143b9aSmrg	(void) umask (oldUmask);
97773143b9aSmrg	return TRANS_CREATE_LISTENER_FAILED;
97873143b9aSmrg    }
97973143b9aSmrg#endif
98073143b9aSmrg
98173143b9aSmrg    memset(&sockname, 0, sizeof(sockname));
98273143b9aSmrg    sockname.sun_family = AF_UNIX;
98373143b9aSmrg
98473143b9aSmrg    if (!(port && *port)) {
98573143b9aSmrg	snprintf (tmpport, sizeof(tmpport), "%s%ld", UNIX_PATH, (long)getpid());
98673143b9aSmrg	port = tmpport;
98773143b9aSmrg    }
98873143b9aSmrg    if (set_sun_path(port, UNIX_PATH, sockname.sun_path, abstract) != 0) {
989fe567363Smrg	prmsg (1, "SocketUNIXCreateListener: path too long\n");
99073143b9aSmrg	return TRANS_CREATE_LISTENER_FAILED;
99173143b9aSmrg    }
99273143b9aSmrg
993fe567363Smrg#if (defined(BSD44SOCKETS) || defined(__UNIXWARE__))
99473143b9aSmrg    sockname.sun_len = strlen(sockname.sun_path);
99573143b9aSmrg#endif
99673143b9aSmrg
99773143b9aSmrg#if defined(BSD44SOCKETS) || defined(SUN_LEN)
99873143b9aSmrg    namelen = SUN_LEN(&sockname);
99973143b9aSmrg#else
100073143b9aSmrg    namelen = strlen(sockname.sun_path) + offsetof(struct sockaddr_un, sun_path);
100173143b9aSmrg#endif
100273143b9aSmrg
100373143b9aSmrg    if (abstract) {
100473143b9aSmrg	sockname.sun_path[0] = '\0';
100573143b9aSmrg	namelen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&sockname.sun_path[1]);
100673143b9aSmrg    }
100773143b9aSmrg    else
100873143b9aSmrg	unlink (sockname.sun_path);
100973143b9aSmrg
101073143b9aSmrg    if ((status = TRANS(SocketCreateListener) (ciptr,
101173143b9aSmrg	(struct sockaddr *) &sockname, namelen, flags)) < 0)
101273143b9aSmrg    {
1013fe567363Smrg	prmsg (1,
1014fe567363Smrg    "SocketUNIXCreateListener: ...SocketCreateListener() failed\n");
101573143b9aSmrg	(void) umask (oldUmask);
101673143b9aSmrg	return status;
101773143b9aSmrg    }
101873143b9aSmrg
101973143b9aSmrg    /*
102073143b9aSmrg     * Now that the listener is esablished, create the addr info for
102173143b9aSmrg     * this connection. getpeername() doesn't work for UNIX Domain Sockets
102273143b9aSmrg     * on some systems (hpux at least), so we will just do it manually, instead
102373143b9aSmrg     * of calling something like TRANS(SocketUNIXGetAddr).
102473143b9aSmrg     */
102573143b9aSmrg
102673143b9aSmrg    namelen = sizeof (sockname); /* this will always make it the same size */
102773143b9aSmrg
1028fe567363Smrg    if ((ciptr->addr = malloc (namelen)) == NULL)
102973143b9aSmrg    {
1030fe567363Smrg        prmsg (1,
1031fe567363Smrg        "SocketUNIXCreateListener: Can't allocate space for the addr\n");
103273143b9aSmrg	(void) umask (oldUmask);
103373143b9aSmrg        return TRANS_CREATE_LISTENER_FAILED;
103473143b9aSmrg    }
103573143b9aSmrg
103673143b9aSmrg    if (abstract)
103773143b9aSmrg	sockname.sun_path[0] = '@';
103873143b9aSmrg
103973143b9aSmrg    ciptr->family = sockname.sun_family;
104073143b9aSmrg    ciptr->addrlen = namelen;
104173143b9aSmrg    memcpy (ciptr->addr, &sockname, ciptr->addrlen);
104273143b9aSmrg
104373143b9aSmrg    (void) umask (oldUmask);
104473143b9aSmrg
104573143b9aSmrg    return 0;
104673143b9aSmrg}
104773143b9aSmrg
104873143b9aSmrg
104973143b9aSmrgstatic int
105073143b9aSmrgTRANS(SocketUNIXResetListener) (XtransConnInfo ciptr)
105173143b9aSmrg
105273143b9aSmrg{
105373143b9aSmrg    /*
105473143b9aSmrg     * See if the unix domain socket has disappeared.  If it has, recreate it.
105573143b9aSmrg     */
105673143b9aSmrg
105773143b9aSmrg    struct sockaddr_un 	*unsock = (struct sockaddr_un *) ciptr->addr;
105873143b9aSmrg    struct stat		statb;
105973143b9aSmrg    int 		status = TRANS_RESET_NOOP;
106073143b9aSmrg    unsigned int	mode;
106173143b9aSmrg    int abstract = 0;
106273143b9aSmrg#ifdef HAVE_ABSTRACT_SOCKETS
106373143b9aSmrg    abstract = ciptr->transptr->flags & TRANS_ABSTRACT;
106473143b9aSmrg#endif
106573143b9aSmrg
1066fe567363Smrg    prmsg (3, "SocketUNIXResetListener(%p,%d)\n", ciptr, ciptr->fd);
106773143b9aSmrg
106873143b9aSmrg    if (!abstract && (
106973143b9aSmrg	stat (unsock->sun_path, &statb) == -1 ||
107073143b9aSmrg        ((statb.st_mode & S_IFMT) !=
1071e8a71cdfSmrg#if defined(NCR) || defined(SCO325) || !defined(S_IFSOCK)
107273143b9aSmrg	  		S_IFIFO
107373143b9aSmrg#else
107473143b9aSmrg			S_IFSOCK
107573143b9aSmrg#endif
107673143b9aSmrg				)))
107773143b9aSmrg    {
107873143b9aSmrg	int oldUmask = umask (0);
107973143b9aSmrg
108073143b9aSmrg#ifdef UNIX_DIR
108173143b9aSmrg#ifdef HAS_STICKY_DIR_BIT
108273143b9aSmrg	mode = 01777;
108373143b9aSmrg#else
108473143b9aSmrg	mode = 0777;
108573143b9aSmrg#endif
108673143b9aSmrg        if (trans_mkdir(UNIX_DIR, mode) == -1) {
1087fe567363Smrg            prmsg (1, "SocketUNIXResetListener: mkdir(%s) failed, errno = %d\n",
1088fe567363Smrg	    UNIX_DIR, errno);
108973143b9aSmrg	    (void) umask (oldUmask);
109073143b9aSmrg	    return TRANS_RESET_FAILURE;
109173143b9aSmrg        }
109273143b9aSmrg#endif
109373143b9aSmrg
109473143b9aSmrg	close (ciptr->fd);
109573143b9aSmrg	unlink (unsock->sun_path);
109673143b9aSmrg
109773143b9aSmrg	if ((ciptr->fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
109873143b9aSmrg	{
109973143b9aSmrg	    TRANS(FreeConnInfo) (ciptr);
110073143b9aSmrg	    (void) umask (oldUmask);
110173143b9aSmrg	    return TRANS_RESET_FAILURE;
110273143b9aSmrg	}
110373143b9aSmrg
110473143b9aSmrg	if (bind (ciptr->fd, (struct sockaddr *) unsock, ciptr->addrlen) < 0)
110573143b9aSmrg	{
110673143b9aSmrg	    close (ciptr->fd);
110773143b9aSmrg	    TRANS(FreeConnInfo) (ciptr);
110873143b9aSmrg	    return TRANS_RESET_FAILURE;
110973143b9aSmrg	}
111073143b9aSmrg
111173143b9aSmrg	if (listen (ciptr->fd, BACKLOG) < 0)
111273143b9aSmrg	{
111373143b9aSmrg	    close (ciptr->fd);
111473143b9aSmrg	    TRANS(FreeConnInfo) (ciptr);
111573143b9aSmrg	    (void) umask (oldUmask);
111673143b9aSmrg	    return TRANS_RESET_FAILURE;
111773143b9aSmrg	}
111873143b9aSmrg
111973143b9aSmrg	umask (oldUmask);
112073143b9aSmrg
112173143b9aSmrg	status = TRANS_RESET_NEW_FD;
112273143b9aSmrg    }
112373143b9aSmrg
112473143b9aSmrg    return status;
112573143b9aSmrg}
112673143b9aSmrg
112773143b9aSmrg#endif /* UNIXCONN */
112873143b9aSmrg
112973143b9aSmrg
113073143b9aSmrg#ifdef TCPCONN
113173143b9aSmrg
113273143b9aSmrgstatic XtransConnInfo
113373143b9aSmrgTRANS(SocketINETAccept) (XtransConnInfo ciptr, int *status)
113473143b9aSmrg
113573143b9aSmrg{
113673143b9aSmrg    XtransConnInfo	newciptr;
113773143b9aSmrg    struct sockaddr_in	sockname;
113873143b9aSmrg    SOCKLEN_T		namelen = sizeof(sockname);
113973143b9aSmrg
1140fe567363Smrg    prmsg (2, "SocketINETAccept(%p,%d)\n", ciptr, ciptr->fd);
114173143b9aSmrg
1142fe567363Smrg    if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
114373143b9aSmrg    {
1144fe567363Smrg	prmsg (1, "SocketINETAccept: malloc failed\n");
114573143b9aSmrg	*status = TRANS_ACCEPT_BAD_MALLOC;
114673143b9aSmrg	return NULL;
114773143b9aSmrg    }
114873143b9aSmrg
114973143b9aSmrg    if ((newciptr->fd = accept (ciptr->fd,
115073143b9aSmrg	(struct sockaddr *) &sockname, (void *)&namelen)) < 0)
115173143b9aSmrg    {
115273143b9aSmrg#ifdef WIN32
115373143b9aSmrg	errno = WSAGetLastError();
115473143b9aSmrg#endif
1155fe567363Smrg	prmsg (1, "SocketINETAccept: accept() failed\n");
1156fe567363Smrg	free (newciptr);
115773143b9aSmrg	*status = TRANS_ACCEPT_FAILED;
115873143b9aSmrg	return NULL;
115973143b9aSmrg    }
116073143b9aSmrg
116173143b9aSmrg#ifdef TCP_NODELAY
116273143b9aSmrg    {
116373143b9aSmrg	/*
116473143b9aSmrg	 * turn off TCP coalescence for INET sockets
116573143b9aSmrg	 */
116673143b9aSmrg
116773143b9aSmrg	int tmp = 1;
116873143b9aSmrg	setsockopt (newciptr->fd, IPPROTO_TCP, TCP_NODELAY,
116973143b9aSmrg	    (char *) &tmp, sizeof (int));
117073143b9aSmrg    }
117173143b9aSmrg#endif
117273143b9aSmrg
117373143b9aSmrg    /*
1174fe567363Smrg     * Get this address again because the transport may give a more
117573143b9aSmrg     * specific address now that a connection is established.
117673143b9aSmrg     */
117773143b9aSmrg
117873143b9aSmrg    if (TRANS(SocketINETGetAddr) (newciptr) < 0)
117973143b9aSmrg    {
1180fe567363Smrg	prmsg (1,
1181fe567363Smrg	    "SocketINETAccept: ...SocketINETGetAddr() failed:\n");
118273143b9aSmrg	close (newciptr->fd);
1183fe567363Smrg	free (newciptr);
118473143b9aSmrg	*status = TRANS_ACCEPT_MISC_ERROR;
118573143b9aSmrg        return NULL;
118673143b9aSmrg    }
118773143b9aSmrg
118873143b9aSmrg    if (TRANS(SocketINETGetPeerAddr) (newciptr) < 0)
118973143b9aSmrg    {
1190fe567363Smrg	prmsg (1,
1191fe567363Smrg	  "SocketINETAccept: ...SocketINETGetPeerAddr() failed:\n");
119273143b9aSmrg	close (newciptr->fd);
1193fe567363Smrg	if (newciptr->addr) free (newciptr->addr);
1194fe567363Smrg	free (newciptr);
119573143b9aSmrg	*status = TRANS_ACCEPT_MISC_ERROR;
119673143b9aSmrg        return NULL;
119773143b9aSmrg    }
119873143b9aSmrg
119973143b9aSmrg    *status = 0;
120073143b9aSmrg
120173143b9aSmrg    return newciptr;
120273143b9aSmrg}
120373143b9aSmrg
120473143b9aSmrg#endif /* TCPCONN */
120573143b9aSmrg
120673143b9aSmrg
120773143b9aSmrg#ifdef UNIXCONN
120873143b9aSmrgstatic XtransConnInfo
120973143b9aSmrgTRANS(SocketUNIXAccept) (XtransConnInfo ciptr, int *status)
121073143b9aSmrg
121173143b9aSmrg{
121273143b9aSmrg    XtransConnInfo	newciptr;
121373143b9aSmrg    struct sockaddr_un	sockname;
121473143b9aSmrg    SOCKLEN_T 		namelen = sizeof sockname;
121573143b9aSmrg
1216fe567363Smrg    prmsg (2, "SocketUNIXAccept(%p,%d)\n", ciptr, ciptr->fd);
121773143b9aSmrg
1218fe567363Smrg    if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
121973143b9aSmrg    {
1220fe567363Smrg	prmsg (1, "SocketUNIXAccept: malloc() failed\n");
122173143b9aSmrg	*status = TRANS_ACCEPT_BAD_MALLOC;
122273143b9aSmrg	return NULL;
122373143b9aSmrg    }
122473143b9aSmrg
122573143b9aSmrg    if ((newciptr->fd = accept (ciptr->fd,
122673143b9aSmrg	(struct sockaddr *) &sockname, (void *)&namelen)) < 0)
122773143b9aSmrg    {
1228fe567363Smrg	prmsg (1, "SocketUNIXAccept: accept() failed\n");
1229fe567363Smrg	free (newciptr);
123073143b9aSmrg	*status = TRANS_ACCEPT_FAILED;
123173143b9aSmrg	return NULL;
123273143b9aSmrg    }
123373143b9aSmrg
123473143b9aSmrg	ciptr->addrlen = namelen;
123573143b9aSmrg    /*
123673143b9aSmrg     * Get the socket name and the peer name from the listener socket,
123773143b9aSmrg     * since this is unix domain.
123873143b9aSmrg     */
123973143b9aSmrg
1240fe567363Smrg    if ((newciptr->addr = malloc (ciptr->addrlen)) == NULL)
124173143b9aSmrg    {
1242fe567363Smrg        prmsg (1,
1243fe567363Smrg        "SocketUNIXAccept: Can't allocate space for the addr\n");
124473143b9aSmrg	close (newciptr->fd);
1245fe567363Smrg	free (newciptr);
124673143b9aSmrg	*status = TRANS_ACCEPT_BAD_MALLOC;
124773143b9aSmrg        return NULL;
124873143b9aSmrg    }
124973143b9aSmrg
125073143b9aSmrg    /*
125173143b9aSmrg     * if the socket is abstract, we already modified the address to have a
125273143b9aSmrg     * @ instead of the initial NUL, so no need to do that again here.
125373143b9aSmrg     */
125473143b9aSmrg
125573143b9aSmrg    newciptr->addrlen = ciptr->addrlen;
125673143b9aSmrg    memcpy (newciptr->addr, ciptr->addr, newciptr->addrlen);
125773143b9aSmrg
1258fe567363Smrg    if ((newciptr->peeraddr = malloc (ciptr->addrlen)) == NULL)
125973143b9aSmrg    {
1260fe567363Smrg        prmsg (1,
1261fe567363Smrg	      "SocketUNIXAccept: Can't allocate space for the addr\n");
126273143b9aSmrg	close (newciptr->fd);
1263fe567363Smrg	if (newciptr->addr) free (newciptr->addr);
1264fe567363Smrg	free (newciptr);
126573143b9aSmrg	*status = TRANS_ACCEPT_BAD_MALLOC;
126673143b9aSmrg        return NULL;
126773143b9aSmrg    }
1268fe567363Smrg
126973143b9aSmrg    newciptr->peeraddrlen = ciptr->addrlen;
127073143b9aSmrg    memcpy (newciptr->peeraddr, ciptr->addr, newciptr->addrlen);
127173143b9aSmrg
127273143b9aSmrg    newciptr->family = AF_UNIX;
127373143b9aSmrg
127473143b9aSmrg    *status = 0;
127573143b9aSmrg
127673143b9aSmrg    return newciptr;
127773143b9aSmrg}
127873143b9aSmrg
127973143b9aSmrg#endif /* UNIXCONN */
128073143b9aSmrg
128173143b9aSmrg#endif /* TRANS_SERVER */
128273143b9aSmrg
128373143b9aSmrg
128473143b9aSmrg#ifdef TRANS_CLIENT
128573143b9aSmrg
128673143b9aSmrg#ifdef TCPCONN
128773143b9aSmrg
128873143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
128973143b9aSmrgstruct addrlist {
129073143b9aSmrg    struct addrinfo *	addr;
1291fe567363Smrg    struct addrinfo *	firstaddr;
129273143b9aSmrg    char 		port[PORTBUFSIZE];
129373143b9aSmrg    char 		host[MAXHOSTNAMELEN];
129473143b9aSmrg};
129573143b9aSmrgstatic struct addrlist  *addrlist = NULL;
129673143b9aSmrg#endif
129773143b9aSmrg
129873143b9aSmrg
129973143b9aSmrgstatic int
13006a3641a6SsnjTRANS(SocketINETConnect) (XtransConnInfo ciptr,
13016a3641a6Ssnj                          const char *host, const char *port)
130273143b9aSmrg
130373143b9aSmrg{
130473143b9aSmrg    struct sockaddr *	socketaddr = NULL;
130573143b9aSmrg    int			socketaddrlen = 0;
130673143b9aSmrg    int			res;
130773143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
130873143b9aSmrg    struct addrinfo 	hints;
130973143b9aSmrg    char		ntopbuf[INET6_ADDRSTRLEN];
131073143b9aSmrg    int			resetonce = 0;
1311fe567363Smrg#else
131273143b9aSmrg    struct sockaddr_in	sockname;
1313fe567363Smrg    struct hostent	*hostp;
1314fe567363Smrg    struct servent	*servp;
1315fe567363Smrg    unsigned long 	tmpaddr;
1316fe567363Smrg#endif
131773143b9aSmrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
131873143b9aSmrg    _Xgethostbynameparams hparams;
131973143b9aSmrg    _Xgetservbynameparams sparams;
132073143b9aSmrg#endif
132173143b9aSmrg#ifdef X11_t
132273143b9aSmrg    char	portbuf[PORTBUFSIZE];
132373143b9aSmrg#endif
132473143b9aSmrg
132573143b9aSmrg    char 		hostnamebuf[256];		/* tmp space */
132673143b9aSmrg
1327fe567363Smrg    prmsg (2,"SocketINETConnect(%d,%s,%s)\n", ciptr->fd, host, port);
132873143b9aSmrg
132973143b9aSmrg    if (!host)
133073143b9aSmrg    {
133173143b9aSmrg	hostnamebuf[0] = '\0';
133273143b9aSmrg	(void) TRANS(GetHostname) (hostnamebuf, sizeof hostnamebuf);
133373143b9aSmrg	host = hostnamebuf;
133473143b9aSmrg    }
133573143b9aSmrg
133673143b9aSmrg#ifdef X11_t
133773143b9aSmrg    /*
133873143b9aSmrg     * X has a well known port, that is transport dependent. It is easier
133973143b9aSmrg     * to handle it here, than try and come up with a transport independent
134073143b9aSmrg     * representation that can be passed in and resolved the usual way.
134173143b9aSmrg     *
134273143b9aSmrg     * The port that is passed here is really a string containing the idisplay
134373143b9aSmrg     * from ConnectDisplay().
134473143b9aSmrg     */
134573143b9aSmrg
134673143b9aSmrg    if (is_numeric (port))
134773143b9aSmrg    {
1348fe567363Smrg	long tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10);
1349fe567363Smrg	snprintf (portbuf, sizeof(portbuf), "%lu", tmpport);
135073143b9aSmrg	port = portbuf;
135173143b9aSmrg    }
135273143b9aSmrg#endif
135373143b9aSmrg
135473143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
1355b53e5eeaSmrg    {
135673143b9aSmrg	if (addrlist != NULL) {
135773143b9aSmrg	    if (strcmp(host,addrlist->host) || strcmp(port,addrlist->port)) {
135873143b9aSmrg		if (addrlist->firstaddr)
135973143b9aSmrg		    freeaddrinfo(addrlist->firstaddr);
136073143b9aSmrg		addrlist->firstaddr = NULL;
136173143b9aSmrg	    }
136273143b9aSmrg	} else {
136373143b9aSmrg	    addrlist = malloc(sizeof(struct addrlist));
136473143b9aSmrg	    addrlist->firstaddr = NULL;
136573143b9aSmrg	}
136673143b9aSmrg
136773143b9aSmrg	if (addrlist->firstaddr == NULL) {
136873143b9aSmrg	    strncpy(addrlist->port, port, sizeof(addrlist->port));
136973143b9aSmrg	    addrlist->port[sizeof(addrlist->port) - 1] = '\0';
137073143b9aSmrg	    strncpy(addrlist->host, host, sizeof(addrlist->host));
137173143b9aSmrg	    addrlist->host[sizeof(addrlist->host) - 1] = '\0';
137273143b9aSmrg
137373143b9aSmrg	    bzero(&hints,sizeof(hints));
137473143b9aSmrg	    hints.ai_socktype = Sockettrans2devtab[ciptr->index].devcotsname;
137573143b9aSmrg
137673143b9aSmrg	    res = getaddrinfo(host,port,&hints,&addrlist->firstaddr);
137773143b9aSmrg	    if (res != 0) {
1378fe567363Smrg		prmsg (1, "SocketINETConnect() can't get address "
137973143b9aSmrg			"for %s:%s: %s\n", host, port, gai_strerror(res));
138073143b9aSmrg		ESET(EINVAL);
138173143b9aSmrg		return TRANS_CONNECT_FAILED;
138273143b9aSmrg	    }
138373143b9aSmrg	    for (res = 0, addrlist->addr = addrlist->firstaddr;
138473143b9aSmrg		 addrlist->addr ; res++) {
138573143b9aSmrg		addrlist->addr = addrlist->addr->ai_next;
138673143b9aSmrg	    }
1387fe567363Smrg	    prmsg(4,"Got New Address list with %d addresses\n", res);
138873143b9aSmrg	    res = 0;
138973143b9aSmrg	    addrlist->addr = NULL;
139073143b9aSmrg	}
139173143b9aSmrg
139273143b9aSmrg	while (socketaddr == NULL) {
139373143b9aSmrg	    if (addrlist->addr == NULL) {
1394fe567363Smrg		if (resetonce) {
139573143b9aSmrg		    /* Already checked entire list - no usable addresses */
1396fe567363Smrg		    prmsg (1, "SocketINETConnect() no usable address "
1397fe567363Smrg			   "for %s:%s\n", host, port);
139873143b9aSmrg		    return TRANS_CONNECT_FAILED;
139973143b9aSmrg		} else {
140073143b9aSmrg		    /* Go back to beginning of list */
140173143b9aSmrg		    resetonce = 1;
140273143b9aSmrg		    addrlist->addr = addrlist->firstaddr;
140373143b9aSmrg		}
1404fe567363Smrg	    }
140573143b9aSmrg
140673143b9aSmrg	    socketaddr = addrlist->addr->ai_addr;
140773143b9aSmrg	    socketaddrlen = addrlist->addr->ai_addrlen;
140873143b9aSmrg
140973143b9aSmrg	    if (addrlist->addr->ai_family == AF_INET) {
141073143b9aSmrg		struct sockaddr_in *sin = (struct sockaddr_in *) socketaddr;
141173143b9aSmrg
1412fe567363Smrg		prmsg (4,"SocketINETConnect() sockname.sin_addr = %s\n",
141373143b9aSmrg			inet_ntop(addrlist->addr->ai_family,&sin->sin_addr,
1414fe567363Smrg			ntopbuf,sizeof(ntopbuf)));
141573143b9aSmrg
1416fe567363Smrg		prmsg (4,"SocketINETConnect() sockname.sin_port = %d\n",
1417fe567363Smrg			ntohs(sin->sin_port));
141873143b9aSmrg
141973143b9aSmrg		if (Sockettrans2devtab[ciptr->index].family == AF_INET6) {
142073143b9aSmrg		    if (strcmp(Sockettrans2devtab[ciptr->index].transname,
142173143b9aSmrg				"tcp") == 0) {
142273143b9aSmrg			XtransConnInfo newciptr;
142373143b9aSmrg
142473143b9aSmrg			/*
142573143b9aSmrg			 * Our socket is an IPv6 socket, but the address is
142673143b9aSmrg			 * IPv4.  Close it and get an IPv4 socket.  This is
142773143b9aSmrg			 * needed for IPv4 connections to work on platforms
142873143b9aSmrg			 * that don't allow IPv4 over IPv6 sockets.
142973143b9aSmrg			 */
143073143b9aSmrg			TRANS(SocketINETClose)(ciptr);
143173143b9aSmrg			newciptr = TRANS(SocketOpenCOTSClientBase)(
143273143b9aSmrg					"tcp", "tcp", host, port, ciptr->index);
143373143b9aSmrg			if (newciptr)
143473143b9aSmrg			    ciptr->fd = newciptr->fd;
143573143b9aSmrg			if (!newciptr ||
143673143b9aSmrg			    Sockettrans2devtab[newciptr->index].family !=
143773143b9aSmrg				AF_INET) {
143873143b9aSmrg			    socketaddr = NULL;
1439fe567363Smrg			    prmsg (4,"SocketINETConnect() Cannot get IPv4 "
1440fe567363Smrg					" socketfor IPv4 address\n");
144173143b9aSmrg			}
144273143b9aSmrg			if (newciptr)
1443fe567363Smrg			    free(newciptr);
144473143b9aSmrg		    } else {
144573143b9aSmrg			socketaddr = NULL;
1446fe567363Smrg			prmsg (4,"SocketINETConnect Skipping IPv4 address\n");
144773143b9aSmrg		    }
144873143b9aSmrg		}
144973143b9aSmrg	    } else if (addrlist->addr->ai_family == AF_INET6) {
145073143b9aSmrg		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) socketaddr;
1451fe567363Smrg
1452fe567363Smrg		prmsg (4,"SocketINETConnect() sockname.sin6_addr = %s\n",
145373143b9aSmrg			inet_ntop(addrlist->addr->ai_family,
1454fe567363Smrg				  &sin6->sin6_addr,ntopbuf,sizeof(ntopbuf)));
1455fe567363Smrg		prmsg (4,"SocketINETConnect() sockname.sin6_port = %d\n",
1456fe567363Smrg			ntohs(sin6->sin6_port));
145773143b9aSmrg
145873143b9aSmrg		if (Sockettrans2devtab[ciptr->index].family == AF_INET) {
145973143b9aSmrg		    if (strcmp(Sockettrans2devtab[ciptr->index].transname,
146073143b9aSmrg				"tcp") == 0) {
146173143b9aSmrg			XtransConnInfo newciptr;
146273143b9aSmrg
146373143b9aSmrg			/*
146473143b9aSmrg			 * Close the IPv4 socket and try to open an IPv6 socket.
146573143b9aSmrg			 */
146673143b9aSmrg			TRANS(SocketINETClose)(ciptr);
146773143b9aSmrg			newciptr = TRANS(SocketOpenCOTSClientBase)(
146873143b9aSmrg					"tcp", "tcp", host, port, -1);
146973143b9aSmrg			if (newciptr)
147073143b9aSmrg			    ciptr->fd = newciptr->fd;
147173143b9aSmrg			if (!newciptr ||
147273143b9aSmrg			    Sockettrans2devtab[newciptr->index].family !=
147373143b9aSmrg					AF_INET6) {
147473143b9aSmrg			    socketaddr = NULL;
1475fe567363Smrg			    prmsg (4,"SocketINETConnect() Cannot get IPv6 "
1476fe567363Smrg				   "socket for IPv6 address\n");
147773143b9aSmrg			}
147873143b9aSmrg			if (newciptr)
1479fe567363Smrg			    free(newciptr);
148073143b9aSmrg		    }
148173143b9aSmrg		    else
148273143b9aSmrg		    {
148373143b9aSmrg			socketaddr = NULL;
1484fe567363Smrg			prmsg (4,"SocketINETConnect() Skipping IPv6 address\n");
148573143b9aSmrg		    }
148673143b9aSmrg		}
148773143b9aSmrg	    } else {
148873143b9aSmrg		socketaddr = NULL; /* Unsupported address type */
148973143b9aSmrg	    }
149073143b9aSmrg	    if (socketaddr == NULL) {
149173143b9aSmrg		addrlist->addr = addrlist->addr->ai_next;
149273143b9aSmrg	    }
1493fe567363Smrg	}
1494b53e5eeaSmrg    }
1495b53e5eeaSmrg#else
149673143b9aSmrg    {
149773143b9aSmrg	/*
149873143b9aSmrg	 * Build the socket name.
149973143b9aSmrg	 */
150073143b9aSmrg
150173143b9aSmrg#ifdef BSD44SOCKETS
150273143b9aSmrg	sockname.sin_len = sizeof (struct sockaddr_in);
150373143b9aSmrg#endif
150473143b9aSmrg	sockname.sin_family = AF_INET;
150573143b9aSmrg
150673143b9aSmrg	/*
150773143b9aSmrg	 * fill in sin_addr
150873143b9aSmrg	 */
150973143b9aSmrg
151073143b9aSmrg#ifndef INADDR_NONE
151173143b9aSmrg#define INADDR_NONE ((in_addr_t) 0xffffffff)
151273143b9aSmrg#endif
151373143b9aSmrg
151473143b9aSmrg	/* check for ww.xx.yy.zz host string */
151573143b9aSmrg
151673143b9aSmrg	if (isascii (host[0]) && isdigit (host[0])) {
151773143b9aSmrg	    tmpaddr = inet_addr (host); /* returns network byte order */
151873143b9aSmrg	} else {
151973143b9aSmrg	    tmpaddr = INADDR_NONE;
152073143b9aSmrg	}
152173143b9aSmrg
152281d6fa61Srin	prmsg (4,"SocketINETConnect() inet_addr(%s) = %lx\n", host, tmpaddr);
152373143b9aSmrg
152473143b9aSmrg	if (tmpaddr == INADDR_NONE) {
152573143b9aSmrg	    if ((hostp = _XGethostbyname(host,hparams)) == NULL) {
1526fe567363Smrg		prmsg (1,"SocketINETConnect: Can't get address for %s\n",
1527fe567363Smrg			host);
152873143b9aSmrg		ESET(EINVAL);
152973143b9aSmrg		return TRANS_CONNECT_FAILED;
153073143b9aSmrg	    }
153173143b9aSmrg	    if (hostp->h_addrtype != AF_INET) {  /* is IP host? */
1532fe567363Smrg		prmsg (1,"SocketINETConnect: not INET host%s\n", host);
153373143b9aSmrg		ESET(EPROTOTYPE);
153473143b9aSmrg		return TRANS_CONNECT_FAILED;
153573143b9aSmrg	    }
1536fe567363Smrg
153773143b9aSmrg	    memcpy ((char *) &sockname.sin_addr, (char *) hostp->h_addr,
153873143b9aSmrg		    sizeof (sockname.sin_addr));
153973143b9aSmrg
154073143b9aSmrg	} else {
154173143b9aSmrg	    sockname.sin_addr.s_addr = tmpaddr;
154273143b9aSmrg        }
154373143b9aSmrg
154473143b9aSmrg	/*
154573143b9aSmrg	 * fill in sin_port
154673143b9aSmrg	 */
154773143b9aSmrg
154873143b9aSmrg	/* Check for number in the port string */
154973143b9aSmrg
155073143b9aSmrg	if (!is_numeric (port)) {
155173143b9aSmrg	    if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL) {
1552fe567363Smrg		prmsg (1,"SocketINETConnect: can't get service for %s\n",
1553fe567363Smrg			port);
155473143b9aSmrg		return TRANS_CONNECT_FAILED;
155573143b9aSmrg	    }
155673143b9aSmrg	    sockname.sin_port = htons (servp->s_port);
155773143b9aSmrg	} else {
1558fe567363Smrg	    long tmpport = strtol (port, (char**)NULL, 10);
155973143b9aSmrg	    if (tmpport < 1024 || tmpport > USHRT_MAX)
156073143b9aSmrg		return TRANS_CONNECT_FAILED;
156173143b9aSmrg	    sockname.sin_port = htons (((unsigned short) tmpport));
156273143b9aSmrg	}
156373143b9aSmrg
1564fe567363Smrg	prmsg (4,"SocketINETConnect: sockname.sin_port = %d\n",
1565fe567363Smrg		ntohs(sockname.sin_port));
156673143b9aSmrg	socketaddr = (struct sockaddr *) &sockname;
156773143b9aSmrg	socketaddrlen = sizeof(sockname);
156873143b9aSmrg    }
1569b53e5eeaSmrg#endif
157073143b9aSmrg
157173143b9aSmrg    /*
157273143b9aSmrg     * Turn on socket keepalive so the client process will eventually
157373143b9aSmrg     * be notified with a SIGPIPE signal if the display server fails
157473143b9aSmrg     * to respond to a periodic transmission of messages
157573143b9aSmrg     * on the connected socket.
157673143b9aSmrg     * This is useful to avoid hung application processes when the
157773143b9aSmrg     * processes are not spawned from the xdm session and
157873143b9aSmrg     * the display server terminates abnormally.
157973143b9aSmrg     * (Someone turned off the power switch.)
158073143b9aSmrg     */
158173143b9aSmrg
158273143b9aSmrg    {
158373143b9aSmrg	int tmp = 1;
158473143b9aSmrg	setsockopt (ciptr->fd, SOL_SOCKET, SO_KEEPALIVE,
158573143b9aSmrg		(char *) &tmp, sizeof (int));
158673143b9aSmrg    }
158773143b9aSmrg
158873143b9aSmrg    /*
158973143b9aSmrg     * Do the connect()
159073143b9aSmrg     */
159173143b9aSmrg
159273143b9aSmrg    if (connect (ciptr->fd, socketaddr, socketaddrlen ) < 0)
159373143b9aSmrg    {
159473143b9aSmrg#ifdef WIN32
159573143b9aSmrg	int olderrno = WSAGetLastError();
159673143b9aSmrg#else
159773143b9aSmrg	int olderrno = errno;
159873143b9aSmrg#endif
159973143b9aSmrg
160073143b9aSmrg	/*
160173143b9aSmrg	 * If the error was ECONNREFUSED, the server may be overloaded
160273143b9aSmrg	 * and we should try again.
160373143b9aSmrg	 *
160473143b9aSmrg	 * If the error was EWOULDBLOCK or EINPROGRESS then the socket
160573143b9aSmrg	 * was non-blocking and we should poll using select
160673143b9aSmrg	 *
160773143b9aSmrg	 * If the error was EINTR, the connect was interrupted and we
160873143b9aSmrg	 * should try again.
160973143b9aSmrg	 *
161073143b9aSmrg	 * If multiple addresses are found for a host then we should
161173143b9aSmrg	 * try to connect again with a different address for a larger
161273143b9aSmrg	 * number of errors that made us quit before, since those
161373143b9aSmrg	 * could be caused by trying to use an IPv6 address to contact
161473143b9aSmrg	 * a machine with an IPv4-only server or other reasons that
1615fe567363Smrg	 * only affect one of a set of addresses.
161673143b9aSmrg	 */
161773143b9aSmrg
161873143b9aSmrg	if (olderrno == ECONNREFUSED || olderrno == EINTR
161973143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
1620b53e5eeaSmrg	  || (((addrlist->addr->ai_next != NULL) ||
162173143b9aSmrg	        (addrlist->addr != addrlist->firstaddr)) &&
162273143b9aSmrg               (olderrno == ENETUNREACH || olderrno == EAFNOSUPPORT ||
162373143b9aSmrg		 olderrno == EADDRNOTAVAIL || olderrno == ETIMEDOUT
162473143b9aSmrg#if defined(EHOSTDOWN)
162573143b9aSmrg		   || olderrno == EHOSTDOWN
162673143b9aSmrg#endif
162773143b9aSmrg	       ))
162873143b9aSmrg#endif
162973143b9aSmrg	    )
163073143b9aSmrg	    res = TRANS_TRY_CONNECT_AGAIN;
163173143b9aSmrg	else if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS)
163273143b9aSmrg	    res = TRANS_IN_PROGRESS;
163373143b9aSmrg	else
163473143b9aSmrg	{
1635fe567363Smrg	    prmsg (2,"SocketINETConnect: Can't connect: errno = %d\n",
1636fe567363Smrg		   olderrno);
163773143b9aSmrg
1638fe567363Smrg	    res = TRANS_CONNECT_FAILED;
163973143b9aSmrg	}
164073143b9aSmrg    } else {
164173143b9aSmrg	res = 0;
1642fe567363Smrg
164373143b9aSmrg
164473143b9aSmrg	/*
164573143b9aSmrg	 * Sync up the address fields of ciptr.
164673143b9aSmrg	 */
1647fe567363Smrg
164873143b9aSmrg	if (TRANS(SocketINETGetAddr) (ciptr) < 0)
164973143b9aSmrg	{
1650fe567363Smrg	    prmsg (1,
1651fe567363Smrg	     "SocketINETConnect: ...SocketINETGetAddr() failed:\n");
165273143b9aSmrg	    res = TRANS_CONNECT_FAILED;
165373143b9aSmrg	}
165473143b9aSmrg
165573143b9aSmrg	else if (TRANS(SocketINETGetPeerAddr) (ciptr) < 0)
165673143b9aSmrg	{
1657fe567363Smrg	    prmsg (1,
1658fe567363Smrg	      "SocketINETConnect: ...SocketINETGetPeerAddr() failed:\n");
165973143b9aSmrg	    res = TRANS_CONNECT_FAILED;
166073143b9aSmrg	}
166173143b9aSmrg    }
166273143b9aSmrg
166373143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
1664b53e5eeaSmrg   if (res != 0) {
166573143b9aSmrg	addrlist->addr = addrlist->addr->ai_next;
166673143b9aSmrg   }
166773143b9aSmrg#endif
166873143b9aSmrg
166973143b9aSmrg    return res;
167073143b9aSmrg}
167173143b9aSmrg
167273143b9aSmrg#endif /* TCPCONN */
167373143b9aSmrg
167473143b9aSmrg
167573143b9aSmrg
167673143b9aSmrg#ifdef UNIXCONN
167773143b9aSmrg
167873143b9aSmrg/*
167973143b9aSmrg * Make sure 'host' is really local.
168073143b9aSmrg */
168173143b9aSmrg
168273143b9aSmrgstatic int
16836a3641a6SsnjUnixHostReallyLocal (const char *host)
168473143b9aSmrg
168573143b9aSmrg{
168673143b9aSmrg    char hostnamebuf[256];
168773143b9aSmrg
168873143b9aSmrg    TRANS(GetHostname) (hostnamebuf, sizeof (hostnamebuf));
168973143b9aSmrg
169073143b9aSmrg    if (strcmp (hostnamebuf, host) == 0)
169173143b9aSmrg    {
169273143b9aSmrg	return (1);
1693b53e5eeaSmrg    } else {
169473143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
169573143b9aSmrg	struct addrinfo *localhostaddr;
169673143b9aSmrg	struct addrinfo *otherhostaddr;
169773143b9aSmrg	struct addrinfo *i, *j;
169873143b9aSmrg	int equiv = 0;
169973143b9aSmrg
170073143b9aSmrg	if (getaddrinfo(hostnamebuf, NULL, NULL, &localhostaddr) != 0)
170173143b9aSmrg	    return 0;
170273143b9aSmrg	if (getaddrinfo(host, NULL, NULL, &otherhostaddr) != 0) {
170373143b9aSmrg	    freeaddrinfo(localhostaddr);
170473143b9aSmrg	    return 0;
170573143b9aSmrg	}
170673143b9aSmrg
170773143b9aSmrg	for (i = localhostaddr; i != NULL && equiv == 0; i = i->ai_next) {
170873143b9aSmrg	    for (j = otherhostaddr; j != NULL && equiv == 0; j = j->ai_next) {
170973143b9aSmrg		if (i->ai_family == j->ai_family) {
171073143b9aSmrg		    if (i->ai_family == AF_INET) {
1711fe567363Smrg			struct sockaddr_in *sinA
171273143b9aSmrg			  = (struct sockaddr_in *) i->ai_addr;
171373143b9aSmrg			struct sockaddr_in *sinB
171473143b9aSmrg			  = (struct sockaddr_in *) j->ai_addr;
171573143b9aSmrg			struct in_addr *A = &sinA->sin_addr;
171673143b9aSmrg			struct in_addr *B = &sinB->sin_addr;
171773143b9aSmrg
171873143b9aSmrg			if (memcmp(A,B,sizeof(struct in_addr)) == 0) {
171973143b9aSmrg			    equiv = 1;
172073143b9aSmrg			}
172173143b9aSmrg		    } else if (i->ai_family == AF_INET6) {
1722fe567363Smrg			struct sockaddr_in6 *sinA
172373143b9aSmrg			  = (struct sockaddr_in6 *) i->ai_addr;
1724fe567363Smrg			struct sockaddr_in6 *sinB
172573143b9aSmrg			  = (struct sockaddr_in6 *) j->ai_addr;
172673143b9aSmrg			struct in6_addr *A = &sinA->sin6_addr;
172773143b9aSmrg			struct in6_addr *B = &sinB->sin6_addr;
172873143b9aSmrg
172973143b9aSmrg			if (memcmp(A,B,sizeof(struct in6_addr)) == 0) {
173073143b9aSmrg			    equiv = 1;
173173143b9aSmrg			}
173273143b9aSmrg		    }
173373143b9aSmrg		}
173473143b9aSmrg	    }
173573143b9aSmrg	}
1736fe567363Smrg
173773143b9aSmrg	freeaddrinfo(localhostaddr);
173873143b9aSmrg	freeaddrinfo(otherhostaddr);
173973143b9aSmrg	return equiv;
1740b53e5eeaSmrg#else
174173143b9aSmrg	/*
174273143b9aSmrg	 * A host may have more than one network address.  If any of the
174373143b9aSmrg	 * network addresses of 'host' (specified to the connect call)
174473143b9aSmrg	 * match any of the network addresses of 'hostname' (determined
174573143b9aSmrg	 * by TRANS(GetHostname)), then the two hostnames are equivalent,
174673143b9aSmrg	 * and we know that 'host' is really a local host.
174773143b9aSmrg	 */
174873143b9aSmrg	char specified_local_addr_list[10][4];
174973143b9aSmrg	int scount, equiv, i, j;
175073143b9aSmrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
175173143b9aSmrg	_Xgethostbynameparams hparams;
175273143b9aSmrg#endif
175373143b9aSmrg	struct hostent *hostp;
175473143b9aSmrg
175573143b9aSmrg	if ((hostp = _XGethostbyname (host,hparams)) == NULL)
175673143b9aSmrg	    return (0);
175773143b9aSmrg
175873143b9aSmrg	scount = 0;
175973143b9aSmrg	while (hostp->h_addr_list[scount] && scount <= 8)
176073143b9aSmrg	{
176173143b9aSmrg	    /*
176273143b9aSmrg	     * The 2nd call to gethostname() overrides the data
176373143b9aSmrg	     * from the 1st call, so we must save the address list.
176473143b9aSmrg	     */
176573143b9aSmrg
1766fe567363Smrg	    specified_local_addr_list[scount][0] =
176773143b9aSmrg				hostp->h_addr_list[scount][0];
1768fe567363Smrg	    specified_local_addr_list[scount][1] =
176973143b9aSmrg				hostp->h_addr_list[scount][1];
1770fe567363Smrg	    specified_local_addr_list[scount][2] =
177173143b9aSmrg				hostp->h_addr_list[scount][2];
1772fe567363Smrg	    specified_local_addr_list[scount][3] =
177373143b9aSmrg				hostp->h_addr_list[scount][3];
177473143b9aSmrg	    scount++;
177573143b9aSmrg	}
177673143b9aSmrg	if ((hostp = _XGethostbyname (hostnamebuf,hparams)) == NULL)
177773143b9aSmrg	    return (0);
177873143b9aSmrg
177973143b9aSmrg	equiv = 0;
178073143b9aSmrg	i = 0;
178173143b9aSmrg
178273143b9aSmrg	while (i < scount && !equiv)
178373143b9aSmrg	{
178473143b9aSmrg	    j = 0;
178573143b9aSmrg
178673143b9aSmrg	    while (hostp->h_addr_list[j])
178773143b9aSmrg	    {
1788fe567363Smrg		if ((specified_local_addr_list[i][0] ==
178973143b9aSmrg					hostp->h_addr_list[j][0]) &&
1790fe567363Smrg		    (specified_local_addr_list[i][1] ==
179173143b9aSmrg					hostp->h_addr_list[j][1]) &&
1792fe567363Smrg		    (specified_local_addr_list[i][2] ==
179373143b9aSmrg					hostp->h_addr_list[j][2]) &&
1794fe567363Smrg		    (specified_local_addr_list[i][3] ==
179573143b9aSmrg					hostp->h_addr_list[j][3]))
179673143b9aSmrg		{
179773143b9aSmrg		    /* They're equal, so we're done */
1798fe567363Smrg
179973143b9aSmrg		    equiv = 1;
180073143b9aSmrg		    break;
180173143b9aSmrg		}
180273143b9aSmrg
180373143b9aSmrg		j++;
180473143b9aSmrg	    }
180573143b9aSmrg
180673143b9aSmrg	    i++;
180773143b9aSmrg	}
180873143b9aSmrg	return (equiv);
1809b53e5eeaSmrg#endif
181073143b9aSmrg    }
181173143b9aSmrg}
181273143b9aSmrg
181373143b9aSmrgstatic int
18146a3641a6SsnjTRANS(SocketUNIXConnect) (XtransConnInfo ciptr,
18156a3641a6Ssnj                          const char *host, const char *port)
181673143b9aSmrg
181773143b9aSmrg{
181873143b9aSmrg    struct sockaddr_un	sockname;
181973143b9aSmrg    SOCKLEN_T		namelen;
182073143b9aSmrg
182173143b9aSmrg
182273143b9aSmrg    int abstract = 0;
182373143b9aSmrg#ifdef HAVE_ABSTRACT_SOCKETS
182473143b9aSmrg    abstract = ciptr->transptr->flags & TRANS_ABSTRACT;
182573143b9aSmrg#endif
182673143b9aSmrg
1827fe567363Smrg    prmsg (2,"SocketUNIXConnect(%d,%s,%s)\n", ciptr->fd, host, port);
1828fe567363Smrg
182973143b9aSmrg    /*
183073143b9aSmrg     * Make sure 'host' is really local.  If not, we return failure.
183173143b9aSmrg     * The reason we make this check is because a process may advertise
183273143b9aSmrg     * a "local" network ID for which it can accept connections, but if
183373143b9aSmrg     * a process on a remote machine tries to connect to this network ID,
183473143b9aSmrg     * we know for sure it will fail.
183573143b9aSmrg     */
183673143b9aSmrg
183773143b9aSmrg    if (host && *host && host[0]!='/' && strcmp (host, "unix") != 0 && !UnixHostReallyLocal (host))
183873143b9aSmrg    {
1839fe567363Smrg	prmsg (1,
184073143b9aSmrg	   "SocketUNIXConnect: Cannot connect to non-local host %s\n",
1841fe567363Smrg	       host);
184273143b9aSmrg	return TRANS_CONNECT_FAILED;
184373143b9aSmrg    }
184473143b9aSmrg
184573143b9aSmrg
184673143b9aSmrg    /*
184773143b9aSmrg     * Check the port.
184873143b9aSmrg     */
184973143b9aSmrg
185073143b9aSmrg    if (!port || !*port)
185173143b9aSmrg    {
1852fe567363Smrg	prmsg (1,"SocketUNIXConnect: Missing port specification\n");
185373143b9aSmrg	return TRANS_CONNECT_FAILED;
185473143b9aSmrg    }
185573143b9aSmrg
185673143b9aSmrg    /*
185773143b9aSmrg     * Build the socket name.
185873143b9aSmrg     */
1859fe567363Smrg
186073143b9aSmrg    sockname.sun_family = AF_UNIX;
186173143b9aSmrg
186273143b9aSmrg    if (set_sun_path(port, UNIX_PATH, sockname.sun_path, abstract) != 0) {
1863fe567363Smrg	prmsg (1, "SocketUNIXConnect: path too long\n");
186473143b9aSmrg	return TRANS_CONNECT_FAILED;
186573143b9aSmrg    }
186673143b9aSmrg
1867fe567363Smrg#if (defined(BSD44SOCKETS) || defined(__UNIXWARE__))
186873143b9aSmrg    sockname.sun_len = strlen (sockname.sun_path);
186973143b9aSmrg#endif
187073143b9aSmrg
187173143b9aSmrg#if defined(BSD44SOCKETS) || defined(SUN_LEN)
187273143b9aSmrg    namelen = SUN_LEN (&sockname);
187373143b9aSmrg#else
187473143b9aSmrg    namelen = strlen (sockname.sun_path) + offsetof(struct sockaddr_un, sun_path);
187573143b9aSmrg#endif
187673143b9aSmrg
187773143b9aSmrg
187873143b9aSmrg
187973143b9aSmrg    /*
188073143b9aSmrg     * Adjust the socket path if using abstract sockets.
188173143b9aSmrg     * Done here because otherwise all the strlen() calls above would fail.
188273143b9aSmrg     */
188373143b9aSmrg
188473143b9aSmrg    if (abstract) {
188573143b9aSmrg	sockname.sun_path[0] = '\0';
188673143b9aSmrg    }
188773143b9aSmrg
188873143b9aSmrg    /*
188973143b9aSmrg     * Do the connect()
189073143b9aSmrg     */
189173143b9aSmrg
189273143b9aSmrg    if (connect (ciptr->fd, (struct sockaddr *) &sockname, namelen) < 0)
189373143b9aSmrg    {
189473143b9aSmrg	int olderrno = errno;
189573143b9aSmrg	int connected = 0;
1896fe567363Smrg
189773143b9aSmrg	if (!connected)
189873143b9aSmrg	{
189973143b9aSmrg	    errno = olderrno;
1900fe567363Smrg
190173143b9aSmrg	    /*
190273143b9aSmrg	     * If the error was ENOENT, the server may be starting up; we used
190373143b9aSmrg	     * to suggest to try again in this case with
190473143b9aSmrg	     * TRANS_TRY_CONNECT_AGAIN, but this introduced problems for
190573143b9aSmrg	     * processes still referencing stale sockets in their environment.
190673143b9aSmrg	     * Hence, we now return a hard error, TRANS_CONNECT_FAILED, and it
190773143b9aSmrg	     * is suggested that higher level stacks handle retries on their
190873143b9aSmrg	     * level when they face a slow starting server.
190973143b9aSmrg	     *
191073143b9aSmrg	     * If the error was EWOULDBLOCK or EINPROGRESS then the socket
191173143b9aSmrg	     * was non-blocking and we should poll using select
191273143b9aSmrg	     *
191373143b9aSmrg	     * If the error was EINTR, the connect was interrupted and we
191473143b9aSmrg	     * should try again.
191573143b9aSmrg	     */
191673143b9aSmrg
191773143b9aSmrg	    if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS)
191873143b9aSmrg		return TRANS_IN_PROGRESS;
191973143b9aSmrg	    else if (olderrno == EINTR)
192073143b9aSmrg		return TRANS_TRY_CONNECT_AGAIN;
19218d4c0f7bSmrg	    else if (olderrno == ENOENT || olderrno == ECONNREFUSED) {
192273143b9aSmrg		/* If opening as abstract socket failed, try again normally */
192373143b9aSmrg		if (abstract) {
192473143b9aSmrg		    ciptr->transptr->flags &= ~(TRANS_ABSTRACT);
192573143b9aSmrg		    return TRANS_TRY_CONNECT_AGAIN;
192673143b9aSmrg		} else {
192773143b9aSmrg		    return TRANS_CONNECT_FAILED;
192873143b9aSmrg		}
192973143b9aSmrg	    } else {
1930fe567363Smrg		prmsg (2,"SocketUNIXConnect: Can't connect: errno = %d\n",
1931fe567363Smrg		       EGET());
193273143b9aSmrg
193373143b9aSmrg		return TRANS_CONNECT_FAILED;
193473143b9aSmrg	    }
193573143b9aSmrg	}
193673143b9aSmrg    }
193773143b9aSmrg
193873143b9aSmrg    /*
193973143b9aSmrg     * Get the socket name and the peer name from the connect socket,
194073143b9aSmrg     * since this is unix domain.
194173143b9aSmrg     */
194273143b9aSmrg
1943fe567363Smrg    if ((ciptr->addr = malloc(namelen)) == NULL ||
1944fe567363Smrg       (ciptr->peeraddr = malloc(namelen)) == NULL)
194573143b9aSmrg    {
1946fe567363Smrg        prmsg (1,
1947fe567363Smrg	"SocketUNIXCreateListener: Can't allocate space for the addr\n");
194873143b9aSmrg        return TRANS_CONNECT_FAILED;
194973143b9aSmrg    }
195073143b9aSmrg
195173143b9aSmrg    if (abstract)
195273143b9aSmrg	sockname.sun_path[0] = '@';
195373143b9aSmrg
195473143b9aSmrg    ciptr->family = AF_UNIX;
195573143b9aSmrg    ciptr->addrlen = namelen;
195673143b9aSmrg    ciptr->peeraddrlen = namelen;
195773143b9aSmrg    memcpy (ciptr->addr, &sockname, ciptr->addrlen);
195873143b9aSmrg    memcpy (ciptr->peeraddr, &sockname, ciptr->peeraddrlen);
195973143b9aSmrg
196073143b9aSmrg    return 0;
196173143b9aSmrg}
196273143b9aSmrg
196373143b9aSmrg#endif /* UNIXCONN */
196473143b9aSmrg
196573143b9aSmrg#endif /* TRANS_CLIENT */
196673143b9aSmrg
196773143b9aSmrg
196873143b9aSmrgstatic int
196973143b9aSmrgTRANS(SocketBytesReadable) (XtransConnInfo ciptr, BytesReadable_t *pend)
197073143b9aSmrg
197173143b9aSmrg{
1972fe567363Smrg    prmsg (2,"SocketBytesReadable(%p,%d,%p)\n",
197373143b9aSmrg	ciptr, ciptr->fd, pend);
197473143b9aSmrg#ifdef WIN32
197573143b9aSmrg    {
197673143b9aSmrg	int ret = ioctlsocket ((SOCKET) ciptr->fd, FIONREAD, (u_long *) pend);
197773143b9aSmrg	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
197873143b9aSmrg	return ret;
197973143b9aSmrg    }
198073143b9aSmrg#else
198173143b9aSmrg    return ioctl (ciptr->fd, FIONREAD, (char *) pend);
198273143b9aSmrg#endif /* WIN32 */
198373143b9aSmrg}
198473143b9aSmrg
198575ebec6dSmrg#if XTRANS_SEND_FDS
198675ebec6dSmrg
198775ebec6dSmrgstatic void
198875ebec6dSmrgappendFd(struct _XtransConnFd **prev, int fd, int do_close)
198975ebec6dSmrg{
199075ebec6dSmrg    struct _XtransConnFd *cf, *new;
199175ebec6dSmrg
199275ebec6dSmrg    new = malloc (sizeof (struct _XtransConnFd));
199375ebec6dSmrg    if (!new) {
199475ebec6dSmrg        /* XXX mark connection as broken */
199575ebec6dSmrg        close(fd);
199675ebec6dSmrg        return;
199775ebec6dSmrg    }
199875ebec6dSmrg    new->next = 0;
199975ebec6dSmrg    new->fd = fd;
200075ebec6dSmrg    new->do_close = do_close;
200175ebec6dSmrg    /* search to end of list */
200275ebec6dSmrg    for (; (cf = *prev); prev = &(cf->next));
200375ebec6dSmrg    *prev = new;
200475ebec6dSmrg}
200573143b9aSmrg
200673143b9aSmrgstatic int
200775ebec6dSmrgremoveFd(struct _XtransConnFd **prev)
200875ebec6dSmrg{
200975ebec6dSmrg    struct _XtransConnFd *cf;
201075ebec6dSmrg    int fd;
201175ebec6dSmrg
201275ebec6dSmrg    if ((cf = *prev)) {
201375ebec6dSmrg        *prev = cf->next;
201475ebec6dSmrg        fd = cf->fd;
201575ebec6dSmrg        free(cf);
201675ebec6dSmrg    } else
201775ebec6dSmrg        fd = -1;
201875ebec6dSmrg    return fd;
201975ebec6dSmrg}
202073143b9aSmrg
202175ebec6dSmrgstatic void
202275ebec6dSmrgdiscardFd(struct _XtransConnFd **prev, struct _XtransConnFd *upto, int do_close)
202373143b9aSmrg{
202475ebec6dSmrg    struct _XtransConnFd *cf, *next;
202573143b9aSmrg
202675ebec6dSmrg    for (cf = *prev; cf != upto; cf = next) {
202775ebec6dSmrg        next = cf->next;
202875ebec6dSmrg        if (do_close || cf->do_close)
202975ebec6dSmrg            close(cf->fd);
203075ebec6dSmrg        free(cf);
203173143b9aSmrg    }
203275ebec6dSmrg    *prev = upto;
203373143b9aSmrg}
203473143b9aSmrg
203575ebec6dSmrgstatic void
203675ebec6dSmrgcleanupFds(XtransConnInfo ciptr)
203775ebec6dSmrg{
203875ebec6dSmrg    /* Clean up the send list but don't close the fds */
203975ebec6dSmrg    discardFd(&ciptr->send_fds, NULL, 0);
204075ebec6dSmrg    /* Clean up the recv list and *do* close the fds */
204175ebec6dSmrg    discardFd(&ciptr->recv_fds, NULL, 1);
204275ebec6dSmrg}
204373143b9aSmrg
204473143b9aSmrgstatic int
204575ebec6dSmrgnFd(struct _XtransConnFd **prev)
204675ebec6dSmrg{
204775ebec6dSmrg    struct _XtransConnFd *cf;
204875ebec6dSmrg    int n = 0;
204975ebec6dSmrg
205075ebec6dSmrg    for (cf = *prev; cf; cf = cf->next)
205175ebec6dSmrg        n++;
205275ebec6dSmrg    return n;
205375ebec6dSmrg}
205473143b9aSmrg
205575ebec6dSmrgstatic int
205675ebec6dSmrgTRANS(SocketRecvFd) (XtransConnInfo ciptr)
205773143b9aSmrg{
205875ebec6dSmrg    prmsg (2, "SocketRecvFd(%d)\n", ciptr->fd);
205975ebec6dSmrg    return removeFd(&ciptr->recv_fds);
206075ebec6dSmrg}
206175ebec6dSmrg
206275ebec6dSmrgstatic int
206375ebec6dSmrgTRANS(SocketSendFd) (XtransConnInfo ciptr, int fd, int do_close)
206475ebec6dSmrg{
206575ebec6dSmrg    appendFd(&ciptr->send_fds, fd, do_close);
206675ebec6dSmrg    return 0;
206775ebec6dSmrg}
206875ebec6dSmrg
206975ebec6dSmrgstatic int
207075ebec6dSmrgTRANS(SocketRecvFdInvalid)(XtransConnInfo ciptr)
207175ebec6dSmrg{
207275ebec6dSmrg    errno = EINVAL;
207375ebec6dSmrg    return -1;
207475ebec6dSmrg}
207575ebec6dSmrg
207675ebec6dSmrgstatic int
207775ebec6dSmrgTRANS(SocketSendFdInvalid)(XtransConnInfo ciptr, int fd, int do_close)
207875ebec6dSmrg{
207975ebec6dSmrg    errno = EINVAL;
208075ebec6dSmrg    return -1;
208175ebec6dSmrg}
208275ebec6dSmrg
208375ebec6dSmrg#define MAX_FDS		128
208475ebec6dSmrg
208575ebec6dSmrgunion fd_pass {
208675ebec6dSmrg	struct cmsghdr	cmsghdr;
208775ebec6dSmrg	char		buf[CMSG_SPACE(MAX_FDS * sizeof(int))];
208875ebec6dSmrg};
208975ebec6dSmrg
209075ebec6dSmrg#endif /* XTRANS_SEND_FDS */
209175ebec6dSmrg
209275ebec6dSmrgstatic int
209375ebec6dSmrgTRANS(SocketRead) (XtransConnInfo ciptr, char *buf, int size)
209475ebec6dSmrg
209575ebec6dSmrg{
209675ebec6dSmrg    prmsg (2,"SocketRead(%d,%p,%d)\n", ciptr->fd, buf, size);
209773143b9aSmrg
2098fe567363Smrg#if defined(WIN32)
209973143b9aSmrg    {
210075ebec6dSmrg	int ret = recv ((SOCKET)ciptr->fd, buf, size, 0);
210173143b9aSmrg#ifdef WIN32
210273143b9aSmrg	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
210373143b9aSmrg#endif
210473143b9aSmrg	return ret;
210573143b9aSmrg    }
210673143b9aSmrg#else
210775ebec6dSmrg#if XTRANS_SEND_FDS
210875ebec6dSmrg    {
210975ebec6dSmrg        struct iovec    iov = {
211075ebec6dSmrg            .iov_base = buf,
211175ebec6dSmrg            .iov_len = size
211275ebec6dSmrg        };
211375ebec6dSmrg        union fd_pass   cmsgbuf;
211475ebec6dSmrg        struct msghdr   msg = {
211575ebec6dSmrg            .msg_name = NULL,
211675ebec6dSmrg            .msg_namelen = 0,
211775ebec6dSmrg            .msg_iov = &iov,
211875ebec6dSmrg            .msg_iovlen = 1,
211975ebec6dSmrg            .msg_control = cmsgbuf.buf,
212075ebec6dSmrg            .msg_controllen = CMSG_LEN(MAX_FDS * sizeof(int))
212175ebec6dSmrg        };
212275ebec6dSmrg
212375ebec6dSmrg        size = recvmsg(ciptr->fd, &msg, 0);
212475ebec6dSmrg        if (size >= 0) {
212575ebec6dSmrg            struct cmsghdr *hdr;
212675ebec6dSmrg
212775ebec6dSmrg            for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) {
212875ebec6dSmrg                if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) {
212975ebec6dSmrg                    int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int);
213075ebec6dSmrg                    int i;
213175ebec6dSmrg                    int *fd = (int *) CMSG_DATA(hdr);
213275ebec6dSmrg
213375ebec6dSmrg                    for (i = 0; i < nfd; i++)
213475ebec6dSmrg                        appendFd(&ciptr->recv_fds, fd[i], 0);
213575ebec6dSmrg                }
213675ebec6dSmrg            }
213775ebec6dSmrg        }
213875ebec6dSmrg        return size;
213975ebec6dSmrg    }
214075ebec6dSmrg#else
214175ebec6dSmrg    return read(ciptr->fd, buf, size);
214275ebec6dSmrg#endif /* XTRANS_SEND_FDS */
214373143b9aSmrg#endif /* WIN32 */
214473143b9aSmrg}
214573143b9aSmrg
214673143b9aSmrgstatic int
214773143b9aSmrgTRANS(SocketReadv) (XtransConnInfo ciptr, struct iovec *buf, int size)
214873143b9aSmrg
214973143b9aSmrg{
2150fe567363Smrg    prmsg (2,"SocketReadv(%d,%p,%d)\n", ciptr->fd, buf, size);
215173143b9aSmrg
215275ebec6dSmrg#if XTRANS_SEND_FDS
215375ebec6dSmrg    {
215475ebec6dSmrg        union fd_pass   cmsgbuf;
215575ebec6dSmrg        struct msghdr   msg = {
215675ebec6dSmrg            .msg_name = NULL,
215775ebec6dSmrg            .msg_namelen = 0,
215875ebec6dSmrg            .msg_iov = buf,
215975ebec6dSmrg            .msg_iovlen = size,
216075ebec6dSmrg            .msg_control = cmsgbuf.buf,
216175ebec6dSmrg            .msg_controllen = CMSG_LEN(MAX_FDS * sizeof(int))
216275ebec6dSmrg        };
216375ebec6dSmrg
216475ebec6dSmrg        size = recvmsg(ciptr->fd, &msg, 0);
216575ebec6dSmrg        if (size >= 0) {
216675ebec6dSmrg            struct cmsghdr *hdr;
216775ebec6dSmrg
216875ebec6dSmrg            for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) {
216975ebec6dSmrg                if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) {
217075ebec6dSmrg                    int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int);
217175ebec6dSmrg                    int i;
217275ebec6dSmrg                    int *fd = (int *) CMSG_DATA(hdr);
217375ebec6dSmrg
217475ebec6dSmrg                    for (i = 0; i < nfd; i++)
217575ebec6dSmrg                        appendFd(&ciptr->recv_fds, fd[i], 0);
217675ebec6dSmrg                }
217775ebec6dSmrg            }
217875ebec6dSmrg        }
217975ebec6dSmrg        return size;
218075ebec6dSmrg    }
218175ebec6dSmrg#else
218273143b9aSmrg    return READV (ciptr, buf, size);
218375ebec6dSmrg#endif
218473143b9aSmrg}
218573143b9aSmrg
218673143b9aSmrg
218773143b9aSmrgstatic int
218873143b9aSmrgTRANS(SocketWritev) (XtransConnInfo ciptr, struct iovec *buf, int size)
218973143b9aSmrg
219073143b9aSmrg{
2191fe567363Smrg    prmsg (2,"SocketWritev(%d,%p,%d)\n", ciptr->fd, buf, size);
219273143b9aSmrg
219375ebec6dSmrg#if XTRANS_SEND_FDS
219475ebec6dSmrg    if (ciptr->send_fds)
219575ebec6dSmrg    {
219675ebec6dSmrg        union fd_pass           cmsgbuf;
219775ebec6dSmrg        int                     nfd = nFd(&ciptr->send_fds);
219875ebec6dSmrg        struct _XtransConnFd    *cf = ciptr->send_fds;
219975ebec6dSmrg        struct msghdr           msg = {
220075ebec6dSmrg            .msg_name = NULL,
220175ebec6dSmrg            .msg_namelen = 0,
220275ebec6dSmrg            .msg_iov = buf,
220375ebec6dSmrg            .msg_iovlen = size,
220475ebec6dSmrg            .msg_control = cmsgbuf.buf,
220575ebec6dSmrg            .msg_controllen = CMSG_LEN(nfd * sizeof(int))
220675ebec6dSmrg        };
220775ebec6dSmrg        struct cmsghdr          *hdr = CMSG_FIRSTHDR(&msg);
220875ebec6dSmrg        int                     i;
220975ebec6dSmrg        int                     *fds;
221075ebec6dSmrg
221175ebec6dSmrg        hdr->cmsg_len = msg.msg_controllen;
221275ebec6dSmrg        hdr->cmsg_level = SOL_SOCKET;
221375ebec6dSmrg        hdr->cmsg_type = SCM_RIGHTS;
221475ebec6dSmrg
221575ebec6dSmrg        fds = (int *) CMSG_DATA(hdr);
221675ebec6dSmrg        /* Set up fds */
221775ebec6dSmrg        for (i = 0; i < nfd; i++) {
221875ebec6dSmrg            fds[i] = cf->fd;
221975ebec6dSmrg            cf = cf->next;
222075ebec6dSmrg        }
222175ebec6dSmrg
222275ebec6dSmrg        i = sendmsg(ciptr->fd, &msg, 0);
222375ebec6dSmrg        if (i > 0)
222475ebec6dSmrg            discardFd(&ciptr->send_fds, cf, 0);
222575ebec6dSmrg        return i;
222675ebec6dSmrg    }
222775ebec6dSmrg#endif
222873143b9aSmrg    return WRITEV (ciptr, buf, size);
222973143b9aSmrg}
223073143b9aSmrg
223173143b9aSmrg
223275ebec6dSmrgstatic int
223375ebec6dSmrgTRANS(SocketWrite) (XtransConnInfo ciptr, char *buf, int size)
223475ebec6dSmrg
223575ebec6dSmrg{
223675ebec6dSmrg    prmsg (2,"SocketWrite(%d,%p,%d)\n", ciptr->fd, buf, size);
223775ebec6dSmrg
223875ebec6dSmrg#if defined(WIN32)
223975ebec6dSmrg    {
224075ebec6dSmrg	int ret = send ((SOCKET)ciptr->fd, buf, size, 0);
224175ebec6dSmrg#ifdef WIN32
224275ebec6dSmrg	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
224375ebec6dSmrg#endif
224475ebec6dSmrg	return ret;
224575ebec6dSmrg    }
224675ebec6dSmrg#else
224775ebec6dSmrg#if XTRANS_SEND_FDS
224875ebec6dSmrg    if (ciptr->send_fds)
224975ebec6dSmrg    {
225075ebec6dSmrg        struct iovec            iov;
225175ebec6dSmrg
225275ebec6dSmrg        iov.iov_base = buf;
225375ebec6dSmrg        iov.iov_len = size;
225475ebec6dSmrg        return TRANS(SocketWritev)(ciptr, &iov, 1);
225575ebec6dSmrg    }
225675ebec6dSmrg#endif /* XTRANS_SEND_FDS */
225775ebec6dSmrg    return write (ciptr->fd, buf, size);
225875ebec6dSmrg#endif /* WIN32 */
225975ebec6dSmrg}
226075ebec6dSmrg
226173143b9aSmrgstatic int
226273143b9aSmrgTRANS(SocketDisconnect) (XtransConnInfo ciptr)
226373143b9aSmrg
226473143b9aSmrg{
2265fe567363Smrg    prmsg (2,"SocketDisconnect(%p,%d)\n", ciptr, ciptr->fd);
226673143b9aSmrg
226773143b9aSmrg#ifdef WIN32
2268fe567363Smrg    {
226973143b9aSmrg	int ret = shutdown (ciptr->fd, 2);
227073143b9aSmrg	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
227173143b9aSmrg	return ret;
227273143b9aSmrg    }
227373143b9aSmrg#else
227473143b9aSmrg    return shutdown (ciptr->fd, 2); /* disallow further sends and receives */
227573143b9aSmrg#endif
227673143b9aSmrg}
227773143b9aSmrg
227873143b9aSmrg
227973143b9aSmrg#ifdef TCPCONN
228073143b9aSmrgstatic int
228173143b9aSmrgTRANS(SocketINETClose) (XtransConnInfo ciptr)
228273143b9aSmrg
228373143b9aSmrg{
2284fe567363Smrg    prmsg (2,"SocketINETClose(%p,%d)\n", ciptr, ciptr->fd);
228573143b9aSmrg
228673143b9aSmrg#ifdef WIN32
228773143b9aSmrg    {
228873143b9aSmrg	int ret = close (ciptr->fd);
228973143b9aSmrg	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
229073143b9aSmrg	return ret;
229173143b9aSmrg    }
229273143b9aSmrg#else
229373143b9aSmrg    return close (ciptr->fd);
229473143b9aSmrg#endif
229573143b9aSmrg}
229673143b9aSmrg
229773143b9aSmrg#endif /* TCPCONN */
229873143b9aSmrg
229973143b9aSmrg
230073143b9aSmrg#ifdef UNIXCONN
230173143b9aSmrgstatic int
230273143b9aSmrgTRANS(SocketUNIXClose) (XtransConnInfo ciptr)
230373143b9aSmrg{
230473143b9aSmrg    /*
230573143b9aSmrg     * If this is the server side, then once the socket is closed,
230673143b9aSmrg     * it must be unlinked to completely close it
230773143b9aSmrg     */
230873143b9aSmrg
230973143b9aSmrg    struct sockaddr_un	*sockname = (struct sockaddr_un *) ciptr->addr;
231073143b9aSmrg    int ret;
231173143b9aSmrg
2312fe567363Smrg    prmsg (2,"SocketUNIXClose(%p,%d)\n", ciptr, ciptr->fd);
231373143b9aSmrg
231475ebec6dSmrg#if XTRANS_SEND_FDS
231575ebec6dSmrg    cleanupFds(ciptr);
231675ebec6dSmrg#endif
231773143b9aSmrg    ret = close(ciptr->fd);
231873143b9aSmrg
231973143b9aSmrg    if (ciptr->flags
232073143b9aSmrg       && sockname
232173143b9aSmrg       && sockname->sun_family == AF_UNIX
232273143b9aSmrg       && sockname->sun_path[0])
232373143b9aSmrg    {
232473143b9aSmrg	if (!(ciptr->flags & TRANS_NOUNLINK
232573143b9aSmrg	    || ciptr->transptr->flags & TRANS_ABSTRACT))
232673143b9aSmrg		unlink (sockname->sun_path);
232773143b9aSmrg    }
232873143b9aSmrg
232973143b9aSmrg    return ret;
233073143b9aSmrg}
233173143b9aSmrg
233273143b9aSmrgstatic int
233373143b9aSmrgTRANS(SocketUNIXCloseForCloning) (XtransConnInfo ciptr)
233473143b9aSmrg
233573143b9aSmrg{
233673143b9aSmrg    /*
233773143b9aSmrg     * Don't unlink path.
233873143b9aSmrg     */
233973143b9aSmrg
234073143b9aSmrg    int ret;
234173143b9aSmrg
2342fe567363Smrg    prmsg (2,"SocketUNIXCloseForCloning(%p,%d)\n",
2343fe567363Smrg	ciptr, ciptr->fd);
234473143b9aSmrg
234575ebec6dSmrg#if XTRANS_SEND_FDS
234675ebec6dSmrg    cleanupFds(ciptr);
234775ebec6dSmrg#endif
234873143b9aSmrg    ret = close(ciptr->fd);
234973143b9aSmrg
235073143b9aSmrg    return ret;
235173143b9aSmrg}
235273143b9aSmrg
235373143b9aSmrg#endif /* UNIXCONN */
235473143b9aSmrg
235573143b9aSmrg
235673143b9aSmrg#ifdef TCPCONN
235773143b9aSmrg# ifdef TRANS_SERVER
2358fe567363Smrgstatic const char* tcp_nolisten[] = {
235973143b9aSmrg	"inet",
236073143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
236173143b9aSmrg	"inet6",
236273143b9aSmrg#endif
236373143b9aSmrg	NULL
236473143b9aSmrg};
236573143b9aSmrg# endif
236673143b9aSmrg
236773143b9aSmrgXtransport	TRANS(SocketTCPFuncs) = {
236873143b9aSmrg	/* Socket Interface */
236973143b9aSmrg	"tcp",
237073143b9aSmrg        TRANS_ALIAS,
237173143b9aSmrg#ifdef TRANS_CLIENT
237273143b9aSmrg	TRANS(SocketOpenCOTSClient),
237373143b9aSmrg#endif /* TRANS_CLIENT */
237473143b9aSmrg#ifdef TRANS_SERVER
237573143b9aSmrg	tcp_nolisten,
237673143b9aSmrg	TRANS(SocketOpenCOTSServer),
237773143b9aSmrg#endif /* TRANS_SERVER */
237873143b9aSmrg#ifdef TRANS_REOPEN
237973143b9aSmrg	TRANS(SocketReopenCOTSServer),
238073143b9aSmrg#endif
238173143b9aSmrg	TRANS(SocketSetOption),
238273143b9aSmrg#ifdef TRANS_SERVER
238373143b9aSmrg	TRANS(SocketINETCreateListener),
238473143b9aSmrg	NULL,		       			/* ResetListener */
238573143b9aSmrg	TRANS(SocketINETAccept),
238673143b9aSmrg#endif /* TRANS_SERVER */
238773143b9aSmrg#ifdef TRANS_CLIENT
238873143b9aSmrg	TRANS(SocketINETConnect),
238973143b9aSmrg#endif /* TRANS_CLIENT */
239073143b9aSmrg	TRANS(SocketBytesReadable),
239173143b9aSmrg	TRANS(SocketRead),
239273143b9aSmrg	TRANS(SocketWrite),
239373143b9aSmrg	TRANS(SocketReadv),
239473143b9aSmrg	TRANS(SocketWritev),
239575ebec6dSmrg#if XTRANS_SEND_FDS
239675ebec6dSmrg        TRANS(SocketSendFdInvalid),
239775ebec6dSmrg        TRANS(SocketRecvFdInvalid),
239875ebec6dSmrg#endif
239973143b9aSmrg	TRANS(SocketDisconnect),
240073143b9aSmrg	TRANS(SocketINETClose),
240173143b9aSmrg	TRANS(SocketINETClose),
240273143b9aSmrg	};
240373143b9aSmrg
240473143b9aSmrgXtransport	TRANS(SocketINETFuncs) = {
240573143b9aSmrg	/* Socket Interface */
240673143b9aSmrg	"inet",
240773143b9aSmrg	0,
240873143b9aSmrg#ifdef TRANS_CLIENT
240973143b9aSmrg	TRANS(SocketOpenCOTSClient),
241073143b9aSmrg#endif /* TRANS_CLIENT */
241173143b9aSmrg#ifdef TRANS_SERVER
241273143b9aSmrg	NULL,
241373143b9aSmrg	TRANS(SocketOpenCOTSServer),
241473143b9aSmrg#endif /* TRANS_SERVER */
241573143b9aSmrg#ifdef TRANS_REOPEN
241673143b9aSmrg	TRANS(SocketReopenCOTSServer),
241773143b9aSmrg#endif
241873143b9aSmrg	TRANS(SocketSetOption),
241973143b9aSmrg#ifdef TRANS_SERVER
242073143b9aSmrg	TRANS(SocketINETCreateListener),
242173143b9aSmrg	NULL,		       			/* ResetListener */
242273143b9aSmrg	TRANS(SocketINETAccept),
242373143b9aSmrg#endif /* TRANS_SERVER */
242473143b9aSmrg#ifdef TRANS_CLIENT
242573143b9aSmrg	TRANS(SocketINETConnect),
242673143b9aSmrg#endif /* TRANS_CLIENT */
242773143b9aSmrg	TRANS(SocketBytesReadable),
242873143b9aSmrg	TRANS(SocketRead),
242973143b9aSmrg	TRANS(SocketWrite),
243073143b9aSmrg	TRANS(SocketReadv),
243173143b9aSmrg	TRANS(SocketWritev),
243275ebec6dSmrg#if XTRANS_SEND_FDS
243375ebec6dSmrg        TRANS(SocketSendFdInvalid),
243475ebec6dSmrg        TRANS(SocketRecvFdInvalid),
243575ebec6dSmrg#endif
243673143b9aSmrg	TRANS(SocketDisconnect),
243773143b9aSmrg	TRANS(SocketINETClose),
243873143b9aSmrg	TRANS(SocketINETClose),
243973143b9aSmrg	};
244073143b9aSmrg
244173143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
244273143b9aSmrgXtransport     TRANS(SocketINET6Funcs) = {
244373143b9aSmrg	/* Socket Interface */
244473143b9aSmrg	"inet6",
244573143b9aSmrg	0,
244673143b9aSmrg#ifdef TRANS_CLIENT
244773143b9aSmrg	TRANS(SocketOpenCOTSClient),
244873143b9aSmrg#endif /* TRANS_CLIENT */
244973143b9aSmrg#ifdef TRANS_SERVER
245073143b9aSmrg	NULL,
245173143b9aSmrg	TRANS(SocketOpenCOTSServer),
245273143b9aSmrg#endif /* TRANS_SERVER */
245373143b9aSmrg#ifdef TRANS_REOPEN
245473143b9aSmrg	TRANS(SocketReopenCOTSServer),
245573143b9aSmrg#endif
245673143b9aSmrg	TRANS(SocketSetOption),
245773143b9aSmrg#ifdef TRANS_SERVER
245873143b9aSmrg	TRANS(SocketINETCreateListener),
245973143b9aSmrg	NULL,					/* ResetListener */
246073143b9aSmrg	TRANS(SocketINETAccept),
246173143b9aSmrg#endif /* TRANS_SERVER */
246273143b9aSmrg#ifdef TRANS_CLIENT
246373143b9aSmrg	TRANS(SocketINETConnect),
246473143b9aSmrg#endif /* TRANS_CLIENT */
246573143b9aSmrg	TRANS(SocketBytesReadable),
246673143b9aSmrg	TRANS(SocketRead),
246773143b9aSmrg	TRANS(SocketWrite),
246873143b9aSmrg	TRANS(SocketReadv),
246973143b9aSmrg	TRANS(SocketWritev),
247075ebec6dSmrg#if XTRANS_SEND_FDS
247175ebec6dSmrg        TRANS(SocketSendFdInvalid),
247275ebec6dSmrg        TRANS(SocketRecvFdInvalid),
247375ebec6dSmrg#endif
247473143b9aSmrg	TRANS(SocketDisconnect),
247573143b9aSmrg	TRANS(SocketINETClose),
247673143b9aSmrg	TRANS(SocketINETClose),
247773143b9aSmrg	};
247873143b9aSmrg#endif /* IPv6 */
247973143b9aSmrg#endif /* TCPCONN */
248073143b9aSmrg
248173143b9aSmrg#ifdef UNIXCONN
248273143b9aSmrg#if !defined(LOCALCONN)
248373143b9aSmrgXtransport	TRANS(SocketLocalFuncs) = {
248473143b9aSmrg	/* Socket Interface */
248573143b9aSmrg	"local",
248673143b9aSmrg#ifdef HAVE_ABSTRACT_SOCKETS
248773143b9aSmrg	TRANS_ABSTRACT,
248873143b9aSmrg#else
248973143b9aSmrg	0,
249073143b9aSmrg#endif
249173143b9aSmrg#ifdef TRANS_CLIENT
249273143b9aSmrg	TRANS(SocketOpenCOTSClient),
249373143b9aSmrg#endif /* TRANS_CLIENT */
249473143b9aSmrg#ifdef TRANS_SERVER
249573143b9aSmrg	NULL,
249673143b9aSmrg	TRANS(SocketOpenCOTSServer),
249773143b9aSmrg#endif /* TRANS_SERVER */
249873143b9aSmrg#ifdef TRANS_REOPEN
249973143b9aSmrg	TRANS(SocketReopenCOTSServer),
250073143b9aSmrg#endif
250173143b9aSmrg	TRANS(SocketSetOption),
250273143b9aSmrg#ifdef TRANS_SERVER
250373143b9aSmrg	TRANS(SocketUNIXCreateListener),
250473143b9aSmrg	TRANS(SocketUNIXResetListener),
250573143b9aSmrg	TRANS(SocketUNIXAccept),
250673143b9aSmrg#endif /* TRANS_SERVER */
250773143b9aSmrg#ifdef TRANS_CLIENT
250873143b9aSmrg	TRANS(SocketUNIXConnect),
250973143b9aSmrg#endif /* TRANS_CLIENT */
251073143b9aSmrg	TRANS(SocketBytesReadable),
251173143b9aSmrg	TRANS(SocketRead),
251273143b9aSmrg	TRANS(SocketWrite),
251373143b9aSmrg	TRANS(SocketReadv),
251473143b9aSmrg	TRANS(SocketWritev),
251575ebec6dSmrg#if XTRANS_SEND_FDS
251675ebec6dSmrg        TRANS(SocketSendFd),
251775ebec6dSmrg        TRANS(SocketRecvFd),
251875ebec6dSmrg#endif
251973143b9aSmrg	TRANS(SocketDisconnect),
252073143b9aSmrg	TRANS(SocketUNIXClose),
252173143b9aSmrg	TRANS(SocketUNIXCloseForCloning),
252273143b9aSmrg	};
252373143b9aSmrg#endif /* !LOCALCONN */
252473143b9aSmrg# ifdef TRANS_SERVER
252573143b9aSmrg#  if !defined(LOCALCONN)
252675ebec6dSmrgstatic const char* unix_nolisten[] = { "local" , NULL };
252773143b9aSmrg#  endif
252873143b9aSmrg# endif
2529fe567363Smrg
253073143b9aSmrgXtransport	TRANS(SocketUNIXFuncs) = {
253173143b9aSmrg	/* Socket Interface */
253273143b9aSmrg	"unix",
253373143b9aSmrg#if !defined(LOCALCONN) && !defined(HAVE_ABSTRACT_SOCKETS)
253473143b9aSmrg        TRANS_ALIAS,
253573143b9aSmrg#else
253673143b9aSmrg	0,
253773143b9aSmrg#endif
253873143b9aSmrg#ifdef TRANS_CLIENT
253973143b9aSmrg	TRANS(SocketOpenCOTSClient),
254073143b9aSmrg#endif /* TRANS_CLIENT */
254173143b9aSmrg#ifdef TRANS_SERVER
254273143b9aSmrg#if !defined(LOCALCONN)
254373143b9aSmrg	unix_nolisten,
254473143b9aSmrg#else
254573143b9aSmrg	NULL,
254673143b9aSmrg#endif
254773143b9aSmrg	TRANS(SocketOpenCOTSServer),
254873143b9aSmrg#endif /* TRANS_SERVER */
254973143b9aSmrg#ifdef TRANS_REOPEN
255073143b9aSmrg	TRANS(SocketReopenCOTSServer),
255173143b9aSmrg#endif
255273143b9aSmrg	TRANS(SocketSetOption),
255373143b9aSmrg#ifdef TRANS_SERVER
255473143b9aSmrg	TRANS(SocketUNIXCreateListener),
255573143b9aSmrg	TRANS(SocketUNIXResetListener),
255673143b9aSmrg	TRANS(SocketUNIXAccept),
255773143b9aSmrg#endif /* TRANS_SERVER */
255873143b9aSmrg#ifdef TRANS_CLIENT
255973143b9aSmrg	TRANS(SocketUNIXConnect),
256073143b9aSmrg#endif /* TRANS_CLIENT */
256173143b9aSmrg	TRANS(SocketBytesReadable),
256273143b9aSmrg	TRANS(SocketRead),
256373143b9aSmrg	TRANS(SocketWrite),
256473143b9aSmrg	TRANS(SocketReadv),
256573143b9aSmrg	TRANS(SocketWritev),
256675ebec6dSmrg#if XTRANS_SEND_FDS
256775ebec6dSmrg        TRANS(SocketSendFd),
256875ebec6dSmrg        TRANS(SocketRecvFd),
256975ebec6dSmrg#endif
257073143b9aSmrg	TRANS(SocketDisconnect),
257173143b9aSmrg	TRANS(SocketUNIXClose),
257273143b9aSmrg	TRANS(SocketUNIXCloseForCloning),
257373143b9aSmrg	};
257473143b9aSmrg
257573143b9aSmrg#endif /* UNIXCONN */
2576