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