xref: /plan9/sys/src/cmd/srvold9p/fcall.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 #include "9p1.h"
6 
7 #define	MAXFDATA	(8*1024)
8 #define	MAXRPC		(MAXFDATA+160)
9 
10 /*
11  * reassemble 9P messages for stream based protocols
12  * interposed between devmnt and the network by srv for tcp connections
13  * fcall expects devmnt on fd0, network fd1
14  */
15 uchar msglen[256] =
16 {
17 	[Tnop9p1]		3,
18 	[Rnop9p1]		3,
19 	[Tsession9p1]	3+CHALLEN,
20 	[Rsession9p1]	3+NAMEREC+DOMLEN+CHALLEN,
21 	[Terror9p1]	0,
22 	[Rerror9p1]	67,
23 	[Tflush9p1]	5,
24 	[Rflush9p1]	3,
25 	[Tattach9p1]	5+2*NAMEREC+TICKETLEN+AUTHENTLEN,
26 	[Rattach9p1]	13+AUTHENTLEN,
27 	[Tclone9p1]	7,
28 	[Rclone9p1]	5,
29 	[Twalk9p1]		33,
30 	[Rwalk9p1]		13,
31 	[Topen9p1]		6,
32 	[Ropen9p1]		13,
33 	[Tcreate9p1]	38,
34 	[Rcreate9p1]	13,
35 	[Tread9p1]		15,
36 	[Rread9p1]		8,
37 	[Twrite9p1]	16,
38 	[Rwrite9p1]	7,
39 	[Tclunk9p1]	5,
40 	[Rclunk9p1]	5,
41 	[Tremove9p1]	5,
42 	[Rremove9p1]	5,
43 	[Tstat9p1]		5,
44 	[Rstat9p1]		121,
45 	[Twstat9p1]	121,
46 	[Rwstat9p1]	5,
47 	[Tclwalk9p1]	35,
48 	[Rclwalk9p1]	13,
49 };
50 
51 enum
52 {
53 	Twritehdr	= 16,	/* Min bytes for Twrite */
54 	Rreadhdr	= 8,	/* Min bytes for Rread */
55 	Twritecnt	= 13,	/* Offset in byte stream of write count */
56 	Rreadcnt	= 5,	/* Offset for Readcnt */
57 };
58 
59 int
mntrpclen(uchar * d,int n)60 mntrpclen(uchar *d, int n)
61 {
62 	uchar t;
63 	int len, off;
64 
65 	if(n < 1)
66 		return 0;
67 
68 	t = d[0];
69 	switch(t) {			/* This is the type */
70 	default:
71 		len = msglen[t];
72 		if(len == 0)		/* Illegal type so consume */
73 			return n;
74 		if(n < len)
75 			return 0;
76 		return len;
77 	case Twrite9p1:			/* Fmt: TGGFFOOOOOOOOCC */
78 		len = Twritehdr;	/* T = type, G = tag, F = fid */
79 		off = Twritecnt;	/* O = offset, C = count */
80 		break;
81 	case Rread9p1:			/* Fmt: TGGFFCC */
82 		len = Rreadhdr;
83 		off = Rreadcnt;
84 		break;
85 	}
86 	if(n < off+2)
87 		return 0;
88 
89 	len += d[off]|(d[off+1]<<8);
90 	if(n < len)
91 		return 0;
92 
93 	return len;
94 }
95 
96 int
fcall(int fd)97 fcall(int fd)
98 {
99 	int i, r, n, l;
100 	uchar *p, *buf;
101 	int pipefd[2];
102 
103 	if(pipe(pipefd) < 0)
104 		fatal("fcall pipe: %r");
105 
106 	buf = malloc(MAXRPC);
107 	if(buf == nil)
108 		fatal("fcall malloc");
109 
110 	switch(rfork(RFPROC|RFMEM|RFFDG|RFCNAMEG)){
111 	default:
112 		return pipefd[0];	/* parent returns fd */
113 	case 0:
114 		break;	/* child builds buffers */
115 	case -1:
116 		fatal("fcall fork: %r");
117 	}
118 
119 	/* close file descriptors */
120 	for(i=0; i<20; i++)
121 		if(i!=fd && i!=pipefd[1])
122 			close(i);
123 
124 	l = MAXRPC;
125 	p = buf;
126 	for(;;) {
127 		n = read(fd, p, l);
128 		if(n < 0)
129 			break;
130 		p += n;
131 		l -= n;
132 
133 		for(;;) {
134 			r = mntrpclen(buf, p - buf);
135 			if(r == 0)
136 				break;
137 
138 			if(write(pipefd[1], buf, r) < 0)
139 				break;
140 
141 			n = (p - buf) - r;
142 			memmove(buf, buf+r, n);
143 			p = buf+n;
144 			l = MAXRPC - n;
145 		}
146 	}
147 	close(pipefd[1]);
148 	fatal(nil);
149 	return -1;
150 }
151