Xtranslcl.c revision e45ace2b
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/*
51 *
52 * The connection code/ideas in lib/X and server/os for SVR4/Intel
53 * environments was contributed by the following companies/groups:
54 *
55 *	MetroLink Inc
56 *	NCR
57 *	Pittsburgh Powercomputing Corporation (PPc)/Quarterdeck Office Systems
58 *	SGCS
59 *	Unix System Laboratories (USL) / Novell
60 *	XFree86
61 *
62 * The goal is to have common connection code among all SVR4/Intel vendors.
63 *
64 * ALL THE ABOVE COMPANIES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
65 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
66 * IN NO EVENT SHALL THESE COMPANIES * BE LIABLE FOR ANY SPECIAL, INDIRECT
67 * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
68 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
69 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
70 * OR PERFORMANCE OF THIS SOFTWARE.
71 */
72
73#include <errno.h>
74#include <ctype.h>
75#include <sys/signal.h>
76#include <sys/ioctl.h>
77#include <sys/stat.h>
78#if defined(SVR4) || defined(__SVR4)
79#include <sys/filio.h>
80#endif
81# include <stropts.h>
82#include <sys/wait.h>
83#include <sys/types.h>
84
85/*
86 * The local transports should be treated the same as a UNIX domain socket
87 * wrt authentication, etc. Because of this, we will use struct sockaddr_un
88 * for the address format. This will simplify the code in other places like
89 * The X Server.
90 */
91
92#include <sys/socket.h>
93#ifndef X_NO_SYS_UN
94#include <sys/un.h>
95#endif
96
97
98/* Types of local connections supported:
99 *  - PTS
100 *  - named pipes
101 */
102#if defined(SVR4) || defined(__SVR4)
103# define LOCAL_TRANS_NAMED
104#endif
105
106static int TRANS(LocalClose)(XtransConnInfo ciptr);
107
108/*
109 * These functions actually implement the local connection mechanisms.
110 */
111
112/* Type Not Supported */
113
114static int
115TRANS(OpenFail)(XtransConnInfo ciptr _X_UNUSED, const char *port _X_UNUSED)
116
117{
118    return -1;
119}
120
121#ifdef TRANS_REOPEN
122
123static int
124TRANS(ReopenFail)(XtransConnInfo ciptr _X_UNUSED, int fd _X_UNUSED,
125                  const char *port _X_UNUSED)
126
127{
128    return 0;
129}
130
131#endif /* TRANS_REOPEN */
132
133#if XTRANS_SEND_FDS
134static int
135TRANS(LocalRecvFdInvalid)(XtransConnInfo ciptr)
136{
137    errno = EINVAL;
138    return -1;
139}
140
141static int
142TRANS(LocalSendFdInvalid)(XtransConnInfo ciptr, int fd, int do_close)
143{
144    errno = EINVAL;
145    return -1;
146}
147#endif
148
149
150static int
151TRANS(FillAddrInfo)(XtransConnInfo ciptr,
152                    const char *sun_path, const char *peer_sun_path)
153
154{
155    struct sockaddr_un	*sunaddr;
156    struct sockaddr_un	*p_sunaddr;
157
158    ciptr->family = AF_UNIX;
159    ciptr->addrlen = sizeof (struct sockaddr_un);
160
161    if ((sunaddr = malloc (ciptr->addrlen)) == NULL)
162    {
163	prmsg(1,"FillAddrInfo: failed to allocate memory for addr\n");
164	return 0;
165    }
166
167    sunaddr->sun_family = AF_UNIX;
168
169    if (strlen(sun_path) > sizeof(sunaddr->sun_path) - 1) {
170	prmsg(1, "FillAddrInfo: path too long\n");
171	free((char *) sunaddr);
172	return 0;
173    }
174    strcpy (sunaddr->sun_path, sun_path);
175#if defined(BSD44SOCKETS)
176    sunaddr->sun_len = strlen (sunaddr->sun_path);
177#endif
178
179    ciptr->addr = (char *) sunaddr;
180
181    ciptr->peeraddrlen = sizeof (struct sockaddr_un);
182
183    if ((p_sunaddr = malloc (ciptr->peeraddrlen)) == NULL)
184    {
185	prmsg(1,
186	   "FillAddrInfo: failed to allocate memory for peer addr\n");
187	free (sunaddr);
188	ciptr->addr = NULL;
189
190	return 0;
191    }
192
193    p_sunaddr->sun_family = AF_UNIX;
194
195    if (strlen(peer_sun_path) > sizeof(p_sunaddr->sun_path) - 1) {
196	prmsg(1, "FillAddrInfo: peer path too long\n");
197	free((char *) p_sunaddr);
198	return 0;
199    }
200    strcpy (p_sunaddr->sun_path, peer_sun_path);
201#if defined(BSD44SOCKETS)
202    p_sunaddr->sun_len = strlen (p_sunaddr->sun_path);
203#endif
204
205    ciptr->peeraddr = (char *) p_sunaddr;
206
207    return 1;
208}
209
210
211
212
213#ifndef X11_t
214#define X_STREAMS_DIR	"/dev/X"
215#else
216#define X_STREAMS_DIR	"/tmp/.X11-pipe"
217#endif
218
219#define DEV_PTMX	"/dev/ptmx"
220
221#if defined(X11_t)
222
223#define NAMEDNODENAME "/tmp/.X11-pipe/X"
224#endif
225#if defined(XIM_t)
226#define NAMEDNODENAME "/tmp/.XIM-pipe/XIM"
227#endif
228#if defined(FS_t) || defined (FONT_t)
229#define NAMEDNODENAME	"/tmp/.font-pipe/fs"
230#endif
231#if defined(ICE_t)
232#define NAMEDNODENAME	"/tmp/.ICE-pipe/"
233#endif
234
235
236
237
238
239#ifdef LOCAL_TRANS_NAMED
240
241/* NAMED */
242
243#ifdef TRANS_CLIENT
244
245static int
246TRANS(NAMEDOpenClient)(XtransConnInfo ciptr, const char *port)
247
248{
249#ifdef NAMEDNODENAME
250    int			fd;
251    char		server_path[64];
252    struct stat		filestat;
253#endif
254
255    prmsg(2,"NAMEDOpenClient(%s)\n", port);
256
257#if !defined(NAMEDNODENAME)
258    prmsg(1,"NAMEDOpenClient: Protocol is not supported by a NAMED connection\n");
259    return -1;
260#else
261    if ( port && *port ) {
262	if( *port == '/' ) { /* A full pathname */
263		(void) snprintf(server_path, sizeof(server_path), "%s", port);
264	    } else {
265		(void) snprintf(server_path, sizeof(server_path), "%s%s", NAMEDNODENAME, port);
266	    }
267    } else {
268	(void) snprintf(server_path, sizeof(server_path), "%s%ld", NAMEDNODENAME, (long)getpid());
269    }
270
271    if ((fd = open(server_path, O_RDWR)) < 0) {
272	prmsg(1,"NAMEDOpenClient: Cannot open %s for NAMED connection\n", server_path);
273	return -1;
274    }
275
276    if (fstat(fd, &filestat) < 0 ) {
277	prmsg(1,"NAMEDOpenClient: Cannot stat %s for NAMED connection\n", server_path);
278	(void) close(fd);
279	return -1;
280    }
281
282    if ((filestat.st_mode & S_IFMT) != S_IFIFO) {
283	prmsg(1,"NAMEDOpenClient: Device %s is not a FIFO\n", server_path);
284	/* Is this really a failure? */
285	(void) close(fd);
286	return -1;
287    }
288
289
290    if (isastream(fd) <= 0) {
291	prmsg(1,"NAMEDOpenClient: %s is not a streams device\n", server_path);
292	(void) close(fd);
293	return -1;
294    }
295
296    /*
297     * Everything looks good: fill in the XtransConnInfo structure.
298     */
299
300    if (TRANS(FillAddrInfo) (ciptr, server_path, server_path) == 0)
301    {
302	prmsg(1,"NAMEDOpenClient: failed to fill in addr info\n");
303	close(fd);
304	return -1;
305    }
306
307    return(fd);
308
309#endif /* !NAMEDNODENAME */
310}
311
312#endif /* TRANS_CLIENT */
313
314
315#ifdef TRANS_SERVER
316
317
318#ifdef NAMEDNODENAME
319static int
320TRANS(NAMEDOpenPipe)(const char *server_path)
321{
322    int			fd, pipefd[2];
323    struct stat		sbuf;
324    int			mode;
325
326    prmsg(2,"NAMEDOpenPipe(%s)\n", server_path);
327
328#ifdef HAS_STICKY_DIR_BIT
329    mode = 01777;
330#else
331    mode = 0777;
332#endif
333    if (trans_mkdir(X_STREAMS_DIR, mode) == -1) {
334	prmsg (1, "NAMEDOpenPipe: mkdir(%s) failed, errno = %d\n",
335	       X_STREAMS_DIR, errno);
336	return(-1);
337    }
338
339    if(stat(server_path, &sbuf) != 0) {
340	if (errno == ENOENT) {
341	    if ((fd = creat(server_path, (mode_t)0666)) == -1) {
342		prmsg(1, "NAMEDOpenPipe: Can't open %s\n", server_path);
343		return(-1);
344	    }
345	    if (fchmod(fd, (mode_t)0666) < 0) {
346		prmsg(1, "NAMEDOpenPipe: Can't chmod %s\n", server_path);
347		close(fd);
348		return(-1);
349	    }
350	    close(fd);
351	} else {
352	    prmsg(1, "NAMEDOpenPipe: stat on %s failed\n", server_path);
353	    return(-1);
354	}
355    }
356
357    if( pipe(pipefd) != 0) {
358	prmsg(1, "NAMEDOpenPipe: pipe() failed, errno=%d\n",errno);
359	return(-1);
360    }
361
362    if( ioctl(pipefd[0], I_PUSH, "connld") != 0) {
363	prmsg(1, "NAMEDOpenPipe: ioctl(I_PUSH,\"connld\") failed, errno=%d\n",errno);
364	close(pipefd[0]);
365	close(pipefd[1]);
366	return(-1);
367    }
368
369    if( fattach(pipefd[0], server_path) != 0) {
370	prmsg(1, "NAMEDOpenPipe: fattach(%s) failed, errno=%d\n", server_path,errno);
371	close(pipefd[0]);
372	close(pipefd[1]);
373	return(-1);
374    }
375
376    return(pipefd[1]);
377}
378#endif
379
380static int
381TRANS(NAMEDOpenServer)(XtransConnInfo ciptr, const char *port)
382{
383#ifdef NAMEDNODENAME
384    int			fd;
385    char		server_path[64];
386#endif
387
388    prmsg(2,"NAMEDOpenServer(%s)\n", port);
389
390#if !defined(NAMEDNODENAME)
391    prmsg(1,"NAMEDOpenServer: Protocol is not supported by a NAMED connection\n");
392    return -1;
393#else
394    if ( port && *port ) {
395	if( *port == '/' ) { /* A full pathname */
396	    (void) snprintf(server_path, sizeof(server_path), "%s", port);
397	} else {
398	    (void) snprintf(server_path, sizeof(server_path), "%s%s",
399			    NAMEDNODENAME, port);
400	}
401    } else {
402	(void) snprintf(server_path, sizeof(server_path), "%s%ld",
403		       NAMEDNODENAME, (long)getpid());
404    }
405
406    fd = TRANS(NAMEDOpenPipe)(server_path);
407    if (fd < 0) {
408	return -1;
409    }
410
411    /*
412     * Everything looks good: fill in the XtransConnInfo structure.
413     */
414
415    if (TRANS(FillAddrInfo) (ciptr, server_path, server_path) == 0)
416    {
417	prmsg(1,"NAMEDOpenServer: failed to fill in addr info\n");
418	TRANS(LocalClose)(ciptr);
419	return -1;
420    }
421
422    return fd;
423
424#endif /* !NAMEDNODENAME */
425}
426
427static int
428TRANS(NAMEDResetListener) (XtransConnInfo ciptr)
429
430{
431  struct sockaddr_un      *sockname=(struct sockaddr_un *) ciptr->addr;
432  struct stat     statb;
433
434  prmsg(2,"NAMEDResetListener(%p, %d)\n", ciptr, ciptr->fd);
435
436  if (ciptr->fd != -1) {
437    /*
438     * see if the pipe has disappeared
439     */
440
441    if (stat (sockname->sun_path, &statb) == -1 ||
442	(statb.st_mode & S_IFMT) != S_IFIFO) {
443      prmsg(3, "Pipe %s trashed, recreating\n", sockname->sun_path);
444      TRANS(LocalClose)(ciptr);
445      ciptr->fd = TRANS(NAMEDOpenPipe)(sockname->sun_path);
446      if (ciptr->fd >= 0)
447	  return TRANS_RESET_NEW_FD;
448      else
449	  return TRANS_CREATE_LISTENER_FAILED;
450    }
451  }
452  return TRANS_RESET_NOOP;
453}
454
455static int
456TRANS(NAMEDAccept)(XtransConnInfo ciptr, XtransConnInfo newciptr, int *status)
457
458{
459    struct strrecvfd str;
460
461    prmsg(2,"NAMEDAccept(%p->%d)\n", ciptr, ciptr->fd);
462
463    if( ioctl(ciptr->fd, I_RECVFD, &str ) < 0 ) {
464	prmsg(1, "NAMEDAccept: ioctl(I_RECVFD) failed, errno=%d\n", errno);
465	*status = TRANS_ACCEPT_MISC_ERROR;
466	return(-1);
467    }
468
469    /*
470     * Everything looks good: fill in the XtransConnInfo structure.
471     */
472    newciptr->family=ciptr->family;
473    newciptr->addrlen=ciptr->addrlen;
474    if( (newciptr->addr = malloc(newciptr->addrlen)) == NULL ) {
475	prmsg(1,
476	      "NAMEDAccept: failed to allocate memory for pipe addr\n");
477	close(str.fd);
478	*status = TRANS_ACCEPT_BAD_MALLOC;
479	return -1;
480    }
481
482    memcpy(newciptr->addr,ciptr->addr,newciptr->addrlen);
483
484    newciptr->peeraddrlen=newciptr->addrlen;
485    if( (newciptr->peeraddr = malloc(newciptr->peeraddrlen)) == NULL ) {
486	prmsg(1,
487	"NAMEDAccept: failed to allocate memory for peer addr\n");
488	free(newciptr->addr);
489	close(str.fd);
490	*status = TRANS_ACCEPT_BAD_MALLOC;
491	return -1;
492    }
493
494    memcpy(newciptr->peeraddr,newciptr->addr,newciptr->peeraddrlen);
495
496    *status = 0;
497
498    return str.fd;
499}
500
501#endif /* TRANS_SERVER */
502
503#endif /* LOCAL_TRANS_NAMED */
504
505
506
507
508
509
510
511
512
513
514#ifdef TRANS_REOPEN
515
516#ifdef LOCAL_TRANS_NAMED
517
518static int
519TRANS(NAMEDReopenServer)(XtransConnInfo ciptr, int fd _X_UNUSED, const char *port)
520
521{
522#ifdef NAMEDNODENAME
523    char server_path[64];
524#endif
525
526    prmsg(2,"NAMEDReopenServer(%s)\n", port);
527
528#if !defined(NAMEDNODENAME)
529    prmsg(1,"NAMEDReopenServer: Protocol is not supported by a NAMED connection\n");
530    return 0;
531#else
532    if ( port && *port ) {
533	if( *port == '/' ) { /* A full pathname */
534	    snprintf(server_path, sizeof(server_path),"%s", port);
535	} else {
536	    snprintf(server_path, sizeof(server_path), "%s%s",
537		     NAMEDNODENAME, port);
538	}
539    } else {
540	snprintf(server_path, sizeof(server_path), "%s%ld",
541		NAMEDNODENAME, (long)getpid());
542    }
543
544    if (TRANS(FillAddrInfo) (ciptr, server_path, server_path) == 0)
545    {
546	prmsg(1,"NAMEDReopenServer: failed to fill in addr info\n");
547	return 0;
548    }
549
550    return 1;
551
552#endif /* !NAMEDNODENAME */
553}
554
555#endif /* LOCAL_TRANS_NAMED */
556
557
558
559#endif /* TRANS_REOPEN */
560
561
562
563/*
564 * This table contains all of the entry points for the different local
565 * connection mechanisms.
566 */
567
568typedef struct _LOCALtrans2dev {
569    const char	*transname;
570
571#ifdef TRANS_CLIENT
572
573    int	(*devcotsopenclient)(
574	XtransConnInfo, const char * /*port*/
575);
576
577#endif /* TRANS_CLIENT */
578
579#ifdef TRANS_SERVER
580
581    int	(*devcotsopenserver)(
582	XtransConnInfo, const char * /*port*/
583);
584
585#endif /* TRANS_SERVER */
586
587#ifdef TRANS_CLIENT
588
589    int	(*devcltsopenclient)(
590	XtransConnInfo, const char * /*port*/
591);
592
593#endif /* TRANS_CLIENT */
594
595#ifdef TRANS_SERVER
596
597    int	(*devcltsopenserver)(
598	XtransConnInfo, const char * /*port*/
599);
600
601#endif /* TRANS_SERVER */
602
603#ifdef TRANS_REOPEN
604
605    int	(*devcotsreopenserver)(
606	XtransConnInfo,
607	int, 	/* fd */
608	const char * 	/* port */
609);
610
611    int	(*devcltsreopenserver)(
612	XtransConnInfo,
613	int, 	/* fd */
614	const char *	/* port */
615);
616
617#endif /* TRANS_REOPEN */
618
619#ifdef TRANS_SERVER
620
621    int (*devreset)(
622	XtransConnInfo /* ciptr */
623);
624
625    int	(*devaccept)(
626	XtransConnInfo, XtransConnInfo, int *
627);
628
629#endif /* TRANS_SERVER */
630
631} LOCALtrans2dev;
632
633static LOCALtrans2dev LOCALtrans2devtab[] = {
634{"",
635#ifdef TRANS_CLIENT
636     TRANS(NAMEDOpenClient),
637#endif /* TRANS_CLIENT */
638#ifdef TRANS_SERVER
639     TRANS(NAMEDOpenServer),
640#endif /* TRANS_SERVER */
641#ifdef TRANS_CLIENT
642     TRANS(OpenFail),
643#endif /* TRANS_CLIENT */
644#ifdef TRANS_SERVER
645     TRANS(OpenFail),
646#endif /* TRANS_SERVER */
647#ifdef TRANS_REOPEN
648     TRANS(NAMEDReopenServer),
649     TRANS(ReopenFail),
650#endif
651#ifdef TRANS_SERVER
652     TRANS(NAMEDResetListener),
653     TRANS(NAMEDAccept)
654#endif /* TRANS_SERVER */
655},
656
657{"local",
658#ifdef TRANS_CLIENT
659     TRANS(NAMEDOpenClient),
660#endif /* TRANS_CLIENT */
661#ifdef TRANS_SERVER
662     TRANS(NAMEDOpenServer),
663#endif /* TRANS_SERVER */
664#ifdef TRANS_CLIENT
665     TRANS(OpenFail),
666#endif /* TRANS_CLIENT */
667#ifdef TRANS_SERVER
668     TRANS(OpenFail),
669#endif /* TRANS_SERVER */
670#ifdef TRANS_REOPEN
671     TRANS(NAMEDReopenServer),
672     TRANS(ReopenFail),
673#endif
674#ifdef TRANS_SERVER
675     TRANS(NAMEDResetListener),
676     TRANS(NAMEDAccept)
677#endif /* TRANS_SERVER */
678},
679
680#ifdef LOCAL_TRANS_NAMED
681{"named",
682#ifdef TRANS_CLIENT
683     TRANS(NAMEDOpenClient),
684#endif /* TRANS_CLIENT */
685#ifdef TRANS_SERVER
686     TRANS(NAMEDOpenServer),
687#endif /* TRANS_SERVER */
688#ifdef TRANS_CLIENT
689     TRANS(OpenFail),
690#endif /* TRANS_CLIENT */
691#ifdef TRANS_SERVER
692     TRANS(OpenFail),
693#endif /* TRANS_SERVER */
694#ifdef TRANS_REOPEN
695     TRANS(NAMEDReopenServer),
696     TRANS(ReopenFail),
697#endif
698#ifdef TRANS_SERVER
699     TRANS(NAMEDResetListener),
700     TRANS(NAMEDAccept)
701#endif /* TRANS_SERVER */
702},
703
704{"pipe",
705#ifdef TRANS_CLIENT
706     TRANS(NAMEDOpenClient),
707#endif /* TRANS_CLIENT */
708#ifdef TRANS_SERVER
709     TRANS(NAMEDOpenServer),
710#endif /* TRANS_SERVER */
711#ifdef TRANS_CLIENT
712     TRANS(OpenFail),
713#endif /* TRANS_CLIENT */
714#ifdef TRANS_SERVER
715     TRANS(OpenFail),
716#endif /* TRANS_SERVER */
717#ifdef TRANS_REOPEN
718     TRANS(NAMEDReopenServer),
719     TRANS(ReopenFail),
720#endif
721#ifdef TRANS_SERVER
722     TRANS(NAMEDResetListener),
723     TRANS(NAMEDAccept)
724#endif /* TRANS_SERVER */
725},
726#endif /* LOCAL_TRANS_NAMED */
727
728
729};
730
731#define NUMTRANSPORTS	(sizeof(LOCALtrans2devtab)/sizeof(LOCALtrans2dev))
732
733static const char	*XLOCAL=NULL;
734static	char	*workingXLOCAL=NULL;
735static	char	*freeXLOCAL=NULL;
736
737#define DEF_XLOCAL "UNIX:NAMED"
738
739static void
740TRANS(LocalInitTransports)(const char *protocol)
741
742{
743    prmsg(3,"LocalInitTransports(%s)\n", protocol);
744
745    if( strcmp(protocol,"local") && strcmp(protocol,"LOCAL") )
746    {
747	workingXLOCAL = freeXLOCAL = strdup (protocol);
748    }
749    else {
750	XLOCAL=(char *)getenv("XLOCAL");
751	if(XLOCAL==NULL)
752	    XLOCAL=DEF_XLOCAL;
753	workingXLOCAL = freeXLOCAL = strdup (XLOCAL);
754    }
755}
756
757static void
758TRANS(LocalEndTransports)(void)
759
760{
761    prmsg(3,"LocalEndTransports()\n");
762    free(freeXLOCAL);
763    freeXLOCAL = NULL;
764}
765
766#define TYPEBUFSIZE	32
767
768#ifdef TRANS_CLIENT
769
770static LOCALtrans2dev *
771TRANS(LocalGetNextTransport)(void)
772
773{
774    int		i;
775    char	*typetocheck;
776    prmsg(3,"LocalGetNextTransport()\n");
777
778    while(1)
779    {
780	if( workingXLOCAL == NULL || *workingXLOCAL == '\0' )
781	    return NULL;
782
783	typetocheck=workingXLOCAL;
784	workingXLOCAL=strchr(workingXLOCAL,':');
785	if(workingXLOCAL && *workingXLOCAL)
786	    *workingXLOCAL++='\0';
787
788	for(i=0;i<NUMTRANSPORTS;i++)
789	{
790#ifndef HAVE_STRCASECMP
791	    int		j;
792	    char	typebuf[TYPEBUFSIZE];
793	    /*
794	     * This is equivalent to a case insensitive strcmp(),
795	     * but should be more portable.
796	     */
797	    strncpy(typebuf,typetocheck,TYPEBUFSIZE);
798	    for(j=0;j<TYPEBUFSIZE;j++)
799		if (isupper(typebuf[j]))
800		    typebuf[j]=tolower(typebuf[j]);
801
802	    /* Now, see if they match */
803	    if(!strcmp(LOCALtrans2devtab[i].transname,typebuf))
804#else
805	    if(!strcasecmp(LOCALtrans2devtab[i].transname,typetocheck))
806#endif
807		return &LOCALtrans2devtab[i];
808	}
809    }
810#if 0
811    /*NOTREACHED*/
812    return NULL;
813#endif
814}
815
816#ifdef NEED_UTSNAME
817#include <sys/utsname.h>
818#endif
819
820/*
821 * Make sure 'host' is really local.
822 */
823
824static int
825HostReallyLocal (const char *host)
826
827{
828    /*
829     * The 'host' passed to this function may have been generated
830     * by either uname() or gethostname().  We try both if possible.
831     */
832
833#ifdef NEED_UTSNAME
834    struct utsname name;
835#endif
836    char buf[256];
837
838#ifdef NEED_UTSNAME
839    if (uname (&name) >= 0 && strcmp (host, name.nodename) == 0)
840	return (1);
841#endif
842
843    buf[0] = '\0';
844    (void) gethostname (buf, 256);
845    buf[255] = '\0';
846
847    if (strcmp (host, buf) == 0)
848	return (1);
849
850    return (0);
851}
852
853
854static XtransConnInfo
855TRANS(LocalOpenClient)(int type, const char *protocol,
856                       const char *host, const char *port)
857
858{
859    LOCALtrans2dev *transptr;
860    XtransConnInfo ciptr;
861    int index;
862
863    prmsg(3,"LocalOpenClient()\n");
864
865    /*
866     * Make sure 'host' is really local.  If not, we return failure.
867     * The reason we make this check is because a process may advertise
868     * a "local" address for which it can accept connections, but if a
869     * process on a remote machine tries to connect to this address,
870     * we know for sure it will fail.
871     */
872
873    if (strcmp (host, "unix") != 0 && !HostReallyLocal (host))
874    {
875	prmsg (1,
876	   "LocalOpenClient: Cannot connect to non-local host %s\n",
877	       host);
878	return NULL;
879    }
880
881
882#if defined(X11_t)
883    /*
884     * X has a well known port, that is transport dependent. It is easier
885     * to handle it here, than try and come up with a transport independent
886     * representation that can be passed in and resolved the usual way.
887     *
888     * The port that is passed here is really a string containing the idisplay
889     * from ConnectDisplay(). Since that is what we want for the local transports,
890     * we don't have to do anything special.
891     */
892#endif /* X11_t */
893
894    if( (ciptr = calloc(1,sizeof(struct _XtransConnInfo))) == NULL )
895    {
896	prmsg(1,"LocalOpenClient: calloc(1,%lu) failed\n",
897	      sizeof(struct _XtransConnInfo));
898	return NULL;
899    }
900
901    ciptr->fd = -1;
902
903    TRANS(LocalInitTransports)(protocol);
904
905    index = 0;
906    for(transptr=TRANS(LocalGetNextTransport)();
907	transptr!=NULL;transptr=TRANS(LocalGetNextTransport)(), index++)
908    {
909	switch( type )
910	{
911	case XTRANS_OPEN_COTS_CLIENT:
912	    ciptr->fd=transptr->devcotsopenclient(ciptr,port);
913	    break;
914	case XTRANS_OPEN_COTS_SERVER:
915	    prmsg(1,
916		  "LocalOpenClient: Should not be opening a server with this function\n");
917	    break;
918	default:
919	    prmsg(1,
920		  "LocalOpenClient: Unknown Open type %d\n",
921		  type);
922	}
923	if( ciptr->fd >= 0 )
924	    break;
925    }
926
927    TRANS(LocalEndTransports)();
928
929    if( ciptr->fd < 0 )
930    {
931	free(ciptr);
932	return NULL;
933    }
934
935    ciptr->priv=(char *)transptr;
936    ciptr->index = index;
937
938    return ciptr;
939}
940
941#endif /* TRANS_CLIENT */
942
943
944#ifdef TRANS_SERVER
945
946static XtransConnInfo
947TRANS(LocalOpenServer)(int type, const char *protocol,
948                       const char *host _X_UNUSED, const char *port)
949
950{
951    int	i;
952    XtransConnInfo ciptr;
953
954    prmsg(2,"LocalOpenServer(%d,%s,%s)\n", type, protocol, port);
955
956#if defined(X11_t)
957    /*
958     * For X11, the port will be in the format xserverN where N is the
959     * display number. All of the local connections just need to know
960     * the display number because they don't do any name resolution on
961     * the port. This just truncates port to the display portion.
962     */
963#endif /* X11_t */
964
965    if( (ciptr = calloc(1,sizeof(struct _XtransConnInfo))) == NULL )
966    {
967	prmsg(1,"LocalOpenServer: calloc(1,%lu) failed\n",
968	      sizeof(struct _XtransConnInfo));
969	return NULL;
970    }
971
972    for(i=1;i<NUMTRANSPORTS;i++)
973    {
974	if( strcmp(protocol,LOCALtrans2devtab[i].transname) != 0 )
975	    continue;
976	switch( type )
977	{
978	case XTRANS_OPEN_COTS_CLIENT:
979	    prmsg(1,
980		  "LocalOpenServer: Should not be opening a client with this function\n");
981	    break;
982	case XTRANS_OPEN_COTS_SERVER:
983	    ciptr->fd=LOCALtrans2devtab[i].devcotsopenserver(ciptr,port);
984	    break;
985	default:
986	    prmsg(1,"LocalOpenServer: Unknown Open type %d\n",
987		  type );
988	}
989	if( ciptr->fd >= 0 ) {
990	    ciptr->priv=(char *)&LOCALtrans2devtab[i];
991	    ciptr->index=i;
992	    ciptr->flags = 1 | (ciptr->flags & TRANS_KEEPFLAGS);
993	    return ciptr;
994	}
995    }
996
997    free(ciptr);
998    return NULL;
999}
1000
1001#endif /* TRANS_SERVER */
1002
1003
1004#ifdef TRANS_REOPEN
1005
1006static XtransConnInfo
1007TRANS(LocalReopenServer)(int type, int index, int fd, const char *port)
1008
1009{
1010    XtransConnInfo ciptr;
1011    int stat = 0;
1012
1013    prmsg(2,"LocalReopenServer(%d,%d,%d)\n", type, index, fd);
1014
1015    if( (ciptr = calloc(1,sizeof(struct _XtransConnInfo))) == NULL )
1016    {
1017	prmsg(1,"LocalReopenServer: calloc(1,%lu) failed\n",
1018	      sizeof(struct _XtransConnInfo));
1019	return NULL;
1020    }
1021
1022    ciptr->fd = fd;
1023
1024    switch( type )
1025    {
1026    case XTRANS_OPEN_COTS_SERVER:
1027	stat = LOCALtrans2devtab[index].devcotsreopenserver(ciptr,fd,port);
1028	break;
1029    default:
1030	prmsg(1,"LocalReopenServer: Unknown Open type %d\n",
1031	  type );
1032    }
1033
1034    if( stat > 0 ) {
1035	ciptr->priv=(char *)&LOCALtrans2devtab[index];
1036	ciptr->index=index;
1037	ciptr->flags = 1 | (ciptr->flags & TRANS_KEEPFLAGS);
1038	return ciptr;
1039    }
1040
1041    free(ciptr);
1042    return NULL;
1043}
1044
1045#endif /* TRANS_REOPEN */
1046
1047
1048
1049/*
1050 * This is the Local implementation of the X Transport service layer
1051 */
1052
1053#ifdef TRANS_CLIENT
1054
1055static XtransConnInfo
1056TRANS(LocalOpenCOTSClient)(Xtransport *thistrans _X_UNUSED, const char *protocol,
1057			   const char *host, const char *port)
1058
1059{
1060    prmsg(2,"LocalOpenCOTSClient(%s,%s,%s)\n",protocol,host,port);
1061
1062    return TRANS(LocalOpenClient)(XTRANS_OPEN_COTS_CLIENT, protocol, host, port);
1063}
1064
1065#endif /* TRANS_CLIENT */
1066
1067
1068#ifdef TRANS_SERVER
1069
1070static XtransConnInfo
1071TRANS(LocalOpenCOTSServer)(Xtransport *thistrans, const char *protocol,
1072			   const char *host, const char *port)
1073
1074{
1075    char *typetocheck = NULL;
1076    int found = 0;
1077
1078    prmsg(2,"LocalOpenCOTSServer(%s,%s,%s)\n",protocol,host,port);
1079
1080    /* Check if this local type is in the XLOCAL list */
1081    TRANS(LocalInitTransports)("local");
1082    typetocheck = workingXLOCAL;
1083    while (typetocheck && !found) {
1084#ifndef HAVE_STRCASECMP
1085	int j;
1086	char typebuf[TYPEBUFSIZE];
1087#endif
1088
1089	workingXLOCAL = strchr(workingXLOCAL, ':');
1090	if (workingXLOCAL && *workingXLOCAL)
1091	    *workingXLOCAL++ = '\0';
1092#ifndef HAVE_STRCASECMP
1093	strncpy(typebuf, typetocheck, TYPEBUFSIZE);
1094	for (j = 0; j < TYPEBUFSIZE; j++)
1095	    if (isupper(typebuf[j]))
1096		typebuf[j] = tolower(typebuf[j]);
1097	if (!strcmp(thistrans->TransName, typebuf))
1098#else
1099	if (!strcasecmp(thistrans->TransName, typetocheck))
1100#endif
1101	    found = 1;
1102	typetocheck = workingXLOCAL;
1103    }
1104    TRANS(LocalEndTransports)();
1105
1106    if (!found) {
1107	prmsg(3,"LocalOpenCOTSServer: disabling %s\n",thistrans->TransName);
1108	thistrans->flags |= TRANS_DISABLED;
1109	return NULL;
1110    }
1111
1112    return TRANS(LocalOpenServer)(XTRANS_OPEN_COTS_SERVER, protocol, host, port);
1113}
1114
1115#endif /* TRANS_SERVER */
1116
1117#ifdef TRANS_REOPEN
1118
1119static XtransConnInfo
1120TRANS(LocalReopenCOTSServer)(Xtransport *thistrans, int fd, const char *port)
1121
1122{
1123    int index;
1124
1125    prmsg(2,"LocalReopenCOTSServer(%d,%s)\n", fd, port);
1126
1127    for(index=1;index<NUMTRANSPORTS;index++)
1128    {
1129	if( strcmp(thistrans->TransName,
1130	    LOCALtrans2devtab[index].transname) == 0 )
1131	    break;
1132    }
1133
1134    if (index >= NUMTRANSPORTS)
1135    {
1136	return (NULL);
1137    }
1138
1139    return TRANS(LocalReopenServer)(XTRANS_OPEN_COTS_SERVER,
1140	index, fd, port);
1141}
1142
1143#endif /* TRANS_REOPEN */
1144
1145
1146
1147static int
1148TRANS(LocalSetOption)(XtransConnInfo ciptr, int option, int arg)
1149
1150{
1151    prmsg(2,"LocalSetOption(%d,%d,%d)\n",ciptr->fd,option,arg);
1152
1153    return -1;
1154}
1155
1156
1157#ifdef TRANS_SERVER
1158
1159static int
1160TRANS(LocalCreateListener)(XtransConnInfo ciptr, const char *port,
1161                           unsigned int flags _X_UNUSED)
1162
1163{
1164    prmsg(2,"LocalCreateListener(%p->%d,%s)\n",ciptr,ciptr->fd,port);
1165
1166    return 0;
1167}
1168
1169static int
1170TRANS(LocalResetListener)(XtransConnInfo ciptr)
1171
1172{
1173    LOCALtrans2dev	*transptr;
1174
1175    prmsg(2,"LocalResetListener(%p)\n",ciptr);
1176
1177    transptr=(LOCALtrans2dev *)ciptr->priv;
1178    if (transptr->devreset != NULL) {
1179	return transptr->devreset(ciptr);
1180    }
1181    return TRANS_RESET_NOOP;
1182}
1183
1184
1185static XtransConnInfo
1186TRANS(LocalAccept)(XtransConnInfo ciptr, int *status)
1187
1188{
1189    XtransConnInfo	newciptr;
1190    LOCALtrans2dev	*transptr;
1191
1192    prmsg(2,"LocalAccept(%p->%d)\n", ciptr, ciptr->fd);
1193
1194    transptr=(LOCALtrans2dev *)ciptr->priv;
1195
1196    if( (newciptr = calloc(1,sizeof(struct _XtransConnInfo)))==NULL )
1197    {
1198	prmsg(1,"LocalAccept: calloc(1,%lu) failed\n",
1199	      sizeof(struct _XtransConnInfo));
1200	*status = TRANS_ACCEPT_BAD_MALLOC;
1201	return NULL;
1202    }
1203
1204    newciptr->fd=transptr->devaccept(ciptr,newciptr,status);
1205
1206    if( newciptr->fd < 0 )
1207    {
1208	free(newciptr);
1209	return NULL;
1210    }
1211
1212    newciptr->priv=(char *)transptr;
1213    newciptr->index = ciptr->index;
1214
1215    *status = 0;
1216
1217    return newciptr;
1218}
1219
1220#endif /* TRANS_SERVER */
1221
1222
1223#ifdef TRANS_CLIENT
1224
1225static int
1226TRANS(LocalConnect)(XtransConnInfo ciptr,
1227                    const char *host _X_UNUSED, const char *port)
1228
1229{
1230    prmsg(2,"LocalConnect(%p->%d,%s)\n", ciptr, ciptr->fd, port);
1231
1232    return 0;
1233}
1234
1235#endif /* TRANS_CLIENT */
1236
1237
1238static int
1239TRANS(LocalBytesReadable)(XtransConnInfo ciptr, BytesReadable_t *pend )
1240
1241{
1242    prmsg(2,"LocalBytesReadable(%p->%d,%p)\n", ciptr, ciptr->fd, pend);
1243
1244    return ioctl(ciptr->fd, FIONREAD, (char *)pend);
1245}
1246
1247static int
1248TRANS(LocalRead)(XtransConnInfo ciptr, char *buf, int size)
1249
1250{
1251    prmsg(2,"LocalRead(%d,%p,%d)\n", ciptr->fd, buf, size );
1252
1253    return read(ciptr->fd,buf,size);
1254}
1255
1256static int
1257TRANS(LocalWrite)(XtransConnInfo ciptr, char *buf, int size)
1258
1259{
1260    prmsg(2,"LocalWrite(%d,%p,%d)\n", ciptr->fd, buf, size );
1261
1262    return write(ciptr->fd,buf,size);
1263}
1264
1265static int
1266TRANS(LocalReadv)(XtransConnInfo ciptr, struct iovec *buf, int size)
1267
1268{
1269    prmsg(2,"LocalReadv(%d,%p,%d)\n", ciptr->fd, buf, size );
1270
1271    return READV(ciptr,buf,size);
1272}
1273
1274static int
1275TRANS(LocalWritev)(XtransConnInfo ciptr, struct iovec *buf, int size)
1276
1277{
1278    prmsg(2,"LocalWritev(%d,%p,%d)\n", ciptr->fd, buf, size );
1279
1280    return WRITEV(ciptr,buf,size);
1281}
1282
1283static int
1284TRANS(LocalDisconnect)(XtransConnInfo ciptr)
1285
1286{
1287    prmsg(2,"LocalDisconnect(%p->%d)\n", ciptr, ciptr->fd);
1288
1289    return 0;
1290}
1291
1292static int
1293TRANS(LocalClose)(XtransConnInfo ciptr)
1294
1295{
1296    struct sockaddr_un      *sockname=(struct sockaddr_un *) ciptr->addr;
1297    int	ret;
1298
1299    prmsg(2,"LocalClose(%p->%d)\n", ciptr, ciptr->fd );
1300
1301    ret=close(ciptr->fd);
1302
1303    if(ciptr->flags
1304       && sockname
1305       && sockname->sun_family == AF_UNIX
1306       && sockname->sun_path[0] )
1307    {
1308	if (!(ciptr->flags & TRANS_NOUNLINK))
1309	    unlink(sockname->sun_path);
1310    }
1311
1312    return ret;
1313}
1314
1315static int
1316TRANS(LocalCloseForCloning)(XtransConnInfo ciptr)
1317
1318{
1319    int ret;
1320
1321    prmsg(2,"LocalCloseForCloning(%p->%d)\n", ciptr, ciptr->fd );
1322
1323    /* Don't unlink path */
1324
1325    ret=close(ciptr->fd);
1326
1327    return ret;
1328}
1329
1330
1331/*
1332 * MakeAllCOTSServerListeners() will go through the entire Xtransports[]
1333 * array defined in Xtrans.c and try to OpenCOTSServer() for each entry.
1334 * We will add duplicate entries to that table so that the OpenCOTSServer()
1335 * function will get called once for each type of local transport.
1336 *
1337 * The TransName is in lowercase, so it will never match during a normal
1338 * call to SelectTransport() in Xtrans.c.
1339 */
1340
1341#ifdef TRANS_SERVER
1342static const char * local_aliases[] = {
1343				  "named",
1344				  "pipe", /* compatibility with Solaris Xlib */
1345				  NULL };
1346#endif
1347
1348Xtransport	TRANS(LocalFuncs) = {
1349	/* Local Interface */
1350	"local",
1351	TRANS_ALIAS | TRANS_LOCAL,
1352#ifdef TRANS_CLIENT
1353	TRANS(LocalOpenCOTSClient),
1354#endif /* TRANS_CLIENT */
1355#ifdef TRANS_SERVER
1356	local_aliases,
1357	TRANS(LocalOpenCOTSServer),
1358#endif /* TRANS_SERVER */
1359#ifdef TRANS_REOPEN
1360	TRANS(LocalReopenCOTSServer),
1361#endif
1362	TRANS(LocalSetOption),
1363#ifdef TRANS_SERVER
1364	TRANS(LocalCreateListener),
1365	TRANS(LocalResetListener),
1366	TRANS(LocalAccept),
1367#endif /* TRANS_SERVER */
1368#ifdef TRANS_CLIENT
1369	TRANS(LocalConnect),
1370#endif /* TRANS_CLIENT */
1371	TRANS(LocalBytesReadable),
1372	TRANS(LocalRead),
1373	TRANS(LocalWrite),
1374	TRANS(LocalReadv),
1375	TRANS(LocalWritev),
1376#if XTRANS_SEND_FDS
1377	TRANS(LocalSendFdInvalid),
1378	TRANS(LocalRecvFdInvalid),
1379#endif
1380	TRANS(LocalDisconnect),
1381	TRANS(LocalClose),
1382	TRANS(LocalCloseForCloning),
1383};
1384
1385
1386#ifdef LOCAL_TRANS_NAMED
1387
1388Xtransport	TRANS(NAMEDFuncs) = {
1389	/* Local Interface */
1390	"named",
1391	TRANS_LOCAL,
1392#ifdef TRANS_CLIENT
1393	TRANS(LocalOpenCOTSClient),
1394#endif /* TRANS_CLIENT */
1395#ifdef TRANS_SERVER
1396	NULL,
1397	TRANS(LocalOpenCOTSServer),
1398#endif /* TRANS_SERVER */
1399#ifdef TRANS_REOPEN
1400	TRANS(LocalReopenCOTSServer),
1401#endif
1402	TRANS(LocalSetOption),
1403#ifdef TRANS_SERVER
1404	TRANS(LocalCreateListener),
1405	TRANS(LocalResetListener),
1406	TRANS(LocalAccept),
1407#endif /* TRANS_SERVER */
1408#ifdef TRANS_CLIENT
1409	TRANS(LocalConnect),
1410#endif /* TRANS_CLIENT */
1411	TRANS(LocalBytesReadable),
1412	TRANS(LocalRead),
1413	TRANS(LocalWrite),
1414	TRANS(LocalReadv),
1415	TRANS(LocalWritev),
1416#if XTRANS_SEND_FDS
1417	TRANS(LocalSendFdInvalid),
1418	TRANS(LocalRecvFdInvalid),
1419#endif
1420	TRANS(LocalDisconnect),
1421	TRANS(LocalClose),
1422	TRANS(LocalCloseForCloning),
1423};
1424
1425Xtransport	TRANS(PIPEFuncs) = {
1426	/* Local Interface */
1427	"pipe",
1428	TRANS_ALIAS | TRANS_LOCAL,
1429#ifdef TRANS_CLIENT
1430	TRANS(LocalOpenCOTSClient),
1431#endif /* TRANS_CLIENT */
1432#ifdef TRANS_SERVER
1433	NULL,
1434	TRANS(LocalOpenCOTSServer),
1435#endif /* TRANS_SERVER */
1436#ifdef TRANS_REOPEN
1437	TRANS(LocalReopenCOTSServer),
1438#endif
1439	TRANS(LocalSetOption),
1440#ifdef TRANS_SERVER
1441	TRANS(LocalCreateListener),
1442	TRANS(LocalResetListener),
1443	TRANS(LocalAccept),
1444#endif /* TRANS_SERVER */
1445#ifdef TRANS_CLIENT
1446	TRANS(LocalConnect),
1447#endif /* TRANS_CLIENT */
1448	TRANS(LocalBytesReadable),
1449	TRANS(LocalRead),
1450	TRANS(LocalWrite),
1451	TRANS(LocalReadv),
1452	TRANS(LocalWritev),
1453#if XTRANS_SEND_FDS
1454	TRANS(LocalSendFdInvalid),
1455	TRANS(LocalRecvFdInvalid),
1456#endif
1457	TRANS(LocalDisconnect),
1458	TRANS(LocalClose),
1459	TRANS(LocalCloseForCloning),
1460};
1461#endif /* LOCAL_TRANS_NAMED */
1462
1463
1464