Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <sunrpc.h>
6 /*
7 * Sun RPC server; for now, no reply cache
8 */
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**);
16 typedef struct Targ Targ;
17 struct Targ
18 {
19 void (*fn)(void*);
20 void *arg;
21 };
23 SunSrv*
24 sunsrv(void)
25 {
26 SunSrv *srv;
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);
34 proccreate(sunrpcproc, srv, SunStackSize);
35 return srv;
36 }
38 void
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 }
50 static void
51 sunrpcproc(void *v)
52 {
53 threadcreate(sunrpcreplythread, v, SunStackSize);
54 threadcreate(sunrpcrequestthread, v, SunStackSize);
55 threadcreate(sunrpcforkthread, v, SunStackSize);
57 }
59 static void
60 sunrpcforkthread(void *v)
61 {
62 SunSrv *srv = v;
63 Targ t;
65 while(recv(srv->cthread, &t) == 1)
66 threadcreate(t.fn, t.arg, SunStackSize);
67 }
69 void
70 sunsrvthreadcreate(SunSrv *srv, void (*fn)(void*), void *arg)
71 {
72 Targ t;
74 t.fn = fn;
75 t.arg = arg;
76 send(srv->cthread, &t);
77 }
79 static void
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;
89 while((m = recvp(srv->crequest)) != nil){
90 /* could look up in cache here? */
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;
101 if(srv->chatty)
102 fprint(2, "in: %B\n", &m->rpc);
104 if(srv->alwaysreject){
105 if(srv->chatty)
106 fprint(2, "\trejecting\n");
107 sunmsgreplyerror(m, SunAuthTooWeak);
108 continue;
111 if(!m->rpc.iscall){
112 sunmsgreplyerror(m, SunGarbageArgs);
113 continue;
116 if((pg = sunfindprog(srv, m, &m->rpc, &c)) == nil){
117 /* sunfindprog sent error */
118 continue;
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;
128 m->call->rpc = m->rpc;
130 if(srv->chatty)
131 fprint(2, "\t%C\n", m->call);
133 m->pg = pg;
134 sendp(c, m);
138 static SunProg*
139 sunfindprog(SunSrv *srv, SunMsg *m, SunRpc *rpc, Channel **pc)
141 int i, vlo, vhi;
142 SunProg *pg;
144 vlo = 0x7fffffff;
145 vhi = -1;
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;
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;
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);
173 return nil;
176 static void
177 sunrpcreplythread(void *v)
179 SunMsg *m;
180 SunSrv *srv = v;
182 while((m = recvp(srv->creply)) != nil){
183 /* could record in cache here? */
184 sendp(m->creply, m);
188 int
189 sunmsgreplyerror(SunMsg *m, SunStatus error)
191 uchar *p, *bp, *ep;
192 int n;
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;
200 if(m->srv->chatty)
201 fprint(2, "out: %B\n", &m->rpc);
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;
212 if(p != ep){
213 fprint(2, "sunmsgreplyerror: rpc sizes didn't work out\n");
214 sunmsgdrop(m);
215 return 0;
217 free(m->data);
218 m->data = bp;
219 m->count = n;
220 sendp(m->srv->creply, m);
221 return 0;
224 int
225 sunmsgreply(SunMsg *m, SunCall *c)
227 int n1, n2;
228 uchar *bp, *p, *ep;
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;
237 if(m->srv->chatty){
238 fprint(2, "out: %B\n", &c->rpc);
239 fprint(2, "\t%C\n", c);
242 n1 = sunrpcsize(&c->rpc);
243 n2 = suncallsize(m->pg, c);
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);
252 if(suncallpack(m->pg, p, ep, &p, c) != SunSuccess){
253 fprint(2, "pg->pack failed\n");
254 return sunmsgdrop(m);
256 if(p != ep){
257 fprint(2, "sunmsgreply: sizes didn't work out\n");
258 return sunmsgdrop(m);
260 free(m->data);
261 m->data = bp;
262 m->count = n1+n2;
264 sendp(m->srv->creply, m);
265 return 0;
268 int
269 sunmsgdrop(SunMsg *m)
271 free(m->data);
272 free(m->call);
273 memset(m, 0xFB, sizeof *m);
274 free(m);
275 return 0;