Xtranssock.c revision fe567363
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    return ciptr;
449}
450
451
452#ifdef TRANS_REOPEN
453
454static XtransConnInfo
455TRANS(SocketReopen) (int i _X_UNUSED, int type, int fd, char *port)
456
457{
458    XtransConnInfo	ciptr;
459    int portlen;
460    struct sockaddr *addr;
461    size_t addrlen;
462
463    prmsg (3,"SocketReopen(%d,%d,%s)\n", type, fd, port);
464
465    if (port == NULL) {
466      prmsg (1, "SocketReopen: port was null!\n");
467      return NULL;
468    }
469
470    portlen = strlen(port) + 1; // include space for trailing null
471#ifdef SOCK_MAXADDRLEN
472    if (portlen < 0 || portlen > (SOCK_MAXADDRLEN + 2)) {
473      prmsg (1, "SocketReopen: invalid portlen %d\n", portlen);
474      return NULL;
475    }
476    if (portlen < 14) portlen = 14;
477#else
478    if (portlen < 0 || portlen > 14) {
479      prmsg (1, "SocketReopen: invalid portlen %d\n", portlen);
480      return NULL;
481    }
482#endif /*SOCK_MAXADDRLEN*/
483
484    if ((ciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
485    {
486	prmsg (1, "SocketReopen: malloc(ciptr) failed\n");
487	return NULL;
488    }
489
490    ciptr->fd = fd;
491
492    addrlen = portlen + offsetof(struct sockaddr, sa_data);
493    if ((addr = calloc (1, addrlen)) == NULL) {
494	prmsg (1, "SocketReopen: malloc(addr) failed\n");
495	free (ciptr);
496	return NULL;
497    }
498    ciptr->addr = (char *) addr;
499    ciptr->addrlen = addrlen;
500
501    if ((ciptr->peeraddr = calloc (1, addrlen)) == NULL) {
502	prmsg (1, "SocketReopen: malloc(portaddr) failed\n");
503	free (addr);
504	free (ciptr);
505	return NULL;
506    }
507    ciptr->peeraddrlen = addrlen;
508
509    /* Initialize ciptr structure as if it were a normally-opened unix socket */
510    ciptr->flags = TRANS_LOCAL | TRANS_NOUNLINK;
511#ifdef BSD44SOCKETS
512    addr->sa_len = addrlen;
513#endif
514    addr->sa_family = AF_UNIX;
515#ifdef HAS_STRLCPY
516    strlcpy(addr->sa_data, port, portlen);
517#else
518    strncpy(addr->sa_data, port, portlen);
519#endif
520    ciptr->family = AF_UNIX;
521    memcpy(ciptr->peeraddr, ciptr->addr, addrlen);
522    ciptr->port = rindex(addr->sa_data, ':');
523    if (ciptr->port == NULL) {
524	if (is_numeric(addr->sa_data)) {
525	    ciptr->port = addr->sa_data;
526	}
527    } else if (ciptr->port[0] == ':') {
528	ciptr->port++;
529    }
530    /* port should now point to portnum or NULL */
531    return ciptr;
532}
533
534#endif /* TRANS_REOPEN */
535
536
537/*
538 * These functions are the interface supplied in the Xtransport structure
539 */
540
541#ifdef TRANS_CLIENT
542
543static XtransConnInfo
544TRANS(SocketOpenCOTSClientBase) (const char *transname, const char *protocol,
545			   const char *host, const char *port, int previndex)
546{
547    XtransConnInfo	ciptr;
548    int			i = previndex;
549
550    prmsg (2, "SocketOpenCOTSClient(%s,%s,%s)\n",
551	protocol, host, port);
552
553    SocketInitOnce();
554
555    while ((i = TRANS(SocketSelectFamily) (i, transname)) >= 0) {
556	if ((ciptr = TRANS(SocketOpen) (
557		i, Sockettrans2devtab[i].devcotsname)) != NULL) {
558	    /* Save the index for later use */
559
560	    ciptr->index = i;
561	    break;
562	}
563    }
564    if (i < 0) {
565	if (i == -1)
566	    prmsg (1,"SocketOpenCOTSClient: Unable to open socket for %s\n",
567		   transname);
568	else
569	    prmsg (1,"SocketOpenCOTSClient: Unable to determine socket type for %s\n",
570		   transname);
571	return NULL;
572    }
573
574    return ciptr;
575}
576
577static XtransConnInfo
578TRANS(SocketOpenCOTSClient) (Xtransport *thistrans, char *protocol,
579			     char *host, char *port)
580{
581    return TRANS(SocketOpenCOTSClientBase)(
582			thistrans->TransName, protocol, host, port, -1);
583}
584
585
586#endif /* TRANS_CLIENT */
587
588
589#ifdef TRANS_SERVER
590
591static XtransConnInfo
592TRANS(SocketOpenCOTSServer) (Xtransport *thistrans, char *protocol,
593			     char *host, char *port)
594
595{
596    XtransConnInfo	ciptr;
597    int	i = -1;
598
599    prmsg (2,"SocketOpenCOTSServer(%s,%s,%s)\n", protocol, host, port);
600
601    SocketInitOnce();
602
603    while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
604	if ((ciptr = TRANS(SocketOpen) (
605		 i, Sockettrans2devtab[i].devcotsname)) != NULL)
606	    break;
607    }
608    if (i < 0) {
609	if (i == -1)
610	    prmsg (1,"SocketOpenCOTSServer: Unable to open socket for %s\n",
611		   thistrans->TransName);
612	else
613	    prmsg (1,"SocketOpenCOTSServer: Unable to determine socket type for %s\n",
614		   thistrans->TransName);
615	return NULL;
616    }
617
618    /*
619     * Using this prevents the bind() check for an existing server listening
620     * on the same port, but it is required for other reasons.
621     */
622#ifdef SO_REUSEADDR
623
624    /*
625     * SO_REUSEADDR only applied to AF_INET && AF_INET6
626     */
627
628    if (Sockettrans2devtab[i].family == AF_INET
629#if defined(IPv6) && defined(AF_INET6)
630      || Sockettrans2devtab[i].family == AF_INET6
631#endif
632    )
633    {
634	int one = 1;
635	setsockopt (ciptr->fd, SOL_SOCKET, SO_REUSEADDR,
636		    (char *) &one, sizeof (int));
637    }
638#endif
639#ifdef IPV6_V6ONLY
640    if (Sockettrans2devtab[i].family == AF_INET6)
641    {
642	int one = 1;
643	setsockopt(ciptr->fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(int));
644    }
645#endif
646    /* Save the index for later use */
647
648    ciptr->index = i;
649
650    return ciptr;
651}
652
653#endif /* TRANS_SERVER */
654
655
656#ifdef TRANS_CLIENT
657
658static XtransConnInfo
659TRANS(SocketOpenCLTSClient) (Xtransport *thistrans, char *protocol,
660			     char *host, char *port)
661
662{
663    XtransConnInfo	ciptr;
664    int			i = -1;
665
666    prmsg (2,"SocketOpenCLTSClient(%s,%s,%s)\n", protocol, host, port);
667
668    SocketInitOnce();
669
670    while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
671	if ((ciptr = TRANS(SocketOpen) (
672		 i, Sockettrans2devtab[i].devcotsname)) != NULL)
673	    break;
674    }
675    if (i < 0) {
676	if (i == -1)
677	    prmsg (1,"SocketOpenCLTSClient: Unable to open socket for %s\n",
678		   thistrans->TransName);
679	else
680	    prmsg (1,"SocketOpenCLTSClient: Unable to determine socket type for %s\n",
681		   thistrans->TransName);
682	return NULL;
683    }
684
685    /* Save the index for later use */
686
687    ciptr->index = i;
688
689    return ciptr;
690}
691
692#endif /* TRANS_CLIENT */
693
694
695#ifdef TRANS_SERVER
696
697static XtransConnInfo
698TRANS(SocketOpenCLTSServer) (Xtransport *thistrans, char *protocol,
699			     char *host, char *port)
700
701{
702    XtransConnInfo	ciptr;
703    int	i = -1;
704
705    prmsg (2,"SocketOpenCLTSServer(%s,%s,%s)\n", protocol, host, port);
706
707    SocketInitOnce();
708
709    while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
710	if ((ciptr = TRANS(SocketOpen) (
711		 i, Sockettrans2devtab[i].devcotsname)) != NULL)
712	    break;
713    }
714    if (i < 0) {
715	if (i == -1)
716	    prmsg (1,"SocketOpenCLTSServer: Unable to open socket for %s\n",
717		   thistrans->TransName);
718	else
719	    prmsg (1,"SocketOpenCLTSServer: Unable to determine socket type for %s\n",
720		   thistrans->TransName);
721	return NULL;
722    }
723
724#ifdef IPV6_V6ONLY
725    if (Sockettrans2devtab[i].family == AF_INET6)
726    {
727	int one = 1;
728	setsockopt(ciptr->fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(int));
729    }
730#endif
731    /* Save the index for later use */
732
733    ciptr->index = i;
734
735    return ciptr;
736}
737
738#endif /* TRANS_SERVER */
739
740
741#ifdef TRANS_REOPEN
742
743static XtransConnInfo
744TRANS(SocketReopenCOTSServer) (Xtransport *thistrans, int fd, char *port)
745
746{
747    XtransConnInfo	ciptr;
748    int			i = -1;
749
750    prmsg (2,
751	"SocketReopenCOTSServer(%d, %s)\n", fd, port);
752
753    SocketInitOnce();
754
755    while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
756	if ((ciptr = TRANS(SocketReopen) (
757		 i, Sockettrans2devtab[i].devcotsname, fd, port)) != NULL)
758	    break;
759    }
760    if (i < 0) {
761	if (i == -1)
762	    prmsg (1,"SocketReopenCOTSServer: Unable to open socket for %s\n",
763		   thistrans->TransName);
764	else
765	    prmsg (1,"SocketReopenCOTSServer: Unable to determine socket type for %s\n",
766		   thistrans->TransName);
767	return NULL;
768    }
769
770    /* Save the index for later use */
771
772    ciptr->index = i;
773
774    return ciptr;
775}
776
777static XtransConnInfo
778TRANS(SocketReopenCLTSServer) (Xtransport *thistrans, int fd, char *port)
779
780{
781    XtransConnInfo	ciptr;
782    int			i = -1;
783
784    prmsg (2,
785	"SocketReopenCLTSServer(%d, %s)\n", fd, port);
786
787    SocketInitOnce();
788
789    while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) {
790	if ((ciptr = TRANS(SocketReopen) (
791		 i, Sockettrans2devtab[i].devcotsname, fd, port)) != NULL)
792	    break;
793    }
794    if (i < 0) {
795	if (i == -1)
796	    prmsg (1,"SocketReopenCLTSServer: Unable to open socket for %s\n",
797		   thistrans->TransName);
798	else
799	    prmsg (1,"SocketReopenCLTSServer: Unable to determine socket type for %s\n",
800		   thistrans->TransName);
801	return NULL;
802    }
803
804    /* Save the index for later use */
805
806    ciptr->index = i;
807
808    return ciptr;
809}
810
811#endif /* TRANS_REOPEN */
812
813
814static int
815TRANS(SocketSetOption) (XtransConnInfo ciptr, int option, int arg)
816
817{
818    prmsg (2,"SocketSetOption(%d,%d,%d)\n", ciptr->fd, option, arg);
819
820    return -1;
821}
822
823#ifdef UNIXCONN
824static int
825set_sun_path(const char *port, const char *upath, char *path, int abstract)
826{
827    struct sockaddr_un s;
828    int maxlen = sizeof(s.sun_path) - 1;
829    const char *at = "";
830
831    if (!port || !*port || !path)
832	return -1;
833
834#ifdef HAVE_ABSTRACT_SOCKETS
835    if (port[0] == '@')
836	upath = "";
837    else if (abstract)
838	at = "@";
839#endif
840
841    if (*port == '/') /* a full pathname */
842	upath = "";
843
844    if (strlen(port) + strlen(upath) > maxlen)
845	return -1;
846    snprintf(path, sizeof(s.sun_path), "%s%s%s", at, upath, port);
847    return 0;
848}
849#endif
850
851#ifdef TRANS_SERVER
852
853static int
854TRANS(SocketCreateListener) (XtransConnInfo ciptr,
855			     struct sockaddr *sockname,
856			     int socknamelen, unsigned int flags)
857
858{
859    SOCKLEN_T namelen = socknamelen;
860    int	fd = ciptr->fd;
861    int	retry;
862
863    prmsg (3, "SocketCreateListener(%p,%d)\n", ciptr, fd);
864
865    if (Sockettrans2devtab[ciptr->index].family == AF_INET
866#if defined(IPv6) && defined(AF_INET6)
867      || Sockettrans2devtab[ciptr->index].family == AF_INET6
868#endif
869	)
870	retry = 20;
871    else
872	retry = 0;
873
874    while (bind (fd, (struct sockaddr *) sockname, namelen) < 0)
875    {
876	if (errno == EADDRINUSE) {
877	    if (flags & ADDR_IN_USE_ALLOWED)
878		break;
879	    else
880		return TRANS_ADDR_IN_USE;
881	}
882
883	if (retry-- == 0) {
884	    prmsg (1, "SocketCreateListener: failed to bind listener\n");
885	    close (fd);
886	    return TRANS_CREATE_LISTENER_FAILED;
887	}
888#ifdef SO_REUSEADDR
889	sleep (1);
890#else
891	sleep (10);
892#endif /* SO_REUSEDADDR */
893    }
894
895    if (Sockettrans2devtab[ciptr->index].family == AF_INET
896#if defined(IPv6) && defined(AF_INET6)
897      || Sockettrans2devtab[ciptr->index].family == AF_INET6
898#endif
899	) {
900#ifdef SO_DONTLINGER
901	setsockopt (fd, SOL_SOCKET, SO_DONTLINGER, (char *) NULL, 0);
902#else
903#ifdef SO_LINGER
904    {
905	static int linger[2] = { 0, 0 };
906	setsockopt (fd, SOL_SOCKET, SO_LINGER,
907		(char *) linger, sizeof (linger));
908    }
909#endif
910#endif
911}
912
913    if (listen (fd, BACKLOG) < 0)
914    {
915	prmsg (1, "SocketCreateListener: listen() failed\n");
916	close (fd);
917	return TRANS_CREATE_LISTENER_FAILED;
918    }
919
920    /* Set a flag to indicate that this connection is a listener */
921
922    ciptr->flags = 1 | (ciptr->flags & TRANS_KEEPFLAGS);
923
924    return 0;
925}
926
927#ifdef TCPCONN
928static int
929TRANS(SocketINETCreateListener) (XtransConnInfo ciptr, char *port, unsigned int flags)
930
931{
932#if defined(IPv6) && defined(AF_INET6)
933    struct sockaddr_storage sockname;
934#else
935    struct sockaddr_in	    sockname;
936#endif
937    unsigned short	    sport;
938    SOCKLEN_T	namelen = sizeof(sockname);
939    int		status;
940    long	tmpport;
941#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
942    _Xgetservbynameparams sparams;
943#endif
944    struct servent *servp;
945
946#ifdef X11_t
947    char	portbuf[PORTBUFSIZE];
948#endif
949
950    prmsg (2, "SocketINETCreateListener(%s)\n", port);
951
952#ifdef X11_t
953    /*
954     * X has a well known port, that is transport dependent. It is easier
955     * to handle it here, than try and come up with a transport independent
956     * representation that can be passed in and resolved the usual way.
957     *
958     * The port that is passed here is really a string containing the idisplay
959     * from ConnectDisplay().
960     */
961
962    if (is_numeric (port))
963    {
964	/* fixup the server port address */
965	tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10);
966	snprintf (portbuf, sizeof(portbuf), "%lu", tmpport);
967	port = portbuf;
968    }
969#endif
970
971    if (port && *port)
972    {
973	/* Check to see if the port string is just a number (handles X11) */
974
975	if (!is_numeric (port))
976	{
977	    if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL)
978	    {
979		prmsg (1,
980	     "SocketINETCreateListener: Unable to get service for %s\n",
981		      port);
982		return TRANS_CREATE_LISTENER_FAILED;
983	    }
984	    /* we trust getservbyname to return a valid number */
985	    sport = servp->s_port;
986	}
987	else
988	{
989	    tmpport = strtol (port, (char**)NULL, 10);
990	    /*
991	     * check that somehow the port address isn't negative or in
992	     * the range of reserved port addresses. This can happen and
993	     * be very bad if the server is suid-root and the user does
994	     * something (dumb) like `X :60049`.
995	     */
996	    if (tmpport < 1024 || tmpport > USHRT_MAX)
997		return TRANS_CREATE_LISTENER_FAILED;
998
999	    sport = (unsigned short) tmpport;
1000	}
1001    }
1002    else
1003	sport = 0;
1004
1005    bzero(&sockname, sizeof(sockname));
1006#if defined(IPv6) && defined(AF_INET6)
1007    if (Sockettrans2devtab[ciptr->index].family == AF_INET) {
1008	namelen = sizeof (struct sockaddr_in);
1009#ifdef BSD44SOCKETS
1010	((struct sockaddr_in *)&sockname)->sin_len = namelen;
1011#endif
1012	((struct sockaddr_in *)&sockname)->sin_family = AF_INET;
1013	((struct sockaddr_in *)&sockname)->sin_port = htons(sport);
1014	((struct sockaddr_in *)&sockname)->sin_addr.s_addr = htonl(INADDR_ANY);
1015    } else {
1016	namelen = sizeof (struct sockaddr_in6);
1017#ifdef SIN6_LEN
1018	((struct sockaddr_in6 *)&sockname)->sin6_len = sizeof(sockname);
1019#endif
1020	((struct sockaddr_in6 *)&sockname)->sin6_family = AF_INET6;
1021	((struct sockaddr_in6 *)&sockname)->sin6_port = htons(sport);
1022	((struct sockaddr_in6 *)&sockname)->sin6_addr = in6addr_any;
1023    }
1024#else
1025#ifdef BSD44SOCKETS
1026    sockname.sin_len = sizeof (sockname);
1027#endif
1028    sockname.sin_family = AF_INET;
1029    sockname.sin_port = htons (sport);
1030    sockname.sin_addr.s_addr = htonl (INADDR_ANY);
1031#endif
1032
1033    if ((status = TRANS(SocketCreateListener) (ciptr,
1034	(struct sockaddr *) &sockname, namelen, flags)) < 0)
1035    {
1036	prmsg (1,
1037    "SocketINETCreateListener: ...SocketCreateListener() failed\n");
1038	return status;
1039    }
1040
1041    if (TRANS(SocketINETGetAddr) (ciptr) < 0)
1042    {
1043	prmsg (1,
1044       "SocketINETCreateListener: ...SocketINETGetAddr() failed\n");
1045	return TRANS_CREATE_LISTENER_FAILED;
1046    }
1047
1048    return 0;
1049}
1050
1051#endif /* TCPCONN */
1052
1053
1054#ifdef UNIXCONN
1055
1056static int
1057TRANS(SocketUNIXCreateListener) (XtransConnInfo ciptr, char *port,
1058				 unsigned int flags)
1059
1060{
1061    struct sockaddr_un	sockname;
1062    int			namelen;
1063    int			oldUmask;
1064    int			status;
1065    unsigned int	mode;
1066    char		tmpport[108];
1067
1068    int			abstract = 0;
1069#ifdef HAVE_ABSTRACT_SOCKETS
1070    abstract = ciptr->transptr->flags & TRANS_ABSTRACT;
1071#endif
1072
1073    prmsg (2, "SocketUNIXCreateListener(%s)\n",
1074	port ? port : "NULL");
1075
1076    /* Make sure the directory is created */
1077
1078    oldUmask = umask (0);
1079
1080#ifdef UNIX_DIR
1081#ifdef HAS_STICKY_DIR_BIT
1082    mode = 01777;
1083#else
1084    mode = 0777;
1085#endif
1086    if (!abstract && trans_mkdir(UNIX_DIR, mode) == -1) {
1087	prmsg (1, "SocketUNIXCreateListener: mkdir(%s) failed, errno = %d\n",
1088	       UNIX_DIR, errno);
1089	(void) umask (oldUmask);
1090	return TRANS_CREATE_LISTENER_FAILED;
1091    }
1092#endif
1093
1094    memset(&sockname, 0, sizeof(sockname));
1095    sockname.sun_family = AF_UNIX;
1096
1097    if (!(port && *port)) {
1098	snprintf (tmpport, sizeof(tmpport), "%s%ld", UNIX_PATH, (long)getpid());
1099	port = tmpport;
1100    }
1101    if (set_sun_path(port, UNIX_PATH, sockname.sun_path, abstract) != 0) {
1102	prmsg (1, "SocketUNIXCreateListener: path too long\n");
1103	return TRANS_CREATE_LISTENER_FAILED;
1104    }
1105
1106#if (defined(BSD44SOCKETS) || defined(__UNIXWARE__))
1107    sockname.sun_len = strlen(sockname.sun_path);
1108#endif
1109
1110#if defined(BSD44SOCKETS) || defined(SUN_LEN)
1111    namelen = SUN_LEN(&sockname);
1112#else
1113    namelen = strlen(sockname.sun_path) + offsetof(struct sockaddr_un, sun_path);
1114#endif
1115
1116    if (abstract) {
1117	sockname.sun_path[0] = '\0';
1118	namelen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&sockname.sun_path[1]);
1119    }
1120    else
1121	unlink (sockname.sun_path);
1122
1123    if ((status = TRANS(SocketCreateListener) (ciptr,
1124	(struct sockaddr *) &sockname, namelen, flags)) < 0)
1125    {
1126	prmsg (1,
1127    "SocketUNIXCreateListener: ...SocketCreateListener() failed\n");
1128	(void) umask (oldUmask);
1129	return status;
1130    }
1131
1132    /*
1133     * Now that the listener is esablished, create the addr info for
1134     * this connection. getpeername() doesn't work for UNIX Domain Sockets
1135     * on some systems (hpux at least), so we will just do it manually, instead
1136     * of calling something like TRANS(SocketUNIXGetAddr).
1137     */
1138
1139    namelen = sizeof (sockname); /* this will always make it the same size */
1140
1141    if ((ciptr->addr = malloc (namelen)) == NULL)
1142    {
1143        prmsg (1,
1144        "SocketUNIXCreateListener: Can't allocate space for the addr\n");
1145	(void) umask (oldUmask);
1146        return TRANS_CREATE_LISTENER_FAILED;
1147    }
1148
1149    if (abstract)
1150	sockname.sun_path[0] = '@';
1151
1152    ciptr->family = sockname.sun_family;
1153    ciptr->addrlen = namelen;
1154    memcpy (ciptr->addr, &sockname, ciptr->addrlen);
1155
1156    (void) umask (oldUmask);
1157
1158    return 0;
1159}
1160
1161
1162static int
1163TRANS(SocketUNIXResetListener) (XtransConnInfo ciptr)
1164
1165{
1166    /*
1167     * See if the unix domain socket has disappeared.  If it has, recreate it.
1168     */
1169
1170    struct sockaddr_un 	*unsock = (struct sockaddr_un *) ciptr->addr;
1171    struct stat		statb;
1172    int 		status = TRANS_RESET_NOOP;
1173    unsigned int	mode;
1174    int abstract = 0;
1175#ifdef HAVE_ABSTRACT_SOCKETS
1176    abstract = ciptr->transptr->flags & TRANS_ABSTRACT;
1177#endif
1178
1179    prmsg (3, "SocketUNIXResetListener(%p,%d)\n", ciptr, ciptr->fd);
1180
1181    if (!abstract && (
1182	stat (unsock->sun_path, &statb) == -1 ||
1183        ((statb.st_mode & S_IFMT) !=
1184#if defined(NCR) || defined(SCO325) || !defined(S_IFSOCK)
1185	  		S_IFIFO
1186#else
1187			S_IFSOCK
1188#endif
1189				)))
1190    {
1191	int oldUmask = umask (0);
1192
1193#ifdef UNIX_DIR
1194#ifdef HAS_STICKY_DIR_BIT
1195	mode = 01777;
1196#else
1197	mode = 0777;
1198#endif
1199        if (trans_mkdir(UNIX_DIR, mode) == -1) {
1200            prmsg (1, "SocketUNIXResetListener: mkdir(%s) failed, errno = %d\n",
1201	    UNIX_DIR, errno);
1202	    (void) umask (oldUmask);
1203	    return TRANS_RESET_FAILURE;
1204        }
1205#endif
1206
1207	close (ciptr->fd);
1208	unlink (unsock->sun_path);
1209
1210	if ((ciptr->fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
1211	{
1212	    TRANS(FreeConnInfo) (ciptr);
1213	    (void) umask (oldUmask);
1214	    return TRANS_RESET_FAILURE;
1215	}
1216
1217	if (bind (ciptr->fd, (struct sockaddr *) unsock, ciptr->addrlen) < 0)
1218	{
1219	    close (ciptr->fd);
1220	    TRANS(FreeConnInfo) (ciptr);
1221	    return TRANS_RESET_FAILURE;
1222	}
1223
1224	if (listen (ciptr->fd, BACKLOG) < 0)
1225	{
1226	    close (ciptr->fd);
1227	    TRANS(FreeConnInfo) (ciptr);
1228	    (void) umask (oldUmask);
1229	    return TRANS_RESET_FAILURE;
1230	}
1231
1232	umask (oldUmask);
1233
1234	status = TRANS_RESET_NEW_FD;
1235    }
1236
1237    return status;
1238}
1239
1240#endif /* UNIXCONN */
1241
1242
1243#ifdef TCPCONN
1244
1245static XtransConnInfo
1246TRANS(SocketINETAccept) (XtransConnInfo ciptr, int *status)
1247
1248{
1249    XtransConnInfo	newciptr;
1250    struct sockaddr_in	sockname;
1251    SOCKLEN_T		namelen = sizeof(sockname);
1252
1253    prmsg (2, "SocketINETAccept(%p,%d)\n", ciptr, ciptr->fd);
1254
1255    if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
1256    {
1257	prmsg (1, "SocketINETAccept: malloc failed\n");
1258	*status = TRANS_ACCEPT_BAD_MALLOC;
1259	return NULL;
1260    }
1261
1262    if ((newciptr->fd = accept (ciptr->fd,
1263	(struct sockaddr *) &sockname, (void *)&namelen)) < 0)
1264    {
1265#ifdef WIN32
1266	errno = WSAGetLastError();
1267#endif
1268	prmsg (1, "SocketINETAccept: accept() failed\n");
1269	free (newciptr);
1270	*status = TRANS_ACCEPT_FAILED;
1271	return NULL;
1272    }
1273
1274#ifdef TCP_NODELAY
1275    {
1276	/*
1277	 * turn off TCP coalescence for INET sockets
1278	 */
1279
1280	int tmp = 1;
1281	setsockopt (newciptr->fd, IPPROTO_TCP, TCP_NODELAY,
1282	    (char *) &tmp, sizeof (int));
1283    }
1284#endif
1285
1286    /*
1287     * Get this address again because the transport may give a more
1288     * specific address now that a connection is established.
1289     */
1290
1291    if (TRANS(SocketINETGetAddr) (newciptr) < 0)
1292    {
1293	prmsg (1,
1294	    "SocketINETAccept: ...SocketINETGetAddr() failed:\n");
1295	close (newciptr->fd);
1296	free (newciptr);
1297	*status = TRANS_ACCEPT_MISC_ERROR;
1298        return NULL;
1299    }
1300
1301    if (TRANS(SocketINETGetPeerAddr) (newciptr) < 0)
1302    {
1303	prmsg (1,
1304	  "SocketINETAccept: ...SocketINETGetPeerAddr() failed:\n");
1305	close (newciptr->fd);
1306	if (newciptr->addr) free (newciptr->addr);
1307	free (newciptr);
1308	*status = TRANS_ACCEPT_MISC_ERROR;
1309        return NULL;
1310    }
1311
1312    *status = 0;
1313
1314    return newciptr;
1315}
1316
1317#endif /* TCPCONN */
1318
1319
1320#ifdef UNIXCONN
1321static XtransConnInfo
1322TRANS(SocketUNIXAccept) (XtransConnInfo ciptr, int *status)
1323
1324{
1325    XtransConnInfo	newciptr;
1326    struct sockaddr_un	sockname;
1327    SOCKLEN_T 		namelen = sizeof sockname;
1328
1329    prmsg (2, "SocketUNIXAccept(%p,%d)\n", ciptr, ciptr->fd);
1330
1331    if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL)
1332    {
1333	prmsg (1, "SocketUNIXAccept: malloc() failed\n");
1334	*status = TRANS_ACCEPT_BAD_MALLOC;
1335	return NULL;
1336    }
1337
1338    if ((newciptr->fd = accept (ciptr->fd,
1339	(struct sockaddr *) &sockname, (void *)&namelen)) < 0)
1340    {
1341	prmsg (1, "SocketUNIXAccept: accept() failed\n");
1342	free (newciptr);
1343	*status = TRANS_ACCEPT_FAILED;
1344	return NULL;
1345    }
1346
1347	ciptr->addrlen = namelen;
1348    /*
1349     * Get the socket name and the peer name from the listener socket,
1350     * since this is unix domain.
1351     */
1352
1353    if ((newciptr->addr = malloc (ciptr->addrlen)) == NULL)
1354    {
1355        prmsg (1,
1356        "SocketUNIXAccept: Can't allocate space for the addr\n");
1357	close (newciptr->fd);
1358	free (newciptr);
1359	*status = TRANS_ACCEPT_BAD_MALLOC;
1360        return NULL;
1361    }
1362
1363    /*
1364     * if the socket is abstract, we already modified the address to have a
1365     * @ instead of the initial NUL, so no need to do that again here.
1366     */
1367
1368    newciptr->addrlen = ciptr->addrlen;
1369    memcpy (newciptr->addr, ciptr->addr, newciptr->addrlen);
1370
1371    if ((newciptr->peeraddr = malloc (ciptr->addrlen)) == NULL)
1372    {
1373        prmsg (1,
1374	      "SocketUNIXAccept: Can't allocate space for the addr\n");
1375	close (newciptr->fd);
1376	if (newciptr->addr) free (newciptr->addr);
1377	free (newciptr);
1378	*status = TRANS_ACCEPT_BAD_MALLOC;
1379        return NULL;
1380    }
1381
1382    newciptr->peeraddrlen = ciptr->addrlen;
1383    memcpy (newciptr->peeraddr, ciptr->addr, newciptr->addrlen);
1384
1385    newciptr->family = AF_UNIX;
1386
1387    *status = 0;
1388
1389    return newciptr;
1390}
1391
1392#endif /* UNIXCONN */
1393
1394#endif /* TRANS_SERVER */
1395
1396
1397#ifdef TRANS_CLIENT
1398
1399#ifdef TCPCONN
1400
1401#if defined(IPv6) && defined(AF_INET6)
1402struct addrlist {
1403    struct addrinfo *	addr;
1404    struct addrinfo *	firstaddr;
1405    char 		port[PORTBUFSIZE];
1406    char 		host[MAXHOSTNAMELEN];
1407};
1408static struct addrlist  *addrlist = NULL;
1409#endif
1410
1411
1412static int
1413TRANS(SocketINETConnect) (XtransConnInfo ciptr, char *host, char *port)
1414
1415{
1416    struct sockaddr *	socketaddr = NULL;
1417    int			socketaddrlen = 0;
1418    int			res;
1419#if defined(IPv6) && defined(AF_INET6)
1420    struct addrinfo 	hints;
1421    char		ntopbuf[INET6_ADDRSTRLEN];
1422    int			resetonce = 0;
1423#else
1424    struct sockaddr_in	sockname;
1425    struct hostent	*hostp;
1426    struct servent	*servp;
1427    unsigned long 	tmpaddr;
1428#endif
1429#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1430    _Xgethostbynameparams hparams;
1431    _Xgetservbynameparams sparams;
1432#endif
1433#ifdef X11_t
1434    char	portbuf[PORTBUFSIZE];
1435#endif
1436
1437    char 		hostnamebuf[256];		/* tmp space */
1438
1439    prmsg (2,"SocketINETConnect(%d,%s,%s)\n", ciptr->fd, host, port);
1440
1441    if (!host)
1442    {
1443	hostnamebuf[0] = '\0';
1444	(void) TRANS(GetHostname) (hostnamebuf, sizeof hostnamebuf);
1445	host = hostnamebuf;
1446    }
1447
1448#ifdef X11_t
1449    /*
1450     * X has a well known port, that is transport dependent. It is easier
1451     * to handle it here, than try and come up with a transport independent
1452     * representation that can be passed in and resolved the usual way.
1453     *
1454     * The port that is passed here is really a string containing the idisplay
1455     * from ConnectDisplay().
1456     */
1457
1458    if (is_numeric (port))
1459    {
1460	long tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10);
1461	snprintf (portbuf, sizeof(portbuf), "%lu", tmpport);
1462	port = portbuf;
1463    }
1464#endif
1465
1466#if defined(IPv6) && defined(AF_INET6)
1467    {
1468	if (addrlist != NULL) {
1469	    if (strcmp(host,addrlist->host) || strcmp(port,addrlist->port)) {
1470		if (addrlist->firstaddr)
1471		    freeaddrinfo(addrlist->firstaddr);
1472		addrlist->firstaddr = NULL;
1473	    }
1474	} else {
1475	    addrlist = malloc(sizeof(struct addrlist));
1476	    addrlist->firstaddr = NULL;
1477	}
1478
1479	if (addrlist->firstaddr == NULL) {
1480	    strncpy(addrlist->port, port, sizeof(addrlist->port));
1481	    addrlist->port[sizeof(addrlist->port) - 1] = '\0';
1482	    strncpy(addrlist->host, host, sizeof(addrlist->host));
1483	    addrlist->host[sizeof(addrlist->host) - 1] = '\0';
1484
1485	    bzero(&hints,sizeof(hints));
1486	    hints.ai_socktype = Sockettrans2devtab[ciptr->index].devcotsname;
1487
1488	    res = getaddrinfo(host,port,&hints,&addrlist->firstaddr);
1489	    if (res != 0) {
1490		prmsg (1, "SocketINETConnect() can't get address "
1491			"for %s:%s: %s\n", host, port, gai_strerror(res));
1492		ESET(EINVAL);
1493		return TRANS_CONNECT_FAILED;
1494	    }
1495	    for (res = 0, addrlist->addr = addrlist->firstaddr;
1496		 addrlist->addr ; res++) {
1497		addrlist->addr = addrlist->addr->ai_next;
1498	    }
1499	    prmsg(4,"Got New Address list with %d addresses\n", res);
1500	    res = 0;
1501	    addrlist->addr = NULL;
1502	}
1503
1504	while (socketaddr == NULL) {
1505	    if (addrlist->addr == NULL) {
1506		if (resetonce) {
1507		    /* Already checked entire list - no usable addresses */
1508		    prmsg (1, "SocketINETConnect() no usable address "
1509			   "for %s:%s\n", host, port);
1510		    return TRANS_CONNECT_FAILED;
1511		} else {
1512		    /* Go back to beginning of list */
1513		    resetonce = 1;
1514		    addrlist->addr = addrlist->firstaddr;
1515		}
1516	    }
1517
1518	    socketaddr = addrlist->addr->ai_addr;
1519	    socketaddrlen = addrlist->addr->ai_addrlen;
1520
1521	    if (addrlist->addr->ai_family == AF_INET) {
1522		struct sockaddr_in *sin = (struct sockaddr_in *) socketaddr;
1523
1524		prmsg (4,"SocketINETConnect() sockname.sin_addr = %s\n",
1525			inet_ntop(addrlist->addr->ai_family,&sin->sin_addr,
1526			ntopbuf,sizeof(ntopbuf)));
1527
1528		prmsg (4,"SocketINETConnect() sockname.sin_port = %d\n",
1529			ntohs(sin->sin_port));
1530
1531		if (Sockettrans2devtab[ciptr->index].family == AF_INET6) {
1532		    if (strcmp(Sockettrans2devtab[ciptr->index].transname,
1533				"tcp") == 0) {
1534			XtransConnInfo newciptr;
1535
1536			/*
1537			 * Our socket is an IPv6 socket, but the address is
1538			 * IPv4.  Close it and get an IPv4 socket.  This is
1539			 * needed for IPv4 connections to work on platforms
1540			 * that don't allow IPv4 over IPv6 sockets.
1541			 */
1542			TRANS(SocketINETClose)(ciptr);
1543			newciptr = TRANS(SocketOpenCOTSClientBase)(
1544					"tcp", "tcp", host, port, ciptr->index);
1545			if (newciptr)
1546			    ciptr->fd = newciptr->fd;
1547			if (!newciptr ||
1548			    Sockettrans2devtab[newciptr->index].family !=
1549				AF_INET) {
1550			    socketaddr = NULL;
1551			    prmsg (4,"SocketINETConnect() Cannot get IPv4 "
1552					" socketfor IPv4 address\n");
1553			}
1554			if (newciptr)
1555			    free(newciptr);
1556		    } else {
1557			socketaddr = NULL;
1558			prmsg (4,"SocketINETConnect Skipping IPv4 address\n");
1559		    }
1560		}
1561	    } else if (addrlist->addr->ai_family == AF_INET6) {
1562		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) socketaddr;
1563
1564		prmsg (4,"SocketINETConnect() sockname.sin6_addr = %s\n",
1565			inet_ntop(addrlist->addr->ai_family,
1566				  &sin6->sin6_addr,ntopbuf,sizeof(ntopbuf)));
1567		prmsg (4,"SocketINETConnect() sockname.sin6_port = %d\n",
1568			ntohs(sin6->sin6_port));
1569
1570		if (Sockettrans2devtab[ciptr->index].family == AF_INET) {
1571		    if (strcmp(Sockettrans2devtab[ciptr->index].transname,
1572				"tcp") == 0) {
1573			XtransConnInfo newciptr;
1574
1575			/*
1576			 * Close the IPv4 socket and try to open an IPv6 socket.
1577			 */
1578			TRANS(SocketINETClose)(ciptr);
1579			newciptr = TRANS(SocketOpenCOTSClientBase)(
1580					"tcp", "tcp", host, port, -1);
1581			if (newciptr)
1582			    ciptr->fd = newciptr->fd;
1583			if (!newciptr ||
1584			    Sockettrans2devtab[newciptr->index].family !=
1585					AF_INET6) {
1586			    socketaddr = NULL;
1587			    prmsg (4,"SocketINETConnect() Cannot get IPv6 "
1588				   "socket for IPv6 address\n");
1589			}
1590			if (newciptr)
1591			    free(newciptr);
1592		    }
1593		    else
1594		    {
1595			socketaddr = NULL;
1596			prmsg (4,"SocketINETConnect() Skipping IPv6 address\n");
1597		    }
1598		}
1599	    } else {
1600		socketaddr = NULL; /* Unsupported address type */
1601	    }
1602	    if (socketaddr == NULL) {
1603		addrlist->addr = addrlist->addr->ai_next;
1604	    }
1605	}
1606    }
1607#else
1608    {
1609	/*
1610	 * Build the socket name.
1611	 */
1612
1613#ifdef BSD44SOCKETS
1614	sockname.sin_len = sizeof (struct sockaddr_in);
1615#endif
1616	sockname.sin_family = AF_INET;
1617
1618	/*
1619	 * fill in sin_addr
1620	 */
1621
1622#ifndef INADDR_NONE
1623#define INADDR_NONE ((in_addr_t) 0xffffffff)
1624#endif
1625
1626	/* check for ww.xx.yy.zz host string */
1627
1628	if (isascii (host[0]) && isdigit (host[0])) {
1629	    tmpaddr = inet_addr (host); /* returns network byte order */
1630	} else {
1631	    tmpaddr = INADDR_NONE;
1632	}
1633
1634	prmsg (4,"SocketINETConnect() inet_addr(%s) = %x\n", host, tmpaddr);
1635
1636	if (tmpaddr == INADDR_NONE) {
1637	    if ((hostp = _XGethostbyname(host,hparams)) == NULL) {
1638		prmsg (1,"SocketINETConnect: Can't get address for %s\n",
1639			host);
1640		ESET(EINVAL);
1641		return TRANS_CONNECT_FAILED;
1642	    }
1643	    if (hostp->h_addrtype != AF_INET) {  /* is IP host? */
1644		prmsg (1,"SocketINETConnect: not INET host%s\n", host);
1645		ESET(EPROTOTYPE);
1646		return TRANS_CONNECT_FAILED;
1647	    }
1648
1649	    memcpy ((char *) &sockname.sin_addr, (char *) hostp->h_addr,
1650		    sizeof (sockname.sin_addr));
1651
1652	} else {
1653	    sockname.sin_addr.s_addr = tmpaddr;
1654        }
1655
1656	/*
1657	 * fill in sin_port
1658	 */
1659
1660	/* Check for number in the port string */
1661
1662	if (!is_numeric (port)) {
1663	    if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL) {
1664		prmsg (1,"SocketINETConnect: can't get service for %s\n",
1665			port);
1666		return TRANS_CONNECT_FAILED;
1667	    }
1668	    sockname.sin_port = htons (servp->s_port);
1669	} else {
1670	    long tmpport = strtol (port, (char**)NULL, 10);
1671	    if (tmpport < 1024 || tmpport > USHRT_MAX)
1672		return TRANS_CONNECT_FAILED;
1673	    sockname.sin_port = htons (((unsigned short) tmpport));
1674	}
1675
1676	prmsg (4,"SocketINETConnect: sockname.sin_port = %d\n",
1677		ntohs(sockname.sin_port));
1678	socketaddr = (struct sockaddr *) &sockname;
1679	socketaddrlen = sizeof(sockname);
1680    }
1681#endif
1682
1683    /*
1684     * Turn on socket keepalive so the client process will eventually
1685     * be notified with a SIGPIPE signal if the display server fails
1686     * to respond to a periodic transmission of messages
1687     * on the connected socket.
1688     * This is useful to avoid hung application processes when the
1689     * processes are not spawned from the xdm session and
1690     * the display server terminates abnormally.
1691     * (Someone turned off the power switch.)
1692     */
1693
1694    {
1695	int tmp = 1;
1696	setsockopt (ciptr->fd, SOL_SOCKET, SO_KEEPALIVE,
1697		(char *) &tmp, sizeof (int));
1698    }
1699
1700    /*
1701     * Do the connect()
1702     */
1703
1704    if (connect (ciptr->fd, socketaddr, socketaddrlen ) < 0)
1705    {
1706#ifdef WIN32
1707	int olderrno = WSAGetLastError();
1708#else
1709	int olderrno = errno;
1710#endif
1711
1712	/*
1713	 * If the error was ECONNREFUSED, the server may be overloaded
1714	 * and we should try again.
1715	 *
1716	 * If the error was EWOULDBLOCK or EINPROGRESS then the socket
1717	 * was non-blocking and we should poll using select
1718	 *
1719	 * If the error was EINTR, the connect was interrupted and we
1720	 * should try again.
1721	 *
1722	 * If multiple addresses are found for a host then we should
1723	 * try to connect again with a different address for a larger
1724	 * number of errors that made us quit before, since those
1725	 * could be caused by trying to use an IPv6 address to contact
1726	 * a machine with an IPv4-only server or other reasons that
1727	 * only affect one of a set of addresses.
1728	 */
1729
1730	if (olderrno == ECONNREFUSED || olderrno == EINTR
1731#if defined(IPv6) && defined(AF_INET6)
1732	  || (((addrlist->addr->ai_next != NULL) ||
1733	        (addrlist->addr != addrlist->firstaddr)) &&
1734               (olderrno == ENETUNREACH || olderrno == EAFNOSUPPORT ||
1735		 olderrno == EADDRNOTAVAIL || olderrno == ETIMEDOUT
1736#if defined(EHOSTDOWN)
1737		   || olderrno == EHOSTDOWN
1738#endif
1739	       ))
1740#endif
1741	    )
1742	    res = TRANS_TRY_CONNECT_AGAIN;
1743	else if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS)
1744	    res = TRANS_IN_PROGRESS;
1745	else
1746	{
1747	    prmsg (2,"SocketINETConnect: Can't connect: errno = %d\n",
1748		   olderrno);
1749
1750	    res = TRANS_CONNECT_FAILED;
1751	}
1752    } else {
1753	res = 0;
1754
1755
1756	/*
1757	 * Sync up the address fields of ciptr.
1758	 */
1759
1760	if (TRANS(SocketINETGetAddr) (ciptr) < 0)
1761	{
1762	    prmsg (1,
1763	     "SocketINETConnect: ...SocketINETGetAddr() failed:\n");
1764	    res = TRANS_CONNECT_FAILED;
1765	}
1766
1767	else if (TRANS(SocketINETGetPeerAddr) (ciptr) < 0)
1768	{
1769	    prmsg (1,
1770	      "SocketINETConnect: ...SocketINETGetPeerAddr() failed:\n");
1771	    res = TRANS_CONNECT_FAILED;
1772	}
1773    }
1774
1775#if defined(IPv6) && defined(AF_INET6)
1776   if (res != 0) {
1777	addrlist->addr = addrlist->addr->ai_next;
1778   }
1779#endif
1780
1781    return res;
1782}
1783
1784#endif /* TCPCONN */
1785
1786
1787
1788#ifdef UNIXCONN
1789
1790/*
1791 * Make sure 'host' is really local.
1792 */
1793
1794static int
1795UnixHostReallyLocal (char *host)
1796
1797{
1798    char hostnamebuf[256];
1799
1800    TRANS(GetHostname) (hostnamebuf, sizeof (hostnamebuf));
1801
1802    if (strcmp (hostnamebuf, host) == 0)
1803    {
1804	return (1);
1805    } else {
1806#if defined(IPv6) && defined(AF_INET6)
1807	struct addrinfo *localhostaddr;
1808	struct addrinfo *otherhostaddr;
1809	struct addrinfo *i, *j;
1810	int equiv = 0;
1811
1812	if (getaddrinfo(hostnamebuf, NULL, NULL, &localhostaddr) != 0)
1813	    return 0;
1814	if (getaddrinfo(host, NULL, NULL, &otherhostaddr) != 0) {
1815	    freeaddrinfo(localhostaddr);
1816	    return 0;
1817	}
1818
1819	for (i = localhostaddr; i != NULL && equiv == 0; i = i->ai_next) {
1820	    for (j = otherhostaddr; j != NULL && equiv == 0; j = j->ai_next) {
1821		if (i->ai_family == j->ai_family) {
1822		    if (i->ai_family == AF_INET) {
1823			struct sockaddr_in *sinA
1824			  = (struct sockaddr_in *) i->ai_addr;
1825			struct sockaddr_in *sinB
1826			  = (struct sockaddr_in *) j->ai_addr;
1827			struct in_addr *A = &sinA->sin_addr;
1828			struct in_addr *B = &sinB->sin_addr;
1829
1830			if (memcmp(A,B,sizeof(struct in_addr)) == 0) {
1831			    equiv = 1;
1832			}
1833		    } else if (i->ai_family == AF_INET6) {
1834			struct sockaddr_in6 *sinA
1835			  = (struct sockaddr_in6 *) i->ai_addr;
1836			struct sockaddr_in6 *sinB
1837			  = (struct sockaddr_in6 *) j->ai_addr;
1838			struct in6_addr *A = &sinA->sin6_addr;
1839			struct in6_addr *B = &sinB->sin6_addr;
1840
1841			if (memcmp(A,B,sizeof(struct in6_addr)) == 0) {
1842			    equiv = 1;
1843			}
1844		    }
1845		}
1846	    }
1847	}
1848
1849	freeaddrinfo(localhostaddr);
1850	freeaddrinfo(otherhostaddr);
1851	return equiv;
1852#else
1853	/*
1854	 * A host may have more than one network address.  If any of the
1855	 * network addresses of 'host' (specified to the connect call)
1856	 * match any of the network addresses of 'hostname' (determined
1857	 * by TRANS(GetHostname)), then the two hostnames are equivalent,
1858	 * and we know that 'host' is really a local host.
1859	 */
1860	char specified_local_addr_list[10][4];
1861	int scount, equiv, i, j;
1862#ifdef XTHREADS_NEEDS_BYNAMEPARAMS
1863	_Xgethostbynameparams hparams;
1864#endif
1865	struct hostent *hostp;
1866
1867	if ((hostp = _XGethostbyname (host,hparams)) == NULL)
1868	    return (0);
1869
1870	scount = 0;
1871	while (hostp->h_addr_list[scount] && scount <= 8)
1872	{
1873	    /*
1874	     * The 2nd call to gethostname() overrides the data
1875	     * from the 1st call, so we must save the address list.
1876	     */
1877
1878	    specified_local_addr_list[scount][0] =
1879				hostp->h_addr_list[scount][0];
1880	    specified_local_addr_list[scount][1] =
1881				hostp->h_addr_list[scount][1];
1882	    specified_local_addr_list[scount][2] =
1883				hostp->h_addr_list[scount][2];
1884	    specified_local_addr_list[scount][3] =
1885				hostp->h_addr_list[scount][3];
1886	    scount++;
1887	}
1888	if ((hostp = _XGethostbyname (hostnamebuf,hparams)) == NULL)
1889	    return (0);
1890
1891	equiv = 0;
1892	i = 0;
1893
1894	while (i < scount && !equiv)
1895	{
1896	    j = 0;
1897
1898	    while (hostp->h_addr_list[j])
1899	    {
1900		if ((specified_local_addr_list[i][0] ==
1901					hostp->h_addr_list[j][0]) &&
1902		    (specified_local_addr_list[i][1] ==
1903					hostp->h_addr_list[j][1]) &&
1904		    (specified_local_addr_list[i][2] ==
1905					hostp->h_addr_list[j][2]) &&
1906		    (specified_local_addr_list[i][3] ==
1907					hostp->h_addr_list[j][3]))
1908		{
1909		    /* They're equal, so we're done */
1910
1911		    equiv = 1;
1912		    break;
1913		}
1914
1915		j++;
1916	    }
1917
1918	    i++;
1919	}
1920	return (equiv);
1921#endif
1922    }
1923}
1924
1925static int
1926TRANS(SocketUNIXConnect) (XtransConnInfo ciptr, char *host, char *port)
1927
1928{
1929    struct sockaddr_un	sockname;
1930    SOCKLEN_T		namelen;
1931
1932
1933    int abstract = 0;
1934#ifdef HAVE_ABSTRACT_SOCKETS
1935    abstract = ciptr->transptr->flags & TRANS_ABSTRACT;
1936#endif
1937
1938    prmsg (2,"SocketUNIXConnect(%d,%s,%s)\n", ciptr->fd, host, port);
1939
1940    /*
1941     * Make sure 'host' is really local.  If not, we return failure.
1942     * The reason we make this check is because a process may advertise
1943     * a "local" network ID for which it can accept connections, but if
1944     * a process on a remote machine tries to connect to this network ID,
1945     * we know for sure it will fail.
1946     */
1947
1948    if (host && *host && host[0]!='/' && strcmp (host, "unix") != 0 && !UnixHostReallyLocal (host))
1949    {
1950	prmsg (1,
1951	   "SocketUNIXConnect: Cannot connect to non-local host %s\n",
1952	       host);
1953	return TRANS_CONNECT_FAILED;
1954    }
1955
1956
1957    /*
1958     * Check the port.
1959     */
1960
1961    if (!port || !*port)
1962    {
1963	prmsg (1,"SocketUNIXConnect: Missing port specification\n");
1964	return TRANS_CONNECT_FAILED;
1965    }
1966
1967    /*
1968     * Build the socket name.
1969     */
1970
1971    sockname.sun_family = AF_UNIX;
1972
1973    if (set_sun_path(port, UNIX_PATH, sockname.sun_path, abstract) != 0) {
1974	prmsg (1, "SocketUNIXConnect: path too long\n");
1975	return TRANS_CONNECT_FAILED;
1976    }
1977
1978#if (defined(BSD44SOCKETS) || defined(__UNIXWARE__))
1979    sockname.sun_len = strlen (sockname.sun_path);
1980#endif
1981
1982#if defined(BSD44SOCKETS) || defined(SUN_LEN)
1983    namelen = SUN_LEN (&sockname);
1984#else
1985    namelen = strlen (sockname.sun_path) + offsetof(struct sockaddr_un, sun_path);
1986#endif
1987
1988
1989
1990    /*
1991     * Adjust the socket path if using abstract sockets.
1992     * Done here because otherwise all the strlen() calls above would fail.
1993     */
1994
1995    if (abstract) {
1996	sockname.sun_path[0] = '\0';
1997    }
1998
1999    /*
2000     * Do the connect()
2001     */
2002
2003    if (connect (ciptr->fd, (struct sockaddr *) &sockname, namelen) < 0)
2004    {
2005	int olderrno = errno;
2006	int connected = 0;
2007
2008	if (!connected)
2009	{
2010	    errno = olderrno;
2011
2012	    /*
2013	     * If the error was ENOENT, the server may be starting up; we used
2014	     * to suggest to try again in this case with
2015	     * TRANS_TRY_CONNECT_AGAIN, but this introduced problems for
2016	     * processes still referencing stale sockets in their environment.
2017	     * Hence, we now return a hard error, TRANS_CONNECT_FAILED, and it
2018	     * is suggested that higher level stacks handle retries on their
2019	     * level when they face a slow starting server.
2020	     *
2021	     * If the error was EWOULDBLOCK or EINPROGRESS then the socket
2022	     * was non-blocking and we should poll using select
2023	     *
2024	     * If the error was EINTR, the connect was interrupted and we
2025	     * should try again.
2026	     */
2027
2028	    if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS)
2029		return TRANS_IN_PROGRESS;
2030	    else if (olderrno == EINTR)
2031		return TRANS_TRY_CONNECT_AGAIN;
2032	    else if (olderrno == ENOENT || olderrno == ECONNREFUSED) {
2033		/* If opening as abstract socket failed, try again normally */
2034		if (abstract) {
2035		    ciptr->transptr->flags &= ~(TRANS_ABSTRACT);
2036		    return TRANS_TRY_CONNECT_AGAIN;
2037		} else {
2038		    return TRANS_CONNECT_FAILED;
2039		}
2040	    } else {
2041		prmsg (2,"SocketUNIXConnect: Can't connect: errno = %d\n",
2042		       EGET());
2043
2044		return TRANS_CONNECT_FAILED;
2045	    }
2046	}
2047    }
2048
2049    /*
2050     * Get the socket name and the peer name from the connect socket,
2051     * since this is unix domain.
2052     */
2053
2054    if ((ciptr->addr = malloc(namelen)) == NULL ||
2055       (ciptr->peeraddr = malloc(namelen)) == NULL)
2056    {
2057        prmsg (1,
2058	"SocketUNIXCreateListener: Can't allocate space for the addr\n");
2059        return TRANS_CONNECT_FAILED;
2060    }
2061
2062    if (abstract)
2063	sockname.sun_path[0] = '@';
2064
2065    ciptr->family = AF_UNIX;
2066    ciptr->addrlen = namelen;
2067    ciptr->peeraddrlen = namelen;
2068    memcpy (ciptr->addr, &sockname, ciptr->addrlen);
2069    memcpy (ciptr->peeraddr, &sockname, ciptr->peeraddrlen);
2070
2071    return 0;
2072}
2073
2074#endif /* UNIXCONN */
2075
2076#endif /* TRANS_CLIENT */
2077
2078
2079static int
2080TRANS(SocketBytesReadable) (XtransConnInfo ciptr, BytesReadable_t *pend)
2081
2082{
2083    prmsg (2,"SocketBytesReadable(%p,%d,%p)\n",
2084	ciptr, ciptr->fd, pend);
2085#ifdef WIN32
2086    {
2087	int ret = ioctlsocket ((SOCKET) ciptr->fd, FIONREAD, (u_long *) pend);
2088	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
2089	return ret;
2090    }
2091#else
2092#if defined(__i386__) && defined(SYSV) && !defined(SCO325)
2093    return ioctl (ciptr->fd, I_NREAD, (char *) pend);
2094#else
2095    return ioctl (ciptr->fd, FIONREAD, (char *) pend);
2096#endif /* __i386__ && SYSV || _SEQUENT_ && _SOCKET_VERSION == 1 */
2097#endif /* WIN32 */
2098}
2099
2100
2101static int
2102TRANS(SocketRead) (XtransConnInfo ciptr, char *buf, int size)
2103
2104{
2105    prmsg (2,"SocketRead(%d,%p,%d)\n", ciptr->fd, buf, size);
2106
2107#if defined(WIN32)
2108    {
2109	int ret = recv ((SOCKET)ciptr->fd, buf, size, 0);
2110#ifdef WIN32
2111	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
2112#endif
2113	return ret;
2114    }
2115#else
2116    return read (ciptr->fd, buf, size);
2117#endif /* WIN32 */
2118}
2119
2120
2121static int
2122TRANS(SocketWrite) (XtransConnInfo ciptr, char *buf, int size)
2123
2124{
2125    prmsg (2,"SocketWrite(%d,%p,%d)\n", ciptr->fd, buf, size);
2126
2127#if defined(WIN32)
2128    {
2129	int ret = send ((SOCKET)ciptr->fd, buf, size, 0);
2130#ifdef WIN32
2131	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
2132#endif
2133	return ret;
2134    }
2135#else
2136    return write (ciptr->fd, buf, size);
2137#endif /* WIN32 */
2138}
2139
2140
2141static int
2142TRANS(SocketReadv) (XtransConnInfo ciptr, struct iovec *buf, int size)
2143
2144{
2145    prmsg (2,"SocketReadv(%d,%p,%d)\n", ciptr->fd, buf, size);
2146
2147    return READV (ciptr, buf, size);
2148}
2149
2150
2151static int
2152TRANS(SocketWritev) (XtransConnInfo ciptr, struct iovec *buf, int size)
2153
2154{
2155    prmsg (2,"SocketWritev(%d,%p,%d)\n", ciptr->fd, buf, size);
2156
2157    return WRITEV (ciptr, buf, size);
2158}
2159
2160
2161static int
2162TRANS(SocketDisconnect) (XtransConnInfo ciptr)
2163
2164{
2165    prmsg (2,"SocketDisconnect(%p,%d)\n", ciptr, ciptr->fd);
2166
2167#ifdef WIN32
2168    {
2169	int ret = shutdown (ciptr->fd, 2);
2170	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
2171	return ret;
2172    }
2173#else
2174    return shutdown (ciptr->fd, 2); /* disallow further sends and receives */
2175#endif
2176}
2177
2178
2179#ifdef TCPCONN
2180static int
2181TRANS(SocketINETClose) (XtransConnInfo ciptr)
2182
2183{
2184    prmsg (2,"SocketINETClose(%p,%d)\n", ciptr, ciptr->fd);
2185
2186#ifdef WIN32
2187    {
2188	int ret = close (ciptr->fd);
2189	if (ret == SOCKET_ERROR) errno = WSAGetLastError();
2190	return ret;
2191    }
2192#else
2193    return close (ciptr->fd);
2194#endif
2195}
2196
2197#endif /* TCPCONN */
2198
2199
2200#ifdef UNIXCONN
2201static int
2202TRANS(SocketUNIXClose) (XtransConnInfo ciptr)
2203{
2204    /*
2205     * If this is the server side, then once the socket is closed,
2206     * it must be unlinked to completely close it
2207     */
2208
2209    struct sockaddr_un	*sockname = (struct sockaddr_un *) ciptr->addr;
2210    int ret;
2211
2212    prmsg (2,"SocketUNIXClose(%p,%d)\n", ciptr, ciptr->fd);
2213
2214    ret = close(ciptr->fd);
2215
2216    if (ciptr->flags
2217       && sockname
2218       && sockname->sun_family == AF_UNIX
2219       && sockname->sun_path[0])
2220    {
2221	if (!(ciptr->flags & TRANS_NOUNLINK
2222	    || ciptr->transptr->flags & TRANS_ABSTRACT))
2223		unlink (sockname->sun_path);
2224    }
2225
2226    return ret;
2227}
2228
2229static int
2230TRANS(SocketUNIXCloseForCloning) (XtransConnInfo ciptr)
2231
2232{
2233    /*
2234     * Don't unlink path.
2235     */
2236
2237    int ret;
2238
2239    prmsg (2,"SocketUNIXCloseForCloning(%p,%d)\n",
2240	ciptr, ciptr->fd);
2241
2242    ret = close(ciptr->fd);
2243
2244    return ret;
2245}
2246
2247#endif /* UNIXCONN */
2248
2249
2250#ifdef TCPCONN
2251# ifdef TRANS_SERVER
2252static const char* tcp_nolisten[] = {
2253	"inet",
2254#if defined(IPv6) && defined(AF_INET6)
2255	"inet6",
2256#endif
2257	NULL
2258};
2259# endif
2260
2261Xtransport	TRANS(SocketTCPFuncs) = {
2262	/* Socket Interface */
2263	"tcp",
2264        TRANS_ALIAS,
2265#ifdef TRANS_CLIENT
2266	TRANS(SocketOpenCOTSClient),
2267#endif /* TRANS_CLIENT */
2268#ifdef TRANS_SERVER
2269	tcp_nolisten,
2270	TRANS(SocketOpenCOTSServer),
2271#endif /* TRANS_SERVER */
2272#ifdef TRANS_CLIENT
2273	TRANS(SocketOpenCLTSClient),
2274#endif /* TRANS_CLIENT */
2275#ifdef TRANS_SERVER
2276	TRANS(SocketOpenCLTSServer),
2277#endif /* TRANS_SERVER */
2278#ifdef TRANS_REOPEN
2279	TRANS(SocketReopenCOTSServer),
2280	TRANS(SocketReopenCLTSServer),
2281#endif
2282	TRANS(SocketSetOption),
2283#ifdef TRANS_SERVER
2284	TRANS(SocketINETCreateListener),
2285	NULL,		       			/* ResetListener */
2286	TRANS(SocketINETAccept),
2287#endif /* TRANS_SERVER */
2288#ifdef TRANS_CLIENT
2289	TRANS(SocketINETConnect),
2290#endif /* TRANS_CLIENT */
2291	TRANS(SocketBytesReadable),
2292	TRANS(SocketRead),
2293	TRANS(SocketWrite),
2294	TRANS(SocketReadv),
2295	TRANS(SocketWritev),
2296	TRANS(SocketDisconnect),
2297	TRANS(SocketINETClose),
2298	TRANS(SocketINETClose),
2299	};
2300
2301Xtransport	TRANS(SocketINETFuncs) = {
2302	/* Socket Interface */
2303	"inet",
2304	0,
2305#ifdef TRANS_CLIENT
2306	TRANS(SocketOpenCOTSClient),
2307#endif /* TRANS_CLIENT */
2308#ifdef TRANS_SERVER
2309	NULL,
2310	TRANS(SocketOpenCOTSServer),
2311#endif /* TRANS_SERVER */
2312#ifdef TRANS_CLIENT
2313	TRANS(SocketOpenCLTSClient),
2314#endif /* TRANS_CLIENT */
2315#ifdef TRANS_SERVER
2316	TRANS(SocketOpenCLTSServer),
2317#endif /* TRANS_SERVER */
2318#ifdef TRANS_REOPEN
2319	TRANS(SocketReopenCOTSServer),
2320	TRANS(SocketReopenCLTSServer),
2321#endif
2322	TRANS(SocketSetOption),
2323#ifdef TRANS_SERVER
2324	TRANS(SocketINETCreateListener),
2325	NULL,		       			/* ResetListener */
2326	TRANS(SocketINETAccept),
2327#endif /* TRANS_SERVER */
2328#ifdef TRANS_CLIENT
2329	TRANS(SocketINETConnect),
2330#endif /* TRANS_CLIENT */
2331	TRANS(SocketBytesReadable),
2332	TRANS(SocketRead),
2333	TRANS(SocketWrite),
2334	TRANS(SocketReadv),
2335	TRANS(SocketWritev),
2336	TRANS(SocketDisconnect),
2337	TRANS(SocketINETClose),
2338	TRANS(SocketINETClose),
2339	};
2340
2341#if defined(IPv6) && defined(AF_INET6)
2342Xtransport     TRANS(SocketINET6Funcs) = {
2343	/* Socket Interface */
2344	"inet6",
2345	0,
2346#ifdef TRANS_CLIENT
2347	TRANS(SocketOpenCOTSClient),
2348#endif /* TRANS_CLIENT */
2349#ifdef TRANS_SERVER
2350	NULL,
2351	TRANS(SocketOpenCOTSServer),
2352#endif /* TRANS_SERVER */
2353#ifdef TRANS_CLIENT
2354	TRANS(SocketOpenCLTSClient),
2355#endif /* TRANS_CLIENT */
2356#ifdef TRANS_SERVER
2357	TRANS(SocketOpenCLTSServer),
2358#endif /* TRANS_SERVER */
2359#ifdef TRANS_REOPEN
2360	TRANS(SocketReopenCOTSServer),
2361	TRANS(SocketReopenCLTSServer),
2362#endif
2363	TRANS(SocketSetOption),
2364#ifdef TRANS_SERVER
2365	TRANS(SocketINETCreateListener),
2366	NULL,					/* ResetListener */
2367	TRANS(SocketINETAccept),
2368#endif /* TRANS_SERVER */
2369#ifdef TRANS_CLIENT
2370	TRANS(SocketINETConnect),
2371#endif /* TRANS_CLIENT */
2372	TRANS(SocketBytesReadable),
2373	TRANS(SocketRead),
2374	TRANS(SocketWrite),
2375	TRANS(SocketReadv),
2376	TRANS(SocketWritev),
2377	TRANS(SocketDisconnect),
2378	TRANS(SocketINETClose),
2379	TRANS(SocketINETClose),
2380	};
2381#endif /* IPv6 */
2382#endif /* TCPCONN */
2383
2384#ifdef UNIXCONN
2385#if !defined(LOCALCONN)
2386Xtransport	TRANS(SocketLocalFuncs) = {
2387	/* Socket Interface */
2388	"local",
2389#ifdef HAVE_ABSTRACT_SOCKETS
2390	TRANS_ABSTRACT,
2391#else
2392	0,
2393#endif
2394#ifdef TRANS_CLIENT
2395	TRANS(SocketOpenCOTSClient),
2396#endif /* TRANS_CLIENT */
2397#ifdef TRANS_SERVER
2398	NULL,
2399	TRANS(SocketOpenCOTSServer),
2400#endif /* TRANS_SERVER */
2401#ifdef TRANS_CLIENT
2402	TRANS(SocketOpenCLTSClient),
2403#endif /* TRANS_CLIENT */
2404#ifdef TRANS_SERVER
2405	TRANS(SocketOpenCLTSServer),
2406#endif /* TRANS_SERVER */
2407#ifdef TRANS_REOPEN
2408	TRANS(SocketReopenCOTSServer),
2409	TRANS(SocketReopenCLTSServer),
2410#endif
2411	TRANS(SocketSetOption),
2412#ifdef TRANS_SERVER
2413	TRANS(SocketUNIXCreateListener),
2414	TRANS(SocketUNIXResetListener),
2415	TRANS(SocketUNIXAccept),
2416#endif /* TRANS_SERVER */
2417#ifdef TRANS_CLIENT
2418	TRANS(SocketUNIXConnect),
2419#endif /* TRANS_CLIENT */
2420	TRANS(SocketBytesReadable),
2421	TRANS(SocketRead),
2422	TRANS(SocketWrite),
2423	TRANS(SocketReadv),
2424	TRANS(SocketWritev),
2425	TRANS(SocketDisconnect),
2426	TRANS(SocketUNIXClose),
2427	TRANS(SocketUNIXCloseForCloning),
2428	};
2429#endif /* !LOCALCONN */
2430# ifdef TRANS_SERVER
2431#  if !defined(LOCALCONN)
2432static char* unix_nolisten[] = { "local" , NULL };
2433#  endif
2434# endif
2435
2436Xtransport	TRANS(SocketUNIXFuncs) = {
2437	/* Socket Interface */
2438	"unix",
2439#if !defined(LOCALCONN) && !defined(HAVE_ABSTRACT_SOCKETS)
2440        TRANS_ALIAS,
2441#else
2442	0,
2443#endif
2444#ifdef TRANS_CLIENT
2445	TRANS(SocketOpenCOTSClient),
2446#endif /* TRANS_CLIENT */
2447#ifdef TRANS_SERVER
2448#if !defined(LOCALCONN)
2449	unix_nolisten,
2450#else
2451	NULL,
2452#endif
2453	TRANS(SocketOpenCOTSServer),
2454#endif /* TRANS_SERVER */
2455#ifdef TRANS_CLIENT
2456	TRANS(SocketOpenCLTSClient),
2457#endif /* TRANS_CLIENT */
2458#ifdef TRANS_SERVER
2459	TRANS(SocketOpenCLTSServer),
2460#endif /* TRANS_SERVER */
2461#ifdef TRANS_REOPEN
2462	TRANS(SocketReopenCOTSServer),
2463	TRANS(SocketReopenCLTSServer),
2464#endif
2465	TRANS(SocketSetOption),
2466#ifdef TRANS_SERVER
2467	TRANS(SocketUNIXCreateListener),
2468	TRANS(SocketUNIXResetListener),
2469	TRANS(SocketUNIXAccept),
2470#endif /* TRANS_SERVER */
2471#ifdef TRANS_CLIENT
2472	TRANS(SocketUNIXConnect),
2473#endif /* TRANS_CLIENT */
2474	TRANS(SocketBytesReadable),
2475	TRANS(SocketRead),
2476	TRANS(SocketWrite),
2477	TRANS(SocketReadv),
2478	TRANS(SocketWritev),
2479	TRANS(SocketDisconnect),
2480	TRANS(SocketUNIXClose),
2481	TRANS(SocketUNIXCloseForCloning),
2482	};
2483
2484#endif /* UNIXCONN */
2485