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