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