xref: /plan9/sys/src/cmd/9nfs/server.c (revision ff8c3af2f44d95267f67219afa20ba82ff6cf7e4)
1 #include "all.h"
2 #include <ndb.h>
3 #include <ip.h>
4 
5 static int	alarmflag;
6 
7 static int	Iconv(Fmt*);
8 static void	openudp(int);
9 static void	cachereply(Rpccall*, void*, int);
10 static int	replycache(int, Rpccall*, long (*)(int, void*, long));
11 static void	udpserver(int, Progmap*);
12 static void	tcpserver(int, Progmap*);
13 static void	getendpoints(OUdphdr*, char*);
14 static long	readtcp(int, void*, long);
15 static long	writetcp(int, void*, long);
16 static int	servemsg(int, long (*)(int, void*, long), long (*)(int, void*, long),
17 		int, Progmap*);
18 void	(*rpcalarm)(void);
19 int	rpcdebug;
20 int	rejectall;
21 int	p9debug;
22 
23 int	nocache;
24 
25 uchar	buf[9000];
26 uchar	rbuf[9000];
27 uchar	resultbuf[9000];
28 
29 void
30 server(int argc, char **argv, int myport, Progmap *progmap)
31 {
32 	int Argc=argc; char **Argv=argv;
33 	int tcp = 0;
34 	Progmap *pg;
35 
36 	fmtinstall('I', Iconv);
37 	fmtinstall('F', fcallfmt);
38 	fmtinstall('D', dirfmt);
39 
40 	switch(rfork(RFNOWAIT|RFENVG|RFNAMEG|RFNOTEG|RFFDG|RFPROC)){
41 	case -1:
42 		panic("fork");
43 	default:
44 		_exits(0);
45 	case 0:
46 		break;
47 	}
48 	ARGBEGIN{
49 	case '9':
50 		++p9debug;
51 		break;
52 	case 'r':
53 		++rejectall;
54 		break;
55 	case 'v':
56 		++chatty;
57 		break;
58 	case 'D':
59 		++rpcdebug;
60 		break;
61 	case 'C':
62 		++nocache;
63 		break;
64 	case 't':
65 		tcp = 1;
66 		break;
67 	}ARGEND
68 
69 	switch(rfork(RFMEM|RFPROC)){
70 	case 0:
71 		for(;;){
72 			sleep(30*1000);
73 			alarmflag = 1;
74 		}
75 	case -1:
76 		sysfatal("rfork: %r");
77 	}
78 
79 	for(pg=progmap; pg->init; pg++)
80 		(*pg->init)(Argc, Argv);
81 	if(tcp)
82 		tcpserver(myport, progmap);
83 	else
84 		udpserver(myport, progmap);
85 }
86 
87 static void
88 udpserver(int myport, Progmap *progmap)
89 {
90 	char service[128];
91 	char data[128];
92 	char devdir[40];
93 	int ctlfd, datafd;
94 
95 	snprint(service, sizeof service, "udp!*!%d", myport);
96 	ctlfd = announce(service, devdir);
97 	if(ctlfd < 0)
98 		panic("can't announce %s: %r\n", service);
99 	if(fprint(ctlfd, "headers") < 0)
100 		panic("can't set header mode: %r\n");
101 	fprint(ctlfd, "oldheaders");
102 
103 	snprint(data, sizeof data, "%s/data", devdir);
104 
105 	datafd = open(data, ORDWR);
106 	if(datafd < 0)
107 		panic("can't open udp data: %r\n");
108 	close(ctlfd);
109 
110 	chatsrv(0);
111 	clog("%s: listening to port %d\n", argv0, myport);
112 	for(;;){
113 		if(servemsg(datafd, read, write, myport, progmap) < 0)
114 			break;
115 	}
116 	exits(0);
117 }
118 
119 static void
120 tcpserver(int myport, Progmap *progmap)
121 {
122 	char adir[40];
123 	char ldir[40];
124 	char ds[40];
125 	int actl, lctl, data;
126 
127 	snprint(ds, sizeof ds, "tcp!*!%d", myport);
128 	chatsrv(0);
129 	actl = -1;
130 	for(;;){
131 		if(actl < 0){
132 			actl = announce(ds, adir);
133 			if(actl < 0){
134 				clog("%s: listening to tcp port %d\n", argv0, myport);
135 				clog("announcing: %r");
136 				break;
137 			}
138 		}
139 		lctl = listen(adir, ldir);
140 		if(lctl < 0){
141 			close(actl);
142 			actl = -1;
143 			continue;
144 		}
145 		switch(fork()){
146 		case -1:
147 			clog("%s!%d: %r\n", argv0, myport);
148 			/* fall through */
149 		default:
150 			close(lctl);
151 			continue;
152 		case 0:
153 			close(actl);
154 			data = accept(lctl, ldir);
155 			close(lctl);
156 			if(data < 0)
157 				exits(0);
158 
159 			getendpoints((OUdphdr*)buf, ldir);
160 
161 			for(;;){
162 				if(servemsg(data, readtcp, writetcp, myport, progmap) < 0)
163 					break;
164 			}
165 			close(data);
166 			exits(0);
167 		}
168 	}
169 	exits(0);
170 }
171 
172 static int
173 servemsg(int fd, long (*readmsg)(int, void*, long), long (*writemsg)(int, void*, long),
174 		int myport, Progmap * progmap)
175 {
176 	int i, n, nreply;
177 	Rpccall rcall, rreply;
178 	int vlo, vhi;
179 	Progmap *pg;
180 	Procmap *pp;
181 	char errbuf[ERRMAX];
182 
183 	if(alarmflag){
184 		alarmflag = 0;
185 		if(rpcalarm)
186 			(*rpcalarm)();
187 	}
188 	n = (*readmsg)(fd, buf, sizeof buf);
189 	if(n < 0){
190 		errstr(errbuf, sizeof errbuf);
191 		if(strcmp(errbuf, "interrupted") == 0)
192 			return 0;
193 		clog("port %d: error: %s\n", myport, errbuf);
194 		return -1;
195 	}
196 	if(n == 0){
197 		clog("port %d: EOF\n", myport);
198 		return -1;
199 	}
200 	if(rpcdebug == 1)
201 		fprint(2, "%s: rpc from %d.%d.%d.%d/%d\n",
202 			argv0, buf[12], buf[13], buf[14], buf[15],
203 			(buf[32]<<8)|buf[33]);
204 	i = rpcM2S(buf, &rcall, n);
205 	if(i != 0){
206 		clog("udp port %d: message format error %d\n",
207 			myport, i);
208 		return 0;
209 	}
210 	if(rpcdebug > 1)
211 		rpcprint(2, &rcall);
212 	if(rcall.mtype != CALL)
213 		return 0;
214 	if(replycache(fd, &rcall, writemsg))
215 		return 0;
216 	nreply = 0;
217 	rreply.host = rcall.host;
218 	rreply.port = rcall.port;
219 	rreply.lhost = rcall.lhost;
220 	rreply.lport = rcall.lport;
221 	rreply.xid = rcall.xid;
222 	rreply.mtype = REPLY;
223 	if(rcall.rpcvers != 2){
224 		rreply.stat = MSG_DENIED;
225 		rreply.rstat = RPC_MISMATCH;
226 		rreply.rlow = 2;
227 		rreply.rhigh = 2;
228 		goto send_reply;
229 	}
230 	if(rejectall){
231 		rreply.stat = MSG_DENIED;
232 		rreply.rstat = AUTH_ERROR;
233 		rreply.authstat = AUTH_TOOWEAK;
234 		goto send_reply;
235 	}
236 	i = n - (((uchar *)rcall.args) - buf);
237 	if(rpcdebug > 1)
238 		fprint(2, "arg size = %d\n", i);
239 	rreply.stat = MSG_ACCEPTED;
240 	rreply.averf.flavor = 0;
241 	rreply.averf.count = 0;
242 	rreply.results = resultbuf;
243 	vlo = 0x7fffffff;
244 	vhi = -1;
245 	for(pg=progmap; pg->pmap; pg++){
246 		if(pg->progno != rcall.prog)
247 			continue;
248 		if(pg->vers == rcall.vers)
249 			break;
250 		if(pg->vers < vlo)
251 			vlo = pg->vers;
252 		if(pg->vers > vhi)
253 			vhi = pg->vers;
254 	}
255 	if(pg->pmap == 0){
256 		if(vhi < 0)
257 			rreply.astat = PROG_UNAVAIL;
258 		else{
259 			rreply.astat = PROG_MISMATCH;
260 			rreply.plow = vlo;
261 			rreply.phigh = vhi;
262 		}
263 		goto send_reply;
264 	}
265 	for(pp = pg->pmap; pp->procp; pp++)
266 		if(rcall.proc == pp->procno){
267 			if(rpcdebug > 1)
268 				fprint(2, "process %d\n", pp->procno);
269 			rreply.astat = SUCCESS;
270 			nreply = (*pp->procp)(i, &rcall, &rreply);
271 			goto send_reply;
272 		}
273 	rreply.astat = PROC_UNAVAIL;
274 send_reply:
275 	if(nreply >= 0){
276 		i = rpcS2M(&rreply, nreply, rbuf);
277 		if(rpcdebug > 1)
278 			rpcprint(2, &rreply);
279 		(*writemsg)(fd, rbuf, i);
280 		cachereply(&rreply, rbuf, i);
281 	}
282 	return 0;
283 }
284 
285 static void
286 getendpoint(char *dir, char *file, uchar *addr, uchar *port)
287 {
288 	int fd, n;
289 	char buf[128];
290 	char *sys, *serv;
291 
292 	sys = serv = 0;
293 
294 	snprint(buf, sizeof buf, "%s/%s", dir, file);
295 	fd = open(buf, OREAD);
296 	if(fd >= 0){
297 		n = read(fd, buf, sizeof(buf)-1);
298 		if(n>0){
299 			buf[n-1] = 0;
300 			serv = strchr(buf, '!');
301 			if(serv){
302 				*serv++ = 0;
303 				serv = strdup(serv);
304 			}
305 			sys = strdup(buf);
306 		}
307 		close(fd);
308 	}
309 	if(serv == 0)
310 		serv = strdup("unknown");
311 	if(sys == 0)
312 		sys = strdup("unknown");
313 	parseip(addr, sys);
314 	n = atoi(serv);
315 	hnputs(port, n);
316 }
317 
318 static void
319 getendpoints(OUdphdr *ep, char *dir)
320 {
321 	getendpoint(dir, "local", ep->laddr, ep->lport);
322 	getendpoint(dir, "remote", ep->raddr, ep->rport);
323 }
324 
325 static long
326 readtcp(int fd, void *vbuf, long blen)
327 {
328 	uchar mk[4];
329 	int n, m, sofar;
330 	ulong done;
331 	char *buf;
332 
333 	buf = vbuf;
334 	buf += OUdphdrsize;
335 	blen -= OUdphdrsize;
336 
337 	done = 0;
338 	for(sofar = 0; !done; sofar += n){
339 		m = readn(fd, mk, 4);
340 		if(m < 4)
341 			return 0;
342 		done = (mk[0]<<24)|(mk[1]<<16)|(mk[2]<<8)|mk[3];
343 		m = done & 0x7fffffff;
344 		done &= 0x80000000;
345 		if(m > blen-sofar)
346 			return -1;
347 		n = readn(fd, buf+sofar, m);
348 		if(m != n)
349 			return 0;
350 	}
351 	return sofar + OUdphdrsize;
352 }
353 
354 static long
355 writetcp(int fd, void *vbuf, long len)
356 {
357 	char *buf;
358 
359 	buf = vbuf;
360 	buf += OUdphdrsize;
361 	len -= OUdphdrsize;
362 
363 	buf -= 4;
364 	buf[0] = 0x80 | (len>>24);
365 	buf[1] = len>>16;
366 	buf[2] = len>>8;
367 	buf[3] = len;
368 	len += 4;
369 	return write(fd, buf, len);
370 }
371 /*
372  *long
373  *niwrite(int fd, void *buf, long count)
374  *{
375  *	char errbuf[ERRLEN];
376  *	long n;
377  *
378  *	for(;;){
379  *		n = write(fd, buf, count);
380  *		if(n < 0){
381  *			errstr(errbuf);
382  *			if(strcmp(errbuf, "interrupted") == 0)
383  *				continue;
384  *			clog("niwrite error: %s\n", errbuf);
385  *			werrstr(errbuf);
386  *		}
387  *		break;
388  *	}
389  *	return n;
390  *}
391  */
392 long
393 niwrite(int fd, void *buf, long n)
394 {
395 //	int savalarm;
396 
397 // 	savalarm = alarm(0);
398 	n = write(fd, buf, n);
399 // 	if(savalarm > 0)
400 //		alarm(savalarm);
401 	return n;
402 }
403 
404 typedef struct Namecache	Namecache;
405 struct Namecache {
406 	char dom[256];
407 	ulong ipaddr;
408 	Namecache *next;
409 };
410 
411 Namecache *dnscache;
412 
413 static Namecache*
414 domlookupl(void *name, int len)
415 {
416 	Namecache *n, **ln;
417 
418 	if(len >= sizeof(n->dom))
419 		return nil;
420 
421 	for(ln=&dnscache, n=*ln; n; ln=&(*ln)->next, n=*ln) {
422 		if(strncmp(n->dom, name, len) == 0 && n->dom[len] == 0) {
423 			*ln = n->next;
424 			n->next = dnscache;
425 			dnscache = n;
426 			return n;
427 		}
428 	}
429 	return nil;
430 }
431 
432 static Namecache*
433 domlookup(void *name)
434 {
435 	return domlookupl(name, strlen(name));
436 }
437 
438 static Namecache*
439 iplookup(ulong ip)
440 {
441 	Namecache *n, **ln;
442 
443 	for(ln=&dnscache, n=*ln; n; ln=&(*ln)->next, n=*ln) {
444 		if(n->ipaddr == ip) {
445 			*ln = n->next;
446 			n->next = dnscache;
447 			dnscache = n;
448 			return n;
449 		}
450 	}
451 	return nil;
452 }
453 
454 static Namecache*
455 addcacheentry(void *name, int len, ulong ip)
456 {
457 	Namecache *n;
458 
459 	if(len >= sizeof(n->dom))
460 		return nil;
461 
462 	n = malloc(sizeof(*n));
463 	if(n == nil)
464 		return nil;
465 	strncpy(n->dom, name, len);
466 	n->dom[len] = 0;
467 	n->ipaddr = ip;
468 	n->next = dnscache;
469 	dnscache = n;
470 	return nil;
471 }
472 
473 int
474 getdnsdom(ulong ip, char *name, int len)
475 {
476 	char buf[Ndbvlen];
477 	char dom[Ndbvlen];
478 	Namecache *nc;
479 	Ndbtuple *t;
480 
481 	if(nc=iplookup(ip)) {
482 		strncpy(name, nc->dom, len);
483 		name[len-1] = 0;
484 		return 0;
485 	}
486 	clog("getdnsdom: %I\n", ip);
487 	snprint(buf, sizeof buf, "%I", ip);
488 	t = csgetval("/net", "ip", buf, "dom", dom);
489 clog("csgetval %p\n", t);
490 	if(t == nil)
491 		return -1;
492 	ndbfree(t);
493 clog("csgetval %s\n", dom);
494 	strncpy(name, dom, len-1);
495 	name[len] = 0;
496 	addcacheentry(name, strlen(name), ip);
497 	return 0;
498 }
499 
500 int
501 getdom(ulong ip, char *dom, int len)
502 {
503 	int i;
504 	static char *prefix[] = { "", "gate-", "fddi-", "u-", 0 };
505 	char **pr;
506 
507 	if(getdnsdom(ip, dom, len)<0)
508 		return -1;
509 
510 	for(pr=prefix; *pr; pr++){
511 		i = strlen(*pr);
512 		if(strncmp(dom, *pr, i) == 0) {
513 			memmove(dom, dom+i, len-i);
514 			break;
515 		}
516 	}
517 	return 0;
518 }
519 
520 #define	MAXCACHE	64
521 
522 static Rpccache *head, *tail;
523 static int	ncache;
524 
525 static void
526 cachereply(Rpccall *rp, void *buf, int len)
527 {
528 	Rpccache *cp;
529 
530 	if(nocache)
531 		return;
532 
533 	if(ncache >= MAXCACHE){
534 		if(rpcdebug)
535 			fprint(2, "%s: drop  %I/%ld, xid %uld, len %d\n",
536 				argv0, tail->host,
537 				tail->port, tail->xid, tail->n);
538 		tail = tail->prev;
539 		free(tail->next);
540 		tail->next = 0;
541 		--ncache;
542 	}
543 	cp = malloc(sizeof(Rpccache)+len-4);
544 	if(cp == 0){
545 		clog("cachereply: malloc %d failed\n", len);
546 		return;
547 	}
548 	++ncache;
549 	cp->prev = 0;
550 	cp->next = head;
551 	if(head)
552 		head->prev = cp;
553 	else
554 		tail = cp;
555 	head = cp;
556 	cp->host = rp->host;
557 	cp->port = rp->port;
558 	cp->xid = rp->xid;
559 	cp->n = len;
560 	memmove(cp->data, buf, len);
561 	if(rpcdebug)
562 		fprint(2, "%s: cache %I/%ld, xid %uld, len %d\n",
563 			argv0, cp->host, cp->port, cp->xid, cp->n);
564 }
565 
566 static int
567 replycache(int fd, Rpccall *rp, long (*writemsg)(int, void*, long))
568 {
569 	Rpccache *cp;
570 
571 	for(cp=head; cp; cp=cp->next)
572 		if(cp->host == rp->host &&
573 		   cp->port == rp->port &&
574 		   cp->xid == rp->xid)
575 			break;
576 	if(cp == 0)
577 		return 0;
578 	if(cp->prev){	/* move to front */
579 		cp->prev->next = cp->next;
580 		if(cp->next)
581 			cp->next->prev = cp->prev;
582 		else
583 			tail = cp->prev;
584 		cp->prev = 0;
585 		cp->next = head;
586 		head->prev = cp;
587 		head = cp;
588 	}
589 	(*writemsg)(fd, cp->data, cp->n);
590 	if(rpcdebug)
591 		fprint(2, "%s: reply %I/%ld, xid %uld, len %d\n",
592 			argv0, cp->host, cp->port, cp->xid, cp->n);
593 	return 1;
594 }
595 
596 static int
597 Iconv(Fmt *f)
598 {
599 	char buf[16];
600 	ulong h;
601 
602 	h = va_arg(f->args, ulong);
603 	snprint(buf, sizeof buf, "%ld.%ld.%ld.%ld",
604 		(h>>24)&0xff, (h>>16)&0xff,
605 		(h>>8)&0xff, h&0xff);
606 	return fmtstrcpy(f, buf);
607 }
608