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