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