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 278