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