plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

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 }