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