Xtranssock.c revision a773ec55
1af928962Smrg/*
2a773ec55Smrg * Copyright (c) 2002, Oracle and/or its affiliates.
3af928962Smrg *
4af928962Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5af928962Smrg * copy of this software and associated documentation files (the "Software"),
6af928962Smrg * to deal in the Software without restriction, including without limitation
7af928962Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8af928962Smrg * and/or sell copies of the Software, and to permit persons to whom the
9af928962Smrg * Software is furnished to do so, subject to the following conditions:
10af928962Smrg *
11af928962Smrg * The above copyright notice and this permission notice (including the next
12af928962Smrg * paragraph) shall be included in all copies or substantial portions of the
13af928962Smrg * Software.
14af928962Smrg *
15af928962Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16af928962Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17af928962Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18af928962Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19af928962Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20af928962Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21af928962Smrg * DEALINGS IN THE SOFTWARE.
22af928962Smrg */
2373143b9aSmrg/*
2473143b9aSmrg
2573143b9aSmrgCopyright 1993, 1994, 1998  The Open Group
2673143b9aSmrg
2773143b9aSmrgPermission to use, copy, modify, distribute, and sell this software and its
2873143b9aSmrgdocumentation for any purpose is hereby granted without fee, provided that
2973143b9aSmrgthe above copyright notice appear in all copies and that both that
3073143b9aSmrgcopyright notice and this permission notice appear in supporting
3173143b9aSmrgdocumentation.
3273143b9aSmrg
3373143b9aSmrgThe above copyright notice and this permission notice shall be included
3473143b9aSmrgin all copies or substantial portions of the Software.
3573143b9aSmrg
3673143b9aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
3773143b9aSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
3873143b9aSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
3973143b9aSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
4073143b9aSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
4173143b9aSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
4273143b9aSmrgOTHER DEALINGS IN THE SOFTWARE.
4373143b9aSmrg
4473143b9aSmrgExcept as contained in this notice, the name of the copyright holders shall
4573143b9aSmrgnot be used in advertising or otherwise to promote the sale, use or
4673143b9aSmrgother dealings in this Software without prior written authorization
4773143b9aSmrgfrom the copyright holders.
4873143b9aSmrg
4973143b9aSmrg * Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA
5073143b9aSmrg *
5173143b9aSmrg * All Rights Reserved
5273143b9aSmrg *
5373143b9aSmrg * Permission to use, copy, modify, and distribute this software and its
5473143b9aSmrg * documentation for any purpose and without fee is hereby granted, provided
5573143b9aSmrg * that the above copyright notice appear in all copies and that both that
5673143b9aSmrg * copyright notice and this permission notice appear in supporting
5773143b9aSmrg * documentation, and that the name NCR not be used in advertising
5873143b9aSmrg * or publicity pertaining to distribution of the software without specific,
5973143b9aSmrg * written prior permission.  NCR makes no representations about the
6073143b9aSmrg * suitability of this software for any purpose.  It is provided "as is"
6173143b9aSmrg * without express or implied warranty.
6273143b9aSmrg *
6373143b9aSmrg * NCR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
6473143b9aSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
6573143b9aSmrg * NO EVENT SHALL NCR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
6673143b9aSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
6773143b9aSmrg * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
6873143b9aSmrg * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
6973143b9aSmrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
7073143b9aSmrg */
7173143b9aSmrg
7273143b9aSmrg#include <ctype.h>
7373143b9aSmrg#ifdef XTHREADS
7473143b9aSmrg#include <X11/Xthreads.h>
7573143b9aSmrg#endif
7673143b9aSmrg
7773143b9aSmrg#ifndef WIN32
7873143b9aSmrg
7973143b9aSmrg#if defined(TCPCONN) || defined(UNIXCONN)
8073143b9aSmrg#include <sys/socket.h>
8173143b9aSmrg#include <netinet/in.h>
8273143b9aSmrg#include <arpa/inet.h>
8373143b9aSmrg#endif
8473143b9aSmrg
8573143b9aSmrg#if defined(TCPCONN) || defined(UNIXCONN)
8673143b9aSmrg#define X_INCLUDE_NETDB_H
8773143b9aSmrg#define XOS_USE_NO_LOCKING
8873143b9aSmrg#include <X11/Xos_r.h>
8973143b9aSmrg#endif
9073143b9aSmrg
9173143b9aSmrg#ifdef UNIXCONN
9273143b9aSmrg#ifndef X_NO_SYS_UN
9373143b9aSmrg#include <sys/un.h>
9473143b9aSmrg#endif
9573143b9aSmrg#include <sys/stat.h>
9673143b9aSmrg#endif
9773143b9aSmrg
9873143b9aSmrg
9973143b9aSmrg#ifndef NO_TCP_H
100fe567363Smrg#if defined(linux) || defined(__GLIBC__)
10173143b9aSmrg#include <sys/param.h>
10273143b9aSmrg#endif /* osf */
10373143b9aSmrg#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
10473143b9aSmrg#include <sys/param.h>
10573143b9aSmrg#include <machine/endian.h>
10673143b9aSmrg#endif /* __NetBSD__ || __OpenBSD__ || __FreeBSD__ || __DragonFly__ */
10773143b9aSmrg#include <netinet/tcp.h>
10873143b9aSmrg#endif /* !NO_TCP_H */
10973143b9aSmrg
11073143b9aSmrg#include <sys/ioctl.h>
111e8a71cdfSmrg#if defined(SVR4) || defined(__SVR4)
11273143b9aSmrg#include <sys/filio.h>
11373143b9aSmrg#endif
11473143b9aSmrg
1158d4c0f7bSmrg#include <unistd.h>
1168d4c0f7bSmrg
11773143b9aSmrg#else /* !WIN32 */
11873143b9aSmrg
11973143b9aSmrg#include <X11/Xwinsock.h>
12073143b9aSmrg#include <X11/Xwindows.h>
12173143b9aSmrg#include <X11/Xw32defs.h>
12273143b9aSmrg#undef close
12373143b9aSmrg#define close closesocket
12473143b9aSmrg#define ECONNREFUSED WSAECONNREFUSED
12573143b9aSmrg#define EADDRINUSE WSAEADDRINUSE
12673143b9aSmrg#define EPROTOTYPE WSAEPROTOTYPE
12773143b9aSmrg#undef EWOULDBLOCK
12873143b9aSmrg#define EWOULDBLOCK WSAEWOULDBLOCK
12973143b9aSmrg#define EINPROGRESS WSAEINPROGRESS
13073143b9aSmrg#undef EINTR
13173143b9aSmrg#define EINTR WSAEINTR
13273143b9aSmrg#define X_INCLUDE_NETDB_H
13373143b9aSmrg#define XOS_USE_MTSAFE_NETDBAPI
13473143b9aSmrg#include <X11/Xos_r.h>
13573143b9aSmrg#endif /* WIN32 */
13673143b9aSmrg
13773143b9aSmrg#if defined(SO_DONTLINGER) && defined(SO_LINGER)
13873143b9aSmrg#undef SO_DONTLINGER
13973143b9aSmrg#endif
14073143b9aSmrg
14173143b9aSmrg/* others don't need this */
14273143b9aSmrg#define SocketInitOnce() /**/
14373143b9aSmrg
144a773ec55Smrg#ifdef __linux__
14573143b9aSmrg#define HAVE_ABSTRACT_SOCKETS
14673143b9aSmrg#endif
14773143b9aSmrg
14873143b9aSmrg#define MIN_BACKLOG 128
14973143b9aSmrg#ifdef SOMAXCONN
15073143b9aSmrg#if SOMAXCONN > MIN_BACKLOG
15173143b9aSmrg#define BACKLOG SOMAXCONN
15273143b9aSmrg#endif
15373143b9aSmrg#endif
15473143b9aSmrg#ifndef BACKLOG
15573143b9aSmrg#define BACKLOG MIN_BACKLOG
15673143b9aSmrg#endif
15773143b9aSmrg
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
199a773ec55Smrg#if defined(TCPCONN) || defined(TRANS_REOPEN)
200a773ec55Smrgstatic int
201a773ec55Smrgis_numeric (const char *str)
202a773ec55Smrg{
203a773ec55Smrg    int i;
204a773ec55Smrg
205a773ec55Smrg    for (i = 0; i < (int) strlen (str); i++)
206a773ec55Smrg	if (!isdigit (str[i]))
207a773ec55Smrg	    return (0);
208a773ec55Smrg
209a773ec55Smrg    return (1);
210a773ec55Smrg}
211a773ec55Smrg#endif
212a773ec55Smrg
21373143b9aSmrg#ifdef UNIXCONN
21473143b9aSmrg
21573143b9aSmrg
21673143b9aSmrg#if defined(X11_t)
21773143b9aSmrg#define UNIX_PATH "/tmp/.X11-unix/X"
21873143b9aSmrg#define UNIX_DIR "/tmp/.X11-unix"
21973143b9aSmrg#endif /* X11_t */
22073143b9aSmrg#if defined(XIM_t)
22173143b9aSmrg#define UNIX_PATH "/tmp/.XIM-unix/XIM"
22273143b9aSmrg#define UNIX_DIR "/tmp/.XIM-unix"
22373143b9aSmrg#endif /* XIM_t */
22473143b9aSmrg#if defined(FS_t) || defined(FONT_t)
22573143b9aSmrg#define UNIX_PATH "/tmp/.font-unix/fs"
22673143b9aSmrg#define UNIX_DIR "/tmp/.font-unix"
22773143b9aSmrg#endif /* FS_t || FONT_t */
22873143b9aSmrg#if defined(ICE_t)
22973143b9aSmrg#define UNIX_PATH "/tmp/.ICE-unix/"
23073143b9aSmrg#define UNIX_DIR "/tmp/.ICE-unix"
23173143b9aSmrg#endif /* ICE_t */
23273143b9aSmrg
23373143b9aSmrg
23473143b9aSmrg#endif /* UNIXCONN */
23573143b9aSmrg
23673143b9aSmrg#define PORTBUFSIZE	32
23773143b9aSmrg
23873143b9aSmrg#ifndef MAXHOSTNAMELEN
23973143b9aSmrg#define MAXHOSTNAMELEN 255
24073143b9aSmrg#endif
24173143b9aSmrg
24273143b9aSmrg#if defined HAVE_SOCKLEN_T || (defined(IPv6) && defined(AF_INET6))
24373143b9aSmrg# define SOCKLEN_T socklen_t
244a773ec55Smrg#elif defined(SVR4) || defined(__SVR4)
245fe567363Smrg# define SOCKLEN_T size_t
24673143b9aSmrg#else
24773143b9aSmrg# define SOCKLEN_T int
24873143b9aSmrg#endif
24973143b9aSmrg
25073143b9aSmrg/*
25173143b9aSmrg * These are some utility function used by the real interface function below.
25273143b9aSmrg */
25373143b9aSmrg
25473143b9aSmrgstatic int
255fe567363SmrgTRANS(SocketSelectFamily) (int first, const char *family)
25673143b9aSmrg
25773143b9aSmrg{
25873143b9aSmrg    int     i;
25973143b9aSmrg
260fe567363Smrg    prmsg (3,"SocketSelectFamily(%s)\n", family);
26173143b9aSmrg
26273143b9aSmrg    for (i = first + 1; i < NUMSOCKETFAMILIES;i++)
26373143b9aSmrg    {
26473143b9aSmrg        if (!strcmp (family, Sockettrans2devtab[i].transname))
26573143b9aSmrg	    return i;
26673143b9aSmrg    }
26773143b9aSmrg
26873143b9aSmrg    return (first == -1 ? -2 : -1);
26973143b9aSmrg}
27073143b9aSmrg
27173143b9aSmrg
27273143b9aSmrg/*
27373143b9aSmrg * This function gets the local address of the socket and stores it in the
27473143b9aSmrg * XtransConnInfo structure for the connection.
27573143b9aSmrg */
27673143b9aSmrg
27773143b9aSmrgstatic int
27873143b9aSmrgTRANS(SocketINETGetAddr) (XtransConnInfo ciptr)
27973143b9aSmrg
28073143b9aSmrg{
28173143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
28273143b9aSmrg    struct sockaddr_storage socknamev6;
283b53e5eeaSmrg#else
28473143b9aSmrg    struct sockaddr_in socknamev4;
285b53e5eeaSmrg#endif
28673143b9aSmrg    void *socknamePtr;
28773143b9aSmrg    SOCKLEN_T namelen;
28873143b9aSmrg
289fe567363Smrg    prmsg (3,"SocketINETGetAddr(%p)\n", ciptr);
29073143b9aSmrg
29173143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
292b53e5eeaSmrg    namelen = sizeof(socknamev6);
293b53e5eeaSmrg    socknamePtr = &socknamev6;
294b53e5eeaSmrg#else
295b53e5eeaSmrg    namelen = sizeof(socknamev4);
296b53e5eeaSmrg    socknamePtr = &socknamev4;
29773143b9aSmrg#endif
29873143b9aSmrg
29973143b9aSmrg    bzero(socknamePtr, namelen);
300fe567363Smrg
30173143b9aSmrg    if (getsockname (ciptr->fd,(struct sockaddr *) socknamePtr,
30273143b9aSmrg		     (void *)&namelen) < 0)
30373143b9aSmrg    {
30473143b9aSmrg#ifdef WIN32
30573143b9aSmrg	errno = WSAGetLastError();
30673143b9aSmrg#endif
307fe567363Smrg	prmsg (1,"SocketINETGetAddr: getsockname() failed: %d\n",
308fe567363Smrg	    EGET());
30973143b9aSmrg	return -1;
31073143b9aSmrg    }
31173143b9aSmrg
31273143b9aSmrg    /*
31373143b9aSmrg     * Everything looks good: fill in the XtransConnInfo structure.
31473143b9aSmrg     */
31573143b9aSmrg
316fe567363Smrg    if ((ciptr->addr = malloc (namelen)) == NULL)
31773143b9aSmrg    {
318fe567363Smrg        prmsg (1,
319fe567363Smrg	    "SocketINETGetAddr: Can't allocate space for the addr\n");
32073143b9aSmrg        return -1;
32173143b9aSmrg    }
32273143b9aSmrg
32373143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
324b53e5eeaSmrg    ciptr->family = ((struct sockaddr *)socknamePtr)->sa_family;
325b53e5eeaSmrg#else
326b53e5eeaSmrg    ciptr->family = socknamev4.sin_family;
32773143b9aSmrg#endif
32873143b9aSmrg    ciptr->addrlen = namelen;
32973143b9aSmrg    memcpy (ciptr->addr, socknamePtr, ciptr->addrlen);
33073143b9aSmrg
33173143b9aSmrg    return 0;
33273143b9aSmrg}
33373143b9aSmrg
33473143b9aSmrg
33573143b9aSmrg/*
33673143b9aSmrg * This function gets the remote address of the socket and stores it in the
33773143b9aSmrg * XtransConnInfo structure for the connection.
33873143b9aSmrg */
33973143b9aSmrg
34073143b9aSmrgstatic int
34173143b9aSmrgTRANS(SocketINETGetPeerAddr) (XtransConnInfo ciptr)
34273143b9aSmrg
34373143b9aSmrg{
34473143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
34573143b9aSmrg    struct sockaddr_storage socknamev6;
34673143b9aSmrg#endif
34773143b9aSmrg    struct sockaddr_in 	socknamev4;
34873143b9aSmrg    void *socknamePtr;
34973143b9aSmrg    SOCKLEN_T namelen;
35073143b9aSmrg
35173143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
352b53e5eeaSmrg    if (ciptr->family == AF_INET6)
35373143b9aSmrg    {
35473143b9aSmrg	namelen = sizeof(socknamev6);
35573143b9aSmrg	socknamePtr = &socknamev6;
35673143b9aSmrg    }
35773143b9aSmrg    else
35873143b9aSmrg#endif
35973143b9aSmrg    {
36073143b9aSmrg	namelen = sizeof(socknamev4);
36173143b9aSmrg	socknamePtr = &socknamev4;
36273143b9aSmrg    }
36373143b9aSmrg
36473143b9aSmrg    bzero(socknamePtr, namelen);
365fe567363Smrg
366fe567363Smrg    prmsg (3,"SocketINETGetPeerAddr(%p)\n", ciptr);
36773143b9aSmrg
36873143b9aSmrg    if (getpeername (ciptr->fd, (struct sockaddr *) socknamePtr,
36973143b9aSmrg		     (void *)&namelen) < 0)
37073143b9aSmrg    {
37173143b9aSmrg#ifdef WIN32
37273143b9aSmrg	errno = WSAGetLastError();
37373143b9aSmrg#endif
374fe567363Smrg	prmsg (1,"SocketINETGetPeerAddr: getpeername() failed: %d\n",
375fe567363Smrg	    EGET());
37673143b9aSmrg	return -1;
37773143b9aSmrg    }
37873143b9aSmrg
37973143b9aSmrg    /*
38073143b9aSmrg     * Everything looks good: fill in the XtransConnInfo structure.
38173143b9aSmrg     */
38273143b9aSmrg
383fe567363Smrg    if ((ciptr->peeraddr = malloc (namelen)) == NULL)
38473143b9aSmrg    {
385fe567363Smrg        prmsg (1,
386fe567363Smrg	   "SocketINETGetPeerAddr: Can't allocate space for the addr\n");
38773143b9aSmrg        return -1;
38873143b9aSmrg    }
38973143b9aSmrg
39073143b9aSmrg    ciptr->peeraddrlen = namelen;
39173143b9aSmrg    memcpy (ciptr->peeraddr, socknamePtr, ciptr->peeraddrlen);
39273143b9aSmrg
39373143b9aSmrg    return 0;
39473143b9aSmrg}
39573143b9aSmrg
39673143b9aSmrg
39773143b9aSmrgstatic XtransConnInfo
39873143b9aSmrgTRANS(SocketOpen) (int i, int type)
39973143b9aSmrg
40073143b9aSmrg{
40173143b9aSmrg    XtransConnInfo	ciptr;
40273143b9aSmrg
403fe567363Smrg    prmsg (3,"SocketOpen(%d,%d)\n", i, type);
40473143b9aSmrg
405fe567363Smrg    if ((ciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
40673143b9aSmrg    {
407fe567363Smrg	prmsg (1, "SocketOpen: malloc failed\n");
40873143b9aSmrg	return NULL;
40973143b9aSmrg    }
41073143b9aSmrg
41173143b9aSmrg    if ((ciptr->fd = socket(Sockettrans2devtab[i].family, type,
41273143b9aSmrg	Sockettrans2devtab[i].protocol)) < 0
41373143b9aSmrg#ifndef WIN32
41473143b9aSmrg#if (defined(X11_t) && !defined(USE_POLL)) || defined(FS_t) || defined(FONT_t)
4158d4c0f7bSmrg       || ciptr->fd >= sysconf(_SC_OPEN_MAX)
41673143b9aSmrg#endif
41773143b9aSmrg#endif
41873143b9aSmrg      ) {
41973143b9aSmrg#ifdef WIN32
42073143b9aSmrg	errno = WSAGetLastError();
42173143b9aSmrg#endif
422fe567363Smrg	prmsg (2, "SocketOpen: socket() failed for %s\n",
423fe567363Smrg	    Sockettrans2devtab[i].transname);
42473143b9aSmrg
425fe567363Smrg	free (ciptr);
42673143b9aSmrg	return NULL;
42773143b9aSmrg    }
42873143b9aSmrg
42973143b9aSmrg#ifdef TCP_NODELAY
43073143b9aSmrg    if (Sockettrans2devtab[i].family == AF_INET
43173143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
43273143b9aSmrg      || Sockettrans2devtab[i].family == AF_INET6
43373143b9aSmrg#endif
43473143b9aSmrg    )
43573143b9aSmrg    {
43673143b9aSmrg	/*
43773143b9aSmrg	 * turn off TCP coalescence for INET sockets
43873143b9aSmrg	 */
43973143b9aSmrg
44073143b9aSmrg	int tmp = 1;
44173143b9aSmrg	setsockopt (ciptr->fd, IPPROTO_TCP, TCP_NODELAY,
44273143b9aSmrg	    (char *) &tmp, sizeof (int));
44373143b9aSmrg    }
44473143b9aSmrg#endif
44573143b9aSmrg
4468a0d9095Smrg    /*
4478a0d9095Smrg     * Some systems provide a really small default buffer size for
4488a0d9095Smrg     * UNIX sockets.  Bump it up a bit such that large transfers don't
4498a0d9095Smrg     * proceed at glacial speed.
4508a0d9095Smrg     */
4518a0d9095Smrg#ifdef SO_SNDBUF
4528a0d9095Smrg    if (Sockettrans2devtab[i].family == AF_UNIX)
4538a0d9095Smrg    {
4548a0d9095Smrg	SOCKLEN_T len = sizeof (int);
4558a0d9095Smrg	int val;
4568a0d9095Smrg
4578a0d9095Smrg	if (getsockopt (ciptr->fd, SOL_SOCKET, SO_SNDBUF,
4588a0d9095Smrg	    (char *) &val, &len) == 0 && val < 64 * 1024)
4598a0d9095Smrg	{
4608a0d9095Smrg	    val = 64 * 1024;
4618a0d9095Smrg	    setsockopt (ciptr->fd, SOL_SOCKET, SO_SNDBUF,
4628a0d9095Smrg	        (char *) &val, sizeof (int));
4638a0d9095Smrg	}
4648a0d9095Smrg    }
4658a0d9095Smrg#endif
4668a0d9095Smrg
46773143b9aSmrg    return ciptr;
46873143b9aSmrg}
46973143b9aSmrg
47073143b9aSmrg
47173143b9aSmrg#ifdef TRANS_REOPEN
47273143b9aSmrg
47373143b9aSmrgstatic XtransConnInfo
4746a3641a6SsnjTRANS(SocketReopen) (int i _X_UNUSED, int type, int fd, const char *port)
47573143b9aSmrg
47673143b9aSmrg{
47773143b9aSmrg    XtransConnInfo	ciptr;
47873143b9aSmrg    int portlen;
47973143b9aSmrg    struct sockaddr *addr;
480fe567363Smrg    size_t addrlen;
48173143b9aSmrg
482fe567363Smrg    prmsg (3,"SocketReopen(%d,%d,%s)\n", type, fd, port);
48373143b9aSmrg
48473143b9aSmrg    if (port == NULL) {
485fe567363Smrg      prmsg (1, "SocketReopen: port was null!\n");
48673143b9aSmrg      return NULL;
48773143b9aSmrg    }
48873143b9aSmrg
48973143b9aSmrg    portlen = strlen(port) + 1; // include space for trailing null
49073143b9aSmrg#ifdef SOCK_MAXADDRLEN
49173143b9aSmrg    if (portlen < 0 || portlen > (SOCK_MAXADDRLEN + 2)) {
492fe567363Smrg      prmsg (1, "SocketReopen: invalid portlen %d\n", portlen);
49373143b9aSmrg      return NULL;
49473143b9aSmrg    }
49573143b9aSmrg    if (portlen < 14) portlen = 14;
49673143b9aSmrg#else
49773143b9aSmrg    if (portlen < 0 || portlen > 14) {
498fe567363Smrg      prmsg (1, "SocketReopen: invalid portlen %d\n", portlen);
49973143b9aSmrg      return NULL;
50073143b9aSmrg    }
50173143b9aSmrg#endif /*SOCK_MAXADDRLEN*/
50273143b9aSmrg
503fe567363Smrg    if ((ciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
50473143b9aSmrg    {
505fe567363Smrg	prmsg (1, "SocketReopen: malloc(ciptr) failed\n");
50673143b9aSmrg	return NULL;
50773143b9aSmrg    }
50873143b9aSmrg
50973143b9aSmrg    ciptr->fd = fd;
51073143b9aSmrg
511fe567363Smrg    addrlen = portlen + offsetof(struct sockaddr, sa_data);
512fe567363Smrg    if ((addr = calloc (1, addrlen)) == NULL) {
513fe567363Smrg	prmsg (1, "SocketReopen: malloc(addr) failed\n");
514fe567363Smrg	free (ciptr);
51573143b9aSmrg	return NULL;
51673143b9aSmrg    }
5178d4c0f7bSmrg    ciptr->addr = (char *) addr;
518fe567363Smrg    ciptr->addrlen = addrlen;
51973143b9aSmrg
520fe567363Smrg    if ((ciptr->peeraddr = calloc (1, addrlen)) == NULL) {
521fe567363Smrg	prmsg (1, "SocketReopen: malloc(portaddr) failed\n");
522fe567363Smrg	free (addr);
523fe567363Smrg	free (ciptr);
52473143b9aSmrg	return NULL;
52573143b9aSmrg    }
526fe567363Smrg    ciptr->peeraddrlen = addrlen;
52773143b9aSmrg
52873143b9aSmrg    /* Initialize ciptr structure as if it were a normally-opened unix socket */
52973143b9aSmrg    ciptr->flags = TRANS_LOCAL | TRANS_NOUNLINK;
53073143b9aSmrg#ifdef BSD44SOCKETS
531fe567363Smrg    addr->sa_len = addrlen;
53273143b9aSmrg#endif
53373143b9aSmrg    addr->sa_family = AF_UNIX;
5347448d6e9Smrg#if defined(HAVE_STRLCPY) || defined(HAS_STRLCPY)
53573143b9aSmrg    strlcpy(addr->sa_data, port, portlen);
53673143b9aSmrg#else
53773143b9aSmrg    strncpy(addr->sa_data, port, portlen);
53873143b9aSmrg#endif
53973143b9aSmrg    ciptr->family = AF_UNIX;
540fe567363Smrg    memcpy(ciptr->peeraddr, ciptr->addr, addrlen);
54173143b9aSmrg    ciptr->port = rindex(addr->sa_data, ':');
542e8a71cdfSmrg    if (ciptr->port == NULL) {
543e8a71cdfSmrg	if (is_numeric(addr->sa_data)) {
544e8a71cdfSmrg	    ciptr->port = addr->sa_data;
545e8a71cdfSmrg	}
546e8a71cdfSmrg    } else if (ciptr->port[0] == ':') {
547e8a71cdfSmrg	ciptr->port++;
548e8a71cdfSmrg    }
549e8a71cdfSmrg    /* port should now point to portnum or NULL */
55073143b9aSmrg    return ciptr;
55173143b9aSmrg}
55273143b9aSmrg
55373143b9aSmrg#endif /* TRANS_REOPEN */
55473143b9aSmrg
55573143b9aSmrg
55673143b9aSmrg/*
55773143b9aSmrg * These functions are the interface supplied in the Xtransport structure
55873143b9aSmrg */
55973143b9aSmrg
56073143b9aSmrg#ifdef TRANS_CLIENT
56173143b9aSmrg
56273143b9aSmrgstatic XtransConnInfo
563fe567363SmrgTRANS(SocketOpenCOTSClientBase) (const char *transname, const char *protocol,
564fe567363Smrg			   const char *host, const char *port, int previndex)
56573143b9aSmrg{
56673143b9aSmrg    XtransConnInfo	ciptr;
56773143b9aSmrg    int			i = previndex;
56873143b9aSmrg
569fe567363Smrg    prmsg (2, "SocketOpenCOTSClient(%s,%s,%s)\n",
57073143b9aSmrg	protocol, host, port);
57173143b9aSmrg
57273143b9aSmrg    SocketInitOnce();
57373143b9aSmrg
57473143b9aSmrg    while ((i = TRANS(SocketSelectFamily) (i, transname)) >= 0) {
57573143b9aSmrg	if ((ciptr = TRANS(SocketOpen) (
576e8a71cdfSmrg		i, Sockettrans2devtab[i].devcotsname)) != NULL) {
577e8a71cdfSmrg	    /* Save the index for later use */
578e8a71cdfSmrg
579e8a71cdfSmrg	    ciptr->index = i;
58073143b9aSmrg	    break;
581e8a71cdfSmrg	}
58273143b9aSmrg    }
58373143b9aSmrg    if (i < 0) {
58473143b9aSmrg	if (i == -1)
585fe567363Smrg	    prmsg (1,"SocketOpenCOTSClient: Unable to open socket for %s\n",
586fe567363Smrg		   transname);
58773143b9aSmrg	else
588fe567363Smrg	    prmsg (1,"SocketOpenCOTSClient: Unable to determine socket type for %s\n",
589fe567363Smrg		   transname);
59073143b9aSmrg	return NULL;
59173143b9aSmrg    }
59273143b9aSmrg
59373143b9aSmrg    return ciptr;
59473143b9aSmrg}
59573143b9aSmrg
59673143b9aSmrgstatic XtransConnInfo
5976a3641a6SsnjTRANS(SocketOpenCOTSClient) (Xtransport *thistrans, const char *protocol,
5986a3641a6Ssnj			     const char *host, const char *port)
59973143b9aSmrg{
60073143b9aSmrg    return TRANS(SocketOpenCOTSClientBase)(
60173143b9aSmrg			thistrans->TransName, protocol, host, port, -1);
60273143b9aSmrg}
60373143b9aSmrg
60473143b9aSmrg
60573143b9aSmrg#endif /* TRANS_CLIENT */
60673143b9aSmrg
60773143b9aSmrg
60873143b9aSmrg#ifdef TRANS_SERVER
60973143b9aSmrg
61073143b9aSmrgstatic XtransConnInfo
6116a3641a6SsnjTRANS(SocketOpenCOTSServer) (Xtransport *thistrans, const char *protocol,
6126a3641a6Ssnj			     const char *host, const char *port)
61373143b9aSmrg
61473143b9aSmrg{
61573143b9aSmrg    XtransConnInfo	ciptr;
61673143b9aSmrg    int	i = -1;
61773143b9aSmrg
618fe567363Smrg    prmsg (2,"SocketOpenCOTSServer(%s,%s,%s)\n", protocol, host, port);
61973143b9aSmrg
62073143b9aSmrg    SocketInitOnce();
62173143b9aSmrg
62273143b9aSmrg    while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
62373143b9aSmrg	if ((ciptr = TRANS(SocketOpen) (
62473143b9aSmrg		 i, Sockettrans2devtab[i].devcotsname)) != NULL)
62573143b9aSmrg	    break;
62673143b9aSmrg    }
62773143b9aSmrg    if (i < 0) {
628a773ec55Smrg	if (i == -1) {
629a773ec55Smrg		if (errno == EAFNOSUPPORT) {
630a773ec55Smrg			thistrans->flags |= TRANS_NOLISTEN;
631a773ec55Smrg			prmsg (1,"SocketOpenCOTSServer: Socket for %s unsupported on this system.\n",
632a773ec55Smrg			       thistrans->TransName);
633a773ec55Smrg		} else {
634a773ec55Smrg			prmsg (1,"SocketOpenCOTSServer: Unable to open socket for %s\n",
635a773ec55Smrg			       thistrans->TransName);
636a773ec55Smrg		}
637a773ec55Smrg	} else {
638fe567363Smrg	    prmsg (1,"SocketOpenCOTSServer: Unable to determine socket type for %s\n",
639fe567363Smrg		   thistrans->TransName);
640a773ec55Smrg	}
64173143b9aSmrg	return NULL;
64273143b9aSmrg    }
64373143b9aSmrg
64473143b9aSmrg    /*
64573143b9aSmrg     * Using this prevents the bind() check for an existing server listening
64673143b9aSmrg     * on the same port, but it is required for other reasons.
64773143b9aSmrg     */
64873143b9aSmrg#ifdef SO_REUSEADDR
64973143b9aSmrg
65073143b9aSmrg    /*
65173143b9aSmrg     * SO_REUSEADDR only applied to AF_INET && AF_INET6
65273143b9aSmrg     */
65373143b9aSmrg
65473143b9aSmrg    if (Sockettrans2devtab[i].family == AF_INET
65573143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
65673143b9aSmrg      || Sockettrans2devtab[i].family == AF_INET6
65773143b9aSmrg#endif
65873143b9aSmrg    )
65973143b9aSmrg    {
66073143b9aSmrg	int one = 1;
66173143b9aSmrg	setsockopt (ciptr->fd, SOL_SOCKET, SO_REUSEADDR,
66273143b9aSmrg		    (char *) &one, sizeof (int));
66373143b9aSmrg    }
66473143b9aSmrg#endif
66573143b9aSmrg#ifdef IPV6_V6ONLY
66673143b9aSmrg    if (Sockettrans2devtab[i].family == AF_INET6)
66773143b9aSmrg    {
66873143b9aSmrg	int one = 1;
66973143b9aSmrg	setsockopt(ciptr->fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(int));
67073143b9aSmrg    }
67173143b9aSmrg#endif
67273143b9aSmrg    /* Save the index for later use */
67373143b9aSmrg
67473143b9aSmrg    ciptr->index = i;
67573143b9aSmrg
67673143b9aSmrg    return ciptr;
67773143b9aSmrg}
67873143b9aSmrg
67973143b9aSmrg#endif /* TRANS_SERVER */
68073143b9aSmrg
68173143b9aSmrg
68273143b9aSmrg#ifdef TRANS_REOPEN
68373143b9aSmrg
68473143b9aSmrgstatic XtransConnInfo
6856a3641a6SsnjTRANS(SocketReopenCOTSServer) (Xtransport *thistrans, int fd, const char *port)
68673143b9aSmrg
68773143b9aSmrg{
68873143b9aSmrg    XtransConnInfo	ciptr;
68973143b9aSmrg    int			i = -1;
69073143b9aSmrg
691fe567363Smrg    prmsg (2,
692fe567363Smrg	"SocketReopenCOTSServer(%d, %s)\n", fd, port);
69373143b9aSmrg
69473143b9aSmrg    SocketInitOnce();
69573143b9aSmrg
69673143b9aSmrg    while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
69773143b9aSmrg	if ((ciptr = TRANS(SocketReopen) (
69873143b9aSmrg		 i, Sockettrans2devtab[i].devcotsname, fd, port)) != NULL)
69973143b9aSmrg	    break;
70073143b9aSmrg    }
70173143b9aSmrg    if (i < 0) {
70273143b9aSmrg	if (i == -1)
703fe567363Smrg	    prmsg (1,"SocketReopenCOTSServer: Unable to open socket for %s\n",
704fe567363Smrg		   thistrans->TransName);
70573143b9aSmrg	else
706fe567363Smrg	    prmsg (1,"SocketReopenCOTSServer: Unable to determine socket type for %s\n",
707fe567363Smrg		   thistrans->TransName);
70873143b9aSmrg	return NULL;
70973143b9aSmrg    }
71073143b9aSmrg
71173143b9aSmrg    /* Save the index for later use */
71273143b9aSmrg
71373143b9aSmrg    ciptr->index = i;
71473143b9aSmrg
71573143b9aSmrg    return ciptr;
71673143b9aSmrg}
71773143b9aSmrg
71873143b9aSmrg#endif /* TRANS_REOPEN */
71973143b9aSmrg
72073143b9aSmrg
72173143b9aSmrgstatic int
72273143b9aSmrgTRANS(SocketSetOption) (XtransConnInfo ciptr, int option, int arg)
72373143b9aSmrg
72473143b9aSmrg{
725fe567363Smrg    prmsg (2,"SocketSetOption(%d,%d,%d)\n", ciptr->fd, option, arg);
72673143b9aSmrg
72773143b9aSmrg    return -1;
72873143b9aSmrg}
72973143b9aSmrg
73073143b9aSmrg#ifdef UNIXCONN
73173143b9aSmrgstatic int
73273143b9aSmrgset_sun_path(const char *port, const char *upath, char *path, int abstract)
73373143b9aSmrg{
73473143b9aSmrg    struct sockaddr_un s;
73573143b9aSmrg    int maxlen = sizeof(s.sun_path) - 1;
73673143b9aSmrg    const char *at = "";
73773143b9aSmrg
73873143b9aSmrg    if (!port || !*port || !path)
73973143b9aSmrg	return -1;
74073143b9aSmrg
74173143b9aSmrg#ifdef HAVE_ABSTRACT_SOCKETS
74273143b9aSmrg    if (port[0] == '@')
74373143b9aSmrg	upath = "";
74473143b9aSmrg    else if (abstract)
74573143b9aSmrg	at = "@";
74673143b9aSmrg#endif
74773143b9aSmrg
74873143b9aSmrg    if (*port == '/') /* a full pathname */
74973143b9aSmrg	upath = "";
75073143b9aSmrg
75173143b9aSmrg    if (strlen(port) + strlen(upath) > maxlen)
75273143b9aSmrg	return -1;
753fe567363Smrg    snprintf(path, sizeof(s.sun_path), "%s%s%s", at, upath, port);
75473143b9aSmrg    return 0;
75573143b9aSmrg}
75673143b9aSmrg#endif
75773143b9aSmrg
75873143b9aSmrg#ifdef TRANS_SERVER
75973143b9aSmrg
76073143b9aSmrgstatic int
761fe567363SmrgTRANS(SocketCreateListener) (XtransConnInfo ciptr,
76273143b9aSmrg			     struct sockaddr *sockname,
76373143b9aSmrg			     int socknamelen, unsigned int flags)
76473143b9aSmrg
76573143b9aSmrg{
76673143b9aSmrg    SOCKLEN_T namelen = socknamelen;
76773143b9aSmrg    int	fd = ciptr->fd;
76873143b9aSmrg    int	retry;
76973143b9aSmrg
770fe567363Smrg    prmsg (3, "SocketCreateListener(%p,%d)\n", ciptr, fd);
77173143b9aSmrg
77273143b9aSmrg    if (Sockettrans2devtab[ciptr->index].family == AF_INET
77373143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
77473143b9aSmrg      || Sockettrans2devtab[ciptr->index].family == AF_INET6
77573143b9aSmrg#endif
77673143b9aSmrg	)
77773143b9aSmrg	retry = 20;
77873143b9aSmrg    else
77973143b9aSmrg	retry = 0;
78073143b9aSmrg
78173143b9aSmrg    while (bind (fd, (struct sockaddr *) sockname, namelen) < 0)
78273143b9aSmrg    {
78373143b9aSmrg	if (errno == EADDRINUSE) {
78473143b9aSmrg	    if (flags & ADDR_IN_USE_ALLOWED)
78573143b9aSmrg		break;
78673143b9aSmrg	    else
78773143b9aSmrg		return TRANS_ADDR_IN_USE;
78873143b9aSmrg	}
789fe567363Smrg
79073143b9aSmrg	if (retry-- == 0) {
791fe567363Smrg	    prmsg (1, "SocketCreateListener: failed to bind listener\n");
79273143b9aSmrg	    close (fd);
79373143b9aSmrg	    return TRANS_CREATE_LISTENER_FAILED;
79473143b9aSmrg	}
79573143b9aSmrg#ifdef SO_REUSEADDR
79673143b9aSmrg	sleep (1);
79773143b9aSmrg#else
79873143b9aSmrg	sleep (10);
79973143b9aSmrg#endif /* SO_REUSEDADDR */
80073143b9aSmrg    }
80173143b9aSmrg
80273143b9aSmrg    if (Sockettrans2devtab[ciptr->index].family == AF_INET
80373143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
80473143b9aSmrg      || Sockettrans2devtab[ciptr->index].family == AF_INET6
80573143b9aSmrg#endif
80673143b9aSmrg	) {
80773143b9aSmrg#ifdef SO_DONTLINGER
80873143b9aSmrg	setsockopt (fd, SOL_SOCKET, SO_DONTLINGER, (char *) NULL, 0);
80973143b9aSmrg#else
81073143b9aSmrg#ifdef SO_LINGER
81173143b9aSmrg    {
81273143b9aSmrg	static int linger[2] = { 0, 0 };
81373143b9aSmrg	setsockopt (fd, SOL_SOCKET, SO_LINGER,
81473143b9aSmrg		(char *) linger, sizeof (linger));
81573143b9aSmrg    }
81673143b9aSmrg#endif
81773143b9aSmrg#endif
81873143b9aSmrg}
81973143b9aSmrg
82073143b9aSmrg    if (listen (fd, BACKLOG) < 0)
82173143b9aSmrg    {
822fe567363Smrg	prmsg (1, "SocketCreateListener: listen() failed\n");
82373143b9aSmrg	close (fd);
82473143b9aSmrg	return TRANS_CREATE_LISTENER_FAILED;
82573143b9aSmrg    }
826fe567363Smrg
82773143b9aSmrg    /* Set a flag to indicate that this connection is a listener */
82873143b9aSmrg
82973143b9aSmrg    ciptr->flags = 1 | (ciptr->flags & TRANS_KEEPFLAGS);
83073143b9aSmrg
83173143b9aSmrg    return 0;
83273143b9aSmrg}
83373143b9aSmrg
83473143b9aSmrg#ifdef TCPCONN
83573143b9aSmrgstatic int
8366a3641a6SsnjTRANS(SocketINETCreateListener) (XtransConnInfo ciptr, const char *port,
8376a3641a6Ssnj                                 unsigned int flags)
83873143b9aSmrg
83973143b9aSmrg{
84073143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
84173143b9aSmrg    struct sockaddr_storage sockname;
84273143b9aSmrg#else
84373143b9aSmrg    struct sockaddr_in	    sockname;
84473143b9aSmrg#endif
84573143b9aSmrg    unsigned short	    sport;
84673143b9aSmrg    SOCKLEN_T	namelen = sizeof(sockname);
84773143b9aSmrg    int		status;
84873143b9aSmrg    long	tmpport;
84973143b9aSmrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
85073143b9aSmrg    _Xgetservbynameparams sparams;
85173143b9aSmrg#endif
85273143b9aSmrg    struct servent *servp;
85373143b9aSmrg
85473143b9aSmrg#ifdef X11_t
85573143b9aSmrg    char	portbuf[PORTBUFSIZE];
85673143b9aSmrg#endif
857fe567363Smrg
858fe567363Smrg    prmsg (2, "SocketINETCreateListener(%s)\n", port);
85973143b9aSmrg
86073143b9aSmrg#ifdef X11_t
86173143b9aSmrg    /*
86273143b9aSmrg     * X has a well known port, that is transport dependent. It is easier
86373143b9aSmrg     * to handle it here, than try and come up with a transport independent
86473143b9aSmrg     * representation that can be passed in and resolved the usual way.
86573143b9aSmrg     *
86673143b9aSmrg     * The port that is passed here is really a string containing the idisplay
86773143b9aSmrg     * from ConnectDisplay().
86873143b9aSmrg     */
86973143b9aSmrg
87073143b9aSmrg    if (is_numeric (port))
87173143b9aSmrg    {
87273143b9aSmrg	/* fixup the server port address */
87373143b9aSmrg	tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10);
874fe567363Smrg	snprintf (portbuf, sizeof(portbuf), "%lu", tmpport);
87573143b9aSmrg	port = portbuf;
87673143b9aSmrg    }
87773143b9aSmrg#endif
87873143b9aSmrg
87973143b9aSmrg    if (port && *port)
88073143b9aSmrg    {
88173143b9aSmrg	/* Check to see if the port string is just a number (handles X11) */
88273143b9aSmrg
88373143b9aSmrg	if (!is_numeric (port))
88473143b9aSmrg	{
88573143b9aSmrg	    if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL)
88673143b9aSmrg	    {
887fe567363Smrg		prmsg (1,
88873143b9aSmrg	     "SocketINETCreateListener: Unable to get service for %s\n",
889fe567363Smrg		      port);
89073143b9aSmrg		return TRANS_CREATE_LISTENER_FAILED;
89173143b9aSmrg	    }
89273143b9aSmrg	    /* we trust getservbyname to return a valid number */
89373143b9aSmrg	    sport = servp->s_port;
89473143b9aSmrg	}
89573143b9aSmrg	else
89673143b9aSmrg	{
89773143b9aSmrg	    tmpport = strtol (port, (char**)NULL, 10);
898fe567363Smrg	    /*
89973143b9aSmrg	     * check that somehow the port address isn't negative or in
90073143b9aSmrg	     * the range of reserved port addresses. This can happen and
901fe567363Smrg	     * be very bad if the server is suid-root and the user does
902fe567363Smrg	     * something (dumb) like `X :60049`.
90373143b9aSmrg	     */
90473143b9aSmrg	    if (tmpport < 1024 || tmpport > USHRT_MAX)
90573143b9aSmrg		return TRANS_CREATE_LISTENER_FAILED;
90673143b9aSmrg
90773143b9aSmrg	    sport = (unsigned short) tmpport;
90873143b9aSmrg	}
90973143b9aSmrg    }
91073143b9aSmrg    else
91173143b9aSmrg	sport = 0;
91273143b9aSmrg
91373143b9aSmrg    bzero(&sockname, sizeof(sockname));
91473143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
91573143b9aSmrg    if (Sockettrans2devtab[ciptr->index].family == AF_INET) {
91673143b9aSmrg	namelen = sizeof (struct sockaddr_in);
91773143b9aSmrg#ifdef BSD44SOCKETS
91873143b9aSmrg	((struct sockaddr_in *)&sockname)->sin_len = namelen;
91973143b9aSmrg#endif
92073143b9aSmrg	((struct sockaddr_in *)&sockname)->sin_family = AF_INET;
92173143b9aSmrg	((struct sockaddr_in *)&sockname)->sin_port = htons(sport);
92273143b9aSmrg	((struct sockaddr_in *)&sockname)->sin_addr.s_addr = htonl(INADDR_ANY);
92373143b9aSmrg    } else {
92473143b9aSmrg	namelen = sizeof (struct sockaddr_in6);
92573143b9aSmrg#ifdef SIN6_LEN
92673143b9aSmrg	((struct sockaddr_in6 *)&sockname)->sin6_len = sizeof(sockname);
92773143b9aSmrg#endif
92873143b9aSmrg	((struct sockaddr_in6 *)&sockname)->sin6_family = AF_INET6;
92973143b9aSmrg	((struct sockaddr_in6 *)&sockname)->sin6_port = htons(sport);
93073143b9aSmrg	((struct sockaddr_in6 *)&sockname)->sin6_addr = in6addr_any;
93173143b9aSmrg    }
93273143b9aSmrg#else
93373143b9aSmrg#ifdef BSD44SOCKETS
93473143b9aSmrg    sockname.sin_len = sizeof (sockname);
93573143b9aSmrg#endif
93673143b9aSmrg    sockname.sin_family = AF_INET;
93773143b9aSmrg    sockname.sin_port = htons (sport);
93873143b9aSmrg    sockname.sin_addr.s_addr = htonl (INADDR_ANY);
93973143b9aSmrg#endif
94073143b9aSmrg
94173143b9aSmrg    if ((status = TRANS(SocketCreateListener) (ciptr,
94273143b9aSmrg	(struct sockaddr *) &sockname, namelen, flags)) < 0)
94373143b9aSmrg    {
944fe567363Smrg	prmsg (1,
945fe567363Smrg    "SocketINETCreateListener: ...SocketCreateListener() failed\n");
94673143b9aSmrg	return status;
94773143b9aSmrg    }
94873143b9aSmrg
94973143b9aSmrg    if (TRANS(SocketINETGetAddr) (ciptr) < 0)
95073143b9aSmrg    {
951fe567363Smrg	prmsg (1,
952fe567363Smrg       "SocketINETCreateListener: ...SocketINETGetAddr() failed\n");
95373143b9aSmrg	return TRANS_CREATE_LISTENER_FAILED;
95473143b9aSmrg    }
95573143b9aSmrg
95673143b9aSmrg    return 0;
95773143b9aSmrg}
95873143b9aSmrg
95973143b9aSmrg#endif /* TCPCONN */
96073143b9aSmrg
96173143b9aSmrg
96273143b9aSmrg#ifdef UNIXCONN
96373143b9aSmrg
96473143b9aSmrgstatic int
9656a3641a6SsnjTRANS(SocketUNIXCreateListener) (XtransConnInfo ciptr, const char *port,
96673143b9aSmrg				 unsigned int flags)
96773143b9aSmrg
96873143b9aSmrg{
96973143b9aSmrg    struct sockaddr_un	sockname;
97073143b9aSmrg    int			namelen;
97173143b9aSmrg    int			oldUmask;
97273143b9aSmrg    int			status;
97373143b9aSmrg    unsigned int	mode;
97473143b9aSmrg    char		tmpport[108];
97573143b9aSmrg
97673143b9aSmrg    int			abstract = 0;
97773143b9aSmrg#ifdef HAVE_ABSTRACT_SOCKETS
97873143b9aSmrg    abstract = ciptr->transptr->flags & TRANS_ABSTRACT;
97973143b9aSmrg#endif
98073143b9aSmrg
981fe567363Smrg    prmsg (2, "SocketUNIXCreateListener(%s)\n",
982fe567363Smrg	port ? port : "NULL");
98373143b9aSmrg
98473143b9aSmrg    /* Make sure the directory is created */
98573143b9aSmrg
98673143b9aSmrg    oldUmask = umask (0);
98773143b9aSmrg
98873143b9aSmrg#ifdef UNIX_DIR
98973143b9aSmrg#ifdef HAS_STICKY_DIR_BIT
99073143b9aSmrg    mode = 01777;
99173143b9aSmrg#else
99273143b9aSmrg    mode = 0777;
99373143b9aSmrg#endif
9948d4c0f7bSmrg    if (!abstract && trans_mkdir(UNIX_DIR, mode) == -1) {
995fe567363Smrg	prmsg (1, "SocketUNIXCreateListener: mkdir(%s) failed, errno = %d\n",
996fe567363Smrg	       UNIX_DIR, errno);
99773143b9aSmrg	(void) umask (oldUmask);
99873143b9aSmrg	return TRANS_CREATE_LISTENER_FAILED;
99973143b9aSmrg    }
100073143b9aSmrg#endif
100173143b9aSmrg
100273143b9aSmrg    memset(&sockname, 0, sizeof(sockname));
100373143b9aSmrg    sockname.sun_family = AF_UNIX;
100473143b9aSmrg
100573143b9aSmrg    if (!(port && *port)) {
100673143b9aSmrg	snprintf (tmpport, sizeof(tmpport), "%s%ld", UNIX_PATH, (long)getpid());
100773143b9aSmrg	port = tmpport;
100873143b9aSmrg    }
100973143b9aSmrg    if (set_sun_path(port, UNIX_PATH, sockname.sun_path, abstract) != 0) {
1010fe567363Smrg	prmsg (1, "SocketUNIXCreateListener: path too long\n");
101173143b9aSmrg	return TRANS_CREATE_LISTENER_FAILED;
101273143b9aSmrg    }
101373143b9aSmrg
1014a773ec55Smrg#if defined(BSD44SOCKETS)
101573143b9aSmrg    sockname.sun_len = strlen(sockname.sun_path);
101673143b9aSmrg#endif
101773143b9aSmrg
101873143b9aSmrg#if defined(BSD44SOCKETS) || defined(SUN_LEN)
101973143b9aSmrg    namelen = SUN_LEN(&sockname);
102073143b9aSmrg#else
102173143b9aSmrg    namelen = strlen(sockname.sun_path) + offsetof(struct sockaddr_un, sun_path);
102273143b9aSmrg#endif
102373143b9aSmrg
102473143b9aSmrg    if (abstract) {
102573143b9aSmrg	sockname.sun_path[0] = '\0';
102673143b9aSmrg	namelen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&sockname.sun_path[1]);
102773143b9aSmrg    }
102873143b9aSmrg    else
102973143b9aSmrg	unlink (sockname.sun_path);
103073143b9aSmrg
103173143b9aSmrg    if ((status = TRANS(SocketCreateListener) (ciptr,
103273143b9aSmrg	(struct sockaddr *) &sockname, namelen, flags)) < 0)
103373143b9aSmrg    {
1034fe567363Smrg	prmsg (1,
1035fe567363Smrg    "SocketUNIXCreateListener: ...SocketCreateListener() failed\n");
103673143b9aSmrg	(void) umask (oldUmask);
103773143b9aSmrg	return status;
103873143b9aSmrg    }
103973143b9aSmrg
104073143b9aSmrg    /*
104173143b9aSmrg     * Now that the listener is esablished, create the addr info for
104273143b9aSmrg     * this connection. getpeername() doesn't work for UNIX Domain Sockets
104373143b9aSmrg     * on some systems (hpux at least), so we will just do it manually, instead
104473143b9aSmrg     * of calling something like TRANS(SocketUNIXGetAddr).
104573143b9aSmrg     */
104673143b9aSmrg
104773143b9aSmrg    namelen = sizeof (sockname); /* this will always make it the same size */
104873143b9aSmrg
1049fe567363Smrg    if ((ciptr->addr = malloc (namelen)) == NULL)
105073143b9aSmrg    {
1051fe567363Smrg        prmsg (1,
1052fe567363Smrg        "SocketUNIXCreateListener: Can't allocate space for the addr\n");
105373143b9aSmrg	(void) umask (oldUmask);
105473143b9aSmrg        return TRANS_CREATE_LISTENER_FAILED;
105573143b9aSmrg    }
105673143b9aSmrg
105773143b9aSmrg    if (abstract)
105873143b9aSmrg	sockname.sun_path[0] = '@';
105973143b9aSmrg
106073143b9aSmrg    ciptr->family = sockname.sun_family;
106173143b9aSmrg    ciptr->addrlen = namelen;
106273143b9aSmrg    memcpy (ciptr->addr, &sockname, ciptr->addrlen);
106373143b9aSmrg
106473143b9aSmrg    (void) umask (oldUmask);
106573143b9aSmrg
106673143b9aSmrg    return 0;
106773143b9aSmrg}
106873143b9aSmrg
106973143b9aSmrg
107073143b9aSmrgstatic int
107173143b9aSmrgTRANS(SocketUNIXResetListener) (XtransConnInfo ciptr)
107273143b9aSmrg
107373143b9aSmrg{
107473143b9aSmrg    /*
107573143b9aSmrg     * See if the unix domain socket has disappeared.  If it has, recreate it.
107673143b9aSmrg     */
107773143b9aSmrg
107873143b9aSmrg    struct sockaddr_un 	*unsock = (struct sockaddr_un *) ciptr->addr;
107973143b9aSmrg    struct stat		statb;
108073143b9aSmrg    int 		status = TRANS_RESET_NOOP;
108173143b9aSmrg    unsigned int	mode;
108273143b9aSmrg    int abstract = 0;
108373143b9aSmrg#ifdef HAVE_ABSTRACT_SOCKETS
108473143b9aSmrg    abstract = ciptr->transptr->flags & TRANS_ABSTRACT;
108573143b9aSmrg#endif
108673143b9aSmrg
1087fe567363Smrg    prmsg (3, "SocketUNIXResetListener(%p,%d)\n", ciptr, ciptr->fd);
108873143b9aSmrg
108973143b9aSmrg    if (!abstract && (
109073143b9aSmrg	stat (unsock->sun_path, &statb) == -1 ||
109173143b9aSmrg        ((statb.st_mode & S_IFMT) !=
1092a773ec55Smrg#if !defined(S_IFSOCK)
109373143b9aSmrg	  		S_IFIFO
109473143b9aSmrg#else
109573143b9aSmrg			S_IFSOCK
109673143b9aSmrg#endif
109773143b9aSmrg				)))
109873143b9aSmrg    {
109973143b9aSmrg	int oldUmask = umask (0);
110073143b9aSmrg
110173143b9aSmrg#ifdef UNIX_DIR
110273143b9aSmrg#ifdef HAS_STICKY_DIR_BIT
110373143b9aSmrg	mode = 01777;
110473143b9aSmrg#else
110573143b9aSmrg	mode = 0777;
110673143b9aSmrg#endif
110773143b9aSmrg        if (trans_mkdir(UNIX_DIR, mode) == -1) {
1108fe567363Smrg            prmsg (1, "SocketUNIXResetListener: mkdir(%s) failed, errno = %d\n",
1109fe567363Smrg	    UNIX_DIR, errno);
111073143b9aSmrg	    (void) umask (oldUmask);
111173143b9aSmrg	    return TRANS_RESET_FAILURE;
111273143b9aSmrg        }
111373143b9aSmrg#endif
111473143b9aSmrg
111573143b9aSmrg	close (ciptr->fd);
111673143b9aSmrg	unlink (unsock->sun_path);
111773143b9aSmrg
111873143b9aSmrg	if ((ciptr->fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
111973143b9aSmrg	{
112073143b9aSmrg	    TRANS(FreeConnInfo) (ciptr);
112173143b9aSmrg	    (void) umask (oldUmask);
112273143b9aSmrg	    return TRANS_RESET_FAILURE;
112373143b9aSmrg	}
112473143b9aSmrg
112573143b9aSmrg	if (bind (ciptr->fd, (struct sockaddr *) unsock, ciptr->addrlen) < 0)
112673143b9aSmrg	{
112773143b9aSmrg	    close (ciptr->fd);
112873143b9aSmrg	    TRANS(FreeConnInfo) (ciptr);
112973143b9aSmrg	    return TRANS_RESET_FAILURE;
113073143b9aSmrg	}
113173143b9aSmrg
113273143b9aSmrg	if (listen (ciptr->fd, BACKLOG) < 0)
113373143b9aSmrg	{
113473143b9aSmrg	    close (ciptr->fd);
113573143b9aSmrg	    TRANS(FreeConnInfo) (ciptr);
113673143b9aSmrg	    (void) umask (oldUmask);
113773143b9aSmrg	    return TRANS_RESET_FAILURE;
113873143b9aSmrg	}
113973143b9aSmrg
114073143b9aSmrg	umask (oldUmask);
114173143b9aSmrg
114273143b9aSmrg	status = TRANS_RESET_NEW_FD;
114373143b9aSmrg    }
114473143b9aSmrg
114573143b9aSmrg    return status;
114673143b9aSmrg}
114773143b9aSmrg
114873143b9aSmrg#endif /* UNIXCONN */
114973143b9aSmrg
115073143b9aSmrg
115173143b9aSmrg#ifdef TCPCONN
115273143b9aSmrg
115373143b9aSmrgstatic XtransConnInfo
115473143b9aSmrgTRANS(SocketINETAccept) (XtransConnInfo ciptr, int *status)
115573143b9aSmrg
115673143b9aSmrg{
115773143b9aSmrg    XtransConnInfo	newciptr;
115873143b9aSmrg    struct sockaddr_in	sockname;
115973143b9aSmrg    SOCKLEN_T		namelen = sizeof(sockname);
116073143b9aSmrg
1161fe567363Smrg    prmsg (2, "SocketINETAccept(%p,%d)\n", ciptr, ciptr->fd);
116273143b9aSmrg
1163fe567363Smrg    if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
116473143b9aSmrg    {
1165fe567363Smrg	prmsg (1, "SocketINETAccept: malloc failed\n");
116673143b9aSmrg	*status = TRANS_ACCEPT_BAD_MALLOC;
116773143b9aSmrg	return NULL;
116873143b9aSmrg    }
116973143b9aSmrg
117073143b9aSmrg    if ((newciptr->fd = accept (ciptr->fd,
117173143b9aSmrg	(struct sockaddr *) &sockname, (void *)&namelen)) < 0)
117273143b9aSmrg    {
117373143b9aSmrg#ifdef WIN32
117473143b9aSmrg	errno = WSAGetLastError();
117573143b9aSmrg#endif
1176fe567363Smrg	prmsg (1, "SocketINETAccept: accept() failed\n");
1177fe567363Smrg	free (newciptr);
117873143b9aSmrg	*status = TRANS_ACCEPT_FAILED;
117973143b9aSmrg	return NULL;
118073143b9aSmrg    }
118173143b9aSmrg
118273143b9aSmrg#ifdef TCP_NODELAY
118373143b9aSmrg    {
118473143b9aSmrg	/*
118573143b9aSmrg	 * turn off TCP coalescence for INET sockets
118673143b9aSmrg	 */
118773143b9aSmrg
118873143b9aSmrg	int tmp = 1;
118973143b9aSmrg	setsockopt (newciptr->fd, IPPROTO_TCP, TCP_NODELAY,
119073143b9aSmrg	    (char *) &tmp, sizeof (int));
119173143b9aSmrg    }
119273143b9aSmrg#endif
119373143b9aSmrg
119473143b9aSmrg    /*
1195fe567363Smrg     * Get this address again because the transport may give a more
119673143b9aSmrg     * specific address now that a connection is established.
119773143b9aSmrg     */
119873143b9aSmrg
119973143b9aSmrg    if (TRANS(SocketINETGetAddr) (newciptr) < 0)
120073143b9aSmrg    {
1201fe567363Smrg	prmsg (1,
1202fe567363Smrg	    "SocketINETAccept: ...SocketINETGetAddr() failed:\n");
120373143b9aSmrg	close (newciptr->fd);
1204fe567363Smrg	free (newciptr);
120573143b9aSmrg	*status = TRANS_ACCEPT_MISC_ERROR;
120673143b9aSmrg        return NULL;
120773143b9aSmrg    }
120873143b9aSmrg
120973143b9aSmrg    if (TRANS(SocketINETGetPeerAddr) (newciptr) < 0)
121073143b9aSmrg    {
1211fe567363Smrg	prmsg (1,
1212fe567363Smrg	  "SocketINETAccept: ...SocketINETGetPeerAddr() failed:\n");
121373143b9aSmrg	close (newciptr->fd);
1214fe567363Smrg	if (newciptr->addr) free (newciptr->addr);
1215fe567363Smrg	free (newciptr);
121673143b9aSmrg	*status = TRANS_ACCEPT_MISC_ERROR;
121773143b9aSmrg        return NULL;
121873143b9aSmrg    }
121973143b9aSmrg
122073143b9aSmrg    *status = 0;
122173143b9aSmrg
122273143b9aSmrg    return newciptr;
122373143b9aSmrg}
122473143b9aSmrg
122573143b9aSmrg#endif /* TCPCONN */
122673143b9aSmrg
122773143b9aSmrg
122873143b9aSmrg#ifdef UNIXCONN
122973143b9aSmrgstatic XtransConnInfo
123073143b9aSmrgTRANS(SocketUNIXAccept) (XtransConnInfo ciptr, int *status)
123173143b9aSmrg
123273143b9aSmrg{
123373143b9aSmrg    XtransConnInfo	newciptr;
123473143b9aSmrg    struct sockaddr_un	sockname;
123573143b9aSmrg    SOCKLEN_T 		namelen = sizeof sockname;
123673143b9aSmrg
1237fe567363Smrg    prmsg (2, "SocketUNIXAccept(%p,%d)\n", ciptr, ciptr->fd);
123873143b9aSmrg
1239fe567363Smrg    if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
124073143b9aSmrg    {
1241fe567363Smrg	prmsg (1, "SocketUNIXAccept: malloc() failed\n");
124273143b9aSmrg	*status = TRANS_ACCEPT_BAD_MALLOC;
124373143b9aSmrg	return NULL;
124473143b9aSmrg    }
124573143b9aSmrg
124673143b9aSmrg    if ((newciptr->fd = accept (ciptr->fd,
124773143b9aSmrg	(struct sockaddr *) &sockname, (void *)&namelen)) < 0)
124873143b9aSmrg    {
1249fe567363Smrg	prmsg (1, "SocketUNIXAccept: accept() failed\n");
1250fe567363Smrg	free (newciptr);
125173143b9aSmrg	*status = TRANS_ACCEPT_FAILED;
125273143b9aSmrg	return NULL;
125373143b9aSmrg    }
125473143b9aSmrg
125573143b9aSmrg	ciptr->addrlen = namelen;
125673143b9aSmrg    /*
125773143b9aSmrg     * Get the socket name and the peer name from the listener socket,
125873143b9aSmrg     * since this is unix domain.
125973143b9aSmrg     */
126073143b9aSmrg
1261fe567363Smrg    if ((newciptr->addr = malloc (ciptr->addrlen)) == NULL)
126273143b9aSmrg    {
1263fe567363Smrg        prmsg (1,
1264fe567363Smrg        "SocketUNIXAccept: Can't allocate space for the addr\n");
126573143b9aSmrg	close (newciptr->fd);
1266fe567363Smrg	free (newciptr);
126773143b9aSmrg	*status = TRANS_ACCEPT_BAD_MALLOC;
126873143b9aSmrg        return NULL;
126973143b9aSmrg    }
127073143b9aSmrg
127173143b9aSmrg    /*
127273143b9aSmrg     * if the socket is abstract, we already modified the address to have a
127373143b9aSmrg     * @ instead of the initial NUL, so no need to do that again here.
127473143b9aSmrg     */
127573143b9aSmrg
127673143b9aSmrg    newciptr->addrlen = ciptr->addrlen;
127773143b9aSmrg    memcpy (newciptr->addr, ciptr->addr, newciptr->addrlen);
127873143b9aSmrg
1279fe567363Smrg    if ((newciptr->peeraddr = malloc (ciptr->addrlen)) == NULL)
128073143b9aSmrg    {
1281fe567363Smrg        prmsg (1,
1282fe567363Smrg	      "SocketUNIXAccept: Can't allocate space for the addr\n");
128373143b9aSmrg	close (newciptr->fd);
1284fe567363Smrg	if (newciptr->addr) free (newciptr->addr);
1285fe567363Smrg	free (newciptr);
128673143b9aSmrg	*status = TRANS_ACCEPT_BAD_MALLOC;
128773143b9aSmrg        return NULL;
128873143b9aSmrg    }
1289fe567363Smrg
129073143b9aSmrg    newciptr->peeraddrlen = ciptr->addrlen;
129173143b9aSmrg    memcpy (newciptr->peeraddr, ciptr->addr, newciptr->addrlen);
129273143b9aSmrg
129373143b9aSmrg    newciptr->family = AF_UNIX;
129473143b9aSmrg
129573143b9aSmrg    *status = 0;
129673143b9aSmrg
129773143b9aSmrg    return newciptr;
129873143b9aSmrg}
129973143b9aSmrg
130073143b9aSmrg#endif /* UNIXCONN */
130173143b9aSmrg
130273143b9aSmrg#endif /* TRANS_SERVER */
130373143b9aSmrg
130473143b9aSmrg
130573143b9aSmrg#ifdef TRANS_CLIENT
130673143b9aSmrg
130773143b9aSmrg#ifdef TCPCONN
130873143b9aSmrg
130973143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
131073143b9aSmrgstruct addrlist {
131173143b9aSmrg    struct addrinfo *	addr;
1312fe567363Smrg    struct addrinfo *	firstaddr;
131373143b9aSmrg    char 		port[PORTBUFSIZE];
131473143b9aSmrg    char 		host[MAXHOSTNAMELEN];
131573143b9aSmrg};
131673143b9aSmrgstatic struct addrlist  *addrlist = NULL;
131773143b9aSmrg#endif
131873143b9aSmrg
131973143b9aSmrg
132073143b9aSmrgstatic int
13216a3641a6SsnjTRANS(SocketINETConnect) (XtransConnInfo ciptr,
13226a3641a6Ssnj                          const char *host, const char *port)
132373143b9aSmrg
132473143b9aSmrg{
132573143b9aSmrg    struct sockaddr *	socketaddr = NULL;
132673143b9aSmrg    int			socketaddrlen = 0;
132773143b9aSmrg    int			res;
132873143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
132973143b9aSmrg    struct addrinfo 	hints;
133073143b9aSmrg    char		ntopbuf[INET6_ADDRSTRLEN];
133173143b9aSmrg    int			resetonce = 0;
1332fe567363Smrg#else
133373143b9aSmrg    struct sockaddr_in	sockname;
1334fe567363Smrg    struct hostent	*hostp;
1335fe567363Smrg    struct servent	*servp;
1336fe567363Smrg    unsigned long 	tmpaddr;
1337fe567363Smrg#endif
133873143b9aSmrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
133973143b9aSmrg    _Xgethostbynameparams hparams;
134073143b9aSmrg    _Xgetservbynameparams sparams;
134173143b9aSmrg#endif
134273143b9aSmrg#ifdef X11_t
134373143b9aSmrg    char	portbuf[PORTBUFSIZE];
134473143b9aSmrg#endif
134573143b9aSmrg
134673143b9aSmrg    char 		hostnamebuf[256];		/* tmp space */
134773143b9aSmrg
1348fe567363Smrg    prmsg (2,"SocketINETConnect(%d,%s,%s)\n", ciptr->fd, host, port);
134973143b9aSmrg
135073143b9aSmrg    if (!host)
135173143b9aSmrg    {
135273143b9aSmrg	hostnamebuf[0] = '\0';
135373143b9aSmrg	(void) TRANS(GetHostname) (hostnamebuf, sizeof hostnamebuf);
135473143b9aSmrg	host = hostnamebuf;
135573143b9aSmrg    }
135673143b9aSmrg
135773143b9aSmrg#ifdef X11_t
135873143b9aSmrg    /*
135973143b9aSmrg     * X has a well known port, that is transport dependent. It is easier
136073143b9aSmrg     * to handle it here, than try and come up with a transport independent
136173143b9aSmrg     * representation that can be passed in and resolved the usual way.
136273143b9aSmrg     *
136373143b9aSmrg     * The port that is passed here is really a string containing the idisplay
136473143b9aSmrg     * from ConnectDisplay().
136573143b9aSmrg     */
136673143b9aSmrg
136773143b9aSmrg    if (is_numeric (port))
136873143b9aSmrg    {
1369fe567363Smrg	long tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10);
1370fe567363Smrg	snprintf (portbuf, sizeof(portbuf), "%lu", tmpport);
137173143b9aSmrg	port = portbuf;
137273143b9aSmrg    }
137373143b9aSmrg#endif
137473143b9aSmrg
137573143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
1376b53e5eeaSmrg    {
137773143b9aSmrg	if (addrlist != NULL) {
137873143b9aSmrg	    if (strcmp(host,addrlist->host) || strcmp(port,addrlist->port)) {
137973143b9aSmrg		if (addrlist->firstaddr)
138073143b9aSmrg		    freeaddrinfo(addrlist->firstaddr);
138173143b9aSmrg		addrlist->firstaddr = NULL;
138273143b9aSmrg	    }
138373143b9aSmrg	} else {
138473143b9aSmrg	    addrlist = malloc(sizeof(struct addrlist));
138573143b9aSmrg	    addrlist->firstaddr = NULL;
138673143b9aSmrg	}
138773143b9aSmrg
138873143b9aSmrg	if (addrlist->firstaddr == NULL) {
138973143b9aSmrg	    strncpy(addrlist->port, port, sizeof(addrlist->port));
139073143b9aSmrg	    addrlist->port[sizeof(addrlist->port) - 1] = '\0';
139173143b9aSmrg	    strncpy(addrlist->host, host, sizeof(addrlist->host));
139273143b9aSmrg	    addrlist->host[sizeof(addrlist->host) - 1] = '\0';
139373143b9aSmrg
139473143b9aSmrg	    bzero(&hints,sizeof(hints));
139573143b9aSmrg	    hints.ai_socktype = Sockettrans2devtab[ciptr->index].devcotsname;
139673143b9aSmrg
139773143b9aSmrg	    res = getaddrinfo(host,port,&hints,&addrlist->firstaddr);
139873143b9aSmrg	    if (res != 0) {
1399fe567363Smrg		prmsg (1, "SocketINETConnect() can't get address "
140073143b9aSmrg			"for %s:%s: %s\n", host, port, gai_strerror(res));
140173143b9aSmrg		ESET(EINVAL);
140273143b9aSmrg		return TRANS_CONNECT_FAILED;
140373143b9aSmrg	    }
140473143b9aSmrg	    for (res = 0, addrlist->addr = addrlist->firstaddr;
140573143b9aSmrg		 addrlist->addr ; res++) {
140673143b9aSmrg		addrlist->addr = addrlist->addr->ai_next;
140773143b9aSmrg	    }
1408fe567363Smrg	    prmsg(4,"Got New Address list with %d addresses\n", res);
140973143b9aSmrg	    res = 0;
141073143b9aSmrg	    addrlist->addr = NULL;
141173143b9aSmrg	}
141273143b9aSmrg
141373143b9aSmrg	while (socketaddr == NULL) {
141473143b9aSmrg	    if (addrlist->addr == NULL) {
1415fe567363Smrg		if (resetonce) {
141673143b9aSmrg		    /* Already checked entire list - no usable addresses */
1417fe567363Smrg		    prmsg (1, "SocketINETConnect() no usable address "
1418fe567363Smrg			   "for %s:%s\n", host, port);
141973143b9aSmrg		    return TRANS_CONNECT_FAILED;
142073143b9aSmrg		} else {
142173143b9aSmrg		    /* Go back to beginning of list */
142273143b9aSmrg		    resetonce = 1;
142373143b9aSmrg		    addrlist->addr = addrlist->firstaddr;
142473143b9aSmrg		}
1425fe567363Smrg	    }
142673143b9aSmrg
142773143b9aSmrg	    socketaddr = addrlist->addr->ai_addr;
142873143b9aSmrg	    socketaddrlen = addrlist->addr->ai_addrlen;
142973143b9aSmrg
143073143b9aSmrg	    if (addrlist->addr->ai_family == AF_INET) {
143173143b9aSmrg		struct sockaddr_in *sin = (struct sockaddr_in *) socketaddr;
143273143b9aSmrg
1433fe567363Smrg		prmsg (4,"SocketINETConnect() sockname.sin_addr = %s\n",
143473143b9aSmrg			inet_ntop(addrlist->addr->ai_family,&sin->sin_addr,
1435fe567363Smrg			ntopbuf,sizeof(ntopbuf)));
143673143b9aSmrg
1437fe567363Smrg		prmsg (4,"SocketINETConnect() sockname.sin_port = %d\n",
1438fe567363Smrg			ntohs(sin->sin_port));
143973143b9aSmrg
144073143b9aSmrg		if (Sockettrans2devtab[ciptr->index].family == AF_INET6) {
144173143b9aSmrg		    if (strcmp(Sockettrans2devtab[ciptr->index].transname,
144273143b9aSmrg				"tcp") == 0) {
144373143b9aSmrg			XtransConnInfo newciptr;
144473143b9aSmrg
144573143b9aSmrg			/*
144673143b9aSmrg			 * Our socket is an IPv6 socket, but the address is
144773143b9aSmrg			 * IPv4.  Close it and get an IPv4 socket.  This is
144873143b9aSmrg			 * needed for IPv4 connections to work on platforms
144973143b9aSmrg			 * that don't allow IPv4 over IPv6 sockets.
145073143b9aSmrg			 */
145173143b9aSmrg			TRANS(SocketINETClose)(ciptr);
145273143b9aSmrg			newciptr = TRANS(SocketOpenCOTSClientBase)(
145373143b9aSmrg					"tcp", "tcp", host, port, ciptr->index);
145473143b9aSmrg			if (newciptr)
145573143b9aSmrg			    ciptr->fd = newciptr->fd;
145673143b9aSmrg			if (!newciptr ||
145773143b9aSmrg			    Sockettrans2devtab[newciptr->index].family !=
145873143b9aSmrg				AF_INET) {
145973143b9aSmrg			    socketaddr = NULL;
1460fe567363Smrg			    prmsg (4,"SocketINETConnect() Cannot get IPv4 "
1461fe567363Smrg					" socketfor IPv4 address\n");
146273143b9aSmrg			}
146373143b9aSmrg			if (newciptr)
1464fe567363Smrg			    free(newciptr);
146573143b9aSmrg		    } else {
146673143b9aSmrg			socketaddr = NULL;
1467fe567363Smrg			prmsg (4,"SocketINETConnect Skipping IPv4 address\n");
146873143b9aSmrg		    }
146973143b9aSmrg		}
147073143b9aSmrg	    } else if (addrlist->addr->ai_family == AF_INET6) {
147173143b9aSmrg		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) socketaddr;
1472fe567363Smrg
1473fe567363Smrg		prmsg (4,"SocketINETConnect() sockname.sin6_addr = %s\n",
147473143b9aSmrg			inet_ntop(addrlist->addr->ai_family,
1475fe567363Smrg				  &sin6->sin6_addr,ntopbuf,sizeof(ntopbuf)));
1476fe567363Smrg		prmsg (4,"SocketINETConnect() sockname.sin6_port = %d\n",
1477fe567363Smrg			ntohs(sin6->sin6_port));
147873143b9aSmrg
147973143b9aSmrg		if (Sockettrans2devtab[ciptr->index].family == AF_INET) {
148073143b9aSmrg		    if (strcmp(Sockettrans2devtab[ciptr->index].transname,
148173143b9aSmrg				"tcp") == 0) {
148273143b9aSmrg			XtransConnInfo newciptr;
148373143b9aSmrg
148473143b9aSmrg			/*
148573143b9aSmrg			 * Close the IPv4 socket and try to open an IPv6 socket.
148673143b9aSmrg			 */
148773143b9aSmrg			TRANS(SocketINETClose)(ciptr);
148873143b9aSmrg			newciptr = TRANS(SocketOpenCOTSClientBase)(
148973143b9aSmrg					"tcp", "tcp", host, port, -1);
149073143b9aSmrg			if (newciptr)
149173143b9aSmrg			    ciptr->fd = newciptr->fd;
149273143b9aSmrg			if (!newciptr ||
149373143b9aSmrg			    Sockettrans2devtab[newciptr->index].family !=
149473143b9aSmrg					AF_INET6) {
149573143b9aSmrg			    socketaddr = NULL;
1496fe567363Smrg			    prmsg (4,"SocketINETConnect() Cannot get IPv6 "
1497fe567363Smrg				   "socket for IPv6 address\n");
149873143b9aSmrg			}
149973143b9aSmrg			if (newciptr)
1500fe567363Smrg			    free(newciptr);
150173143b9aSmrg		    }
150273143b9aSmrg		    else
150373143b9aSmrg		    {
150473143b9aSmrg			socketaddr = NULL;
1505fe567363Smrg			prmsg (4,"SocketINETConnect() Skipping IPv6 address\n");
150673143b9aSmrg		    }
150773143b9aSmrg		}
150873143b9aSmrg	    } else {
150973143b9aSmrg		socketaddr = NULL; /* Unsupported address type */
151073143b9aSmrg	    }
151173143b9aSmrg	    if (socketaddr == NULL) {
151273143b9aSmrg		addrlist->addr = addrlist->addr->ai_next;
151373143b9aSmrg	    }
1514fe567363Smrg	}
1515b53e5eeaSmrg    }
1516b53e5eeaSmrg#else
151773143b9aSmrg    {
151873143b9aSmrg	/*
151973143b9aSmrg	 * Build the socket name.
152073143b9aSmrg	 */
152173143b9aSmrg
152273143b9aSmrg#ifdef BSD44SOCKETS
152373143b9aSmrg	sockname.sin_len = sizeof (struct sockaddr_in);
152473143b9aSmrg#endif
152573143b9aSmrg	sockname.sin_family = AF_INET;
152673143b9aSmrg
152773143b9aSmrg	/*
152873143b9aSmrg	 * fill in sin_addr
152973143b9aSmrg	 */
153073143b9aSmrg
153173143b9aSmrg#ifndef INADDR_NONE
153273143b9aSmrg#define INADDR_NONE ((in_addr_t) 0xffffffff)
153373143b9aSmrg#endif
153473143b9aSmrg
153573143b9aSmrg	/* check for ww.xx.yy.zz host string */
153673143b9aSmrg
153773143b9aSmrg	if (isascii (host[0]) && isdigit (host[0])) {
153873143b9aSmrg	    tmpaddr = inet_addr (host); /* returns network byte order */
153973143b9aSmrg	} else {
154073143b9aSmrg	    tmpaddr = INADDR_NONE;
154173143b9aSmrg	}
154273143b9aSmrg
154381d6fa61Srin	prmsg (4,"SocketINETConnect() inet_addr(%s) = %lx\n", host, tmpaddr);
154473143b9aSmrg
154573143b9aSmrg	if (tmpaddr == INADDR_NONE) {
154673143b9aSmrg	    if ((hostp = _XGethostbyname(host,hparams)) == NULL) {
1547fe567363Smrg		prmsg (1,"SocketINETConnect: Can't get address for %s\n",
1548fe567363Smrg			host);
154973143b9aSmrg		ESET(EINVAL);
155073143b9aSmrg		return TRANS_CONNECT_FAILED;
155173143b9aSmrg	    }
155273143b9aSmrg	    if (hostp->h_addrtype != AF_INET) {  /* is IP host? */
1553fe567363Smrg		prmsg (1,"SocketINETConnect: not INET host%s\n", host);
155473143b9aSmrg		ESET(EPROTOTYPE);
155573143b9aSmrg		return TRANS_CONNECT_FAILED;
155673143b9aSmrg	    }
1557fe567363Smrg
155873143b9aSmrg	    memcpy ((char *) &sockname.sin_addr, (char *) hostp->h_addr,
155973143b9aSmrg		    sizeof (sockname.sin_addr));
156073143b9aSmrg
156173143b9aSmrg	} else {
156273143b9aSmrg	    sockname.sin_addr.s_addr = tmpaddr;
156373143b9aSmrg        }
156473143b9aSmrg
156573143b9aSmrg	/*
156673143b9aSmrg	 * fill in sin_port
156773143b9aSmrg	 */
156873143b9aSmrg
156973143b9aSmrg	/* Check for number in the port string */
157073143b9aSmrg
157173143b9aSmrg	if (!is_numeric (port)) {
157273143b9aSmrg	    if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL) {
1573fe567363Smrg		prmsg (1,"SocketINETConnect: can't get service for %s\n",
1574fe567363Smrg			port);
157573143b9aSmrg		return TRANS_CONNECT_FAILED;
157673143b9aSmrg	    }
157773143b9aSmrg	    sockname.sin_port = htons (servp->s_port);
157873143b9aSmrg	} else {
1579fe567363Smrg	    long tmpport = strtol (port, (char**)NULL, 10);
158073143b9aSmrg	    if (tmpport < 1024 || tmpport > USHRT_MAX)
158173143b9aSmrg		return TRANS_CONNECT_FAILED;
158273143b9aSmrg	    sockname.sin_port = htons (((unsigned short) tmpport));
158373143b9aSmrg	}
158473143b9aSmrg
1585fe567363Smrg	prmsg (4,"SocketINETConnect: sockname.sin_port = %d\n",
1586fe567363Smrg		ntohs(sockname.sin_port));
158773143b9aSmrg	socketaddr = (struct sockaddr *) &sockname;
158873143b9aSmrg	socketaddrlen = sizeof(sockname);
158973143b9aSmrg    }
1590b53e5eeaSmrg#endif
159173143b9aSmrg
159273143b9aSmrg    /*
159373143b9aSmrg     * Turn on socket keepalive so the client process will eventually
159473143b9aSmrg     * be notified with a SIGPIPE signal if the display server fails
159573143b9aSmrg     * to respond to a periodic transmission of messages
159673143b9aSmrg     * on the connected socket.
159773143b9aSmrg     * This is useful to avoid hung application processes when the
159873143b9aSmrg     * processes are not spawned from the xdm session and
159973143b9aSmrg     * the display server terminates abnormally.
160073143b9aSmrg     * (Someone turned off the power switch.)
160173143b9aSmrg     */
160273143b9aSmrg
160373143b9aSmrg    {
160473143b9aSmrg	int tmp = 1;
160573143b9aSmrg	setsockopt (ciptr->fd, SOL_SOCKET, SO_KEEPALIVE,
160673143b9aSmrg		(char *) &tmp, sizeof (int));
160773143b9aSmrg    }
160873143b9aSmrg
160973143b9aSmrg    /*
161073143b9aSmrg     * Do the connect()
161173143b9aSmrg     */
161273143b9aSmrg
161373143b9aSmrg    if (connect (ciptr->fd, socketaddr, socketaddrlen ) < 0)
161473143b9aSmrg    {
161573143b9aSmrg#ifdef WIN32
161673143b9aSmrg	int olderrno = WSAGetLastError();
161773143b9aSmrg#else
161873143b9aSmrg	int olderrno = errno;
161973143b9aSmrg#endif
162073143b9aSmrg
162173143b9aSmrg	/*
162273143b9aSmrg	 * If the error was ECONNREFUSED, the server may be overloaded
162373143b9aSmrg	 * and we should try again.
162473143b9aSmrg	 *
162573143b9aSmrg	 * If the error was EWOULDBLOCK or EINPROGRESS then the socket
162673143b9aSmrg	 * was non-blocking and we should poll using select
162773143b9aSmrg	 *
162873143b9aSmrg	 * If the error was EINTR, the connect was interrupted and we
162973143b9aSmrg	 * should try again.
163073143b9aSmrg	 *
163173143b9aSmrg	 * If multiple addresses are found for a host then we should
163273143b9aSmrg	 * try to connect again with a different address for a larger
163373143b9aSmrg	 * number of errors that made us quit before, since those
163473143b9aSmrg	 * could be caused by trying to use an IPv6 address to contact
163573143b9aSmrg	 * a machine with an IPv4-only server or other reasons that
1636fe567363Smrg	 * only affect one of a set of addresses.
163773143b9aSmrg	 */
163873143b9aSmrg
163973143b9aSmrg	if (olderrno == ECONNREFUSED || olderrno == EINTR
164073143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
1641b53e5eeaSmrg	  || (((addrlist->addr->ai_next != NULL) ||
164273143b9aSmrg	        (addrlist->addr != addrlist->firstaddr)) &&
164373143b9aSmrg               (olderrno == ENETUNREACH || olderrno == EAFNOSUPPORT ||
164473143b9aSmrg		 olderrno == EADDRNOTAVAIL || olderrno == ETIMEDOUT
164573143b9aSmrg#if defined(EHOSTDOWN)
164673143b9aSmrg		   || olderrno == EHOSTDOWN
164773143b9aSmrg#endif
164873143b9aSmrg	       ))
164973143b9aSmrg#endif
165073143b9aSmrg	    )
165173143b9aSmrg	    res = TRANS_TRY_CONNECT_AGAIN;
165273143b9aSmrg	else if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS)
165373143b9aSmrg	    res = TRANS_IN_PROGRESS;
165473143b9aSmrg	else
165573143b9aSmrg	{
1656fe567363Smrg	    prmsg (2,"SocketINETConnect: Can't connect: errno = %d\n",
1657fe567363Smrg		   olderrno);
165873143b9aSmrg
1659fe567363Smrg	    res = TRANS_CONNECT_FAILED;
166073143b9aSmrg	}
166173143b9aSmrg    } else {
166273143b9aSmrg	res = 0;
1663fe567363Smrg
166473143b9aSmrg
166573143b9aSmrg	/*
166673143b9aSmrg	 * Sync up the address fields of ciptr.
166773143b9aSmrg	 */
1668fe567363Smrg
166973143b9aSmrg	if (TRANS(SocketINETGetAddr) (ciptr) < 0)
167073143b9aSmrg	{
1671fe567363Smrg	    prmsg (1,
1672fe567363Smrg	     "SocketINETConnect: ...SocketINETGetAddr() failed:\n");
167373143b9aSmrg	    res = TRANS_CONNECT_FAILED;
167473143b9aSmrg	}
167573143b9aSmrg
167673143b9aSmrg	else if (TRANS(SocketINETGetPeerAddr) (ciptr) < 0)
167773143b9aSmrg	{
1678fe567363Smrg	    prmsg (1,
1679fe567363Smrg	      "SocketINETConnect: ...SocketINETGetPeerAddr() failed:\n");
168073143b9aSmrg	    res = TRANS_CONNECT_FAILED;
168173143b9aSmrg	}
168273143b9aSmrg    }
168373143b9aSmrg
168473143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
1685b53e5eeaSmrg   if (res != 0) {
168673143b9aSmrg	addrlist->addr = addrlist->addr->ai_next;
168773143b9aSmrg   }
168873143b9aSmrg#endif
168973143b9aSmrg
169073143b9aSmrg    return res;
169173143b9aSmrg}
169273143b9aSmrg
169373143b9aSmrg#endif /* TCPCONN */
169473143b9aSmrg
169573143b9aSmrg
169673143b9aSmrg
169773143b9aSmrg#ifdef UNIXCONN
169873143b9aSmrg
169973143b9aSmrg/*
170073143b9aSmrg * Make sure 'host' is really local.
170173143b9aSmrg */
170273143b9aSmrg
170373143b9aSmrgstatic int
17046a3641a6SsnjUnixHostReallyLocal (const char *host)
170573143b9aSmrg
170673143b9aSmrg{
170773143b9aSmrg    char hostnamebuf[256];
170873143b9aSmrg
170973143b9aSmrg    TRANS(GetHostname) (hostnamebuf, sizeof (hostnamebuf));
171073143b9aSmrg
171173143b9aSmrg    if (strcmp (hostnamebuf, host) == 0)
171273143b9aSmrg    {
171373143b9aSmrg	return (1);
1714b53e5eeaSmrg    } else {
171573143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
171673143b9aSmrg	struct addrinfo *localhostaddr;
171773143b9aSmrg	struct addrinfo *otherhostaddr;
171873143b9aSmrg	struct addrinfo *i, *j;
171973143b9aSmrg	int equiv = 0;
172073143b9aSmrg
172173143b9aSmrg	if (getaddrinfo(hostnamebuf, NULL, NULL, &localhostaddr) != 0)
172273143b9aSmrg	    return 0;
172373143b9aSmrg	if (getaddrinfo(host, NULL, NULL, &otherhostaddr) != 0) {
172473143b9aSmrg	    freeaddrinfo(localhostaddr);
172573143b9aSmrg	    return 0;
172673143b9aSmrg	}
172773143b9aSmrg
172873143b9aSmrg	for (i = localhostaddr; i != NULL && equiv == 0; i = i->ai_next) {
172973143b9aSmrg	    for (j = otherhostaddr; j != NULL && equiv == 0; j = j->ai_next) {
173073143b9aSmrg		if (i->ai_family == j->ai_family) {
173173143b9aSmrg		    if (i->ai_family == AF_INET) {
1732fe567363Smrg			struct sockaddr_in *sinA
173373143b9aSmrg			  = (struct sockaddr_in *) i->ai_addr;
173473143b9aSmrg			struct sockaddr_in *sinB
173573143b9aSmrg			  = (struct sockaddr_in *) j->ai_addr;
173673143b9aSmrg			struct in_addr *A = &sinA->sin_addr;
173773143b9aSmrg			struct in_addr *B = &sinB->sin_addr;
173873143b9aSmrg
173973143b9aSmrg			if (memcmp(A,B,sizeof(struct in_addr)) == 0) {
174073143b9aSmrg			    equiv = 1;
174173143b9aSmrg			}
174273143b9aSmrg		    } else if (i->ai_family == AF_INET6) {
1743fe567363Smrg			struct sockaddr_in6 *sinA
174473143b9aSmrg			  = (struct sockaddr_in6 *) i->ai_addr;
1745fe567363Smrg			struct sockaddr_in6 *sinB
174673143b9aSmrg			  = (struct sockaddr_in6 *) j->ai_addr;
174773143b9aSmrg			struct in6_addr *A = &sinA->sin6_addr;
174873143b9aSmrg			struct in6_addr *B = &sinB->sin6_addr;
174973143b9aSmrg
175073143b9aSmrg			if (memcmp(A,B,sizeof(struct in6_addr)) == 0) {
175173143b9aSmrg			    equiv = 1;
175273143b9aSmrg			}
175373143b9aSmrg		    }
175473143b9aSmrg		}
175573143b9aSmrg	    }
175673143b9aSmrg	}
1757fe567363Smrg
175873143b9aSmrg	freeaddrinfo(localhostaddr);
175973143b9aSmrg	freeaddrinfo(otherhostaddr);
176073143b9aSmrg	return equiv;
1761b53e5eeaSmrg#else
176273143b9aSmrg	/*
176373143b9aSmrg	 * A host may have more than one network address.  If any of the
176473143b9aSmrg	 * network addresses of 'host' (specified to the connect call)
176573143b9aSmrg	 * match any of the network addresses of 'hostname' (determined
176673143b9aSmrg	 * by TRANS(GetHostname)), then the two hostnames are equivalent,
176773143b9aSmrg	 * and we know that 'host' is really a local host.
176873143b9aSmrg	 */
176973143b9aSmrg	char specified_local_addr_list[10][4];
177073143b9aSmrg	int scount, equiv, i, j;
177173143b9aSmrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
177273143b9aSmrg	_Xgethostbynameparams hparams;
177373143b9aSmrg#endif
177473143b9aSmrg	struct hostent *hostp;
177573143b9aSmrg
177673143b9aSmrg	if ((hostp = _XGethostbyname (host,hparams)) == NULL)
177773143b9aSmrg	    return (0);
177873143b9aSmrg
177973143b9aSmrg	scount = 0;
178073143b9aSmrg	while (hostp->h_addr_list[scount] && scount <= 8)
178173143b9aSmrg	{
178273143b9aSmrg	    /*
178373143b9aSmrg	     * The 2nd call to gethostname() overrides the data
178473143b9aSmrg	     * from the 1st call, so we must save the address list.
178573143b9aSmrg	     */
178673143b9aSmrg
1787fe567363Smrg	    specified_local_addr_list[scount][0] =
178873143b9aSmrg				hostp->h_addr_list[scount][0];
1789fe567363Smrg	    specified_local_addr_list[scount][1] =
179073143b9aSmrg				hostp->h_addr_list[scount][1];
1791fe567363Smrg	    specified_local_addr_list[scount][2] =
179273143b9aSmrg				hostp->h_addr_list[scount][2];
1793fe567363Smrg	    specified_local_addr_list[scount][3] =
179473143b9aSmrg				hostp->h_addr_list[scount][3];
179573143b9aSmrg	    scount++;
179673143b9aSmrg	}
179773143b9aSmrg	if ((hostp = _XGethostbyname (hostnamebuf,hparams)) == NULL)
179873143b9aSmrg	    return (0);
179973143b9aSmrg
180073143b9aSmrg	equiv = 0;
180173143b9aSmrg	i = 0;
180273143b9aSmrg
180373143b9aSmrg	while (i < scount && !equiv)
180473143b9aSmrg	{
180573143b9aSmrg	    j = 0;
180673143b9aSmrg
180773143b9aSmrg	    while (hostp->h_addr_list[j])
180873143b9aSmrg	    {
1809fe567363Smrg		if ((specified_local_addr_list[i][0] ==
181073143b9aSmrg					hostp->h_addr_list[j][0]) &&
1811fe567363Smrg		    (specified_local_addr_list[i][1] ==
181273143b9aSmrg					hostp->h_addr_list[j][1]) &&
1813fe567363Smrg		    (specified_local_addr_list[i][2] ==
181473143b9aSmrg					hostp->h_addr_list[j][2]) &&
1815fe567363Smrg		    (specified_local_addr_list[i][3] ==
181673143b9aSmrg					hostp->h_addr_list[j][3]))
181773143b9aSmrg		{
181873143b9aSmrg		    /* They're equal, so we're done */
1819fe567363Smrg
182073143b9aSmrg		    equiv = 1;
182173143b9aSmrg		    break;
182273143b9aSmrg		}
182373143b9aSmrg
182473143b9aSmrg		j++;
182573143b9aSmrg	    }
182673143b9aSmrg
182773143b9aSmrg	    i++;
182873143b9aSmrg	}
182973143b9aSmrg	return (equiv);
1830b53e5eeaSmrg#endif
183173143b9aSmrg    }
183273143b9aSmrg}
183373143b9aSmrg
183473143b9aSmrgstatic int
18356a3641a6SsnjTRANS(SocketUNIXConnect) (XtransConnInfo ciptr,
18366a3641a6Ssnj                          const char *host, const char *port)
183773143b9aSmrg
183873143b9aSmrg{
183973143b9aSmrg    struct sockaddr_un	sockname;
184073143b9aSmrg    SOCKLEN_T		namelen;
184173143b9aSmrg
1842fe567363Smrg    prmsg (2,"SocketUNIXConnect(%d,%s,%s)\n", ciptr->fd, host, port);
1843fe567363Smrg
184473143b9aSmrg    /*
184573143b9aSmrg     * Make sure 'host' is really local.  If not, we return failure.
184673143b9aSmrg     * The reason we make this check is because a process may advertise
184773143b9aSmrg     * a "local" network ID for which it can accept connections, but if
184873143b9aSmrg     * a process on a remote machine tries to connect to this network ID,
184973143b9aSmrg     * we know for sure it will fail.
185073143b9aSmrg     */
185173143b9aSmrg
185273143b9aSmrg    if (host && *host && host[0]!='/' && strcmp (host, "unix") != 0 && !UnixHostReallyLocal (host))
185373143b9aSmrg    {
1854fe567363Smrg	prmsg (1,
185573143b9aSmrg	   "SocketUNIXConnect: Cannot connect to non-local host %s\n",
1856fe567363Smrg	       host);
185773143b9aSmrg	return TRANS_CONNECT_FAILED;
185873143b9aSmrg    }
185973143b9aSmrg
186073143b9aSmrg
186173143b9aSmrg    /*
186273143b9aSmrg     * Check the port.
186373143b9aSmrg     */
186473143b9aSmrg
186573143b9aSmrg    if (!port || !*port)
186673143b9aSmrg    {
1867fe567363Smrg	prmsg (1,"SocketUNIXConnect: Missing port specification\n");
186873143b9aSmrg	return TRANS_CONNECT_FAILED;
186973143b9aSmrg    }
187073143b9aSmrg
187173143b9aSmrg    /*
187273143b9aSmrg     * Build the socket name.
187373143b9aSmrg     */
1874fe567363Smrg
187573143b9aSmrg    sockname.sun_family = AF_UNIX;
187673143b9aSmrg
1877a773ec55Smrg    if (set_sun_path(port, UNIX_PATH, sockname.sun_path, 0) != 0) {
1878fe567363Smrg	prmsg (1, "SocketUNIXConnect: path too long\n");
187973143b9aSmrg	return TRANS_CONNECT_FAILED;
188073143b9aSmrg    }
188173143b9aSmrg
1882a773ec55Smrg#if defined(BSD44SOCKETS)
188373143b9aSmrg    sockname.sun_len = strlen (sockname.sun_path);
188473143b9aSmrg#endif
188573143b9aSmrg
188673143b9aSmrg#if defined(BSD44SOCKETS) || defined(SUN_LEN)
188773143b9aSmrg    namelen = SUN_LEN (&sockname);
188873143b9aSmrg#else
188973143b9aSmrg    namelen = strlen (sockname.sun_path) + offsetof(struct sockaddr_un, sun_path);
189073143b9aSmrg#endif
189173143b9aSmrg
189273143b9aSmrg
189373143b9aSmrg    /*
189473143b9aSmrg     * Do the connect()
189573143b9aSmrg     */
189673143b9aSmrg
189773143b9aSmrg    if (connect (ciptr->fd, (struct sockaddr *) &sockname, namelen) < 0)
189873143b9aSmrg    {
189973143b9aSmrg	int olderrno = errno;
190073143b9aSmrg	int connected = 0;
1901fe567363Smrg
190273143b9aSmrg	if (!connected)
190373143b9aSmrg	{
190473143b9aSmrg	    errno = olderrno;
1905fe567363Smrg
190673143b9aSmrg	    /*
190773143b9aSmrg	     * If the error was ENOENT, the server may be starting up; we used
190873143b9aSmrg	     * to suggest to try again in this case with
190973143b9aSmrg	     * TRANS_TRY_CONNECT_AGAIN, but this introduced problems for
191073143b9aSmrg	     * processes still referencing stale sockets in their environment.
191173143b9aSmrg	     * Hence, we now return a hard error, TRANS_CONNECT_FAILED, and it
191273143b9aSmrg	     * is suggested that higher level stacks handle retries on their
191373143b9aSmrg	     * level when they face a slow starting server.
191473143b9aSmrg	     *
191573143b9aSmrg	     * If the error was EWOULDBLOCK or EINPROGRESS then the socket
191673143b9aSmrg	     * was non-blocking and we should poll using select
191773143b9aSmrg	     *
191873143b9aSmrg	     * If the error was EINTR, the connect was interrupted and we
191973143b9aSmrg	     * should try again.
192073143b9aSmrg	     */
192173143b9aSmrg
192273143b9aSmrg	    if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS)
192373143b9aSmrg		return TRANS_IN_PROGRESS;
192473143b9aSmrg	    else if (olderrno == EINTR)
192573143b9aSmrg		return TRANS_TRY_CONNECT_AGAIN;
1926a773ec55Smrg	    else {
1927fe567363Smrg		prmsg (2,"SocketUNIXConnect: Can't connect: errno = %d\n",
1928fe567363Smrg		       EGET());
192973143b9aSmrg
193073143b9aSmrg		return TRANS_CONNECT_FAILED;
193173143b9aSmrg	    }
193273143b9aSmrg	}
193373143b9aSmrg    }
193473143b9aSmrg
193573143b9aSmrg    /*
193673143b9aSmrg     * Get the socket name and the peer name from the connect socket,
193773143b9aSmrg     * since this is unix domain.
193873143b9aSmrg     */
193973143b9aSmrg
1940fe567363Smrg    if ((ciptr->addr = malloc(namelen)) == NULL ||
1941fe567363Smrg       (ciptr->peeraddr = malloc(namelen)) == NULL)
194273143b9aSmrg    {
1943fe567363Smrg        prmsg (1,
1944fe567363Smrg	"SocketUNIXCreateListener: Can't allocate space for the addr\n");
194573143b9aSmrg        return TRANS_CONNECT_FAILED;
194673143b9aSmrg    }
194773143b9aSmrg
194873143b9aSmrg    ciptr->family = AF_UNIX;
194973143b9aSmrg    ciptr->addrlen = namelen;
195073143b9aSmrg    ciptr->peeraddrlen = namelen;
195173143b9aSmrg    memcpy (ciptr->addr, &sockname, ciptr->addrlen);
195273143b9aSmrg    memcpy (ciptr->peeraddr, &sockname, ciptr->peeraddrlen);
195373143b9aSmrg
195473143b9aSmrg    return 0;
195573143b9aSmrg}
195673143b9aSmrg
195773143b9aSmrg#endif /* UNIXCONN */
195873143b9aSmrg
195973143b9aSmrg#endif /* TRANS_CLIENT */
196073143b9aSmrg
196173143b9aSmrg
196273143b9aSmrgstatic int
196373143b9aSmrgTRANS(SocketBytesReadable) (XtransConnInfo ciptr, BytesReadable_t *pend)
196473143b9aSmrg
196573143b9aSmrg{
1966fe567363Smrg    prmsg (2,"SocketBytesReadable(%p,%d,%p)\n",
196773143b9aSmrg	ciptr, ciptr->fd, pend);
196873143b9aSmrg#ifdef WIN32
196973143b9aSmrg    {
197073143b9aSmrg	int ret = ioctlsocket ((SOCKET) ciptr->fd, FIONREAD, (u_long *) pend);
197173143b9aSmrg	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
197273143b9aSmrg	return ret;
197373143b9aSmrg    }
197473143b9aSmrg#else
197573143b9aSmrg    return ioctl (ciptr->fd, FIONREAD, (char *) pend);
197673143b9aSmrg#endif /* WIN32 */
197773143b9aSmrg}
197873143b9aSmrg
197975ebec6dSmrg#if XTRANS_SEND_FDS
198075ebec6dSmrg
198175ebec6dSmrgstatic void
198275ebec6dSmrgappendFd(struct _XtransConnFd **prev, int fd, int do_close)
198375ebec6dSmrg{
198475ebec6dSmrg    struct _XtransConnFd *cf, *new;
198575ebec6dSmrg
198675ebec6dSmrg    new = malloc (sizeof (struct _XtransConnFd));
198775ebec6dSmrg    if (!new) {
198875ebec6dSmrg        /* XXX mark connection as broken */
198975ebec6dSmrg        close(fd);
199075ebec6dSmrg        return;
199175ebec6dSmrg    }
199275ebec6dSmrg    new->next = 0;
199375ebec6dSmrg    new->fd = fd;
199475ebec6dSmrg    new->do_close = do_close;
199575ebec6dSmrg    /* search to end of list */
199675ebec6dSmrg    for (; (cf = *prev); prev = &(cf->next));
199775ebec6dSmrg    *prev = new;
199875ebec6dSmrg}
199973143b9aSmrg
200073143b9aSmrgstatic int
200175ebec6dSmrgremoveFd(struct _XtransConnFd **prev)
200275ebec6dSmrg{
200375ebec6dSmrg    struct _XtransConnFd *cf;
200475ebec6dSmrg    int fd;
200575ebec6dSmrg
200675ebec6dSmrg    if ((cf = *prev)) {
200775ebec6dSmrg        *prev = cf->next;
200875ebec6dSmrg        fd = cf->fd;
200975ebec6dSmrg        free(cf);
201075ebec6dSmrg    } else
201175ebec6dSmrg        fd = -1;
201275ebec6dSmrg    return fd;
201375ebec6dSmrg}
201473143b9aSmrg
201575ebec6dSmrgstatic void
201675ebec6dSmrgdiscardFd(struct _XtransConnFd **prev, struct _XtransConnFd *upto, int do_close)
201773143b9aSmrg{
201875ebec6dSmrg    struct _XtransConnFd *cf, *next;
201973143b9aSmrg
202075ebec6dSmrg    for (cf = *prev; cf != upto; cf = next) {
202175ebec6dSmrg        next = cf->next;
202275ebec6dSmrg        if (do_close || cf->do_close)
202375ebec6dSmrg            close(cf->fd);
202475ebec6dSmrg        free(cf);
202573143b9aSmrg    }
202675ebec6dSmrg    *prev = upto;
202773143b9aSmrg}
202873143b9aSmrg
202975ebec6dSmrgstatic void
203075ebec6dSmrgcleanupFds(XtransConnInfo ciptr)
203175ebec6dSmrg{
203275ebec6dSmrg    /* Clean up the send list but don't close the fds */
203375ebec6dSmrg    discardFd(&ciptr->send_fds, NULL, 0);
203475ebec6dSmrg    /* Clean up the recv list and *do* close the fds */
203575ebec6dSmrg    discardFd(&ciptr->recv_fds, NULL, 1);
203675ebec6dSmrg}
203773143b9aSmrg
203873143b9aSmrgstatic int
203975ebec6dSmrgnFd(struct _XtransConnFd **prev)
204075ebec6dSmrg{
204175ebec6dSmrg    struct _XtransConnFd *cf;
204275ebec6dSmrg    int n = 0;
204375ebec6dSmrg
204475ebec6dSmrg    for (cf = *prev; cf; cf = cf->next)
204575ebec6dSmrg        n++;
204675ebec6dSmrg    return n;
204775ebec6dSmrg}
204873143b9aSmrg
204975ebec6dSmrgstatic int
205075ebec6dSmrgTRANS(SocketRecvFd) (XtransConnInfo ciptr)
205173143b9aSmrg{
205275ebec6dSmrg    prmsg (2, "SocketRecvFd(%d)\n", ciptr->fd);
205375ebec6dSmrg    return removeFd(&ciptr->recv_fds);
205475ebec6dSmrg}
205575ebec6dSmrg
205675ebec6dSmrgstatic int
205775ebec6dSmrgTRANS(SocketSendFd) (XtransConnInfo ciptr, int fd, int do_close)
205875ebec6dSmrg{
205975ebec6dSmrg    appendFd(&ciptr->send_fds, fd, do_close);
206075ebec6dSmrg    return 0;
206175ebec6dSmrg}
206275ebec6dSmrg
206375ebec6dSmrgstatic int
206475ebec6dSmrgTRANS(SocketRecvFdInvalid)(XtransConnInfo ciptr)
206575ebec6dSmrg{
206675ebec6dSmrg    errno = EINVAL;
206775ebec6dSmrg    return -1;
206875ebec6dSmrg}
206975ebec6dSmrg
207075ebec6dSmrgstatic int
207175ebec6dSmrgTRANS(SocketSendFdInvalid)(XtransConnInfo ciptr, int fd, int do_close)
207275ebec6dSmrg{
207375ebec6dSmrg    errno = EINVAL;
207475ebec6dSmrg    return -1;
207575ebec6dSmrg}
207675ebec6dSmrg
207775ebec6dSmrg#define MAX_FDS		128
207875ebec6dSmrg
207975ebec6dSmrgunion fd_pass {
208075ebec6dSmrg	struct cmsghdr	cmsghdr;
208175ebec6dSmrg	char		buf[CMSG_SPACE(MAX_FDS * sizeof(int))];
208275ebec6dSmrg};
208375ebec6dSmrg
208475ebec6dSmrg#endif /* XTRANS_SEND_FDS */
208575ebec6dSmrg
208675ebec6dSmrgstatic int
208775ebec6dSmrgTRANS(SocketRead) (XtransConnInfo ciptr, char *buf, int size)
208875ebec6dSmrg
208975ebec6dSmrg{
209075ebec6dSmrg    prmsg (2,"SocketRead(%d,%p,%d)\n", ciptr->fd, buf, size);
209173143b9aSmrg
2092fe567363Smrg#if defined(WIN32)
209373143b9aSmrg    {
209475ebec6dSmrg	int ret = recv ((SOCKET)ciptr->fd, buf, size, 0);
209573143b9aSmrg#ifdef WIN32
209673143b9aSmrg	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
209773143b9aSmrg#endif
209873143b9aSmrg	return ret;
209973143b9aSmrg    }
210073143b9aSmrg#else
210175ebec6dSmrg#if XTRANS_SEND_FDS
210275ebec6dSmrg    {
210375ebec6dSmrg        struct iovec    iov = {
210475ebec6dSmrg            .iov_base = buf,
210575ebec6dSmrg            .iov_len = size
210675ebec6dSmrg        };
210775ebec6dSmrg        union fd_pass   cmsgbuf;
210875ebec6dSmrg        struct msghdr   msg = {
210975ebec6dSmrg            .msg_name = NULL,
211075ebec6dSmrg            .msg_namelen = 0,
211175ebec6dSmrg            .msg_iov = &iov,
211275ebec6dSmrg            .msg_iovlen = 1,
211375ebec6dSmrg            .msg_control = cmsgbuf.buf,
211475ebec6dSmrg            .msg_controllen = CMSG_LEN(MAX_FDS * sizeof(int))
211575ebec6dSmrg        };
211675ebec6dSmrg
211775ebec6dSmrg        size = recvmsg(ciptr->fd, &msg, 0);
211875ebec6dSmrg        if (size >= 0) {
211975ebec6dSmrg            struct cmsghdr *hdr;
212075ebec6dSmrg
212175ebec6dSmrg            for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) {
212275ebec6dSmrg                if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) {
212375ebec6dSmrg                    int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int);
212475ebec6dSmrg                    int i;
212575ebec6dSmrg                    int *fd = (int *) CMSG_DATA(hdr);
212675ebec6dSmrg
212775ebec6dSmrg                    for (i = 0; i < nfd; i++)
212875ebec6dSmrg                        appendFd(&ciptr->recv_fds, fd[i], 0);
212975ebec6dSmrg                }
213075ebec6dSmrg            }
213175ebec6dSmrg        }
213275ebec6dSmrg        return size;
213375ebec6dSmrg    }
213475ebec6dSmrg#else
213575ebec6dSmrg    return read(ciptr->fd, buf, size);
213675ebec6dSmrg#endif /* XTRANS_SEND_FDS */
213773143b9aSmrg#endif /* WIN32 */
213873143b9aSmrg}
213973143b9aSmrg
214073143b9aSmrgstatic int
214173143b9aSmrgTRANS(SocketReadv) (XtransConnInfo ciptr, struct iovec *buf, int size)
214273143b9aSmrg
214373143b9aSmrg{
2144fe567363Smrg    prmsg (2,"SocketReadv(%d,%p,%d)\n", ciptr->fd, buf, size);
214573143b9aSmrg
214675ebec6dSmrg#if XTRANS_SEND_FDS
214775ebec6dSmrg    {
214875ebec6dSmrg        union fd_pass   cmsgbuf;
214975ebec6dSmrg        struct msghdr   msg = {
215075ebec6dSmrg            .msg_name = NULL,
215175ebec6dSmrg            .msg_namelen = 0,
215275ebec6dSmrg            .msg_iov = buf,
215375ebec6dSmrg            .msg_iovlen = size,
215475ebec6dSmrg            .msg_control = cmsgbuf.buf,
215575ebec6dSmrg            .msg_controllen = CMSG_LEN(MAX_FDS * sizeof(int))
215675ebec6dSmrg        };
215775ebec6dSmrg
215875ebec6dSmrg        size = recvmsg(ciptr->fd, &msg, 0);
215975ebec6dSmrg        if (size >= 0) {
216075ebec6dSmrg            struct cmsghdr *hdr;
216175ebec6dSmrg
216275ebec6dSmrg            for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) {
216375ebec6dSmrg                if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) {
216475ebec6dSmrg                    int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int);
216575ebec6dSmrg                    int i;
216675ebec6dSmrg                    int *fd = (int *) CMSG_DATA(hdr);
216775ebec6dSmrg
216875ebec6dSmrg                    for (i = 0; i < nfd; i++)
216975ebec6dSmrg                        appendFd(&ciptr->recv_fds, fd[i], 0);
217075ebec6dSmrg                }
217175ebec6dSmrg            }
217275ebec6dSmrg        }
217375ebec6dSmrg        return size;
217475ebec6dSmrg    }
217575ebec6dSmrg#else
217673143b9aSmrg    return READV (ciptr, buf, size);
217775ebec6dSmrg#endif
217873143b9aSmrg}
217973143b9aSmrg
218073143b9aSmrg
218173143b9aSmrgstatic int
218273143b9aSmrgTRANS(SocketWritev) (XtransConnInfo ciptr, struct iovec *buf, int size)
218373143b9aSmrg
218473143b9aSmrg{
2185fe567363Smrg    prmsg (2,"SocketWritev(%d,%p,%d)\n", ciptr->fd, buf, size);
218673143b9aSmrg
218775ebec6dSmrg#if XTRANS_SEND_FDS
218875ebec6dSmrg    if (ciptr->send_fds)
218975ebec6dSmrg    {
219075ebec6dSmrg        union fd_pass           cmsgbuf;
219175ebec6dSmrg        int                     nfd = nFd(&ciptr->send_fds);
219275ebec6dSmrg        struct _XtransConnFd    *cf = ciptr->send_fds;
219375ebec6dSmrg        struct msghdr           msg = {
219475ebec6dSmrg            .msg_name = NULL,
219575ebec6dSmrg            .msg_namelen = 0,
219675ebec6dSmrg            .msg_iov = buf,
219775ebec6dSmrg            .msg_iovlen = size,
219875ebec6dSmrg            .msg_control = cmsgbuf.buf,
219975ebec6dSmrg            .msg_controllen = CMSG_LEN(nfd * sizeof(int))
220075ebec6dSmrg        };
220175ebec6dSmrg        struct cmsghdr          *hdr = CMSG_FIRSTHDR(&msg);
220275ebec6dSmrg        int                     i;
220375ebec6dSmrg        int                     *fds;
220475ebec6dSmrg
220575ebec6dSmrg        hdr->cmsg_len = msg.msg_controllen;
220675ebec6dSmrg        hdr->cmsg_level = SOL_SOCKET;
220775ebec6dSmrg        hdr->cmsg_type = SCM_RIGHTS;
220875ebec6dSmrg
220975ebec6dSmrg        fds = (int *) CMSG_DATA(hdr);
221075ebec6dSmrg        /* Set up fds */
221175ebec6dSmrg        for (i = 0; i < nfd; i++) {
221275ebec6dSmrg            fds[i] = cf->fd;
221375ebec6dSmrg            cf = cf->next;
221475ebec6dSmrg        }
221575ebec6dSmrg
221675ebec6dSmrg        i = sendmsg(ciptr->fd, &msg, 0);
221775ebec6dSmrg        if (i > 0)
221875ebec6dSmrg            discardFd(&ciptr->send_fds, cf, 0);
221975ebec6dSmrg        return i;
222075ebec6dSmrg    }
222175ebec6dSmrg#endif
222273143b9aSmrg    return WRITEV (ciptr, buf, size);
222373143b9aSmrg}
222473143b9aSmrg
222573143b9aSmrg
222675ebec6dSmrgstatic int
222775ebec6dSmrgTRANS(SocketWrite) (XtransConnInfo ciptr, char *buf, int size)
222875ebec6dSmrg
222975ebec6dSmrg{
223075ebec6dSmrg    prmsg (2,"SocketWrite(%d,%p,%d)\n", ciptr->fd, buf, size);
223175ebec6dSmrg
223275ebec6dSmrg#if defined(WIN32)
223375ebec6dSmrg    {
223475ebec6dSmrg	int ret = send ((SOCKET)ciptr->fd, buf, size, 0);
223575ebec6dSmrg#ifdef WIN32
223675ebec6dSmrg	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
223775ebec6dSmrg#endif
223875ebec6dSmrg	return ret;
223975ebec6dSmrg    }
224075ebec6dSmrg#else
224175ebec6dSmrg#if XTRANS_SEND_FDS
224275ebec6dSmrg    if (ciptr->send_fds)
224375ebec6dSmrg    {
224475ebec6dSmrg        struct iovec            iov;
224575ebec6dSmrg
224675ebec6dSmrg        iov.iov_base = buf;
224775ebec6dSmrg        iov.iov_len = size;
224875ebec6dSmrg        return TRANS(SocketWritev)(ciptr, &iov, 1);
224975ebec6dSmrg    }
225075ebec6dSmrg#endif /* XTRANS_SEND_FDS */
225175ebec6dSmrg    return write (ciptr->fd, buf, size);
225275ebec6dSmrg#endif /* WIN32 */
225375ebec6dSmrg}
225475ebec6dSmrg
225573143b9aSmrgstatic int
225673143b9aSmrgTRANS(SocketDisconnect) (XtransConnInfo ciptr)
225773143b9aSmrg
225873143b9aSmrg{
2259fe567363Smrg    prmsg (2,"SocketDisconnect(%p,%d)\n", ciptr, ciptr->fd);
226073143b9aSmrg
226173143b9aSmrg#ifdef WIN32
2262fe567363Smrg    {
226373143b9aSmrg	int ret = shutdown (ciptr->fd, 2);
226473143b9aSmrg	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
226573143b9aSmrg	return ret;
226673143b9aSmrg    }
226773143b9aSmrg#else
226873143b9aSmrg    return shutdown (ciptr->fd, 2); /* disallow further sends and receives */
226973143b9aSmrg#endif
227073143b9aSmrg}
227173143b9aSmrg
227273143b9aSmrg
227373143b9aSmrg#ifdef TCPCONN
227473143b9aSmrgstatic int
227573143b9aSmrgTRANS(SocketINETClose) (XtransConnInfo ciptr)
227673143b9aSmrg
227773143b9aSmrg{
2278fe567363Smrg    prmsg (2,"SocketINETClose(%p,%d)\n", ciptr, ciptr->fd);
227973143b9aSmrg
228073143b9aSmrg#ifdef WIN32
228173143b9aSmrg    {
228273143b9aSmrg	int ret = close (ciptr->fd);
228373143b9aSmrg	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
228473143b9aSmrg	return ret;
228573143b9aSmrg    }
228673143b9aSmrg#else
228773143b9aSmrg    return close (ciptr->fd);
228873143b9aSmrg#endif
228973143b9aSmrg}
229073143b9aSmrg
229173143b9aSmrg#endif /* TCPCONN */
229273143b9aSmrg
229373143b9aSmrg
229473143b9aSmrg#ifdef UNIXCONN
229573143b9aSmrgstatic int
229673143b9aSmrgTRANS(SocketUNIXClose) (XtransConnInfo ciptr)
229773143b9aSmrg{
229873143b9aSmrg    /*
229973143b9aSmrg     * If this is the server side, then once the socket is closed,
230073143b9aSmrg     * it must be unlinked to completely close it
230173143b9aSmrg     */
230273143b9aSmrg
230373143b9aSmrg    struct sockaddr_un	*sockname = (struct sockaddr_un *) ciptr->addr;
230473143b9aSmrg    int ret;
230573143b9aSmrg
2306fe567363Smrg    prmsg (2,"SocketUNIXClose(%p,%d)\n", ciptr, ciptr->fd);
230773143b9aSmrg
230875ebec6dSmrg#if XTRANS_SEND_FDS
230975ebec6dSmrg    cleanupFds(ciptr);
231075ebec6dSmrg#endif
231173143b9aSmrg    ret = close(ciptr->fd);
231273143b9aSmrg
231373143b9aSmrg    if (ciptr->flags
231473143b9aSmrg       && sockname
231573143b9aSmrg       && sockname->sun_family == AF_UNIX
231673143b9aSmrg       && sockname->sun_path[0])
231773143b9aSmrg    {
231873143b9aSmrg	if (!(ciptr->flags & TRANS_NOUNLINK
231973143b9aSmrg	    || ciptr->transptr->flags & TRANS_ABSTRACT))
232073143b9aSmrg		unlink (sockname->sun_path);
232173143b9aSmrg    }
232273143b9aSmrg
232373143b9aSmrg    return ret;
232473143b9aSmrg}
232573143b9aSmrg
232673143b9aSmrgstatic int
232773143b9aSmrgTRANS(SocketUNIXCloseForCloning) (XtransConnInfo ciptr)
232873143b9aSmrg
232973143b9aSmrg{
233073143b9aSmrg    /*
233173143b9aSmrg     * Don't unlink path.
233273143b9aSmrg     */
233373143b9aSmrg
233473143b9aSmrg    int ret;
233573143b9aSmrg
2336fe567363Smrg    prmsg (2,"SocketUNIXCloseForCloning(%p,%d)\n",
2337fe567363Smrg	ciptr, ciptr->fd);
233873143b9aSmrg
233975ebec6dSmrg#if XTRANS_SEND_FDS
234075ebec6dSmrg    cleanupFds(ciptr);
234175ebec6dSmrg#endif
234273143b9aSmrg    ret = close(ciptr->fd);
234373143b9aSmrg
234473143b9aSmrg    return ret;
234573143b9aSmrg}
234673143b9aSmrg
234773143b9aSmrg#endif /* UNIXCONN */
234873143b9aSmrg
234973143b9aSmrg
235073143b9aSmrg#ifdef TCPCONN
235173143b9aSmrg# ifdef TRANS_SERVER
2352fe567363Smrgstatic const char* tcp_nolisten[] = {
235373143b9aSmrg	"inet",
235473143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
235573143b9aSmrg	"inet6",
235673143b9aSmrg#endif
235773143b9aSmrg	NULL
235873143b9aSmrg};
235973143b9aSmrg# endif
236073143b9aSmrg
236173143b9aSmrgXtransport	TRANS(SocketTCPFuncs) = {
236273143b9aSmrg	/* Socket Interface */
236373143b9aSmrg	"tcp",
236473143b9aSmrg        TRANS_ALIAS,
236573143b9aSmrg#ifdef TRANS_CLIENT
236673143b9aSmrg	TRANS(SocketOpenCOTSClient),
236773143b9aSmrg#endif /* TRANS_CLIENT */
236873143b9aSmrg#ifdef TRANS_SERVER
236973143b9aSmrg	tcp_nolisten,
237073143b9aSmrg	TRANS(SocketOpenCOTSServer),
237173143b9aSmrg#endif /* TRANS_SERVER */
237273143b9aSmrg#ifdef TRANS_REOPEN
237373143b9aSmrg	TRANS(SocketReopenCOTSServer),
237473143b9aSmrg#endif
237573143b9aSmrg	TRANS(SocketSetOption),
237673143b9aSmrg#ifdef TRANS_SERVER
237773143b9aSmrg	TRANS(SocketINETCreateListener),
237873143b9aSmrg	NULL,		       			/* ResetListener */
237973143b9aSmrg	TRANS(SocketINETAccept),
238073143b9aSmrg#endif /* TRANS_SERVER */
238173143b9aSmrg#ifdef TRANS_CLIENT
238273143b9aSmrg	TRANS(SocketINETConnect),
238373143b9aSmrg#endif /* TRANS_CLIENT */
238473143b9aSmrg	TRANS(SocketBytesReadable),
238573143b9aSmrg	TRANS(SocketRead),
238673143b9aSmrg	TRANS(SocketWrite),
238773143b9aSmrg	TRANS(SocketReadv),
238873143b9aSmrg	TRANS(SocketWritev),
238975ebec6dSmrg#if XTRANS_SEND_FDS
239075ebec6dSmrg        TRANS(SocketSendFdInvalid),
239175ebec6dSmrg        TRANS(SocketRecvFdInvalid),
239275ebec6dSmrg#endif
239373143b9aSmrg	TRANS(SocketDisconnect),
239473143b9aSmrg	TRANS(SocketINETClose),
239573143b9aSmrg	TRANS(SocketINETClose),
239673143b9aSmrg	};
239773143b9aSmrg
239873143b9aSmrgXtransport	TRANS(SocketINETFuncs) = {
239973143b9aSmrg	/* Socket Interface */
240073143b9aSmrg	"inet",
240173143b9aSmrg	0,
240273143b9aSmrg#ifdef TRANS_CLIENT
240373143b9aSmrg	TRANS(SocketOpenCOTSClient),
240473143b9aSmrg#endif /* TRANS_CLIENT */
240573143b9aSmrg#ifdef TRANS_SERVER
240673143b9aSmrg	NULL,
240773143b9aSmrg	TRANS(SocketOpenCOTSServer),
240873143b9aSmrg#endif /* TRANS_SERVER */
240973143b9aSmrg#ifdef TRANS_REOPEN
241073143b9aSmrg	TRANS(SocketReopenCOTSServer),
241173143b9aSmrg#endif
241273143b9aSmrg	TRANS(SocketSetOption),
241373143b9aSmrg#ifdef TRANS_SERVER
241473143b9aSmrg	TRANS(SocketINETCreateListener),
241573143b9aSmrg	NULL,		       			/* ResetListener */
241673143b9aSmrg	TRANS(SocketINETAccept),
241773143b9aSmrg#endif /* TRANS_SERVER */
241873143b9aSmrg#ifdef TRANS_CLIENT
241973143b9aSmrg	TRANS(SocketINETConnect),
242073143b9aSmrg#endif /* TRANS_CLIENT */
242173143b9aSmrg	TRANS(SocketBytesReadable),
242273143b9aSmrg	TRANS(SocketRead),
242373143b9aSmrg	TRANS(SocketWrite),
242473143b9aSmrg	TRANS(SocketReadv),
242573143b9aSmrg	TRANS(SocketWritev),
242675ebec6dSmrg#if XTRANS_SEND_FDS
242775ebec6dSmrg        TRANS(SocketSendFdInvalid),
242875ebec6dSmrg        TRANS(SocketRecvFdInvalid),
242975ebec6dSmrg#endif
243073143b9aSmrg	TRANS(SocketDisconnect),
243173143b9aSmrg	TRANS(SocketINETClose),
243273143b9aSmrg	TRANS(SocketINETClose),
243373143b9aSmrg	};
243473143b9aSmrg
243573143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
243673143b9aSmrgXtransport     TRANS(SocketINET6Funcs) = {
243773143b9aSmrg	/* Socket Interface */
243873143b9aSmrg	"inet6",
243973143b9aSmrg	0,
244073143b9aSmrg#ifdef TRANS_CLIENT
244173143b9aSmrg	TRANS(SocketOpenCOTSClient),
244273143b9aSmrg#endif /* TRANS_CLIENT */
244373143b9aSmrg#ifdef TRANS_SERVER
244473143b9aSmrg	NULL,
244573143b9aSmrg	TRANS(SocketOpenCOTSServer),
244673143b9aSmrg#endif /* TRANS_SERVER */
244773143b9aSmrg#ifdef TRANS_REOPEN
244873143b9aSmrg	TRANS(SocketReopenCOTSServer),
244973143b9aSmrg#endif
245073143b9aSmrg	TRANS(SocketSetOption),
245173143b9aSmrg#ifdef TRANS_SERVER
245273143b9aSmrg	TRANS(SocketINETCreateListener),
245373143b9aSmrg	NULL,					/* ResetListener */
245473143b9aSmrg	TRANS(SocketINETAccept),
245573143b9aSmrg#endif /* TRANS_SERVER */
245673143b9aSmrg#ifdef TRANS_CLIENT
245773143b9aSmrg	TRANS(SocketINETConnect),
245873143b9aSmrg#endif /* TRANS_CLIENT */
245973143b9aSmrg	TRANS(SocketBytesReadable),
246073143b9aSmrg	TRANS(SocketRead),
246173143b9aSmrg	TRANS(SocketWrite),
246273143b9aSmrg	TRANS(SocketReadv),
246373143b9aSmrg	TRANS(SocketWritev),
246475ebec6dSmrg#if XTRANS_SEND_FDS
246575ebec6dSmrg        TRANS(SocketSendFdInvalid),
246675ebec6dSmrg        TRANS(SocketRecvFdInvalid),
246775ebec6dSmrg#endif
246873143b9aSmrg	TRANS(SocketDisconnect),
246973143b9aSmrg	TRANS(SocketINETClose),
247073143b9aSmrg	TRANS(SocketINETClose),
247173143b9aSmrg	};
247273143b9aSmrg#endif /* IPv6 */
247373143b9aSmrg#endif /* TCPCONN */
247473143b9aSmrg
247573143b9aSmrg#ifdef UNIXCONN
247673143b9aSmrg#if !defined(LOCALCONN)
247773143b9aSmrgXtransport	TRANS(SocketLocalFuncs) = {
247873143b9aSmrg	/* Socket Interface */
247973143b9aSmrg	"local",
248073143b9aSmrg#ifdef HAVE_ABSTRACT_SOCKETS
248173143b9aSmrg	TRANS_ABSTRACT,
248273143b9aSmrg#else
248373143b9aSmrg	0,
248473143b9aSmrg#endif
248573143b9aSmrg#ifdef TRANS_CLIENT
248673143b9aSmrg	TRANS(SocketOpenCOTSClient),
248773143b9aSmrg#endif /* TRANS_CLIENT */
248873143b9aSmrg#ifdef TRANS_SERVER
248973143b9aSmrg	NULL,
249073143b9aSmrg	TRANS(SocketOpenCOTSServer),
249173143b9aSmrg#endif /* TRANS_SERVER */
249273143b9aSmrg#ifdef TRANS_REOPEN
249373143b9aSmrg	TRANS(SocketReopenCOTSServer),
249473143b9aSmrg#endif
249573143b9aSmrg	TRANS(SocketSetOption),
249673143b9aSmrg#ifdef TRANS_SERVER
249773143b9aSmrg	TRANS(SocketUNIXCreateListener),
249873143b9aSmrg	TRANS(SocketUNIXResetListener),
249973143b9aSmrg	TRANS(SocketUNIXAccept),
250073143b9aSmrg#endif /* TRANS_SERVER */
250173143b9aSmrg#ifdef TRANS_CLIENT
250273143b9aSmrg	TRANS(SocketUNIXConnect),
250373143b9aSmrg#endif /* TRANS_CLIENT */
250473143b9aSmrg	TRANS(SocketBytesReadable),
250573143b9aSmrg	TRANS(SocketRead),
250673143b9aSmrg	TRANS(SocketWrite),
250773143b9aSmrg	TRANS(SocketReadv),
250873143b9aSmrg	TRANS(SocketWritev),
250975ebec6dSmrg#if XTRANS_SEND_FDS
251075ebec6dSmrg        TRANS(SocketSendFd),
251175ebec6dSmrg        TRANS(SocketRecvFd),
251275ebec6dSmrg#endif
251373143b9aSmrg	TRANS(SocketDisconnect),
251473143b9aSmrg	TRANS(SocketUNIXClose),
251573143b9aSmrg	TRANS(SocketUNIXCloseForCloning),
251673143b9aSmrg	};
251773143b9aSmrg#endif /* !LOCALCONN */
251873143b9aSmrg# ifdef TRANS_SERVER
251973143b9aSmrg#  if !defined(LOCALCONN)
252075ebec6dSmrgstatic const char* unix_nolisten[] = { "local" , NULL };
252173143b9aSmrg#  endif
252273143b9aSmrg# endif
2523fe567363Smrg
252473143b9aSmrgXtransport	TRANS(SocketUNIXFuncs) = {
252573143b9aSmrg	/* Socket Interface */
252673143b9aSmrg	"unix",
252773143b9aSmrg#if !defined(LOCALCONN) && !defined(HAVE_ABSTRACT_SOCKETS)
252873143b9aSmrg        TRANS_ALIAS,
252973143b9aSmrg#else
253073143b9aSmrg	0,
253173143b9aSmrg#endif
253273143b9aSmrg#ifdef TRANS_CLIENT
253373143b9aSmrg	TRANS(SocketOpenCOTSClient),
253473143b9aSmrg#endif /* TRANS_CLIENT */
253573143b9aSmrg#ifdef TRANS_SERVER
253673143b9aSmrg#if !defined(LOCALCONN)
253773143b9aSmrg	unix_nolisten,
253873143b9aSmrg#else
253973143b9aSmrg	NULL,
254073143b9aSmrg#endif
254173143b9aSmrg	TRANS(SocketOpenCOTSServer),
254273143b9aSmrg#endif /* TRANS_SERVER */
254373143b9aSmrg#ifdef TRANS_REOPEN
254473143b9aSmrg	TRANS(SocketReopenCOTSServer),
254573143b9aSmrg#endif
254673143b9aSmrg	TRANS(SocketSetOption),
254773143b9aSmrg#ifdef TRANS_SERVER
254873143b9aSmrg	TRANS(SocketUNIXCreateListener),
254973143b9aSmrg	TRANS(SocketUNIXResetListener),
255073143b9aSmrg	TRANS(SocketUNIXAccept),
255173143b9aSmrg#endif /* TRANS_SERVER */
255273143b9aSmrg#ifdef TRANS_CLIENT
255373143b9aSmrg	TRANS(SocketUNIXConnect),
255473143b9aSmrg#endif /* TRANS_CLIENT */
255573143b9aSmrg	TRANS(SocketBytesReadable),
255673143b9aSmrg	TRANS(SocketRead),
255773143b9aSmrg	TRANS(SocketWrite),
255873143b9aSmrg	TRANS(SocketReadv),
255973143b9aSmrg	TRANS(SocketWritev),
256075ebec6dSmrg#if XTRANS_SEND_FDS
256175ebec6dSmrg        TRANS(SocketSendFd),
256275ebec6dSmrg        TRANS(SocketRecvFd),
256375ebec6dSmrg#endif
256473143b9aSmrg	TRANS(SocketDisconnect),
256573143b9aSmrg	TRANS(SocketUNIXClose),
256673143b9aSmrg	TRANS(SocketUNIXCloseForCloning),
256773143b9aSmrg	};
256873143b9aSmrg
256973143b9aSmrg#endif /* UNIXCONN */
2570