Xtranslcl.c revision 47a4502c
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 = 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    char	*typetocheck;
775    prmsg(3,"LocalGetNextTransport()\n");
776
777    while(1)
778    {
779	if( workingXLOCAL == NULL || *workingXLOCAL == '\0' )
780	    return NULL;
781
782	typetocheck=workingXLOCAL;
783	workingXLOCAL=strchr(workingXLOCAL,':');
784	if(workingXLOCAL && *workingXLOCAL)
785	    *workingXLOCAL++='\0';
786
787	for (unsigned int i = 0; i < NUMTRANSPORTS; i++)
788	{
789#ifndef HAVE_STRCASECMP
790	    int		j;
791	    char	typebuf[TYPEBUFSIZE];
792	    /*
793	     * This is equivalent to a case insensitive strcmp(),
794	     * but should be more portable.
795	     */
796	    strncpy(typebuf,typetocheck,TYPEBUFSIZE);
797	    for(j=0;j<TYPEBUFSIZE;j++)
798		if (isupper(typebuf[j]))
799		    typebuf[j]=tolower(typebuf[j]);
800
801	    /* Now, see if they match */
802	    if(!strcmp(LOCALtrans2devtab[i].transname,typebuf))
803#else
804	    if(!strcasecmp(LOCALtrans2devtab[i].transname,typetocheck))
805#endif
806		return &LOCALtrans2devtab[i];
807	}
808    }
809#if 0
810    /*NOTREACHED*/
811    return NULL;
812#endif
813}
814
815#ifdef NEED_UTSNAME
816#include <sys/utsname.h>
817#endif
818
819/*
820 * Make sure 'host' is really local.
821 */
822
823static int
824HostReallyLocal (const char *host)
825
826{
827    /*
828     * The 'host' passed to this function may have been generated
829     * by either uname() or gethostname().  We try both if possible.
830     */
831
832#ifdef NEED_UTSNAME
833    struct utsname name;
834#endif
835    char buf[256];
836
837#ifdef NEED_UTSNAME
838    if (uname (&name) >= 0 && strcmp (host, name.nodename) == 0)
839	return (1);
840#endif
841
842    buf[0] = '\0';
843    (void) gethostname (buf, 256);
844    buf[255] = '\0';
845
846    if (strcmp (host, buf) == 0)
847	return (1);
848
849    return (0);
850}
851
852
853static XtransConnInfo
854TRANS(LocalOpenClient)(int type, const char *protocol,
855                       const char *host, const char *port)
856
857{
858    LOCALtrans2dev *transptr;
859    XtransConnInfo ciptr;
860    int index;
861
862    prmsg(3,"LocalOpenClient()\n");
863
864    /*
865     * Make sure 'host' is really local.  If not, we return failure.
866     * The reason we make this check is because a process may advertise
867     * a "local" address for which it can accept connections, but if a
868     * process on a remote machine tries to connect to this address,
869     * we know for sure it will fail.
870     */
871
872    if (strcmp (host, "unix") != 0 && !HostReallyLocal (host))
873    {
874	prmsg (1,
875	   "LocalOpenClient: Cannot connect to non-local host %s\n",
876	       host);
877	return NULL;
878    }
879
880
881#if defined(X11_t)
882    /*
883     * X has a well known port, that is transport dependent. It is easier
884     * to handle it here, than try and come up with a transport independent
885     * representation that can be passed in and resolved the usual way.
886     *
887     * The port that is passed here is really a string containing the idisplay
888     * from ConnectDisplay(). Since that is what we want for the local transports,
889     * we don't have to do anything special.
890     */
891#endif /* X11_t */
892
893    if( (ciptr = calloc(1,sizeof(struct _XtransConnInfo))) == NULL )
894    {
895	prmsg(1,"LocalOpenClient: calloc(1,%lu) failed\n",
896	      sizeof(struct _XtransConnInfo));
897	return NULL;
898    }
899
900    ciptr->fd = -1;
901
902    TRANS(LocalInitTransports)(protocol);
903
904    index = 0;
905    for(transptr=TRANS(LocalGetNextTransport)();
906	transptr!=NULL;transptr=TRANS(LocalGetNextTransport)(), index++)
907    {
908	switch( type )
909	{
910	case XTRANS_OPEN_COTS_CLIENT:
911	    ciptr->fd=transptr->devcotsopenclient(ciptr,port);
912	    break;
913	case XTRANS_OPEN_COTS_SERVER:
914	    prmsg(1,
915		  "LocalOpenClient: Should not be opening a server with this function\n");
916	    break;
917	default:
918	    prmsg(1,
919		  "LocalOpenClient: Unknown Open type %d\n",
920		  type);
921	}
922	if( ciptr->fd >= 0 )
923	    break;
924    }
925
926    TRANS(LocalEndTransports)();
927
928    if( ciptr->fd < 0 )
929    {
930	free(ciptr);
931	return NULL;
932    }
933
934    ciptr->priv=(char *)transptr;
935    ciptr->index = index;
936
937    return ciptr;
938}
939
940#endif /* TRANS_CLIENT */
941
942
943#ifdef TRANS_SERVER
944
945static XtransConnInfo
946TRANS(LocalOpenServer)(int type, const char *protocol,
947                       const char *host _X_UNUSED, const char *port)
948
949{
950    XtransConnInfo ciptr;
951
952    prmsg(2,"LocalOpenServer(%d,%s,%s)\n", type, protocol, port);
953
954#if defined(X11_t)
955    /*
956     * For X11, the port will be in the format xserverN where N is the
957     * display number. All of the local connections just need to know
958     * the display number because they don't do any name resolution on
959     * the port. This just truncates port to the display portion.
960     */
961#endif /* X11_t */
962
963    if( (ciptr = calloc(1,sizeof(struct _XtransConnInfo))) == NULL )
964    {
965	prmsg(1,"LocalOpenServer: calloc(1,%lu) failed\n",
966	      sizeof(struct _XtransConnInfo));
967	return NULL;
968    }
969
970    for (unsigned int i = 1; i < NUMTRANSPORTS; i++)
971    {
972	if( strcmp(protocol,LOCALtrans2devtab[i].transname) != 0 )
973	    continue;
974	switch( type )
975	{
976	case XTRANS_OPEN_COTS_CLIENT:
977	    prmsg(1,
978		  "LocalOpenServer: Should not be opening a client with this function\n");
979	    break;
980	case XTRANS_OPEN_COTS_SERVER:
981	    ciptr->fd=LOCALtrans2devtab[i].devcotsopenserver(ciptr,port);
982	    break;
983	default:
984	    prmsg(1,"LocalOpenServer: Unknown Open type %d\n",
985		  type );
986	}
987	if( ciptr->fd >= 0 ) {
988	    ciptr->priv=(char *)&LOCALtrans2devtab[i];
989	    ciptr->index=i;
990	    ciptr->flags = 1 | (ciptr->flags & TRANS_KEEPFLAGS);
991	    return ciptr;
992	}
993    }
994
995    free(ciptr);
996    return NULL;
997}
998
999#endif /* TRANS_SERVER */
1000
1001
1002#ifdef TRANS_REOPEN
1003
1004static XtransConnInfo
1005TRANS(LocalReopenServer)(int type, int index, int fd, const char *port)
1006
1007{
1008    XtransConnInfo ciptr;
1009    int stat = 0;
1010
1011    prmsg(2,"LocalReopenServer(%d,%d,%d)\n", type, index, fd);
1012
1013    if( (ciptr = calloc(1,sizeof(struct _XtransConnInfo))) == NULL )
1014    {
1015	prmsg(1,"LocalReopenServer: calloc(1,%lu) failed\n",
1016	      sizeof(struct _XtransConnInfo));
1017	return NULL;
1018    }
1019
1020    ciptr->fd = fd;
1021
1022    switch( type )
1023    {
1024    case XTRANS_OPEN_COTS_SERVER:
1025	stat = LOCALtrans2devtab[index].devcotsreopenserver(ciptr,fd,port);
1026	break;
1027    default:
1028	prmsg(1,"LocalReopenServer: Unknown Open type %d\n",
1029	  type );
1030    }
1031
1032    if( stat > 0 ) {
1033	ciptr->priv=(char *)&LOCALtrans2devtab[index];
1034	ciptr->index=index;
1035	ciptr->flags = 1 | (ciptr->flags & TRANS_KEEPFLAGS);
1036	return ciptr;
1037    }
1038
1039    free(ciptr);
1040    return NULL;
1041}
1042
1043#endif /* TRANS_REOPEN */
1044
1045
1046
1047/*
1048 * This is the Local implementation of the X Transport service layer
1049 */
1050
1051#ifdef TRANS_CLIENT
1052
1053static XtransConnInfo
1054TRANS(LocalOpenCOTSClient)(Xtransport *thistrans _X_UNUSED, const char *protocol,
1055			   const char *host, const char *port)
1056
1057{
1058    prmsg(2,"LocalOpenCOTSClient(%s,%s,%s)\n",protocol,host,port);
1059
1060    return TRANS(LocalOpenClient)(XTRANS_OPEN_COTS_CLIENT, protocol, host, port);
1061}
1062
1063#endif /* TRANS_CLIENT */
1064
1065
1066#ifdef TRANS_SERVER
1067
1068static XtransConnInfo
1069TRANS(LocalOpenCOTSServer)(Xtransport *thistrans, const char *protocol,
1070			   const char *host, const char *port)
1071
1072{
1073    char *typetocheck = NULL;
1074    int found = 0;
1075
1076    prmsg(2,"LocalOpenCOTSServer(%s,%s,%s)\n",protocol,host,port);
1077
1078    /* Check if this local type is in the XLOCAL list */
1079    TRANS(LocalInitTransports)("local");
1080    typetocheck = workingXLOCAL;
1081    while (typetocheck && !found) {
1082#ifndef HAVE_STRCASECMP
1083	int j;
1084	char typebuf[TYPEBUFSIZE];
1085#endif
1086
1087	workingXLOCAL = strchr(workingXLOCAL, ':');
1088	if (workingXLOCAL && *workingXLOCAL)
1089	    *workingXLOCAL++ = '\0';
1090#ifndef HAVE_STRCASECMP
1091	strncpy(typebuf, typetocheck, TYPEBUFSIZE);
1092	for (j = 0; j < TYPEBUFSIZE; j++)
1093	    if (isupper(typebuf[j]))
1094		typebuf[j] = tolower(typebuf[j]);
1095	if (!strcmp(thistrans->TransName, typebuf))
1096#else
1097	if (!strcasecmp(thistrans->TransName, typetocheck))
1098#endif
1099	    found = 1;
1100	typetocheck = workingXLOCAL;
1101    }
1102    TRANS(LocalEndTransports)();
1103
1104    if (!found) {
1105	prmsg(3,"LocalOpenCOTSServer: disabling %s\n",thistrans->TransName);
1106	thistrans->flags |= TRANS_DISABLED;
1107	return NULL;
1108    }
1109
1110    return TRANS(LocalOpenServer)(XTRANS_OPEN_COTS_SERVER, protocol, host, port);
1111}
1112
1113#endif /* TRANS_SERVER */
1114
1115#ifdef TRANS_REOPEN
1116
1117static XtransConnInfo
1118TRANS(LocalReopenCOTSServer)(Xtransport *thistrans, int fd, const char *port)
1119
1120{
1121    unsigned int index;
1122
1123    prmsg(2,"LocalReopenCOTSServer(%d,%s)\n", fd, port);
1124
1125    for(index=1;index<NUMTRANSPORTS;index++)
1126    {
1127	if( strcmp(thistrans->TransName,
1128	    LOCALtrans2devtab[index].transname) == 0 )
1129	    break;
1130    }
1131
1132    if (index >= NUMTRANSPORTS)
1133    {
1134	return (NULL);
1135    }
1136
1137    return TRANS(LocalReopenServer)(XTRANS_OPEN_COTS_SERVER,
1138	index, fd, port);
1139}
1140
1141#endif /* TRANS_REOPEN */
1142
1143
1144
1145static int
1146TRANS(LocalSetOption)(XtransConnInfo ciptr, int option, int arg)
1147
1148{
1149    prmsg(2,"LocalSetOption(%d,%d,%d)\n",ciptr->fd,option,arg);
1150
1151    return -1;
1152}
1153
1154
1155#ifdef TRANS_SERVER
1156
1157static int
1158TRANS(LocalCreateListener)(XtransConnInfo ciptr, const char *port,
1159                           unsigned int flags _X_UNUSED)
1160
1161{
1162    prmsg(2,"LocalCreateListener(%p->%d,%s)\n",ciptr,ciptr->fd,port);
1163
1164    return 0;
1165}
1166
1167static int
1168TRANS(LocalResetListener)(XtransConnInfo ciptr)
1169
1170{
1171    LOCALtrans2dev	*transptr;
1172
1173    prmsg(2,"LocalResetListener(%p)\n",ciptr);
1174
1175    transptr=(LOCALtrans2dev *)ciptr->priv;
1176    if (transptr->devreset != NULL) {
1177	return transptr->devreset(ciptr);
1178    }
1179    return TRANS_RESET_NOOP;
1180}
1181
1182
1183static XtransConnInfo
1184TRANS(LocalAccept)(XtransConnInfo ciptr, int *status)
1185
1186{
1187    XtransConnInfo	newciptr;
1188    LOCALtrans2dev	*transptr;
1189
1190    prmsg(2,"LocalAccept(%p->%d)\n", ciptr, ciptr->fd);
1191
1192    transptr=(LOCALtrans2dev *)ciptr->priv;
1193
1194    if( (newciptr = calloc(1,sizeof(struct _XtransConnInfo)))==NULL )
1195    {
1196	prmsg(1,"LocalAccept: calloc(1,%lu) failed\n",
1197	      sizeof(struct _XtransConnInfo));
1198	*status = TRANS_ACCEPT_BAD_MALLOC;
1199	return NULL;
1200    }
1201
1202    newciptr->fd=transptr->devaccept(ciptr,newciptr,status);
1203
1204    if( newciptr->fd < 0 )
1205    {
1206	free(newciptr);
1207	return NULL;
1208    }
1209
1210    newciptr->priv=(char *)transptr;
1211    newciptr->index = ciptr->index;
1212
1213    *status = 0;
1214
1215    return newciptr;
1216}
1217
1218#endif /* TRANS_SERVER */
1219
1220
1221#ifdef TRANS_CLIENT
1222
1223static int
1224TRANS(LocalConnect)(XtransConnInfo ciptr,
1225                    const char *host _X_UNUSED, const char *port)
1226
1227{
1228    prmsg(2,"LocalConnect(%p->%d,%s)\n", ciptr, ciptr->fd, port);
1229
1230    return 0;
1231}
1232
1233#endif /* TRANS_CLIENT */
1234
1235
1236static int
1237TRANS(LocalBytesReadable)(XtransConnInfo ciptr, BytesReadable_t *pend )
1238
1239{
1240    prmsg(2,"LocalBytesReadable(%p->%d,%p)\n", ciptr, ciptr->fd, pend);
1241
1242    return ioctl(ciptr->fd, FIONREAD, (char *)pend);
1243}
1244
1245static int
1246TRANS(LocalRead)(XtransConnInfo ciptr, char *buf, int size)
1247
1248{
1249    prmsg(2,"LocalRead(%d,%p,%d)\n", ciptr->fd, buf, size );
1250
1251    return read(ciptr->fd,buf,size);
1252}
1253
1254static int
1255TRANS(LocalWrite)(XtransConnInfo ciptr, char *buf, int size)
1256
1257{
1258    prmsg(2,"LocalWrite(%d,%p,%d)\n", ciptr->fd, buf, size );
1259
1260    return write(ciptr->fd,buf,size);
1261}
1262
1263static int
1264TRANS(LocalReadv)(XtransConnInfo ciptr, struct iovec *buf, int size)
1265
1266{
1267    prmsg(2,"LocalReadv(%d,%p,%d)\n", ciptr->fd, buf, size );
1268
1269    return READV(ciptr,buf,size);
1270}
1271
1272static int
1273TRANS(LocalWritev)(XtransConnInfo ciptr, struct iovec *buf, int size)
1274
1275{
1276    prmsg(2,"LocalWritev(%d,%p,%d)\n", ciptr->fd, buf, size );
1277
1278    return WRITEV(ciptr,buf,size);
1279}
1280
1281static int
1282TRANS(LocalDisconnect)(XtransConnInfo ciptr)
1283
1284{
1285    prmsg(2,"LocalDisconnect(%p->%d)\n", ciptr, ciptr->fd);
1286
1287    return 0;
1288}
1289
1290static int
1291TRANS(LocalClose)(XtransConnInfo ciptr)
1292
1293{
1294    struct sockaddr_un      *sockname=(struct sockaddr_un *) ciptr->addr;
1295    int	ret;
1296
1297    prmsg(2,"LocalClose(%p->%d)\n", ciptr, ciptr->fd );
1298
1299    ret=close(ciptr->fd);
1300
1301    if(ciptr->flags
1302       && sockname
1303       && sockname->sun_family == AF_UNIX
1304       && sockname->sun_path[0] )
1305    {
1306	if (!(ciptr->flags & TRANS_NOUNLINK))
1307	    unlink(sockname->sun_path);
1308    }
1309
1310    return ret;
1311}
1312
1313static int
1314TRANS(LocalCloseForCloning)(XtransConnInfo ciptr)
1315
1316{
1317    int ret;
1318
1319    prmsg(2,"LocalCloseForCloning(%p->%d)\n", ciptr, ciptr->fd );
1320
1321    /* Don't unlink path */
1322
1323    ret=close(ciptr->fd);
1324
1325    return ret;
1326}
1327
1328
1329/*
1330 * MakeAllCOTSServerListeners() will go through the entire Xtransports[]
1331 * array defined in Xtrans.c and try to OpenCOTSServer() for each entry.
1332 * We will add duplicate entries to that table so that the OpenCOTSServer()
1333 * function will get called once for each type of local transport.
1334 *
1335 * The TransName is in lowercase, so it will never match during a normal
1336 * call to SelectTransport() in Xtrans.c.
1337 */
1338
1339#ifdef TRANS_SERVER
1340static const char * local_aliases[] = {
1341				  "named",
1342				  "pipe", /* compatibility with Solaris Xlib */
1343				  NULL };
1344#endif
1345
1346Xtransport	TRANS(LocalFuncs) = {
1347	/* Local Interface */
1348	"local",
1349	TRANS_ALIAS | TRANS_LOCAL,
1350#ifdef TRANS_CLIENT
1351	TRANS(LocalOpenCOTSClient),
1352#endif /* TRANS_CLIENT */
1353#ifdef TRANS_SERVER
1354	local_aliases,
1355	TRANS(LocalOpenCOTSServer),
1356#endif /* TRANS_SERVER */
1357#ifdef TRANS_REOPEN
1358	TRANS(LocalReopenCOTSServer),
1359#endif
1360	TRANS(LocalSetOption),
1361#ifdef TRANS_SERVER
1362	TRANS(LocalCreateListener),
1363	TRANS(LocalResetListener),
1364	TRANS(LocalAccept),
1365#endif /* TRANS_SERVER */
1366#ifdef TRANS_CLIENT
1367	TRANS(LocalConnect),
1368#endif /* TRANS_CLIENT */
1369	TRANS(LocalBytesReadable),
1370	TRANS(LocalRead),
1371	TRANS(LocalWrite),
1372	TRANS(LocalReadv),
1373	TRANS(LocalWritev),
1374#if XTRANS_SEND_FDS
1375	TRANS(LocalSendFdInvalid),
1376	TRANS(LocalRecvFdInvalid),
1377#endif
1378	TRANS(LocalDisconnect),
1379	TRANS(LocalClose),
1380	TRANS(LocalCloseForCloning),
1381};
1382
1383
1384#ifdef LOCAL_TRANS_NAMED
1385
1386Xtransport	TRANS(NAMEDFuncs) = {
1387	/* Local Interface */
1388	"named",
1389	TRANS_LOCAL,
1390#ifdef TRANS_CLIENT
1391	TRANS(LocalOpenCOTSClient),
1392#endif /* TRANS_CLIENT */
1393#ifdef TRANS_SERVER
1394	NULL,
1395	TRANS(LocalOpenCOTSServer),
1396#endif /* TRANS_SERVER */
1397#ifdef TRANS_REOPEN
1398	TRANS(LocalReopenCOTSServer),
1399#endif
1400	TRANS(LocalSetOption),
1401#ifdef TRANS_SERVER
1402	TRANS(LocalCreateListener),
1403	TRANS(LocalResetListener),
1404	TRANS(LocalAccept),
1405#endif /* TRANS_SERVER */
1406#ifdef TRANS_CLIENT
1407	TRANS(LocalConnect),
1408#endif /* TRANS_CLIENT */
1409	TRANS(LocalBytesReadable),
1410	TRANS(LocalRead),
1411	TRANS(LocalWrite),
1412	TRANS(LocalReadv),
1413	TRANS(LocalWritev),
1414#if XTRANS_SEND_FDS
1415	TRANS(LocalSendFdInvalid),
1416	TRANS(LocalRecvFdInvalid),
1417#endif
1418	TRANS(LocalDisconnect),
1419	TRANS(LocalClose),
1420	TRANS(LocalCloseForCloning),
1421};
1422
1423Xtransport	TRANS(PIPEFuncs) = {
1424	/* Local Interface */
1425	"pipe",
1426	TRANS_ALIAS | TRANS_LOCAL,
1427#ifdef TRANS_CLIENT
1428	TRANS(LocalOpenCOTSClient),
1429#endif /* TRANS_CLIENT */
1430#ifdef TRANS_SERVER
1431	NULL,
1432	TRANS(LocalOpenCOTSServer),
1433#endif /* TRANS_SERVER */
1434#ifdef TRANS_REOPEN
1435	TRANS(LocalReopenCOTSServer),
1436#endif
1437	TRANS(LocalSetOption),
1438#ifdef TRANS_SERVER
1439	TRANS(LocalCreateListener),
1440	TRANS(LocalResetListener),
1441	TRANS(LocalAccept),
1442#endif /* TRANS_SERVER */
1443#ifdef TRANS_CLIENT
1444	TRANS(LocalConnect),
1445#endif /* TRANS_CLIENT */
1446	TRANS(LocalBytesReadable),
1447	TRANS(LocalRead),
1448	TRANS(LocalWrite),
1449	TRANS(LocalReadv),
1450	TRANS(LocalWritev),
1451#if XTRANS_SEND_FDS
1452	TRANS(LocalSendFdInvalid),
1453	TRANS(LocalRecvFdInvalid),
1454#endif
1455	TRANS(LocalDisconnect),
1456	TRANS(LocalClose),
1457	TRANS(LocalCloseForCloning),
1458};
1459#endif /* LOCAL_TRANS_NAMED */
1460
1461
1462