618 lines · 11.1 KB · C
RawDownload
#include "all.h"#include <ndb.h> static int	alarmflag; static int	Iconv(Fmt*);static void	openudp(int);static void	cachereply(Rpccall*, void*, int);static int	replycache(int, Rpccall*, long (*)(int, void*, long));static void	udpserver(int, Progmap*);static void	tcpserver(int, Progmap*);static void	getendpoints(Udphdr*, char*);static long	readtcp(int, void*, long);static long	writetcp(int, void*, long);static int	servemsg(int, long (*)(int, void*, long), long (*)(int, void*, long),		int, Progmap*);void	(*rpcalarm)(void);int	rpcdebug;int	rejectall;int	p9debug; int	nocache; uchar	buf[9000];uchar	rbuf[9000];uchar	resultbuf[9000]; static int tcp; char *commonopts = "[-9CDrtv]";			/* for usage() messages */ /* * this recognises common, nominally rcp-related options. * they may not take arguments. */intargopt(int c){	switch(c){	case '9':		++p9debug;		return 0;	case 'C':		++nocache;		return 0;	case 'D':		++rpcdebug;		return 0;	case 'r':		++rejectall;		return 0;	case 't':		tcp = 1;		return 0;	case 'v':		++chatty;		return 0;	default:		return -1;	}} /* * all option parsing is now done in (*pg->init)(), which can call back * here to argopt for common options. */voidserver(int argc, char **argv, int myport, Progmap *progmap){	Progmap *pg; 	fmtinstall('I', Iconv);	fmtinstall('F', fcallfmt);	fmtinstall('D', dirfmt); 	switch(rfork(RFNOWAIT|RFENVG|RFNAMEG|RFNOTEG|RFFDG|RFPROC)){	case -1:		panic("fork");	default:		_exits(0);	case 0:		break;	} 	switch(rfork(RFMEM|RFPROC)){	case 0:		for(;;){			sleep(30*1000);			alarmflag = 1;		}	case -1:		sysfatal("rfork: %r");	} 	for(pg=progmap; pg->init; pg++)		(*pg->init)(argc, argv);	if(tcp)		tcpserver(myport, progmap);	else		udpserver(myport, progmap);} static voidudpserver(int myport, Progmap *progmap){	char service[128];	char data[128];	char devdir[40];	int ctlfd, datafd; 	snprint(service, sizeof service, "udp!*!%d", myport);	ctlfd = announce(service, devdir);	if(ctlfd < 0)		panic("can't announce %s: %r\n", service);	if(fprint(ctlfd, "headers") < 0)		panic("can't set header mode: %r\n"); 	snprint(data, sizeof data, "%s/data", devdir);	datafd = open(data, ORDWR);	if(datafd < 0)		panic("can't open udp data: %r\n");	close(ctlfd); 	chatsrv(0);	clog("%s: listening to port %d\n", argv0, myport);	while (servemsg(datafd, read, write, myport, progmap) >= 0)		continue;	exits(0);} static voidtcpserver(int myport, Progmap *progmap){	char adir[40];	char ldir[40];	char ds[40];	int actl, lctl, data; 	snprint(ds, sizeof ds, "tcp!*!%d", myport);	chatsrv(0);	actl = -1;	for(;;){		if(actl < 0){			actl = announce(ds, adir);			if(actl < 0){				clog("%s: listening to tcp port %d\n",					argv0, myport);				clog("announcing: %r");				break;			}		}		lctl = listen(adir, ldir);		if(lctl < 0){			close(actl);			actl = -1;			continue;		}		switch(fork()){		case -1:			clog("%s!%d: %r\n", argv0, myport);			/* fall through */		default:			close(lctl);			continue;		case 0:			close(actl);			data = accept(lctl, ldir);			close(lctl);			if(data < 0)				exits(0); 			/* pretend it's udp; fill in Udphdr */			getendpoints((Udphdr*)buf, ldir); 			while (servemsg(data, readtcp, writetcp, myport,			    progmap) >= 0)				continue;			close(data);			exits(0);		}	}	exits(0);} static intservemsg(int fd, long (*readmsg)(int, void*, long), long (*writemsg)(int, void*, long),		int myport, Progmap * progmap){	int i, n, nreply;	Rpccall rcall, rreply;	int vlo, vhi;	Progmap *pg;	Procmap *pp;	char errbuf[ERRMAX]; 	if(alarmflag){		alarmflag = 0;		if(rpcalarm)			(*rpcalarm)();	}	n = (*readmsg)(fd, buf, sizeof buf);	if(n < 0){		errstr(errbuf, sizeof errbuf);		if(strcmp(errbuf, "interrupted") == 0)			return 0;		clog("port %d: error: %s\n", myport, errbuf);		return -1;	}	if(n == 0){		clog("port %d: EOF\n", myport);		return -1;	}	if(rpcdebug == 1)		fprint(2, "%s: rpc from %d.%d.%d.%d/%d\n",			argv0, buf[12], buf[13], buf[14], buf[15],			(buf[32]<<8)|buf[33]);	i = rpcM2S(buf, &rcall, n);	if(i != 0){		clog("udp port %d: message format error %d\n",			myport, i);		return 0;	}	if(rpcdebug > 1)		rpcprint(2, &rcall);	if(rcall.mtype != CALL)		return 0;	if(replycache(fd, &rcall, writemsg))		return 0;	nreply = 0;	rreply.host = rcall.host;	rreply.port = rcall.port;	rreply.lhost = rcall.lhost;	rreply.lport = rcall.lport;	rreply.xid = rcall.xid;	rreply.mtype = REPLY;	if(rcall.rpcvers != 2){		rreply.stat = MSG_DENIED;		rreply.rstat = RPC_MISMATCH;		rreply.rlow = 2;		rreply.rhigh = 2;		goto send_reply;	}	if(rejectall){		rreply.stat = MSG_DENIED;		rreply.rstat = AUTH_ERROR;		rreply.authstat = AUTH_TOOWEAK;		goto send_reply;	}	i = n - (((uchar *)rcall.args) - buf);	if(rpcdebug > 1)		fprint(2, "arg size = %d\n", i);	rreply.stat = MSG_ACCEPTED;	rreply.averf.flavor = 0;	rreply.averf.count = 0;	rreply.results = resultbuf;	vlo = 0x7fffffff;	vhi = -1;	for(pg=progmap; pg->pmap; pg++){		if(pg->progno != rcall.prog)			continue;		if(pg->vers == rcall.vers)			break;		if(pg->vers < vlo)			vlo = pg->vers;		if(pg->vers > vhi)			vhi = pg->vers;	}	if(pg->pmap == 0){		if(vhi < 0)			rreply.astat = PROG_UNAVAIL;		else{			rreply.astat = PROG_MISMATCH;			rreply.plow = vlo;			rreply.phigh = vhi;		}		goto send_reply;	}	for(pp = pg->pmap; pp->procp; pp++)		if(rcall.proc == pp->procno){			if(rpcdebug > 1)				fprint(2, "process %d\n", pp->procno);			rreply.astat = SUCCESS;			nreply = (*pp->procp)(i, &rcall, &rreply);			goto send_reply;		}	rreply.astat = PROC_UNAVAIL;send_reply:	if(nreply >= 0){		i = rpcS2M(&rreply, nreply, rbuf);		if(rpcdebug > 1)			rpcprint(2, &rreply);		(*writemsg)(fd, rbuf, i);		cachereply(&rreply, rbuf, i);	}	return 0;} static voidgetendpoint(char *dir, char *file, uchar *addr, uchar *port){	int fd, n;	char buf[128];	char *sys, *serv; 	sys = serv = 0; 	snprint(buf, sizeof buf, "%s/%s", dir, file);	fd = open(buf, OREAD);	if(fd >= 0){		n = read(fd, buf, sizeof(buf)-1);		if(n>0){			buf[n-1] = 0;			serv = strchr(buf, '!');			if(serv){				*serv++ = 0;				serv = strdup(serv);			}			sys = strdup(buf);		}		close(fd);	}	if(serv == 0)		serv = strdup("unknown");	if(sys == 0)		sys = strdup("unknown");	parseip(addr, sys);	n = atoi(serv);	hnputs(port, n);} /* set Udphdr values from protocol dir local & remote files */static voidgetendpoints(Udphdr *ep, char *dir){	getendpoint(dir, "local", ep->laddr, ep->lport);	getendpoint(dir, "remote", ep->raddr, ep->rport);} static longreadtcp(int fd, void *vbuf, long blen){	uchar mk[4];	int n, m, sofar;	ulong done;	char *buf; 	buf = vbuf;	buf += Udphdrsize;	blen -= Udphdrsize; 	done = 0;	for(sofar = 0; !done; sofar += n){		m = readn(fd, mk, 4);		if(m < 4)			return 0;		done = (mk[0]<<24)|(mk[1]<<16)|(mk[2]<<8)|mk[3];		m = done & 0x7fffffff;		done &= 0x80000000;		if(m > blen-sofar)			return -1;		n = readn(fd, buf+sofar, m);		if(m != n)			return 0;	}	return sofar + Udphdrsize;} static longwritetcp(int fd, void *vbuf, long len){	char *buf; 	buf = vbuf;	buf += Udphdrsize;	len -= Udphdrsize; 	buf -= 4;	buf[0] = 0x80 | (len>>24);	buf[1] = len>>16;	buf[2] = len>>8;	buf[3] = len;	len += 4;	return write(fd, buf, len);}/* *long *niwrite(int fd, void *buf, long count) *{ *	char errbuf[ERRLEN]; *	long n; * *	for(;;){ *		n = write(fd, buf, count); *		if(n < 0){ *			errstr(errbuf); *			if(strcmp(errbuf, "interrupted") == 0) *				continue; *			clog("niwrite error: %s\n", errbuf); *			werrstr(errbuf); *		} *		break; *	} *	return n; *} */longniwrite(int fd, void *buf, long n){//	int savalarm; // 	savalarm = alarm(0);	n = write(fd, buf, n);// 	if(savalarm > 0)//		alarm(savalarm);	return n;} typedef struct Namecache	Namecache;struct Namecache {	char dom[256];	ulong ipaddr;	Namecache *next;}; Namecache *dnscache; static Namecache*domlookupl(void *name, int len){	Namecache *n, **ln; 	if(len >= sizeof(n->dom))		return nil; 	for(ln=&dnscache, n=*ln; n; ln=&(*ln)->next, n=*ln) {		if(strncmp(n->dom, name, len) == 0 && n->dom[len] == 0) {			*ln = n->next;			n->next = dnscache;			dnscache = n;			return n;		}	}	return nil;} static Namecache*domlookup(void *name){	return domlookupl(name, strlen(name));} static Namecache*iplookup(ulong ip){	Namecache *n, **ln; 	for(ln=&dnscache, n=*ln; n; ln=&(*ln)->next, n=*ln) {		if(n->ipaddr == ip) {			*ln = n->next;			n->next = dnscache;			dnscache = n;			return n;		}	}	return nil;} static Namecache*addcacheentry(void *name, int len, ulong ip){	Namecache *n; 	if(len >= sizeof(n->dom))		return nil; 	n = malloc(sizeof(*n));	if(n == nil)		return nil;	strncpy(n->dom, name, len);	n->dom[len] = 0;	n->ipaddr = ip;	n->next = dnscache;	dnscache = n;	return nil;} intgetdnsdom(ulong ip, char *name, int len){	char buf[128];	Namecache *nc;	char *p; 	if(nc=iplookup(ip)) {		strncpy(name, nc->dom, len);		name[len-1] = 0;		return 0;	}	clog("getdnsdom: %I\n", ip);	snprint(buf, sizeof buf, "%I", ip);

Lines 1–500 of 618.