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