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