xref: /plan9/sys/src/libsunrpc/server.c (revision fb7f0c934c48abaed6040d054ef636408c3c522d)
134e04225SDavid du Colombier #include <u.h>
234e04225SDavid du Colombier #include <libc.h>
334e04225SDavid du Colombier #include <thread.h>
434e04225SDavid du Colombier #include <sunrpc.h>
534e04225SDavid du Colombier 
634e04225SDavid du Colombier /*
734e04225SDavid du Colombier  * Sun RPC server; for now, no reply cache
834e04225SDavid du Colombier  */
934e04225SDavid du Colombier 
1034e04225SDavid du Colombier static void sunRpcProc(void*);
1134e04225SDavid du Colombier static void sunRpcRequestThread(void*);
1234e04225SDavid du Colombier static void sunRpcReplyThread(void*);
1334e04225SDavid du Colombier static void sunRpcForkThread(void*);
1434e04225SDavid du Colombier static SunProg *sunFindProg(SunSrv*, SunMsg*, SunRpc*, Channel**);
1534e04225SDavid du Colombier 
1634e04225SDavid du Colombier typedef struct Targ Targ;
1734e04225SDavid du Colombier struct Targ
1834e04225SDavid du Colombier {
1934e04225SDavid du Colombier 	void (*fn)(void*);
2034e04225SDavid du Colombier 	void *arg;
2134e04225SDavid du Colombier };
2234e04225SDavid du Colombier 
2334e04225SDavid du Colombier SunSrv*
sunSrv(void)2434e04225SDavid du Colombier sunSrv(void)
2534e04225SDavid du Colombier {
2634e04225SDavid du Colombier 	SunSrv *srv;
2734e04225SDavid du Colombier 
2834e04225SDavid du Colombier 	srv = emalloc(sizeof(SunSrv));
2934e04225SDavid du Colombier 	srv->chatty = 0;
3034e04225SDavid du Colombier 	srv->crequest = chancreate(sizeof(SunMsg*), 16);
3134e04225SDavid du Colombier 	srv->creply = chancreate(sizeof(SunMsg*), 16);
3234e04225SDavid du Colombier 	srv->cthread = chancreate(sizeof(Targ), 4);
3334e04225SDavid du Colombier 
3434e04225SDavid du Colombier 	proccreate(sunRpcProc, srv, SunStackSize);
3534e04225SDavid du Colombier 	return srv;
3634e04225SDavid du Colombier }
3734e04225SDavid du Colombier 
3834e04225SDavid du Colombier void
sunSrvProg(SunSrv * srv,SunProg * prog,Channel * c)3934e04225SDavid du Colombier sunSrvProg(SunSrv *srv, SunProg *prog, Channel *c)
4034e04225SDavid du Colombier {
4134e04225SDavid du Colombier 	if(srv->nprog%16 == 0){
4234e04225SDavid du Colombier 		srv->prog = erealloc(srv->prog, (srv->nprog+16)*sizeof(srv->prog[0]));
4334e04225SDavid du Colombier 		srv->cdispatch = erealloc(srv->cdispatch, (srv->nprog+16)*sizeof(srv->cdispatch[0]));
4434e04225SDavid du Colombier 	}
4534e04225SDavid du Colombier 	srv->prog[srv->nprog] = prog;
4634e04225SDavid du Colombier 	srv->cdispatch[srv->nprog] = c;
4734e04225SDavid du Colombier 	srv->nprog++;
4834e04225SDavid du Colombier }
4934e04225SDavid du Colombier 
5034e04225SDavid du Colombier static void
sunRpcProc(void * v)5134e04225SDavid du Colombier sunRpcProc(void *v)
5234e04225SDavid du Colombier {
5334e04225SDavid du Colombier 	threadcreate(sunRpcReplyThread, v, SunStackSize);
5434e04225SDavid du Colombier 	threadcreate(sunRpcRequestThread, v, SunStackSize);
5534e04225SDavid du Colombier 	threadcreate(sunRpcForkThread, v, SunStackSize);
5634e04225SDavid du Colombier 
5734e04225SDavid du Colombier }
5834e04225SDavid du Colombier 
5934e04225SDavid du Colombier static void
sunRpcForkThread(void * v)6034e04225SDavid du Colombier sunRpcForkThread(void *v)
6134e04225SDavid du Colombier {
6234e04225SDavid du Colombier 	SunSrv *srv = v;
6334e04225SDavid du Colombier 	Targ t;
6434e04225SDavid du Colombier 
6534e04225SDavid du Colombier 	while(recv(srv->cthread, &t) == 1)
6634e04225SDavid du Colombier 		threadcreate(t.fn, t.arg, SunStackSize);
6734e04225SDavid du Colombier }
6834e04225SDavid du Colombier 
6934e04225SDavid du Colombier void
sunSrvThreadCreate(SunSrv * srv,void (* fn)(void *),void * arg)7034e04225SDavid du Colombier sunSrvThreadCreate(SunSrv *srv, void (*fn)(void*), void *arg)
7134e04225SDavid du Colombier {
7234e04225SDavid du Colombier 	Targ t;
7334e04225SDavid du Colombier 
7434e04225SDavid du Colombier 	t.fn = fn;
7534e04225SDavid du Colombier 	t.arg = arg;
7634e04225SDavid du Colombier 	send(srv->cthread, &t);
7734e04225SDavid du Colombier }
7834e04225SDavid du Colombier 
7934e04225SDavid du Colombier static void
sunRpcRequestThread(void * v)8034e04225SDavid du Colombier sunRpcRequestThread(void *v)
8134e04225SDavid du Colombier {
8234e04225SDavid du Colombier 	uchar *p, *ep;
8334e04225SDavid du Colombier 	Channel *c;
8434e04225SDavid du Colombier 	SunSrv *srv = v;
8534e04225SDavid du Colombier 	SunMsg *m;
8634e04225SDavid du Colombier 	SunProg *pg;
8734e04225SDavid du Colombier 	SunStatus ok;
8834e04225SDavid du Colombier 
8934e04225SDavid du Colombier 	while((m = recvp(srv->crequest)) != nil){
9034e04225SDavid du Colombier 		/* could look up in cache here? */
9134e04225SDavid du Colombier 
926ff5e913SDavid du Colombier if(srv->chatty) fprint(2, "sun msg %p count %d\n", m, m->count);
9334e04225SDavid du Colombier 		m->srv = srv;
9434e04225SDavid du Colombier 		p = m->data;
9534e04225SDavid du Colombier 		ep = p+m->count;
96*fb7f0c93SDavid du Colombier 		if(sunRpcUnpack(p, ep, &p, &m->rpc) != SunSuccess){
976ff5e913SDavid du Colombier 			fprint(2, "in: %.*H unpack failed\n", m->count, m->data);
9834e04225SDavid du Colombier 			sunMsgDrop(m);
9934e04225SDavid du Colombier 			continue;
10034e04225SDavid du Colombier 		}
10134e04225SDavid du Colombier 		if(srv->chatty)
1026ff5e913SDavid du Colombier 			fprint(2, "in: %B\n", &m->rpc);
10334e04225SDavid du Colombier 
10434e04225SDavid du Colombier 		if(srv->alwaysReject){
10534e04225SDavid du Colombier 			if(srv->chatty)
1066ff5e913SDavid du Colombier 				fprint(2, "\trejecting\n");
10734e04225SDavid du Colombier 			sunMsgReplyError(m, SunAuthTooWeak);
10834e04225SDavid du Colombier 			continue;
10934e04225SDavid du Colombier 		}
11034e04225SDavid du Colombier 
11134e04225SDavid du Colombier 		if(!m->rpc.iscall){
11234e04225SDavid du Colombier 			sunMsgReplyError(m, SunGarbageArgs);
11334e04225SDavid du Colombier 			continue;
11434e04225SDavid du Colombier 		}
11534e04225SDavid du Colombier 
11634e04225SDavid du Colombier 		if((pg = sunFindProg(srv, m, &m->rpc, &c)) == nil){
11734e04225SDavid du Colombier 			/* sunFindProg sent error */
11834e04225SDavid du Colombier 			continue;
11934e04225SDavid du Colombier 		}
12034e04225SDavid du Colombier 
12134e04225SDavid du Colombier 		p = m->rpc.data;
12234e04225SDavid du Colombier 		ep = p+m->rpc.ndata;
12334e04225SDavid du Colombier 		m->call = nil;
12434e04225SDavid du Colombier 		if((ok = sunCallUnpackAlloc(pg, m->rpc.proc<<1, p, ep, &p, &m->call)) != SunSuccess){
12534e04225SDavid du Colombier 			sunMsgReplyError(m, ok);
12634e04225SDavid du Colombier 			continue;
12734e04225SDavid du Colombier 		}
12834e04225SDavid du Colombier 		m->call->rpc = m->rpc;
12934e04225SDavid du Colombier 
13034e04225SDavid du Colombier 		if(srv->chatty)
1316ff5e913SDavid du Colombier 			fprint(2, "\t%C\n", m->call);
13234e04225SDavid du Colombier 
13334e04225SDavid du Colombier 		m->pg = pg;
13434e04225SDavid du Colombier 		sendp(c, m);
13534e04225SDavid du Colombier 	}
13634e04225SDavid du Colombier }
13734e04225SDavid du Colombier 
13834e04225SDavid du Colombier static SunProg*
sunFindProg(SunSrv * srv,SunMsg * m,SunRpc * rpc,Channel ** pc)13934e04225SDavid du Colombier sunFindProg(SunSrv *srv, SunMsg *m, SunRpc *rpc, Channel **pc)
14034e04225SDavid du Colombier {
14134e04225SDavid du Colombier 	int i, vlo, vhi;
14234e04225SDavid du Colombier 	SunProg *pg;
14334e04225SDavid du Colombier 
14434e04225SDavid du Colombier 	vlo = 0x7fffffff;
14534e04225SDavid du Colombier 	vhi = -1;
14634e04225SDavid du Colombier 
14734e04225SDavid du Colombier 	for(i=0; i<srv->nprog; i++){
14834e04225SDavid du Colombier 		pg = srv->prog[i];
14934e04225SDavid du Colombier 		if(pg->prog != rpc->prog)
15034e04225SDavid du Colombier 			continue;
15134e04225SDavid du Colombier 		if(pg->vers == rpc->vers){
15234e04225SDavid du Colombier 			*pc = srv->cdispatch[i];
15334e04225SDavid du Colombier 			return pg;
15434e04225SDavid du Colombier 		}
15534e04225SDavid du Colombier 		/* right program, wrong version: record range */
15634e04225SDavid du Colombier 		if(pg->vers < vlo)
15734e04225SDavid du Colombier 			vlo = pg->vers;
15834e04225SDavid du Colombier 		if(pg->vers > vhi)
15934e04225SDavid du Colombier 			vhi = pg->vers;
16034e04225SDavid du Colombier 	}
16134e04225SDavid du Colombier 	if(vhi == -1){
16234e04225SDavid du Colombier 		if(srv->chatty)
1636ff5e913SDavid du Colombier 			fprint(2, "\tprogram %ud unavailable\n", rpc->prog);
16434e04225SDavid du Colombier 		sunMsgReplyError(m, SunProgUnavail);
16534e04225SDavid du Colombier 	}else{
16634e04225SDavid du Colombier 		/* putting these in rpc is a botch */
16734e04225SDavid du Colombier 		rpc->low = vlo;
16834e04225SDavid du Colombier 		rpc->high = vhi;
16934e04225SDavid du Colombier 		if(srv->chatty)
1706ff5e913SDavid du Colombier 			fprint(2, "\tversion %ud unavailable; have %d-%d\n", rpc->vers, vlo, vhi);
17134e04225SDavid du Colombier 		sunMsgReplyError(m, SunProgMismatch);
17234e04225SDavid du Colombier 	}
17334e04225SDavid du Colombier 	return nil;
17434e04225SDavid du Colombier }
17534e04225SDavid du Colombier 
17634e04225SDavid du Colombier static void
sunRpcReplyThread(void * v)17734e04225SDavid du Colombier sunRpcReplyThread(void *v)
17834e04225SDavid du Colombier {
17934e04225SDavid du Colombier 	SunMsg *m;
18034e04225SDavid du Colombier 	SunSrv *srv = v;
18134e04225SDavid du Colombier 
18234e04225SDavid du Colombier 	while((m = recvp(srv->creply)) != nil){
18334e04225SDavid du Colombier 		/* could record in cache here? */
18434e04225SDavid du Colombier 		sendp(m->creply, m);
18534e04225SDavid du Colombier 	}
18634e04225SDavid du Colombier }
18734e04225SDavid du Colombier 
18834e04225SDavid du Colombier int
sunMsgReplyError(SunMsg * m,SunStatus error)18934e04225SDavid du Colombier sunMsgReplyError(SunMsg *m, SunStatus error)
19034e04225SDavid du Colombier {
19134e04225SDavid du Colombier 	uchar *p, *bp, *ep;
19234e04225SDavid du Colombier 	int n;
19334e04225SDavid du Colombier 
19434e04225SDavid du Colombier 	m->rpc.status = error;
19534e04225SDavid du Colombier 	m->rpc.iscall = 0;
19634e04225SDavid du Colombier 	m->rpc.verf.flavor = SunAuthNone;
19734e04225SDavid du Colombier 	m->rpc.data = nil;
19834e04225SDavid du Colombier 	m->rpc.ndata = 0;
19934e04225SDavid du Colombier 
20034e04225SDavid du Colombier 	if(m->srv->chatty)
2016ff5e913SDavid du Colombier 		fprint(2, "out: %B\n", &m->rpc);
20234e04225SDavid du Colombier 
20334e04225SDavid du Colombier 	n = sunRpcSize(&m->rpc);
20434e04225SDavid du Colombier 	bp = emalloc(n);
20534e04225SDavid du Colombier 	ep = bp+n;
20634e04225SDavid du Colombier 	p = bp;
20734e04225SDavid du Colombier 	if(sunRpcPack(p, ep, &p, &m->rpc) < 0){
20834e04225SDavid du Colombier 		fprint(2, "sunRpcPack failed\n");
20934e04225SDavid du Colombier 		sunMsgDrop(m);
21034e04225SDavid du Colombier 		return 0;
21134e04225SDavid du Colombier 	}
21234e04225SDavid du Colombier 	if(p != ep){
21334e04225SDavid du Colombier 		fprint(2, "sunMsgReplyError: rpc sizes didn't work out\n");
21434e04225SDavid du Colombier 		sunMsgDrop(m);
21534e04225SDavid du Colombier 		return 0;
21634e04225SDavid du Colombier 	}
21734e04225SDavid du Colombier 	free(m->data);
21834e04225SDavid du Colombier 	m->data = bp;
21934e04225SDavid du Colombier 	m->count = n;
22034e04225SDavid du Colombier 	sendp(m->srv->creply, m);
22134e04225SDavid du Colombier 	return 0;
22234e04225SDavid du Colombier }
22334e04225SDavid du Colombier 
22434e04225SDavid du Colombier int
sunMsgReply(SunMsg * m,SunCall * c)22534e04225SDavid du Colombier sunMsgReply(SunMsg *m, SunCall *c)
22634e04225SDavid du Colombier {
22734e04225SDavid du Colombier 	int n1, n2;
22834e04225SDavid du Colombier 	uchar *bp, *p, *ep;
22934e04225SDavid du Colombier 
23034e04225SDavid du Colombier 	c->type = m->call->type+1;
23134e04225SDavid du Colombier 	c->rpc.iscall = 0;
23234e04225SDavid du Colombier 	c->rpc.prog = m->rpc.prog;
23334e04225SDavid du Colombier 	c->rpc.vers = m->rpc.vers;
23434e04225SDavid du Colombier 	c->rpc.proc = m->rpc.proc;
23534e04225SDavid du Colombier 	c->rpc.xid = m->rpc.xid;
23634e04225SDavid du Colombier 
23734e04225SDavid du Colombier 	if(m->srv->chatty){
2386ff5e913SDavid du Colombier 		fprint(2, "out: %B\n", &c->rpc);
2396ff5e913SDavid du Colombier 		fprint(2, "\t%C\n", c);
24034e04225SDavid du Colombier 	}
24134e04225SDavid du Colombier 
24234e04225SDavid du Colombier 	n1 = sunRpcSize(&c->rpc);
24334e04225SDavid du Colombier 	n2 = sunCallSize(m->pg, c);
24434e04225SDavid du Colombier 
24534e04225SDavid du Colombier 	bp = emalloc(n1+n2);
24634e04225SDavid du Colombier 	ep = bp+n1+n2;
24734e04225SDavid du Colombier 	p = bp;
24834e04225SDavid du Colombier 	if(sunRpcPack(p, ep, &p, &c->rpc) != SunSuccess){
24934e04225SDavid du Colombier 		fprint(2, "sunRpcPack failed\n");
25034e04225SDavid du Colombier 		return sunMsgDrop(m);
25134e04225SDavid du Colombier 	}
25234e04225SDavid du Colombier 	if(sunCallPack(m->pg, p, ep, &p, c) != SunSuccess){
25334e04225SDavid du Colombier 		fprint(2, "pg->pack failed\n");
25434e04225SDavid du Colombier 		return sunMsgDrop(m);
25534e04225SDavid du Colombier 	}
25634e04225SDavid du Colombier 	if(p != ep){
25734e04225SDavid du Colombier 		fprint(2, "sunMsgReply: sizes didn't work out\n");
25834e04225SDavid du Colombier 		return sunMsgDrop(m);
25934e04225SDavid du Colombier 	}
26034e04225SDavid du Colombier 	free(m->data);
26134e04225SDavid du Colombier 	m->data = bp;
26234e04225SDavid du Colombier 	m->count = n1+n2;
26334e04225SDavid du Colombier 
26434e04225SDavid du Colombier 	sendp(m->srv->creply, m);
26534e04225SDavid du Colombier 	return 0;
26634e04225SDavid du Colombier }
26734e04225SDavid du Colombier 
26834e04225SDavid du Colombier int
sunMsgDrop(SunMsg * m)26934e04225SDavid du Colombier sunMsgDrop(SunMsg *m)
27034e04225SDavid du Colombier {
27134e04225SDavid du Colombier 	free(m->data);
27234e04225SDavid du Colombier 	free(m->call);
27334e04225SDavid du Colombier 	memset(m, 0xFB, sizeof *m);
27434e04225SDavid du Colombier 	free(m);
27534e04225SDavid du Colombier 	return 0;
27634e04225SDavid du Colombier }
27734e04225SDavid du Colombier 
278