master
ブランチ master
ShaderPlayground / deps / xlibre / include / X11 / Xtrans / Xtrans.c
29 KB、1365行 生 Blame 履歴
1/*
2
3Copyright 1993, 1994, 1998 The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27 * Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA
28 *
29 * All Rights Reserved
30 *
31 * Permission to use, copy, modify, and distribute this software and its
32 * documentation for any purpose and without fee is hereby granted, provided
33 * that the above copyright notice appear in all copies and that both that
34 * copyright notice and this permission notice appear in supporting
35 * documentation, and that the name NCR not be used in advertising
36 * or publicity pertaining to distribution of the software without specific,
37 * written prior permission. NCR makes no representations about the
38 * suitability of this software for any purpose. It is provided "as is"
39 * without express or implied warranty.
40 *
41 * NCR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
42 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
43 * NO EVENT SHALL NCR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
44 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
45 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
46 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
47 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
48 */
49
50#include <ctype.h>
51#include <stdlib.h>
52#include <string.h>
53#ifdef HAVE_SYSTEMD_DAEMON
54#include <systemd/sd-daemon.h>
55#endif
56
57/*
58 * The transport table contains a definition for every transport (protocol)
59 * family. All operations that can be made on the transport go through this
60 * table.
61 *
62 * Each transport is assigned a unique transport id.
63 *
64 * New transports can be added by adding an entry in this table.
65 * For compatibility, the transport ids should never be renumbered.
66 * Always add to the end of the list.
67 */
68
69#define TRANS_TLI_INET_INDEX 1
70#define TRANS_TLI_TCP_INDEX 2
71#define TRANS_TLI_TLI_INDEX 3
72#define TRANS_SOCKET_UNIX_INDEX 4
73#define TRANS_SOCKET_LOCAL_INDEX 5
74#define TRANS_SOCKET_INET_INDEX 6
75#define TRANS_SOCKET_TCP_INDEX 7
76#define TRANS_DNET_INDEX 8
77#define TRANS_LOCAL_LOCAL_INDEX 9
78/* 10 used to be PTS, but that's gone. */
79#define TRANS_LOCAL_NAMED_INDEX 11
80/* 12 used to be ISC, but that's gone. */
81/* 13 used to be SCO, but that's gone. */
82#define TRANS_SOCKET_INET6_INDEX 14
83#define TRANS_LOCAL_PIPE_INDEX 15
84
85#if defined(IPv6) && !defined(AF_INET6)
86#error "Cannot build IPv6 support without AF_INET6"
87#endif
88
89static
90Xtransport_table Xtransports[] = {
91#if defined(TCPCONN)
92 { &TRANS(SocketTCPFuncs), TRANS_SOCKET_TCP_INDEX },
93#if defined(IPv6)
94 { &TRANS(SocketINET6Funcs), TRANS_SOCKET_INET6_INDEX },
95#endif /* IPv6 */
96 { &TRANS(SocketINETFuncs), TRANS_SOCKET_INET_INDEX },
97#endif /* TCPCONN */
98#if defined(UNIXCONN)
99#if !defined(LOCALCONN)
100 { &TRANS(SocketLocalFuncs), TRANS_SOCKET_LOCAL_INDEX },
101#endif /* !LOCALCONN */
102 { &TRANS(SocketUNIXFuncs), TRANS_SOCKET_UNIX_INDEX },
103#endif /* UNIXCONN */
104#if defined(LOCALCONN)
105 { &TRANS(LocalFuncs), TRANS_LOCAL_LOCAL_INDEX },
106#if defined(SVR4) || defined(__SVR4)
107 { &TRANS(NAMEDFuncs), TRANS_LOCAL_NAMED_INDEX },
108#endif
109#ifdef __sun
110 { &TRANS(PIPEFuncs), TRANS_LOCAL_PIPE_INDEX },
111#endif /* __sun */
112#endif /* LOCALCONN */
113};
114
115#define NUMTRANS (sizeof(Xtransports)/sizeof(Xtransport_table))
116
117
118#ifdef WIN32
119#define ioctl ioctlsocket
120#endif
121
122
123
124/*
125 * These are a few utility function used by the public interface functions.
126 */
127
128void
129TRANS(FreeConnInfo) (XtransConnInfo ciptr)
130
131{
132 prmsg (3,"FreeConnInfo(%p)\n", (void *) ciptr);
133
134 if (ciptr->addr)
135 free (ciptr->addr);
136
137 if (ciptr->peeraddr)
138 free (ciptr->peeraddr);
139
140 if (ciptr->port)
141 free (ciptr->port);
142
143 free (ciptr);
144}
145
146
147#define PROTOBUFSIZE 20
148
149static Xtransport *
150TRANS(SelectTransport) (const char *protocol)
151
152{
153#ifndef HAVE_STRCASECMP
154 char protobuf[PROTOBUFSIZE];
155#endif
156
157 prmsg (3,"SelectTransport(%s)\n", protocol);
158
159#ifndef HAVE_STRCASECMP
160 /*
161 * Force Protocol to be lowercase as a way of doing
162 * a case insensitive match.
163 */
164
165 strncpy (protobuf, protocol, PROTOBUFSIZE - 1);
166 protobuf[PROTOBUFSIZE-1] = '\0';
167
168 for (unsigned int i = 0; i < PROTOBUFSIZE && protobuf[i] != '\0'; i++)
169 if (isupper ((unsigned char)protobuf[i]))
170 protobuf[i] = tolower ((unsigned char)protobuf[i]);
171#endif
172
173 /* Look at all of the configured protocols */
174
175 for (unsigned int i = 0; i < NUMTRANS; i++)
176 {
177#ifndef HAVE_STRCASECMP
178 if (!strcmp (protobuf, Xtransports[i].transport->TransName))
179#else
180 if (!strcasecmp (protocol, Xtransports[i].transport->TransName))
181#endif
182 return Xtransports[i].transport;
183 }
184
185 return NULL;
186}
187
188static int
189TRANS(ParseAddress) (const char *address,
190 char **protocol, char **host, char **port)
191
192{
193 /*
194 * For the font library, the address is a string formatted
195 * as "protocol/host:port[/catalogue]". Note that the catologue
196 * is optional. At this time, the catologue info is ignored, but
197 * we have to parse it anyways.
198 *
199 * Other than fontlib, the address is a string formatted
200 * as "protocol/host:port".
201 *
202 * If the protocol part is missing, then assume TCP.
203 * If the protocol part and host part are missing, then assume local.
204 * If a "::" is found then assume DNET.
205 */
206
207 char *mybuf, *tmpptr = NULL;
208 const char *_protocol = NULL;
209 const char *_host, *_port;
210 char hostnamebuf[256];
211 char *_host_buf;
212 int _host_len;
213
214 prmsg (3,"ParseAddress(%s)\n", address);
215
216 /* First, check for AF_UNIX socket paths */
217 if (address[0] == '/') {
218 _protocol = "local";
219 _host = "";
220 _port = address;
221 } else
222#ifdef HAVE_LAUNCHD
223 /* launchd sockets will look like 'local//tmp/launch-XgkNns/:0' */
224 if(!strncmp(address,"local//",7)) {
225 _protocol="local";
226 _host="";
227 _port=address+6;
228 } else
229#endif
230 if (!strncmp(address, "unix:", 5)) {
231 _protocol = "local";
232 _host = "";
233 _port = address + 5;
234 }
235 if (_protocol)
236 goto done_parsing;
237
238 /* Copy the string so it can be changed */
239
240 tmpptr = mybuf = strdup (address);
241
242 /* Parse the string to get each component */
243
244 /* Get the protocol part */
245
246 _protocol = mybuf;
247
248
249 if ((mybuf == NULL) ||
250 ( ((mybuf = strchr (mybuf, '/')) == NULL) &&
251 ((mybuf = strrchr (tmpptr, ':')) == NULL) ) )
252 {
253 /* address is in a bad format */
254 *protocol = NULL;
255 *host = NULL;
256 *port = NULL;
257 free (tmpptr);
258 return 0;
259 }
260
261 if (*mybuf == ':')
262 {
263 /*
264 * If there is a hostname, then assume tcp, otherwise
265 * it must be local.
266 */
267 if (mybuf == tmpptr)
268 {
269 /* There is neither a protocol or host specified */
270 _protocol = "local";
271 }
272 else
273 {
274 /* There is a hostname specified */
275 _protocol = "tcp";
276 mybuf = tmpptr; /* reset to the beginning of the host ptr */
277 }
278 }
279 else
280 {
281 /* *mybuf == '/' */
282
283 *mybuf ++= '\0'; /* put a null at the end of the protocol */
284
285 if (strlen(_protocol) == 0)
286 {
287 /*
288 * If there is a hostname, then assume tcp, otherwise
289 * it must be local.
290 */
291 if (*mybuf != ':')
292 _protocol = "tcp";
293 else
294 _protocol = "local";
295 }
296 }
297
298 /* Get the host part */
299
300 _host = _host_buf = mybuf;
301
302 if ((mybuf = strrchr (mybuf,':')) == NULL)
303 {
304 *protocol = NULL;
305 *host = NULL;
306 *port = NULL;
307 free (tmpptr);
308 return 0;
309 }
310
311 *mybuf ++= '\0';
312
313 _host_len = strlen(_host);
314 if (_host_len == 0)
315 {
316 TRANS(GetHostname) (hostnamebuf, sizeof (hostnamebuf));
317 _host = hostnamebuf;
318 }
319#ifdef IPv6
320 /* hostname in IPv6 [numeric_addr]:0 form? */
321 else if ( (_host_len > 3) &&
322 ((strcmp(_protocol, "tcp") == 0) || (strcmp(_protocol, "inet6") == 0))
323 && (_host_buf[0] == '[') && (_host_buf[_host_len - 1] == ']') ) {
324 struct sockaddr_in6 sin6;
325
326 _host_buf[_host_len - 1] = '\0';
327
328 /* Verify address is valid IPv6 numeric form */
329 if (inet_pton(AF_INET6, _host + 1, &sin6) == 1) {
330 /* It is. Use it as such. */
331 _host++;
332 _protocol = "inet6";
333 } else {
334 /* It's not, restore it just in case some other code can use it. */
335 _host_buf[_host_len - 1] = ']';
336 }
337 }
338#endif
339
340
341 /* Get the port */
342
343 _port = mybuf;
344
345#if defined(FONT_t) || defined(FS_t)
346 /*
347 * Is there an optional catalogue list?
348 */
349
350 if ((mybuf = strchr (mybuf,'/')) != NULL)
351 *mybuf ++= '\0';
352
353 /*
354 * The rest, if any, is the (currently unused) catalogue list.
355 *
356 * _catalogue = mybuf;
357 */
358#endif
359
360done_parsing:
361 /*
362 * Now that we have all of the components, allocate new
363 * string space for them.
364 */
365
366 if ((*protocol = strdup (_protocol)) == NULL)
367 {
368 /* Malloc failed */
369 *port = NULL;
370 *host = NULL;
371 *protocol = NULL;
372 free (tmpptr);
373 return 0;
374 }
375
376 if ((*host = strdup (_host)) == NULL)
377 {
378 /* Malloc failed */
379 *port = NULL;
380 *host = NULL;
381 free (*protocol);
382 *protocol = NULL;
383 free (tmpptr);
384 return 0;
385 }
386
387 if ((*port = strdup (_port)) == NULL)
388 {
389 /* Malloc failed */
390 *port = NULL;
391 free (*host);
392 *host = NULL;
393 free (*protocol);
394 *protocol = NULL;
395 free (tmpptr);
396 return 0;
397 }
398
399 free (tmpptr);
400
401 return 1;
402}
403
404
405/*
406 * TRANS(Open) does all of the real work opening a connection. The only
407 * funny part about this is the type parameter which is used to decide which
408 * type of open to perform.
409 */
410
411static XtransConnInfo
412TRANS(Open) (int type, const char *address)
413
414{
415 char *protocol = NULL, *host = NULL, *port = NULL;
416 XtransConnInfo ciptr = NULL;
417 Xtransport *thistrans;
418
419 prmsg (2,"Open(%d,%s)\n", type, address);
420
421#if defined(WIN32) && defined(TCPCONN)
422 if (TRANS(WSAStartup)())
423 {
424 prmsg (1,"Open: WSAStartup failed\n");
425 return NULL;
426 }
427#endif
428
429 /* Parse the Address */
430
431 if (TRANS(ParseAddress) (address, &protocol, &host, &port) == 0)
432 {
433 prmsg (1,"Open: Unable to Parse address %s\n", address);
434 return NULL;
435 }
436
437 /* Determine the transport type */
438
439 if ((thistrans = TRANS(SelectTransport) (protocol)) == NULL)
440 {
441 prmsg (1,"Open: Unable to find transport for %s\n",
442 protocol);
443
444 free (protocol);
445 free (host);
446 free (port);
447 return NULL;
448 }
449
450 /* Open the transport */
451
452 switch (type)
453 {
454 case XTRANS_OPEN_COTS_CLIENT:
455#ifdef TRANS_CLIENT
456 ciptr = thistrans->OpenCOTSClient(thistrans, protocol, host, port);
457#endif /* TRANS_CLIENT */
458 break;
459 case XTRANS_OPEN_COTS_SERVER:
460#ifdef TRANS_SERVER
461 ciptr = thistrans->OpenCOTSServer(thistrans, protocol, host, port);
462#endif /* TRANS_SERVER */
463 break;
464 default:
465 prmsg (1,"Open: Unknown Open type %d\n", type);
466 }
467
468 if (ciptr == NULL)
469 {
470 if (!(thistrans->flags & TRANS_DISABLED))
471 {
472 prmsg (1,"Open: transport open failed for %s/%s:%s\n",
473 protocol, host, port);
474 }
475 free (protocol);
476 free (host);
477 free (port);
478 return NULL;
479 }
480
481 ciptr->transptr = thistrans;
482 ciptr->port = port; /* We need this for TRANS(Reopen) */
483
484 free (protocol);
485 free (host);
486
487 return ciptr;
488}
489
490
491#ifdef TRANS_REOPEN
492
493/*
494 * We might want to create an XtransConnInfo object based on a previously
495 * opened connection. For example, the font server may clone itself and
496 * pass file descriptors to the parent.
497 */
498
499static XtransConnInfo
500TRANS(Reopen) (int type, int trans_id, int fd, const char *port)
501
502{
503 XtransConnInfo ciptr = NULL;
504 Xtransport *thistrans = NULL;
505 char *save_port;
506
507 prmsg (2,"Reopen(%d,%d,%s)\n", trans_id, fd, port);
508
509 /* Determine the transport type */
510
511 for (unsigned int i = 0; i < NUMTRANS; i++)
512 {
513 if (Xtransports[i].transport_id == trans_id)
514 {
515 thistrans = Xtransports[i].transport;
516 break;
517 }
518 }
519
520 if (thistrans == NULL)
521 {
522 prmsg (1,"Reopen: Unable to find transport id %d\n",
523 trans_id);
524
525 return NULL;
526 }
527
528 if ((save_port = strdup (port)) == NULL)
529 {
530 prmsg (1,"Reopen: Unable to malloc port string\n");
531
532 return NULL;
533 }
534
535 /* Get a new XtransConnInfo object */
536
537 switch (type)
538 {
539 case XTRANS_OPEN_COTS_SERVER:
540 ciptr = thistrans->ReopenCOTSServer(thistrans, fd, port);
541 break;
542 default:
543 prmsg (1,"Reopen: Bad Open type %d\n", type);
544 }
545
546 if (ciptr == NULL)
547 {
548 prmsg (1,"Reopen: transport open failed\n");
549 free (save_port);
550 return NULL;
551 }
552
553 ciptr->transptr = thistrans;
554 ciptr->port = save_port;
555
556 return ciptr;
557}
558
559#endif /* TRANS_REOPEN */
560
561
562
563/*
564 * These are the public interfaces to this Transport interface.
565 * These are the only functions that should have knowledge of the transport
566 * table.
567 */
568
569#ifdef TRANS_CLIENT
570
571XtransConnInfo
572TRANS(OpenCOTSClient) (const char *address)
573
574{
575 prmsg (2,"OpenCOTSClient(%s)\n", address);
576 return TRANS(Open) (XTRANS_OPEN_COTS_CLIENT, address);
577}
578
579#endif /* TRANS_CLIENT */
580
581
582#ifdef TRANS_SERVER
583
584XtransConnInfo
585TRANS(OpenCOTSServer) (const char *address)
586
587{
588 prmsg (2,"OpenCOTSServer(%s)\n", address);
589 return TRANS(Open) (XTRANS_OPEN_COTS_SERVER, address);
590}
591
592#endif /* TRANS_SERVER */
593
594
595#ifdef TRANS_REOPEN
596
597XtransConnInfo
598TRANS(ReopenCOTSServer) (int trans_id, int fd, const char *port)
599
600{
601 prmsg (2,"ReopenCOTSServer(%d, %d, %s)\n", trans_id, fd, port);
602 return TRANS(Reopen) (XTRANS_OPEN_COTS_SERVER, trans_id, fd, port);
603}
604
605int
606TRANS(GetReopenInfo) (XtransConnInfo ciptr,
607 int *trans_id, int *fd, char **port)
608
609{
610 for (unsigned int i = 0; i < NUMTRANS; i++)
611 {
612 if (Xtransports[i].transport == ciptr->transptr)
613 {
614 *trans_id = Xtransports[i].transport_id;
615 *fd = ciptr->fd;
616
617 if ((*port = strdup (ciptr->port)) == NULL)
618 return 0;
619 else
620 return 1;
621 }
622 }
623
624 return 0;
625}
626
627#endif /* TRANS_REOPEN */
628
629
630int
631TRANS(SetOption) (XtransConnInfo ciptr, int option, int arg)
632
633{
634 int fd = ciptr->fd;
635 int ret = 0;
636
637 prmsg (2,"SetOption(%d,%d,%d)\n", fd, option, arg);
638
639 /*
640 * For now, all transport type use the same stuff for setting options.
641 * As long as this is true, we can put the common code here. Once a more
642 * complicated transport such as shared memory or an OSI implementation
643 * that uses the session and application libraries is implemented, this
644 * code may have to move to a transport dependent function.
645 *
646 * ret = ciptr->transptr->SetOption (ciptr, option, arg);
647 */
648
649 switch (option)
650 {
651 case TRANS_NONBLOCKING:
652 switch (arg)
653 {
654 case 0:
655 /* Set to blocking mode */
656 break;
657 case 1: /* Set to non-blocking mode */
658
659#if defined(O_NONBLOCK)
660 ret = fcntl (fd, F_GETFL, 0);
661 if (ret != -1)
662 ret = fcntl (fd, F_SETFL, ret | O_NONBLOCK);
663#else
664#ifdef FIOSNBIO
665 {
666 int arg;
667 arg = 1;
668 ret = ioctl (fd, FIOSNBIO, &arg);
669 }
670#else
671#if defined(WIN32)
672 {
673#ifdef WIN32
674 u_long arg;
675#else
676 int arg;
677#endif
678 arg = 1;
679/* IBM TCP/IP understands this option too well: it causes TRANS(Read) to fail
680 * eventually with EWOULDBLOCK */
681 ret = ioctl (fd, FIONBIO, &arg);
682 }
683#else
684 ret = fcntl (fd, F_GETFL, 0);
685#ifdef FNDELAY
686 ret = fcntl (fd, F_SETFL, ret | FNDELAY);
687#else
688 ret = fcntl (fd, F_SETFL, ret | O_NDELAY);
689#endif
690#endif /* AIXV3 || uniosu */
691#endif /* FIOSNBIO */
692#endif /* O_NONBLOCK */
693 break;
694 default:
695 /* Unknown option */
696 break;
697 }
698 break;
699 case TRANS_CLOSEONEXEC:
700#ifdef F_SETFD
701#ifdef FD_CLOEXEC
702 ret = fcntl (fd, F_SETFD, FD_CLOEXEC);
703#else
704 ret = fcntl (fd, F_SETFD, 1);
705#endif /* FD_CLOEXEC */
706#endif /* F_SETFD */
707 break;
708 }
709
710 return ret;
711}
712
713#ifdef TRANS_SERVER
714
715int
716TRANS(CreateListener) (XtransConnInfo ciptr, const char *port, unsigned int flags)
717
718{
719 return ciptr->transptr->CreateListener (ciptr, port, flags);
720}
721
722int
723TRANS(Received) (const char * protocol)
724
725{
726 Xtransport *trans;
727 int i = 0, ret = 0;
728
729 prmsg (5, "Received(%s)\n", protocol);
730
731 if ((trans = TRANS(SelectTransport)(protocol)) == NULL)
732 {
733 prmsg (1,"Received: unable to find transport: %s\n",
734 protocol);
735
736 return -1;
737 }
738 if (trans->flags & TRANS_ALIAS) {
739 if (trans->nolisten)
740 while (trans->nolisten[i]) {
741 ret |= TRANS(Received)(trans->nolisten[i]);
742 i++;
743 }
744 }
745
746 trans->flags |= TRANS_RECEIVED;
747 return ret;
748}
749
750int
751TRANS(NoListen) (const char * protocol)
752
753{
754 Xtransport *trans;
755 int i = 0, ret = 0;
756
757 if ((trans = TRANS(SelectTransport)(protocol)) == NULL)
758 {
759 prmsg (1,"TransNoListen: unable to find transport: %s\n",
760 protocol);
761
762 return -1;
763 }
764 if (trans->flags & TRANS_ALIAS) {
765 if (trans->nolisten)
766 while (trans->nolisten[i]) {
767 ret |= TRANS(NoListen)(trans->nolisten[i]);
768 i++;
769 }
770 }
771
772 trans->flags |= TRANS_NOLISTEN;
773 return ret;
774}
775
776int
777TRANS(Listen) (const char * protocol)
778{
779 Xtransport *trans;
780 int i = 0, ret = 0;
781
782 if ((trans = TRANS(SelectTransport)(protocol)) == NULL)
783 {
784 prmsg (1,"TransListen: unable to find transport: %s\n",
785 protocol);
786
787 return -1;
788 }
789 if (trans->flags & TRANS_ALIAS) {
790 if (trans->nolisten)
791 while (trans->nolisten[i]) {
792 ret |= TRANS(Listen)(trans->nolisten[i]);
793 i++;
794 }
795 }
796
797 trans->flags &= ~TRANS_NOLISTEN;
798 return ret;
799}
800
801int
802TRANS(IsListening) (const char * protocol)
803{
804 Xtransport *trans;
805
806 if ((trans = TRANS(SelectTransport)(protocol)) == NULL)
807 {
808 prmsg (1,"TransIsListening: unable to find transport: %s\n",
809 protocol);
810
811 return 0;
812 }
813
814 return !(trans->flags & TRANS_NOLISTEN);
815}
816
817int
818TRANS(ResetListener) (XtransConnInfo ciptr)
819
820{
821 if (ciptr->transptr->ResetListener)
822 return ciptr->transptr->ResetListener (ciptr);
823 else
824 return TRANS_RESET_NOOP;
825}
826
827
828XtransConnInfo
829TRANS(Accept) (XtransConnInfo ciptr, int *status)
830
831{
832 XtransConnInfo newciptr;
833
834 prmsg (2,"Accept(%d)\n", ciptr->fd);
835
836 newciptr = ciptr->transptr->Accept (ciptr, status);
837
838 if (newciptr)
839 newciptr->transptr = ciptr->transptr;
840
841 return newciptr;
842}
843
844#endif /* TRANS_SERVER */
845
846
847#ifdef TRANS_CLIENT
848
849int
850TRANS(Connect) (XtransConnInfo ciptr, const char *address)
851
852{
853 char *protocol;
854 char *host;
855 char *port;
856 int ret;
857
858 prmsg (2,"Connect(%d,%s)\n", ciptr->fd, address);
859
860 if (TRANS(ParseAddress) (address, &protocol, &host, &port) == 0)
861 {
862 prmsg (1,"Connect: Unable to Parse address %s\n",
863 address);
864 return -1;
865 }
866
867#ifdef HAVE_LAUNCHD
868 if (!host) host=strdup("");
869#endif
870
871 if (!port || !*port)
872 {
873 prmsg (1,"Connect: Missing port specification in %s\n",
874 address);
875 if (protocol) free (protocol);
876 if (host) free (host);
877 return -1;
878 }
879
880 ret = ciptr->transptr->Connect (ciptr, host, port);
881
882 if (protocol) free (protocol);
883 if (host) free (host);
884 if (port) free (port);
885
886 return ret;
887}
888
889#endif /* TRANS_CLIENT */
890
891
892int
893TRANS(BytesReadable) (XtransConnInfo ciptr, BytesReadable_t *pend)
894
895{
896 return ciptr->transptr->BytesReadable (ciptr, pend);
897}
898
899int
900TRANS(Read) (XtransConnInfo ciptr, char *buf, int size)
901
902{
903 return ciptr->transptr->Read (ciptr, buf, size);
904}
905
906int
907TRANS(Write) (XtransConnInfo ciptr, const char *buf, int size)
908
909{
910 return ciptr->transptr->Write (ciptr, buf, size);
911}
912
913int
914TRANS(Readv) (XtransConnInfo ciptr, struct iovec *buf, int size)
915
916{
917 return ciptr->transptr->Readv (ciptr, buf, size);
918}
919
920int
921TRANS(Writev) (XtransConnInfo ciptr, struct iovec *buf, int size)
922
923{
924 return ciptr->transptr->Writev (ciptr, buf, size);
925}
926
927#if XTRANS_SEND_FDS
928int
929TRANS(SendFd) (XtransConnInfo ciptr, int fd, int do_close)
930{
931 return ciptr->transptr->SendFd(ciptr, fd, do_close);
932}
933
934int
935TRANS(RecvFd) (XtransConnInfo ciptr)
936{
937 return ciptr->transptr->RecvFd(ciptr);
938}
939#endif
940
941int
942TRANS(Disconnect) (XtransConnInfo ciptr)
943
944{
945 return ciptr->transptr->Disconnect (ciptr);
946}
947
948int
949TRANS(Close) (XtransConnInfo ciptr)
950
951{
952 int ret;
953
954 prmsg (2,"Close(%d)\n", ciptr->fd);
955
956 ret = ciptr->transptr->Close (ciptr);
957
958 TRANS(FreeConnInfo) (ciptr);
959
960 return ret;
961}
962
963int
964TRANS(CloseForCloning) (XtransConnInfo ciptr)
965
966{
967 int ret;
968
969 prmsg (2,"CloseForCloning(%d)\n", ciptr->fd);
970
971 ret = ciptr->transptr->CloseForCloning (ciptr);
972
973 TRANS(FreeConnInfo) (ciptr);
974
975 return ret;
976}
977
978int
979TRANS(IsLocal) (XtransConnInfo ciptr)
980
981{
982 return (ciptr->family == AF_UNIX);
983}
984
985int
986TRANS(GetPeerAddr) (XtransConnInfo ciptr, int *familyp, int *addrlenp,
987 Xtransaddr **addrp)
988
989{
990 prmsg (2,"GetPeerAddr(%d)\n", ciptr->fd);
991
992 *familyp = ciptr->family;
993 *addrlenp = ciptr->peeraddrlen;
994
995 if ((*addrp = malloc (ciptr->peeraddrlen)) == NULL)
996 {
997 prmsg (1,"GetPeerAddr: malloc failed\n");
998 return -1;
999 }
1000 memcpy(*addrp, ciptr->peeraddr, ciptr->peeraddrlen);
1001
1002 return 0;
1003}
1004
1005
1006int
1007TRANS(GetConnectionNumber) (XtransConnInfo ciptr)
1008
1009{
1010 return ciptr->fd;
1011}
1012
1013
1014/*
1015 * These functions are really utility functions, but they require knowledge
1016 * of the internal data structures, so they have to be part of the Transport
1017 * Independent API.
1018 */
1019
1020#ifdef TRANS_SERVER
1021
1022static int
1023complete_network_count (void)
1024
1025{
1026 int count = 0;
1027 int found_local = 0;
1028
1029 /*
1030 * For a complete network, we only need one LOCALCONN transport to work
1031 */
1032
1033 for (unsigned int i = 0; i < NUMTRANS; i++)
1034 {
1035 if (Xtransports[i].transport->flags & TRANS_ALIAS
1036 || Xtransports[i].transport->flags & TRANS_NOLISTEN)
1037 continue;
1038
1039 if (Xtransports[i].transport->flags & TRANS_LOCAL)
1040 found_local = 1;
1041 else
1042 count++;
1043 }
1044
1045 return (count + found_local);
1046}
1047
1048
1049static int
1050receive_listening_fds(const char* port, XtransConnInfo* temp_ciptrs,
1051 int* count_ret)
1052
1053{
1054#ifdef HAVE_SYSTEMD_DAEMON
1055 XtransConnInfo ciptr;
1056 int i, systemd_listen_fds;
1057
1058 systemd_listen_fds = sd_listen_fds(1);
1059 if (systemd_listen_fds < 0)
1060 {
1061 prmsg (1, "receive_listening_fds: sd_listen_fds error: %s\n",
1062 strerror(-systemd_listen_fds));
1063 return -1;
1064 }
1065
1066 for (i = 0; i < systemd_listen_fds && *count_ret < (int)NUMTRANS; i++)
1067 {
1068 struct sockaddr_storage a;
1069 int ti;
1070 const char* tn;
1071 socklen_t al;
1072
1073 al = sizeof(a);
1074 if (getsockname(i + SD_LISTEN_FDS_START, (struct sockaddr*)&a, &al) < 0) {
1075 prmsg (1, "receive_listening_fds: getsockname error: %s\n",
1076 strerror(errno));
1077 return -1;
1078 }
1079
1080 switch (a.ss_family)
1081 {
1082 case AF_UNIX:
1083 ti = TRANS_SOCKET_UNIX_INDEX;
1084 if (*((struct sockaddr_un*)&a)->sun_path == '\0' &&
1085 al > sizeof(sa_family_t))
1086 tn = "local";
1087 else
1088 tn = "unix";
1089 break;
1090 case AF_INET:
1091 ti = TRANS_SOCKET_INET_INDEX;
1092 tn = "inet";
1093 break;
1094#ifdef IPv6
1095 case AF_INET6:
1096 ti = TRANS_SOCKET_INET6_INDEX;
1097 tn = "inet6";
1098 break;
1099#endif /* IPv6 */
1100 default:
1101 prmsg (1, "receive_listening_fds:"
1102 "Got unknown socket address family\n");
1103 return -1;
1104 }
1105
1106 ciptr = TRANS(ReopenCOTSServer)(ti, i + SD_LISTEN_FDS_START, port);
1107 if (!ciptr)
1108 {
1109 prmsg (1, "receive_listening_fds:"
1110 "Got NULL while trying to reopen socket received from systemd.\n");
1111 return -1;
1112 }
1113
1114 prmsg (5, "receive_listening_fds: received listener for %s, %d\n",
1115 tn, ciptr->fd);
1116 temp_ciptrs[(*count_ret)++] = ciptr;
1117 TRANS(Received)(tn);
1118 }
1119#endif /* HAVE_SYSTEMD_DAEMON */
1120 return 0;
1121}
1122
1123#ifdef XQUARTZ_EXPORTS_LAUNCHD_FD
1124extern int xquartz_launchd_fd;
1125#endif
1126
1127int
1128TRANS(MakeAllCOTSServerListeners) (const char *port, int *partial,
1129 int *count_ret, XtransConnInfo **ciptrs_ret)
1130
1131{
1132 char buffer[256]; /* ??? What size ?? */
1133 XtransConnInfo ciptr, temp_ciptrs[NUMTRANS] = { NULL };
1134 int status, j;
1135
1136#ifdef IPv6
1137 int ipv6_succ = 0;
1138#endif
1139 prmsg (2,"MakeAllCOTSServerListeners(%s,%p)\n",
1140 port ? port : "NULL", (void *) ciptrs_ret);
1141
1142 *count_ret = 0;
1143
1144#ifdef XQUARTZ_EXPORTS_LAUNCHD_FD
1145 fprintf(stderr, "Launchd socket fd: %d\n", xquartz_launchd_fd);
1146 if(xquartz_launchd_fd != -1) {
1147 if((ciptr = TRANS(ReopenCOTSServer(TRANS_SOCKET_LOCAL_INDEX,
1148 xquartz_launchd_fd, getenv("DISPLAY"))))==NULL)
1149 fprintf(stderr,"Got NULL while trying to Reopen launchd port\n");
1150 else
1151 temp_ciptrs[(*count_ret)++] = ciptr;
1152 }
1153#endif
1154
1155 if (receive_listening_fds(port, temp_ciptrs, count_ret) < 0)
1156 return -1;
1157
1158 for (unsigned int i = 0; i < NUMTRANS; i++)
1159 {
1160 Xtransport *trans = Xtransports[i].transport;
1161 unsigned int flags = 0;
1162
1163 if (trans->flags&TRANS_ALIAS || trans->flags&TRANS_NOLISTEN ||
1164 trans->flags&TRANS_RECEIVED)
1165 continue;
1166
1167 snprintf(buffer, sizeof(buffer), "%s/:%s",
1168 trans->TransName, port ? port : "");
1169
1170 prmsg (5,"MakeAllCOTSServerListeners: opening %s\n",
1171 buffer);
1172
1173 if ((ciptr = TRANS(OpenCOTSServer(buffer))) == NULL)
1174 {
1175 if (trans->flags & TRANS_DISABLED)
1176 continue;
1177
1178 prmsg (1,
1179 "MakeAllCOTSServerListeners: failed to open listener for %s\n",
1180 trans->TransName);
1181 continue;
1182 }
1183#ifdef IPv6
1184 if ((Xtransports[i].transport_id == TRANS_SOCKET_INET_INDEX
1185 && ipv6_succ))
1186 flags |= ADDR_IN_USE_ALLOWED;
1187#endif
1188
1189 if ((status = TRANS(CreateListener (ciptr, port, flags))) < 0)
1190 {
1191 if (*partial != 0)
1192 continue;
1193
1194 if (status == TRANS_ADDR_IN_USE)
1195 {
1196 /*
1197 * We failed to bind to the specified address because the
1198 * address is in use. It must be that a server is already
1199 * running at this address, and this function should fail.
1200 */
1201
1202 prmsg (1,
1203 "MakeAllCOTSServerListeners: server already running\n");
1204
1205 for (j = 0; j < *count_ret; j++)
1206 if (temp_ciptrs[j] != NULL)
1207 TRANS(Close) (temp_ciptrs[j]);
1208
1209 *count_ret = 0;
1210 *ciptrs_ret = NULL;
1211 *partial = 0;
1212 return -1;
1213 }
1214 else
1215 {
1216 prmsg (1,
1217 "MakeAllCOTSServerListeners: failed to create listener for %s\n",
1218 trans->TransName);
1219
1220 continue;
1221 }
1222 }
1223
1224#ifdef IPv6
1225 if (Xtransports[i].transport_id == TRANS_SOCKET_INET6_INDEX)
1226 ipv6_succ = 1;
1227#endif
1228
1229 prmsg (5,
1230 "MakeAllCOTSServerListeners: opened listener for %s, %d\n",
1231 trans->TransName, ciptr->fd);
1232
1233 temp_ciptrs[*count_ret] = ciptr;
1234 (*count_ret)++;
1235 }
1236
1237 *partial = (*count_ret < complete_network_count());
1238
1239 prmsg (5,
1240 "MakeAllCOTSServerListeners: partial=%d, actual=%d, complete=%d \n",
1241 *partial, *count_ret, complete_network_count());
1242
1243 if (*count_ret > 0)
1244 {
1245 if ((*ciptrs_ret = malloc (
1246 *count_ret * sizeof (XtransConnInfo))) == NULL)
1247 {
1248 return -1;
1249 }
1250
1251 for (int i = 0; i < *count_ret; i++)
1252 {
1253 (*ciptrs_ret)[i] = temp_ciptrs[i];
1254 }
1255 }
1256 else
1257 *ciptrs_ret = NULL;
1258
1259 return 0;
1260}
1261
1262#endif /* TRANS_SERVER */
1263
1264
1265
1266/*
1267 * These routines are not part of the X Transport Interface, but they
1268 * may be used by it.
1269 */
1270
1271
1272#ifdef WIN32
1273
1274/*
1275 * emulate readv
1276 */
1277
1278static int TRANS(ReadV) (XtransConnInfo ciptr, struct iovec *iov, int iovcnt)
1279
1280{
1281 int i, len, total;
1282 char *base;
1283
1284 ESET(0);
1285 for (i = 0, total = 0; i < iovcnt; i++, iov++) {
1286 len = iov->iov_len;
1287 base = iov->iov_base;
1288 while (len > 0) {
1289 register int nbytes;
1290 nbytes = TRANS(Read) (ciptr, base, len);
1291 if (nbytes < 0 && total == 0) return -1;
1292 if (nbytes <= 0) return total;
1293 ESET(0);
1294 len -= nbytes;
1295 total += nbytes;
1296 base += nbytes;
1297 }
1298 }
1299 return total;
1300}
1301
1302
1303/*
1304 * emulate writev
1305 */
1306
1307static int TRANS(WriteV) (XtransConnInfo ciptr, struct iovec *iov, int iovcnt)
1308
1309{
1310 int i, len, total;
1311 char *base;
1312
1313 ESET(0);
1314 for (i = 0, total = 0; i < iovcnt; i++, iov++) {
1315 len = iov->iov_len;
1316 base = iov->iov_base;
1317 while (len > 0) {
1318 register int nbytes;
1319 nbytes = TRANS(Write) (ciptr, base, len);
1320 if (nbytes < 0 && total == 0) return -1;
1321 if (nbytes <= 0) return total;
1322 ESET(0);
1323 len -= nbytes;
1324 total += nbytes;
1325 base += nbytes;
1326 }
1327 }
1328 return total;
1329}
1330
1331#endif /* WIN32 */
1332
1333
1334#if defined(_POSIX_SOURCE) || defined(SVR4) || defined(__SVR4)
1335#ifndef NEED_UTSNAME
1336#define NEED_UTSNAME
1337#endif
1338#include <sys/utsname.h>
1339#endif
1340
1341/*
1342 * TRANS(GetHostname) - similar to gethostname but allows special processing.
1343 */
1344
1345int TRANS(GetHostname) (char *buf, int maxlen)
1346
1347{
1348 int len;
1349
1350#ifdef NEED_UTSNAME
1351 struct utsname name;
1352
1353 uname (&name);
1354 len = strlen (name.nodename);
1355 if (len >= maxlen) len = maxlen - 1;
1356 memcpy (buf, name.nodename, len);
1357 buf[len] = '\0';
1358#else
1359 buf[0] = '\0';
1360 (void) gethostname (buf, maxlen);
1361 buf [maxlen - 1] = '\0';
1362 len = strlen(buf);
1363#endif /* NEED_UTSNAME */
1364 return len;
1365}