Xtranssock.c revision ac57ed83
1/*
2 * Copyright (c) 2002, 2025, Oracle and/or its affiliates.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23/*
24
25Copyright 1993, 1994, 1998  The Open Group
26
27Permission to use, copy, modify, distribute, and sell this software and its
28documentation for any purpose is hereby granted without fee, provided that
29the above copyright notice appear in all copies and that both that
30copyright notice and this permission notice appear in supporting
31documentation.
32
33The above copyright notice and this permission notice shall be included
34in all copies or substantial portions of the Software.
35
36THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
37OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
38MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
39IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
40OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
41ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
42OTHER DEALINGS IN THE SOFTWARE.
43
44Except as contained in this notice, the name of the copyright holders shall
45not be used in advertising or otherwise to promote the sale, use or
46other dealings in this Software without prior written authorization
47from the copyright holders.
48
49 * Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA
50 *
51 * All Rights Reserved
52 *
53 * Permission to use, copy, modify, and distribute this software and its
54 * documentation for any purpose and without fee is hereby granted, provided
55 * that the above copyright notice appear in all copies and that both that
56 * copyright notice and this permission notice appear in supporting
57 * documentation, and that the name NCR not be used in advertising
58 * or publicity pertaining to distribution of the software without specific,
59 * written prior permission.  NCR makes no representations about the
60 * suitability of this software for any purpose.  It is provided "as is"
61 * without express or implied warranty.
62 *
63 * NCR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
64 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
65 * NO EVENT SHALL NCR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
66 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
67 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
68 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
69 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
70 */
71
72#include <ctype.h>
73#ifdef XTHREADS
74#include <X11/Xthreads.h>
75#endif
76
77#ifndef WIN32
78
79#if defined(TCPCONN) || defined(UNIXCONN)
80#include <sys/socket.h>
81#include <netinet/in.h>
82#include <arpa/inet.h>
83#endif
84
85#if defined(TCPCONN) || defined(UNIXCONN)
86#define X_INCLUDE_NETDB_H
87#define XOS_USE_NO_LOCKING
88#include <X11/Xos_r.h>
89#endif
90
91#ifdef UNIXCONN
92#ifndef X_NO_SYS_UN
93#include <sys/un.h>
94#endif
95#include <sys/stat.h>
96#endif
97
98
99#ifndef NO_TCP_H
100#if defined(linux) || defined(__GLIBC__)
101#include <sys/param.h>
102#endif /* osf */
103#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
104#include <sys/param.h>
105#include <machine/endian.h>
106#endif /* __NetBSD__ || __OpenBSD__ || __FreeBSD__ || __DragonFly__ */
107#include <netinet/tcp.h>
108#endif /* !NO_TCP_H */
109
110#include <sys/ioctl.h>
111#if defined(SVR4) || defined(__SVR4)
112#include <sys/filio.h>
113#endif
114
115#include <unistd.h>
116
117#else /* !WIN32 */
118
119#include <X11/Xwinsock.h>
120#include <X11/Xwindows.h>
121#include <X11/Xw32defs.h>
122#undef close
123#define close closesocket
124#define ECONNREFUSED WSAECONNREFUSED
125#define EADDRINUSE WSAEADDRINUSE
126#define EPROTOTYPE WSAEPROTOTYPE
127#undef EWOULDBLOCK
128#define EWOULDBLOCK WSAEWOULDBLOCK
129#define EINPROGRESS WSAEINPROGRESS
130#undef EINTR
131#define EINTR WSAEINTR
132#define X_INCLUDE_NETDB_H
133#define XOS_USE_MTSAFE_NETDBAPI
134#include <X11/Xos_r.h>
135#endif /* WIN32 */
136
137#if defined(SO_DONTLINGER) && defined(SO_LINGER)
138#undef SO_DONTLINGER
139#endif
140
141/* others don't need this */
142#define SocketInitOnce() /**/
143
144#ifdef __linux__
145#define HAVE_ABSTRACT_SOCKETS
146#endif
147
148#define MIN_BACKLOG 128
149#ifdef SOMAXCONN
150#if SOMAXCONN > MIN_BACKLOG
151#define BACKLOG SOMAXCONN
152#endif
153#endif
154#ifndef BACKLOG
155#define BACKLOG MIN_BACKLOG
156#endif
157
158#if defined(IPv6) && !defined(AF_INET6)
159#error "Cannot build IPv6 support without AF_INET6"
160#endif
161
162/* Temporary workaround for consumers whose configure scripts were
163   generated with pre-1.6 versions of xtrans.m4 */
164#if defined(IPv6) && !defined(HAVE_GETADDRINFO)
165#define HAVE_GETADDRINFO
166#endif
167
168/*
169 * This is the Socket implementation of the X Transport service layer
170 *
171 * This file contains the implementation for both the UNIX and INET domains,
172 * and can be built for either one, or both.
173 *
174 */
175
176typedef struct _Sockettrans2dev {
177    const char	*transname;
178    int		family;
179    int		devcotsname;
180    int		devcltsname;
181    int		protocol;
182} Sockettrans2dev;
183
184/* As documented in the X(7) man page:
185 *  tcp     TCP over IPv4 or IPv6
186 *  inet    TCP over IPv4 only
187 *  inet6   TCP over IPv6 only
188 *  unix    UNIX Domain Sockets (same host only)
189 *  local   Platform preferred local connection method
190 */
191static Sockettrans2dev Sockettrans2devtab[] = {
192#ifdef TCPCONN
193    {"inet",AF_INET,SOCK_STREAM,SOCK_DGRAM,0},
194#ifndef IPv6
195    {"tcp",AF_INET,SOCK_STREAM,SOCK_DGRAM,0},
196#else /* IPv6 */
197    {"tcp",AF_INET6,SOCK_STREAM,SOCK_DGRAM,0},
198    {"tcp",AF_INET,SOCK_STREAM,SOCK_DGRAM,0}, /* fallback */
199    {"inet6",AF_INET6,SOCK_STREAM,SOCK_DGRAM,0},
200#endif
201#endif /* TCPCONN */
202#ifdef UNIXCONN
203    {"unix",AF_UNIX,SOCK_STREAM,SOCK_DGRAM,0},
204#if !defined(LOCALCONN)
205    {"local",AF_UNIX,SOCK_STREAM,SOCK_DGRAM,0},
206#endif /* !LOCALCONN */
207#endif /* UNIXCONN */
208};
209
210#define NUMSOCKETFAMILIES (sizeof(Sockettrans2devtab)/sizeof(Sockettrans2dev))
211
212#ifdef TCPCONN
213static int TRANS(SocketINETClose) (XtransConnInfo ciptr);
214#endif
215
216#if (defined(TCPCONN) && \
217     (defined(TRANS_SERVER) || defined(X11_t) || !defined(HAVE_GETADDRINFO))) \
218    || defined(TRANS_REOPEN)
219static int
220is_numeric (const char *str)
221{
222    int i;
223
224    for (i = 0; i < (int) strlen (str); i++)
225	if (!isdigit (str[i]))
226	    return (0);
227
228    return (1);
229}
230#endif
231
232#ifdef UNIXCONN
233
234
235#if defined(X11_t)
236#define UNIX_PATH "/tmp/.X11-unix/X"
237#define UNIX_DIR "/tmp/.X11-unix"
238#endif /* X11_t */
239#if defined(XIM_t)
240#define UNIX_PATH "/tmp/.XIM-unix/XIM"
241#define UNIX_DIR "/tmp/.XIM-unix"
242#endif /* XIM_t */
243#if defined(FS_t) || defined(FONT_t)
244#define UNIX_PATH "/tmp/.font-unix/fs"
245#define UNIX_DIR "/tmp/.font-unix"
246#endif /* FS_t || FONT_t */
247#if defined(ICE_t)
248#define UNIX_PATH "/tmp/.ICE-unix/"
249#define UNIX_DIR "/tmp/.ICE-unix"
250#endif /* ICE_t */
251
252
253#endif /* UNIXCONN */
254
255#define PORTBUFSIZE	32
256
257#ifndef MAXHOSTNAMELEN
258#define MAXHOSTNAMELEN 255
259#endif
260
261#if defined(HAVE_SOCKLEN_T) || defined(IPv6)
262# define SOCKLEN_T socklen_t
263#elif defined(SVR4) || defined(__SVR4)
264# define SOCKLEN_T size_t
265#else
266# define SOCKLEN_T int
267#endif
268
269/*
270 * These are some utility function used by the real interface function below.
271 */
272
273static int
274TRANS(SocketSelectFamily) (int first, const char *family)
275
276{
277    int     i;
278
279    prmsg (3,"SocketSelectFamily(%s)\n", family);
280
281    for (i = first + 1; i < (int)NUMSOCKETFAMILIES; i++)
282    {
283        if (!strcmp (family, Sockettrans2devtab[i].transname))
284	    return i;
285    }
286
287    return (first == -1 ? -2 : -1);
288}
289
290
291/*
292 * This function gets the local address of the socket and stores it in the
293 * XtransConnInfo structure for the connection.
294 */
295
296static int
297TRANS(SocketINETGetAddr) (XtransConnInfo ciptr)
298
299{
300#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
301    struct sockaddr_storage sockname;
302#else
303    struct sockaddr_in sockname;
304#endif
305    void *socknamePtr = &sockname;
306    SOCKLEN_T namelen = sizeof(sockname);
307
308    prmsg (3,"SocketINETGetAddr(%p)\n", (void *) ciptr);
309
310    bzero(socknamePtr, namelen);
311
312    if (getsockname (ciptr->fd,(struct sockaddr *) socknamePtr,
313		     (void *)&namelen) < 0)
314    {
315#ifdef WIN32
316	errno = WSAGetLastError();
317#endif
318	prmsg (1,"SocketINETGetAddr: getsockname() failed: %d\n",
319	    EGET());
320	return -1;
321    }
322
323    /*
324     * Everything looks good: fill in the XtransConnInfo structure.
325     */
326
327    if ((ciptr->addr = malloc (namelen)) == NULL)
328    {
329        prmsg (1,
330	    "SocketINETGetAddr: Can't allocate space for the addr\n");
331        return -1;
332    }
333
334    ciptr->family = ((struct sockaddr *)socknamePtr)->sa_family;
335    ciptr->addrlen = namelen;
336    memcpy (ciptr->addr, socknamePtr, ciptr->addrlen);
337
338    return 0;
339}
340
341
342/*
343 * This function gets the remote address of the socket and stores it in the
344 * XtransConnInfo structure for the connection.
345 */
346
347static int
348TRANS(SocketINETGetPeerAddr) (XtransConnInfo ciptr)
349
350{
351#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
352    struct sockaddr_storage sockname;
353#else
354    struct sockaddr_in 	sockname;
355#endif
356    void *socknamePtr = &sockname;
357    SOCKLEN_T namelen = sizeof(sockname);
358
359    bzero(socknamePtr, namelen);
360
361    prmsg (3,"SocketINETGetPeerAddr(%p)\n", (void *) ciptr);
362
363    if (getpeername (ciptr->fd, (struct sockaddr *) socknamePtr,
364		     (void *)&namelen) < 0)
365    {
366#ifdef WIN32
367	errno = WSAGetLastError();
368#endif
369	prmsg (1,"SocketINETGetPeerAddr: getpeername() failed: %d\n",
370	    EGET());
371	return -1;
372    }
373
374    /*
375     * Everything looks good: fill in the XtransConnInfo structure.
376     */
377
378    if ((ciptr->peeraddr = malloc (namelen)) == NULL)
379    {
380        prmsg (1,
381	   "SocketINETGetPeerAddr: Can't allocate space for the addr\n");
382        return -1;
383    }
384
385    ciptr->peeraddrlen = namelen;
386    memcpy (ciptr->peeraddr, socknamePtr, ciptr->peeraddrlen);
387
388    return 0;
389}
390
391
392static XtransConnInfo
393TRANS(SocketOpen) (int i, int type)
394
395{
396    XtransConnInfo	ciptr;
397
398    prmsg (3,"SocketOpen(%d,%d)\n", i, type);
399
400    if ((ciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
401    {
402	prmsg (1, "SocketOpen: malloc failed\n");
403	return NULL;
404    }
405
406    ciptr->fd = socket(Sockettrans2devtab[i].family, type,
407                       Sockettrans2devtab[i].protocol);
408
409#ifndef WIN32
410#if (defined(X11_t) && !defined(USE_POLL)) || defined(FS_t) || defined(FONT_t)
411    if (ciptr->fd >= sysconf(_SC_OPEN_MAX))
412    {
413	prmsg (2, "SocketOpen: socket() returned out of range fd %d\n",
414	       ciptr->fd);
415	close (ciptr->fd);
416	ciptr->fd = -1;
417    }
418#endif
419#endif
420
421    if (ciptr->fd < 0) {
422#ifdef WIN32
423	errno = WSAGetLastError();
424#endif
425	prmsg (2, "SocketOpen: socket() failed for %s\n",
426	    Sockettrans2devtab[i].transname);
427
428	free (ciptr);
429	return NULL;
430    }
431
432#ifdef TCP_NODELAY
433    if (Sockettrans2devtab[i].family == AF_INET
434#ifdef IPv6
435      || Sockettrans2devtab[i].family == AF_INET6
436#endif
437    )
438    {
439	/*
440	 * turn off TCP coalescence for INET sockets
441	 */
442
443	int tmp = 1;
444	setsockopt (ciptr->fd, IPPROTO_TCP, TCP_NODELAY,
445	    (char *) &tmp, sizeof (int));
446    }
447#endif
448
449    /*
450     * Some systems provide a really small default buffer size for
451     * UNIX sockets.  Bump it up a bit such that large transfers don't
452     * proceed at glacial speed.
453     */
454#ifdef SO_SNDBUF
455    if (Sockettrans2devtab[i].family == AF_UNIX)
456    {
457	SOCKLEN_T len = sizeof (int);
458	int val;
459
460	if (getsockopt (ciptr->fd, SOL_SOCKET, SO_SNDBUF,
461	    (char *) &val, &len) == 0 && val < 64 * 1024)
462	{
463	    val = 64 * 1024;
464	    setsockopt (ciptr->fd, SOL_SOCKET, SO_SNDBUF,
465	        (char *) &val, sizeof (int));
466	}
467    }
468#endif
469
470    return ciptr;
471}
472
473
474#ifdef TRANS_REOPEN
475
476static XtransConnInfo
477TRANS(SocketReopen) (int i _X_UNUSED, int type, int fd, const char *port)
478
479{
480    XtransConnInfo	ciptr;
481    int portlen;
482    struct sockaddr *addr;
483    size_t addrlen;
484
485    prmsg (3,"SocketReopen(%d,%d,%s)\n", type, fd, port);
486
487    if (port == NULL) {
488      prmsg (1, "SocketReopen: port was null!\n");
489      return NULL;
490    }
491
492    portlen = strlen(port) + 1; // include space for trailing null
493#ifdef SOCK_MAXADDRLEN
494    if (portlen < 0 || portlen > (SOCK_MAXADDRLEN + 2)) {
495      prmsg (1, "SocketReopen: invalid portlen %d\n", portlen);
496      return NULL;
497    }
498    if (portlen < 14) portlen = 14;
499#else
500    if (portlen < 0 || portlen > 14) {
501      prmsg (1, "SocketReopen: invalid portlen %d\n", portlen);
502      return NULL;
503    }
504#endif /*SOCK_MAXADDRLEN*/
505
506    if ((ciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
507    {
508	prmsg (1, "SocketReopen: malloc(ciptr) failed\n");
509	return NULL;
510    }
511
512    ciptr->fd = fd;
513
514    addrlen = portlen + offsetof(struct sockaddr, sa_data);
515    if ((addr = calloc (1, addrlen)) == NULL) {
516	prmsg (1, "SocketReopen: malloc(addr) failed\n");
517	free (ciptr);
518	return NULL;
519    }
520    ciptr->addr = (char *) addr;
521    ciptr->addrlen = addrlen;
522
523    if ((ciptr->peeraddr = calloc (1, addrlen)) == NULL) {
524	prmsg (1, "SocketReopen: malloc(portaddr) failed\n");
525	free (addr);
526	free (ciptr);
527	return NULL;
528    }
529    ciptr->peeraddrlen = addrlen;
530
531    /* Initialize ciptr structure as if it were a normally-opened unix socket */
532    ciptr->flags = TRANS_LOCAL | TRANS_NOUNLINK;
533#ifdef BSD44SOCKETS
534    addr->sa_len = addrlen;
535#endif
536    addr->sa_family = AF_UNIX;
537#if defined(HAVE_STRLCPY) || defined(HAS_STRLCPY)
538    strlcpy(addr->sa_data, port, portlen);
539#else
540    strncpy(addr->sa_data, port, portlen);
541#endif
542    ciptr->family = AF_UNIX;
543    memcpy(ciptr->peeraddr, ciptr->addr, addrlen);
544    ciptr->port = rindex(addr->sa_data, ':');
545    if (ciptr->port == NULL) {
546	if (is_numeric(addr->sa_data)) {
547	    ciptr->port = addr->sa_data;
548	}
549    } else if (ciptr->port[0] == ':') {
550	ciptr->port++;
551    }
552    /* port should now point to portnum or NULL */
553    return ciptr;
554}
555
556#endif /* TRANS_REOPEN */
557
558
559/*
560 * These functions are the interface supplied in the Xtransport structure
561 */
562
563#ifdef TRANS_CLIENT
564
565static XtransConnInfo
566TRANS(SocketOpenCOTSClientBase) (const char *transname, const char *protocol,
567			   const char *host, const char *port, int previndex)
568{
569    XtransConnInfo	ciptr = NULL;
570    int			i = previndex;
571
572    prmsg (2, "SocketOpenCOTSClient(%s,%s,%s)\n",
573	protocol, host, port);
574
575    SocketInitOnce();
576
577    while ((i = TRANS(SocketSelectFamily) (i, transname)) >= 0) {
578	if ((ciptr = TRANS(SocketOpen) (
579		i, Sockettrans2devtab[i].devcotsname)) != NULL) {
580	    /* Save the index for later use */
581
582	    ciptr->index = i;
583	    break;
584	}
585    }
586    if (i < 0) {
587	if (i == -1)
588	    prmsg (1,"SocketOpenCOTSClient: Unable to open socket for %s\n",
589		   transname);
590	else
591	    prmsg (1,"SocketOpenCOTSClient: Unable to determine socket type for %s\n",
592		   transname);
593	return NULL;
594    }
595
596    return ciptr;
597}
598
599static XtransConnInfo
600TRANS(SocketOpenCOTSClient) (Xtransport *thistrans, const char *protocol,
601			     const char *host, const char *port)
602{
603    return TRANS(SocketOpenCOTSClientBase)(
604			thistrans->TransName, protocol, host, port, -1);
605}
606
607
608#endif /* TRANS_CLIENT */
609
610
611#ifdef TRANS_SERVER
612
613static XtransConnInfo
614TRANS(SocketOpenCOTSServer) (Xtransport *thistrans, const char *protocol,
615			     const char *host, const char *port)
616
617{
618    XtransConnInfo	ciptr = NULL;
619    int	i = -1;
620
621    prmsg (2,"SocketOpenCOTSServer(%s,%s,%s)\n", protocol, host, port);
622
623    SocketInitOnce();
624
625    while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
626	if ((ciptr = TRANS(SocketOpen) (
627		 i, Sockettrans2devtab[i].devcotsname)) != NULL)
628	    break;
629    }
630    if (i < 0) {
631	if (i == -1) {
632		if (errno == EAFNOSUPPORT) {
633			thistrans->flags |= TRANS_NOLISTEN;
634			prmsg (1,"SocketOpenCOTSServer: Socket for %s unsupported on this system.\n",
635			       thistrans->TransName);
636		} else {
637			prmsg (1,"SocketOpenCOTSServer: Unable to open socket for %s\n",
638			       thistrans->TransName);
639		}
640	} else {
641	    prmsg (1,"SocketOpenCOTSServer: Unable to determine socket type for %s\n",
642		   thistrans->TransName);
643	}
644	return NULL;
645    }
646
647    /*
648     * Using this prevents the bind() check for an existing server listening
649     * on the same port, but it is required for other reasons.
650     */
651#ifdef SO_REUSEADDR
652
653    /*
654     * SO_REUSEADDR only applied to AF_INET && AF_INET6
655     */
656
657    if (Sockettrans2devtab[i].family == AF_INET
658#ifdef IPv6
659      || Sockettrans2devtab[i].family == AF_INET6
660#endif
661    )
662    {
663	int one = 1;
664	setsockopt (ciptr->fd, SOL_SOCKET, SO_REUSEADDR,
665		    (char *) &one, sizeof (int));
666    }
667#endif
668#ifdef IPV6_V6ONLY
669    if (Sockettrans2devtab[i].family == AF_INET6)
670    {
671	int one = 1;
672	setsockopt(ciptr->fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(int));
673    }
674#endif
675    /* Save the index for later use */
676
677    ciptr->index = i;
678
679    return ciptr;
680}
681
682#endif /* TRANS_SERVER */
683
684
685#ifdef TRANS_REOPEN
686
687static XtransConnInfo
688TRANS(SocketReopenCOTSServer) (Xtransport *thistrans, int fd, const char *port)
689
690{
691    XtransConnInfo	ciptr;
692    int			i = -1;
693
694    prmsg (2,
695	"SocketReopenCOTSServer(%d, %s)\n", fd, port);
696
697    SocketInitOnce();
698
699    while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
700	if ((ciptr = TRANS(SocketReopen) (
701		 i, Sockettrans2devtab[i].devcotsname, fd, port)) != NULL)
702	    break;
703    }
704    if (i < 0) {
705	if (i == -1)
706	    prmsg (1,"SocketReopenCOTSServer: Unable to open socket for %s\n",
707		   thistrans->TransName);
708	else
709	    prmsg (1,"SocketReopenCOTSServer: Unable to determine socket type for %s\n",
710		   thistrans->TransName);
711	return NULL;
712    }
713
714    /* Save the index for later use */
715
716    ciptr->index = i;
717
718    return ciptr;
719}
720
721#endif /* TRANS_REOPEN */
722
723
724static int
725TRANS(SocketSetOption) (XtransConnInfo ciptr, int option, int arg)
726
727{
728    prmsg (2,"SocketSetOption(%d,%d,%d)\n", ciptr->fd, option, arg);
729
730    return -1;
731}
732
733#ifdef UNIXCONN
734static int
735set_sun_path(const char *port, const char *upath, char *path, int abstract)
736{
737    struct sockaddr_un s;
738    ssize_t maxlen = sizeof(s.sun_path) - 1;
739    const char *at = "";
740
741    if (!port || !*port || !path)
742	return -1;
743
744#ifdef HAVE_ABSTRACT_SOCKETS
745    if (port[0] == '@')
746	upath = "";
747    else if (abstract)
748	at = "@";
749#endif
750
751    if (*port == '/') /* a full pathname */
752	upath = "";
753
754    if ((ssize_t)(strlen(at) + strlen(upath) + strlen(port)) > maxlen)
755	return -1;
756    snprintf(path, sizeof(s.sun_path), "%s%s%s", at, upath, port);
757    return 0;
758}
759#endif
760
761#ifdef TRANS_SERVER
762
763static int
764TRANS(SocketCreateListener) (XtransConnInfo ciptr,
765			     struct sockaddr *sockname,
766			     int socknamelen, unsigned int flags)
767
768{
769    SOCKLEN_T namelen = socknamelen;
770    int	fd = ciptr->fd;
771    int	retry;
772
773    prmsg (3, "SocketCreateListener(%p,%d)\n", (void *) ciptr, fd);
774
775    if (Sockettrans2devtab[ciptr->index].family == AF_INET
776#ifdef IPv6
777      || Sockettrans2devtab[ciptr->index].family == AF_INET6
778#endif
779	)
780	retry = 20;
781    else
782	retry = 0;
783
784    while (bind (fd, sockname, namelen) < 0)
785    {
786	if (errno == EADDRINUSE) {
787	    if (flags & ADDR_IN_USE_ALLOWED)
788		break;
789	    else
790		return TRANS_ADDR_IN_USE;
791	}
792
793	if (retry-- == 0) {
794	    prmsg (1, "SocketCreateListener: failed to bind listener\n");
795	    close (fd);
796	    return TRANS_CREATE_LISTENER_FAILED;
797	}
798#ifdef SO_REUSEADDR
799	sleep (1);
800#else
801	sleep (10);
802#endif /* SO_REUSEDADDR */
803    }
804
805    if (Sockettrans2devtab[ciptr->index].family == AF_INET
806#ifdef IPv6
807      || Sockettrans2devtab[ciptr->index].family == AF_INET6
808#endif
809	) {
810#ifdef SO_DONTLINGER
811	setsockopt (fd, SOL_SOCKET, SO_DONTLINGER, (char *) NULL, 0);
812#else
813#ifdef SO_LINGER
814    {
815	static int linger[2] = { 0, 0 };
816	setsockopt (fd, SOL_SOCKET, SO_LINGER,
817		(char *) linger, sizeof (linger));
818    }
819#endif
820#endif
821}
822
823    if (listen (fd, BACKLOG) < 0)
824    {
825	prmsg (1, "SocketCreateListener: listen() failed\n");
826	close (fd);
827	return TRANS_CREATE_LISTENER_FAILED;
828    }
829
830    /* Set a flag to indicate that this connection is a listener */
831
832    ciptr->flags = 1 | (ciptr->flags & TRANS_KEEPFLAGS);
833
834    return 0;
835}
836
837#ifdef TCPCONN
838static int
839TRANS(SocketINETCreateListener) (XtransConnInfo ciptr, const char *port,
840                                 unsigned int flags)
841
842{
843#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
844    struct sockaddr_storage sockname;
845#else
846    struct sockaddr_in	    sockname;
847#endif
848    unsigned short	    sport;
849    SOCKLEN_T	namelen = sizeof(sockname);
850    int		status;
851    long	tmpport;
852#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
853    _Xgetservbynameparams sparams;
854#endif
855    struct servent *servp;
856
857#ifdef X11_t
858    char	portbuf[PORTBUFSIZE];
859#endif
860
861    prmsg (2, "SocketINETCreateListener(%s)\n", port);
862
863#ifdef X11_t
864    /*
865     * X has a well known port, that is transport dependent. It is easier
866     * to handle it here, than try and come up with a transport independent
867     * representation that can be passed in and resolved the usual way.
868     *
869     * The port that is passed here is really a string containing the idisplay
870     * from ConnectDisplay().
871     */
872
873    if (is_numeric (port))
874    {
875	/* fixup the server port address */
876	tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10);
877	snprintf (portbuf, sizeof(portbuf), "%lu", tmpport);
878	port = portbuf;
879    }
880#endif
881
882    if (port && *port)
883    {
884	/* Check to see if the port string is just a number (handles X11) */
885
886	if (!is_numeric (port))
887	{
888	    if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL)
889	    {
890		prmsg (1,
891	     "SocketINETCreateListener: Unable to get service for %s\n",
892		      port);
893		return TRANS_CREATE_LISTENER_FAILED;
894	    }
895	    /* we trust getservbyname to return a valid number */
896	    sport = servp->s_port;
897	}
898	else
899	{
900	    tmpport = strtol (port, (char**)NULL, 10);
901	    /*
902	     * check that somehow the port address isn't negative or in
903	     * the range of reserved port addresses. This can happen and
904	     * be very bad if the server is suid-root and the user does
905	     * something (dumb) like `X :60049`.
906	     */
907	    if (tmpport < 1024 || tmpport > USHRT_MAX)
908		return TRANS_CREATE_LISTENER_FAILED;
909
910	    sport = (unsigned short) tmpport;
911	}
912    }
913    else
914	sport = 0;
915
916    bzero(&sockname, sizeof(sockname));
917    if (Sockettrans2devtab[ciptr->index].family == AF_INET) {
918	namelen = sizeof (struct sockaddr_in);
919#ifdef BSD44SOCKETS
920	((struct sockaddr_in *)&sockname)->sin_len = namelen;
921#endif
922	((struct sockaddr_in *)&sockname)->sin_family = AF_INET;
923	((struct sockaddr_in *)&sockname)->sin_port = htons(sport);
924	((struct sockaddr_in *)&sockname)->sin_addr.s_addr = htonl(INADDR_ANY);
925    } else {
926#ifdef IPv6
927	namelen = sizeof (struct sockaddr_in6);
928#ifdef SIN6_LEN
929	((struct sockaddr_in6 *)&sockname)->sin6_len = sizeof(sockname);
930#endif
931	((struct sockaddr_in6 *)&sockname)->sin6_family = AF_INET6;
932	((struct sockaddr_in6 *)&sockname)->sin6_port = htons(sport);
933	((struct sockaddr_in6 *)&sockname)->sin6_addr = in6addr_any;
934#else
935        prmsg (1,
936               "SocketINETCreateListener: unsupported address family %d\n",
937               Sockettrans2devtab[ciptr->index].family);
938        return TRANS_CREATE_LISTENER_FAILED;
939#endif
940    }
941
942    if ((status = TRANS(SocketCreateListener) (ciptr,
943	(struct sockaddr *) &sockname, namelen, flags)) < 0)
944    {
945	prmsg (1,
946    "SocketINETCreateListener: ...SocketCreateListener() failed\n");
947	return status;
948    }
949
950    if (TRANS(SocketINETGetAddr) (ciptr) < 0)
951    {
952	prmsg (1,
953       "SocketINETCreateListener: ...SocketINETGetAddr() failed\n");
954	return TRANS_CREATE_LISTENER_FAILED;
955    }
956
957    return 0;
958}
959
960#endif /* TCPCONN */
961
962
963#ifdef UNIXCONN
964
965static int
966TRANS(SocketUNIXCreateListener) (XtransConnInfo ciptr, const char *port,
967				 unsigned int flags)
968
969{
970    struct sockaddr_un	sockname;
971    int			namelen;
972    int			oldUmask;
973    int			status;
974    unsigned int	mode;
975    char		tmpport[108];
976
977    int			abstract = 0;
978#ifdef HAVE_ABSTRACT_SOCKETS
979    abstract = ciptr->transptr->flags & TRANS_ABSTRACT;
980#endif
981
982    prmsg (2, "SocketUNIXCreateListener(%s)\n",
983	port ? port : "NULL");
984
985    /* Make sure the directory is created */
986
987    oldUmask = umask (0);
988
989#ifdef UNIX_DIR
990#ifdef HAS_STICKY_DIR_BIT
991    mode = 01777;
992#else
993    mode = 0777;
994#endif
995    if (!abstract && trans_mkdir(UNIX_DIR, mode) == -1) {
996	prmsg (1, "SocketUNIXCreateListener: mkdir(%s) failed, errno = %d\n",
997	       UNIX_DIR, errno);
998	(void) umask (oldUmask);
999	return TRANS_CREATE_LISTENER_FAILED;
1000    }
1001#endif
1002
1003    memset(&sockname, 0, sizeof(sockname));
1004    sockname.sun_family = AF_UNIX;
1005
1006    if (!(port && *port)) {
1007	snprintf (tmpport, sizeof(tmpport), "%s%ld", UNIX_PATH, (long)getpid());
1008	port = tmpport;
1009    }
1010    if (set_sun_path(port, UNIX_PATH, sockname.sun_path, abstract) != 0) {
1011	prmsg (1, "SocketUNIXCreateListener: path too long\n");
1012	return TRANS_CREATE_LISTENER_FAILED;
1013    }
1014
1015#if defined(BSD44SOCKETS)
1016    sockname.sun_len = strlen(sockname.sun_path);
1017#endif
1018
1019#if defined(BSD44SOCKETS) || defined(SUN_LEN)
1020    namelen = SUN_LEN(&sockname);
1021#else
1022    namelen = strlen(sockname.sun_path) + offsetof(struct sockaddr_un, sun_path);
1023#endif
1024
1025    if (abstract) {
1026	sockname.sun_path[0] = '\0';
1027	namelen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&sockname.sun_path[1]);
1028    }
1029    else
1030	unlink (sockname.sun_path);
1031
1032    if ((status = TRANS(SocketCreateListener) (ciptr,
1033	(struct sockaddr *) &sockname, namelen, flags)) < 0)
1034    {
1035	prmsg (1,
1036    "SocketUNIXCreateListener: ...SocketCreateListener() failed\n");
1037	(void) umask (oldUmask);
1038	return status;
1039    }
1040
1041    /*
1042     * Now that the listener is esablished, create the addr info for
1043     * this connection. getpeername() doesn't work for UNIX Domain Sockets
1044     * on some systems (hpux at least), so we will just do it manually, instead
1045     * of calling something like TRANS(SocketUNIXGetAddr).
1046     */
1047
1048    namelen = sizeof (sockname); /* this will always make it the same size */
1049
1050    if ((ciptr->addr = malloc (namelen)) == NULL)
1051    {
1052        prmsg (1,
1053        "SocketUNIXCreateListener: Can't allocate space for the addr\n");
1054	(void) umask (oldUmask);
1055        return TRANS_CREATE_LISTENER_FAILED;
1056    }
1057
1058    if (abstract)
1059	sockname.sun_path[0] = '@';
1060
1061    ciptr->family = sockname.sun_family;
1062    ciptr->addrlen = namelen;
1063    memcpy (ciptr->addr, &sockname, ciptr->addrlen);
1064
1065    (void) umask (oldUmask);
1066
1067    return 0;
1068}
1069
1070
1071static int
1072TRANS(SocketUNIXResetListener) (XtransConnInfo ciptr)
1073
1074{
1075    /*
1076     * See if the unix domain socket has disappeared.  If it has, recreate it.
1077     */
1078
1079    struct sockaddr_un 	*unsock = (struct sockaddr_un *) ciptr->addr;
1080    struct stat		statb;
1081    int 		status = TRANS_RESET_NOOP;
1082    unsigned int	mode;
1083    int abstract = 0;
1084#ifdef HAVE_ABSTRACT_SOCKETS
1085    abstract = ciptr->transptr->flags & TRANS_ABSTRACT;
1086#endif
1087
1088    prmsg (3, "SocketUNIXResetListener(%p,%d)\n", (void *) ciptr, ciptr->fd);
1089
1090    if (!abstract && (
1091	stat (unsock->sun_path, &statb) == -1 ||
1092        ((statb.st_mode & S_IFMT) !=
1093#if !defined(S_IFSOCK)
1094	  		S_IFIFO
1095#else
1096			S_IFSOCK
1097#endif
1098				)))
1099    {
1100	int oldUmask = umask (0);
1101
1102#ifdef UNIX_DIR
1103#ifdef HAS_STICKY_DIR_BIT
1104	mode = 01777;
1105#else
1106	mode = 0777;
1107#endif
1108        if (trans_mkdir(UNIX_DIR, mode) == -1) {
1109            prmsg (1, "SocketUNIXResetListener: mkdir(%s) failed, errno = %d\n",
1110	    UNIX_DIR, errno);
1111	    (void) umask (oldUmask);
1112	    return TRANS_RESET_FAILURE;
1113        }
1114#endif
1115
1116	close (ciptr->fd);
1117	unlink (unsock->sun_path);
1118
1119	if ((ciptr->fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
1120	{
1121	    TRANS(FreeConnInfo) (ciptr);
1122	    (void) umask (oldUmask);
1123	    return TRANS_RESET_FAILURE;
1124	}
1125
1126	if (bind (ciptr->fd, (struct sockaddr *) unsock, ciptr->addrlen) < 0)
1127	{
1128	    close (ciptr->fd);
1129	    TRANS(FreeConnInfo) (ciptr);
1130	    return TRANS_RESET_FAILURE;
1131	}
1132
1133	if (listen (ciptr->fd, BACKLOG) < 0)
1134	{
1135	    close (ciptr->fd);
1136	    TRANS(FreeConnInfo) (ciptr);
1137	    (void) umask (oldUmask);
1138	    return TRANS_RESET_FAILURE;
1139	}
1140
1141	umask (oldUmask);
1142
1143	status = TRANS_RESET_NEW_FD;
1144    }
1145
1146    return status;
1147}
1148
1149#endif /* UNIXCONN */
1150
1151
1152#ifdef TCPCONN
1153
1154static XtransConnInfo
1155TRANS(SocketINETAccept) (XtransConnInfo ciptr, int *status)
1156
1157{
1158    XtransConnInfo	newciptr;
1159    struct sockaddr_in	sockname;
1160    SOCKLEN_T		namelen = sizeof(sockname);
1161
1162    prmsg (2, "SocketINETAccept(%p,%d)\n", (void *) ciptr, ciptr->fd);
1163
1164    if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
1165    {
1166	prmsg (1, "SocketINETAccept: malloc failed\n");
1167	*status = TRANS_ACCEPT_BAD_MALLOC;
1168	return NULL;
1169    }
1170
1171    if ((newciptr->fd = accept (ciptr->fd,
1172	(struct sockaddr *) &sockname, (void *)&namelen)) < 0)
1173    {
1174#ifdef WIN32
1175	errno = WSAGetLastError();
1176#endif
1177	prmsg (1, "SocketINETAccept: accept() failed\n");
1178	free (newciptr);
1179	*status = TRANS_ACCEPT_FAILED;
1180	return NULL;
1181    }
1182
1183#ifdef TCP_NODELAY
1184    {
1185	/*
1186	 * turn off TCP coalescence for INET sockets
1187	 */
1188
1189	int tmp = 1;
1190	setsockopt (newciptr->fd, IPPROTO_TCP, TCP_NODELAY,
1191	    (char *) &tmp, sizeof (int));
1192    }
1193#endif
1194
1195    /*
1196     * Get this address again because the transport may give a more
1197     * specific address now that a connection is established.
1198     */
1199
1200    if (TRANS(SocketINETGetAddr) (newciptr) < 0)
1201    {
1202	prmsg (1,
1203	    "SocketINETAccept: ...SocketINETGetAddr() failed:\n");
1204	close (newciptr->fd);
1205	free (newciptr);
1206	*status = TRANS_ACCEPT_MISC_ERROR;
1207        return NULL;
1208    }
1209
1210    if (TRANS(SocketINETGetPeerAddr) (newciptr) < 0)
1211    {
1212	prmsg (1,
1213	  "SocketINETAccept: ...SocketINETGetPeerAddr() failed:\n");
1214	close (newciptr->fd);
1215	if (newciptr->addr) free (newciptr->addr);
1216	free (newciptr);
1217	*status = TRANS_ACCEPT_MISC_ERROR;
1218        return NULL;
1219    }
1220
1221    *status = 0;
1222
1223    return newciptr;
1224}
1225
1226#endif /* TCPCONN */
1227
1228
1229#ifdef UNIXCONN
1230static XtransConnInfo
1231TRANS(SocketUNIXAccept) (XtransConnInfo ciptr, int *status)
1232
1233{
1234    XtransConnInfo	newciptr;
1235    struct sockaddr_un	sockname;
1236    SOCKLEN_T 		namelen = sizeof sockname;
1237
1238    prmsg (2, "SocketUNIXAccept(%p,%d)\n", (void *) ciptr, ciptr->fd);
1239
1240    if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
1241    {
1242	prmsg (1, "SocketUNIXAccept: malloc() failed\n");
1243	*status = TRANS_ACCEPT_BAD_MALLOC;
1244	return NULL;
1245    }
1246
1247    if ((newciptr->fd = accept (ciptr->fd,
1248	(struct sockaddr *) &sockname, (void *)&namelen)) < 0)
1249    {
1250	prmsg (1, "SocketUNIXAccept: accept() failed\n");
1251	free (newciptr);
1252	*status = TRANS_ACCEPT_FAILED;
1253	return NULL;
1254    }
1255
1256	ciptr->addrlen = namelen;
1257    /*
1258     * Get the socket name and the peer name from the listener socket,
1259     * since this is unix domain.
1260     */
1261
1262    if ((newciptr->addr = malloc (ciptr->addrlen)) == NULL)
1263    {
1264        prmsg (1,
1265        "SocketUNIXAccept: Can't allocate space for the addr\n");
1266	close (newciptr->fd);
1267	free (newciptr);
1268	*status = TRANS_ACCEPT_BAD_MALLOC;
1269        return NULL;
1270    }
1271
1272    /*
1273     * if the socket is abstract, we already modified the address to have a
1274     * @ instead of the initial NUL, so no need to do that again here.
1275     */
1276
1277    newciptr->addrlen = ciptr->addrlen;
1278    memcpy (newciptr->addr, ciptr->addr, newciptr->addrlen);
1279
1280    if ((newciptr->peeraddr = malloc (ciptr->addrlen)) == NULL)
1281    {
1282        prmsg (1,
1283	      "SocketUNIXAccept: Can't allocate space for the addr\n");
1284	close (newciptr->fd);
1285	if (newciptr->addr) free (newciptr->addr);
1286	free (newciptr);
1287	*status = TRANS_ACCEPT_BAD_MALLOC;
1288        return NULL;
1289    }
1290
1291    newciptr->peeraddrlen = ciptr->addrlen;
1292    memcpy (newciptr->peeraddr, ciptr->addr, newciptr->addrlen);
1293
1294    newciptr->family = AF_UNIX;
1295
1296    *status = 0;
1297
1298    return newciptr;
1299}
1300
1301#endif /* UNIXCONN */
1302
1303#endif /* TRANS_SERVER */
1304
1305
1306#ifdef TRANS_CLIENT
1307
1308#ifdef TCPCONN
1309
1310#ifdef HAVE_GETADDRINFO
1311struct addrlist {
1312    struct addrinfo *	addr;
1313    struct addrinfo *	firstaddr;
1314    char 		port[PORTBUFSIZE];
1315    char 		host[MAXHOSTNAMELEN];
1316};
1317static struct addrlist  *addrlist = NULL;
1318#endif
1319
1320
1321static int
1322TRANS(SocketINETConnect) (XtransConnInfo ciptr,
1323                          const char *host, const char *port)
1324
1325{
1326    struct sockaddr *	socketaddr = NULL;
1327    int			socketaddrlen = 0;
1328    int			res;
1329#ifdef HAVE_GETADDRINFO
1330    struct addrinfo 	hints;
1331    char		ntopbuf[INET6_ADDRSTRLEN];
1332    int			resetonce = 0;
1333#else
1334    struct sockaddr_in	sockname;
1335    struct hostent	*hostp;
1336    struct servent	*servp;
1337    unsigned long 	tmpaddr;
1338#endif
1339#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1340    _Xgethostbynameparams hparams;
1341    _Xgetservbynameparams sparams;
1342#endif
1343#ifdef X11_t
1344    char	portbuf[PORTBUFSIZE];
1345#endif
1346
1347    char 		hostnamebuf[256];		/* tmp space */
1348
1349    prmsg (2,"SocketINETConnect(%d,%s,%s)\n", ciptr->fd, host, port);
1350
1351    if (!host)
1352    {
1353	hostnamebuf[0] = '\0';
1354	(void) TRANS(GetHostname) (hostnamebuf, sizeof hostnamebuf);
1355	host = hostnamebuf;
1356    }
1357
1358#ifdef X11_t
1359    /*
1360     * X has a well known port, that is transport dependent. It is easier
1361     * to handle it here, than try and come up with a transport independent
1362     * representation that can be passed in and resolved the usual way.
1363     *
1364     * The port that is passed here is really a string containing the idisplay
1365     * from ConnectDisplay().
1366     */
1367
1368    if (is_numeric (port))
1369    {
1370	long tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10);
1371	snprintf (portbuf, sizeof(portbuf), "%lu", tmpport);
1372	port = portbuf;
1373    }
1374#endif
1375
1376#ifdef HAVE_GETADDRINFO
1377    {
1378	if (addrlist != NULL) {
1379	    if (strcmp(host,addrlist->host) || strcmp(port,addrlist->port)) {
1380		if (addrlist->firstaddr)
1381		    freeaddrinfo(addrlist->firstaddr);
1382		addrlist->firstaddr = NULL;
1383	    }
1384	} else {
1385	    addrlist = malloc(sizeof(struct addrlist));
1386	    if (addrlist == NULL) {
1387		prmsg (1, "SocketINETConnect() can't allocate memory "
1388			"for addrlist: %s\n", strerror(errno));
1389		return TRANS_CONNECT_FAILED;
1390	    }
1391	    addrlist->firstaddr = NULL;
1392	}
1393
1394	if (addrlist->firstaddr == NULL) {
1395	    strncpy(addrlist->port, port, sizeof(addrlist->port));
1396	    addrlist->port[sizeof(addrlist->port) - 1] = '\0';
1397	    strncpy(addrlist->host, host, sizeof(addrlist->host));
1398	    addrlist->host[sizeof(addrlist->host) - 1] = '\0';
1399
1400	    bzero(&hints,sizeof(hints));
1401#ifdef IPv6
1402	    if (strcmp(Sockettrans2devtab[ciptr->index].transname, "tcp") == 0)
1403		hints.ai_family = AF_UNSPEC;
1404	    else
1405#endif
1406		hints.ai_family = Sockettrans2devtab[ciptr->index].family;
1407	    hints.ai_socktype = Sockettrans2devtab[ciptr->index].devcotsname;
1408
1409	    res = getaddrinfo(host,port,&hints,&addrlist->firstaddr);
1410	    if (res != 0) {
1411		prmsg (1, "SocketINETConnect() can't get address "
1412			"for %s:%s: %s\n", host, port, gai_strerror(res));
1413		ESET(EINVAL);
1414		return TRANS_CONNECT_FAILED;
1415	    }
1416	    for (res = 0, addrlist->addr = addrlist->firstaddr;
1417		 addrlist->addr ; res++) {
1418		addrlist->addr = addrlist->addr->ai_next;
1419	    }
1420	    prmsg(4,"Got New Address list with %d addresses\n", res);
1421	    res = 0;
1422	    addrlist->addr = NULL;
1423	}
1424
1425	while (socketaddr == NULL) {
1426	    if (addrlist->addr == NULL) {
1427		if (resetonce) {
1428		    /* Already checked entire list - no usable addresses */
1429		    prmsg (1, "SocketINETConnect() no usable address "
1430			   "for %s:%s\n", host, port);
1431		    return TRANS_CONNECT_FAILED;
1432		} else {
1433		    /* Go back to beginning of list */
1434		    resetonce = 1;
1435		    addrlist->addr = addrlist->firstaddr;
1436		}
1437	    }
1438
1439	    socketaddr = addrlist->addr->ai_addr;
1440	    socketaddrlen = addrlist->addr->ai_addrlen;
1441
1442	    if (addrlist->addr->ai_family == AF_INET) {
1443		struct sockaddr_in *sin = (struct sockaddr_in *) socketaddr;
1444
1445		prmsg (4,"SocketINETConnect() sockname.sin_addr = %s\n",
1446			inet_ntop(addrlist->addr->ai_family,&sin->sin_addr,
1447			ntopbuf,sizeof(ntopbuf)));
1448
1449		prmsg (4,"SocketINETConnect() sockname.sin_port = %d\n",
1450			ntohs(sin->sin_port));
1451
1452#ifdef IPv6
1453		if (Sockettrans2devtab[ciptr->index].family == AF_INET6) {
1454		    if (strcmp(Sockettrans2devtab[ciptr->index].transname,
1455				"tcp") == 0) {
1456			XtransConnInfo newciptr;
1457
1458			/*
1459			 * Our socket is an IPv6 socket, but the address is
1460			 * IPv4.  Close it and get an IPv4 socket.  This is
1461			 * needed for IPv4 connections to work on platforms
1462			 * that don't allow IPv4 over IPv6 sockets.
1463			 */
1464			TRANS(SocketINETClose)(ciptr);
1465			newciptr = TRANS(SocketOpenCOTSClientBase)(
1466					"tcp", "tcp", host, port, ciptr->index);
1467			if (newciptr)
1468			    ciptr->fd = newciptr->fd;
1469			if (!newciptr ||
1470			    Sockettrans2devtab[newciptr->index].family !=
1471				AF_INET) {
1472			    socketaddr = NULL;
1473			    prmsg (4,"SocketINETConnect() Cannot get IPv4 "
1474					" socketfor IPv4 address\n");
1475			}
1476			if (newciptr)
1477			    free(newciptr);
1478		    } else {
1479			socketaddr = NULL;
1480			prmsg (4,"SocketINETConnect Skipping IPv4 address\n");
1481		    }
1482		}
1483	    } else if (addrlist->addr->ai_family == AF_INET6) {
1484		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) socketaddr;
1485
1486		prmsg (4,"SocketINETConnect() sockname.sin6_addr = %s\n",
1487			inet_ntop(addrlist->addr->ai_family,
1488				  &sin6->sin6_addr,ntopbuf,sizeof(ntopbuf)));
1489		prmsg (4,"SocketINETConnect() sockname.sin6_port = %d\n",
1490			ntohs(sin6->sin6_port));
1491
1492		if (Sockettrans2devtab[ciptr->index].family == AF_INET) {
1493		    if (strcmp(Sockettrans2devtab[ciptr->index].transname,
1494				"tcp") == 0) {
1495			XtransConnInfo newciptr;
1496
1497			/*
1498			 * Close the IPv4 socket and try to open an IPv6 socket.
1499			 */
1500			TRANS(SocketINETClose)(ciptr);
1501			newciptr = TRANS(SocketOpenCOTSClientBase)(
1502					"tcp", "tcp", host, port, -1);
1503			if (newciptr)
1504			    ciptr->fd = newciptr->fd;
1505			if (!newciptr ||
1506			    Sockettrans2devtab[newciptr->index].family !=
1507					AF_INET6) {
1508			    socketaddr = NULL;
1509			    prmsg (4,"SocketINETConnect() Cannot get IPv6 "
1510				   "socket for IPv6 address\n");
1511			}
1512			if (newciptr)
1513			    free(newciptr);
1514		    }
1515		    else
1516		    {
1517			socketaddr = NULL;
1518			prmsg (4,"SocketINETConnect() Skipping IPv6 address\n");
1519		    }
1520		}
1521#endif /* IPv6 */
1522	    } else {
1523		socketaddr = NULL; /* Unsupported address type */
1524	    }
1525	    if (socketaddr == NULL) {
1526		addrlist->addr = addrlist->addr->ai_next;
1527	    }
1528	}
1529    }
1530#else /* !HAVE_GETADDRINFO */
1531    {
1532	/*
1533	 * Build the socket name.
1534	 */
1535
1536#ifdef BSD44SOCKETS
1537	sockname.sin_len = sizeof (struct sockaddr_in);
1538#endif
1539	sockname.sin_family = AF_INET;
1540
1541	/*
1542	 * fill in sin_addr
1543	 */
1544
1545#ifndef INADDR_NONE
1546#define INADDR_NONE ((in_addr_t) 0xffffffff)
1547#endif
1548
1549	/* check for ww.xx.yy.zz host string */
1550
1551	if (isascii (host[0]) && isdigit (host[0])) {
1552	    tmpaddr = inet_addr (host); /* returns network byte order */
1553	} else {
1554	    tmpaddr = INADDR_NONE;
1555	}
1556
1557	prmsg (4,"SocketINETConnect() inet_addr(%s) = %lx\n", host, tmpaddr);
1558
1559	if (tmpaddr == INADDR_NONE) {
1560	    if ((hostp = _XGethostbyname(host,hparams)) == NULL) {
1561		prmsg (1,"SocketINETConnect: Can't get address for %s\n",
1562			host);
1563		ESET(EINVAL);
1564		return TRANS_CONNECT_FAILED;
1565	    }
1566	    if (hostp->h_addrtype != AF_INET) {  /* is IP host? */
1567		prmsg (1,"SocketINETConnect: not INET host%s\n", host);
1568		ESET(EPROTOTYPE);
1569		return TRANS_CONNECT_FAILED;
1570	    }
1571
1572	    memcpy ((char *) &sockname.sin_addr, (char *) hostp->h_addr,
1573		    sizeof (sockname.sin_addr));
1574
1575	} else {
1576	    sockname.sin_addr.s_addr = tmpaddr;
1577        }
1578
1579	/*
1580	 * fill in sin_port
1581	 */
1582
1583	/* Check for number in the port string */
1584
1585	if (!is_numeric (port)) {
1586	    if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL) {
1587		prmsg (1,"SocketINETConnect: can't get service for %s\n",
1588			port);
1589		return TRANS_CONNECT_FAILED;
1590	    }
1591	    sockname.sin_port = htons (servp->s_port);
1592	} else {
1593	    long tmpport = strtol (port, (char**)NULL, 10);
1594	    if (tmpport < 1024 || tmpport > USHRT_MAX)
1595		return TRANS_CONNECT_FAILED;
1596	    sockname.sin_port = htons (((unsigned short) tmpport));
1597	}
1598
1599	prmsg (4,"SocketINETConnect: sockname.sin_port = %d\n",
1600		ntohs(sockname.sin_port));
1601	socketaddr = (struct sockaddr *) &sockname;
1602	socketaddrlen = sizeof(sockname);
1603    }
1604#endif
1605
1606    /*
1607     * Turn on socket keepalive so the client process will eventually
1608     * be notified with a SIGPIPE signal if the display server fails
1609     * to respond to a periodic transmission of messages
1610     * on the connected socket.
1611     * This is useful to avoid hung application processes when the
1612     * processes are not spawned from the xdm session and
1613     * the display server terminates abnormally.
1614     * (Someone turned off the power switch.)
1615     */
1616
1617    {
1618	int tmp = 1;
1619	setsockopt (ciptr->fd, SOL_SOCKET, SO_KEEPALIVE,
1620		(char *) &tmp, sizeof (int));
1621    }
1622
1623    /*
1624     * Do the connect()
1625     */
1626
1627    if (connect (ciptr->fd, socketaddr, socketaddrlen ) < 0)
1628    {
1629#ifdef WIN32
1630	int olderrno = WSAGetLastError();
1631#else
1632	int olderrno = errno;
1633#endif
1634
1635	/*
1636	 * If the error was ECONNREFUSED, the server may be overloaded
1637	 * and we should try again.
1638	 *
1639	 * If the error was EWOULDBLOCK or EINPROGRESS then the socket
1640	 * was non-blocking and we should poll using select
1641	 *
1642	 * If the error was EINTR, the connect was interrupted and we
1643	 * should try again.
1644	 *
1645	 * If multiple addresses are found for a host then we should
1646	 * try to connect again with a different address for a larger
1647	 * number of errors that made us quit before, since those
1648	 * could be caused by trying to use an IPv6 address to contact
1649	 * a machine with an IPv4-only server or other reasons that
1650	 * only affect one of a set of addresses.
1651	 */
1652
1653	if (olderrno == ECONNREFUSED || olderrno == EINTR
1654#ifdef HAVE_GETADDRINFO
1655	  || (((addrlist->addr->ai_next != NULL) ||
1656	        (addrlist->addr != addrlist->firstaddr)) &&
1657               (olderrno == ENETUNREACH || olderrno == EAFNOSUPPORT ||
1658		 olderrno == EADDRNOTAVAIL || olderrno == ETIMEDOUT
1659#if defined(EHOSTDOWN)
1660		   || olderrno == EHOSTDOWN
1661#endif
1662	       ))
1663#endif
1664	    )
1665	    res = TRANS_TRY_CONNECT_AGAIN;
1666	else if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS)
1667	    res = TRANS_IN_PROGRESS;
1668	else
1669	{
1670	    prmsg (2,"SocketINETConnect: Can't connect: errno = %d\n",
1671		   olderrno);
1672
1673	    res = TRANS_CONNECT_FAILED;
1674	}
1675    } else {
1676	res = 0;
1677
1678
1679	/*
1680	 * Sync up the address fields of ciptr.
1681	 */
1682
1683	if (TRANS(SocketINETGetAddr) (ciptr) < 0)
1684	{
1685	    prmsg (1,
1686	     "SocketINETConnect: ...SocketINETGetAddr() failed:\n");
1687	    res = TRANS_CONNECT_FAILED;
1688	}
1689
1690	else if (TRANS(SocketINETGetPeerAddr) (ciptr) < 0)
1691	{
1692	    prmsg (1,
1693	      "SocketINETConnect: ...SocketINETGetPeerAddr() failed:\n");
1694	    res = TRANS_CONNECT_FAILED;
1695	}
1696    }
1697
1698#ifdef HAVE_GETADDRINFO
1699   if (res != 0) {
1700	addrlist->addr = addrlist->addr->ai_next;
1701   }
1702#endif
1703
1704    return res;
1705}
1706
1707#endif /* TCPCONN */
1708
1709
1710
1711#ifdef UNIXCONN
1712
1713/*
1714 * Make sure 'host' is really local.
1715 */
1716
1717static int
1718UnixHostReallyLocal (const char *host)
1719
1720{
1721    char hostnamebuf[256];
1722
1723    TRANS(GetHostname) (hostnamebuf, sizeof (hostnamebuf));
1724
1725    if (strcmp (hostnamebuf, host) == 0)
1726    {
1727	return (1);
1728    } else {
1729#ifdef HAVE_GETADDRINFO
1730	struct addrinfo *localhostaddr;
1731	struct addrinfo *otherhostaddr;
1732	struct addrinfo *i, *j;
1733	int equiv = 0;
1734
1735	if (getaddrinfo(hostnamebuf, NULL, NULL, &localhostaddr) != 0)
1736	    return 0;
1737	if (getaddrinfo(host, NULL, NULL, &otherhostaddr) != 0) {
1738	    freeaddrinfo(localhostaddr);
1739	    return 0;
1740	}
1741
1742	for (i = localhostaddr; i != NULL && equiv == 0; i = i->ai_next) {
1743	    for (j = otherhostaddr; j != NULL && equiv == 0; j = j->ai_next) {
1744		if (i->ai_family == j->ai_family) {
1745		    if (i->ai_family == AF_INET) {
1746			struct sockaddr_in *sinA
1747			  = (struct sockaddr_in *) i->ai_addr;
1748			struct sockaddr_in *sinB
1749			  = (struct sockaddr_in *) j->ai_addr;
1750			struct in_addr *A = &sinA->sin_addr;
1751			struct in_addr *B = &sinB->sin_addr;
1752
1753			if (memcmp(A,B,sizeof(struct in_addr)) == 0) {
1754			    equiv = 1;
1755			}
1756#ifdef IPv6
1757		    } else if (i->ai_family == AF_INET6) {
1758			struct sockaddr_in6 *sinA
1759			  = (struct sockaddr_in6 *) i->ai_addr;
1760			struct sockaddr_in6 *sinB
1761			  = (struct sockaddr_in6 *) j->ai_addr;
1762			struct in6_addr *A = &sinA->sin6_addr;
1763			struct in6_addr *B = &sinB->sin6_addr;
1764
1765			if (memcmp(A,B,sizeof(struct in6_addr)) == 0) {
1766			    equiv = 1;
1767			}
1768#endif /* IPv6 */
1769		    }
1770		}
1771	    }
1772	}
1773
1774	freeaddrinfo(localhostaddr);
1775	freeaddrinfo(otherhostaddr);
1776	return equiv;
1777#else /* !HAVE_GETADDRINFO */
1778	/*
1779	 * A host may have more than one network address.  If any of the
1780	 * network addresses of 'host' (specified to the connect call)
1781	 * match any of the network addresses of 'hostname' (determined
1782	 * by TRANS(GetHostname)), then the two hostnames are equivalent,
1783	 * and we know that 'host' is really a local host.
1784	 */
1785	char specified_local_addr_list[10][4];
1786	int scount, equiv, i, j;
1787#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1788	_Xgethostbynameparams hparams;
1789#endif
1790	struct hostent *hostp;
1791
1792	if ((hostp = _XGethostbyname (host,hparams)) == NULL)
1793	    return (0);
1794
1795	scount = 0;
1796	while (hostp->h_addr_list[scount] && scount <= 8)
1797	{
1798	    /*
1799	     * The 2nd call to gethostname() overrides the data
1800	     * from the 1st call, so we must save the address list.
1801	     */
1802
1803	    specified_local_addr_list[scount][0] =
1804				hostp->h_addr_list[scount][0];
1805	    specified_local_addr_list[scount][1] =
1806				hostp->h_addr_list[scount][1];
1807	    specified_local_addr_list[scount][2] =
1808				hostp->h_addr_list[scount][2];
1809	    specified_local_addr_list[scount][3] =
1810				hostp->h_addr_list[scount][3];
1811	    scount++;
1812	}
1813	if ((hostp = _XGethostbyname (hostnamebuf,hparams)) == NULL)
1814	    return (0);
1815
1816	equiv = 0;
1817	i = 0;
1818
1819	while (i < scount && !equiv)
1820	{
1821	    j = 0;
1822
1823	    while (hostp->h_addr_list[j])
1824	    {
1825		if ((specified_local_addr_list[i][0] ==
1826					hostp->h_addr_list[j][0]) &&
1827		    (specified_local_addr_list[i][1] ==
1828					hostp->h_addr_list[j][1]) &&
1829		    (specified_local_addr_list[i][2] ==
1830					hostp->h_addr_list[j][2]) &&
1831		    (specified_local_addr_list[i][3] ==
1832					hostp->h_addr_list[j][3]))
1833		{
1834		    /* They're equal, so we're done */
1835
1836		    equiv = 1;
1837		    break;
1838		}
1839
1840		j++;
1841	    }
1842
1843	    i++;
1844	}
1845	return (equiv);
1846#endif
1847    }
1848}
1849
1850static int
1851TRANS(SocketUNIXConnect) (XtransConnInfo ciptr,
1852                          const char *host, const char *port)
1853
1854{
1855    struct sockaddr_un	sockname;
1856    SOCKLEN_T		namelen;
1857
1858    prmsg (2,"SocketUNIXConnect(%d,%s,%s)\n", ciptr->fd, host, port);
1859
1860    /*
1861     * Make sure 'host' is really local.  If not, we return failure.
1862     * The reason we make this check is because a process may advertise
1863     * a "local" network ID for which it can accept connections, but if
1864     * a process on a remote machine tries to connect to this network ID,
1865     * we know for sure it will fail.
1866     */
1867
1868    if (host && *host && host[0]!='/' && strcmp (host, "unix") != 0 && !UnixHostReallyLocal (host))
1869    {
1870	prmsg (1,
1871	   "SocketUNIXConnect: Cannot connect to non-local host %s\n",
1872	       host);
1873	return TRANS_CONNECT_FAILED;
1874    }
1875
1876
1877    /*
1878     * Check the port.
1879     */
1880
1881    if (!port || !*port)
1882    {
1883	prmsg (1,"SocketUNIXConnect: Missing port specification\n");
1884	return TRANS_CONNECT_FAILED;
1885    }
1886
1887    /*
1888     * Build the socket name.
1889     */
1890
1891    sockname.sun_family = AF_UNIX;
1892
1893    if (set_sun_path(port, UNIX_PATH, sockname.sun_path, 0) != 0) {
1894	prmsg (1, "SocketUNIXConnect: path too long\n");
1895	return TRANS_CONNECT_FAILED;
1896    }
1897
1898#if defined(BSD44SOCKETS)
1899    sockname.sun_len = strlen (sockname.sun_path);
1900#endif
1901
1902#if defined(BSD44SOCKETS) || defined(SUN_LEN)
1903    namelen = SUN_LEN (&sockname);
1904#else
1905    namelen = strlen (sockname.sun_path) + offsetof(struct sockaddr_un, sun_path);
1906#endif
1907
1908
1909    /*
1910     * Do the connect()
1911     */
1912
1913    if (connect (ciptr->fd, (struct sockaddr *) &sockname, namelen) < 0)
1914    {
1915	int olderrno = errno;
1916	int connected = 0;
1917
1918	if (!connected)
1919	{
1920	    errno = olderrno;
1921
1922	    /*
1923	     * If the error was ENOENT, the server may be starting up; we used
1924	     * to suggest to try again in this case with
1925	     * TRANS_TRY_CONNECT_AGAIN, but this introduced problems for
1926	     * processes still referencing stale sockets in their environment.
1927	     * Hence, we now return a hard error, TRANS_CONNECT_FAILED, and it
1928	     * is suggested that higher level stacks handle retries on their
1929	     * level when they face a slow starting server.
1930	     *
1931	     * If the error was EWOULDBLOCK or EINPROGRESS then the socket
1932	     * was non-blocking and we should poll using select
1933	     *
1934	     * If the error was EINTR, the connect was interrupted and we
1935	     * should try again.
1936	     */
1937
1938	    if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS)
1939		return TRANS_IN_PROGRESS;
1940	    else if (olderrno == EINTR)
1941		return TRANS_TRY_CONNECT_AGAIN;
1942	    else {
1943		prmsg (2,"SocketUNIXConnect: Can't connect: errno = %d\n",
1944		       EGET());
1945
1946		return TRANS_CONNECT_FAILED;
1947	    }
1948	}
1949    }
1950
1951    /*
1952     * Get the socket name and the peer name from the connect socket,
1953     * since this is unix domain.
1954     */
1955
1956    if ((ciptr->addr = malloc(namelen)) == NULL ||
1957       (ciptr->peeraddr = malloc(namelen)) == NULL)
1958    {
1959        prmsg (1,
1960	"SocketUNIXCreateListener: Can't allocate space for the addr\n");
1961        return TRANS_CONNECT_FAILED;
1962    }
1963
1964    ciptr->family = AF_UNIX;
1965    ciptr->addrlen = namelen;
1966    ciptr->peeraddrlen = namelen;
1967    memcpy (ciptr->addr, &sockname, ciptr->addrlen);
1968    memcpy (ciptr->peeraddr, &sockname, ciptr->peeraddrlen);
1969
1970    return 0;
1971}
1972
1973#endif /* UNIXCONN */
1974
1975#endif /* TRANS_CLIENT */
1976
1977
1978static int
1979TRANS(SocketBytesReadable) (XtransConnInfo ciptr, BytesReadable_t *pend)
1980
1981{
1982    prmsg (2,"SocketBytesReadable(%p,%d,%p)\n",
1983	(void *) ciptr, ciptr->fd, (void *) pend);
1984#ifdef WIN32
1985    {
1986	int ret = ioctlsocket ((SOCKET) ciptr->fd, FIONREAD, (u_long *) pend);
1987	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
1988	return ret;
1989    }
1990#else
1991    return ioctl (ciptr->fd, FIONREAD, (char *) pend);
1992#endif /* WIN32 */
1993}
1994
1995#if XTRANS_SEND_FDS
1996
1997static void
1998appendFd(struct _XtransConnFd **prev, int fd, int do_close)
1999{
2000    struct _XtransConnFd *cf, *new;
2001
2002    new = malloc (sizeof (struct _XtransConnFd));
2003    if (!new) {
2004        /* XXX mark connection as broken */
2005        close(fd);
2006        return;
2007    }
2008    new->next = 0;
2009    new->fd = fd;
2010    new->do_close = do_close;
2011    /* search to end of list */
2012    for (; (cf = *prev); prev = &(cf->next));
2013    *prev = new;
2014}
2015
2016static int
2017removeFd(struct _XtransConnFd **prev)
2018{
2019    struct _XtransConnFd *cf;
2020    int fd;
2021
2022    if ((cf = *prev)) {
2023        *prev = cf->next;
2024        fd = cf->fd;
2025        free(cf);
2026    } else
2027        fd = -1;
2028    return fd;
2029}
2030
2031static void
2032discardFd(struct _XtransConnFd **prev, struct _XtransConnFd *upto, int do_close)
2033{
2034    struct _XtransConnFd *cf, *next;
2035
2036    for (cf = *prev; cf != upto; cf = next) {
2037        next = cf->next;
2038        if (do_close || cf->do_close)
2039            close(cf->fd);
2040        free(cf);
2041    }
2042    *prev = upto;
2043}
2044
2045static void
2046cleanupFds(XtransConnInfo ciptr)
2047{
2048    /* Clean up the send list but don't close the fds */
2049    discardFd(&ciptr->send_fds, NULL, 0);
2050    /* Clean up the recv list and *do* close the fds */
2051    discardFd(&ciptr->recv_fds, NULL, 1);
2052}
2053
2054static int
2055nFd(struct _XtransConnFd **prev)
2056{
2057    struct _XtransConnFd *cf;
2058    int n = 0;
2059
2060    for (cf = *prev; cf; cf = cf->next)
2061        n++;
2062    return n;
2063}
2064
2065static int
2066TRANS(SocketRecvFd) (XtransConnInfo ciptr)
2067{
2068    prmsg (2, "SocketRecvFd(%d)\n", ciptr->fd);
2069    return removeFd(&ciptr->recv_fds);
2070}
2071
2072static int
2073TRANS(SocketSendFd) (XtransConnInfo ciptr, int fd, int do_close)
2074{
2075    appendFd(&ciptr->send_fds, fd, do_close);
2076    return 0;
2077}
2078
2079static int
2080TRANS(SocketRecvFdInvalid)(XtransConnInfo ciptr)
2081{
2082    errno = EINVAL;
2083    return -1;
2084}
2085
2086static int
2087TRANS(SocketSendFdInvalid)(XtransConnInfo ciptr, int fd, int do_close)
2088{
2089    errno = EINVAL;
2090    return -1;
2091}
2092
2093#define MAX_FDS		128
2094
2095union fd_pass {
2096	struct cmsghdr	cmsghdr;
2097	char		buf[CMSG_SPACE(MAX_FDS * sizeof(int))];
2098};
2099
2100#endif /* XTRANS_SEND_FDS */
2101
2102static int
2103TRANS(SocketRead) (XtransConnInfo ciptr, char *buf, int size)
2104
2105{
2106    prmsg (2,"SocketRead(%d,%p,%d)\n", ciptr->fd, (void *) buf, size);
2107
2108#if defined(WIN32)
2109    {
2110	int ret = recv ((SOCKET)ciptr->fd, buf, size, 0);
2111#ifdef WIN32
2112	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
2113#endif
2114	return ret;
2115    }
2116#else
2117#if XTRANS_SEND_FDS
2118    {
2119        struct iovec    iov = {
2120            .iov_base = buf,
2121            .iov_len = size
2122        };
2123        union fd_pass   cmsgbuf;
2124        struct msghdr   msg = {
2125            .msg_name = NULL,
2126            .msg_namelen = 0,
2127            .msg_iov = &iov,
2128            .msg_iovlen = 1,
2129            .msg_control = cmsgbuf.buf,
2130            .msg_controllen = CMSG_LEN(MAX_FDS * sizeof(int))
2131        };
2132
2133        size = recvmsg(ciptr->fd, &msg, 0);
2134        if (size >= 0) {
2135            struct cmsghdr *hdr;
2136
2137            for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) {
2138                if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) {
2139                    int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int);
2140                    int i;
2141                    int *fd = (int *) CMSG_DATA(hdr);
2142
2143                    for (i = 0; i < nfd; i++)
2144                        appendFd(&ciptr->recv_fds, fd[i], 0);
2145                }
2146            }
2147        }
2148        return size;
2149    }
2150#else
2151    return read(ciptr->fd, buf, size);
2152#endif /* XTRANS_SEND_FDS */
2153#endif /* WIN32 */
2154}
2155
2156static int
2157TRANS(SocketReadv) (XtransConnInfo ciptr, struct iovec *buf, int size)
2158
2159{
2160    prmsg (2,"SocketReadv(%d,%p,%d)\n", ciptr->fd, (void *) buf, size);
2161
2162#if XTRANS_SEND_FDS
2163    {
2164        union fd_pass   cmsgbuf;
2165        struct msghdr   msg = {
2166            .msg_name = NULL,
2167            .msg_namelen = 0,
2168            .msg_iov = buf,
2169            .msg_iovlen = size,
2170            .msg_control = cmsgbuf.buf,
2171            .msg_controllen = CMSG_LEN(MAX_FDS * sizeof(int))
2172        };
2173
2174        size = recvmsg(ciptr->fd, &msg, 0);
2175        if (size >= 0) {
2176            struct cmsghdr *hdr;
2177
2178            for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) {
2179                if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) {
2180                    int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int);
2181                    int i;
2182                    int *fd = (int *) CMSG_DATA(hdr);
2183
2184                    for (i = 0; i < nfd; i++)
2185                        appendFd(&ciptr->recv_fds, fd[i], 0);
2186                }
2187            }
2188        }
2189        return size;
2190    }
2191#else
2192    return READV (ciptr, buf, size);
2193#endif
2194}
2195
2196
2197static int
2198TRANS(SocketWritev) (XtransConnInfo ciptr, struct iovec *buf, int size)
2199
2200{
2201    prmsg (2,"SocketWritev(%d,%p,%d)\n", ciptr->fd, (void *) buf, size);
2202
2203#if XTRANS_SEND_FDS
2204    if (ciptr->send_fds)
2205    {
2206        union fd_pass           cmsgbuf;
2207        int                     nfd = nFd(&ciptr->send_fds);
2208        struct _XtransConnFd    *cf = ciptr->send_fds;
2209        struct msghdr           msg = {
2210            .msg_name = NULL,
2211            .msg_namelen = 0,
2212            .msg_iov = buf,
2213            .msg_iovlen = size,
2214            .msg_control = cmsgbuf.buf,
2215            .msg_controllen = CMSG_LEN(nfd * sizeof(int))
2216        };
2217        struct cmsghdr          *hdr = CMSG_FIRSTHDR(&msg);
2218        int                     i;
2219        int                     *fds;
2220
2221        hdr->cmsg_len = msg.msg_controllen;
2222        hdr->cmsg_level = SOL_SOCKET;
2223        hdr->cmsg_type = SCM_RIGHTS;
2224
2225        fds = (int *) CMSG_DATA(hdr);
2226        /* Set up fds */
2227        for (i = 0; i < nfd; i++) {
2228            fds[i] = cf->fd;
2229            cf = cf->next;
2230        }
2231
2232        i = sendmsg(ciptr->fd, &msg, 0);
2233        if (i > 0)
2234            discardFd(&ciptr->send_fds, cf, 0);
2235        return i;
2236    }
2237#endif
2238    return WRITEV (ciptr, buf, size);
2239}
2240
2241
2242static int
2243TRANS(SocketWrite) (XtransConnInfo ciptr, const char *buf, int size)
2244
2245{
2246    prmsg (2,"SocketWrite(%d,%p,%d)\n", ciptr->fd, (const void *) buf, size);
2247
2248#if defined(WIN32)
2249    {
2250	int ret = send ((SOCKET)ciptr->fd, buf, size, 0);
2251#ifdef WIN32
2252	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
2253#endif
2254	return ret;
2255    }
2256#else
2257#if XTRANS_SEND_FDS
2258    if (ciptr->send_fds)
2259    {
2260        struct iovec            iov;
2261
2262        iov.iov_base = (void *) buf;
2263        iov.iov_len = size;
2264        return TRANS(SocketWritev)(ciptr, &iov, 1);
2265    }
2266#endif /* XTRANS_SEND_FDS */
2267    return write (ciptr->fd, buf, size);
2268#endif /* WIN32 */
2269}
2270
2271static int
2272TRANS(SocketDisconnect) (XtransConnInfo ciptr)
2273
2274{
2275    prmsg (2,"SocketDisconnect(%p,%d)\n", (void *) ciptr, ciptr->fd);
2276
2277#ifdef WIN32
2278    {
2279	int ret = shutdown (ciptr->fd, 2);
2280	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
2281	return ret;
2282    }
2283#else
2284    return shutdown (ciptr->fd, 2); /* disallow further sends and receives */
2285#endif
2286}
2287
2288
2289#ifdef TCPCONN
2290static int
2291TRANS(SocketINETClose) (XtransConnInfo ciptr)
2292
2293{
2294    prmsg (2,"SocketINETClose(%p,%d)\n", (void *) ciptr, ciptr->fd);
2295
2296#ifdef WIN32
2297    {
2298	int ret = close (ciptr->fd);
2299	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
2300	return ret;
2301    }
2302#else
2303    return close (ciptr->fd);
2304#endif
2305}
2306
2307#endif /* TCPCONN */
2308
2309
2310#ifdef UNIXCONN
2311static int
2312TRANS(SocketUNIXClose) (XtransConnInfo ciptr)
2313{
2314    /*
2315     * If this is the server side, then once the socket is closed,
2316     * it must be unlinked to completely close it
2317     */
2318
2319    struct sockaddr_un	*sockname = (struct sockaddr_un *) ciptr->addr;
2320    int ret;
2321
2322    prmsg (2,"SocketUNIXClose(%p,%d)\n", (void *) ciptr, ciptr->fd);
2323
2324#if XTRANS_SEND_FDS
2325    cleanupFds(ciptr);
2326#endif
2327    ret = close(ciptr->fd);
2328
2329    if (ciptr->flags
2330       && sockname
2331       && sockname->sun_family == AF_UNIX
2332       && sockname->sun_path[0])
2333    {
2334	if (!(ciptr->flags & TRANS_NOUNLINK
2335	    || ciptr->transptr->flags & TRANS_ABSTRACT))
2336		unlink (sockname->sun_path);
2337    }
2338
2339    return ret;
2340}
2341
2342static int
2343TRANS(SocketUNIXCloseForCloning) (XtransConnInfo ciptr)
2344
2345{
2346    /*
2347     * Don't unlink path.
2348     */
2349
2350    int ret;
2351
2352    prmsg (2,"SocketUNIXCloseForCloning(%p,%d)\n",
2353	(void *) ciptr, ciptr->fd);
2354
2355#if XTRANS_SEND_FDS
2356    cleanupFds(ciptr);
2357#endif
2358    ret = close(ciptr->fd);
2359
2360    return ret;
2361}
2362
2363#endif /* UNIXCONN */
2364
2365
2366#ifdef TCPCONN
2367# ifdef TRANS_SERVER
2368static const char* tcp_nolisten[] = {
2369	"inet",
2370#ifdef IPv6
2371	"inet6",
2372#endif
2373	NULL
2374};
2375# endif
2376
2377static Xtransport	TRANS(SocketTCPFuncs) = {
2378	/* Socket Interface */
2379	"tcp",
2380        TRANS_ALIAS,
2381#ifdef TRANS_CLIENT
2382	TRANS(SocketOpenCOTSClient),
2383#endif /* TRANS_CLIENT */
2384#ifdef TRANS_SERVER
2385	tcp_nolisten,
2386	TRANS(SocketOpenCOTSServer),
2387#endif /* TRANS_SERVER */
2388#ifdef TRANS_REOPEN
2389	TRANS(SocketReopenCOTSServer),
2390#endif
2391	TRANS(SocketSetOption),
2392#ifdef TRANS_SERVER
2393	TRANS(SocketINETCreateListener),
2394	NULL,		       			/* ResetListener */
2395	TRANS(SocketINETAccept),
2396#endif /* TRANS_SERVER */
2397#ifdef TRANS_CLIENT
2398	TRANS(SocketINETConnect),
2399#endif /* TRANS_CLIENT */
2400	TRANS(SocketBytesReadable),
2401	TRANS(SocketRead),
2402	TRANS(SocketWrite),
2403	TRANS(SocketReadv),
2404	TRANS(SocketWritev),
2405#if XTRANS_SEND_FDS
2406        TRANS(SocketSendFdInvalid),
2407        TRANS(SocketRecvFdInvalid),
2408#endif
2409	TRANS(SocketDisconnect),
2410	TRANS(SocketINETClose),
2411	TRANS(SocketINETClose),
2412	};
2413
2414static Xtransport	TRANS(SocketINETFuncs) = {
2415	/* Socket Interface */
2416	"inet",
2417	0,
2418#ifdef TRANS_CLIENT
2419	TRANS(SocketOpenCOTSClient),
2420#endif /* TRANS_CLIENT */
2421#ifdef TRANS_SERVER
2422	NULL,
2423	TRANS(SocketOpenCOTSServer),
2424#endif /* TRANS_SERVER */
2425#ifdef TRANS_REOPEN
2426	TRANS(SocketReopenCOTSServer),
2427#endif
2428	TRANS(SocketSetOption),
2429#ifdef TRANS_SERVER
2430	TRANS(SocketINETCreateListener),
2431	NULL,		       			/* ResetListener */
2432	TRANS(SocketINETAccept),
2433#endif /* TRANS_SERVER */
2434#ifdef TRANS_CLIENT
2435	TRANS(SocketINETConnect),
2436#endif /* TRANS_CLIENT */
2437	TRANS(SocketBytesReadable),
2438	TRANS(SocketRead),
2439	TRANS(SocketWrite),
2440	TRANS(SocketReadv),
2441	TRANS(SocketWritev),
2442#if XTRANS_SEND_FDS
2443        TRANS(SocketSendFdInvalid),
2444        TRANS(SocketRecvFdInvalid),
2445#endif
2446	TRANS(SocketDisconnect),
2447	TRANS(SocketINETClose),
2448	TRANS(SocketINETClose),
2449	};
2450
2451#ifdef IPv6
2452static Xtransport     TRANS(SocketINET6Funcs) = {
2453	/* Socket Interface */
2454	"inet6",
2455	0,
2456#ifdef TRANS_CLIENT
2457	TRANS(SocketOpenCOTSClient),
2458#endif /* TRANS_CLIENT */
2459#ifdef TRANS_SERVER
2460	NULL,
2461	TRANS(SocketOpenCOTSServer),
2462#endif /* TRANS_SERVER */
2463#ifdef TRANS_REOPEN
2464	TRANS(SocketReopenCOTSServer),
2465#endif
2466	TRANS(SocketSetOption),
2467#ifdef TRANS_SERVER
2468	TRANS(SocketINETCreateListener),
2469	NULL,					/* ResetListener */
2470	TRANS(SocketINETAccept),
2471#endif /* TRANS_SERVER */
2472#ifdef TRANS_CLIENT
2473	TRANS(SocketINETConnect),
2474#endif /* TRANS_CLIENT */
2475	TRANS(SocketBytesReadable),
2476	TRANS(SocketRead),
2477	TRANS(SocketWrite),
2478	TRANS(SocketReadv),
2479	TRANS(SocketWritev),
2480#if XTRANS_SEND_FDS
2481        TRANS(SocketSendFdInvalid),
2482        TRANS(SocketRecvFdInvalid),
2483#endif
2484	TRANS(SocketDisconnect),
2485	TRANS(SocketINETClose),
2486	TRANS(SocketINETClose),
2487	};
2488#endif /* IPv6 */
2489#endif /* TCPCONN */
2490
2491#ifdef UNIXCONN
2492#if !defined(LOCALCONN)
2493static Xtransport	TRANS(SocketLocalFuncs) = {
2494	/* Socket Interface */
2495	"local",
2496#ifdef HAVE_ABSTRACT_SOCKETS
2497	TRANS_ABSTRACT,
2498#else
2499	0,
2500#endif
2501#ifdef TRANS_CLIENT
2502	TRANS(SocketOpenCOTSClient),
2503#endif /* TRANS_CLIENT */
2504#ifdef TRANS_SERVER
2505	NULL,
2506	TRANS(SocketOpenCOTSServer),
2507#endif /* TRANS_SERVER */
2508#ifdef TRANS_REOPEN
2509	TRANS(SocketReopenCOTSServer),
2510#endif
2511	TRANS(SocketSetOption),
2512#ifdef TRANS_SERVER
2513	TRANS(SocketUNIXCreateListener),
2514	TRANS(SocketUNIXResetListener),
2515	TRANS(SocketUNIXAccept),
2516#endif /* TRANS_SERVER */
2517#ifdef TRANS_CLIENT
2518	TRANS(SocketUNIXConnect),
2519#endif /* TRANS_CLIENT */
2520	TRANS(SocketBytesReadable),
2521	TRANS(SocketRead),
2522	TRANS(SocketWrite),
2523	TRANS(SocketReadv),
2524	TRANS(SocketWritev),
2525#if XTRANS_SEND_FDS
2526        TRANS(SocketSendFd),
2527        TRANS(SocketRecvFd),
2528#endif
2529	TRANS(SocketDisconnect),
2530	TRANS(SocketUNIXClose),
2531	TRANS(SocketUNIXCloseForCloning),
2532	};
2533#endif /* !LOCALCONN */
2534# ifdef TRANS_SERVER
2535#  if !defined(LOCALCONN)
2536static const char* unix_nolisten[] = { "local" , NULL };
2537#  endif
2538# endif
2539
2540static Xtransport	TRANS(SocketUNIXFuncs) = {
2541	/* Socket Interface */
2542	"unix",
2543#if !defined(LOCALCONN) && !defined(HAVE_ABSTRACT_SOCKETS)
2544        TRANS_ALIAS,
2545#else
2546	0,
2547#endif
2548#ifdef TRANS_CLIENT
2549	TRANS(SocketOpenCOTSClient),
2550#endif /* TRANS_CLIENT */
2551#ifdef TRANS_SERVER
2552#if !defined(LOCALCONN)
2553	unix_nolisten,
2554#else
2555	NULL,
2556#endif
2557	TRANS(SocketOpenCOTSServer),
2558#endif /* TRANS_SERVER */
2559#ifdef TRANS_REOPEN
2560	TRANS(SocketReopenCOTSServer),
2561#endif
2562	TRANS(SocketSetOption),
2563#ifdef TRANS_SERVER
2564	TRANS(SocketUNIXCreateListener),
2565	TRANS(SocketUNIXResetListener),
2566	TRANS(SocketUNIXAccept),
2567#endif /* TRANS_SERVER */
2568#ifdef TRANS_CLIENT
2569	TRANS(SocketUNIXConnect),
2570#endif /* TRANS_CLIENT */
2571	TRANS(SocketBytesReadable),
2572	TRANS(SocketRead),
2573	TRANS(SocketWrite),
2574	TRANS(SocketReadv),
2575	TRANS(SocketWritev),
2576#if XTRANS_SEND_FDS
2577        TRANS(SocketSendFd),
2578        TRANS(SocketRecvFd),
2579#endif
2580	TRANS(SocketDisconnect),
2581	TRANS(SocketUNIXClose),
2582	TRANS(SocketUNIXCloseForCloning),
2583	};
2584
2585#endif /* UNIXCONN */
2586