server.c (5433B)
1 #include <u.h> 2 #include <libc.h> 3 #include <ip.h> 4 #include <thread.h> 5 #include <sunrpc.h> 6 7 /* 8 * Sun RPC server; for now, no reply cache 9 */ 10 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**); 16 17 typedef struct Targ Targ; 18 struct Targ 19 { 20 void (*fn)(void*); 21 void *arg; 22 }; 23 24 SunSrv* 25 sunsrv(void) 26 { 27 SunSrv *srv; 28 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); 34 35 proccreate(sunrpcproc, srv, SunStackSize); 36 return srv; 37 } 38 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 } 50 51 static void 52 sunrpcproc(void *v) 53 { 54 threadcreate(sunrpcreplythread, v, SunStackSize); 55 threadcreate(sunrpcrequestthread, v, SunStackSize); 56 threadcreate(sunrpcforkthread, v, SunStackSize); 57 58 } 59 60 static void 61 sunrpcforkthread(void *v) 62 { 63 SunSrv *srv = v; 64 Targ t; 65 66 while(recv(srv->cthread, &t) == 1) 67 threadcreate(t.fn, t.arg, SunStackSize); 68 } 69 70 void 71 sunsrvthreadcreate(SunSrv *srv, void (*fn)(void*), void *arg) 72 { 73 Targ t; 74 75 t.fn = fn; 76 t.arg = arg; 77 send(srv->cthread, &t); 78 } 79 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; 90 91 while((m = recvp(srv->crequest)) != nil){ 92 /* could look up in cache here? */ 93 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; 103 } 104 if(srv->chatty) 105 fprint(2, "in: %B\n", &m->rpc); 106 if(status){ 107 sunmsgreplyerror(m, status); 108 continue; 109 } 110 if(srv->alwaysreject){ 111 if(srv->chatty) 112 fprint(2, "\trejecting\n"); 113 sunmsgreplyerror(m, SunAuthTooWeak); 114 continue; 115 } 116 117 if(!m->rpc.iscall){ 118 sunmsgreplyerror(m, SunGarbageArgs); 119 continue; 120 } 121 122 if((pg = sunfindprog(srv, m, &m->rpc, &c)) == nil){ 123 /* sunfindprog sent error */ 124 continue; 125 } 126 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; 133 } 134 m->call->rpc = m->rpc; 135 136 if(srv->chatty) 137 fprint(2, "\t%C\n", m->call); 138 139 m->pg = pg; 140 sendp(c, m); 141 } 142 } 143 144 static SunProg* 145 sunfindprog(SunSrv *srv, SunMsg *m, SunRpc *rpc, Channel **pc) 146 { 147 int i, vlo, vhi, any; 148 SunProg *pg; 149 150 vlo = 0; 151 vhi = 0; 152 any = 0; 153 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; 161 } 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; 171 } 172 } 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); 184 } 185 return nil; 186 } 187 188 static void 189 sunrpcreplythread(void *v) 190 { 191 SunMsg *m; 192 SunSrv *srv = v; 193 194 while((m = recvp(srv->creply)) != nil){ 195 /* could record in cache here? */ 196 sendp(m->creply, m); 197 } 198 } 199 200 int 201 sunmsgreplyerror(SunMsg *m, SunStatus error) 202 { 203 uchar *p, *bp, *ep; 204 int n; 205 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; 211 212 if(m->srv->chatty) 213 fprint(2, "out: %B\n", &m->rpc); 214 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; 223 } 224 if(p != ep){ 225 fprint(2, "sunmsgreplyerror: rpc sizes didn't work out\n"); 226 sunmsgdrop(m); 227 return 0; 228 } 229 free(m->data); 230 m->data = bp; 231 m->count = n; 232 sendp(m->srv->creply, m); 233 return 0; 234 } 235 236 int 237 sunmsgreply(SunMsg *m, SunCall *c) 238 { 239 int n1, n2; 240 uchar *bp, *p, *ep; 241 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; 248 249 if(m->srv->chatty){ 250 fprint(2, "out: %B\n", &c->rpc); 251 fprint(2, "\t%C\n", c); 252 } 253 254 n1 = sunrpcsize(&c->rpc); 255 n2 = suncallsize(m->pg, c); 256 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); 263 } 264 if(suncallpack(m->pg, p, ep, &p, c) != SunSuccess){ 265 fprint(2, "pg->pack failed\n"); 266 return sunmsgdrop(m); 267 } 268 if(p != ep){ 269 fprint(2, "sunmsgreply: sizes didn't work out\n"); 270 return sunmsgdrop(m); 271 } 272 free(m->data); 273 m->data = bp; 274 m->count = n1+n2; 275 276 sendp(m->srv->creply, m); 277 return 0; 278 } 279 280 int 281 sunmsgdrop(SunMsg *m) 282 { 283 free(m->data); 284 free(m->call); 285 memset(m, 0xFB, sizeof *m); 286 free(m); 287 return 0; 288 }