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