xref: /plan9/sys/src/libsunrpc/server.c (revision fb7f0c934c48abaed6040d054ef636408c3c522d)
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <sunrpc.h>
5 
6 /*
7  * Sun RPC server; for now, no reply cache
8  */
9 
10 static void sunRpcProc(void*);
11 static void sunRpcRequestThread(void*);
12 static void sunRpcReplyThread(void*);
13 static void sunRpcForkThread(void*);
14 static SunProg *sunFindProg(SunSrv*, SunMsg*, SunRpc*, Channel**);
15 
16 typedef struct Targ Targ;
17 struct Targ
18 {
19 	void (*fn)(void*);
20 	void *arg;
21 };
22 
23 SunSrv*
sunSrv(void)24 sunSrv(void)
25 {
26 	SunSrv *srv;
27 
28 	srv = emalloc(sizeof(SunSrv));
29 	srv->chatty = 0;
30 	srv->crequest = chancreate(sizeof(SunMsg*), 16);
31 	srv->creply = chancreate(sizeof(SunMsg*), 16);
32 	srv->cthread = chancreate(sizeof(Targ), 4);
33 
34 	proccreate(sunRpcProc, srv, SunStackSize);
35 	return srv;
36 }
37 
38 void
sunSrvProg(SunSrv * srv,SunProg * prog,Channel * c)39 sunSrvProg(SunSrv *srv, SunProg *prog, Channel *c)
40 {
41 	if(srv->nprog%16 == 0){
42 		srv->prog = erealloc(srv->prog, (srv->nprog+16)*sizeof(srv->prog[0]));
43 		srv->cdispatch = erealloc(srv->cdispatch, (srv->nprog+16)*sizeof(srv->cdispatch[0]));
44 	}
45 	srv->prog[srv->nprog] = prog;
46 	srv->cdispatch[srv->nprog] = c;
47 	srv->nprog++;
48 }
49 
50 static void
sunRpcProc(void * v)51 sunRpcProc(void *v)
52 {
53 	threadcreate(sunRpcReplyThread, v, SunStackSize);
54 	threadcreate(sunRpcRequestThread, v, SunStackSize);
55 	threadcreate(sunRpcForkThread, v, SunStackSize);
56 
57 }
58 
59 static void
sunRpcForkThread(void * v)60 sunRpcForkThread(void *v)
61 {
62 	SunSrv *srv = v;
63 	Targ t;
64 
65 	while(recv(srv->cthread, &t) == 1)
66 		threadcreate(t.fn, t.arg, SunStackSize);
67 }
68 
69 void
sunSrvThreadCreate(SunSrv * srv,void (* fn)(void *),void * arg)70 sunSrvThreadCreate(SunSrv *srv, void (*fn)(void*), void *arg)
71 {
72 	Targ t;
73 
74 	t.fn = fn;
75 	t.arg = arg;
76 	send(srv->cthread, &t);
77 }
78 
79 static void
sunRpcRequestThread(void * v)80 sunRpcRequestThread(void *v)
81 {
82 	uchar *p, *ep;
83 	Channel *c;
84 	SunSrv *srv = v;
85 	SunMsg *m;
86 	SunProg *pg;
87 	SunStatus ok;
88 
89 	while((m = recvp(srv->crequest)) != nil){
90 		/* could look up in cache here? */
91 
92 if(srv->chatty) fprint(2, "sun msg %p count %d\n", m, m->count);
93 		m->srv = srv;
94 		p = m->data;
95 		ep = p+m->count;
96 		if(sunRpcUnpack(p, ep, &p, &m->rpc) != SunSuccess){
97 			fprint(2, "in: %.*H unpack failed\n", m->count, m->data);
98 			sunMsgDrop(m);
99 			continue;
100 		}
101 		if(srv->chatty)
102 			fprint(2, "in: %B\n", &m->rpc);
103 
104 		if(srv->alwaysReject){
105 			if(srv->chatty)
106 				fprint(2, "\trejecting\n");
107 			sunMsgReplyError(m, SunAuthTooWeak);
108 			continue;
109 		}
110 
111 		if(!m->rpc.iscall){
112 			sunMsgReplyError(m, SunGarbageArgs);
113 			continue;
114 		}
115 
116 		if((pg = sunFindProg(srv, m, &m->rpc, &c)) == nil){
117 			/* sunFindProg sent error */
118 			continue;
119 		}
120 
121 		p = m->rpc.data;
122 		ep = p+m->rpc.ndata;
123 		m->call = nil;
124 		if((ok = sunCallUnpackAlloc(pg, m->rpc.proc<<1, p, ep, &p, &m->call)) != SunSuccess){
125 			sunMsgReplyError(m, ok);
126 			continue;
127 		}
128 		m->call->rpc = m->rpc;
129 
130 		if(srv->chatty)
131 			fprint(2, "\t%C\n", m->call);
132 
133 		m->pg = pg;
134 		sendp(c, m);
135 	}
136 }
137 
138 static SunProg*
sunFindProg(SunSrv * srv,SunMsg * m,SunRpc * rpc,Channel ** pc)139 sunFindProg(SunSrv *srv, SunMsg *m, SunRpc *rpc, Channel **pc)
140 {
141 	int i, vlo, vhi;
142 	SunProg *pg;
143 
144 	vlo = 0x7fffffff;
145 	vhi = -1;
146 
147 	for(i=0; i<srv->nprog; i++){
148 		pg = srv->prog[i];
149 		if(pg->prog != rpc->prog)
150 			continue;
151 		if(pg->vers == rpc->vers){
152 			*pc = srv->cdispatch[i];
153 			return pg;
154 		}
155 		/* right program, wrong version: record range */
156 		if(pg->vers < vlo)
157 			vlo = pg->vers;
158 		if(pg->vers > vhi)
159 			vhi = pg->vers;
160 	}
161 	if(vhi == -1){
162 		if(srv->chatty)
163 			fprint(2, "\tprogram %ud unavailable\n", rpc->prog);
164 		sunMsgReplyError(m, SunProgUnavail);
165 	}else{
166 		/* putting these in rpc is a botch */
167 		rpc->low = vlo;
168 		rpc->high = vhi;
169 		if(srv->chatty)
170 			fprint(2, "\tversion %ud unavailable; have %d-%d\n", rpc->vers, vlo, vhi);
171 		sunMsgReplyError(m, SunProgMismatch);
172 	}
173 	return nil;
174 }
175 
176 static void
sunRpcReplyThread(void * v)177 sunRpcReplyThread(void *v)
178 {
179 	SunMsg *m;
180 	SunSrv *srv = v;
181 
182 	while((m = recvp(srv->creply)) != nil){
183 		/* could record in cache here? */
184 		sendp(m->creply, m);
185 	}
186 }
187 
188 int
sunMsgReplyError(SunMsg * m,SunStatus error)189 sunMsgReplyError(SunMsg *m, SunStatus error)
190 {
191 	uchar *p, *bp, *ep;
192 	int n;
193 
194 	m->rpc.status = error;
195 	m->rpc.iscall = 0;
196 	m->rpc.verf.flavor = SunAuthNone;
197 	m->rpc.data = nil;
198 	m->rpc.ndata = 0;
199 
200 	if(m->srv->chatty)
201 		fprint(2, "out: %B\n", &m->rpc);
202 
203 	n = sunRpcSize(&m->rpc);
204 	bp = emalloc(n);
205 	ep = bp+n;
206 	p = bp;
207 	if(sunRpcPack(p, ep, &p, &m->rpc) < 0){
208 		fprint(2, "sunRpcPack failed\n");
209 		sunMsgDrop(m);
210 		return 0;
211 	}
212 	if(p != ep){
213 		fprint(2, "sunMsgReplyError: rpc sizes didn't work out\n");
214 		sunMsgDrop(m);
215 		return 0;
216 	}
217 	free(m->data);
218 	m->data = bp;
219 	m->count = n;
220 	sendp(m->srv->creply, m);
221 	return 0;
222 }
223 
224 int
sunMsgReply(SunMsg * m,SunCall * c)225 sunMsgReply(SunMsg *m, SunCall *c)
226 {
227 	int n1, n2;
228 	uchar *bp, *p, *ep;
229 
230 	c->type = m->call->type+1;
231 	c->rpc.iscall = 0;
232 	c->rpc.prog = m->rpc.prog;
233 	c->rpc.vers = m->rpc.vers;
234 	c->rpc.proc = m->rpc.proc;
235 	c->rpc.xid = m->rpc.xid;
236 
237 	if(m->srv->chatty){
238 		fprint(2, "out: %B\n", &c->rpc);
239 		fprint(2, "\t%C\n", c);
240 	}
241 
242 	n1 = sunRpcSize(&c->rpc);
243 	n2 = sunCallSize(m->pg, c);
244 
245 	bp = emalloc(n1+n2);
246 	ep = bp+n1+n2;
247 	p = bp;
248 	if(sunRpcPack(p, ep, &p, &c->rpc) != SunSuccess){
249 		fprint(2, "sunRpcPack failed\n");
250 		return sunMsgDrop(m);
251 	}
252 	if(sunCallPack(m->pg, p, ep, &p, c) != SunSuccess){
253 		fprint(2, "pg->pack failed\n");
254 		return sunMsgDrop(m);
255 	}
256 	if(p != ep){
257 		fprint(2, "sunMsgReply: sizes didn't work out\n");
258 		return sunMsgDrop(m);
259 	}
260 	free(m->data);
261 	m->data = bp;
262 	m->count = n1+n2;
263 
264 	sendp(m->srv->creply, m);
265 	return 0;
266 }
267 
268 int
sunMsgDrop(SunMsg * m)269 sunMsgDrop(SunMsg *m)
270 {
271 	free(m->data);
272 	free(m->call);
273 	memset(m, 0xFB, sizeof *m);
274 	free(m);
275 	return 0;
276 }
277 
278