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