diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/libsunrpc/server.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/libsunrpc/server.c')
-rwxr-xr-x | sys/src/libsunrpc/server.c | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/sys/src/libsunrpc/server.c b/sys/src/libsunrpc/server.c new file mode 100755 index 000000000..a8cbbf1c7 --- /dev/null +++ b/sys/src/libsunrpc/server.c @@ -0,0 +1,277 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include <sunrpc.h> + +/* + * Sun RPC server; for now, no reply cache + */ + +static void sunRpcProc(void*); +static void sunRpcRequestThread(void*); +static void sunRpcReplyThread(void*); +static void sunRpcForkThread(void*); +static SunProg *sunFindProg(SunSrv*, SunMsg*, SunRpc*, Channel**); + +typedef struct Targ Targ; +struct Targ +{ + void (*fn)(void*); + void *arg; +}; + +SunSrv* +sunSrv(void) +{ + SunSrv *srv; + + srv = emalloc(sizeof(SunSrv)); + srv->chatty = 0; + srv->crequest = chancreate(sizeof(SunMsg*), 16); + srv->creply = chancreate(sizeof(SunMsg*), 16); + srv->cthread = chancreate(sizeof(Targ), 4); + + proccreate(sunRpcProc, srv, SunStackSize); + return srv; +} + +void +sunSrvProg(SunSrv *srv, SunProg *prog, Channel *c) +{ + if(srv->nprog%16 == 0){ + srv->prog = erealloc(srv->prog, (srv->nprog+16)*sizeof(srv->prog[0])); + srv->cdispatch = erealloc(srv->cdispatch, (srv->nprog+16)*sizeof(srv->cdispatch[0])); + } + srv->prog[srv->nprog] = prog; + srv->cdispatch[srv->nprog] = c; + srv->nprog++; +} + +static void +sunRpcProc(void *v) +{ + threadcreate(sunRpcReplyThread, v, SunStackSize); + threadcreate(sunRpcRequestThread, v, SunStackSize); + threadcreate(sunRpcForkThread, v, SunStackSize); + +} + +static void +sunRpcForkThread(void *v) +{ + SunSrv *srv = v; + Targ t; + + while(recv(srv->cthread, &t) == 1) + threadcreate(t.fn, t.arg, SunStackSize); +} + +void +sunSrvThreadCreate(SunSrv *srv, void (*fn)(void*), void *arg) +{ + Targ t; + + t.fn = fn; + t.arg = arg; + send(srv->cthread, &t); +} + +static void +sunRpcRequestThread(void *v) +{ + uchar *p, *ep; + Channel *c; + SunSrv *srv = v; + SunMsg *m; + SunProg *pg; + SunStatus ok; + + while((m = recvp(srv->crequest)) != nil){ + /* could look up in cache here? */ + +if(srv->chatty) fprint(2, "sun msg %p count %d\n", m, m->count); + m->srv = srv; + p = m->data; + ep = p+m->count; + if(sunRpcUnpack(p, ep, &p, &m->rpc) != SunSuccess){ + fprint(2, "in: %.*H unpack failed\n", m->count, m->data); + sunMsgDrop(m); + continue; + } + if(srv->chatty) + fprint(2, "in: %B\n", &m->rpc); + + if(srv->alwaysReject){ + if(srv->chatty) + fprint(2, "\trejecting\n"); + sunMsgReplyError(m, SunAuthTooWeak); + continue; + } + + if(!m->rpc.iscall){ + sunMsgReplyError(m, SunGarbageArgs); + continue; + } + + if((pg = sunFindProg(srv, m, &m->rpc, &c)) == nil){ + /* sunFindProg sent error */ + continue; + } + + p = m->rpc.data; + ep = p+m->rpc.ndata; + m->call = nil; + if((ok = sunCallUnpackAlloc(pg, m->rpc.proc<<1, p, ep, &p, &m->call)) != SunSuccess){ + sunMsgReplyError(m, ok); + continue; + } + m->call->rpc = m->rpc; + + if(srv->chatty) + fprint(2, "\t%C\n", m->call); + + m->pg = pg; + sendp(c, m); + } +} + +static SunProg* +sunFindProg(SunSrv *srv, SunMsg *m, SunRpc *rpc, Channel **pc) +{ + int i, vlo, vhi; + SunProg *pg; + + vlo = 0x7fffffff; + vhi = -1; + + for(i=0; i<srv->nprog; i++){ + pg = srv->prog[i]; + if(pg->prog != rpc->prog) + continue; + if(pg->vers == rpc->vers){ + *pc = srv->cdispatch[i]; + return pg; + } + /* right program, wrong version: record range */ + if(pg->vers < vlo) + vlo = pg->vers; + if(pg->vers > vhi) + vhi = pg->vers; + } + if(vhi == -1){ + if(srv->chatty) + fprint(2, "\tprogram %ud unavailable\n", rpc->prog); + sunMsgReplyError(m, SunProgUnavail); + }else{ + /* putting these in rpc is a botch */ + rpc->low = vlo; + rpc->high = vhi; + if(srv->chatty) + fprint(2, "\tversion %ud unavailable; have %d-%d\n", rpc->vers, vlo, vhi); + sunMsgReplyError(m, SunProgMismatch); + } + return nil; +} + +static void +sunRpcReplyThread(void *v) +{ + SunMsg *m; + SunSrv *srv = v; + + while((m = recvp(srv->creply)) != nil){ + /* could record in cache here? */ + sendp(m->creply, m); + } +} + +int +sunMsgReplyError(SunMsg *m, SunStatus error) +{ + uchar *p, *bp, *ep; + int n; + + m->rpc.status = error; + m->rpc.iscall = 0; + m->rpc.verf.flavor = SunAuthNone; + m->rpc.data = nil; + m->rpc.ndata = 0; + + if(m->srv->chatty) + fprint(2, "out: %B\n", &m->rpc); + + n = sunRpcSize(&m->rpc); + bp = emalloc(n); + ep = bp+n; + p = bp; + if(sunRpcPack(p, ep, &p, &m->rpc) < 0){ + fprint(2, "sunRpcPack failed\n"); + sunMsgDrop(m); + return 0; + } + if(p != ep){ + fprint(2, "sunMsgReplyError: rpc sizes didn't work out\n"); + sunMsgDrop(m); + return 0; + } + free(m->data); + m->data = bp; + m->count = n; + sendp(m->srv->creply, m); + return 0; +} + +int +sunMsgReply(SunMsg *m, SunCall *c) +{ + int n1, n2; + uchar *bp, *p, *ep; + + c->type = m->call->type+1; + c->rpc.iscall = 0; + c->rpc.prog = m->rpc.prog; + c->rpc.vers = m->rpc.vers; + c->rpc.proc = m->rpc.proc; + c->rpc.xid = m->rpc.xid; + + if(m->srv->chatty){ + fprint(2, "out: %B\n", &c->rpc); + fprint(2, "\t%C\n", c); + } + + n1 = sunRpcSize(&c->rpc); + n2 = sunCallSize(m->pg, c); + + bp = emalloc(n1+n2); + ep = bp+n1+n2; + p = bp; + if(sunRpcPack(p, ep, &p, &c->rpc) != SunSuccess){ + fprint(2, "sunRpcPack failed\n"); + return sunMsgDrop(m); + } + if(sunCallPack(m->pg, p, ep, &p, c) != SunSuccess){ + fprint(2, "pg->pack failed\n"); + return sunMsgDrop(m); + } + if(p != ep){ + fprint(2, "sunMsgReply: sizes didn't work out\n"); + return sunMsgDrop(m); + } + free(m->data); + m->data = bp; + m->count = n1+n2; + + sendp(m->srv->creply, m); + return 0; +} + +int +sunMsgDrop(SunMsg *m) +{ + free(m->data); + free(m->call); + memset(m, 0xFB, sizeof *m); + free(m); + return 0; +} + |