xref: /plan9/sys/src/cmd/9nfs/server.c (revision f27a9a5a0b699d2f44893d9491ecc2336a1fbc19)
19a747e4fSDavid du Colombier #include "all.h"
29a747e4fSDavid du Colombier #include <ndb.h>
39a747e4fSDavid du Colombier #include <ip.h>
49a747e4fSDavid du Colombier 
59a747e4fSDavid du Colombier static int	alarmflag;
69a747e4fSDavid du Colombier 
79a747e4fSDavid du Colombier static int	Iconv(Fmt*);
89a747e4fSDavid du Colombier static void	openudp(int);
99a747e4fSDavid du Colombier static void	cachereply(Rpccall*, void*, int);
109a747e4fSDavid du Colombier static int	replycache(int, Rpccall*, long (*)(int, void*, long));
119a747e4fSDavid du Colombier static void	udpserver(int, Progmap*);
129a747e4fSDavid du Colombier static void	tcpserver(int, Progmap*);
13*f27a9a5aSDavid du Colombier static void	getendpoints(Udphdr*, char*);
149a747e4fSDavid du Colombier static long	readtcp(int, void*, long);
159a747e4fSDavid du Colombier static long	writetcp(int, void*, long);
169a747e4fSDavid du Colombier static int	servemsg(int, long (*)(int, void*, long), long (*)(int, void*, long),
179a747e4fSDavid du Colombier 		int, Progmap*);
189a747e4fSDavid du Colombier void	(*rpcalarm)(void);
199a747e4fSDavid du Colombier int	rpcdebug;
209a747e4fSDavid du Colombier int	rejectall;
219a747e4fSDavid du Colombier int	p9debug;
229a747e4fSDavid du Colombier 
239a747e4fSDavid du Colombier int	nocache;
249a747e4fSDavid du Colombier 
259a747e4fSDavid du Colombier uchar	buf[9000];
269a747e4fSDavid du Colombier uchar	rbuf[9000];
279a747e4fSDavid du Colombier uchar	resultbuf[9000];
289a747e4fSDavid du Colombier 
29363b328dSDavid du Colombier static int tcp;
30363b328dSDavid du Colombier 
31363b328dSDavid du Colombier char *commonopts = "[-9CDrtv]";			/* for usage() messages */
32363b328dSDavid du Colombier 
33363b328dSDavid du Colombier /*
34363b328dSDavid du Colombier  * this recognises common, nominally rcp-related options.
35363b328dSDavid du Colombier  * they may not take arguments.
36363b328dSDavid du Colombier  */
37363b328dSDavid du Colombier int
38363b328dSDavid du Colombier argopt(int c)
39363b328dSDavid du Colombier {
40363b328dSDavid du Colombier 	switch(c){
41363b328dSDavid du Colombier 	case '9':
42363b328dSDavid du Colombier 		++p9debug;
43363b328dSDavid du Colombier 		return 0;
44363b328dSDavid du Colombier 	case 'C':
45363b328dSDavid du Colombier 		++nocache;
46363b328dSDavid du Colombier 		return 0;
47363b328dSDavid du Colombier 	case 'D':
48363b328dSDavid du Colombier 		++rpcdebug;
49363b328dSDavid du Colombier 		return 0;
50363b328dSDavid du Colombier 	case 'r':
51363b328dSDavid du Colombier 		++rejectall;
52363b328dSDavid du Colombier 		return 0;
53363b328dSDavid du Colombier 	case 't':
54363b328dSDavid du Colombier 		tcp = 1;
55363b328dSDavid du Colombier 		return 0;
56363b328dSDavid du Colombier 	case 'v':
57363b328dSDavid du Colombier 		++chatty;
58363b328dSDavid du Colombier 		return 0;
59363b328dSDavid du Colombier 	default:
60363b328dSDavid du Colombier 		return -1;
61363b328dSDavid du Colombier 	}
62363b328dSDavid du Colombier }
63363b328dSDavid du Colombier 
64363b328dSDavid du Colombier /*
65363b328dSDavid du Colombier  * all option parsing is now done in (*pg->init)(), which can call back
66363b328dSDavid du Colombier  * here to argopt for common options.
67363b328dSDavid du Colombier  */
689a747e4fSDavid du Colombier void
699a747e4fSDavid du Colombier server(int argc, char **argv, int myport, Progmap *progmap)
709a747e4fSDavid du Colombier {
719a747e4fSDavid du Colombier 	Progmap *pg;
729a747e4fSDavid du Colombier 
739a747e4fSDavid du Colombier 	fmtinstall('I', Iconv);
749a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
759a747e4fSDavid du Colombier 	fmtinstall('D', dirfmt);
769a747e4fSDavid du Colombier 
779a747e4fSDavid du Colombier 	switch(rfork(RFNOWAIT|RFENVG|RFNAMEG|RFNOTEG|RFFDG|RFPROC)){
789a747e4fSDavid du Colombier 	case -1:
799a747e4fSDavid du Colombier 		panic("fork");
809a747e4fSDavid du Colombier 	default:
819a747e4fSDavid du Colombier 		_exits(0);
829a747e4fSDavid du Colombier 	case 0:
839a747e4fSDavid du Colombier 		break;
849a747e4fSDavid du Colombier 	}
856ab4d0ffSDavid du Colombier 
866ab4d0ffSDavid du Colombier 	switch(rfork(RFMEM|RFPROC)){
876ab4d0ffSDavid du Colombier 	case 0:
886ab4d0ffSDavid du Colombier 		for(;;){
896ab4d0ffSDavid du Colombier 			sleep(30*1000);
906ab4d0ffSDavid du Colombier 			alarmflag = 1;
916ab4d0ffSDavid du Colombier 		}
926ab4d0ffSDavid du Colombier 	case -1:
936ab4d0ffSDavid du Colombier 		sysfatal("rfork: %r");
946ab4d0ffSDavid du Colombier 	}
956ab4d0ffSDavid du Colombier 
969a747e4fSDavid du Colombier 	for(pg=progmap; pg->init; pg++)
97363b328dSDavid du Colombier 		(*pg->init)(argc, argv);
989a747e4fSDavid du Colombier 	if(tcp)
999a747e4fSDavid du Colombier 		tcpserver(myport, progmap);
1009a747e4fSDavid du Colombier 	else
1019a747e4fSDavid du Colombier 		udpserver(myport, progmap);
1029a747e4fSDavid du Colombier }
1039a747e4fSDavid du Colombier 
1049a747e4fSDavid du Colombier static void
1059a747e4fSDavid du Colombier udpserver(int myport, Progmap *progmap)
1069a747e4fSDavid du Colombier {
1079a747e4fSDavid du Colombier 	char service[128];
1089a747e4fSDavid du Colombier 	char data[128];
1099a747e4fSDavid du Colombier 	char devdir[40];
1109a747e4fSDavid du Colombier 	int ctlfd, datafd;
1119a747e4fSDavid du Colombier 
1129a747e4fSDavid du Colombier 	snprint(service, sizeof service, "udp!*!%d", myport);
1139a747e4fSDavid du Colombier 	ctlfd = announce(service, devdir);
1149a747e4fSDavid du Colombier 	if(ctlfd < 0)
1159a747e4fSDavid du Colombier 		panic("can't announce %s: %r\n", service);
1169a747e4fSDavid du Colombier 	if(fprint(ctlfd, "headers") < 0)
1179a747e4fSDavid du Colombier 		panic("can't set header mode: %r\n");
1189a747e4fSDavid du Colombier 
1199a747e4fSDavid du Colombier 	snprint(data, sizeof data, "%s/data", devdir);
1209a747e4fSDavid du Colombier 	datafd = open(data, ORDWR);
1219a747e4fSDavid du Colombier 	if(datafd < 0)
1229a747e4fSDavid du Colombier 		panic("can't open udp data: %r\n");
1239a747e4fSDavid du Colombier 	close(ctlfd);
1249a747e4fSDavid du Colombier 
1259a747e4fSDavid du Colombier 	chatsrv(0);
1269a747e4fSDavid du Colombier 	clog("%s: listening to port %d\n", argv0, myport);
127*f27a9a5aSDavid du Colombier 	while (servemsg(datafd, read, write, myport, progmap) >= 0)
128*f27a9a5aSDavid du Colombier 		continue;
1299a747e4fSDavid du Colombier 	exits(0);
1309a747e4fSDavid du Colombier }
1319a747e4fSDavid du Colombier 
1329a747e4fSDavid du Colombier static void
1339a747e4fSDavid du Colombier tcpserver(int myport, Progmap *progmap)
1349a747e4fSDavid du Colombier {
1359a747e4fSDavid du Colombier 	char adir[40];
1369a747e4fSDavid du Colombier 	char ldir[40];
1379a747e4fSDavid du Colombier 	char ds[40];
1389a747e4fSDavid du Colombier 	int actl, lctl, data;
1399a747e4fSDavid du Colombier 
1409a747e4fSDavid du Colombier 	snprint(ds, sizeof ds, "tcp!*!%d", myport);
1419a747e4fSDavid du Colombier 	chatsrv(0);
1429a747e4fSDavid du Colombier 	actl = -1;
1439a747e4fSDavid du Colombier 	for(;;){
1449a747e4fSDavid du Colombier 		if(actl < 0){
1459a747e4fSDavid du Colombier 			actl = announce(ds, adir);
1469a747e4fSDavid du Colombier 			if(actl < 0){
1479a747e4fSDavid du Colombier 				clog("%s: listening to tcp port %d\n", argv0, myport);
1489a747e4fSDavid du Colombier 				clog("announcing: %r");
1499a747e4fSDavid du Colombier 				break;
1509a747e4fSDavid du Colombier 			}
1519a747e4fSDavid du Colombier 		}
1529a747e4fSDavid du Colombier 		lctl = listen(adir, ldir);
1539a747e4fSDavid du Colombier 		if(lctl < 0){
1549a747e4fSDavid du Colombier 			close(actl);
1559a747e4fSDavid du Colombier 			actl = -1;
1569a747e4fSDavid du Colombier 			continue;
1579a747e4fSDavid du Colombier 		}
1589a747e4fSDavid du Colombier 		switch(fork()){
1599a747e4fSDavid du Colombier 		case -1:
1609a747e4fSDavid du Colombier 			clog("%s!%d: %r\n", argv0, myport);
1619a747e4fSDavid du Colombier 			/* fall through */
1629a747e4fSDavid du Colombier 		default:
1639a747e4fSDavid du Colombier 			close(lctl);
1649a747e4fSDavid du Colombier 			continue;
1659a747e4fSDavid du Colombier 		case 0:
1669a747e4fSDavid du Colombier 			close(actl);
1679a747e4fSDavid du Colombier 			data = accept(lctl, ldir);
1689a747e4fSDavid du Colombier 			close(lctl);
1699a747e4fSDavid du Colombier 			if(data < 0)
1709a747e4fSDavid du Colombier 				exits(0);
1719a747e4fSDavid du Colombier 
172*f27a9a5aSDavid du Colombier 			getendpoints((Udphdr*)buf, ldir);
1739a747e4fSDavid du Colombier 
1749a747e4fSDavid du Colombier 			for(;;){
1759a747e4fSDavid du Colombier 				if(servemsg(data, readtcp, writetcp, myport, progmap) < 0)
1769a747e4fSDavid du Colombier 					break;
1779a747e4fSDavid du Colombier 			}
1789a747e4fSDavid du Colombier 			close(data);
1799a747e4fSDavid du Colombier 			exits(0);
1809a747e4fSDavid du Colombier 		}
1819a747e4fSDavid du Colombier 	}
1829a747e4fSDavid du Colombier 	exits(0);
1839a747e4fSDavid du Colombier }
1849a747e4fSDavid du Colombier 
1859a747e4fSDavid du Colombier static int
1869a747e4fSDavid du Colombier servemsg(int fd, long (*readmsg)(int, void*, long), long (*writemsg)(int, void*, long),
1879a747e4fSDavid du Colombier 		int myport, Progmap * progmap)
1889a747e4fSDavid du Colombier {
1899a747e4fSDavid du Colombier 	int i, n, nreply;
1909a747e4fSDavid du Colombier 	Rpccall rcall, rreply;
1919a747e4fSDavid du Colombier 	int vlo, vhi;
1929a747e4fSDavid du Colombier 	Progmap *pg;
1939a747e4fSDavid du Colombier 	Procmap *pp;
1949a747e4fSDavid du Colombier 	char errbuf[ERRMAX];
1959a747e4fSDavid du Colombier 
1969a747e4fSDavid du Colombier 	if(alarmflag){
1979a747e4fSDavid du Colombier 		alarmflag = 0;
1989a747e4fSDavid du Colombier 		if(rpcalarm)
1999a747e4fSDavid du Colombier 			(*rpcalarm)();
2009a747e4fSDavid du Colombier 	}
2019a747e4fSDavid du Colombier 	n = (*readmsg)(fd, buf, sizeof buf);
2029a747e4fSDavid du Colombier 	if(n < 0){
2039a747e4fSDavid du Colombier 		errstr(errbuf, sizeof errbuf);
2049a747e4fSDavid du Colombier 		if(strcmp(errbuf, "interrupted") == 0)
2059a747e4fSDavid du Colombier 			return 0;
2069a747e4fSDavid du Colombier 		clog("port %d: error: %s\n", myport, errbuf);
2079a747e4fSDavid du Colombier 		return -1;
2089a747e4fSDavid du Colombier 	}
2099a747e4fSDavid du Colombier 	if(n == 0){
2109a747e4fSDavid du Colombier 		clog("port %d: EOF\n", myport);
2119a747e4fSDavid du Colombier 		return -1;
2129a747e4fSDavid du Colombier 	}
2139a747e4fSDavid du Colombier 	if(rpcdebug == 1)
2149a747e4fSDavid du Colombier 		fprint(2, "%s: rpc from %d.%d.%d.%d/%d\n",
2159a747e4fSDavid du Colombier 			argv0, buf[12], buf[13], buf[14], buf[15],
2169a747e4fSDavid du Colombier 			(buf[32]<<8)|buf[33]);
2179a747e4fSDavid du Colombier 	i = rpcM2S(buf, &rcall, n);
2189a747e4fSDavid du Colombier 	if(i != 0){
2199a747e4fSDavid du Colombier 		clog("udp port %d: message format error %d\n",
2209a747e4fSDavid du Colombier 			myport, i);
2219a747e4fSDavid du Colombier 		return 0;
2229a747e4fSDavid du Colombier 	}
2239a747e4fSDavid du Colombier 	if(rpcdebug > 1)
2249a747e4fSDavid du Colombier 		rpcprint(2, &rcall);
2259a747e4fSDavid du Colombier 	if(rcall.mtype != CALL)
2269a747e4fSDavid du Colombier 		return 0;
2279a747e4fSDavid du Colombier 	if(replycache(fd, &rcall, writemsg))
2289a747e4fSDavid du Colombier 		return 0;
2299a747e4fSDavid du Colombier 	nreply = 0;
2309a747e4fSDavid du Colombier 	rreply.host = rcall.host;
2319a747e4fSDavid du Colombier 	rreply.port = rcall.port;
2329a747e4fSDavid du Colombier 	rreply.lhost = rcall.lhost;
2339a747e4fSDavid du Colombier 	rreply.lport = rcall.lport;
2349a747e4fSDavid du Colombier 	rreply.xid = rcall.xid;
2359a747e4fSDavid du Colombier 	rreply.mtype = REPLY;
2369a747e4fSDavid du Colombier 	if(rcall.rpcvers != 2){
2379a747e4fSDavid du Colombier 		rreply.stat = MSG_DENIED;
2389a747e4fSDavid du Colombier 		rreply.rstat = RPC_MISMATCH;
2399a747e4fSDavid du Colombier 		rreply.rlow = 2;
2409a747e4fSDavid du Colombier 		rreply.rhigh = 2;
2419a747e4fSDavid du Colombier 		goto send_reply;
2429a747e4fSDavid du Colombier 	}
2439a747e4fSDavid du Colombier 	if(rejectall){
2449a747e4fSDavid du Colombier 		rreply.stat = MSG_DENIED;
2459a747e4fSDavid du Colombier 		rreply.rstat = AUTH_ERROR;
2469a747e4fSDavid du Colombier 		rreply.authstat = AUTH_TOOWEAK;
2479a747e4fSDavid du Colombier 		goto send_reply;
2489a747e4fSDavid du Colombier 	}
2499a747e4fSDavid du Colombier 	i = n - (((uchar *)rcall.args) - buf);
2509a747e4fSDavid du Colombier 	if(rpcdebug > 1)
2519a747e4fSDavid du Colombier 		fprint(2, "arg size = %d\n", i);
2529a747e4fSDavid du Colombier 	rreply.stat = MSG_ACCEPTED;
2539a747e4fSDavid du Colombier 	rreply.averf.flavor = 0;
2549a747e4fSDavid du Colombier 	rreply.averf.count = 0;
2559a747e4fSDavid du Colombier 	rreply.results = resultbuf;
2569a747e4fSDavid du Colombier 	vlo = 0x7fffffff;
2579a747e4fSDavid du Colombier 	vhi = -1;
2589a747e4fSDavid du Colombier 	for(pg=progmap; pg->pmap; pg++){
2599a747e4fSDavid du Colombier 		if(pg->progno != rcall.prog)
2609a747e4fSDavid du Colombier 			continue;
2619a747e4fSDavid du Colombier 		if(pg->vers == rcall.vers)
2629a747e4fSDavid du Colombier 			break;
2639a747e4fSDavid du Colombier 		if(pg->vers < vlo)
2649a747e4fSDavid du Colombier 			vlo = pg->vers;
2659a747e4fSDavid du Colombier 		if(pg->vers > vhi)
2669a747e4fSDavid du Colombier 			vhi = pg->vers;
2679a747e4fSDavid du Colombier 	}
2689a747e4fSDavid du Colombier 	if(pg->pmap == 0){
2699a747e4fSDavid du Colombier 		if(vhi < 0)
2709a747e4fSDavid du Colombier 			rreply.astat = PROG_UNAVAIL;
2719a747e4fSDavid du Colombier 		else{
2729a747e4fSDavid du Colombier 			rreply.astat = PROG_MISMATCH;
2739a747e4fSDavid du Colombier 			rreply.plow = vlo;
2749a747e4fSDavid du Colombier 			rreply.phigh = vhi;
2759a747e4fSDavid du Colombier 		}
2769a747e4fSDavid du Colombier 		goto send_reply;
2779a747e4fSDavid du Colombier 	}
2789a747e4fSDavid du Colombier 	for(pp = pg->pmap; pp->procp; pp++)
2799a747e4fSDavid du Colombier 		if(rcall.proc == pp->procno){
2809a747e4fSDavid du Colombier 			if(rpcdebug > 1)
2819a747e4fSDavid du Colombier 				fprint(2, "process %d\n", pp->procno);
2829a747e4fSDavid du Colombier 			rreply.astat = SUCCESS;
2839a747e4fSDavid du Colombier 			nreply = (*pp->procp)(i, &rcall, &rreply);
2849a747e4fSDavid du Colombier 			goto send_reply;
2859a747e4fSDavid du Colombier 		}
2869a747e4fSDavid du Colombier 	rreply.astat = PROC_UNAVAIL;
2879a747e4fSDavid du Colombier send_reply:
2889a747e4fSDavid du Colombier 	if(nreply >= 0){
2899a747e4fSDavid du Colombier 		i = rpcS2M(&rreply, nreply, rbuf);
2909a747e4fSDavid du Colombier 		if(rpcdebug > 1)
2919a747e4fSDavid du Colombier 			rpcprint(2, &rreply);
2929a747e4fSDavid du Colombier 		(*writemsg)(fd, rbuf, i);
2939a747e4fSDavid du Colombier 		cachereply(&rreply, rbuf, i);
2949a747e4fSDavid du Colombier 	}
2959a747e4fSDavid du Colombier 	return 0;
2969a747e4fSDavid du Colombier }
2979a747e4fSDavid du Colombier 
2989a747e4fSDavid du Colombier static void
2999a747e4fSDavid du Colombier getendpoint(char *dir, char *file, uchar *addr, uchar *port)
3009a747e4fSDavid du Colombier {
3019a747e4fSDavid du Colombier 	int fd, n;
3029a747e4fSDavid du Colombier 	char buf[128];
3039a747e4fSDavid du Colombier 	char *sys, *serv;
3049a747e4fSDavid du Colombier 
3059a747e4fSDavid du Colombier 	sys = serv = 0;
3069a747e4fSDavid du Colombier 
3079a747e4fSDavid du Colombier 	snprint(buf, sizeof buf, "%s/%s", dir, file);
3089a747e4fSDavid du Colombier 	fd = open(buf, OREAD);
3099a747e4fSDavid du Colombier 	if(fd >= 0){
3109a747e4fSDavid du Colombier 		n = read(fd, buf, sizeof(buf)-1);
3119a747e4fSDavid du Colombier 		if(n>0){
3129a747e4fSDavid du Colombier 			buf[n-1] = 0;
3139a747e4fSDavid du Colombier 			serv = strchr(buf, '!');
3149a747e4fSDavid du Colombier 			if(serv){
3159a747e4fSDavid du Colombier 				*serv++ = 0;
3169a747e4fSDavid du Colombier 				serv = strdup(serv);
3179a747e4fSDavid du Colombier 			}
3189a747e4fSDavid du Colombier 			sys = strdup(buf);
3199a747e4fSDavid du Colombier 		}
3209a747e4fSDavid du Colombier 		close(fd);
3219a747e4fSDavid du Colombier 	}
3229a747e4fSDavid du Colombier 	if(serv == 0)
3239a747e4fSDavid du Colombier 		serv = strdup("unknown");
3249a747e4fSDavid du Colombier 	if(sys == 0)
3259a747e4fSDavid du Colombier 		sys = strdup("unknown");
3269a747e4fSDavid du Colombier 	parseip(addr, sys);
3279a747e4fSDavid du Colombier 	n = atoi(serv);
3289a747e4fSDavid du Colombier 	hnputs(port, n);
3299a747e4fSDavid du Colombier }
3309a747e4fSDavid du Colombier 
3319a747e4fSDavid du Colombier static void
332*f27a9a5aSDavid du Colombier getendpoints(Udphdr *ep, char *dir)
3339a747e4fSDavid du Colombier {
3349a747e4fSDavid du Colombier 	getendpoint(dir, "local", ep->laddr, ep->lport);
3359a747e4fSDavid du Colombier 	getendpoint(dir, "remote", ep->raddr, ep->rport);
3369a747e4fSDavid du Colombier }
3379a747e4fSDavid du Colombier 
3389a747e4fSDavid du Colombier static long
3399a747e4fSDavid du Colombier readtcp(int fd, void *vbuf, long blen)
3409a747e4fSDavid du Colombier {
3419a747e4fSDavid du Colombier 	uchar mk[4];
3429a747e4fSDavid du Colombier 	int n, m, sofar;
3439a747e4fSDavid du Colombier 	ulong done;
3449a747e4fSDavid du Colombier 	char *buf;
3459a747e4fSDavid du Colombier 
3469a747e4fSDavid du Colombier 	buf = vbuf;
347*f27a9a5aSDavid du Colombier 	buf += Udphdrsize;
348*f27a9a5aSDavid du Colombier 	blen -= Udphdrsize;
3499a747e4fSDavid du Colombier 
3509a747e4fSDavid du Colombier 	done = 0;
3519a747e4fSDavid du Colombier 	for(sofar = 0; !done; sofar += n){
3529a747e4fSDavid du Colombier 		m = readn(fd, mk, 4);
3539a747e4fSDavid du Colombier 		if(m < 4)
3549a747e4fSDavid du Colombier 			return 0;
3559a747e4fSDavid du Colombier 		done = (mk[0]<<24)|(mk[1]<<16)|(mk[2]<<8)|mk[3];
3569a747e4fSDavid du Colombier 		m = done & 0x7fffffff;
3579a747e4fSDavid du Colombier 		done &= 0x80000000;
3589a747e4fSDavid du Colombier 		if(m > blen-sofar)
3599a747e4fSDavid du Colombier 			return -1;
3609a747e4fSDavid du Colombier 		n = readn(fd, buf+sofar, m);
3619a747e4fSDavid du Colombier 		if(m != n)
3629a747e4fSDavid du Colombier 			return 0;
3639a747e4fSDavid du Colombier 	}
364*f27a9a5aSDavid du Colombier 	return sofar + Udphdrsize;
3659a747e4fSDavid du Colombier }
3669a747e4fSDavid du Colombier 
3679a747e4fSDavid du Colombier static long
3689a747e4fSDavid du Colombier writetcp(int fd, void *vbuf, long len)
3699a747e4fSDavid du Colombier {
3709a747e4fSDavid du Colombier 	char *buf;
3719a747e4fSDavid du Colombier 
3729a747e4fSDavid du Colombier 	buf = vbuf;
373*f27a9a5aSDavid du Colombier 	buf += Udphdrsize;
374*f27a9a5aSDavid du Colombier 	len -= Udphdrsize;
3759a747e4fSDavid du Colombier 
3769a747e4fSDavid du Colombier 	buf -= 4;
3779a747e4fSDavid du Colombier 	buf[0] = 0x80 | (len>>24);
3789a747e4fSDavid du Colombier 	buf[1] = len>>16;
3799a747e4fSDavid du Colombier 	buf[2] = len>>8;
3809a747e4fSDavid du Colombier 	buf[3] = len;
3819a747e4fSDavid du Colombier 	len += 4;
3829a747e4fSDavid du Colombier 	return write(fd, buf, len);
3839a747e4fSDavid du Colombier }
3849a747e4fSDavid du Colombier /*
3859a747e4fSDavid du Colombier  *long
3869a747e4fSDavid du Colombier  *niwrite(int fd, void *buf, long count)
3879a747e4fSDavid du Colombier  *{
3889a747e4fSDavid du Colombier  *	char errbuf[ERRLEN];
3899a747e4fSDavid du Colombier  *	long n;
3909a747e4fSDavid du Colombier  *
3919a747e4fSDavid du Colombier  *	for(;;){
3929a747e4fSDavid du Colombier  *		n = write(fd, buf, count);
3939a747e4fSDavid du Colombier  *		if(n < 0){
3949a747e4fSDavid du Colombier  *			errstr(errbuf);
3959a747e4fSDavid du Colombier  *			if(strcmp(errbuf, "interrupted") == 0)
3969a747e4fSDavid du Colombier  *				continue;
3979a747e4fSDavid du Colombier  *			clog("niwrite error: %s\n", errbuf);
3989a747e4fSDavid du Colombier  *			werrstr(errbuf);
3999a747e4fSDavid du Colombier  *		}
4009a747e4fSDavid du Colombier  *		break;
4019a747e4fSDavid du Colombier  *	}
4029a747e4fSDavid du Colombier  *	return n;
4039a747e4fSDavid du Colombier  *}
4049a747e4fSDavid du Colombier  */
4059a747e4fSDavid du Colombier long
4069a747e4fSDavid du Colombier niwrite(int fd, void *buf, long n)
4079a747e4fSDavid du Colombier {
4086ab4d0ffSDavid du Colombier //	int savalarm;
4099a747e4fSDavid du Colombier 
4106ab4d0ffSDavid du Colombier // 	savalarm = alarm(0);
4119a747e4fSDavid du Colombier 	n = write(fd, buf, n);
4126ab4d0ffSDavid du Colombier // 	if(savalarm > 0)
4136ab4d0ffSDavid du Colombier //		alarm(savalarm);
4149a747e4fSDavid du Colombier 	return n;
4159a747e4fSDavid du Colombier }
4169a747e4fSDavid du Colombier 
4179a747e4fSDavid du Colombier typedef struct Namecache	Namecache;
4189a747e4fSDavid du Colombier struct Namecache {
4199a747e4fSDavid du Colombier 	char dom[256];
4209a747e4fSDavid du Colombier 	ulong ipaddr;
4219a747e4fSDavid du Colombier 	Namecache *next;
4229a747e4fSDavid du Colombier };
4239a747e4fSDavid du Colombier 
4249a747e4fSDavid du Colombier Namecache *dnscache;
4259a747e4fSDavid du Colombier 
4269a747e4fSDavid du Colombier static Namecache*
4279a747e4fSDavid du Colombier domlookupl(void *name, int len)
4289a747e4fSDavid du Colombier {
4299a747e4fSDavid du Colombier 	Namecache *n, **ln;
4309a747e4fSDavid du Colombier 
4319a747e4fSDavid du Colombier 	if(len >= sizeof(n->dom))
4329a747e4fSDavid du Colombier 		return nil;
4339a747e4fSDavid du Colombier 
4349a747e4fSDavid du Colombier 	for(ln=&dnscache, n=*ln; n; ln=&(*ln)->next, n=*ln) {
4359a747e4fSDavid du Colombier 		if(strncmp(n->dom, name, len) == 0 && n->dom[len] == 0) {
4369a747e4fSDavid du Colombier 			*ln = n->next;
4379a747e4fSDavid du Colombier 			n->next = dnscache;
4389a747e4fSDavid du Colombier 			dnscache = n;
4399a747e4fSDavid du Colombier 			return n;
4409a747e4fSDavid du Colombier 		}
4419a747e4fSDavid du Colombier 	}
4429a747e4fSDavid du Colombier 	return nil;
4439a747e4fSDavid du Colombier }
4449a747e4fSDavid du Colombier 
4459a747e4fSDavid du Colombier static Namecache*
4469a747e4fSDavid du Colombier domlookup(void *name)
4479a747e4fSDavid du Colombier {
4489a747e4fSDavid du Colombier 	return domlookupl(name, strlen(name));
4499a747e4fSDavid du Colombier }
4509a747e4fSDavid du Colombier 
4519a747e4fSDavid du Colombier static Namecache*
4529a747e4fSDavid du Colombier iplookup(ulong ip)
4539a747e4fSDavid du Colombier {
4549a747e4fSDavid du Colombier 	Namecache *n, **ln;
4559a747e4fSDavid du Colombier 
4569a747e4fSDavid du Colombier 	for(ln=&dnscache, n=*ln; n; ln=&(*ln)->next, n=*ln) {
4579a747e4fSDavid du Colombier 		if(n->ipaddr == ip) {
4589a747e4fSDavid du Colombier 			*ln = n->next;
4599a747e4fSDavid du Colombier 			n->next = dnscache;
4609a747e4fSDavid du Colombier 			dnscache = n;
4619a747e4fSDavid du Colombier 			return n;
4629a747e4fSDavid du Colombier 		}
4639a747e4fSDavid du Colombier 	}
4649a747e4fSDavid du Colombier 	return nil;
4659a747e4fSDavid du Colombier }
4669a747e4fSDavid du Colombier 
4679a747e4fSDavid du Colombier static Namecache*
4689a747e4fSDavid du Colombier addcacheentry(void *name, int len, ulong ip)
4699a747e4fSDavid du Colombier {
4709a747e4fSDavid du Colombier 	Namecache *n;
4719a747e4fSDavid du Colombier 
4729a747e4fSDavid du Colombier 	if(len >= sizeof(n->dom))
4739a747e4fSDavid du Colombier 		return nil;
4749a747e4fSDavid du Colombier 
4759a747e4fSDavid du Colombier 	n = malloc(sizeof(*n));
4769a747e4fSDavid du Colombier 	if(n == nil)
4779a747e4fSDavid du Colombier 		return nil;
4789a747e4fSDavid du Colombier 	strncpy(n->dom, name, len);
4799a747e4fSDavid du Colombier 	n->dom[len] = 0;
4809a747e4fSDavid du Colombier 	n->ipaddr = ip;
4819a747e4fSDavid du Colombier 	n->next = dnscache;
4829a747e4fSDavid du Colombier 	dnscache = n;
4839a747e4fSDavid du Colombier 	return nil;
4849a747e4fSDavid du Colombier }
4859a747e4fSDavid du Colombier 
4869a747e4fSDavid du Colombier int
4879a747e4fSDavid du Colombier getdnsdom(ulong ip, char *name, int len)
4889a747e4fSDavid du Colombier {
48957837e0bSDavid du Colombier 	char buf[128];
4909a747e4fSDavid du Colombier 	Namecache *nc;
49157837e0bSDavid du Colombier 	char *p;
4929a747e4fSDavid du Colombier 
4939a747e4fSDavid du Colombier 	if(nc=iplookup(ip)) {
4949a747e4fSDavid du Colombier 		strncpy(name, nc->dom, len);
4959a747e4fSDavid du Colombier 		name[len-1] = 0;
4969a747e4fSDavid du Colombier 		return 0;
4979a747e4fSDavid du Colombier 	}
4989a747e4fSDavid du Colombier 	clog("getdnsdom: %I\n", ip);
4999a747e4fSDavid du Colombier 	snprint(buf, sizeof buf, "%I", ip);
50057837e0bSDavid du Colombier 	p = csgetvalue("/net", "ip", buf, "dom", nil);
50157837e0bSDavid du Colombier 	if(p == nil)
5029a747e4fSDavid du Colombier 		return -1;
50357837e0bSDavid du Colombier 	strncpy(name, p, len-1);
5049a747e4fSDavid du Colombier 	name[len] = 0;
50557837e0bSDavid du Colombier 	free(p);
5069a747e4fSDavid du Colombier 	addcacheentry(name, strlen(name), ip);
5079a747e4fSDavid du Colombier 	return 0;
5089a747e4fSDavid du Colombier }
5099a747e4fSDavid du Colombier 
5109a747e4fSDavid du Colombier int
5119a747e4fSDavid du Colombier getdom(ulong ip, char *dom, int len)
5129a747e4fSDavid du Colombier {
5139a747e4fSDavid du Colombier 	int i;
5149a747e4fSDavid du Colombier 	static char *prefix[] = { "", "gate-", "fddi-", "u-", 0 };
5159a747e4fSDavid du Colombier 	char **pr;
5169a747e4fSDavid du Colombier 
5179a747e4fSDavid du Colombier 	if(getdnsdom(ip, dom, len)<0)
5189a747e4fSDavid du Colombier 		return -1;
5199a747e4fSDavid du Colombier 
5209a747e4fSDavid du Colombier 	for(pr=prefix; *pr; pr++){
5219a747e4fSDavid du Colombier 		i = strlen(*pr);
5229a747e4fSDavid du Colombier 		if(strncmp(dom, *pr, i) == 0) {
5239a747e4fSDavid du Colombier 			memmove(dom, dom+i, len-i);
5249a747e4fSDavid du Colombier 			break;
5259a747e4fSDavid du Colombier 		}
5269a747e4fSDavid du Colombier 	}
5279a747e4fSDavid du Colombier 	return 0;
5289a747e4fSDavid du Colombier }
5299a747e4fSDavid du Colombier 
5309a747e4fSDavid du Colombier #define	MAXCACHE	64
5319a747e4fSDavid du Colombier 
5329a747e4fSDavid du Colombier static Rpccache *head, *tail;
5339a747e4fSDavid du Colombier static int	ncache;
5349a747e4fSDavid du Colombier 
5359a747e4fSDavid du Colombier static void
5369a747e4fSDavid du Colombier cachereply(Rpccall *rp, void *buf, int len)
5379a747e4fSDavid du Colombier {
5389a747e4fSDavid du Colombier 	Rpccache *cp;
5399a747e4fSDavid du Colombier 
5409a747e4fSDavid du Colombier 	if(nocache)
5419a747e4fSDavid du Colombier 		return;
5429a747e4fSDavid du Colombier 
5439a747e4fSDavid du Colombier 	if(ncache >= MAXCACHE){
5449a747e4fSDavid du Colombier 		if(rpcdebug)
5459a747e4fSDavid du Colombier 			fprint(2, "%s: drop  %I/%ld, xid %uld, len %d\n",
5469a747e4fSDavid du Colombier 				argv0, tail->host,
5479a747e4fSDavid du Colombier 				tail->port, tail->xid, tail->n);
5489a747e4fSDavid du Colombier 		tail = tail->prev;
5499a747e4fSDavid du Colombier 		free(tail->next);
5509a747e4fSDavid du Colombier 		tail->next = 0;
5519a747e4fSDavid du Colombier 		--ncache;
5529a747e4fSDavid du Colombier 	}
5539a747e4fSDavid du Colombier 	cp = malloc(sizeof(Rpccache)+len-4);
5549a747e4fSDavid du Colombier 	if(cp == 0){
5559a747e4fSDavid du Colombier 		clog("cachereply: malloc %d failed\n", len);
5569a747e4fSDavid du Colombier 		return;
5579a747e4fSDavid du Colombier 	}
5589a747e4fSDavid du Colombier 	++ncache;
5599a747e4fSDavid du Colombier 	cp->prev = 0;
5609a747e4fSDavid du Colombier 	cp->next = head;
5619a747e4fSDavid du Colombier 	if(head)
5629a747e4fSDavid du Colombier 		head->prev = cp;
5639a747e4fSDavid du Colombier 	else
5649a747e4fSDavid du Colombier 		tail = cp;
5659a747e4fSDavid du Colombier 	head = cp;
5669a747e4fSDavid du Colombier 	cp->host = rp->host;
5679a747e4fSDavid du Colombier 	cp->port = rp->port;
5689a747e4fSDavid du Colombier 	cp->xid = rp->xid;
5699a747e4fSDavid du Colombier 	cp->n = len;
5709a747e4fSDavid du Colombier 	memmove(cp->data, buf, len);
5719a747e4fSDavid du Colombier 	if(rpcdebug)
5729a747e4fSDavid du Colombier 		fprint(2, "%s: cache %I/%ld, xid %uld, len %d\n",
5739a747e4fSDavid du Colombier 			argv0, cp->host, cp->port, cp->xid, cp->n);
5749a747e4fSDavid du Colombier }
5759a747e4fSDavid du Colombier 
5769a747e4fSDavid du Colombier static int
5779a747e4fSDavid du Colombier replycache(int fd, Rpccall *rp, long (*writemsg)(int, void*, long))
5789a747e4fSDavid du Colombier {
5799a747e4fSDavid du Colombier 	Rpccache *cp;
5809a747e4fSDavid du Colombier 
5819a747e4fSDavid du Colombier 	for(cp=head; cp; cp=cp->next)
5829a747e4fSDavid du Colombier 		if(cp->host == rp->host &&
5839a747e4fSDavid du Colombier 		   cp->port == rp->port &&
5849a747e4fSDavid du Colombier 		   cp->xid == rp->xid)
5859a747e4fSDavid du Colombier 			break;
5869a747e4fSDavid du Colombier 	if(cp == 0)
5879a747e4fSDavid du Colombier 		return 0;
5889a747e4fSDavid du Colombier 	if(cp->prev){	/* move to front */
5899a747e4fSDavid du Colombier 		cp->prev->next = cp->next;
5909a747e4fSDavid du Colombier 		if(cp->next)
5919a747e4fSDavid du Colombier 			cp->next->prev = cp->prev;
5929a747e4fSDavid du Colombier 		else
5939a747e4fSDavid du Colombier 			tail = cp->prev;
5949a747e4fSDavid du Colombier 		cp->prev = 0;
5959a747e4fSDavid du Colombier 		cp->next = head;
5969a747e4fSDavid du Colombier 		head->prev = cp;
5979a747e4fSDavid du Colombier 		head = cp;
5989a747e4fSDavid du Colombier 	}
5999a747e4fSDavid du Colombier 	(*writemsg)(fd, cp->data, cp->n);
6009a747e4fSDavid du Colombier 	if(rpcdebug)
6019a747e4fSDavid du Colombier 		fprint(2, "%s: reply %I/%ld, xid %uld, len %d\n",
6029a747e4fSDavid du Colombier 			argv0, cp->host, cp->port, cp->xid, cp->n);
6039a747e4fSDavid du Colombier 	return 1;
6049a747e4fSDavid du Colombier }
6059a747e4fSDavid du Colombier 
6069a747e4fSDavid du Colombier static int
6079a747e4fSDavid du Colombier Iconv(Fmt *f)
6089a747e4fSDavid du Colombier {
6099a747e4fSDavid du Colombier 	char buf[16];
6109a747e4fSDavid du Colombier 	ulong h;
6119a747e4fSDavid du Colombier 
6129a747e4fSDavid du Colombier 	h = va_arg(f->args, ulong);
6139a747e4fSDavid du Colombier 	snprint(buf, sizeof buf, "%ld.%ld.%ld.%ld",
6149a747e4fSDavid du Colombier 		(h>>24)&0xff, (h>>16)&0xff,
6159a747e4fSDavid du Colombier 		(h>>8)&0xff, h&0xff);
6169a747e4fSDavid du Colombier 	return fmtstrcpy(f, buf);
6179a747e4fSDavid du Colombier }
618