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