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