Xtranssock.c revision 8a0d9095
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, 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, char *protocol,
600			     char *host, 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, char *protocol,
614			     char *host, 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, char *protocol,
681			     char *host, 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, char *protocol,
720			     char *host, 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, 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, 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, char *port, unsigned int flags)
951
952{
953#if defined(IPv6) && defined(AF_INET6)
954    struct sockaddr_storage sockname;
955#else
956    struct sockaddr_in	    sockname;
957#endif
958    unsigned short	    sport;
959    SOCKLEN_T	namelen = sizeof(sockname);
960    int		status;
961    long	tmpport;
962#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
963    _Xgetservbynameparams sparams;
964#endif
965    struct servent *servp;
966
967#ifdef X11_t
968    char	portbuf[PORTBUFSIZE];
969#endif
970
971    prmsg (2, "SocketINETCreateListener(%s)\n", port);
972
973#ifdef X11_t
974    /*
975     * X has a well known port, that is transport dependent. It is easier
976     * to handle it here, than try and come up with a transport independent
977     * representation that can be passed in and resolved the usual way.
978     *
979     * The port that is passed here is really a string containing the idisplay
980     * from ConnectDisplay().
981     */
982
983    if (is_numeric (port))
984    {
985	/* fixup the server port address */
986	tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10);
987	snprintf (portbuf, sizeof(portbuf), "%lu", tmpport);
988	port = portbuf;
989    }
990#endif
991
992    if (port && *port)
993    {
994	/* Check to see if the port string is just a number (handles X11) */
995
996	if (!is_numeric (port))
997	{
998	    if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL)
999	    {
1000		prmsg (1,
1001	     "SocketINETCreateListener: Unable to get service for %s\n",
1002		      port);
1003		return TRANS_CREATE_LISTENER_FAILED;
1004	    }
1005	    /* we trust getservbyname to return a valid number */
1006	    sport = servp->s_port;
1007	}
1008	else
1009	{
1010	    tmpport = strtol (port, (char**)NULL, 10);
1011	    /*
1012	     * check that somehow the port address isn't negative or in
1013	     * the range of reserved port addresses. This can happen and
1014	     * be very bad if the server is suid-root and the user does
1015	     * something (dumb) like `X :60049`.
1016	     */
1017	    if (tmpport < 1024 || tmpport > USHRT_MAX)
1018		return TRANS_CREATE_LISTENER_FAILED;
1019
1020	    sport = (unsigned short) tmpport;
1021	}
1022    }
1023    else
1024	sport = 0;
1025
1026    bzero(&sockname, sizeof(sockname));
1027#if defined(IPv6) && defined(AF_INET6)
1028    if (Sockettrans2devtab[ciptr->index].family == AF_INET) {
1029	namelen = sizeof (struct sockaddr_in);
1030#ifdef BSD44SOCKETS
1031	((struct sockaddr_in *)&sockname)->sin_len = namelen;
1032#endif
1033	((struct sockaddr_in *)&sockname)->sin_family = AF_INET;
1034	((struct sockaddr_in *)&sockname)->sin_port = htons(sport);
1035	((struct sockaddr_in *)&sockname)->sin_addr.s_addr = htonl(INADDR_ANY);
1036    } else {
1037	namelen = sizeof (struct sockaddr_in6);
1038#ifdef SIN6_LEN
1039	((struct sockaddr_in6 *)&sockname)->sin6_len = sizeof(sockname);
1040#endif
1041	((struct sockaddr_in6 *)&sockname)->sin6_family = AF_INET6;
1042	((struct sockaddr_in6 *)&sockname)->sin6_port = htons(sport);
1043	((struct sockaddr_in6 *)&sockname)->sin6_addr = in6addr_any;
1044    }
1045#else
1046#ifdef BSD44SOCKETS
1047    sockname.sin_len = sizeof (sockname);
1048#endif
1049    sockname.sin_family = AF_INET;
1050    sockname.sin_port = htons (sport);
1051    sockname.sin_addr.s_addr = htonl (INADDR_ANY);
1052#endif
1053
1054    if ((status = TRANS(SocketCreateListener) (ciptr,
1055	(struct sockaddr *) &sockname, namelen, flags)) < 0)
1056    {
1057	prmsg (1,
1058    "SocketINETCreateListener: ...SocketCreateListener() failed\n");
1059	return status;
1060    }
1061
1062    if (TRANS(SocketINETGetAddr) (ciptr) < 0)
1063    {
1064	prmsg (1,
1065       "SocketINETCreateListener: ...SocketINETGetAddr() failed\n");
1066	return TRANS_CREATE_LISTENER_FAILED;
1067    }
1068
1069    return 0;
1070}
1071
1072#endif /* TCPCONN */
1073
1074
1075#ifdef UNIXCONN
1076
1077static int
1078TRANS(SocketUNIXCreateListener) (XtransConnInfo ciptr, char *port,
1079				 unsigned int flags)
1080
1081{
1082    struct sockaddr_un	sockname;
1083    int			namelen;
1084    int			oldUmask;
1085    int			status;
1086    unsigned int	mode;
1087    char		tmpport[108];
1088
1089    int			abstract = 0;
1090#ifdef HAVE_ABSTRACT_SOCKETS
1091    abstract = ciptr->transptr->flags & TRANS_ABSTRACT;
1092#endif
1093
1094    prmsg (2, "SocketUNIXCreateListener(%s)\n",
1095	port ? port : "NULL");
1096
1097    /* Make sure the directory is created */
1098
1099    oldUmask = umask (0);
1100
1101#ifdef UNIX_DIR
1102#ifdef HAS_STICKY_DIR_BIT
1103    mode = 01777;
1104#else
1105    mode = 0777;
1106#endif
1107    if (!abstract && trans_mkdir(UNIX_DIR, mode) == -1) {
1108	prmsg (1, "SocketUNIXCreateListener: mkdir(%s) failed, errno = %d\n",
1109	       UNIX_DIR, errno);
1110	(void) umask (oldUmask);
1111	return TRANS_CREATE_LISTENER_FAILED;
1112    }
1113#endif
1114
1115    memset(&sockname, 0, sizeof(sockname));
1116    sockname.sun_family = AF_UNIX;
1117
1118    if (!(port && *port)) {
1119	snprintf (tmpport, sizeof(tmpport), "%s%ld", UNIX_PATH, (long)getpid());
1120	port = tmpport;
1121    }
1122    if (set_sun_path(port, UNIX_PATH, sockname.sun_path, abstract) != 0) {
1123	prmsg (1, "SocketUNIXCreateListener: path too long\n");
1124	return TRANS_CREATE_LISTENER_FAILED;
1125    }
1126
1127#if (defined(BSD44SOCKETS) || defined(__UNIXWARE__))
1128    sockname.sun_len = strlen(sockname.sun_path);
1129#endif
1130
1131#if defined(BSD44SOCKETS) || defined(SUN_LEN)
1132    namelen = SUN_LEN(&sockname);
1133#else
1134    namelen = strlen(sockname.sun_path) + offsetof(struct sockaddr_un, sun_path);
1135#endif
1136
1137    if (abstract) {
1138	sockname.sun_path[0] = '\0';
1139	namelen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&sockname.sun_path[1]);
1140    }
1141    else
1142	unlink (sockname.sun_path);
1143
1144    if ((status = TRANS(SocketCreateListener) (ciptr,
1145	(struct sockaddr *) &sockname, namelen, flags)) < 0)
1146    {
1147	prmsg (1,
1148    "SocketUNIXCreateListener: ...SocketCreateListener() failed\n");
1149	(void) umask (oldUmask);
1150	return status;
1151    }
1152
1153    /*
1154     * Now that the listener is esablished, create the addr info for
1155     * this connection. getpeername() doesn't work for UNIX Domain Sockets
1156     * on some systems (hpux at least), so we will just do it manually, instead
1157     * of calling something like TRANS(SocketUNIXGetAddr).
1158     */
1159
1160    namelen = sizeof (sockname); /* this will always make it the same size */
1161
1162    if ((ciptr->addr = malloc (namelen)) == NULL)
1163    {
1164        prmsg (1,
1165        "SocketUNIXCreateListener: Can't allocate space for the addr\n");
1166	(void) umask (oldUmask);
1167        return TRANS_CREATE_LISTENER_FAILED;
1168    }
1169
1170    if (abstract)
1171	sockname.sun_path[0] = '@';
1172
1173    ciptr->family = sockname.sun_family;
1174    ciptr->addrlen = namelen;
1175    memcpy (ciptr->addr, &sockname, ciptr->addrlen);
1176
1177    (void) umask (oldUmask);
1178
1179    return 0;
1180}
1181
1182
1183static int
1184TRANS(SocketUNIXResetListener) (XtransConnInfo ciptr)
1185
1186{
1187    /*
1188     * See if the unix domain socket has disappeared.  If it has, recreate it.
1189     */
1190
1191    struct sockaddr_un 	*unsock = (struct sockaddr_un *) ciptr->addr;
1192    struct stat		statb;
1193    int 		status = TRANS_RESET_NOOP;
1194    unsigned int	mode;
1195    int abstract = 0;
1196#ifdef HAVE_ABSTRACT_SOCKETS
1197    abstract = ciptr->transptr->flags & TRANS_ABSTRACT;
1198#endif
1199
1200    prmsg (3, "SocketUNIXResetListener(%p,%d)\n", ciptr, ciptr->fd);
1201
1202    if (!abstract && (
1203	stat (unsock->sun_path, &statb) == -1 ||
1204        ((statb.st_mode & S_IFMT) !=
1205#if defined(NCR) || defined(SCO325) || !defined(S_IFSOCK)
1206	  		S_IFIFO
1207#else
1208			S_IFSOCK
1209#endif
1210				)))
1211    {
1212	int oldUmask = umask (0);
1213
1214#ifdef UNIX_DIR
1215#ifdef HAS_STICKY_DIR_BIT
1216	mode = 01777;
1217#else
1218	mode = 0777;
1219#endif
1220        if (trans_mkdir(UNIX_DIR, mode) == -1) {
1221            prmsg (1, "SocketUNIXResetListener: mkdir(%s) failed, errno = %d\n",
1222	    UNIX_DIR, errno);
1223	    (void) umask (oldUmask);
1224	    return TRANS_RESET_FAILURE;
1225        }
1226#endif
1227
1228	close (ciptr->fd);
1229	unlink (unsock->sun_path);
1230
1231	if ((ciptr->fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
1232	{
1233	    TRANS(FreeConnInfo) (ciptr);
1234	    (void) umask (oldUmask);
1235	    return TRANS_RESET_FAILURE;
1236	}
1237
1238	if (bind (ciptr->fd, (struct sockaddr *) unsock, ciptr->addrlen) < 0)
1239	{
1240	    close (ciptr->fd);
1241	    TRANS(FreeConnInfo) (ciptr);
1242	    return TRANS_RESET_FAILURE;
1243	}
1244
1245	if (listen (ciptr->fd, BACKLOG) < 0)
1246	{
1247	    close (ciptr->fd);
1248	    TRANS(FreeConnInfo) (ciptr);
1249	    (void) umask (oldUmask);
1250	    return TRANS_RESET_FAILURE;
1251	}
1252
1253	umask (oldUmask);
1254
1255	status = TRANS_RESET_NEW_FD;
1256    }
1257
1258    return status;
1259}
1260
1261#endif /* UNIXCONN */
1262
1263
1264#ifdef TCPCONN
1265
1266static XtransConnInfo
1267TRANS(SocketINETAccept) (XtransConnInfo ciptr, int *status)
1268
1269{
1270    XtransConnInfo	newciptr;
1271    struct sockaddr_in	sockname;
1272    SOCKLEN_T		namelen = sizeof(sockname);
1273
1274    prmsg (2, "SocketINETAccept(%p,%d)\n", ciptr, ciptr->fd);
1275
1276    if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
1277    {
1278	prmsg (1, "SocketINETAccept: malloc failed\n");
1279	*status = TRANS_ACCEPT_BAD_MALLOC;
1280	return NULL;
1281    }
1282
1283    if ((newciptr->fd = accept (ciptr->fd,
1284	(struct sockaddr *) &sockname, (void *)&namelen)) < 0)
1285    {
1286#ifdef WIN32
1287	errno = WSAGetLastError();
1288#endif
1289	prmsg (1, "SocketINETAccept: accept() failed\n");
1290	free (newciptr);
1291	*status = TRANS_ACCEPT_FAILED;
1292	return NULL;
1293    }
1294
1295#ifdef TCP_NODELAY
1296    {
1297	/*
1298	 * turn off TCP coalescence for INET sockets
1299	 */
1300
1301	int tmp = 1;
1302	setsockopt (newciptr->fd, IPPROTO_TCP, TCP_NODELAY,
1303	    (char *) &tmp, sizeof (int));
1304    }
1305#endif
1306
1307    /*
1308     * Get this address again because the transport may give a more
1309     * specific address now that a connection is established.
1310     */
1311
1312    if (TRANS(SocketINETGetAddr) (newciptr) < 0)
1313    {
1314	prmsg (1,
1315	    "SocketINETAccept: ...SocketINETGetAddr() failed:\n");
1316	close (newciptr->fd);
1317	free (newciptr);
1318	*status = TRANS_ACCEPT_MISC_ERROR;
1319        return NULL;
1320    }
1321
1322    if (TRANS(SocketINETGetPeerAddr) (newciptr) < 0)
1323    {
1324	prmsg (1,
1325	  "SocketINETAccept: ...SocketINETGetPeerAddr() failed:\n");
1326	close (newciptr->fd);
1327	if (newciptr->addr) free (newciptr->addr);
1328	free (newciptr);
1329	*status = TRANS_ACCEPT_MISC_ERROR;
1330        return NULL;
1331    }
1332
1333    *status = 0;
1334
1335    return newciptr;
1336}
1337
1338#endif /* TCPCONN */
1339
1340
1341#ifdef UNIXCONN
1342static XtransConnInfo
1343TRANS(SocketUNIXAccept) (XtransConnInfo ciptr, int *status)
1344
1345{
1346    XtransConnInfo	newciptr;
1347    struct sockaddr_un	sockname;
1348    SOCKLEN_T 		namelen = sizeof sockname;
1349
1350    prmsg (2, "SocketUNIXAccept(%p,%d)\n", ciptr, ciptr->fd);
1351
1352    if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
1353    {
1354	prmsg (1, "SocketUNIXAccept: malloc() failed\n");
1355	*status = TRANS_ACCEPT_BAD_MALLOC;
1356	return NULL;
1357    }
1358
1359    if ((newciptr->fd = accept (ciptr->fd,
1360	(struct sockaddr *) &sockname, (void *)&namelen)) < 0)
1361    {
1362	prmsg (1, "SocketUNIXAccept: accept() failed\n");
1363	free (newciptr);
1364	*status = TRANS_ACCEPT_FAILED;
1365	return NULL;
1366    }
1367
1368	ciptr->addrlen = namelen;
1369    /*
1370     * Get the socket name and the peer name from the listener socket,
1371     * since this is unix domain.
1372     */
1373
1374    if ((newciptr->addr = malloc (ciptr->addrlen)) == NULL)
1375    {
1376        prmsg (1,
1377        "SocketUNIXAccept: Can't allocate space for the addr\n");
1378	close (newciptr->fd);
1379	free (newciptr);
1380	*status = TRANS_ACCEPT_BAD_MALLOC;
1381        return NULL;
1382    }
1383
1384    /*
1385     * if the socket is abstract, we already modified the address to have a
1386     * @ instead of the initial NUL, so no need to do that again here.
1387     */
1388
1389    newciptr->addrlen = ciptr->addrlen;
1390    memcpy (newciptr->addr, ciptr->addr, newciptr->addrlen);
1391
1392    if ((newciptr->peeraddr = malloc (ciptr->addrlen)) == NULL)
1393    {
1394        prmsg (1,
1395	      "SocketUNIXAccept: Can't allocate space for the addr\n");
1396	close (newciptr->fd);
1397	if (newciptr->addr) free (newciptr->addr);
1398	free (newciptr);
1399	*status = TRANS_ACCEPT_BAD_MALLOC;
1400        return NULL;
1401    }
1402
1403    newciptr->peeraddrlen = ciptr->addrlen;
1404    memcpy (newciptr->peeraddr, ciptr->addr, newciptr->addrlen);
1405
1406    newciptr->family = AF_UNIX;
1407
1408    *status = 0;
1409
1410    return newciptr;
1411}
1412
1413#endif /* UNIXCONN */
1414
1415#endif /* TRANS_SERVER */
1416
1417
1418#ifdef TRANS_CLIENT
1419
1420#ifdef TCPCONN
1421
1422#if defined(IPv6) && defined(AF_INET6)
1423struct addrlist {
1424    struct addrinfo *	addr;
1425    struct addrinfo *	firstaddr;
1426    char 		port[PORTBUFSIZE];
1427    char 		host[MAXHOSTNAMELEN];
1428};
1429static struct addrlist  *addrlist = NULL;
1430#endif
1431
1432
1433static int
1434TRANS(SocketINETConnect) (XtransConnInfo ciptr, char *host, char *port)
1435
1436{
1437    struct sockaddr *	socketaddr = NULL;
1438    int			socketaddrlen = 0;
1439    int			res;
1440#if defined(IPv6) && defined(AF_INET6)
1441    struct addrinfo 	hints;
1442    char		ntopbuf[INET6_ADDRSTRLEN];
1443    int			resetonce = 0;
1444#else
1445    struct sockaddr_in	sockname;
1446    struct hostent	*hostp;
1447    struct servent	*servp;
1448    unsigned long 	tmpaddr;
1449#endif
1450#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1451    _Xgethostbynameparams hparams;
1452    _Xgetservbynameparams sparams;
1453#endif
1454#ifdef X11_t
1455    char	portbuf[PORTBUFSIZE];
1456#endif
1457
1458    char 		hostnamebuf[256];		/* tmp space */
1459
1460    prmsg (2,"SocketINETConnect(%d,%s,%s)\n", ciptr->fd, host, port);
1461
1462    if (!host)
1463    {
1464	hostnamebuf[0] = '\0';
1465	(void) TRANS(GetHostname) (hostnamebuf, sizeof hostnamebuf);
1466	host = hostnamebuf;
1467    }
1468
1469#ifdef X11_t
1470    /*
1471     * X has a well known port, that is transport dependent. It is easier
1472     * to handle it here, than try and come up with a transport independent
1473     * representation that can be passed in and resolved the usual way.
1474     *
1475     * The port that is passed here is really a string containing the idisplay
1476     * from ConnectDisplay().
1477     */
1478
1479    if (is_numeric (port))
1480    {
1481	long tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10);
1482	snprintf (portbuf, sizeof(portbuf), "%lu", tmpport);
1483	port = portbuf;
1484    }
1485#endif
1486
1487#if defined(IPv6) && defined(AF_INET6)
1488    {
1489	if (addrlist != NULL) {
1490	    if (strcmp(host,addrlist->host) || strcmp(port,addrlist->port)) {
1491		if (addrlist->firstaddr)
1492		    freeaddrinfo(addrlist->firstaddr);
1493		addrlist->firstaddr = NULL;
1494	    }
1495	} else {
1496	    addrlist = malloc(sizeof(struct addrlist));
1497	    addrlist->firstaddr = NULL;
1498	}
1499
1500	if (addrlist->firstaddr == NULL) {
1501	    strncpy(addrlist->port, port, sizeof(addrlist->port));
1502	    addrlist->port[sizeof(addrlist->port) - 1] = '\0';
1503	    strncpy(addrlist->host, host, sizeof(addrlist->host));
1504	    addrlist->host[sizeof(addrlist->host) - 1] = '\0';
1505
1506	    bzero(&hints,sizeof(hints));
1507	    hints.ai_socktype = Sockettrans2devtab[ciptr->index].devcotsname;
1508
1509	    res = getaddrinfo(host,port,&hints,&addrlist->firstaddr);
1510	    if (res != 0) {
1511		prmsg (1, "SocketINETConnect() can't get address "
1512			"for %s:%s: %s\n", host, port, gai_strerror(res));
1513		ESET(EINVAL);
1514		return TRANS_CONNECT_FAILED;
1515	    }
1516	    for (res = 0, addrlist->addr = addrlist->firstaddr;
1517		 addrlist->addr ; res++) {
1518		addrlist->addr = addrlist->addr->ai_next;
1519	    }
1520	    prmsg(4,"Got New Address list with %d addresses\n", res);
1521	    res = 0;
1522	    addrlist->addr = NULL;
1523	}
1524
1525	while (socketaddr == NULL) {
1526	    if (addrlist->addr == NULL) {
1527		if (resetonce) {
1528		    /* Already checked entire list - no usable addresses */
1529		    prmsg (1, "SocketINETConnect() no usable address "
1530			   "for %s:%s\n", host, port);
1531		    return TRANS_CONNECT_FAILED;
1532		} else {
1533		    /* Go back to beginning of list */
1534		    resetonce = 1;
1535		    addrlist->addr = addrlist->firstaddr;
1536		}
1537	    }
1538
1539	    socketaddr = addrlist->addr->ai_addr;
1540	    socketaddrlen = addrlist->addr->ai_addrlen;
1541
1542	    if (addrlist->addr->ai_family == AF_INET) {
1543		struct sockaddr_in *sin = (struct sockaddr_in *) socketaddr;
1544
1545		prmsg (4,"SocketINETConnect() sockname.sin_addr = %s\n",
1546			inet_ntop(addrlist->addr->ai_family,&sin->sin_addr,
1547			ntopbuf,sizeof(ntopbuf)));
1548
1549		prmsg (4,"SocketINETConnect() sockname.sin_port = %d\n",
1550			ntohs(sin->sin_port));
1551
1552		if (Sockettrans2devtab[ciptr->index].family == AF_INET6) {
1553		    if (strcmp(Sockettrans2devtab[ciptr->index].transname,
1554				"tcp") == 0) {
1555			XtransConnInfo newciptr;
1556
1557			/*
1558			 * Our socket is an IPv6 socket, but the address is
1559			 * IPv4.  Close it and get an IPv4 socket.  This is
1560			 * needed for IPv4 connections to work on platforms
1561			 * that don't allow IPv4 over IPv6 sockets.
1562			 */
1563			TRANS(SocketINETClose)(ciptr);
1564			newciptr = TRANS(SocketOpenCOTSClientBase)(
1565					"tcp", "tcp", host, port, ciptr->index);
1566			if (newciptr)
1567			    ciptr->fd = newciptr->fd;
1568			if (!newciptr ||
1569			    Sockettrans2devtab[newciptr->index].family !=
1570				AF_INET) {
1571			    socketaddr = NULL;
1572			    prmsg (4,"SocketINETConnect() Cannot get IPv4 "
1573					" socketfor IPv4 address\n");
1574			}
1575			if (newciptr)
1576			    free(newciptr);
1577		    } else {
1578			socketaddr = NULL;
1579			prmsg (4,"SocketINETConnect Skipping IPv4 address\n");
1580		    }
1581		}
1582	    } else if (addrlist->addr->ai_family == AF_INET6) {
1583		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) socketaddr;
1584
1585		prmsg (4,"SocketINETConnect() sockname.sin6_addr = %s\n",
1586			inet_ntop(addrlist->addr->ai_family,
1587				  &sin6->sin6_addr,ntopbuf,sizeof(ntopbuf)));
1588		prmsg (4,"SocketINETConnect() sockname.sin6_port = %d\n",
1589			ntohs(sin6->sin6_port));
1590
1591		if (Sockettrans2devtab[ciptr->index].family == AF_INET) {
1592		    if (strcmp(Sockettrans2devtab[ciptr->index].transname,
1593				"tcp") == 0) {
1594			XtransConnInfo newciptr;
1595
1596			/*
1597			 * Close the IPv4 socket and try to open an IPv6 socket.
1598			 */
1599			TRANS(SocketINETClose)(ciptr);
1600			newciptr = TRANS(SocketOpenCOTSClientBase)(
1601					"tcp", "tcp", host, port, -1);
1602			if (newciptr)
1603			    ciptr->fd = newciptr->fd;
1604			if (!newciptr ||
1605			    Sockettrans2devtab[newciptr->index].family !=
1606					AF_INET6) {
1607			    socketaddr = NULL;
1608			    prmsg (4,"SocketINETConnect() Cannot get IPv6 "
1609				   "socket for IPv6 address\n");
1610			}
1611			if (newciptr)
1612			    free(newciptr);
1613		    }
1614		    else
1615		    {
1616			socketaddr = NULL;
1617			prmsg (4,"SocketINETConnect() Skipping IPv6 address\n");
1618		    }
1619		}
1620	    } else {
1621		socketaddr = NULL; /* Unsupported address type */
1622	    }
1623	    if (socketaddr == NULL) {
1624		addrlist->addr = addrlist->addr->ai_next;
1625	    }
1626	}
1627    }
1628#else
1629    {
1630	/*
1631	 * Build the socket name.
1632	 */
1633
1634#ifdef BSD44SOCKETS
1635	sockname.sin_len = sizeof (struct sockaddr_in);
1636#endif
1637	sockname.sin_family = AF_INET;
1638
1639	/*
1640	 * fill in sin_addr
1641	 */
1642
1643#ifndef INADDR_NONE
1644#define INADDR_NONE ((in_addr_t) 0xffffffff)
1645#endif
1646
1647	/* check for ww.xx.yy.zz host string */
1648
1649	if (isascii (host[0]) && isdigit (host[0])) {
1650	    tmpaddr = inet_addr (host); /* returns network byte order */
1651	} else {
1652	    tmpaddr = INADDR_NONE;
1653	}
1654
1655	prmsg (4,"SocketINETConnect() inet_addr(%s) = %x\n", host, tmpaddr);
1656
1657	if (tmpaddr == INADDR_NONE) {
1658	    if ((hostp = _XGethostbyname(host,hparams)) == NULL) {
1659		prmsg (1,"SocketINETConnect: Can't get address for %s\n",
1660			host);
1661		ESET(EINVAL);
1662		return TRANS_CONNECT_FAILED;
1663	    }
1664	    if (hostp->h_addrtype != AF_INET) {  /* is IP host? */
1665		prmsg (1,"SocketINETConnect: not INET host%s\n", host);
1666		ESET(EPROTOTYPE);
1667		return TRANS_CONNECT_FAILED;
1668	    }
1669
1670	    memcpy ((char *) &sockname.sin_addr, (char *) hostp->h_addr,
1671		    sizeof (sockname.sin_addr));
1672
1673	} else {
1674	    sockname.sin_addr.s_addr = tmpaddr;
1675        }
1676
1677	/*
1678	 * fill in sin_port
1679	 */
1680
1681	/* Check for number in the port string */
1682
1683	if (!is_numeric (port)) {
1684	    if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL) {
1685		prmsg (1,"SocketINETConnect: can't get service for %s\n",
1686			port);
1687		return TRANS_CONNECT_FAILED;
1688	    }
1689	    sockname.sin_port = htons (servp->s_port);
1690	} else {
1691	    long tmpport = strtol (port, (char**)NULL, 10);
1692	    if (tmpport < 1024 || tmpport > USHRT_MAX)
1693		return TRANS_CONNECT_FAILED;
1694	    sockname.sin_port = htons (((unsigned short) tmpport));
1695	}
1696
1697	prmsg (4,"SocketINETConnect: sockname.sin_port = %d\n",
1698		ntohs(sockname.sin_port));
1699	socketaddr = (struct sockaddr *) &sockname;
1700	socketaddrlen = sizeof(sockname);
1701    }
1702#endif
1703
1704    /*
1705     * Turn on socket keepalive so the client process will eventually
1706     * be notified with a SIGPIPE signal if the display server fails
1707     * to respond to a periodic transmission of messages
1708     * on the connected socket.
1709     * This is useful to avoid hung application processes when the
1710     * processes are not spawned from the xdm session and
1711     * the display server terminates abnormally.
1712     * (Someone turned off the power switch.)
1713     */
1714
1715    {
1716	int tmp = 1;
1717	setsockopt (ciptr->fd, SOL_SOCKET, SO_KEEPALIVE,
1718		(char *) &tmp, sizeof (int));
1719    }
1720
1721    /*
1722     * Do the connect()
1723     */
1724
1725    if (connect (ciptr->fd, socketaddr, socketaddrlen ) < 0)
1726    {
1727#ifdef WIN32
1728	int olderrno = WSAGetLastError();
1729#else
1730	int olderrno = errno;
1731#endif
1732
1733	/*
1734	 * If the error was ECONNREFUSED, the server may be overloaded
1735	 * and we should try again.
1736	 *
1737	 * If the error was EWOULDBLOCK or EINPROGRESS then the socket
1738	 * was non-blocking and we should poll using select
1739	 *
1740	 * If the error was EINTR, the connect was interrupted and we
1741	 * should try again.
1742	 *
1743	 * If multiple addresses are found for a host then we should
1744	 * try to connect again with a different address for a larger
1745	 * number of errors that made us quit before, since those
1746	 * could be caused by trying to use an IPv6 address to contact
1747	 * a machine with an IPv4-only server or other reasons that
1748	 * only affect one of a set of addresses.
1749	 */
1750
1751	if (olderrno == ECONNREFUSED || olderrno == EINTR
1752#if defined(IPv6) && defined(AF_INET6)
1753	  || (((addrlist->addr->ai_next != NULL) ||
1754	        (addrlist->addr != addrlist->firstaddr)) &&
1755               (olderrno == ENETUNREACH || olderrno == EAFNOSUPPORT ||
1756		 olderrno == EADDRNOTAVAIL || olderrno == ETIMEDOUT
1757#if defined(EHOSTDOWN)
1758		   || olderrno == EHOSTDOWN
1759#endif
1760	       ))
1761#endif
1762	    )
1763	    res = TRANS_TRY_CONNECT_AGAIN;
1764	else if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS)
1765	    res = TRANS_IN_PROGRESS;
1766	else
1767	{
1768	    prmsg (2,"SocketINETConnect: Can't connect: errno = %d\n",
1769		   olderrno);
1770
1771	    res = TRANS_CONNECT_FAILED;
1772	}
1773    } else {
1774	res = 0;
1775
1776
1777	/*
1778	 * Sync up the address fields of ciptr.
1779	 */
1780
1781	if (TRANS(SocketINETGetAddr) (ciptr) < 0)
1782	{
1783	    prmsg (1,
1784	     "SocketINETConnect: ...SocketINETGetAddr() failed:\n");
1785	    res = TRANS_CONNECT_FAILED;
1786	}
1787
1788	else if (TRANS(SocketINETGetPeerAddr) (ciptr) < 0)
1789	{
1790	    prmsg (1,
1791	      "SocketINETConnect: ...SocketINETGetPeerAddr() failed:\n");
1792	    res = TRANS_CONNECT_FAILED;
1793	}
1794    }
1795
1796#if defined(IPv6) && defined(AF_INET6)
1797   if (res != 0) {
1798	addrlist->addr = addrlist->addr->ai_next;
1799   }
1800#endif
1801
1802    return res;
1803}
1804
1805#endif /* TCPCONN */
1806
1807
1808
1809#ifdef UNIXCONN
1810
1811/*
1812 * Make sure 'host' is really local.
1813 */
1814
1815static int
1816UnixHostReallyLocal (char *host)
1817
1818{
1819    char hostnamebuf[256];
1820
1821    TRANS(GetHostname) (hostnamebuf, sizeof (hostnamebuf));
1822
1823    if (strcmp (hostnamebuf, host) == 0)
1824    {
1825	return (1);
1826    } else {
1827#if defined(IPv6) && defined(AF_INET6)
1828	struct addrinfo *localhostaddr;
1829	struct addrinfo *otherhostaddr;
1830	struct addrinfo *i, *j;
1831	int equiv = 0;
1832
1833	if (getaddrinfo(hostnamebuf, NULL, NULL, &localhostaddr) != 0)
1834	    return 0;
1835	if (getaddrinfo(host, NULL, NULL, &otherhostaddr) != 0) {
1836	    freeaddrinfo(localhostaddr);
1837	    return 0;
1838	}
1839
1840	for (i = localhostaddr; i != NULL && equiv == 0; i = i->ai_next) {
1841	    for (j = otherhostaddr; j != NULL && equiv == 0; j = j->ai_next) {
1842		if (i->ai_family == j->ai_family) {
1843		    if (i->ai_family == AF_INET) {
1844			struct sockaddr_in *sinA
1845			  = (struct sockaddr_in *) i->ai_addr;
1846			struct sockaddr_in *sinB
1847			  = (struct sockaddr_in *) j->ai_addr;
1848			struct in_addr *A = &sinA->sin_addr;
1849			struct in_addr *B = &sinB->sin_addr;
1850
1851			if (memcmp(A,B,sizeof(struct in_addr)) == 0) {
1852			    equiv = 1;
1853			}
1854		    } else if (i->ai_family == AF_INET6) {
1855			struct sockaddr_in6 *sinA
1856			  = (struct sockaddr_in6 *) i->ai_addr;
1857			struct sockaddr_in6 *sinB
1858			  = (struct sockaddr_in6 *) j->ai_addr;
1859			struct in6_addr *A = &sinA->sin6_addr;
1860			struct in6_addr *B = &sinB->sin6_addr;
1861
1862			if (memcmp(A,B,sizeof(struct in6_addr)) == 0) {
1863			    equiv = 1;
1864			}
1865		    }
1866		}
1867	    }
1868	}
1869
1870	freeaddrinfo(localhostaddr);
1871	freeaddrinfo(otherhostaddr);
1872	return equiv;
1873#else
1874	/*
1875	 * A host may have more than one network address.  If any of the
1876	 * network addresses of 'host' (specified to the connect call)
1877	 * match any of the network addresses of 'hostname' (determined
1878	 * by TRANS(GetHostname)), then the two hostnames are equivalent,
1879	 * and we know that 'host' is really a local host.
1880	 */
1881	char specified_local_addr_list[10][4];
1882	int scount, equiv, i, j;
1883#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1884	_Xgethostbynameparams hparams;
1885#endif
1886	struct hostent *hostp;
1887
1888	if ((hostp = _XGethostbyname (host,hparams)) == NULL)
1889	    return (0);
1890
1891	scount = 0;
1892	while (hostp->h_addr_list[scount] && scount <= 8)
1893	{
1894	    /*
1895	     * The 2nd call to gethostname() overrides the data
1896	     * from the 1st call, so we must save the address list.
1897	     */
1898
1899	    specified_local_addr_list[scount][0] =
1900				hostp->h_addr_list[scount][0];
1901	    specified_local_addr_list[scount][1] =
1902				hostp->h_addr_list[scount][1];
1903	    specified_local_addr_list[scount][2] =
1904				hostp->h_addr_list[scount][2];
1905	    specified_local_addr_list[scount][3] =
1906				hostp->h_addr_list[scount][3];
1907	    scount++;
1908	}
1909	if ((hostp = _XGethostbyname (hostnamebuf,hparams)) == NULL)
1910	    return (0);
1911
1912	equiv = 0;
1913	i = 0;
1914
1915	while (i < scount && !equiv)
1916	{
1917	    j = 0;
1918
1919	    while (hostp->h_addr_list[j])
1920	    {
1921		if ((specified_local_addr_list[i][0] ==
1922					hostp->h_addr_list[j][0]) &&
1923		    (specified_local_addr_list[i][1] ==
1924					hostp->h_addr_list[j][1]) &&
1925		    (specified_local_addr_list[i][2] ==
1926					hostp->h_addr_list[j][2]) &&
1927		    (specified_local_addr_list[i][3] ==
1928					hostp->h_addr_list[j][3]))
1929		{
1930		    /* They're equal, so we're done */
1931
1932		    equiv = 1;
1933		    break;
1934		}
1935
1936		j++;
1937	    }
1938
1939	    i++;
1940	}
1941	return (equiv);
1942#endif
1943    }
1944}
1945
1946static int
1947TRANS(SocketUNIXConnect) (XtransConnInfo ciptr, char *host, char *port)
1948
1949{
1950    struct sockaddr_un	sockname;
1951    SOCKLEN_T		namelen;
1952
1953
1954    int abstract = 0;
1955#ifdef HAVE_ABSTRACT_SOCKETS
1956    abstract = ciptr->transptr->flags & TRANS_ABSTRACT;
1957#endif
1958
1959    prmsg (2,"SocketUNIXConnect(%d,%s,%s)\n", ciptr->fd, host, port);
1960
1961    /*
1962     * Make sure 'host' is really local.  If not, we return failure.
1963     * The reason we make this check is because a process may advertise
1964     * a "local" network ID for which it can accept connections, but if
1965     * a process on a remote machine tries to connect to this network ID,
1966     * we know for sure it will fail.
1967     */
1968
1969    if (host && *host && host[0]!='/' && strcmp (host, "unix") != 0 && !UnixHostReallyLocal (host))
1970    {
1971	prmsg (1,
1972	   "SocketUNIXConnect: Cannot connect to non-local host %s\n",
1973	       host);
1974	return TRANS_CONNECT_FAILED;
1975    }
1976
1977
1978    /*
1979     * Check the port.
1980     */
1981
1982    if (!port || !*port)
1983    {
1984	prmsg (1,"SocketUNIXConnect: Missing port specification\n");
1985	return TRANS_CONNECT_FAILED;
1986    }
1987
1988    /*
1989     * Build the socket name.
1990     */
1991
1992    sockname.sun_family = AF_UNIX;
1993
1994    if (set_sun_path(port, UNIX_PATH, sockname.sun_path, abstract) != 0) {
1995	prmsg (1, "SocketUNIXConnect: path too long\n");
1996	return TRANS_CONNECT_FAILED;
1997    }
1998
1999#if (defined(BSD44SOCKETS) || defined(__UNIXWARE__))
2000    sockname.sun_len = strlen (sockname.sun_path);
2001#endif
2002
2003#if defined(BSD44SOCKETS) || defined(SUN_LEN)
2004    namelen = SUN_LEN (&sockname);
2005#else
2006    namelen = strlen (sockname.sun_path) + offsetof(struct sockaddr_un, sun_path);
2007#endif
2008
2009
2010
2011    /*
2012     * Adjust the socket path if using abstract sockets.
2013     * Done here because otherwise all the strlen() calls above would fail.
2014     */
2015
2016    if (abstract) {
2017	sockname.sun_path[0] = '\0';
2018    }
2019
2020    /*
2021     * Do the connect()
2022     */
2023
2024    if (connect (ciptr->fd, (struct sockaddr *) &sockname, namelen) < 0)
2025    {
2026	int olderrno = errno;
2027	int connected = 0;
2028
2029	if (!connected)
2030	{
2031	    errno = olderrno;
2032
2033	    /*
2034	     * If the error was ENOENT, the server may be starting up; we used
2035	     * to suggest to try again in this case with
2036	     * TRANS_TRY_CONNECT_AGAIN, but this introduced problems for
2037	     * processes still referencing stale sockets in their environment.
2038	     * Hence, we now return a hard error, TRANS_CONNECT_FAILED, and it
2039	     * is suggested that higher level stacks handle retries on their
2040	     * level when they face a slow starting server.
2041	     *
2042	     * If the error was EWOULDBLOCK or EINPROGRESS then the socket
2043	     * was non-blocking and we should poll using select
2044	     *
2045	     * If the error was EINTR, the connect was interrupted and we
2046	     * should try again.
2047	     */
2048
2049	    if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS)
2050		return TRANS_IN_PROGRESS;
2051	    else if (olderrno == EINTR)
2052		return TRANS_TRY_CONNECT_AGAIN;
2053	    else if (olderrno == ENOENT || olderrno == ECONNREFUSED) {
2054		/* If opening as abstract socket failed, try again normally */
2055		if (abstract) {
2056		    ciptr->transptr->flags &= ~(TRANS_ABSTRACT);
2057		    return TRANS_TRY_CONNECT_AGAIN;
2058		} else {
2059		    return TRANS_CONNECT_FAILED;
2060		}
2061	    } else {
2062		prmsg (2,"SocketUNIXConnect: Can't connect: errno = %d\n",
2063		       EGET());
2064
2065		return TRANS_CONNECT_FAILED;
2066	    }
2067	}
2068    }
2069
2070    /*
2071     * Get the socket name and the peer name from the connect socket,
2072     * since this is unix domain.
2073     */
2074
2075    if ((ciptr->addr = malloc(namelen)) == NULL ||
2076       (ciptr->peeraddr = malloc(namelen)) == NULL)
2077    {
2078        prmsg (1,
2079	"SocketUNIXCreateListener: Can't allocate space for the addr\n");
2080        return TRANS_CONNECT_FAILED;
2081    }
2082
2083    if (abstract)
2084	sockname.sun_path[0] = '@';
2085
2086    ciptr->family = AF_UNIX;
2087    ciptr->addrlen = namelen;
2088    ciptr->peeraddrlen = namelen;
2089    memcpy (ciptr->addr, &sockname, ciptr->addrlen);
2090    memcpy (ciptr->peeraddr, &sockname, ciptr->peeraddrlen);
2091
2092    return 0;
2093}
2094
2095#endif /* UNIXCONN */
2096
2097#endif /* TRANS_CLIENT */
2098
2099
2100static int
2101TRANS(SocketBytesReadable) (XtransConnInfo ciptr, BytesReadable_t *pend)
2102
2103{
2104    prmsg (2,"SocketBytesReadable(%p,%d,%p)\n",
2105	ciptr, ciptr->fd, pend);
2106#ifdef WIN32
2107    {
2108	int ret = ioctlsocket ((SOCKET) ciptr->fd, FIONREAD, (u_long *) pend);
2109	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
2110	return ret;
2111    }
2112#else
2113#if defined(__i386__) && defined(SYSV) && !defined(SCO325)
2114    return ioctl (ciptr->fd, I_NREAD, (char *) pend);
2115#else
2116    return ioctl (ciptr->fd, FIONREAD, (char *) pend);
2117#endif /* __i386__ && SYSV || _SEQUENT_ && _SOCKET_VERSION == 1 */
2118#endif /* WIN32 */
2119}
2120
2121#if XTRANS_SEND_FDS
2122
2123static void
2124appendFd(struct _XtransConnFd **prev, int fd, int do_close)
2125{
2126    struct _XtransConnFd *cf, *new;
2127
2128    new = malloc (sizeof (struct _XtransConnFd));
2129    if (!new) {
2130        /* XXX mark connection as broken */
2131        close(fd);
2132        return;
2133    }
2134    new->next = 0;
2135    new->fd = fd;
2136    new->do_close = do_close;
2137    /* search to end of list */
2138    for (; (cf = *prev); prev = &(cf->next));
2139    *prev = new;
2140}
2141
2142static int
2143removeFd(struct _XtransConnFd **prev)
2144{
2145    struct _XtransConnFd *cf;
2146    int fd;
2147
2148    if ((cf = *prev)) {
2149        *prev = cf->next;
2150        fd = cf->fd;
2151        free(cf);
2152    } else
2153        fd = -1;
2154    return fd;
2155}
2156
2157static void
2158discardFd(struct _XtransConnFd **prev, struct _XtransConnFd *upto, int do_close)
2159{
2160    struct _XtransConnFd *cf, *next;
2161
2162    for (cf = *prev; cf != upto; cf = next) {
2163        next = cf->next;
2164        if (do_close || cf->do_close)
2165            close(cf->fd);
2166        free(cf);
2167    }
2168    *prev = upto;
2169}
2170
2171static void
2172cleanupFds(XtransConnInfo ciptr)
2173{
2174    /* Clean up the send list but don't close the fds */
2175    discardFd(&ciptr->send_fds, NULL, 0);
2176    /* Clean up the recv list and *do* close the fds */
2177    discardFd(&ciptr->recv_fds, NULL, 1);
2178}
2179
2180static int
2181nFd(struct _XtransConnFd **prev)
2182{
2183    struct _XtransConnFd *cf;
2184    int n = 0;
2185
2186    for (cf = *prev; cf; cf = cf->next)
2187        n++;
2188    return n;
2189}
2190
2191static int
2192TRANS(SocketRecvFd) (XtransConnInfo ciptr)
2193{
2194    prmsg (2, "SocketRecvFd(%d)\n", ciptr->fd);
2195    return removeFd(&ciptr->recv_fds);
2196}
2197
2198static int
2199TRANS(SocketSendFd) (XtransConnInfo ciptr, int fd, int do_close)
2200{
2201    appendFd(&ciptr->send_fds, fd, do_close);
2202    return 0;
2203}
2204
2205static int
2206TRANS(SocketRecvFdInvalid)(XtransConnInfo ciptr)
2207{
2208    errno = EINVAL;
2209    return -1;
2210}
2211
2212static int
2213TRANS(SocketSendFdInvalid)(XtransConnInfo ciptr, int fd, int do_close)
2214{
2215    errno = EINVAL;
2216    return -1;
2217}
2218
2219#define MAX_FDS		128
2220
2221union fd_pass {
2222	struct cmsghdr	cmsghdr;
2223	char		buf[CMSG_SPACE(MAX_FDS * sizeof(int))];
2224};
2225
2226#endif /* XTRANS_SEND_FDS */
2227
2228static int
2229TRANS(SocketRead) (XtransConnInfo ciptr, char *buf, int size)
2230
2231{
2232    prmsg (2,"SocketRead(%d,%p,%d)\n", ciptr->fd, buf, size);
2233
2234#if defined(WIN32)
2235    {
2236	int ret = recv ((SOCKET)ciptr->fd, buf, size, 0);
2237#ifdef WIN32
2238	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
2239#endif
2240	return ret;
2241    }
2242#else
2243#if XTRANS_SEND_FDS
2244    {
2245        struct iovec    iov = {
2246            .iov_base = buf,
2247            .iov_len = size
2248        };
2249        union fd_pass   cmsgbuf;
2250        struct msghdr   msg = {
2251            .msg_name = NULL,
2252            .msg_namelen = 0,
2253            .msg_iov = &iov,
2254            .msg_iovlen = 1,
2255            .msg_control = cmsgbuf.buf,
2256            .msg_controllen = CMSG_LEN(MAX_FDS * sizeof(int))
2257        };
2258
2259        size = recvmsg(ciptr->fd, &msg, 0);
2260        if (size >= 0) {
2261            struct cmsghdr *hdr;
2262
2263            for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) {
2264                if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) {
2265                    int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int);
2266                    int i;
2267                    int *fd = (int *) CMSG_DATA(hdr);
2268
2269                    for (i = 0; i < nfd; i++)
2270                        appendFd(&ciptr->recv_fds, fd[i], 0);
2271                }
2272            }
2273        }
2274        return size;
2275    }
2276#else
2277    return read(ciptr->fd, buf, size);
2278#endif /* XTRANS_SEND_FDS */
2279#endif /* WIN32 */
2280}
2281
2282static int
2283TRANS(SocketReadv) (XtransConnInfo ciptr, struct iovec *buf, int size)
2284
2285{
2286    prmsg (2,"SocketReadv(%d,%p,%d)\n", ciptr->fd, buf, size);
2287
2288#if XTRANS_SEND_FDS
2289    {
2290        union fd_pass   cmsgbuf;
2291        struct msghdr   msg = {
2292            .msg_name = NULL,
2293            .msg_namelen = 0,
2294            .msg_iov = buf,
2295            .msg_iovlen = size,
2296            .msg_control = cmsgbuf.buf,
2297            .msg_controllen = CMSG_LEN(MAX_FDS * sizeof(int))
2298        };
2299
2300        size = recvmsg(ciptr->fd, &msg, 0);
2301        if (size >= 0) {
2302            struct cmsghdr *hdr;
2303
2304            for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) {
2305                if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) {
2306                    int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int);
2307                    int i;
2308                    int *fd = (int *) CMSG_DATA(hdr);
2309
2310                    for (i = 0; i < nfd; i++)
2311                        appendFd(&ciptr->recv_fds, fd[i], 0);
2312                }
2313            }
2314        }
2315        return size;
2316    }
2317#else
2318    return READV (ciptr, buf, size);
2319#endif
2320}
2321
2322
2323static int
2324TRANS(SocketWritev) (XtransConnInfo ciptr, struct iovec *buf, int size)
2325
2326{
2327    prmsg (2,"SocketWritev(%d,%p,%d)\n", ciptr->fd, buf, size);
2328
2329#if XTRANS_SEND_FDS
2330    if (ciptr->send_fds)
2331    {
2332        union fd_pass           cmsgbuf;
2333        int                     nfd = nFd(&ciptr->send_fds);
2334        struct _XtransConnFd    *cf = ciptr->send_fds;
2335        struct msghdr           msg = {
2336            .msg_name = NULL,
2337            .msg_namelen = 0,
2338            .msg_iov = buf,
2339            .msg_iovlen = size,
2340            .msg_control = cmsgbuf.buf,
2341            .msg_controllen = CMSG_LEN(nfd * sizeof(int))
2342        };
2343        struct cmsghdr          *hdr = CMSG_FIRSTHDR(&msg);
2344        int                     i;
2345        int                     *fds;
2346
2347        hdr->cmsg_len = msg.msg_controllen;
2348        hdr->cmsg_level = SOL_SOCKET;
2349        hdr->cmsg_type = SCM_RIGHTS;
2350
2351        fds = (int *) CMSG_DATA(hdr);
2352        /* Set up fds */
2353        for (i = 0; i < nfd; i++) {
2354            fds[i] = cf->fd;
2355            cf = cf->next;
2356        }
2357
2358        i = sendmsg(ciptr->fd, &msg, 0);
2359        if (i > 0)
2360            discardFd(&ciptr->send_fds, cf, 0);
2361        return i;
2362    }
2363#endif
2364    return WRITEV (ciptr, buf, size);
2365}
2366
2367
2368static int
2369TRANS(SocketWrite) (XtransConnInfo ciptr, char *buf, int size)
2370
2371{
2372    prmsg (2,"SocketWrite(%d,%p,%d)\n", ciptr->fd, buf, size);
2373
2374#if defined(WIN32)
2375    {
2376	int ret = send ((SOCKET)ciptr->fd, buf, size, 0);
2377#ifdef WIN32
2378	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
2379#endif
2380	return ret;
2381    }
2382#else
2383#if XTRANS_SEND_FDS
2384    if (ciptr->send_fds)
2385    {
2386        struct iovec            iov;
2387
2388        iov.iov_base = buf;
2389        iov.iov_len = size;
2390        return TRANS(SocketWritev)(ciptr, &iov, 1);
2391    }
2392#endif /* XTRANS_SEND_FDS */
2393    return write (ciptr->fd, buf, size);
2394#endif /* WIN32 */
2395}
2396
2397static int
2398TRANS(SocketDisconnect) (XtransConnInfo ciptr)
2399
2400{
2401    prmsg (2,"SocketDisconnect(%p,%d)\n", ciptr, ciptr->fd);
2402
2403#ifdef WIN32
2404    {
2405	int ret = shutdown (ciptr->fd, 2);
2406	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
2407	return ret;
2408    }
2409#else
2410    return shutdown (ciptr->fd, 2); /* disallow further sends and receives */
2411#endif
2412}
2413
2414
2415#ifdef TCPCONN
2416static int
2417TRANS(SocketINETClose) (XtransConnInfo ciptr)
2418
2419{
2420    prmsg (2,"SocketINETClose(%p,%d)\n", ciptr, ciptr->fd);
2421
2422#ifdef WIN32
2423    {
2424	int ret = close (ciptr->fd);
2425	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
2426	return ret;
2427    }
2428#else
2429    return close (ciptr->fd);
2430#endif
2431}
2432
2433#endif /* TCPCONN */
2434
2435
2436#ifdef UNIXCONN
2437static int
2438TRANS(SocketUNIXClose) (XtransConnInfo ciptr)
2439{
2440    /*
2441     * If this is the server side, then once the socket is closed,
2442     * it must be unlinked to completely close it
2443     */
2444
2445    struct sockaddr_un	*sockname = (struct sockaddr_un *) ciptr->addr;
2446    int ret;
2447
2448    prmsg (2,"SocketUNIXClose(%p,%d)\n", ciptr, ciptr->fd);
2449
2450#if XTRANS_SEND_FDS
2451    cleanupFds(ciptr);
2452#endif
2453    ret = close(ciptr->fd);
2454
2455    if (ciptr->flags
2456       && sockname
2457       && sockname->sun_family == AF_UNIX
2458       && sockname->sun_path[0])
2459    {
2460	if (!(ciptr->flags & TRANS_NOUNLINK
2461	    || ciptr->transptr->flags & TRANS_ABSTRACT))
2462		unlink (sockname->sun_path);
2463    }
2464
2465    return ret;
2466}
2467
2468static int
2469TRANS(SocketUNIXCloseForCloning) (XtransConnInfo ciptr)
2470
2471{
2472    /*
2473     * Don't unlink path.
2474     */
2475
2476    int ret;
2477
2478    prmsg (2,"SocketUNIXCloseForCloning(%p,%d)\n",
2479	ciptr, ciptr->fd);
2480
2481#if XTRANS_SEND_FDS
2482    cleanupFds(ciptr);
2483#endif
2484    ret = close(ciptr->fd);
2485
2486    return ret;
2487}
2488
2489#endif /* UNIXCONN */
2490
2491
2492#ifdef TCPCONN
2493# ifdef TRANS_SERVER
2494static const char* tcp_nolisten[] = {
2495	"inet",
2496#if defined(IPv6) && defined(AF_INET6)
2497	"inet6",
2498#endif
2499	NULL
2500};
2501# endif
2502
2503Xtransport	TRANS(SocketTCPFuncs) = {
2504	/* Socket Interface */
2505	"tcp",
2506        TRANS_ALIAS,
2507#ifdef TRANS_CLIENT
2508	TRANS(SocketOpenCOTSClient),
2509#endif /* TRANS_CLIENT */
2510#ifdef TRANS_SERVER
2511	tcp_nolisten,
2512	TRANS(SocketOpenCOTSServer),
2513#endif /* TRANS_SERVER */
2514#ifdef TRANS_CLIENT
2515	TRANS(SocketOpenCLTSClient),
2516#endif /* TRANS_CLIENT */
2517#ifdef TRANS_SERVER
2518	TRANS(SocketOpenCLTSServer),
2519#endif /* TRANS_SERVER */
2520#ifdef TRANS_REOPEN
2521	TRANS(SocketReopenCOTSServer),
2522	TRANS(SocketReopenCLTSServer),
2523#endif
2524	TRANS(SocketSetOption),
2525#ifdef TRANS_SERVER
2526	TRANS(SocketINETCreateListener),
2527	NULL,		       			/* ResetListener */
2528	TRANS(SocketINETAccept),
2529#endif /* TRANS_SERVER */
2530#ifdef TRANS_CLIENT
2531	TRANS(SocketINETConnect),
2532#endif /* TRANS_CLIENT */
2533	TRANS(SocketBytesReadable),
2534	TRANS(SocketRead),
2535	TRANS(SocketWrite),
2536	TRANS(SocketReadv),
2537	TRANS(SocketWritev),
2538#if XTRANS_SEND_FDS
2539        TRANS(SocketSendFdInvalid),
2540        TRANS(SocketRecvFdInvalid),
2541#endif
2542	TRANS(SocketDisconnect),
2543	TRANS(SocketINETClose),
2544	TRANS(SocketINETClose),
2545	};
2546
2547Xtransport	TRANS(SocketINETFuncs) = {
2548	/* Socket Interface */
2549	"inet",
2550	0,
2551#ifdef TRANS_CLIENT
2552	TRANS(SocketOpenCOTSClient),
2553#endif /* TRANS_CLIENT */
2554#ifdef TRANS_SERVER
2555	NULL,
2556	TRANS(SocketOpenCOTSServer),
2557#endif /* TRANS_SERVER */
2558#ifdef TRANS_CLIENT
2559	TRANS(SocketOpenCLTSClient),
2560#endif /* TRANS_CLIENT */
2561#ifdef TRANS_SERVER
2562	TRANS(SocketOpenCLTSServer),
2563#endif /* TRANS_SERVER */
2564#ifdef TRANS_REOPEN
2565	TRANS(SocketReopenCOTSServer),
2566	TRANS(SocketReopenCLTSServer),
2567#endif
2568	TRANS(SocketSetOption),
2569#ifdef TRANS_SERVER
2570	TRANS(SocketINETCreateListener),
2571	NULL,		       			/* ResetListener */
2572	TRANS(SocketINETAccept),
2573#endif /* TRANS_SERVER */
2574#ifdef TRANS_CLIENT
2575	TRANS(SocketINETConnect),
2576#endif /* TRANS_CLIENT */
2577	TRANS(SocketBytesReadable),
2578	TRANS(SocketRead),
2579	TRANS(SocketWrite),
2580	TRANS(SocketReadv),
2581	TRANS(SocketWritev),
2582#if XTRANS_SEND_FDS
2583        TRANS(SocketSendFdInvalid),
2584        TRANS(SocketRecvFdInvalid),
2585#endif
2586	TRANS(SocketDisconnect),
2587	TRANS(SocketINETClose),
2588	TRANS(SocketINETClose),
2589	};
2590
2591#if defined(IPv6) && defined(AF_INET6)
2592Xtransport     TRANS(SocketINET6Funcs) = {
2593	/* Socket Interface */
2594	"inet6",
2595	0,
2596#ifdef TRANS_CLIENT
2597	TRANS(SocketOpenCOTSClient),
2598#endif /* TRANS_CLIENT */
2599#ifdef TRANS_SERVER
2600	NULL,
2601	TRANS(SocketOpenCOTSServer),
2602#endif /* TRANS_SERVER */
2603#ifdef TRANS_CLIENT
2604	TRANS(SocketOpenCLTSClient),
2605#endif /* TRANS_CLIENT */
2606#ifdef TRANS_SERVER
2607	TRANS(SocketOpenCLTSServer),
2608#endif /* TRANS_SERVER */
2609#ifdef TRANS_REOPEN
2610	TRANS(SocketReopenCOTSServer),
2611	TRANS(SocketReopenCLTSServer),
2612#endif
2613	TRANS(SocketSetOption),
2614#ifdef TRANS_SERVER
2615	TRANS(SocketINETCreateListener),
2616	NULL,					/* ResetListener */
2617	TRANS(SocketINETAccept),
2618#endif /* TRANS_SERVER */
2619#ifdef TRANS_CLIENT
2620	TRANS(SocketINETConnect),
2621#endif /* TRANS_CLIENT */
2622	TRANS(SocketBytesReadable),
2623	TRANS(SocketRead),
2624	TRANS(SocketWrite),
2625	TRANS(SocketReadv),
2626	TRANS(SocketWritev),
2627#if XTRANS_SEND_FDS
2628        TRANS(SocketSendFdInvalid),
2629        TRANS(SocketRecvFdInvalid),
2630#endif
2631	TRANS(SocketDisconnect),
2632	TRANS(SocketINETClose),
2633	TRANS(SocketINETClose),
2634	};
2635#endif /* IPv6 */
2636#endif /* TCPCONN */
2637
2638#ifdef UNIXCONN
2639#if !defined(LOCALCONN)
2640Xtransport	TRANS(SocketLocalFuncs) = {
2641	/* Socket Interface */
2642	"local",
2643#ifdef HAVE_ABSTRACT_SOCKETS
2644	TRANS_ABSTRACT,
2645#else
2646	0,
2647#endif
2648#ifdef TRANS_CLIENT
2649	TRANS(SocketOpenCOTSClient),
2650#endif /* TRANS_CLIENT */
2651#ifdef TRANS_SERVER
2652	NULL,
2653	TRANS(SocketOpenCOTSServer),
2654#endif /* TRANS_SERVER */
2655#ifdef TRANS_CLIENT
2656	TRANS(SocketOpenCLTSClient),
2657#endif /* TRANS_CLIENT */
2658#ifdef TRANS_SERVER
2659	TRANS(SocketOpenCLTSServer),
2660#endif /* TRANS_SERVER */
2661#ifdef TRANS_REOPEN
2662	TRANS(SocketReopenCOTSServer),
2663	TRANS(SocketReopenCLTSServer),
2664#endif
2665	TRANS(SocketSetOption),
2666#ifdef TRANS_SERVER
2667	TRANS(SocketUNIXCreateListener),
2668	TRANS(SocketUNIXResetListener),
2669	TRANS(SocketUNIXAccept),
2670#endif /* TRANS_SERVER */
2671#ifdef TRANS_CLIENT
2672	TRANS(SocketUNIXConnect),
2673#endif /* TRANS_CLIENT */
2674	TRANS(SocketBytesReadable),
2675	TRANS(SocketRead),
2676	TRANS(SocketWrite),
2677	TRANS(SocketReadv),
2678	TRANS(SocketWritev),
2679#if XTRANS_SEND_FDS
2680        TRANS(SocketSendFd),
2681        TRANS(SocketRecvFd),
2682#endif
2683	TRANS(SocketDisconnect),
2684	TRANS(SocketUNIXClose),
2685	TRANS(SocketUNIXCloseForCloning),
2686	};
2687#endif /* !LOCALCONN */
2688# ifdef TRANS_SERVER
2689#  if !defined(LOCALCONN)
2690static const char* unix_nolisten[] = { "local" , NULL };
2691#  endif
2692# endif
2693
2694Xtransport	TRANS(SocketUNIXFuncs) = {
2695	/* Socket Interface */
2696	"unix",
2697#if !defined(LOCALCONN) && !defined(HAVE_ABSTRACT_SOCKETS)
2698        TRANS_ALIAS,
2699#else
2700	0,
2701#endif
2702#ifdef TRANS_CLIENT
2703	TRANS(SocketOpenCOTSClient),
2704#endif /* TRANS_CLIENT */
2705#ifdef TRANS_SERVER
2706#if !defined(LOCALCONN)
2707	unix_nolisten,
2708#else
2709	NULL,
2710#endif
2711	TRANS(SocketOpenCOTSServer),
2712#endif /* TRANS_SERVER */
2713#ifdef TRANS_CLIENT
2714	TRANS(SocketOpenCLTSClient),
2715#endif /* TRANS_CLIENT */
2716#ifdef TRANS_SERVER
2717	TRANS(SocketOpenCLTSServer),
2718#endif /* TRANS_SERVER */
2719#ifdef TRANS_REOPEN
2720	TRANS(SocketReopenCOTSServer),
2721	TRANS(SocketReopenCLTSServer),
2722#endif
2723	TRANS(SocketSetOption),
2724#ifdef TRANS_SERVER
2725	TRANS(SocketUNIXCreateListener),
2726	TRANS(SocketUNIXResetListener),
2727	TRANS(SocketUNIXAccept),
2728#endif /* TRANS_SERVER */
2729#ifdef TRANS_CLIENT
2730	TRANS(SocketUNIXConnect),
2731#endif /* TRANS_CLIENT */
2732	TRANS(SocketBytesReadable),
2733	TRANS(SocketRead),
2734	TRANS(SocketWrite),
2735	TRANS(SocketReadv),
2736	TRANS(SocketWritev),
2737#if XTRANS_SEND_FDS
2738        TRANS(SocketSendFd),
2739        TRANS(SocketRecvFd),
2740#endif
2741	TRANS(SocketDisconnect),
2742	TRANS(SocketUNIXClose),
2743	TRANS(SocketUNIXCloseForCloning),
2744	};
2745
2746#endif /* UNIXCONN */
2747