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