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