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