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