xref: /plan9/sys/src/cmd/9nfs/server.c (revision ea58ad6fbee60d5a3fca57ac646881779dd8f0ea)
19a747e4fSDavid du Colombier #include "all.h"
29a747e4fSDavid du Colombier #include <ndb.h>
39a747e4fSDavid du Colombier 
49a747e4fSDavid du Colombier static int	alarmflag;
59a747e4fSDavid du Colombier 
69a747e4fSDavid du Colombier static int	Iconv(Fmt*);
79a747e4fSDavid du Colombier static void	openudp(int);
89a747e4fSDavid du Colombier static void	cachereply(Rpccall*, void*, int);
99a747e4fSDavid du Colombier static int	replycache(int, Rpccall*, long (*)(int, void*, long));
109a747e4fSDavid du Colombier static void	udpserver(int, Progmap*);
119a747e4fSDavid du Colombier static void	tcpserver(int, Progmap*);
12f27a9a5aSDavid du Colombier static void	getendpoints(Udphdr*, char*);
139a747e4fSDavid du Colombier static long	readtcp(int, void*, long);
149a747e4fSDavid du Colombier static long	writetcp(int, void*, long);
159a747e4fSDavid du Colombier static int	servemsg(int, long (*)(int, void*, long), long (*)(int, void*, long),
169a747e4fSDavid du Colombier 		int, Progmap*);
179a747e4fSDavid du Colombier void	(*rpcalarm)(void);
189a747e4fSDavid du Colombier int	rpcdebug;
199a747e4fSDavid du Colombier int	rejectall;
209a747e4fSDavid du Colombier int	p9debug;
219a747e4fSDavid du Colombier 
229a747e4fSDavid du Colombier int	nocache;
239a747e4fSDavid du Colombier 
249a747e4fSDavid du Colombier uchar	buf[9000];
259a747e4fSDavid du Colombier uchar	rbuf[9000];
269a747e4fSDavid du Colombier uchar	resultbuf[9000];
279a747e4fSDavid du Colombier 
28363b328dSDavid du Colombier static int tcp;
29363b328dSDavid du Colombier 
30363b328dSDavid du Colombier char *commonopts = "[-9CDrtv]";			/* for usage() messages */
31363b328dSDavid du Colombier 
32363b328dSDavid du Colombier /*
33363b328dSDavid du Colombier  * this recognises common, nominally rcp-related options.
34363b328dSDavid du Colombier  * they may not take arguments.
35363b328dSDavid du Colombier  */
36363b328dSDavid du Colombier int
argopt(int c)37363b328dSDavid du Colombier argopt(int c)
38363b328dSDavid du Colombier {
39363b328dSDavid du Colombier 	switch(c){
40363b328dSDavid du Colombier 	case '9':
41363b328dSDavid du Colombier 		++p9debug;
42363b328dSDavid du Colombier 		return 0;
43363b328dSDavid du Colombier 	case 'C':
44363b328dSDavid du Colombier 		++nocache;
45363b328dSDavid du Colombier 		return 0;
46363b328dSDavid du Colombier 	case 'D':
47363b328dSDavid du Colombier 		++rpcdebug;
48363b328dSDavid du Colombier 		return 0;
49363b328dSDavid du Colombier 	case 'r':
50363b328dSDavid du Colombier 		++rejectall;
51363b328dSDavid du Colombier 		return 0;
52363b328dSDavid du Colombier 	case 't':
53363b328dSDavid du Colombier 		tcp = 1;
54363b328dSDavid du Colombier 		return 0;
55363b328dSDavid du Colombier 	case 'v':
56363b328dSDavid du Colombier 		++chatty;
57363b328dSDavid du Colombier 		return 0;
58363b328dSDavid du Colombier 	default:
59363b328dSDavid du Colombier 		return -1;
60363b328dSDavid du Colombier 	}
61363b328dSDavid du Colombier }
62363b328dSDavid du Colombier 
63363b328dSDavid du Colombier /*
64363b328dSDavid du Colombier  * all option parsing is now done in (*pg->init)(), which can call back
65363b328dSDavid du Colombier  * here to argopt for common options.
66363b328dSDavid du Colombier  */
679a747e4fSDavid du Colombier void
server(int argc,char ** argv,int myport,Progmap * progmap)689a747e4fSDavid du Colombier server(int argc, char **argv, int myport, Progmap *progmap)
699a747e4fSDavid du Colombier {
709a747e4fSDavid du Colombier 	Progmap *pg;
719a747e4fSDavid du Colombier 
729a747e4fSDavid du Colombier 	fmtinstall('I', Iconv);
739a747e4fSDavid du Colombier 	fmtinstall('F', fcallfmt);
749a747e4fSDavid du Colombier 	fmtinstall('D', dirfmt);
759a747e4fSDavid du Colombier 
769a747e4fSDavid du Colombier 	switch(rfork(RFNOWAIT|RFENVG|RFNAMEG|RFNOTEG|RFFDG|RFPROC)){
779a747e4fSDavid du Colombier 	case -1:
789a747e4fSDavid du Colombier 		panic("fork");
799a747e4fSDavid du Colombier 	default:
809a747e4fSDavid du Colombier 		_exits(0);
819a747e4fSDavid du Colombier 	case 0:
829a747e4fSDavid du Colombier 		break;
839a747e4fSDavid du Colombier 	}
846ab4d0ffSDavid du Colombier 
856ab4d0ffSDavid du Colombier 	switch(rfork(RFMEM|RFPROC)){
866ab4d0ffSDavid du Colombier 	case 0:
876ab4d0ffSDavid du Colombier 		for(;;){
886ab4d0ffSDavid du Colombier 			sleep(30*1000);
896ab4d0ffSDavid du Colombier 			alarmflag = 1;
906ab4d0ffSDavid du Colombier 		}
916ab4d0ffSDavid du Colombier 	case -1:
926ab4d0ffSDavid du Colombier 		sysfatal("rfork: %r");
936ab4d0ffSDavid du Colombier 	}
946ab4d0ffSDavid du Colombier 
959a747e4fSDavid du Colombier 	for(pg=progmap; pg->init; pg++)
96363b328dSDavid du Colombier 		(*pg->init)(argc, argv);
979a747e4fSDavid du Colombier 	if(tcp)
989a747e4fSDavid du Colombier 		tcpserver(myport, progmap);
999a747e4fSDavid du Colombier 	else
1009a747e4fSDavid du Colombier 		udpserver(myport, progmap);
1019a747e4fSDavid du Colombier }
1029a747e4fSDavid du Colombier 
1039a747e4fSDavid du Colombier static void
udpserver(int myport,Progmap * progmap)1049a747e4fSDavid du Colombier udpserver(int myport, Progmap *progmap)
1059a747e4fSDavid du Colombier {
1069a747e4fSDavid du Colombier 	char service[128];
1079a747e4fSDavid du Colombier 	char data[128];
1089a747e4fSDavid du Colombier 	char devdir[40];
1099a747e4fSDavid du Colombier 	int ctlfd, datafd;
1109a747e4fSDavid du Colombier 
1119a747e4fSDavid du Colombier 	snprint(service, sizeof service, "udp!*!%d", myport);
1129a747e4fSDavid du Colombier 	ctlfd = announce(service, devdir);
1139a747e4fSDavid du Colombier 	if(ctlfd < 0)
1149a747e4fSDavid du Colombier 		panic("can't announce %s: %r\n", service);
1159a747e4fSDavid du Colombier 	if(fprint(ctlfd, "headers") < 0)
1169a747e4fSDavid du Colombier 		panic("can't set header mode: %r\n");
1179a747e4fSDavid du Colombier 
1189a747e4fSDavid du Colombier 	snprint(data, sizeof data, "%s/data", devdir);
1199a747e4fSDavid du Colombier 	datafd = open(data, ORDWR);
1209a747e4fSDavid du Colombier 	if(datafd < 0)
1219a747e4fSDavid du Colombier 		panic("can't open udp data: %r\n");
1229a747e4fSDavid du Colombier 	close(ctlfd);
1239a747e4fSDavid du Colombier 
1249a747e4fSDavid du Colombier 	chatsrv(0);
1259a747e4fSDavid du Colombier 	clog("%s: listening to port %d\n", argv0, myport);
126f27a9a5aSDavid du Colombier 	while (servemsg(datafd, read, write, myport, progmap) >= 0)
127f27a9a5aSDavid du Colombier 		continue;
1289a747e4fSDavid du Colombier 	exits(0);
1299a747e4fSDavid du Colombier }
1309a747e4fSDavid du Colombier 
1319a747e4fSDavid du Colombier static void
tcpserver(int myport,Progmap * progmap)1329a747e4fSDavid du Colombier tcpserver(int myport, Progmap *progmap)
1339a747e4fSDavid du Colombier {
1349a747e4fSDavid du Colombier 	char adir[40];
1359a747e4fSDavid du Colombier 	char ldir[40];
1369a747e4fSDavid du Colombier 	char ds[40];
1379a747e4fSDavid du Colombier 	int actl, lctl, data;
1389a747e4fSDavid du Colombier 
1399a747e4fSDavid du Colombier 	snprint(ds, sizeof ds, "tcp!*!%d", myport);
1409a747e4fSDavid du Colombier 	chatsrv(0);
1419a747e4fSDavid du Colombier 	actl = -1;
1429a747e4fSDavid du Colombier 	for(;;){
1439a747e4fSDavid du Colombier 		if(actl < 0){
1449a747e4fSDavid du Colombier 			actl = announce(ds, adir);
1459a747e4fSDavid du Colombier 			if(actl < 0){
146883a8c51SDavid du Colombier 				clog("%s: listening to tcp port %d\n",
147883a8c51SDavid du Colombier 					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 
172883a8c51SDavid du Colombier 			/* pretend it's udp; fill in Udphdr */
173f27a9a5aSDavid du Colombier 			getendpoints((Udphdr*)buf, ldir);
1749a747e4fSDavid du Colombier 
175883a8c51SDavid du Colombier 			while (servemsg(data, readtcp, writetcp, myport,
176883a8c51SDavid du Colombier 			    progmap) >= 0)
177883a8c51SDavid du Colombier 				continue;
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
servemsg(int fd,long (* readmsg)(int,void *,long),long (* writemsg)(int,void *,long),int myport,Progmap * progmap)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
getendpoint(char * dir,char * file,uchar * addr,uchar * port)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 
331*ea58ad6fSDavid du Colombier /* set Udphdr values from protocol dir local & remote files */
3329a747e4fSDavid du Colombier static void
getendpoints(Udphdr * ep,char * dir)333f27a9a5aSDavid du Colombier getendpoints(Udphdr *ep, char *dir)
3349a747e4fSDavid du Colombier {
3359a747e4fSDavid du Colombier 	getendpoint(dir, "local", ep->laddr, ep->lport);
3369a747e4fSDavid du Colombier 	getendpoint(dir, "remote", ep->raddr, ep->rport);
3379a747e4fSDavid du Colombier }
3389a747e4fSDavid du Colombier 
3399a747e4fSDavid du Colombier static long
readtcp(int fd,void * vbuf,long blen)3409a747e4fSDavid du Colombier readtcp(int fd, void *vbuf, long blen)
3419a747e4fSDavid du Colombier {
3429a747e4fSDavid du Colombier 	uchar mk[4];
3439a747e4fSDavid du Colombier 	int n, m, sofar;
3449a747e4fSDavid du Colombier 	ulong done;
3459a747e4fSDavid du Colombier 	char *buf;
3469a747e4fSDavid du Colombier 
3479a747e4fSDavid du Colombier 	buf = vbuf;
348f27a9a5aSDavid du Colombier 	buf += Udphdrsize;
349f27a9a5aSDavid du Colombier 	blen -= Udphdrsize;
3509a747e4fSDavid du Colombier 
3519a747e4fSDavid du Colombier 	done = 0;
3529a747e4fSDavid du Colombier 	for(sofar = 0; !done; sofar += n){
3539a747e4fSDavid du Colombier 		m = readn(fd, mk, 4);
3549a747e4fSDavid du Colombier 		if(m < 4)
3559a747e4fSDavid du Colombier 			return 0;
3569a747e4fSDavid du Colombier 		done = (mk[0]<<24)|(mk[1]<<16)|(mk[2]<<8)|mk[3];
3579a747e4fSDavid du Colombier 		m = done & 0x7fffffff;
3589a747e4fSDavid du Colombier 		done &= 0x80000000;
3599a747e4fSDavid du Colombier 		if(m > blen-sofar)
3609a747e4fSDavid du Colombier 			return -1;
3619a747e4fSDavid du Colombier 		n = readn(fd, buf+sofar, m);
3629a747e4fSDavid du Colombier 		if(m != n)
3639a747e4fSDavid du Colombier 			return 0;
3649a747e4fSDavid du Colombier 	}
365f27a9a5aSDavid du Colombier 	return sofar + Udphdrsize;
3669a747e4fSDavid du Colombier }
3679a747e4fSDavid du Colombier 
3689a747e4fSDavid du Colombier static long
writetcp(int fd,void * vbuf,long len)3699a747e4fSDavid du Colombier writetcp(int fd, void *vbuf, long len)
3709a747e4fSDavid du Colombier {
3719a747e4fSDavid du Colombier 	char *buf;
3729a747e4fSDavid du Colombier 
3739a747e4fSDavid du Colombier 	buf = vbuf;
374f27a9a5aSDavid du Colombier 	buf += Udphdrsize;
375f27a9a5aSDavid du Colombier 	len -= Udphdrsize;
3769a747e4fSDavid du Colombier 
3779a747e4fSDavid du Colombier 	buf -= 4;
3789a747e4fSDavid du Colombier 	buf[0] = 0x80 | (len>>24);
3799a747e4fSDavid du Colombier 	buf[1] = len>>16;
3809a747e4fSDavid du Colombier 	buf[2] = len>>8;
3819a747e4fSDavid du Colombier 	buf[3] = len;
3829a747e4fSDavid du Colombier 	len += 4;
3839a747e4fSDavid du Colombier 	return write(fd, buf, len);
3849a747e4fSDavid du Colombier }
3859a747e4fSDavid du Colombier /*
3869a747e4fSDavid du Colombier  *long
3879a747e4fSDavid du Colombier  *niwrite(int fd, void *buf, long count)
3889a747e4fSDavid du Colombier  *{
3899a747e4fSDavid du Colombier  *	char errbuf[ERRLEN];
3909a747e4fSDavid du Colombier  *	long n;
3919a747e4fSDavid du Colombier  *
3929a747e4fSDavid du Colombier  *	for(;;){
3939a747e4fSDavid du Colombier  *		n = write(fd, buf, count);
3949a747e4fSDavid du Colombier  *		if(n < 0){
3959a747e4fSDavid du Colombier  *			errstr(errbuf);
3969a747e4fSDavid du Colombier  *			if(strcmp(errbuf, "interrupted") == 0)
3979a747e4fSDavid du Colombier  *				continue;
3989a747e4fSDavid du Colombier  *			clog("niwrite error: %s\n", errbuf);
3999a747e4fSDavid du Colombier  *			werrstr(errbuf);
4009a747e4fSDavid du Colombier  *		}
4019a747e4fSDavid du Colombier  *		break;
4029a747e4fSDavid du Colombier  *	}
4039a747e4fSDavid du Colombier  *	return n;
4049a747e4fSDavid du Colombier  *}
4059a747e4fSDavid du Colombier  */
4069a747e4fSDavid du Colombier long
niwrite(int fd,void * buf,long n)4079a747e4fSDavid du Colombier niwrite(int fd, void *buf, long n)
4089a747e4fSDavid du Colombier {
4096ab4d0ffSDavid du Colombier //	int savalarm;
4109a747e4fSDavid du Colombier 
4116ab4d0ffSDavid du Colombier // 	savalarm = alarm(0);
4129a747e4fSDavid du Colombier 	n = write(fd, buf, n);
4136ab4d0ffSDavid du Colombier // 	if(savalarm > 0)
4146ab4d0ffSDavid du Colombier //		alarm(savalarm);
4159a747e4fSDavid du Colombier 	return n;
4169a747e4fSDavid du Colombier }
4179a747e4fSDavid du Colombier 
4189a747e4fSDavid du Colombier typedef struct Namecache	Namecache;
4199a747e4fSDavid du Colombier struct Namecache {
4209a747e4fSDavid du Colombier 	char dom[256];
4219a747e4fSDavid du Colombier 	ulong ipaddr;
4229a747e4fSDavid du Colombier 	Namecache *next;
4239a747e4fSDavid du Colombier };
4249a747e4fSDavid du Colombier 
4259a747e4fSDavid du Colombier Namecache *dnscache;
4269a747e4fSDavid du Colombier 
4279a747e4fSDavid du Colombier static Namecache*
domlookupl(void * name,int len)4289a747e4fSDavid du Colombier domlookupl(void *name, int len)
4299a747e4fSDavid du Colombier {
4309a747e4fSDavid du Colombier 	Namecache *n, **ln;
4319a747e4fSDavid du Colombier 
4329a747e4fSDavid du Colombier 	if(len >= sizeof(n->dom))
4339a747e4fSDavid du Colombier 		return nil;
4349a747e4fSDavid du Colombier 
4359a747e4fSDavid du Colombier 	for(ln=&dnscache, n=*ln; n; ln=&(*ln)->next, n=*ln) {
4369a747e4fSDavid du Colombier 		if(strncmp(n->dom, name, len) == 0 && n->dom[len] == 0) {
4379a747e4fSDavid du Colombier 			*ln = n->next;
4389a747e4fSDavid du Colombier 			n->next = dnscache;
4399a747e4fSDavid du Colombier 			dnscache = n;
4409a747e4fSDavid du Colombier 			return n;
4419a747e4fSDavid du Colombier 		}
4429a747e4fSDavid du Colombier 	}
4439a747e4fSDavid du Colombier 	return nil;
4449a747e4fSDavid du Colombier }
4459a747e4fSDavid du Colombier 
4469a747e4fSDavid du Colombier static Namecache*
domlookup(void * name)4479a747e4fSDavid du Colombier domlookup(void *name)
4489a747e4fSDavid du Colombier {
4499a747e4fSDavid du Colombier 	return domlookupl(name, strlen(name));
4509a747e4fSDavid du Colombier }
4519a747e4fSDavid du Colombier 
4529a747e4fSDavid du Colombier static Namecache*
iplookup(ulong ip)4539a747e4fSDavid du Colombier iplookup(ulong ip)
4549a747e4fSDavid du Colombier {
4559a747e4fSDavid du Colombier 	Namecache *n, **ln;
4569a747e4fSDavid du Colombier 
4579a747e4fSDavid du Colombier 	for(ln=&dnscache, n=*ln; n; ln=&(*ln)->next, n=*ln) {
4589a747e4fSDavid du Colombier 		if(n->ipaddr == ip) {
4599a747e4fSDavid du Colombier 			*ln = n->next;
4609a747e4fSDavid du Colombier 			n->next = dnscache;
4619a747e4fSDavid du Colombier 			dnscache = n;
4629a747e4fSDavid du Colombier 			return n;
4639a747e4fSDavid du Colombier 		}
4649a747e4fSDavid du Colombier 	}
4659a747e4fSDavid du Colombier 	return nil;
4669a747e4fSDavid du Colombier }
4679a747e4fSDavid du Colombier 
4689a747e4fSDavid du Colombier static Namecache*
addcacheentry(void * name,int len,ulong ip)4699a747e4fSDavid du Colombier addcacheentry(void *name, int len, ulong ip)
4709a747e4fSDavid du Colombier {
4719a747e4fSDavid du Colombier 	Namecache *n;
4729a747e4fSDavid du Colombier 
4739a747e4fSDavid du Colombier 	if(len >= sizeof(n->dom))
4749a747e4fSDavid du Colombier 		return nil;
4759a747e4fSDavid du Colombier 
4769a747e4fSDavid du Colombier 	n = malloc(sizeof(*n));
4779a747e4fSDavid du Colombier 	if(n == nil)
4789a747e4fSDavid du Colombier 		return nil;
4799a747e4fSDavid du Colombier 	strncpy(n->dom, name, len);
4809a747e4fSDavid du Colombier 	n->dom[len] = 0;
4819a747e4fSDavid du Colombier 	n->ipaddr = ip;
4829a747e4fSDavid du Colombier 	n->next = dnscache;
4839a747e4fSDavid du Colombier 	dnscache = n;
4849a747e4fSDavid du Colombier 	return nil;
4859a747e4fSDavid du Colombier }
4869a747e4fSDavid du Colombier 
4879a747e4fSDavid du Colombier int
getdnsdom(ulong ip,char * name,int len)4889a747e4fSDavid du Colombier getdnsdom(ulong ip, char *name, int len)
4899a747e4fSDavid du Colombier {
49057837e0bSDavid du Colombier 	char buf[128];
4919a747e4fSDavid du Colombier 	Namecache *nc;
49257837e0bSDavid du Colombier 	char *p;
4939a747e4fSDavid du Colombier 
4949a747e4fSDavid du Colombier 	if(nc=iplookup(ip)) {
4959a747e4fSDavid du Colombier 		strncpy(name, nc->dom, len);
4969a747e4fSDavid du Colombier 		name[len-1] = 0;
4979a747e4fSDavid du Colombier 		return 0;
4989a747e4fSDavid du Colombier 	}
4999a747e4fSDavid du Colombier 	clog("getdnsdom: %I\n", ip);
5009a747e4fSDavid du Colombier 	snprint(buf, sizeof buf, "%I", ip);
50157837e0bSDavid du Colombier 	p = csgetvalue("/net", "ip", buf, "dom", nil);
50257837e0bSDavid du Colombier 	if(p == nil)
5039a747e4fSDavid du Colombier 		return -1;
50457837e0bSDavid du Colombier 	strncpy(name, p, len-1);
5059a747e4fSDavid du Colombier 	name[len] = 0;
50657837e0bSDavid du Colombier 	free(p);
5079a747e4fSDavid du Colombier 	addcacheentry(name, strlen(name), ip);
5089a747e4fSDavid du Colombier 	return 0;
5099a747e4fSDavid du Colombier }
5109a747e4fSDavid du Colombier 
5119a747e4fSDavid du Colombier int
getdom(ulong ip,char * dom,int len)5129a747e4fSDavid du Colombier getdom(ulong ip, char *dom, int len)
5139a747e4fSDavid du Colombier {
5149a747e4fSDavid du Colombier 	int i;
5159a747e4fSDavid du Colombier 	static char *prefix[] = { "", "gate-", "fddi-", "u-", 0 };
5169a747e4fSDavid du Colombier 	char **pr;
5179a747e4fSDavid du Colombier 
5189a747e4fSDavid du Colombier 	if(getdnsdom(ip, dom, len)<0)
5199a747e4fSDavid du Colombier 		return -1;
5209a747e4fSDavid du Colombier 
5219a747e4fSDavid du Colombier 	for(pr=prefix; *pr; pr++){
5229a747e4fSDavid du Colombier 		i = strlen(*pr);
5239a747e4fSDavid du Colombier 		if(strncmp(dom, *pr, i) == 0) {
5249a747e4fSDavid du Colombier 			memmove(dom, dom+i, len-i);
5259a747e4fSDavid du Colombier 			break;
5269a747e4fSDavid du Colombier 		}
5279a747e4fSDavid du Colombier 	}
5289a747e4fSDavid du Colombier 	return 0;
5299a747e4fSDavid du Colombier }
5309a747e4fSDavid du Colombier 
5319a747e4fSDavid du Colombier #define	MAXCACHE	64
5329a747e4fSDavid du Colombier 
5339a747e4fSDavid du Colombier static Rpccache *head, *tail;
5349a747e4fSDavid du Colombier static int	ncache;
5359a747e4fSDavid du Colombier 
5369a747e4fSDavid du Colombier static void
cachereply(Rpccall * rp,void * buf,int len)5379a747e4fSDavid du Colombier cachereply(Rpccall *rp, void *buf, int len)
5389a747e4fSDavid du Colombier {
5399a747e4fSDavid du Colombier 	Rpccache *cp;
5409a747e4fSDavid du Colombier 
5419a747e4fSDavid du Colombier 	if(nocache)
5429a747e4fSDavid du Colombier 		return;
5439a747e4fSDavid du Colombier 
5449a747e4fSDavid du Colombier 	if(ncache >= MAXCACHE){
5459a747e4fSDavid du Colombier 		if(rpcdebug)
5469a747e4fSDavid du Colombier 			fprint(2, "%s: drop  %I/%ld, xid %uld, len %d\n",
5479a747e4fSDavid du Colombier 				argv0, tail->host,
5489a747e4fSDavid du Colombier 				tail->port, tail->xid, tail->n);
5499a747e4fSDavid du Colombier 		tail = tail->prev;
5509a747e4fSDavid du Colombier 		free(tail->next);
5519a747e4fSDavid du Colombier 		tail->next = 0;
5529a747e4fSDavid du Colombier 		--ncache;
5539a747e4fSDavid du Colombier 	}
5549a747e4fSDavid du Colombier 	cp = malloc(sizeof(Rpccache)+len-4);
5559a747e4fSDavid du Colombier 	if(cp == 0){
5569a747e4fSDavid du Colombier 		clog("cachereply: malloc %d failed\n", len);
5579a747e4fSDavid du Colombier 		return;
5589a747e4fSDavid du Colombier 	}
5599a747e4fSDavid du Colombier 	++ncache;
5609a747e4fSDavid du Colombier 	cp->prev = 0;
5619a747e4fSDavid du Colombier 	cp->next = head;
5629a747e4fSDavid du Colombier 	if(head)
5639a747e4fSDavid du Colombier 		head->prev = cp;
5649a747e4fSDavid du Colombier 	else
5659a747e4fSDavid du Colombier 		tail = cp;
5669a747e4fSDavid du Colombier 	head = cp;
5679a747e4fSDavid du Colombier 	cp->host = rp->host;
5689a747e4fSDavid du Colombier 	cp->port = rp->port;
5699a747e4fSDavid du Colombier 	cp->xid = rp->xid;
5709a747e4fSDavid du Colombier 	cp->n = len;
5719a747e4fSDavid du Colombier 	memmove(cp->data, buf, len);
5729a747e4fSDavid du Colombier 	if(rpcdebug)
5739a747e4fSDavid du Colombier 		fprint(2, "%s: cache %I/%ld, xid %uld, len %d\n",
5749a747e4fSDavid du Colombier 			argv0, cp->host, cp->port, cp->xid, cp->n);
5759a747e4fSDavid du Colombier }
5769a747e4fSDavid du Colombier 
5779a747e4fSDavid du Colombier static int
replycache(int fd,Rpccall * rp,long (* writemsg)(int,void *,long))5789a747e4fSDavid du Colombier replycache(int fd, Rpccall *rp, long (*writemsg)(int, void*, long))
5799a747e4fSDavid du Colombier {
5809a747e4fSDavid du Colombier 	Rpccache *cp;
5819a747e4fSDavid du Colombier 
5829a747e4fSDavid du Colombier 	for(cp=head; cp; cp=cp->next)
5839a747e4fSDavid du Colombier 		if(cp->host == rp->host &&
5849a747e4fSDavid du Colombier 		   cp->port == rp->port &&
5859a747e4fSDavid du Colombier 		   cp->xid == rp->xid)
5869a747e4fSDavid du Colombier 			break;
5879a747e4fSDavid du Colombier 	if(cp == 0)
5889a747e4fSDavid du Colombier 		return 0;
5899a747e4fSDavid du Colombier 	if(cp->prev){	/* move to front */
5909a747e4fSDavid du Colombier 		cp->prev->next = cp->next;
5919a747e4fSDavid du Colombier 		if(cp->next)
5929a747e4fSDavid du Colombier 			cp->next->prev = cp->prev;
5939a747e4fSDavid du Colombier 		else
5949a747e4fSDavid du Colombier 			tail = cp->prev;
5959a747e4fSDavid du Colombier 		cp->prev = 0;
5969a747e4fSDavid du Colombier 		cp->next = head;
5979a747e4fSDavid du Colombier 		head->prev = cp;
5989a747e4fSDavid du Colombier 		head = cp;
5999a747e4fSDavid du Colombier 	}
6009a747e4fSDavid du Colombier 	(*writemsg)(fd, cp->data, cp->n);
6019a747e4fSDavid du Colombier 	if(rpcdebug)
6029a747e4fSDavid du Colombier 		fprint(2, "%s: reply %I/%ld, xid %uld, len %d\n",
6039a747e4fSDavid du Colombier 			argv0, cp->host, cp->port, cp->xid, cp->n);
6049a747e4fSDavid du Colombier 	return 1;
6059a747e4fSDavid du Colombier }
6069a747e4fSDavid du Colombier 
6079a747e4fSDavid du Colombier static int
Iconv(Fmt * f)6089a747e4fSDavid du Colombier Iconv(Fmt *f)
6099a747e4fSDavid du Colombier {
6109a747e4fSDavid du Colombier 	char buf[16];
6119a747e4fSDavid du Colombier 	ulong h;
6129a747e4fSDavid du Colombier 
6139a747e4fSDavid du Colombier 	h = va_arg(f->args, ulong);
6149a747e4fSDavid du Colombier 	snprint(buf, sizeof buf, "%ld.%ld.%ld.%ld",
6159a747e4fSDavid du Colombier 		(h>>24)&0xff, (h>>16)&0xff,
6169a747e4fSDavid du Colombier 		(h>>8)&0xff, h&0xff);
6179a747e4fSDavid du Colombier 	return fmtstrcpy(f, buf);
6189a747e4fSDavid du Colombier }
619