Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include <thread.h>
5 #include <sunrpc.h>
7 /*
8 * Sun RPC server; for now, no reply cache
9 */
11 static void sunrpcproc(void*);
12 static void sunrpcrequestthread(void*);
13 static void sunrpcreplythread(void*);
14 static void sunrpcforkthread(void*);
15 static SunProg *sunfindprog(SunSrv*, SunMsg*, SunRpc*, Channel**);
17 typedef struct Targ Targ;
18 struct Targ
19 {
20 void (*fn)(void*);
21 void *arg;
22 };
24 SunSrv*
25 sunsrv(void)
26 {
27 SunSrv *srv;
29 srv = emalloc(sizeof(SunSrv));
30 srv->chatty = 0;
31 srv->crequest = chancreate(sizeof(SunMsg*), 16);
32 srv->creply = chancreate(sizeof(SunMsg*), 16);
33 srv->cthread = chancreate(sizeof(Targ), 4);
35 proccreate(sunrpcproc, srv, SunStackSize);
36 return srv;
37 }
39 void
40 sunsrvprog(SunSrv *srv, SunProg *prog, Channel *c)
41 {
42 if(srv->nprog%16 == 0){
43 srv->prog = erealloc(srv->prog, (srv->nprog+16)*sizeof(srv->prog[0]));
44 srv->cdispatch = erealloc(srv->cdispatch, (srv->nprog+16)*sizeof(srv->cdispatch[0]));
45 }
46 srv->prog[srv->nprog] = prog;
47 srv->cdispatch[srv->nprog] = c;
48 srv->nprog++;
49 }
51 static void
52 sunrpcproc(void *v)
53 {
54 threadcreate(sunrpcreplythread, v, SunStackSize);
55 threadcreate(sunrpcrequestthread, v, SunStackSize);
56 threadcreate(sunrpcforkthread, v, SunStackSize);
58 }
60 static void
61 sunrpcforkthread(void *v)
62 {
63 SunSrv *srv = v;
64 Targ t;
66 while(recv(srv->cthread, &t) == 1)
67 threadcreate(t.fn, t.arg, SunStackSize);
68 }
70 void
71 sunsrvthreadcreate(SunSrv *srv, void (*fn)(void*), void *arg)
72 {
73 Targ t;
75 t.fn = fn;
76 t.arg = arg;
77 send(srv->cthread, &t);
78 }
80 static void
81 sunrpcrequestthread(void *v)
82 {
83 int status;
84 uchar *p, *ep;
85 Channel *c;
86 SunSrv *srv = v;
87 SunMsg *m;
88 SunProg *pg;
89 SunStatus ok;
91 while((m = recvp(srv->crequest)) != nil){
92 /* could look up in cache here? */
94 if(srv->chatty) fprint(2, "sun msg %p count %d\n", m, m->count);
95 m->srv = srv;
96 p = m->data;
97 ep = p+m->count;
98 status = m->rpc.status;
99 if(sunrpcunpack(p, ep, &p, &m->rpc) != SunSuccess){
100 fprint(2, "in: %.*H unpack failed\n", m->count, m->data);
101 sunmsgdrop(m);
102 continue;
104 if(srv->chatty)
105 fprint(2, "in: %B\n", &m->rpc);
106 if(status){
107 sunmsgreplyerror(m, status);
108 continue;
110 if(srv->alwaysreject){
111 if(srv->chatty)
112 fprint(2, "\trejecting\n");
113 sunmsgreplyerror(m, SunAuthTooWeak);
114 continue;
117 if(!m->rpc.iscall){
118 sunmsgreplyerror(m, SunGarbageArgs);
119 continue;
122 if((pg = sunfindprog(srv, m, &m->rpc, &c)) == nil){
123 /* sunfindprog sent error */
124 continue;
127 p = m->rpc.data;
128 ep = p+m->rpc.ndata;
129 m->call = nil;
130 if((ok = suncallunpackalloc(pg, m->rpc.proc<<1, p, ep, &p, &m->call)) != SunSuccess){
131 sunmsgreplyerror(m, ok);
132 continue;
134 m->call->rpc = m->rpc;
136 if(srv->chatty)
137 fprint(2, "\t%C\n", m->call);
139 m->pg = pg;
140 sendp(c, m);
144 static SunProg*
145 sunfindprog(SunSrv *srv, SunMsg *m, SunRpc *rpc, Channel **pc)
147 int i, vlo, vhi, any;
148 SunProg *pg;
150 vlo = 0;
151 vhi = 0;
152 any = 0;
154 for(i=0; i<srv->nprog; i++){
155 pg = srv->prog[i];
156 if(pg->prog != rpc->prog)
157 continue;
158 if(pg->vers == rpc->vers){
159 *pc = srv->cdispatch[i];
160 return pg;
162 /* right program, wrong version: record range */
163 if(!any++){
164 vlo = pg->vers;
165 vhi = pg->vers;
166 }else{
167 if(pg->vers < vlo)
168 vlo = pg->vers;
169 if(pg->vers > vhi)
170 vhi = pg->vers;
173 if(vhi == -1){
174 if(srv->chatty)
175 fprint(2, "\tprogram %ud unavailable\n", rpc->prog);
176 sunmsgreplyerror(m, SunProgUnavail);
177 }else{
178 /* putting these in rpc is a botch */
179 rpc->low = vlo;
180 rpc->high = vhi;
181 if(srv->chatty)
182 fprint(2, "\tversion %ud unavailable; have %d-%d\n", rpc->vers, vlo, vhi);
183 sunmsgreplyerror(m, SunProgMismatch);
185 return nil;
188 static void
189 sunrpcreplythread(void *v)
191 SunMsg *m;
192 SunSrv *srv = v;
194 while((m = recvp(srv->creply)) != nil){
195 /* could record in cache here? */
196 sendp(m->creply, m);
200 int
201 sunmsgreplyerror(SunMsg *m, SunStatus error)
203 uchar *p, *bp, *ep;
204 int n;
206 m->rpc.status = error;
207 m->rpc.iscall = 0;
208 m->rpc.verf.flavor = SunAuthNone;
209 m->rpc.data = nil;
210 m->rpc.ndata = 0;
212 if(m->srv->chatty)
213 fprint(2, "out: %B\n", &m->rpc);
215 n = sunrpcsize(&m->rpc);
216 bp = emalloc(n);
217 ep = bp+n;
218 p = bp;
219 if((int32)sunrpcpack(p, ep, &p, &m->rpc) < 0){
220 fprint(2, "sunrpcpack failed\n");
221 sunmsgdrop(m);
222 return 0;
224 if(p != ep){
225 fprint(2, "sunmsgreplyerror: rpc sizes didn't work out\n");
226 sunmsgdrop(m);
227 return 0;
229 free(m->data);
230 m->data = bp;
231 m->count = n;
232 sendp(m->srv->creply, m);
233 return 0;
236 int
237 sunmsgreply(SunMsg *m, SunCall *c)
239 int n1, n2;
240 uchar *bp, *p, *ep;
242 c->type = m->call->type+1;
243 c->rpc.iscall = 0;
244 c->rpc.prog = m->rpc.prog;
245 c->rpc.vers = m->rpc.vers;
246 c->rpc.proc = m->rpc.proc;
247 c->rpc.xid = m->rpc.xid;
249 if(m->srv->chatty){
250 fprint(2, "out: %B\n", &c->rpc);
251 fprint(2, "\t%C\n", c);
254 n1 = sunrpcsize(&c->rpc);
255 n2 = suncallsize(m->pg, c);
257 bp = emalloc(n1+n2);
258 ep = bp+n1+n2;
259 p = bp;
260 if(sunrpcpack(p, ep, &p, &c->rpc) != SunSuccess){
261 fprint(2, "sunrpcpack failed\n");
262 return sunmsgdrop(m);
264 if(suncallpack(m->pg, p, ep, &p, c) != SunSuccess){
265 fprint(2, "pg->pack failed\n");
266 return sunmsgdrop(m);
268 if(p != ep){
269 fprint(2, "sunmsgreply: sizes didn't work out\n");
270 return sunmsgdrop(m);
272 free(m->data);
273 m->data = bp;
274 m->count = n1+n2;
276 sendp(m->srv->creply, m);
277 return 0;
280 int
281 sunmsgdrop(SunMsg *m)
283 free(m->data);
284 free(m->call);
285 memset(m, 0xFB, sizeof *m);
286 free(m);
287 return 0;