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