]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libsunrpc/server.c
merge
[plan9front.git] / sys / src / libsunrpc / server.c
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*
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
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
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
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
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
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*
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
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
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
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
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