Xtranssock.c revision 94f982db
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
19994f982dbSmrg#if (defined(TCPCONN) && defined(TRANS_SERVER)) || defined(TRANS_REOPEN) || \
20094f982dbSmrg    !defined(IPv6)
201a773ec55Smrgstatic int
202a773ec55Smrgis_numeric (const char *str)
203a773ec55Smrg{
204a773ec55Smrg    int i;
205a773ec55Smrg
206a773ec55Smrg    for (i = 0; i < (int) strlen (str); i++)
207a773ec55Smrg	if (!isdigit (str[i]))
208a773ec55Smrg	    return (0);
209a773ec55Smrg
210a773ec55Smrg    return (1);
211a773ec55Smrg}
212a773ec55Smrg#endif
213a773ec55Smrg
21473143b9aSmrg#ifdef UNIXCONN
21573143b9aSmrg
21673143b9aSmrg
21773143b9aSmrg#if defined(X11_t)
21873143b9aSmrg#define UNIX_PATH "/tmp/.X11-unix/X"
21973143b9aSmrg#define UNIX_DIR "/tmp/.X11-unix"
22073143b9aSmrg#endif /* X11_t */
22173143b9aSmrg#if defined(XIM_t)
22273143b9aSmrg#define UNIX_PATH "/tmp/.XIM-unix/XIM"
22373143b9aSmrg#define UNIX_DIR "/tmp/.XIM-unix"
22473143b9aSmrg#endif /* XIM_t */
22573143b9aSmrg#if defined(FS_t) || defined(FONT_t)
22673143b9aSmrg#define UNIX_PATH "/tmp/.font-unix/fs"
22773143b9aSmrg#define UNIX_DIR "/tmp/.font-unix"
22873143b9aSmrg#endif /* FS_t || FONT_t */
22973143b9aSmrg#if defined(ICE_t)
23073143b9aSmrg#define UNIX_PATH "/tmp/.ICE-unix/"
23173143b9aSmrg#define UNIX_DIR "/tmp/.ICE-unix"
23273143b9aSmrg#endif /* ICE_t */
23373143b9aSmrg
23473143b9aSmrg
23573143b9aSmrg#endif /* UNIXCONN */
23673143b9aSmrg
23773143b9aSmrg#define PORTBUFSIZE	32
23873143b9aSmrg
23973143b9aSmrg#ifndef MAXHOSTNAMELEN
24073143b9aSmrg#define MAXHOSTNAMELEN 255
24173143b9aSmrg#endif
24273143b9aSmrg
24373143b9aSmrg#if defined HAVE_SOCKLEN_T || (defined(IPv6) && defined(AF_INET6))
24473143b9aSmrg# define SOCKLEN_T socklen_t
245a773ec55Smrg#elif defined(SVR4) || defined(__SVR4)
246fe567363Smrg# define SOCKLEN_T size_t
24773143b9aSmrg#else
24873143b9aSmrg# define SOCKLEN_T int
24973143b9aSmrg#endif
25073143b9aSmrg
25173143b9aSmrg/*
25273143b9aSmrg * These are some utility function used by the real interface function below.
25373143b9aSmrg */
25473143b9aSmrg
25573143b9aSmrgstatic int
256fe567363SmrgTRANS(SocketSelectFamily) (int first, const char *family)
25773143b9aSmrg
25873143b9aSmrg{
25973143b9aSmrg    int     i;
26073143b9aSmrg
261fe567363Smrg    prmsg (3,"SocketSelectFamily(%s)\n", family);
26273143b9aSmrg
26394f982dbSmrg    for (i = first + 1; i < (int)NUMSOCKETFAMILIES; i++)
26473143b9aSmrg    {
26573143b9aSmrg        if (!strcmp (family, Sockettrans2devtab[i].transname))
26673143b9aSmrg	    return i;
26773143b9aSmrg    }
26873143b9aSmrg
26973143b9aSmrg    return (first == -1 ? -2 : -1);
27073143b9aSmrg}
27173143b9aSmrg
27273143b9aSmrg
27373143b9aSmrg/*
27473143b9aSmrg * This function gets the local address of the socket and stores it in the
27573143b9aSmrg * XtransConnInfo structure for the connection.
27673143b9aSmrg */
27773143b9aSmrg
27873143b9aSmrgstatic int
27973143b9aSmrgTRANS(SocketINETGetAddr) (XtransConnInfo ciptr)
28073143b9aSmrg
28173143b9aSmrg{
28273143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
28373143b9aSmrg    struct sockaddr_storage socknamev6;
284b53e5eeaSmrg#else
28573143b9aSmrg    struct sockaddr_in socknamev4;
286b53e5eeaSmrg#endif
28773143b9aSmrg    void *socknamePtr;
28873143b9aSmrg    SOCKLEN_T namelen;
28973143b9aSmrg
290fe567363Smrg    prmsg (3,"SocketINETGetAddr(%p)\n", ciptr);
29173143b9aSmrg
29273143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
293b53e5eeaSmrg    namelen = sizeof(socknamev6);
294b53e5eeaSmrg    socknamePtr = &socknamev6;
295b53e5eeaSmrg#else
296b53e5eeaSmrg    namelen = sizeof(socknamev4);
297b53e5eeaSmrg    socknamePtr = &socknamev4;
29873143b9aSmrg#endif
29973143b9aSmrg
30073143b9aSmrg    bzero(socknamePtr, namelen);
301fe567363Smrg
30273143b9aSmrg    if (getsockname (ciptr->fd,(struct sockaddr *) socknamePtr,
30373143b9aSmrg		     (void *)&namelen) < 0)
30473143b9aSmrg    {
30573143b9aSmrg#ifdef WIN32
30673143b9aSmrg	errno = WSAGetLastError();
30773143b9aSmrg#endif
308fe567363Smrg	prmsg (1,"SocketINETGetAddr: getsockname() failed: %d\n",
309fe567363Smrg	    EGET());
31073143b9aSmrg	return -1;
31173143b9aSmrg    }
31273143b9aSmrg
31373143b9aSmrg    /*
31473143b9aSmrg     * Everything looks good: fill in the XtransConnInfo structure.
31573143b9aSmrg     */
31673143b9aSmrg
317fe567363Smrg    if ((ciptr->addr = malloc (namelen)) == NULL)
31873143b9aSmrg    {
319fe567363Smrg        prmsg (1,
320fe567363Smrg	    "SocketINETGetAddr: Can't allocate space for the addr\n");
32173143b9aSmrg        return -1;
32273143b9aSmrg    }
32373143b9aSmrg
32473143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
325b53e5eeaSmrg    ciptr->family = ((struct sockaddr *)socknamePtr)->sa_family;
326b53e5eeaSmrg#else
327b53e5eeaSmrg    ciptr->family = socknamev4.sin_family;
32873143b9aSmrg#endif
32973143b9aSmrg    ciptr->addrlen = namelen;
33073143b9aSmrg    memcpy (ciptr->addr, socknamePtr, ciptr->addrlen);
33173143b9aSmrg
33273143b9aSmrg    return 0;
33373143b9aSmrg}
33473143b9aSmrg
33573143b9aSmrg
33673143b9aSmrg/*
33773143b9aSmrg * This function gets the remote address of the socket and stores it in the
33873143b9aSmrg * XtransConnInfo structure for the connection.
33973143b9aSmrg */
34073143b9aSmrg
34173143b9aSmrgstatic int
34273143b9aSmrgTRANS(SocketINETGetPeerAddr) (XtransConnInfo ciptr)
34373143b9aSmrg
34473143b9aSmrg{
34573143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
34673143b9aSmrg    struct sockaddr_storage socknamev6;
34773143b9aSmrg#endif
34873143b9aSmrg    struct sockaddr_in 	socknamev4;
34973143b9aSmrg    void *socknamePtr;
35073143b9aSmrg    SOCKLEN_T namelen;
35173143b9aSmrg
35273143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
353b53e5eeaSmrg    if (ciptr->family == AF_INET6)
35473143b9aSmrg    {
35573143b9aSmrg	namelen = sizeof(socknamev6);
35673143b9aSmrg	socknamePtr = &socknamev6;
35773143b9aSmrg    }
35873143b9aSmrg    else
35973143b9aSmrg#endif
36073143b9aSmrg    {
36173143b9aSmrg	namelen = sizeof(socknamev4);
36273143b9aSmrg	socknamePtr = &socknamev4;
36373143b9aSmrg    }
36473143b9aSmrg
36573143b9aSmrg    bzero(socknamePtr, namelen);
366fe567363Smrg
367fe567363Smrg    prmsg (3,"SocketINETGetPeerAddr(%p)\n", ciptr);
36873143b9aSmrg
36973143b9aSmrg    if (getpeername (ciptr->fd, (struct sockaddr *) socknamePtr,
37073143b9aSmrg		     (void *)&namelen) < 0)
37173143b9aSmrg    {
37273143b9aSmrg#ifdef WIN32
37373143b9aSmrg	errno = WSAGetLastError();
37473143b9aSmrg#endif
375fe567363Smrg	prmsg (1,"SocketINETGetPeerAddr: getpeername() failed: %d\n",
376fe567363Smrg	    EGET());
37773143b9aSmrg	return -1;
37873143b9aSmrg    }
37973143b9aSmrg
38073143b9aSmrg    /*
38173143b9aSmrg     * Everything looks good: fill in the XtransConnInfo structure.
38273143b9aSmrg     */
38373143b9aSmrg
384fe567363Smrg    if ((ciptr->peeraddr = malloc (namelen)) == NULL)
38573143b9aSmrg    {
386fe567363Smrg        prmsg (1,
387fe567363Smrg	   "SocketINETGetPeerAddr: Can't allocate space for the addr\n");
38873143b9aSmrg        return -1;
38973143b9aSmrg    }
39073143b9aSmrg
39173143b9aSmrg    ciptr->peeraddrlen = namelen;
39273143b9aSmrg    memcpy (ciptr->peeraddr, socknamePtr, ciptr->peeraddrlen);
39373143b9aSmrg
39473143b9aSmrg    return 0;
39573143b9aSmrg}
39673143b9aSmrg
39773143b9aSmrg
39873143b9aSmrgstatic XtransConnInfo
39973143b9aSmrgTRANS(SocketOpen) (int i, int type)
40073143b9aSmrg
40173143b9aSmrg{
40273143b9aSmrg    XtransConnInfo	ciptr;
40373143b9aSmrg
404fe567363Smrg    prmsg (3,"SocketOpen(%d,%d)\n", i, type);
40573143b9aSmrg
406fe567363Smrg    if ((ciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
40773143b9aSmrg    {
408fe567363Smrg	prmsg (1, "SocketOpen: malloc failed\n");
40973143b9aSmrg	return NULL;
41073143b9aSmrg    }
41173143b9aSmrg
41294f982dbSmrg    ciptr->fd = socket(Sockettrans2devtab[i].family, type,
41394f982dbSmrg                       Sockettrans2devtab[i].protocol);
41494f982dbSmrg
41573143b9aSmrg#ifndef WIN32
41673143b9aSmrg#if (defined(X11_t) && !defined(USE_POLL)) || defined(FS_t) || defined(FONT_t)
41794f982dbSmrg    if (ciptr->fd >= sysconf(_SC_OPEN_MAX))
41894f982dbSmrg    {
41994f982dbSmrg	prmsg (2, "SocketOpen: socket() returned out of range fd %d\n",
42094f982dbSmrg	       ciptr->fd);
42194f982dbSmrg	close (ciptr->fd);
42294f982dbSmrg	ciptr->fd = -1;
42394f982dbSmrg    }
42473143b9aSmrg#endif
42573143b9aSmrg#endif
42694f982dbSmrg
42794f982dbSmrg    if (ciptr->fd < 0) {
42873143b9aSmrg#ifdef WIN32
42973143b9aSmrg	errno = WSAGetLastError();
43073143b9aSmrg#endif
431fe567363Smrg	prmsg (2, "SocketOpen: socket() failed for %s\n",
432fe567363Smrg	    Sockettrans2devtab[i].transname);
43373143b9aSmrg
434fe567363Smrg	free (ciptr);
43573143b9aSmrg	return NULL;
43673143b9aSmrg    }
43773143b9aSmrg
43873143b9aSmrg#ifdef TCP_NODELAY
43973143b9aSmrg    if (Sockettrans2devtab[i].family == AF_INET
44073143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
44173143b9aSmrg      || Sockettrans2devtab[i].family == AF_INET6
44273143b9aSmrg#endif
44373143b9aSmrg    )
44473143b9aSmrg    {
44573143b9aSmrg	/*
44673143b9aSmrg	 * turn off TCP coalescence for INET sockets
44773143b9aSmrg	 */
44873143b9aSmrg
44973143b9aSmrg	int tmp = 1;
45073143b9aSmrg	setsockopt (ciptr->fd, IPPROTO_TCP, TCP_NODELAY,
45173143b9aSmrg	    (char *) &tmp, sizeof (int));
45273143b9aSmrg    }
45373143b9aSmrg#endif
45473143b9aSmrg
4558a0d9095Smrg    /*
4568a0d9095Smrg     * Some systems provide a really small default buffer size for
4578a0d9095Smrg     * UNIX sockets.  Bump it up a bit such that large transfers don't
4588a0d9095Smrg     * proceed at glacial speed.
4598a0d9095Smrg     */
4608a0d9095Smrg#ifdef SO_SNDBUF
4618a0d9095Smrg    if (Sockettrans2devtab[i].family == AF_UNIX)
4628a0d9095Smrg    {
4638a0d9095Smrg	SOCKLEN_T len = sizeof (int);
4648a0d9095Smrg	int val;
4658a0d9095Smrg
4668a0d9095Smrg	if (getsockopt (ciptr->fd, SOL_SOCKET, SO_SNDBUF,
4678a0d9095Smrg	    (char *) &val, &len) == 0 && val < 64 * 1024)
4688a0d9095Smrg	{
4698a0d9095Smrg	    val = 64 * 1024;
4708a0d9095Smrg	    setsockopt (ciptr->fd, SOL_SOCKET, SO_SNDBUF,
4718a0d9095Smrg	        (char *) &val, sizeof (int));
4728a0d9095Smrg	}
4738a0d9095Smrg    }
4748a0d9095Smrg#endif
4758a0d9095Smrg
47673143b9aSmrg    return ciptr;
47773143b9aSmrg}
47873143b9aSmrg
47973143b9aSmrg
48073143b9aSmrg#ifdef TRANS_REOPEN
48173143b9aSmrg
48273143b9aSmrgstatic XtransConnInfo
4836a3641a6SsnjTRANS(SocketReopen) (int i _X_UNUSED, int type, int fd, const char *port)
48473143b9aSmrg
48573143b9aSmrg{
48673143b9aSmrg    XtransConnInfo	ciptr;
48773143b9aSmrg    int portlen;
48873143b9aSmrg    struct sockaddr *addr;
489fe567363Smrg    size_t addrlen;
49073143b9aSmrg
491fe567363Smrg    prmsg (3,"SocketReopen(%d,%d,%s)\n", type, fd, port);
49273143b9aSmrg
49373143b9aSmrg    if (port == NULL) {
494fe567363Smrg      prmsg (1, "SocketReopen: port was null!\n");
49573143b9aSmrg      return NULL;
49673143b9aSmrg    }
49773143b9aSmrg
49873143b9aSmrg    portlen = strlen(port) + 1; // include space for trailing null
49973143b9aSmrg#ifdef SOCK_MAXADDRLEN
50073143b9aSmrg    if (portlen < 0 || portlen > (SOCK_MAXADDRLEN + 2)) {
501fe567363Smrg      prmsg (1, "SocketReopen: invalid portlen %d\n", portlen);
50273143b9aSmrg      return NULL;
50373143b9aSmrg    }
50473143b9aSmrg    if (portlen < 14) portlen = 14;
50573143b9aSmrg#else
50673143b9aSmrg    if (portlen < 0 || portlen > 14) {
507fe567363Smrg      prmsg (1, "SocketReopen: invalid portlen %d\n", portlen);
50873143b9aSmrg      return NULL;
50973143b9aSmrg    }
51073143b9aSmrg#endif /*SOCK_MAXADDRLEN*/
51173143b9aSmrg
512fe567363Smrg    if ((ciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
51373143b9aSmrg    {
514fe567363Smrg	prmsg (1, "SocketReopen: malloc(ciptr) failed\n");
51573143b9aSmrg	return NULL;
51673143b9aSmrg    }
51773143b9aSmrg
51873143b9aSmrg    ciptr->fd = fd;
51973143b9aSmrg
520fe567363Smrg    addrlen = portlen + offsetof(struct sockaddr, sa_data);
521fe567363Smrg    if ((addr = calloc (1, addrlen)) == NULL) {
522fe567363Smrg	prmsg (1, "SocketReopen: malloc(addr) failed\n");
523fe567363Smrg	free (ciptr);
52473143b9aSmrg	return NULL;
52573143b9aSmrg    }
5268d4c0f7bSmrg    ciptr->addr = (char *) addr;
527fe567363Smrg    ciptr->addrlen = addrlen;
52873143b9aSmrg
529fe567363Smrg    if ((ciptr->peeraddr = calloc (1, addrlen)) == NULL) {
530fe567363Smrg	prmsg (1, "SocketReopen: malloc(portaddr) failed\n");
531fe567363Smrg	free (addr);
532fe567363Smrg	free (ciptr);
53373143b9aSmrg	return NULL;
53473143b9aSmrg    }
535fe567363Smrg    ciptr->peeraddrlen = addrlen;
53673143b9aSmrg
53773143b9aSmrg    /* Initialize ciptr structure as if it were a normally-opened unix socket */
53873143b9aSmrg    ciptr->flags = TRANS_LOCAL | TRANS_NOUNLINK;
53973143b9aSmrg#ifdef BSD44SOCKETS
540fe567363Smrg    addr->sa_len = addrlen;
54173143b9aSmrg#endif
54273143b9aSmrg    addr->sa_family = AF_UNIX;
5437448d6e9Smrg#if defined(HAVE_STRLCPY) || defined(HAS_STRLCPY)
54473143b9aSmrg    strlcpy(addr->sa_data, port, portlen);
54573143b9aSmrg#else
54673143b9aSmrg    strncpy(addr->sa_data, port, portlen);
54773143b9aSmrg#endif
54873143b9aSmrg    ciptr->family = AF_UNIX;
549fe567363Smrg    memcpy(ciptr->peeraddr, ciptr->addr, addrlen);
55073143b9aSmrg    ciptr->port = rindex(addr->sa_data, ':');
551e8a71cdfSmrg    if (ciptr->port == NULL) {
552e8a71cdfSmrg	if (is_numeric(addr->sa_data)) {
553e8a71cdfSmrg	    ciptr->port = addr->sa_data;
554e8a71cdfSmrg	}
555e8a71cdfSmrg    } else if (ciptr->port[0] == ':') {
556e8a71cdfSmrg	ciptr->port++;
557e8a71cdfSmrg    }
558e8a71cdfSmrg    /* port should now point to portnum or NULL */
55973143b9aSmrg    return ciptr;
56073143b9aSmrg}
56173143b9aSmrg
56273143b9aSmrg#endif /* TRANS_REOPEN */
56373143b9aSmrg
56473143b9aSmrg
56573143b9aSmrg/*
56673143b9aSmrg * These functions are the interface supplied in the Xtransport structure
56773143b9aSmrg */
56873143b9aSmrg
56973143b9aSmrg#ifdef TRANS_CLIENT
57073143b9aSmrg
57173143b9aSmrgstatic XtransConnInfo
572fe567363SmrgTRANS(SocketOpenCOTSClientBase) (const char *transname, const char *protocol,
573fe567363Smrg			   const char *host, const char *port, int previndex)
57473143b9aSmrg{
57573143b9aSmrg    XtransConnInfo	ciptr;
57673143b9aSmrg    int			i = previndex;
57773143b9aSmrg
578fe567363Smrg    prmsg (2, "SocketOpenCOTSClient(%s,%s,%s)\n",
57973143b9aSmrg	protocol, host, port);
58073143b9aSmrg
58173143b9aSmrg    SocketInitOnce();
58273143b9aSmrg
58373143b9aSmrg    while ((i = TRANS(SocketSelectFamily) (i, transname)) >= 0) {
58473143b9aSmrg	if ((ciptr = TRANS(SocketOpen) (
585e8a71cdfSmrg		i, Sockettrans2devtab[i].devcotsname)) != NULL) {
586e8a71cdfSmrg	    /* Save the index for later use */
587e8a71cdfSmrg
588e8a71cdfSmrg	    ciptr->index = i;
58973143b9aSmrg	    break;
590e8a71cdfSmrg	}
59173143b9aSmrg    }
59273143b9aSmrg    if (i < 0) {
59373143b9aSmrg	if (i == -1)
594fe567363Smrg	    prmsg (1,"SocketOpenCOTSClient: Unable to open socket for %s\n",
595fe567363Smrg		   transname);
59673143b9aSmrg	else
597fe567363Smrg	    prmsg (1,"SocketOpenCOTSClient: Unable to determine socket type for %s\n",
598fe567363Smrg		   transname);
59973143b9aSmrg	return NULL;
60073143b9aSmrg    }
60173143b9aSmrg
60273143b9aSmrg    return ciptr;
60373143b9aSmrg}
60473143b9aSmrg
60573143b9aSmrgstatic XtransConnInfo
6066a3641a6SsnjTRANS(SocketOpenCOTSClient) (Xtransport *thistrans, const char *protocol,
6076a3641a6Ssnj			     const char *host, const char *port)
60873143b9aSmrg{
60973143b9aSmrg    return TRANS(SocketOpenCOTSClientBase)(
61073143b9aSmrg			thistrans->TransName, protocol, host, port, -1);
61173143b9aSmrg}
61273143b9aSmrg
61373143b9aSmrg
61473143b9aSmrg#endif /* TRANS_CLIENT */
61573143b9aSmrg
61673143b9aSmrg
61773143b9aSmrg#ifdef TRANS_SERVER
61873143b9aSmrg
61973143b9aSmrgstatic XtransConnInfo
6206a3641a6SsnjTRANS(SocketOpenCOTSServer) (Xtransport *thistrans, const char *protocol,
6216a3641a6Ssnj			     const char *host, const char *port)
62273143b9aSmrg
62373143b9aSmrg{
62473143b9aSmrg    XtransConnInfo	ciptr;
62573143b9aSmrg    int	i = -1;
62673143b9aSmrg
627fe567363Smrg    prmsg (2,"SocketOpenCOTSServer(%s,%s,%s)\n", protocol, host, port);
62873143b9aSmrg
62973143b9aSmrg    SocketInitOnce();
63073143b9aSmrg
63173143b9aSmrg    while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
63273143b9aSmrg	if ((ciptr = TRANS(SocketOpen) (
63373143b9aSmrg		 i, Sockettrans2devtab[i].devcotsname)) != NULL)
63473143b9aSmrg	    break;
63573143b9aSmrg    }
63673143b9aSmrg    if (i < 0) {
637a773ec55Smrg	if (i == -1) {
638a773ec55Smrg		if (errno == EAFNOSUPPORT) {
639a773ec55Smrg			thistrans->flags |= TRANS_NOLISTEN;
640a773ec55Smrg			prmsg (1,"SocketOpenCOTSServer: Socket for %s unsupported on this system.\n",
641a773ec55Smrg			       thistrans->TransName);
642a773ec55Smrg		} else {
643a773ec55Smrg			prmsg (1,"SocketOpenCOTSServer: Unable to open socket for %s\n",
644a773ec55Smrg			       thistrans->TransName);
645a773ec55Smrg		}
646a773ec55Smrg	} else {
647fe567363Smrg	    prmsg (1,"SocketOpenCOTSServer: Unable to determine socket type for %s\n",
648fe567363Smrg		   thistrans->TransName);
649a773ec55Smrg	}
65073143b9aSmrg	return NULL;
65173143b9aSmrg    }
65273143b9aSmrg
65373143b9aSmrg    /*
65473143b9aSmrg     * Using this prevents the bind() check for an existing server listening
65573143b9aSmrg     * on the same port, but it is required for other reasons.
65673143b9aSmrg     */
65773143b9aSmrg#ifdef SO_REUSEADDR
65873143b9aSmrg
65973143b9aSmrg    /*
66073143b9aSmrg     * SO_REUSEADDR only applied to AF_INET && AF_INET6
66173143b9aSmrg     */
66273143b9aSmrg
66373143b9aSmrg    if (Sockettrans2devtab[i].family == AF_INET
66473143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
66573143b9aSmrg      || Sockettrans2devtab[i].family == AF_INET6
66673143b9aSmrg#endif
66773143b9aSmrg    )
66873143b9aSmrg    {
66973143b9aSmrg	int one = 1;
67073143b9aSmrg	setsockopt (ciptr->fd, SOL_SOCKET, SO_REUSEADDR,
67173143b9aSmrg		    (char *) &one, sizeof (int));
67273143b9aSmrg    }
67373143b9aSmrg#endif
67473143b9aSmrg#ifdef IPV6_V6ONLY
67573143b9aSmrg    if (Sockettrans2devtab[i].family == AF_INET6)
67673143b9aSmrg    {
67773143b9aSmrg	int one = 1;
67873143b9aSmrg	setsockopt(ciptr->fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(int));
67973143b9aSmrg    }
68073143b9aSmrg#endif
68173143b9aSmrg    /* Save the index for later use */
68273143b9aSmrg
68373143b9aSmrg    ciptr->index = i;
68473143b9aSmrg
68573143b9aSmrg    return ciptr;
68673143b9aSmrg}
68773143b9aSmrg
68873143b9aSmrg#endif /* TRANS_SERVER */
68973143b9aSmrg
69073143b9aSmrg
69173143b9aSmrg#ifdef TRANS_REOPEN
69273143b9aSmrg
69373143b9aSmrgstatic XtransConnInfo
6946a3641a6SsnjTRANS(SocketReopenCOTSServer) (Xtransport *thistrans, int fd, const char *port)
69573143b9aSmrg
69673143b9aSmrg{
69773143b9aSmrg    XtransConnInfo	ciptr;
69873143b9aSmrg    int			i = -1;
69973143b9aSmrg
700fe567363Smrg    prmsg (2,
701fe567363Smrg	"SocketReopenCOTSServer(%d, %s)\n", fd, port);
70273143b9aSmrg
70373143b9aSmrg    SocketInitOnce();
70473143b9aSmrg
70573143b9aSmrg    while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
70673143b9aSmrg	if ((ciptr = TRANS(SocketReopen) (
70773143b9aSmrg		 i, Sockettrans2devtab[i].devcotsname, fd, port)) != NULL)
70873143b9aSmrg	    break;
70973143b9aSmrg    }
71073143b9aSmrg    if (i < 0) {
71173143b9aSmrg	if (i == -1)
712fe567363Smrg	    prmsg (1,"SocketReopenCOTSServer: Unable to open socket for %s\n",
713fe567363Smrg		   thistrans->TransName);
71473143b9aSmrg	else
715fe567363Smrg	    prmsg (1,"SocketReopenCOTSServer: Unable to determine socket type for %s\n",
716fe567363Smrg		   thistrans->TransName);
71773143b9aSmrg	return NULL;
71873143b9aSmrg    }
71973143b9aSmrg
72073143b9aSmrg    /* Save the index for later use */
72173143b9aSmrg
72273143b9aSmrg    ciptr->index = i;
72373143b9aSmrg
72473143b9aSmrg    return ciptr;
72573143b9aSmrg}
72673143b9aSmrg
72773143b9aSmrg#endif /* TRANS_REOPEN */
72873143b9aSmrg
72973143b9aSmrg
73073143b9aSmrgstatic int
73173143b9aSmrgTRANS(SocketSetOption) (XtransConnInfo ciptr, int option, int arg)
73273143b9aSmrg
73373143b9aSmrg{
734fe567363Smrg    prmsg (2,"SocketSetOption(%d,%d,%d)\n", ciptr->fd, option, arg);
73573143b9aSmrg
73673143b9aSmrg    return -1;
73773143b9aSmrg}
73873143b9aSmrg
73973143b9aSmrg#ifdef UNIXCONN
74073143b9aSmrgstatic int
74173143b9aSmrgset_sun_path(const char *port, const char *upath, char *path, int abstract)
74273143b9aSmrg{
74373143b9aSmrg    struct sockaddr_un s;
74494f982dbSmrg    ssize_t maxlen = sizeof(s.sun_path) - 1;
74573143b9aSmrg    const char *at = "";
74673143b9aSmrg
74773143b9aSmrg    if (!port || !*port || !path)
74873143b9aSmrg	return -1;
74973143b9aSmrg
75073143b9aSmrg#ifdef HAVE_ABSTRACT_SOCKETS
75173143b9aSmrg    if (port[0] == '@')
75273143b9aSmrg	upath = "";
75373143b9aSmrg    else if (abstract)
75473143b9aSmrg	at = "@";
75573143b9aSmrg#endif
75673143b9aSmrg
75773143b9aSmrg    if (*port == '/') /* a full pathname */
75873143b9aSmrg	upath = "";
75973143b9aSmrg
76094f982dbSmrg    if ((ssize_t)(strlen(at) + strlen(upath) + strlen(port)) > maxlen)
76173143b9aSmrg	return -1;
762fe567363Smrg    snprintf(path, sizeof(s.sun_path), "%s%s%s", at, upath, port);
76373143b9aSmrg    return 0;
76473143b9aSmrg}
76573143b9aSmrg#endif
76673143b9aSmrg
76773143b9aSmrg#ifdef TRANS_SERVER
76873143b9aSmrg
76973143b9aSmrgstatic int
770fe567363SmrgTRANS(SocketCreateListener) (XtransConnInfo ciptr,
77173143b9aSmrg			     struct sockaddr *sockname,
77273143b9aSmrg			     int socknamelen, unsigned int flags)
77373143b9aSmrg
77473143b9aSmrg{
77573143b9aSmrg    SOCKLEN_T namelen = socknamelen;
77673143b9aSmrg    int	fd = ciptr->fd;
77773143b9aSmrg    int	retry;
77873143b9aSmrg
779fe567363Smrg    prmsg (3, "SocketCreateListener(%p,%d)\n", ciptr, fd);
78073143b9aSmrg
78173143b9aSmrg    if (Sockettrans2devtab[ciptr->index].family == AF_INET
78273143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
78373143b9aSmrg      || Sockettrans2devtab[ciptr->index].family == AF_INET6
78473143b9aSmrg#endif
78573143b9aSmrg	)
78673143b9aSmrg	retry = 20;
78773143b9aSmrg    else
78873143b9aSmrg	retry = 0;
78973143b9aSmrg
79094f982dbSmrg    while (bind (fd, sockname, namelen) < 0)
79173143b9aSmrg    {
79273143b9aSmrg	if (errno == EADDRINUSE) {
79373143b9aSmrg	    if (flags & ADDR_IN_USE_ALLOWED)
79473143b9aSmrg		break;
79573143b9aSmrg	    else
79673143b9aSmrg		return TRANS_ADDR_IN_USE;
79773143b9aSmrg	}
798fe567363Smrg
79973143b9aSmrg	if (retry-- == 0) {
800fe567363Smrg	    prmsg (1, "SocketCreateListener: failed to bind listener\n");
80173143b9aSmrg	    close (fd);
80273143b9aSmrg	    return TRANS_CREATE_LISTENER_FAILED;
80373143b9aSmrg	}
80473143b9aSmrg#ifdef SO_REUSEADDR
80573143b9aSmrg	sleep (1);
80673143b9aSmrg#else
80773143b9aSmrg	sleep (10);
80873143b9aSmrg#endif /* SO_REUSEDADDR */
80973143b9aSmrg    }
81073143b9aSmrg
81173143b9aSmrg    if (Sockettrans2devtab[ciptr->index].family == AF_INET
81273143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
81373143b9aSmrg      || Sockettrans2devtab[ciptr->index].family == AF_INET6
81473143b9aSmrg#endif
81573143b9aSmrg	) {
81673143b9aSmrg#ifdef SO_DONTLINGER
81773143b9aSmrg	setsockopt (fd, SOL_SOCKET, SO_DONTLINGER, (char *) NULL, 0);
81873143b9aSmrg#else
81973143b9aSmrg#ifdef SO_LINGER
82073143b9aSmrg    {
82173143b9aSmrg	static int linger[2] = { 0, 0 };
82273143b9aSmrg	setsockopt (fd, SOL_SOCKET, SO_LINGER,
82373143b9aSmrg		(char *) linger, sizeof (linger));
82473143b9aSmrg    }
82573143b9aSmrg#endif
82673143b9aSmrg#endif
82773143b9aSmrg}
82873143b9aSmrg
82973143b9aSmrg    if (listen (fd, BACKLOG) < 0)
83073143b9aSmrg    {
831fe567363Smrg	prmsg (1, "SocketCreateListener: listen() failed\n");
83273143b9aSmrg	close (fd);
83373143b9aSmrg	return TRANS_CREATE_LISTENER_FAILED;
83473143b9aSmrg    }
835fe567363Smrg
83673143b9aSmrg    /* Set a flag to indicate that this connection is a listener */
83773143b9aSmrg
83873143b9aSmrg    ciptr->flags = 1 | (ciptr->flags & TRANS_KEEPFLAGS);
83973143b9aSmrg
84073143b9aSmrg    return 0;
84173143b9aSmrg}
84273143b9aSmrg
84373143b9aSmrg#ifdef TCPCONN
84473143b9aSmrgstatic int
8456a3641a6SsnjTRANS(SocketINETCreateListener) (XtransConnInfo ciptr, const char *port,
8466a3641a6Ssnj                                 unsigned int flags)
84773143b9aSmrg
84873143b9aSmrg{
84973143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
85073143b9aSmrg    struct sockaddr_storage sockname;
85173143b9aSmrg#else
85273143b9aSmrg    struct sockaddr_in	    sockname;
85373143b9aSmrg#endif
85473143b9aSmrg    unsigned short	    sport;
85573143b9aSmrg    SOCKLEN_T	namelen = sizeof(sockname);
85673143b9aSmrg    int		status;
85773143b9aSmrg    long	tmpport;
85873143b9aSmrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
85973143b9aSmrg    _Xgetservbynameparams sparams;
86073143b9aSmrg#endif
86173143b9aSmrg    struct servent *servp;
86273143b9aSmrg
86373143b9aSmrg#ifdef X11_t
86473143b9aSmrg    char	portbuf[PORTBUFSIZE];
86573143b9aSmrg#endif
866fe567363Smrg
867fe567363Smrg    prmsg (2, "SocketINETCreateListener(%s)\n", port);
86873143b9aSmrg
86973143b9aSmrg#ifdef X11_t
87073143b9aSmrg    /*
87173143b9aSmrg     * X has a well known port, that is transport dependent. It is easier
87273143b9aSmrg     * to handle it here, than try and come up with a transport independent
87373143b9aSmrg     * representation that can be passed in and resolved the usual way.
87473143b9aSmrg     *
87573143b9aSmrg     * The port that is passed here is really a string containing the idisplay
87673143b9aSmrg     * from ConnectDisplay().
87773143b9aSmrg     */
87873143b9aSmrg
87973143b9aSmrg    if (is_numeric (port))
88073143b9aSmrg    {
88173143b9aSmrg	/* fixup the server port address */
88273143b9aSmrg	tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10);
883fe567363Smrg	snprintf (portbuf, sizeof(portbuf), "%lu", tmpport);
88473143b9aSmrg	port = portbuf;
88573143b9aSmrg    }
88673143b9aSmrg#endif
88773143b9aSmrg
88873143b9aSmrg    if (port && *port)
88973143b9aSmrg    {
89073143b9aSmrg	/* Check to see if the port string is just a number (handles X11) */
89173143b9aSmrg
89273143b9aSmrg	if (!is_numeric (port))
89373143b9aSmrg	{
89473143b9aSmrg	    if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL)
89573143b9aSmrg	    {
896fe567363Smrg		prmsg (1,
89773143b9aSmrg	     "SocketINETCreateListener: Unable to get service for %s\n",
898fe567363Smrg		      port);
89973143b9aSmrg		return TRANS_CREATE_LISTENER_FAILED;
90073143b9aSmrg	    }
90173143b9aSmrg	    /* we trust getservbyname to return a valid number */
90273143b9aSmrg	    sport = servp->s_port;
90373143b9aSmrg	}
90473143b9aSmrg	else
90573143b9aSmrg	{
90673143b9aSmrg	    tmpport = strtol (port, (char**)NULL, 10);
907fe567363Smrg	    /*
90873143b9aSmrg	     * check that somehow the port address isn't negative or in
90973143b9aSmrg	     * the range of reserved port addresses. This can happen and
910fe567363Smrg	     * be very bad if the server is suid-root and the user does
911fe567363Smrg	     * something (dumb) like `X :60049`.
91273143b9aSmrg	     */
91373143b9aSmrg	    if (tmpport < 1024 || tmpport > USHRT_MAX)
91473143b9aSmrg		return TRANS_CREATE_LISTENER_FAILED;
91573143b9aSmrg
91673143b9aSmrg	    sport = (unsigned short) tmpport;
91773143b9aSmrg	}
91873143b9aSmrg    }
91973143b9aSmrg    else
92073143b9aSmrg	sport = 0;
92173143b9aSmrg
92273143b9aSmrg    bzero(&sockname, sizeof(sockname));
92373143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
92473143b9aSmrg    if (Sockettrans2devtab[ciptr->index].family == AF_INET) {
92573143b9aSmrg	namelen = sizeof (struct sockaddr_in);
92673143b9aSmrg#ifdef BSD44SOCKETS
92773143b9aSmrg	((struct sockaddr_in *)&sockname)->sin_len = namelen;
92873143b9aSmrg#endif
92973143b9aSmrg	((struct sockaddr_in *)&sockname)->sin_family = AF_INET;
93073143b9aSmrg	((struct sockaddr_in *)&sockname)->sin_port = htons(sport);
93173143b9aSmrg	((struct sockaddr_in *)&sockname)->sin_addr.s_addr = htonl(INADDR_ANY);
93273143b9aSmrg    } else {
93373143b9aSmrg	namelen = sizeof (struct sockaddr_in6);
93473143b9aSmrg#ifdef SIN6_LEN
93573143b9aSmrg	((struct sockaddr_in6 *)&sockname)->sin6_len = sizeof(sockname);
93673143b9aSmrg#endif
93773143b9aSmrg	((struct sockaddr_in6 *)&sockname)->sin6_family = AF_INET6;
93873143b9aSmrg	((struct sockaddr_in6 *)&sockname)->sin6_port = htons(sport);
93973143b9aSmrg	((struct sockaddr_in6 *)&sockname)->sin6_addr = in6addr_any;
94073143b9aSmrg    }
94173143b9aSmrg#else
94273143b9aSmrg#ifdef BSD44SOCKETS
94373143b9aSmrg    sockname.sin_len = sizeof (sockname);
94473143b9aSmrg#endif
94573143b9aSmrg    sockname.sin_family = AF_INET;
94673143b9aSmrg    sockname.sin_port = htons (sport);
94773143b9aSmrg    sockname.sin_addr.s_addr = htonl (INADDR_ANY);
94873143b9aSmrg#endif
94973143b9aSmrg
95073143b9aSmrg    if ((status = TRANS(SocketCreateListener) (ciptr,
95173143b9aSmrg	(struct sockaddr *) &sockname, namelen, flags)) < 0)
95273143b9aSmrg    {
953fe567363Smrg	prmsg (1,
954fe567363Smrg    "SocketINETCreateListener: ...SocketCreateListener() failed\n");
95573143b9aSmrg	return status;
95673143b9aSmrg    }
95773143b9aSmrg
95873143b9aSmrg    if (TRANS(SocketINETGetAddr) (ciptr) < 0)
95973143b9aSmrg    {
960fe567363Smrg	prmsg (1,
961fe567363Smrg       "SocketINETCreateListener: ...SocketINETGetAddr() failed\n");
96273143b9aSmrg	return TRANS_CREATE_LISTENER_FAILED;
96373143b9aSmrg    }
96473143b9aSmrg
96573143b9aSmrg    return 0;
96673143b9aSmrg}
96773143b9aSmrg
96873143b9aSmrg#endif /* TCPCONN */
96973143b9aSmrg
97073143b9aSmrg
97173143b9aSmrg#ifdef UNIXCONN
97273143b9aSmrg
97373143b9aSmrgstatic int
9746a3641a6SsnjTRANS(SocketUNIXCreateListener) (XtransConnInfo ciptr, const char *port,
97573143b9aSmrg				 unsigned int flags)
97673143b9aSmrg
97773143b9aSmrg{
97873143b9aSmrg    struct sockaddr_un	sockname;
97973143b9aSmrg    int			namelen;
98073143b9aSmrg    int			oldUmask;
98173143b9aSmrg    int			status;
98273143b9aSmrg    unsigned int	mode;
98373143b9aSmrg    char		tmpport[108];
98473143b9aSmrg
98573143b9aSmrg    int			abstract = 0;
98673143b9aSmrg#ifdef HAVE_ABSTRACT_SOCKETS
98773143b9aSmrg    abstract = ciptr->transptr->flags & TRANS_ABSTRACT;
98873143b9aSmrg#endif
98973143b9aSmrg
990fe567363Smrg    prmsg (2, "SocketUNIXCreateListener(%s)\n",
991fe567363Smrg	port ? port : "NULL");
99273143b9aSmrg
99373143b9aSmrg    /* Make sure the directory is created */
99473143b9aSmrg
99573143b9aSmrg    oldUmask = umask (0);
99673143b9aSmrg
99773143b9aSmrg#ifdef UNIX_DIR
99873143b9aSmrg#ifdef HAS_STICKY_DIR_BIT
99973143b9aSmrg    mode = 01777;
100073143b9aSmrg#else
100173143b9aSmrg    mode = 0777;
100273143b9aSmrg#endif
10038d4c0f7bSmrg    if (!abstract && trans_mkdir(UNIX_DIR, mode) == -1) {
1004fe567363Smrg	prmsg (1, "SocketUNIXCreateListener: mkdir(%s) failed, errno = %d\n",
1005fe567363Smrg	       UNIX_DIR, errno);
100673143b9aSmrg	(void) umask (oldUmask);
100773143b9aSmrg	return TRANS_CREATE_LISTENER_FAILED;
100873143b9aSmrg    }
100973143b9aSmrg#endif
101073143b9aSmrg
101173143b9aSmrg    memset(&sockname, 0, sizeof(sockname));
101273143b9aSmrg    sockname.sun_family = AF_UNIX;
101373143b9aSmrg
101473143b9aSmrg    if (!(port && *port)) {
101573143b9aSmrg	snprintf (tmpport, sizeof(tmpport), "%s%ld", UNIX_PATH, (long)getpid());
101673143b9aSmrg	port = tmpport;
101773143b9aSmrg    }
101873143b9aSmrg    if (set_sun_path(port, UNIX_PATH, sockname.sun_path, abstract) != 0) {
1019fe567363Smrg	prmsg (1, "SocketUNIXCreateListener: path too long\n");
102073143b9aSmrg	return TRANS_CREATE_LISTENER_FAILED;
102173143b9aSmrg    }
102273143b9aSmrg
1023a773ec55Smrg#if defined(BSD44SOCKETS)
102473143b9aSmrg    sockname.sun_len = strlen(sockname.sun_path);
102573143b9aSmrg#endif
102673143b9aSmrg
102773143b9aSmrg#if defined(BSD44SOCKETS) || defined(SUN_LEN)
102873143b9aSmrg    namelen = SUN_LEN(&sockname);
102973143b9aSmrg#else
103073143b9aSmrg    namelen = strlen(sockname.sun_path) + offsetof(struct sockaddr_un, sun_path);
103173143b9aSmrg#endif
103273143b9aSmrg
103373143b9aSmrg    if (abstract) {
103473143b9aSmrg	sockname.sun_path[0] = '\0';
103573143b9aSmrg	namelen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&sockname.sun_path[1]);
103673143b9aSmrg    }
103773143b9aSmrg    else
103873143b9aSmrg	unlink (sockname.sun_path);
103973143b9aSmrg
104073143b9aSmrg    if ((status = TRANS(SocketCreateListener) (ciptr,
104173143b9aSmrg	(struct sockaddr *) &sockname, namelen, flags)) < 0)
104273143b9aSmrg    {
1043fe567363Smrg	prmsg (1,
1044fe567363Smrg    "SocketUNIXCreateListener: ...SocketCreateListener() failed\n");
104573143b9aSmrg	(void) umask (oldUmask);
104673143b9aSmrg	return status;
104773143b9aSmrg    }
104873143b9aSmrg
104973143b9aSmrg    /*
105073143b9aSmrg     * Now that the listener is esablished, create the addr info for
105173143b9aSmrg     * this connection. getpeername() doesn't work for UNIX Domain Sockets
105273143b9aSmrg     * on some systems (hpux at least), so we will just do it manually, instead
105373143b9aSmrg     * of calling something like TRANS(SocketUNIXGetAddr).
105473143b9aSmrg     */
105573143b9aSmrg
105673143b9aSmrg    namelen = sizeof (sockname); /* this will always make it the same size */
105773143b9aSmrg
1058fe567363Smrg    if ((ciptr->addr = malloc (namelen)) == NULL)
105973143b9aSmrg    {
1060fe567363Smrg        prmsg (1,
1061fe567363Smrg        "SocketUNIXCreateListener: Can't allocate space for the addr\n");
106273143b9aSmrg	(void) umask (oldUmask);
106373143b9aSmrg        return TRANS_CREATE_LISTENER_FAILED;
106473143b9aSmrg    }
106573143b9aSmrg
106673143b9aSmrg    if (abstract)
106773143b9aSmrg	sockname.sun_path[0] = '@';
106873143b9aSmrg
106973143b9aSmrg    ciptr->family = sockname.sun_family;
107073143b9aSmrg    ciptr->addrlen = namelen;
107173143b9aSmrg    memcpy (ciptr->addr, &sockname, ciptr->addrlen);
107273143b9aSmrg
107373143b9aSmrg    (void) umask (oldUmask);
107473143b9aSmrg
107573143b9aSmrg    return 0;
107673143b9aSmrg}
107773143b9aSmrg
107873143b9aSmrg
107973143b9aSmrgstatic int
108073143b9aSmrgTRANS(SocketUNIXResetListener) (XtransConnInfo ciptr)
108173143b9aSmrg
108273143b9aSmrg{
108373143b9aSmrg    /*
108473143b9aSmrg     * See if the unix domain socket has disappeared.  If it has, recreate it.
108573143b9aSmrg     */
108673143b9aSmrg
108773143b9aSmrg    struct sockaddr_un 	*unsock = (struct sockaddr_un *) ciptr->addr;
108873143b9aSmrg    struct stat		statb;
108973143b9aSmrg    int 		status = TRANS_RESET_NOOP;
109073143b9aSmrg    unsigned int	mode;
109173143b9aSmrg    int abstract = 0;
109273143b9aSmrg#ifdef HAVE_ABSTRACT_SOCKETS
109373143b9aSmrg    abstract = ciptr->transptr->flags & TRANS_ABSTRACT;
109473143b9aSmrg#endif
109573143b9aSmrg
1096fe567363Smrg    prmsg (3, "SocketUNIXResetListener(%p,%d)\n", ciptr, ciptr->fd);
109773143b9aSmrg
109873143b9aSmrg    if (!abstract && (
109973143b9aSmrg	stat (unsock->sun_path, &statb) == -1 ||
110073143b9aSmrg        ((statb.st_mode & S_IFMT) !=
1101a773ec55Smrg#if !defined(S_IFSOCK)
110273143b9aSmrg	  		S_IFIFO
110373143b9aSmrg#else
110473143b9aSmrg			S_IFSOCK
110573143b9aSmrg#endif
110673143b9aSmrg				)))
110773143b9aSmrg    {
110873143b9aSmrg	int oldUmask = umask (0);
110973143b9aSmrg
111073143b9aSmrg#ifdef UNIX_DIR
111173143b9aSmrg#ifdef HAS_STICKY_DIR_BIT
111273143b9aSmrg	mode = 01777;
111373143b9aSmrg#else
111473143b9aSmrg	mode = 0777;
111573143b9aSmrg#endif
111673143b9aSmrg        if (trans_mkdir(UNIX_DIR, mode) == -1) {
1117fe567363Smrg            prmsg (1, "SocketUNIXResetListener: mkdir(%s) failed, errno = %d\n",
1118fe567363Smrg	    UNIX_DIR, errno);
111973143b9aSmrg	    (void) umask (oldUmask);
112073143b9aSmrg	    return TRANS_RESET_FAILURE;
112173143b9aSmrg        }
112273143b9aSmrg#endif
112373143b9aSmrg
112473143b9aSmrg	close (ciptr->fd);
112573143b9aSmrg	unlink (unsock->sun_path);
112673143b9aSmrg
112773143b9aSmrg	if ((ciptr->fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
112873143b9aSmrg	{
112973143b9aSmrg	    TRANS(FreeConnInfo) (ciptr);
113073143b9aSmrg	    (void) umask (oldUmask);
113173143b9aSmrg	    return TRANS_RESET_FAILURE;
113273143b9aSmrg	}
113373143b9aSmrg
113473143b9aSmrg	if (bind (ciptr->fd, (struct sockaddr *) unsock, ciptr->addrlen) < 0)
113573143b9aSmrg	{
113673143b9aSmrg	    close (ciptr->fd);
113773143b9aSmrg	    TRANS(FreeConnInfo) (ciptr);
113873143b9aSmrg	    return TRANS_RESET_FAILURE;
113973143b9aSmrg	}
114073143b9aSmrg
114173143b9aSmrg	if (listen (ciptr->fd, BACKLOG) < 0)
114273143b9aSmrg	{
114373143b9aSmrg	    close (ciptr->fd);
114473143b9aSmrg	    TRANS(FreeConnInfo) (ciptr);
114573143b9aSmrg	    (void) umask (oldUmask);
114673143b9aSmrg	    return TRANS_RESET_FAILURE;
114773143b9aSmrg	}
114873143b9aSmrg
114973143b9aSmrg	umask (oldUmask);
115073143b9aSmrg
115173143b9aSmrg	status = TRANS_RESET_NEW_FD;
115273143b9aSmrg    }
115373143b9aSmrg
115473143b9aSmrg    return status;
115573143b9aSmrg}
115673143b9aSmrg
115773143b9aSmrg#endif /* UNIXCONN */
115873143b9aSmrg
115973143b9aSmrg
116073143b9aSmrg#ifdef TCPCONN
116173143b9aSmrg
116273143b9aSmrgstatic XtransConnInfo
116373143b9aSmrgTRANS(SocketINETAccept) (XtransConnInfo ciptr, int *status)
116473143b9aSmrg
116573143b9aSmrg{
116673143b9aSmrg    XtransConnInfo	newciptr;
116773143b9aSmrg    struct sockaddr_in	sockname;
116873143b9aSmrg    SOCKLEN_T		namelen = sizeof(sockname);
116973143b9aSmrg
1170fe567363Smrg    prmsg (2, "SocketINETAccept(%p,%d)\n", ciptr, ciptr->fd);
117173143b9aSmrg
1172fe567363Smrg    if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
117373143b9aSmrg    {
1174fe567363Smrg	prmsg (1, "SocketINETAccept: malloc failed\n");
117573143b9aSmrg	*status = TRANS_ACCEPT_BAD_MALLOC;
117673143b9aSmrg	return NULL;
117773143b9aSmrg    }
117873143b9aSmrg
117973143b9aSmrg    if ((newciptr->fd = accept (ciptr->fd,
118073143b9aSmrg	(struct sockaddr *) &sockname, (void *)&namelen)) < 0)
118173143b9aSmrg    {
118273143b9aSmrg#ifdef WIN32
118373143b9aSmrg	errno = WSAGetLastError();
118473143b9aSmrg#endif
1185fe567363Smrg	prmsg (1, "SocketINETAccept: accept() failed\n");
1186fe567363Smrg	free (newciptr);
118773143b9aSmrg	*status = TRANS_ACCEPT_FAILED;
118873143b9aSmrg	return NULL;
118973143b9aSmrg    }
119073143b9aSmrg
119173143b9aSmrg#ifdef TCP_NODELAY
119273143b9aSmrg    {
119373143b9aSmrg	/*
119473143b9aSmrg	 * turn off TCP coalescence for INET sockets
119573143b9aSmrg	 */
119673143b9aSmrg
119773143b9aSmrg	int tmp = 1;
119873143b9aSmrg	setsockopt (newciptr->fd, IPPROTO_TCP, TCP_NODELAY,
119973143b9aSmrg	    (char *) &tmp, sizeof (int));
120073143b9aSmrg    }
120173143b9aSmrg#endif
120273143b9aSmrg
120373143b9aSmrg    /*
1204fe567363Smrg     * Get this address again because the transport may give a more
120573143b9aSmrg     * specific address now that a connection is established.
120673143b9aSmrg     */
120773143b9aSmrg
120873143b9aSmrg    if (TRANS(SocketINETGetAddr) (newciptr) < 0)
120973143b9aSmrg    {
1210fe567363Smrg	prmsg (1,
1211fe567363Smrg	    "SocketINETAccept: ...SocketINETGetAddr() failed:\n");
121273143b9aSmrg	close (newciptr->fd);
1213fe567363Smrg	free (newciptr);
121473143b9aSmrg	*status = TRANS_ACCEPT_MISC_ERROR;
121573143b9aSmrg        return NULL;
121673143b9aSmrg    }
121773143b9aSmrg
121873143b9aSmrg    if (TRANS(SocketINETGetPeerAddr) (newciptr) < 0)
121973143b9aSmrg    {
1220fe567363Smrg	prmsg (1,
1221fe567363Smrg	  "SocketINETAccept: ...SocketINETGetPeerAddr() failed:\n");
122273143b9aSmrg	close (newciptr->fd);
1223fe567363Smrg	if (newciptr->addr) free (newciptr->addr);
1224fe567363Smrg	free (newciptr);
122573143b9aSmrg	*status = TRANS_ACCEPT_MISC_ERROR;
122673143b9aSmrg        return NULL;
122773143b9aSmrg    }
122873143b9aSmrg
122973143b9aSmrg    *status = 0;
123073143b9aSmrg
123173143b9aSmrg    return newciptr;
123273143b9aSmrg}
123373143b9aSmrg
123473143b9aSmrg#endif /* TCPCONN */
123573143b9aSmrg
123673143b9aSmrg
123773143b9aSmrg#ifdef UNIXCONN
123873143b9aSmrgstatic XtransConnInfo
123973143b9aSmrgTRANS(SocketUNIXAccept) (XtransConnInfo ciptr, int *status)
124073143b9aSmrg
124173143b9aSmrg{
124273143b9aSmrg    XtransConnInfo	newciptr;
124373143b9aSmrg    struct sockaddr_un	sockname;
124473143b9aSmrg    SOCKLEN_T 		namelen = sizeof sockname;
124573143b9aSmrg
1246fe567363Smrg    prmsg (2, "SocketUNIXAccept(%p,%d)\n", ciptr, ciptr->fd);
124773143b9aSmrg
1248fe567363Smrg    if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
124973143b9aSmrg    {
1250fe567363Smrg	prmsg (1, "SocketUNIXAccept: malloc() failed\n");
125173143b9aSmrg	*status = TRANS_ACCEPT_BAD_MALLOC;
125273143b9aSmrg	return NULL;
125373143b9aSmrg    }
125473143b9aSmrg
125573143b9aSmrg    if ((newciptr->fd = accept (ciptr->fd,
125673143b9aSmrg	(struct sockaddr *) &sockname, (void *)&namelen)) < 0)
125773143b9aSmrg    {
1258fe567363Smrg	prmsg (1, "SocketUNIXAccept: accept() failed\n");
1259fe567363Smrg	free (newciptr);
126073143b9aSmrg	*status = TRANS_ACCEPT_FAILED;
126173143b9aSmrg	return NULL;
126273143b9aSmrg    }
126373143b9aSmrg
126473143b9aSmrg	ciptr->addrlen = namelen;
126573143b9aSmrg    /*
126673143b9aSmrg     * Get the socket name and the peer name from the listener socket,
126773143b9aSmrg     * since this is unix domain.
126873143b9aSmrg     */
126973143b9aSmrg
1270fe567363Smrg    if ((newciptr->addr = malloc (ciptr->addrlen)) == NULL)
127173143b9aSmrg    {
1272fe567363Smrg        prmsg (1,
1273fe567363Smrg        "SocketUNIXAccept: Can't allocate space for the addr\n");
127473143b9aSmrg	close (newciptr->fd);
1275fe567363Smrg	free (newciptr);
127673143b9aSmrg	*status = TRANS_ACCEPT_BAD_MALLOC;
127773143b9aSmrg        return NULL;
127873143b9aSmrg    }
127973143b9aSmrg
128073143b9aSmrg    /*
128173143b9aSmrg     * if the socket is abstract, we already modified the address to have a
128273143b9aSmrg     * @ instead of the initial NUL, so no need to do that again here.
128373143b9aSmrg     */
128473143b9aSmrg
128573143b9aSmrg    newciptr->addrlen = ciptr->addrlen;
128673143b9aSmrg    memcpy (newciptr->addr, ciptr->addr, newciptr->addrlen);
128773143b9aSmrg
1288fe567363Smrg    if ((newciptr->peeraddr = malloc (ciptr->addrlen)) == NULL)
128973143b9aSmrg    {
1290fe567363Smrg        prmsg (1,
1291fe567363Smrg	      "SocketUNIXAccept: Can't allocate space for the addr\n");
129273143b9aSmrg	close (newciptr->fd);
1293fe567363Smrg	if (newciptr->addr) free (newciptr->addr);
1294fe567363Smrg	free (newciptr);
129573143b9aSmrg	*status = TRANS_ACCEPT_BAD_MALLOC;
129673143b9aSmrg        return NULL;
129773143b9aSmrg    }
1298fe567363Smrg
129973143b9aSmrg    newciptr->peeraddrlen = ciptr->addrlen;
130073143b9aSmrg    memcpy (newciptr->peeraddr, ciptr->addr, newciptr->addrlen);
130173143b9aSmrg
130273143b9aSmrg    newciptr->family = AF_UNIX;
130373143b9aSmrg
130473143b9aSmrg    *status = 0;
130573143b9aSmrg
130673143b9aSmrg    return newciptr;
130773143b9aSmrg}
130873143b9aSmrg
130973143b9aSmrg#endif /* UNIXCONN */
131073143b9aSmrg
131173143b9aSmrg#endif /* TRANS_SERVER */
131273143b9aSmrg
131373143b9aSmrg
131473143b9aSmrg#ifdef TRANS_CLIENT
131573143b9aSmrg
131673143b9aSmrg#ifdef TCPCONN
131773143b9aSmrg
131873143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
131973143b9aSmrgstruct addrlist {
132073143b9aSmrg    struct addrinfo *	addr;
1321fe567363Smrg    struct addrinfo *	firstaddr;
132273143b9aSmrg    char 		port[PORTBUFSIZE];
132373143b9aSmrg    char 		host[MAXHOSTNAMELEN];
132473143b9aSmrg};
132573143b9aSmrgstatic struct addrlist  *addrlist = NULL;
132673143b9aSmrg#endif
132773143b9aSmrg
132873143b9aSmrg
132973143b9aSmrgstatic int
13306a3641a6SsnjTRANS(SocketINETConnect) (XtransConnInfo ciptr,
13316a3641a6Ssnj                          const char *host, const char *port)
133273143b9aSmrg
133373143b9aSmrg{
133473143b9aSmrg    struct sockaddr *	socketaddr = NULL;
133573143b9aSmrg    int			socketaddrlen = 0;
133673143b9aSmrg    int			res;
133773143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
133873143b9aSmrg    struct addrinfo 	hints;
133973143b9aSmrg    char		ntopbuf[INET6_ADDRSTRLEN];
134073143b9aSmrg    int			resetonce = 0;
1341fe567363Smrg#else
134273143b9aSmrg    struct sockaddr_in	sockname;
1343fe567363Smrg    struct hostent	*hostp;
1344fe567363Smrg    struct servent	*servp;
1345fe567363Smrg    unsigned long 	tmpaddr;
1346fe567363Smrg#endif
134773143b9aSmrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
134873143b9aSmrg    _Xgethostbynameparams hparams;
134973143b9aSmrg    _Xgetservbynameparams sparams;
135073143b9aSmrg#endif
135173143b9aSmrg#ifdef X11_t
135273143b9aSmrg    char	portbuf[PORTBUFSIZE];
135373143b9aSmrg#endif
135473143b9aSmrg
135573143b9aSmrg    char 		hostnamebuf[256];		/* tmp space */
135673143b9aSmrg
1357fe567363Smrg    prmsg (2,"SocketINETConnect(%d,%s,%s)\n", ciptr->fd, host, port);
135873143b9aSmrg
135973143b9aSmrg    if (!host)
136073143b9aSmrg    {
136173143b9aSmrg	hostnamebuf[0] = '\0';
136273143b9aSmrg	(void) TRANS(GetHostname) (hostnamebuf, sizeof hostnamebuf);
136373143b9aSmrg	host = hostnamebuf;
136473143b9aSmrg    }
136573143b9aSmrg
136673143b9aSmrg#ifdef X11_t
136773143b9aSmrg    /*
136873143b9aSmrg     * X has a well known port, that is transport dependent. It is easier
136973143b9aSmrg     * to handle it here, than try and come up with a transport independent
137073143b9aSmrg     * representation that can be passed in and resolved the usual way.
137173143b9aSmrg     *
137273143b9aSmrg     * The port that is passed here is really a string containing the idisplay
137373143b9aSmrg     * from ConnectDisplay().
137473143b9aSmrg     */
137573143b9aSmrg
137673143b9aSmrg    if (is_numeric (port))
137773143b9aSmrg    {
1378fe567363Smrg	long tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10);
1379fe567363Smrg	snprintf (portbuf, sizeof(portbuf), "%lu", tmpport);
138073143b9aSmrg	port = portbuf;
138173143b9aSmrg    }
138273143b9aSmrg#endif
138373143b9aSmrg
138473143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
1385b53e5eeaSmrg    {
138673143b9aSmrg	if (addrlist != NULL) {
138773143b9aSmrg	    if (strcmp(host,addrlist->host) || strcmp(port,addrlist->port)) {
138873143b9aSmrg		if (addrlist->firstaddr)
138973143b9aSmrg		    freeaddrinfo(addrlist->firstaddr);
139073143b9aSmrg		addrlist->firstaddr = NULL;
139173143b9aSmrg	    }
139273143b9aSmrg	} else {
139373143b9aSmrg	    addrlist = malloc(sizeof(struct addrlist));
139494f982dbSmrg	    if (addrlist == NULL) {
139594f982dbSmrg		prmsg (1, "SocketINETConnect() can't allocate memory "
139694f982dbSmrg			"for addrlist: %s\n", strerror(errno));
139794f982dbSmrg		return TRANS_CONNECT_FAILED;
139894f982dbSmrg	    }
139973143b9aSmrg	    addrlist->firstaddr = NULL;
140073143b9aSmrg	}
140173143b9aSmrg
140273143b9aSmrg	if (addrlist->firstaddr == NULL) {
140373143b9aSmrg	    strncpy(addrlist->port, port, sizeof(addrlist->port));
140473143b9aSmrg	    addrlist->port[sizeof(addrlist->port) - 1] = '\0';
140573143b9aSmrg	    strncpy(addrlist->host, host, sizeof(addrlist->host));
140673143b9aSmrg	    addrlist->host[sizeof(addrlist->host) - 1] = '\0';
140773143b9aSmrg
140873143b9aSmrg	    bzero(&hints,sizeof(hints));
140973143b9aSmrg	    hints.ai_socktype = Sockettrans2devtab[ciptr->index].devcotsname;
141073143b9aSmrg
141173143b9aSmrg	    res = getaddrinfo(host,port,&hints,&addrlist->firstaddr);
141273143b9aSmrg	    if (res != 0) {
1413fe567363Smrg		prmsg (1, "SocketINETConnect() can't get address "
141473143b9aSmrg			"for %s:%s: %s\n", host, port, gai_strerror(res));
141573143b9aSmrg		ESET(EINVAL);
141673143b9aSmrg		return TRANS_CONNECT_FAILED;
141773143b9aSmrg	    }
141873143b9aSmrg	    for (res = 0, addrlist->addr = addrlist->firstaddr;
141973143b9aSmrg		 addrlist->addr ; res++) {
142073143b9aSmrg		addrlist->addr = addrlist->addr->ai_next;
142173143b9aSmrg	    }
1422fe567363Smrg	    prmsg(4,"Got New Address list with %d addresses\n", res);
142373143b9aSmrg	    res = 0;
142473143b9aSmrg	    addrlist->addr = NULL;
142573143b9aSmrg	}
142673143b9aSmrg
142773143b9aSmrg	while (socketaddr == NULL) {
142873143b9aSmrg	    if (addrlist->addr == NULL) {
1429fe567363Smrg		if (resetonce) {
143073143b9aSmrg		    /* Already checked entire list - no usable addresses */
1431fe567363Smrg		    prmsg (1, "SocketINETConnect() no usable address "
1432fe567363Smrg			   "for %s:%s\n", host, port);
143373143b9aSmrg		    return TRANS_CONNECT_FAILED;
143473143b9aSmrg		} else {
143573143b9aSmrg		    /* Go back to beginning of list */
143673143b9aSmrg		    resetonce = 1;
143773143b9aSmrg		    addrlist->addr = addrlist->firstaddr;
143873143b9aSmrg		}
1439fe567363Smrg	    }
144073143b9aSmrg
144173143b9aSmrg	    socketaddr = addrlist->addr->ai_addr;
144273143b9aSmrg	    socketaddrlen = addrlist->addr->ai_addrlen;
144373143b9aSmrg
144473143b9aSmrg	    if (addrlist->addr->ai_family == AF_INET) {
144573143b9aSmrg		struct sockaddr_in *sin = (struct sockaddr_in *) socketaddr;
144673143b9aSmrg
1447fe567363Smrg		prmsg (4,"SocketINETConnect() sockname.sin_addr = %s\n",
144873143b9aSmrg			inet_ntop(addrlist->addr->ai_family,&sin->sin_addr,
1449fe567363Smrg			ntopbuf,sizeof(ntopbuf)));
145073143b9aSmrg
1451fe567363Smrg		prmsg (4,"SocketINETConnect() sockname.sin_port = %d\n",
1452fe567363Smrg			ntohs(sin->sin_port));
145373143b9aSmrg
145473143b9aSmrg		if (Sockettrans2devtab[ciptr->index].family == AF_INET6) {
145573143b9aSmrg		    if (strcmp(Sockettrans2devtab[ciptr->index].transname,
145673143b9aSmrg				"tcp") == 0) {
145773143b9aSmrg			XtransConnInfo newciptr;
145873143b9aSmrg
145973143b9aSmrg			/*
146073143b9aSmrg			 * Our socket is an IPv6 socket, but the address is
146173143b9aSmrg			 * IPv4.  Close it and get an IPv4 socket.  This is
146273143b9aSmrg			 * needed for IPv4 connections to work on platforms
146373143b9aSmrg			 * that don't allow IPv4 over IPv6 sockets.
146473143b9aSmrg			 */
146573143b9aSmrg			TRANS(SocketINETClose)(ciptr);
146673143b9aSmrg			newciptr = TRANS(SocketOpenCOTSClientBase)(
146773143b9aSmrg					"tcp", "tcp", host, port, ciptr->index);
146873143b9aSmrg			if (newciptr)
146973143b9aSmrg			    ciptr->fd = newciptr->fd;
147073143b9aSmrg			if (!newciptr ||
147173143b9aSmrg			    Sockettrans2devtab[newciptr->index].family !=
147273143b9aSmrg				AF_INET) {
147373143b9aSmrg			    socketaddr = NULL;
1474fe567363Smrg			    prmsg (4,"SocketINETConnect() Cannot get IPv4 "
1475fe567363Smrg					" socketfor IPv4 address\n");
147673143b9aSmrg			}
147773143b9aSmrg			if (newciptr)
1478fe567363Smrg			    free(newciptr);
147973143b9aSmrg		    } else {
148073143b9aSmrg			socketaddr = NULL;
1481fe567363Smrg			prmsg (4,"SocketINETConnect Skipping IPv4 address\n");
148273143b9aSmrg		    }
148373143b9aSmrg		}
148473143b9aSmrg	    } else if (addrlist->addr->ai_family == AF_INET6) {
148573143b9aSmrg		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) socketaddr;
1486fe567363Smrg
1487fe567363Smrg		prmsg (4,"SocketINETConnect() sockname.sin6_addr = %s\n",
148873143b9aSmrg			inet_ntop(addrlist->addr->ai_family,
1489fe567363Smrg				  &sin6->sin6_addr,ntopbuf,sizeof(ntopbuf)));
1490fe567363Smrg		prmsg (4,"SocketINETConnect() sockname.sin6_port = %d\n",
1491fe567363Smrg			ntohs(sin6->sin6_port));
149273143b9aSmrg
149373143b9aSmrg		if (Sockettrans2devtab[ciptr->index].family == AF_INET) {
149473143b9aSmrg		    if (strcmp(Sockettrans2devtab[ciptr->index].transname,
149573143b9aSmrg				"tcp") == 0) {
149673143b9aSmrg			XtransConnInfo newciptr;
149773143b9aSmrg
149873143b9aSmrg			/*
149973143b9aSmrg			 * Close the IPv4 socket and try to open an IPv6 socket.
150073143b9aSmrg			 */
150173143b9aSmrg			TRANS(SocketINETClose)(ciptr);
150273143b9aSmrg			newciptr = TRANS(SocketOpenCOTSClientBase)(
150373143b9aSmrg					"tcp", "tcp", host, port, -1);
150473143b9aSmrg			if (newciptr)
150573143b9aSmrg			    ciptr->fd = newciptr->fd;
150673143b9aSmrg			if (!newciptr ||
150773143b9aSmrg			    Sockettrans2devtab[newciptr->index].family !=
150873143b9aSmrg					AF_INET6) {
150973143b9aSmrg			    socketaddr = NULL;
1510fe567363Smrg			    prmsg (4,"SocketINETConnect() Cannot get IPv6 "
1511fe567363Smrg				   "socket for IPv6 address\n");
151273143b9aSmrg			}
151373143b9aSmrg			if (newciptr)
1514fe567363Smrg			    free(newciptr);
151573143b9aSmrg		    }
151673143b9aSmrg		    else
151773143b9aSmrg		    {
151873143b9aSmrg			socketaddr = NULL;
1519fe567363Smrg			prmsg (4,"SocketINETConnect() Skipping IPv6 address\n");
152073143b9aSmrg		    }
152173143b9aSmrg		}
152273143b9aSmrg	    } else {
152373143b9aSmrg		socketaddr = NULL; /* Unsupported address type */
152473143b9aSmrg	    }
152573143b9aSmrg	    if (socketaddr == NULL) {
152673143b9aSmrg		addrlist->addr = addrlist->addr->ai_next;
152773143b9aSmrg	    }
1528fe567363Smrg	}
1529b53e5eeaSmrg    }
1530b53e5eeaSmrg#else
153173143b9aSmrg    {
153273143b9aSmrg	/*
153373143b9aSmrg	 * Build the socket name.
153473143b9aSmrg	 */
153573143b9aSmrg
153673143b9aSmrg#ifdef BSD44SOCKETS
153773143b9aSmrg	sockname.sin_len = sizeof (struct sockaddr_in);
153873143b9aSmrg#endif
153973143b9aSmrg	sockname.sin_family = AF_INET;
154073143b9aSmrg
154173143b9aSmrg	/*
154273143b9aSmrg	 * fill in sin_addr
154373143b9aSmrg	 */
154473143b9aSmrg
154573143b9aSmrg#ifndef INADDR_NONE
154673143b9aSmrg#define INADDR_NONE ((in_addr_t) 0xffffffff)
154773143b9aSmrg#endif
154873143b9aSmrg
154973143b9aSmrg	/* check for ww.xx.yy.zz host string */
155073143b9aSmrg
155173143b9aSmrg	if (isascii (host[0]) && isdigit (host[0])) {
155273143b9aSmrg	    tmpaddr = inet_addr (host); /* returns network byte order */
155373143b9aSmrg	} else {
155473143b9aSmrg	    tmpaddr = INADDR_NONE;
155573143b9aSmrg	}
155673143b9aSmrg
155781d6fa61Srin	prmsg (4,"SocketINETConnect() inet_addr(%s) = %lx\n", host, tmpaddr);
155873143b9aSmrg
155973143b9aSmrg	if (tmpaddr == INADDR_NONE) {
156073143b9aSmrg	    if ((hostp = _XGethostbyname(host,hparams)) == NULL) {
1561fe567363Smrg		prmsg (1,"SocketINETConnect: Can't get address for %s\n",
1562fe567363Smrg			host);
156373143b9aSmrg		ESET(EINVAL);
156473143b9aSmrg		return TRANS_CONNECT_FAILED;
156573143b9aSmrg	    }
156673143b9aSmrg	    if (hostp->h_addrtype != AF_INET) {  /* is IP host? */
1567fe567363Smrg		prmsg (1,"SocketINETConnect: not INET host%s\n", host);
156873143b9aSmrg		ESET(EPROTOTYPE);
156973143b9aSmrg		return TRANS_CONNECT_FAILED;
157073143b9aSmrg	    }
1571fe567363Smrg
157273143b9aSmrg	    memcpy ((char *) &sockname.sin_addr, (char *) hostp->h_addr,
157373143b9aSmrg		    sizeof (sockname.sin_addr));
157473143b9aSmrg
157573143b9aSmrg	} else {
157673143b9aSmrg	    sockname.sin_addr.s_addr = tmpaddr;
157773143b9aSmrg        }
157873143b9aSmrg
157973143b9aSmrg	/*
158073143b9aSmrg	 * fill in sin_port
158173143b9aSmrg	 */
158273143b9aSmrg
158373143b9aSmrg	/* Check for number in the port string */
158473143b9aSmrg
158573143b9aSmrg	if (!is_numeric (port)) {
158673143b9aSmrg	    if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL) {
1587fe567363Smrg		prmsg (1,"SocketINETConnect: can't get service for %s\n",
1588fe567363Smrg			port);
158973143b9aSmrg		return TRANS_CONNECT_FAILED;
159073143b9aSmrg	    }
159173143b9aSmrg	    sockname.sin_port = htons (servp->s_port);
159273143b9aSmrg	} else {
1593fe567363Smrg	    long tmpport = strtol (port, (char**)NULL, 10);
159473143b9aSmrg	    if (tmpport < 1024 || tmpport > USHRT_MAX)
159573143b9aSmrg		return TRANS_CONNECT_FAILED;
159673143b9aSmrg	    sockname.sin_port = htons (((unsigned short) tmpport));
159773143b9aSmrg	}
159873143b9aSmrg
1599fe567363Smrg	prmsg (4,"SocketINETConnect: sockname.sin_port = %d\n",
1600fe567363Smrg		ntohs(sockname.sin_port));
160173143b9aSmrg	socketaddr = (struct sockaddr *) &sockname;
160273143b9aSmrg	socketaddrlen = sizeof(sockname);
160373143b9aSmrg    }
1604b53e5eeaSmrg#endif
160573143b9aSmrg
160673143b9aSmrg    /*
160773143b9aSmrg     * Turn on socket keepalive so the client process will eventually
160873143b9aSmrg     * be notified with a SIGPIPE signal if the display server fails
160973143b9aSmrg     * to respond to a periodic transmission of messages
161073143b9aSmrg     * on the connected socket.
161173143b9aSmrg     * This is useful to avoid hung application processes when the
161273143b9aSmrg     * processes are not spawned from the xdm session and
161373143b9aSmrg     * the display server terminates abnormally.
161473143b9aSmrg     * (Someone turned off the power switch.)
161573143b9aSmrg     */
161673143b9aSmrg
161773143b9aSmrg    {
161873143b9aSmrg	int tmp = 1;
161973143b9aSmrg	setsockopt (ciptr->fd, SOL_SOCKET, SO_KEEPALIVE,
162073143b9aSmrg		(char *) &tmp, sizeof (int));
162173143b9aSmrg    }
162273143b9aSmrg
162373143b9aSmrg    /*
162473143b9aSmrg     * Do the connect()
162573143b9aSmrg     */
162673143b9aSmrg
162773143b9aSmrg    if (connect (ciptr->fd, socketaddr, socketaddrlen ) < 0)
162873143b9aSmrg    {
162973143b9aSmrg#ifdef WIN32
163073143b9aSmrg	int olderrno = WSAGetLastError();
163173143b9aSmrg#else
163273143b9aSmrg	int olderrno = errno;
163373143b9aSmrg#endif
163473143b9aSmrg
163573143b9aSmrg	/*
163673143b9aSmrg	 * If the error was ECONNREFUSED, the server may be overloaded
163773143b9aSmrg	 * and we should try again.
163873143b9aSmrg	 *
163973143b9aSmrg	 * If the error was EWOULDBLOCK or EINPROGRESS then the socket
164073143b9aSmrg	 * was non-blocking and we should poll using select
164173143b9aSmrg	 *
164273143b9aSmrg	 * If the error was EINTR, the connect was interrupted and we
164373143b9aSmrg	 * should try again.
164473143b9aSmrg	 *
164573143b9aSmrg	 * If multiple addresses are found for a host then we should
164673143b9aSmrg	 * try to connect again with a different address for a larger
164773143b9aSmrg	 * number of errors that made us quit before, since those
164873143b9aSmrg	 * could be caused by trying to use an IPv6 address to contact
164973143b9aSmrg	 * a machine with an IPv4-only server or other reasons that
1650fe567363Smrg	 * only affect one of a set of addresses.
165173143b9aSmrg	 */
165273143b9aSmrg
165373143b9aSmrg	if (olderrno == ECONNREFUSED || olderrno == EINTR
165473143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
1655b53e5eeaSmrg	  || (((addrlist->addr->ai_next != NULL) ||
165673143b9aSmrg	        (addrlist->addr != addrlist->firstaddr)) &&
165773143b9aSmrg               (olderrno == ENETUNREACH || olderrno == EAFNOSUPPORT ||
165873143b9aSmrg		 olderrno == EADDRNOTAVAIL || olderrno == ETIMEDOUT
165973143b9aSmrg#if defined(EHOSTDOWN)
166073143b9aSmrg		   || olderrno == EHOSTDOWN
166173143b9aSmrg#endif
166273143b9aSmrg	       ))
166373143b9aSmrg#endif
166473143b9aSmrg	    )
166573143b9aSmrg	    res = TRANS_TRY_CONNECT_AGAIN;
166673143b9aSmrg	else if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS)
166773143b9aSmrg	    res = TRANS_IN_PROGRESS;
166873143b9aSmrg	else
166973143b9aSmrg	{
1670fe567363Smrg	    prmsg (2,"SocketINETConnect: Can't connect: errno = %d\n",
1671fe567363Smrg		   olderrno);
167273143b9aSmrg
1673fe567363Smrg	    res = TRANS_CONNECT_FAILED;
167473143b9aSmrg	}
167573143b9aSmrg    } else {
167673143b9aSmrg	res = 0;
1677fe567363Smrg
167873143b9aSmrg
167973143b9aSmrg	/*
168073143b9aSmrg	 * Sync up the address fields of ciptr.
168173143b9aSmrg	 */
1682fe567363Smrg
168373143b9aSmrg	if (TRANS(SocketINETGetAddr) (ciptr) < 0)
168473143b9aSmrg	{
1685fe567363Smrg	    prmsg (1,
1686fe567363Smrg	     "SocketINETConnect: ...SocketINETGetAddr() failed:\n");
168773143b9aSmrg	    res = TRANS_CONNECT_FAILED;
168873143b9aSmrg	}
168973143b9aSmrg
169073143b9aSmrg	else if (TRANS(SocketINETGetPeerAddr) (ciptr) < 0)
169173143b9aSmrg	{
1692fe567363Smrg	    prmsg (1,
1693fe567363Smrg	      "SocketINETConnect: ...SocketINETGetPeerAddr() failed:\n");
169473143b9aSmrg	    res = TRANS_CONNECT_FAILED;
169573143b9aSmrg	}
169673143b9aSmrg    }
169773143b9aSmrg
169873143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
1699b53e5eeaSmrg   if (res != 0) {
170073143b9aSmrg	addrlist->addr = addrlist->addr->ai_next;
170173143b9aSmrg   }
170273143b9aSmrg#endif
170373143b9aSmrg
170473143b9aSmrg    return res;
170573143b9aSmrg}
170673143b9aSmrg
170773143b9aSmrg#endif /* TCPCONN */
170873143b9aSmrg
170973143b9aSmrg
171073143b9aSmrg
171173143b9aSmrg#ifdef UNIXCONN
171273143b9aSmrg
171373143b9aSmrg/*
171473143b9aSmrg * Make sure 'host' is really local.
171573143b9aSmrg */
171673143b9aSmrg
171773143b9aSmrgstatic int
17186a3641a6SsnjUnixHostReallyLocal (const char *host)
171973143b9aSmrg
172073143b9aSmrg{
172173143b9aSmrg    char hostnamebuf[256];
172273143b9aSmrg
172373143b9aSmrg    TRANS(GetHostname) (hostnamebuf, sizeof (hostnamebuf));
172473143b9aSmrg
172573143b9aSmrg    if (strcmp (hostnamebuf, host) == 0)
172673143b9aSmrg    {
172773143b9aSmrg	return (1);
1728b53e5eeaSmrg    } else {
172973143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
173073143b9aSmrg	struct addrinfo *localhostaddr;
173173143b9aSmrg	struct addrinfo *otherhostaddr;
173273143b9aSmrg	struct addrinfo *i, *j;
173373143b9aSmrg	int equiv = 0;
173473143b9aSmrg
173573143b9aSmrg	if (getaddrinfo(hostnamebuf, NULL, NULL, &localhostaddr) != 0)
173673143b9aSmrg	    return 0;
173773143b9aSmrg	if (getaddrinfo(host, NULL, NULL, &otherhostaddr) != 0) {
173873143b9aSmrg	    freeaddrinfo(localhostaddr);
173973143b9aSmrg	    return 0;
174073143b9aSmrg	}
174173143b9aSmrg
174273143b9aSmrg	for (i = localhostaddr; i != NULL && equiv == 0; i = i->ai_next) {
174373143b9aSmrg	    for (j = otherhostaddr; j != NULL && equiv == 0; j = j->ai_next) {
174473143b9aSmrg		if (i->ai_family == j->ai_family) {
174573143b9aSmrg		    if (i->ai_family == AF_INET) {
1746fe567363Smrg			struct sockaddr_in *sinA
174773143b9aSmrg			  = (struct sockaddr_in *) i->ai_addr;
174873143b9aSmrg			struct sockaddr_in *sinB
174973143b9aSmrg			  = (struct sockaddr_in *) j->ai_addr;
175073143b9aSmrg			struct in_addr *A = &sinA->sin_addr;
175173143b9aSmrg			struct in_addr *B = &sinB->sin_addr;
175273143b9aSmrg
175373143b9aSmrg			if (memcmp(A,B,sizeof(struct in_addr)) == 0) {
175473143b9aSmrg			    equiv = 1;
175573143b9aSmrg			}
175673143b9aSmrg		    } else if (i->ai_family == AF_INET6) {
1757fe567363Smrg			struct sockaddr_in6 *sinA
175873143b9aSmrg			  = (struct sockaddr_in6 *) i->ai_addr;
1759fe567363Smrg			struct sockaddr_in6 *sinB
176073143b9aSmrg			  = (struct sockaddr_in6 *) j->ai_addr;
176173143b9aSmrg			struct in6_addr *A = &sinA->sin6_addr;
176273143b9aSmrg			struct in6_addr *B = &sinB->sin6_addr;
176373143b9aSmrg
176473143b9aSmrg			if (memcmp(A,B,sizeof(struct in6_addr)) == 0) {
176573143b9aSmrg			    equiv = 1;
176673143b9aSmrg			}
176773143b9aSmrg		    }
176873143b9aSmrg		}
176973143b9aSmrg	    }
177073143b9aSmrg	}
1771fe567363Smrg
177273143b9aSmrg	freeaddrinfo(localhostaddr);
177373143b9aSmrg	freeaddrinfo(otherhostaddr);
177473143b9aSmrg	return equiv;
1775b53e5eeaSmrg#else
177673143b9aSmrg	/*
177773143b9aSmrg	 * A host may have more than one network address.  If any of the
177873143b9aSmrg	 * network addresses of 'host' (specified to the connect call)
177973143b9aSmrg	 * match any of the network addresses of 'hostname' (determined
178073143b9aSmrg	 * by TRANS(GetHostname)), then the two hostnames are equivalent,
178173143b9aSmrg	 * and we know that 'host' is really a local host.
178273143b9aSmrg	 */
178373143b9aSmrg	char specified_local_addr_list[10][4];
178473143b9aSmrg	int scount, equiv, i, j;
178573143b9aSmrg#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
178673143b9aSmrg	_Xgethostbynameparams hparams;
178773143b9aSmrg#endif
178873143b9aSmrg	struct hostent *hostp;
178973143b9aSmrg
179073143b9aSmrg	if ((hostp = _XGethostbyname (host,hparams)) == NULL)
179173143b9aSmrg	    return (0);
179273143b9aSmrg
179373143b9aSmrg	scount = 0;
179473143b9aSmrg	while (hostp->h_addr_list[scount] && scount <= 8)
179573143b9aSmrg	{
179673143b9aSmrg	    /*
179773143b9aSmrg	     * The 2nd call to gethostname() overrides the data
179873143b9aSmrg	     * from the 1st call, so we must save the address list.
179973143b9aSmrg	     */
180073143b9aSmrg
1801fe567363Smrg	    specified_local_addr_list[scount][0] =
180273143b9aSmrg				hostp->h_addr_list[scount][0];
1803fe567363Smrg	    specified_local_addr_list[scount][1] =
180473143b9aSmrg				hostp->h_addr_list[scount][1];
1805fe567363Smrg	    specified_local_addr_list[scount][2] =
180673143b9aSmrg				hostp->h_addr_list[scount][2];
1807fe567363Smrg	    specified_local_addr_list[scount][3] =
180873143b9aSmrg				hostp->h_addr_list[scount][3];
180973143b9aSmrg	    scount++;
181073143b9aSmrg	}
181173143b9aSmrg	if ((hostp = _XGethostbyname (hostnamebuf,hparams)) == NULL)
181273143b9aSmrg	    return (0);
181373143b9aSmrg
181473143b9aSmrg	equiv = 0;
181573143b9aSmrg	i = 0;
181673143b9aSmrg
181773143b9aSmrg	while (i < scount && !equiv)
181873143b9aSmrg	{
181973143b9aSmrg	    j = 0;
182073143b9aSmrg
182173143b9aSmrg	    while (hostp->h_addr_list[j])
182273143b9aSmrg	    {
1823fe567363Smrg		if ((specified_local_addr_list[i][0] ==
182473143b9aSmrg					hostp->h_addr_list[j][0]) &&
1825fe567363Smrg		    (specified_local_addr_list[i][1] ==
182673143b9aSmrg					hostp->h_addr_list[j][1]) &&
1827fe567363Smrg		    (specified_local_addr_list[i][2] ==
182873143b9aSmrg					hostp->h_addr_list[j][2]) &&
1829fe567363Smrg		    (specified_local_addr_list[i][3] ==
183073143b9aSmrg					hostp->h_addr_list[j][3]))
183173143b9aSmrg		{
183273143b9aSmrg		    /* They're equal, so we're done */
1833fe567363Smrg
183473143b9aSmrg		    equiv = 1;
183573143b9aSmrg		    break;
183673143b9aSmrg		}
183773143b9aSmrg
183873143b9aSmrg		j++;
183973143b9aSmrg	    }
184073143b9aSmrg
184173143b9aSmrg	    i++;
184273143b9aSmrg	}
184373143b9aSmrg	return (equiv);
1844b53e5eeaSmrg#endif
184573143b9aSmrg    }
184673143b9aSmrg}
184773143b9aSmrg
184873143b9aSmrgstatic int
18496a3641a6SsnjTRANS(SocketUNIXConnect) (XtransConnInfo ciptr,
18506a3641a6Ssnj                          const char *host, const char *port)
185173143b9aSmrg
185273143b9aSmrg{
185373143b9aSmrg    struct sockaddr_un	sockname;
185473143b9aSmrg    SOCKLEN_T		namelen;
185573143b9aSmrg
1856fe567363Smrg    prmsg (2,"SocketUNIXConnect(%d,%s,%s)\n", ciptr->fd, host, port);
1857fe567363Smrg
185873143b9aSmrg    /*
185973143b9aSmrg     * Make sure 'host' is really local.  If not, we return failure.
186073143b9aSmrg     * The reason we make this check is because a process may advertise
186173143b9aSmrg     * a "local" network ID for which it can accept connections, but if
186273143b9aSmrg     * a process on a remote machine tries to connect to this network ID,
186373143b9aSmrg     * we know for sure it will fail.
186473143b9aSmrg     */
186573143b9aSmrg
186673143b9aSmrg    if (host && *host && host[0]!='/' && strcmp (host, "unix") != 0 && !UnixHostReallyLocal (host))
186773143b9aSmrg    {
1868fe567363Smrg	prmsg (1,
186973143b9aSmrg	   "SocketUNIXConnect: Cannot connect to non-local host %s\n",
1870fe567363Smrg	       host);
187173143b9aSmrg	return TRANS_CONNECT_FAILED;
187273143b9aSmrg    }
187373143b9aSmrg
187473143b9aSmrg
187573143b9aSmrg    /*
187673143b9aSmrg     * Check the port.
187773143b9aSmrg     */
187873143b9aSmrg
187973143b9aSmrg    if (!port || !*port)
188073143b9aSmrg    {
1881fe567363Smrg	prmsg (1,"SocketUNIXConnect: Missing port specification\n");
188273143b9aSmrg	return TRANS_CONNECT_FAILED;
188373143b9aSmrg    }
188473143b9aSmrg
188573143b9aSmrg    /*
188673143b9aSmrg     * Build the socket name.
188773143b9aSmrg     */
1888fe567363Smrg
188973143b9aSmrg    sockname.sun_family = AF_UNIX;
189073143b9aSmrg
1891a773ec55Smrg    if (set_sun_path(port, UNIX_PATH, sockname.sun_path, 0) != 0) {
1892fe567363Smrg	prmsg (1, "SocketUNIXConnect: path too long\n");
189373143b9aSmrg	return TRANS_CONNECT_FAILED;
189473143b9aSmrg    }
189573143b9aSmrg
1896a773ec55Smrg#if defined(BSD44SOCKETS)
189773143b9aSmrg    sockname.sun_len = strlen (sockname.sun_path);
189873143b9aSmrg#endif
189973143b9aSmrg
190073143b9aSmrg#if defined(BSD44SOCKETS) || defined(SUN_LEN)
190173143b9aSmrg    namelen = SUN_LEN (&sockname);
190273143b9aSmrg#else
190373143b9aSmrg    namelen = strlen (sockname.sun_path) + offsetof(struct sockaddr_un, sun_path);
190473143b9aSmrg#endif
190573143b9aSmrg
190673143b9aSmrg
190773143b9aSmrg    /*
190873143b9aSmrg     * Do the connect()
190973143b9aSmrg     */
191073143b9aSmrg
191173143b9aSmrg    if (connect (ciptr->fd, (struct sockaddr *) &sockname, namelen) < 0)
191273143b9aSmrg    {
191373143b9aSmrg	int olderrno = errno;
191473143b9aSmrg	int connected = 0;
1915fe567363Smrg
191673143b9aSmrg	if (!connected)
191773143b9aSmrg	{
191873143b9aSmrg	    errno = olderrno;
1919fe567363Smrg
192073143b9aSmrg	    /*
192173143b9aSmrg	     * If the error was ENOENT, the server may be starting up; we used
192273143b9aSmrg	     * to suggest to try again in this case with
192373143b9aSmrg	     * TRANS_TRY_CONNECT_AGAIN, but this introduced problems for
192473143b9aSmrg	     * processes still referencing stale sockets in their environment.
192573143b9aSmrg	     * Hence, we now return a hard error, TRANS_CONNECT_FAILED, and it
192673143b9aSmrg	     * is suggested that higher level stacks handle retries on their
192773143b9aSmrg	     * level when they face a slow starting server.
192873143b9aSmrg	     *
192973143b9aSmrg	     * If the error was EWOULDBLOCK or EINPROGRESS then the socket
193073143b9aSmrg	     * was non-blocking and we should poll using select
193173143b9aSmrg	     *
193273143b9aSmrg	     * If the error was EINTR, the connect was interrupted and we
193373143b9aSmrg	     * should try again.
193473143b9aSmrg	     */
193573143b9aSmrg
193673143b9aSmrg	    if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS)
193773143b9aSmrg		return TRANS_IN_PROGRESS;
193873143b9aSmrg	    else if (olderrno == EINTR)
193973143b9aSmrg		return TRANS_TRY_CONNECT_AGAIN;
1940a773ec55Smrg	    else {
1941fe567363Smrg		prmsg (2,"SocketUNIXConnect: Can't connect: errno = %d\n",
1942fe567363Smrg		       EGET());
194373143b9aSmrg
194473143b9aSmrg		return TRANS_CONNECT_FAILED;
194573143b9aSmrg	    }
194673143b9aSmrg	}
194773143b9aSmrg    }
194873143b9aSmrg
194973143b9aSmrg    /*
195073143b9aSmrg     * Get the socket name and the peer name from the connect socket,
195173143b9aSmrg     * since this is unix domain.
195273143b9aSmrg     */
195373143b9aSmrg
1954fe567363Smrg    if ((ciptr->addr = malloc(namelen)) == NULL ||
1955fe567363Smrg       (ciptr->peeraddr = malloc(namelen)) == NULL)
195673143b9aSmrg    {
1957fe567363Smrg        prmsg (1,
1958fe567363Smrg	"SocketUNIXCreateListener: Can't allocate space for the addr\n");
195973143b9aSmrg        return TRANS_CONNECT_FAILED;
196073143b9aSmrg    }
196173143b9aSmrg
196273143b9aSmrg    ciptr->family = AF_UNIX;
196373143b9aSmrg    ciptr->addrlen = namelen;
196473143b9aSmrg    ciptr->peeraddrlen = namelen;
196573143b9aSmrg    memcpy (ciptr->addr, &sockname, ciptr->addrlen);
196673143b9aSmrg    memcpy (ciptr->peeraddr, &sockname, ciptr->peeraddrlen);
196773143b9aSmrg
196873143b9aSmrg    return 0;
196973143b9aSmrg}
197073143b9aSmrg
197173143b9aSmrg#endif /* UNIXCONN */
197273143b9aSmrg
197373143b9aSmrg#endif /* TRANS_CLIENT */
197473143b9aSmrg
197573143b9aSmrg
197673143b9aSmrgstatic int
197773143b9aSmrgTRANS(SocketBytesReadable) (XtransConnInfo ciptr, BytesReadable_t *pend)
197873143b9aSmrg
197973143b9aSmrg{
1980fe567363Smrg    prmsg (2,"SocketBytesReadable(%p,%d,%p)\n",
198173143b9aSmrg	ciptr, ciptr->fd, pend);
198273143b9aSmrg#ifdef WIN32
198373143b9aSmrg    {
198473143b9aSmrg	int ret = ioctlsocket ((SOCKET) ciptr->fd, FIONREAD, (u_long *) pend);
198573143b9aSmrg	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
198673143b9aSmrg	return ret;
198773143b9aSmrg    }
198873143b9aSmrg#else
198973143b9aSmrg    return ioctl (ciptr->fd, FIONREAD, (char *) pend);
199073143b9aSmrg#endif /* WIN32 */
199173143b9aSmrg}
199273143b9aSmrg
199375ebec6dSmrg#if XTRANS_SEND_FDS
199475ebec6dSmrg
199575ebec6dSmrgstatic void
199675ebec6dSmrgappendFd(struct _XtransConnFd **prev, int fd, int do_close)
199775ebec6dSmrg{
199875ebec6dSmrg    struct _XtransConnFd *cf, *new;
199975ebec6dSmrg
200075ebec6dSmrg    new = malloc (sizeof (struct _XtransConnFd));
200175ebec6dSmrg    if (!new) {
200275ebec6dSmrg        /* XXX mark connection as broken */
200375ebec6dSmrg        close(fd);
200475ebec6dSmrg        return;
200575ebec6dSmrg    }
200675ebec6dSmrg    new->next = 0;
200775ebec6dSmrg    new->fd = fd;
200875ebec6dSmrg    new->do_close = do_close;
200975ebec6dSmrg    /* search to end of list */
201075ebec6dSmrg    for (; (cf = *prev); prev = &(cf->next));
201175ebec6dSmrg    *prev = new;
201275ebec6dSmrg}
201373143b9aSmrg
201473143b9aSmrgstatic int
201575ebec6dSmrgremoveFd(struct _XtransConnFd **prev)
201675ebec6dSmrg{
201775ebec6dSmrg    struct _XtransConnFd *cf;
201875ebec6dSmrg    int fd;
201975ebec6dSmrg
202075ebec6dSmrg    if ((cf = *prev)) {
202175ebec6dSmrg        *prev = cf->next;
202275ebec6dSmrg        fd = cf->fd;
202375ebec6dSmrg        free(cf);
202475ebec6dSmrg    } else
202575ebec6dSmrg        fd = -1;
202675ebec6dSmrg    return fd;
202775ebec6dSmrg}
202873143b9aSmrg
202975ebec6dSmrgstatic void
203075ebec6dSmrgdiscardFd(struct _XtransConnFd **prev, struct _XtransConnFd *upto, int do_close)
203173143b9aSmrg{
203275ebec6dSmrg    struct _XtransConnFd *cf, *next;
203373143b9aSmrg
203475ebec6dSmrg    for (cf = *prev; cf != upto; cf = next) {
203575ebec6dSmrg        next = cf->next;
203675ebec6dSmrg        if (do_close || cf->do_close)
203775ebec6dSmrg            close(cf->fd);
203875ebec6dSmrg        free(cf);
203973143b9aSmrg    }
204075ebec6dSmrg    *prev = upto;
204173143b9aSmrg}
204273143b9aSmrg
204375ebec6dSmrgstatic void
204475ebec6dSmrgcleanupFds(XtransConnInfo ciptr)
204575ebec6dSmrg{
204675ebec6dSmrg    /* Clean up the send list but don't close the fds */
204775ebec6dSmrg    discardFd(&ciptr->send_fds, NULL, 0);
204875ebec6dSmrg    /* Clean up the recv list and *do* close the fds */
204975ebec6dSmrg    discardFd(&ciptr->recv_fds, NULL, 1);
205075ebec6dSmrg}
205173143b9aSmrg
205273143b9aSmrgstatic int
205375ebec6dSmrgnFd(struct _XtransConnFd **prev)
205475ebec6dSmrg{
205575ebec6dSmrg    struct _XtransConnFd *cf;
205675ebec6dSmrg    int n = 0;
205775ebec6dSmrg
205875ebec6dSmrg    for (cf = *prev; cf; cf = cf->next)
205975ebec6dSmrg        n++;
206075ebec6dSmrg    return n;
206175ebec6dSmrg}
206273143b9aSmrg
206375ebec6dSmrgstatic int
206475ebec6dSmrgTRANS(SocketRecvFd) (XtransConnInfo ciptr)
206573143b9aSmrg{
206675ebec6dSmrg    prmsg (2, "SocketRecvFd(%d)\n", ciptr->fd);
206775ebec6dSmrg    return removeFd(&ciptr->recv_fds);
206875ebec6dSmrg}
206975ebec6dSmrg
207075ebec6dSmrgstatic int
207175ebec6dSmrgTRANS(SocketSendFd) (XtransConnInfo ciptr, int fd, int do_close)
207275ebec6dSmrg{
207375ebec6dSmrg    appendFd(&ciptr->send_fds, fd, do_close);
207475ebec6dSmrg    return 0;
207575ebec6dSmrg}
207675ebec6dSmrg
207775ebec6dSmrgstatic int
207875ebec6dSmrgTRANS(SocketRecvFdInvalid)(XtransConnInfo ciptr)
207975ebec6dSmrg{
208075ebec6dSmrg    errno = EINVAL;
208175ebec6dSmrg    return -1;
208275ebec6dSmrg}
208375ebec6dSmrg
208475ebec6dSmrgstatic int
208575ebec6dSmrgTRANS(SocketSendFdInvalid)(XtransConnInfo ciptr, int fd, int do_close)
208675ebec6dSmrg{
208775ebec6dSmrg    errno = EINVAL;
208875ebec6dSmrg    return -1;
208975ebec6dSmrg}
209075ebec6dSmrg
209175ebec6dSmrg#define MAX_FDS		128
209275ebec6dSmrg
209375ebec6dSmrgunion fd_pass {
209475ebec6dSmrg	struct cmsghdr	cmsghdr;
209575ebec6dSmrg	char		buf[CMSG_SPACE(MAX_FDS * sizeof(int))];
209675ebec6dSmrg};
209775ebec6dSmrg
209875ebec6dSmrg#endif /* XTRANS_SEND_FDS */
209975ebec6dSmrg
210075ebec6dSmrgstatic int
210175ebec6dSmrgTRANS(SocketRead) (XtransConnInfo ciptr, char *buf, int size)
210275ebec6dSmrg
210375ebec6dSmrg{
210475ebec6dSmrg    prmsg (2,"SocketRead(%d,%p,%d)\n", ciptr->fd, buf, size);
210573143b9aSmrg
2106fe567363Smrg#if defined(WIN32)
210773143b9aSmrg    {
210875ebec6dSmrg	int ret = recv ((SOCKET)ciptr->fd, buf, size, 0);
210973143b9aSmrg#ifdef WIN32
211073143b9aSmrg	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
211173143b9aSmrg#endif
211273143b9aSmrg	return ret;
211373143b9aSmrg    }
211473143b9aSmrg#else
211575ebec6dSmrg#if XTRANS_SEND_FDS
211675ebec6dSmrg    {
211775ebec6dSmrg        struct iovec    iov = {
211875ebec6dSmrg            .iov_base = buf,
211975ebec6dSmrg            .iov_len = size
212075ebec6dSmrg        };
212175ebec6dSmrg        union fd_pass   cmsgbuf;
212275ebec6dSmrg        struct msghdr   msg = {
212375ebec6dSmrg            .msg_name = NULL,
212475ebec6dSmrg            .msg_namelen = 0,
212575ebec6dSmrg            .msg_iov = &iov,
212675ebec6dSmrg            .msg_iovlen = 1,
212775ebec6dSmrg            .msg_control = cmsgbuf.buf,
212875ebec6dSmrg            .msg_controllen = CMSG_LEN(MAX_FDS * sizeof(int))
212975ebec6dSmrg        };
213075ebec6dSmrg
213175ebec6dSmrg        size = recvmsg(ciptr->fd, &msg, 0);
213275ebec6dSmrg        if (size >= 0) {
213375ebec6dSmrg            struct cmsghdr *hdr;
213475ebec6dSmrg
213575ebec6dSmrg            for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) {
213675ebec6dSmrg                if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) {
213775ebec6dSmrg                    int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int);
213875ebec6dSmrg                    int i;
213975ebec6dSmrg                    int *fd = (int *) CMSG_DATA(hdr);
214075ebec6dSmrg
214175ebec6dSmrg                    for (i = 0; i < nfd; i++)
214275ebec6dSmrg                        appendFd(&ciptr->recv_fds, fd[i], 0);
214375ebec6dSmrg                }
214475ebec6dSmrg            }
214575ebec6dSmrg        }
214675ebec6dSmrg        return size;
214775ebec6dSmrg    }
214875ebec6dSmrg#else
214975ebec6dSmrg    return read(ciptr->fd, buf, size);
215075ebec6dSmrg#endif /* XTRANS_SEND_FDS */
215173143b9aSmrg#endif /* WIN32 */
215273143b9aSmrg}
215373143b9aSmrg
215473143b9aSmrgstatic int
215573143b9aSmrgTRANS(SocketReadv) (XtransConnInfo ciptr, struct iovec *buf, int size)
215673143b9aSmrg
215773143b9aSmrg{
2158fe567363Smrg    prmsg (2,"SocketReadv(%d,%p,%d)\n", ciptr->fd, buf, size);
215973143b9aSmrg
216075ebec6dSmrg#if XTRANS_SEND_FDS
216175ebec6dSmrg    {
216275ebec6dSmrg        union fd_pass   cmsgbuf;
216375ebec6dSmrg        struct msghdr   msg = {
216475ebec6dSmrg            .msg_name = NULL,
216575ebec6dSmrg            .msg_namelen = 0,
216675ebec6dSmrg            .msg_iov = buf,
216775ebec6dSmrg            .msg_iovlen = size,
216875ebec6dSmrg            .msg_control = cmsgbuf.buf,
216975ebec6dSmrg            .msg_controllen = CMSG_LEN(MAX_FDS * sizeof(int))
217075ebec6dSmrg        };
217175ebec6dSmrg
217275ebec6dSmrg        size = recvmsg(ciptr->fd, &msg, 0);
217375ebec6dSmrg        if (size >= 0) {
217475ebec6dSmrg            struct cmsghdr *hdr;
217575ebec6dSmrg
217675ebec6dSmrg            for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) {
217775ebec6dSmrg                if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) {
217875ebec6dSmrg                    int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int);
217975ebec6dSmrg                    int i;
218075ebec6dSmrg                    int *fd = (int *) CMSG_DATA(hdr);
218175ebec6dSmrg
218275ebec6dSmrg                    for (i = 0; i < nfd; i++)
218375ebec6dSmrg                        appendFd(&ciptr->recv_fds, fd[i], 0);
218475ebec6dSmrg                }
218575ebec6dSmrg            }
218675ebec6dSmrg        }
218775ebec6dSmrg        return size;
218875ebec6dSmrg    }
218975ebec6dSmrg#else
219073143b9aSmrg    return READV (ciptr, buf, size);
219175ebec6dSmrg#endif
219273143b9aSmrg}
219373143b9aSmrg
219473143b9aSmrg
219573143b9aSmrgstatic int
219673143b9aSmrgTRANS(SocketWritev) (XtransConnInfo ciptr, struct iovec *buf, int size)
219773143b9aSmrg
219873143b9aSmrg{
2199fe567363Smrg    prmsg (2,"SocketWritev(%d,%p,%d)\n", ciptr->fd, buf, size);
220073143b9aSmrg
220175ebec6dSmrg#if XTRANS_SEND_FDS
220275ebec6dSmrg    if (ciptr->send_fds)
220375ebec6dSmrg    {
220475ebec6dSmrg        union fd_pass           cmsgbuf;
220575ebec6dSmrg        int                     nfd = nFd(&ciptr->send_fds);
220675ebec6dSmrg        struct _XtransConnFd    *cf = ciptr->send_fds;
220775ebec6dSmrg        struct msghdr           msg = {
220875ebec6dSmrg            .msg_name = NULL,
220975ebec6dSmrg            .msg_namelen = 0,
221075ebec6dSmrg            .msg_iov = buf,
221175ebec6dSmrg            .msg_iovlen = size,
221275ebec6dSmrg            .msg_control = cmsgbuf.buf,
221375ebec6dSmrg            .msg_controllen = CMSG_LEN(nfd * sizeof(int))
221475ebec6dSmrg        };
221575ebec6dSmrg        struct cmsghdr          *hdr = CMSG_FIRSTHDR(&msg);
221675ebec6dSmrg        int                     i;
221775ebec6dSmrg        int                     *fds;
221875ebec6dSmrg
221975ebec6dSmrg        hdr->cmsg_len = msg.msg_controllen;
222075ebec6dSmrg        hdr->cmsg_level = SOL_SOCKET;
222175ebec6dSmrg        hdr->cmsg_type = SCM_RIGHTS;
222275ebec6dSmrg
222375ebec6dSmrg        fds = (int *) CMSG_DATA(hdr);
222475ebec6dSmrg        /* Set up fds */
222575ebec6dSmrg        for (i = 0; i < nfd; i++) {
222675ebec6dSmrg            fds[i] = cf->fd;
222775ebec6dSmrg            cf = cf->next;
222875ebec6dSmrg        }
222975ebec6dSmrg
223075ebec6dSmrg        i = sendmsg(ciptr->fd, &msg, 0);
223175ebec6dSmrg        if (i > 0)
223275ebec6dSmrg            discardFd(&ciptr->send_fds, cf, 0);
223375ebec6dSmrg        return i;
223475ebec6dSmrg    }
223575ebec6dSmrg#endif
223673143b9aSmrg    return WRITEV (ciptr, buf, size);
223773143b9aSmrg}
223873143b9aSmrg
223973143b9aSmrg
224075ebec6dSmrgstatic int
224175ebec6dSmrgTRANS(SocketWrite) (XtransConnInfo ciptr, char *buf, int size)
224275ebec6dSmrg
224375ebec6dSmrg{
224475ebec6dSmrg    prmsg (2,"SocketWrite(%d,%p,%d)\n", ciptr->fd, buf, size);
224575ebec6dSmrg
224675ebec6dSmrg#if defined(WIN32)
224775ebec6dSmrg    {
224875ebec6dSmrg	int ret = send ((SOCKET)ciptr->fd, buf, size, 0);
224975ebec6dSmrg#ifdef WIN32
225075ebec6dSmrg	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
225175ebec6dSmrg#endif
225275ebec6dSmrg	return ret;
225375ebec6dSmrg    }
225475ebec6dSmrg#else
225575ebec6dSmrg#if XTRANS_SEND_FDS
225675ebec6dSmrg    if (ciptr->send_fds)
225775ebec6dSmrg    {
225875ebec6dSmrg        struct iovec            iov;
225975ebec6dSmrg
226075ebec6dSmrg        iov.iov_base = buf;
226175ebec6dSmrg        iov.iov_len = size;
226275ebec6dSmrg        return TRANS(SocketWritev)(ciptr, &iov, 1);
226375ebec6dSmrg    }
226475ebec6dSmrg#endif /* XTRANS_SEND_FDS */
226575ebec6dSmrg    return write (ciptr->fd, buf, size);
226675ebec6dSmrg#endif /* WIN32 */
226775ebec6dSmrg}
226875ebec6dSmrg
226973143b9aSmrgstatic int
227073143b9aSmrgTRANS(SocketDisconnect) (XtransConnInfo ciptr)
227173143b9aSmrg
227273143b9aSmrg{
2273fe567363Smrg    prmsg (2,"SocketDisconnect(%p,%d)\n", ciptr, ciptr->fd);
227473143b9aSmrg
227573143b9aSmrg#ifdef WIN32
2276fe567363Smrg    {
227773143b9aSmrg	int ret = shutdown (ciptr->fd, 2);
227873143b9aSmrg	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
227973143b9aSmrg	return ret;
228073143b9aSmrg    }
228173143b9aSmrg#else
228273143b9aSmrg    return shutdown (ciptr->fd, 2); /* disallow further sends and receives */
228373143b9aSmrg#endif
228473143b9aSmrg}
228573143b9aSmrg
228673143b9aSmrg
228773143b9aSmrg#ifdef TCPCONN
228873143b9aSmrgstatic int
228973143b9aSmrgTRANS(SocketINETClose) (XtransConnInfo ciptr)
229073143b9aSmrg
229173143b9aSmrg{
2292fe567363Smrg    prmsg (2,"SocketINETClose(%p,%d)\n", ciptr, ciptr->fd);
229373143b9aSmrg
229473143b9aSmrg#ifdef WIN32
229573143b9aSmrg    {
229673143b9aSmrg	int ret = close (ciptr->fd);
229773143b9aSmrg	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
229873143b9aSmrg	return ret;
229973143b9aSmrg    }
230073143b9aSmrg#else
230173143b9aSmrg    return close (ciptr->fd);
230273143b9aSmrg#endif
230373143b9aSmrg}
230473143b9aSmrg
230573143b9aSmrg#endif /* TCPCONN */
230673143b9aSmrg
230773143b9aSmrg
230873143b9aSmrg#ifdef UNIXCONN
230973143b9aSmrgstatic int
231073143b9aSmrgTRANS(SocketUNIXClose) (XtransConnInfo ciptr)
231173143b9aSmrg{
231273143b9aSmrg    /*
231373143b9aSmrg     * If this is the server side, then once the socket is closed,
231473143b9aSmrg     * it must be unlinked to completely close it
231573143b9aSmrg     */
231673143b9aSmrg
231773143b9aSmrg    struct sockaddr_un	*sockname = (struct sockaddr_un *) ciptr->addr;
231873143b9aSmrg    int ret;
231973143b9aSmrg
2320fe567363Smrg    prmsg (2,"SocketUNIXClose(%p,%d)\n", ciptr, ciptr->fd);
232173143b9aSmrg
232275ebec6dSmrg#if XTRANS_SEND_FDS
232375ebec6dSmrg    cleanupFds(ciptr);
232475ebec6dSmrg#endif
232573143b9aSmrg    ret = close(ciptr->fd);
232673143b9aSmrg
232773143b9aSmrg    if (ciptr->flags
232873143b9aSmrg       && sockname
232973143b9aSmrg       && sockname->sun_family == AF_UNIX
233073143b9aSmrg       && sockname->sun_path[0])
233173143b9aSmrg    {
233273143b9aSmrg	if (!(ciptr->flags & TRANS_NOUNLINK
233373143b9aSmrg	    || ciptr->transptr->flags & TRANS_ABSTRACT))
233473143b9aSmrg		unlink (sockname->sun_path);
233573143b9aSmrg    }
233673143b9aSmrg
233773143b9aSmrg    return ret;
233873143b9aSmrg}
233973143b9aSmrg
234073143b9aSmrgstatic int
234173143b9aSmrgTRANS(SocketUNIXCloseForCloning) (XtransConnInfo ciptr)
234273143b9aSmrg
234373143b9aSmrg{
234473143b9aSmrg    /*
234573143b9aSmrg     * Don't unlink path.
234673143b9aSmrg     */
234773143b9aSmrg
234873143b9aSmrg    int ret;
234973143b9aSmrg
2350fe567363Smrg    prmsg (2,"SocketUNIXCloseForCloning(%p,%d)\n",
2351fe567363Smrg	ciptr, ciptr->fd);
235273143b9aSmrg
235375ebec6dSmrg#if XTRANS_SEND_FDS
235475ebec6dSmrg    cleanupFds(ciptr);
235575ebec6dSmrg#endif
235673143b9aSmrg    ret = close(ciptr->fd);
235773143b9aSmrg
235873143b9aSmrg    return ret;
235973143b9aSmrg}
236073143b9aSmrg
236173143b9aSmrg#endif /* UNIXCONN */
236273143b9aSmrg
236373143b9aSmrg
236473143b9aSmrg#ifdef TCPCONN
236573143b9aSmrg# ifdef TRANS_SERVER
2366fe567363Smrgstatic const char* tcp_nolisten[] = {
236773143b9aSmrg	"inet",
236873143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
236973143b9aSmrg	"inet6",
237073143b9aSmrg#endif
237173143b9aSmrg	NULL
237273143b9aSmrg};
237373143b9aSmrg# endif
237473143b9aSmrg
237573143b9aSmrgXtransport	TRANS(SocketTCPFuncs) = {
237673143b9aSmrg	/* Socket Interface */
237773143b9aSmrg	"tcp",
237873143b9aSmrg        TRANS_ALIAS,
237973143b9aSmrg#ifdef TRANS_CLIENT
238073143b9aSmrg	TRANS(SocketOpenCOTSClient),
238173143b9aSmrg#endif /* TRANS_CLIENT */
238273143b9aSmrg#ifdef TRANS_SERVER
238373143b9aSmrg	tcp_nolisten,
238473143b9aSmrg	TRANS(SocketOpenCOTSServer),
238573143b9aSmrg#endif /* TRANS_SERVER */
238673143b9aSmrg#ifdef TRANS_REOPEN
238773143b9aSmrg	TRANS(SocketReopenCOTSServer),
238873143b9aSmrg#endif
238973143b9aSmrg	TRANS(SocketSetOption),
239073143b9aSmrg#ifdef TRANS_SERVER
239173143b9aSmrg	TRANS(SocketINETCreateListener),
239273143b9aSmrg	NULL,		       			/* ResetListener */
239373143b9aSmrg	TRANS(SocketINETAccept),
239473143b9aSmrg#endif /* TRANS_SERVER */
239573143b9aSmrg#ifdef TRANS_CLIENT
239673143b9aSmrg	TRANS(SocketINETConnect),
239773143b9aSmrg#endif /* TRANS_CLIENT */
239873143b9aSmrg	TRANS(SocketBytesReadable),
239973143b9aSmrg	TRANS(SocketRead),
240073143b9aSmrg	TRANS(SocketWrite),
240173143b9aSmrg	TRANS(SocketReadv),
240273143b9aSmrg	TRANS(SocketWritev),
240375ebec6dSmrg#if XTRANS_SEND_FDS
240475ebec6dSmrg        TRANS(SocketSendFdInvalid),
240575ebec6dSmrg        TRANS(SocketRecvFdInvalid),
240675ebec6dSmrg#endif
240773143b9aSmrg	TRANS(SocketDisconnect),
240873143b9aSmrg	TRANS(SocketINETClose),
240973143b9aSmrg	TRANS(SocketINETClose),
241073143b9aSmrg	};
241173143b9aSmrg
241273143b9aSmrgXtransport	TRANS(SocketINETFuncs) = {
241373143b9aSmrg	/* Socket Interface */
241473143b9aSmrg	"inet",
241573143b9aSmrg	0,
241673143b9aSmrg#ifdef TRANS_CLIENT
241773143b9aSmrg	TRANS(SocketOpenCOTSClient),
241873143b9aSmrg#endif /* TRANS_CLIENT */
241973143b9aSmrg#ifdef TRANS_SERVER
242073143b9aSmrg	NULL,
242173143b9aSmrg	TRANS(SocketOpenCOTSServer),
242273143b9aSmrg#endif /* TRANS_SERVER */
242373143b9aSmrg#ifdef TRANS_REOPEN
242473143b9aSmrg	TRANS(SocketReopenCOTSServer),
242573143b9aSmrg#endif
242673143b9aSmrg	TRANS(SocketSetOption),
242773143b9aSmrg#ifdef TRANS_SERVER
242873143b9aSmrg	TRANS(SocketINETCreateListener),
242973143b9aSmrg	NULL,		       			/* ResetListener */
243073143b9aSmrg	TRANS(SocketINETAccept),
243173143b9aSmrg#endif /* TRANS_SERVER */
243273143b9aSmrg#ifdef TRANS_CLIENT
243373143b9aSmrg	TRANS(SocketINETConnect),
243473143b9aSmrg#endif /* TRANS_CLIENT */
243573143b9aSmrg	TRANS(SocketBytesReadable),
243673143b9aSmrg	TRANS(SocketRead),
243773143b9aSmrg	TRANS(SocketWrite),
243873143b9aSmrg	TRANS(SocketReadv),
243973143b9aSmrg	TRANS(SocketWritev),
244075ebec6dSmrg#if XTRANS_SEND_FDS
244175ebec6dSmrg        TRANS(SocketSendFdInvalid),
244275ebec6dSmrg        TRANS(SocketRecvFdInvalid),
244375ebec6dSmrg#endif
244473143b9aSmrg	TRANS(SocketDisconnect),
244573143b9aSmrg	TRANS(SocketINETClose),
244673143b9aSmrg	TRANS(SocketINETClose),
244773143b9aSmrg	};
244873143b9aSmrg
244973143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
245073143b9aSmrgXtransport     TRANS(SocketINET6Funcs) = {
245173143b9aSmrg	/* Socket Interface */
245273143b9aSmrg	"inet6",
245373143b9aSmrg	0,
245473143b9aSmrg#ifdef TRANS_CLIENT
245573143b9aSmrg	TRANS(SocketOpenCOTSClient),
245673143b9aSmrg#endif /* TRANS_CLIENT */
245773143b9aSmrg#ifdef TRANS_SERVER
245873143b9aSmrg	NULL,
245973143b9aSmrg	TRANS(SocketOpenCOTSServer),
246073143b9aSmrg#endif /* TRANS_SERVER */
246173143b9aSmrg#ifdef TRANS_REOPEN
246273143b9aSmrg	TRANS(SocketReopenCOTSServer),
246373143b9aSmrg#endif
246473143b9aSmrg	TRANS(SocketSetOption),
246573143b9aSmrg#ifdef TRANS_SERVER
246673143b9aSmrg	TRANS(SocketINETCreateListener),
246773143b9aSmrg	NULL,					/* ResetListener */
246873143b9aSmrg	TRANS(SocketINETAccept),
246973143b9aSmrg#endif /* TRANS_SERVER */
247073143b9aSmrg#ifdef TRANS_CLIENT
247173143b9aSmrg	TRANS(SocketINETConnect),
247273143b9aSmrg#endif /* TRANS_CLIENT */
247373143b9aSmrg	TRANS(SocketBytesReadable),
247473143b9aSmrg	TRANS(SocketRead),
247573143b9aSmrg	TRANS(SocketWrite),
247673143b9aSmrg	TRANS(SocketReadv),
247773143b9aSmrg	TRANS(SocketWritev),
247875ebec6dSmrg#if XTRANS_SEND_FDS
247975ebec6dSmrg        TRANS(SocketSendFdInvalid),
248075ebec6dSmrg        TRANS(SocketRecvFdInvalid),
248175ebec6dSmrg#endif
248273143b9aSmrg	TRANS(SocketDisconnect),
248373143b9aSmrg	TRANS(SocketINETClose),
248473143b9aSmrg	TRANS(SocketINETClose),
248573143b9aSmrg	};
248673143b9aSmrg#endif /* IPv6 */
248773143b9aSmrg#endif /* TCPCONN */
248873143b9aSmrg
248973143b9aSmrg#ifdef UNIXCONN
249073143b9aSmrg#if !defined(LOCALCONN)
249173143b9aSmrgXtransport	TRANS(SocketLocalFuncs) = {
249273143b9aSmrg	/* Socket Interface */
249373143b9aSmrg	"local",
249473143b9aSmrg#ifdef HAVE_ABSTRACT_SOCKETS
249573143b9aSmrg	TRANS_ABSTRACT,
249673143b9aSmrg#else
249773143b9aSmrg	0,
249873143b9aSmrg#endif
249973143b9aSmrg#ifdef TRANS_CLIENT
250073143b9aSmrg	TRANS(SocketOpenCOTSClient),
250173143b9aSmrg#endif /* TRANS_CLIENT */
250273143b9aSmrg#ifdef TRANS_SERVER
250373143b9aSmrg	NULL,
250473143b9aSmrg	TRANS(SocketOpenCOTSServer),
250573143b9aSmrg#endif /* TRANS_SERVER */
250673143b9aSmrg#ifdef TRANS_REOPEN
250773143b9aSmrg	TRANS(SocketReopenCOTSServer),
250873143b9aSmrg#endif
250973143b9aSmrg	TRANS(SocketSetOption),
251073143b9aSmrg#ifdef TRANS_SERVER
251173143b9aSmrg	TRANS(SocketUNIXCreateListener),
251273143b9aSmrg	TRANS(SocketUNIXResetListener),
251373143b9aSmrg	TRANS(SocketUNIXAccept),
251473143b9aSmrg#endif /* TRANS_SERVER */
251573143b9aSmrg#ifdef TRANS_CLIENT
251673143b9aSmrg	TRANS(SocketUNIXConnect),
251773143b9aSmrg#endif /* TRANS_CLIENT */
251873143b9aSmrg	TRANS(SocketBytesReadable),
251973143b9aSmrg	TRANS(SocketRead),
252073143b9aSmrg	TRANS(SocketWrite),
252173143b9aSmrg	TRANS(SocketReadv),
252273143b9aSmrg	TRANS(SocketWritev),
252375ebec6dSmrg#if XTRANS_SEND_FDS
252475ebec6dSmrg        TRANS(SocketSendFd),
252575ebec6dSmrg        TRANS(SocketRecvFd),
252675ebec6dSmrg#endif
252773143b9aSmrg	TRANS(SocketDisconnect),
252873143b9aSmrg	TRANS(SocketUNIXClose),
252973143b9aSmrg	TRANS(SocketUNIXCloseForCloning),
253073143b9aSmrg	};
253173143b9aSmrg#endif /* !LOCALCONN */
253273143b9aSmrg# ifdef TRANS_SERVER
253373143b9aSmrg#  if !defined(LOCALCONN)
253475ebec6dSmrgstatic const char* unix_nolisten[] = { "local" , NULL };
253573143b9aSmrg#  endif
253673143b9aSmrg# endif
2537fe567363Smrg
253873143b9aSmrgXtransport	TRANS(SocketUNIXFuncs) = {
253973143b9aSmrg	/* Socket Interface */
254073143b9aSmrg	"unix",
254173143b9aSmrg#if !defined(LOCALCONN) && !defined(HAVE_ABSTRACT_SOCKETS)
254273143b9aSmrg        TRANS_ALIAS,
254373143b9aSmrg#else
254473143b9aSmrg	0,
254573143b9aSmrg#endif
254673143b9aSmrg#ifdef TRANS_CLIENT
254773143b9aSmrg	TRANS(SocketOpenCOTSClient),
254873143b9aSmrg#endif /* TRANS_CLIENT */
254973143b9aSmrg#ifdef TRANS_SERVER
255073143b9aSmrg#if !defined(LOCALCONN)
255173143b9aSmrg	unix_nolisten,
255273143b9aSmrg#else
255373143b9aSmrg	NULL,
255473143b9aSmrg#endif
255573143b9aSmrg	TRANS(SocketOpenCOTSServer),
255673143b9aSmrg#endif /* TRANS_SERVER */
255773143b9aSmrg#ifdef TRANS_REOPEN
255873143b9aSmrg	TRANS(SocketReopenCOTSServer),
255973143b9aSmrg#endif
256073143b9aSmrg	TRANS(SocketSetOption),
256173143b9aSmrg#ifdef TRANS_SERVER
256273143b9aSmrg	TRANS(SocketUNIXCreateListener),
256373143b9aSmrg	TRANS(SocketUNIXResetListener),
256473143b9aSmrg	TRANS(SocketUNIXAccept),
256573143b9aSmrg#endif /* TRANS_SERVER */
256673143b9aSmrg#ifdef TRANS_CLIENT
256773143b9aSmrg	TRANS(SocketUNIXConnect),
256873143b9aSmrg#endif /* TRANS_CLIENT */
256973143b9aSmrg	TRANS(SocketBytesReadable),
257073143b9aSmrg	TRANS(SocketRead),
257173143b9aSmrg	TRANS(SocketWrite),
257273143b9aSmrg	TRANS(SocketReadv),
257373143b9aSmrg	TRANS(SocketWritev),
257475ebec6dSmrg#if XTRANS_SEND_FDS
257575ebec6dSmrg        TRANS(SocketSendFd),
257675ebec6dSmrg        TRANS(SocketRecvFd),
257775ebec6dSmrg#endif
257873143b9aSmrg	TRANS(SocketDisconnect),
257973143b9aSmrg	TRANS(SocketUNIXClose),
258073143b9aSmrg	TRANS(SocketUNIXCloseForCloning),
258173143b9aSmrg	};
258273143b9aSmrg
258373143b9aSmrg#endif /* UNIXCONN */
2584