870 lines · 14.4 KB · C
RawDownload
#include "u.h"#include "lib.h"#include "dat.h"#include "fns.h"#include "error.h"#include "ip.h" #include "devip.h" void	csclose(Chan*);long	csread(Chan*, void*, long, vlong);long	cswrite(Chan*, void*, long, vlong); void osipinit(void); enum{	Qtopdir		= 1,	/* top level directory */	Qtopbase,	Qcs		= Qtopbase, 	Qprotodir,		/* directory for a protocol */	Qprotobase,	Qclone		= Qprotobase, 	Qconvdir,		/* directory for a conversation */	Qconvbase,	Qctl		= Qconvbase,	Qdata,	Qstatus,	Qremote,	Qlocal,	Qlisten, 	MAXPROTO	= 4};#define TYPE(x) 	((int)((x).path & 0xf))#define CONV(x) 	((int)(((x).path >> 4)&0xfff))#define PROTO(x) 	((int)(((x).path >> 16)&0xff))#define QID(p, c, y) 	(((p)<<16) | ((c)<<4) | (y))#define ipzero(x)	memset(x, 0, IPaddrlen) typedef struct Proto	Proto;typedef struct Conv	Conv;struct Conv{	int	x;	Ref	r;	int	sfd;	int	perm;	char	owner[KNAMELEN];	char*	state;	uchar	laddr[IPaddrlen];	ushort	lport;	uchar	raddr[IPaddrlen];	ushort	rport;	int	restricted;	char	cerr[KNAMELEN];	Proto*	p;}; struct Proto{	Lock	l;	int	x;	int	stype;	char	name[KNAMELEN];	int	nc;	int	maxconv;	Conv**	conv;	Qid	qid;}; static	int	np;static	Proto	proto[MAXPROTO]; static	Conv*	protoclone(Proto*, char*, int);static	void	setladdr(Conv*); static char	network[] = "network"; static intip3gen(Chan *c, int i, Dir *dp){	Qid q;	Conv *cv;	char *p; 	cv = proto[PROTO(c->qid)].conv[CONV(c->qid)];	mkqid(&q, QID(PROTO(c->qid), CONV(c->qid), i), 0, QTFILE); 	switch(i) {	default:		return -1;	case Qctl:		devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp);		return 1;	case Qdata:		devdir(c, q, "data", 0, cv->owner, cv->perm, dp);		return 1;	case Qlisten:		devdir(c, q, "listen", 0, cv->owner, cv->perm, dp);		return 1;	case Qlocal:		p = "local";		break;	case Qremote:		p = "remote";		break;	case Qstatus:		p = "status";		break;	}	devdir(c, q, p, 0, cv->owner, 0444, dp);	return 1;} static intip2gen(Chan *c, int i, Dir *dp){	Qid q; 	switch(i) {	case Qclone:		mkqid(&q, QID(PROTO(c->qid), 0, Qclone), 0, QTFILE);		devdir(c, q, "clone", 0, network, 0666, dp);		return 1;	}	return -1;} static intip1gen(Chan *c, int i, Dir *dp){	Qid q;	char *p;	int prot;	int len = 0; 	prot = 0666;	mkqid(&q, QID(0, 0, i), 0, QTFILE);	switch(i) {	default:		return -1;	case Qcs:		p = "cs";		prot = 0664;		break;	}	devdir(c, q, p, len, network, prot, dp);	return 1;} static intipgen(Chan *c, char *nname, Dirtab *d, int nd, int s, Dir *dp){	Qid q;	Conv *cv; 	switch(TYPE(c->qid)) {	case Qtopdir:		if(s == DEVDOTDOT){			mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);			snprint(up->genbuf, sizeof up->genbuf, "#I%lud", c->dev);			devdir(c, q, up->genbuf, 0, network, 0555, dp);			return 1;		}		if(s < np) {			mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);			devdir(c, q, proto[s].name, 0, network, 0555, dp);			return 1;		}		s -= np;		return ip1gen(c, s+Qtopbase, dp);	case Qcs:		return ip1gen(c, TYPE(c->qid), dp);	case Qprotodir:		if(s == DEVDOTDOT){			mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);			snprint(up->genbuf, sizeof up->genbuf, "#I%lud", c->dev);			devdir(c, q, up->genbuf, 0, network, 0555, dp);			return 1;		}		if(s < proto[PROTO(c->qid)].nc) {			cv = proto[PROTO(c->qid)].conv[s];			snprint(up->genbuf, sizeof up->genbuf, "%d", s);			mkqid(&q, QID(PROTO(c->qid), s, Qconvdir), 0, QTDIR);			devdir(c, q, up->genbuf, 0, cv->owner, 0555, dp);			return 1;		}		s -= proto[PROTO(c->qid)].nc;		return ip2gen(c, s+Qprotobase, dp);	case Qclone:		return ip2gen(c, TYPE(c->qid), dp);	case Qconvdir:		if(s == DEVDOTDOT){			s = PROTO(c->qid);			mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);			devdir(c, q, proto[s].name, 0, network, 0555, dp);			return 1;		}		return ip3gen(c, s+Qconvbase, dp);	case Qctl:	case Qdata:	case Qlisten:	case Qlocal:	case Qremote:	case Qstatus:		return ip3gen(c, TYPE(c->qid), dp);	}	return -1;} static voidnewproto(char *name, int type, int maxconv){	int l;	Proto *p; 	if(np >= MAXPROTO) {		print("no %s: increase MAXPROTO", name);		return;	} 	p = &proto[np];	strcpy(p->name, name);	p->stype = type;	p->qid.path = QID(np, 0, Qprotodir);	p->qid.type = QTDIR;	p->x = np++;	p->maxconv = maxconv;	l = sizeof(Conv*)*(p->maxconv+1);	p->conv = mallocz(l, 1);	if(p->conv == 0)		panic("no memory");} voidipinit(void){	osipinit(); 	newproto("udp", S_UDP, 10);	newproto("tcp", S_TCP, 30); 	fmtinstall('I', eipfmt);	fmtinstall('E', eipfmt);	} Chan *ipattach(char *spec){	Chan *c; 	c = devattach('I', spec);	c->qid.path = QID(0, 0, Qtopdir);	c->qid.type = QTDIR;	c->qid.vers = 0;	return c;} static Walkqid*ipwalk(Chan *c, Chan *nc, char **name, int nname){	return devwalk(c, nc, name, nname, 0, 0, ipgen);} intipstat(Chan *c, uchar *dp, int n){	return devstat(c, dp, n, 0, 0, ipgen);} Chan *ipopen(Chan *c, int omode){	Proto *p;	uchar raddr[IPaddrlen];	ushort rport;	int perm, sfd;	Conv *cv, *lcv; 	omode &= 3;	perm = 0;	switch(omode) {	case OREAD:		perm = 4;		break;	case OWRITE:		perm = 2;		break;	case ORDWR:		perm = 6;		break;	} 	switch(TYPE(c->qid)) {	default:		break;	case Qtopdir:	case Qprotodir:	case Qconvdir:	case Qstatus:	case Qremote:	case Qlocal:		if(omode != OREAD)			error(Eperm);		break;	case Qclone:		p = &proto[PROTO(c->qid)];		cv = protoclone(p, up->user, -1);		if(cv == 0)			error(Enodev);		c->qid.path = QID(p->x, cv->x, Qctl);		c->qid.vers = 0;		break;	case Qdata:	case Qctl:		p = &proto[PROTO(c->qid)];		lock(&p->l);		cv = p->conv[CONV(c->qid)];		lock(&cv->r.lk);		if((perm & (cv->perm>>6)) != perm) {			if(strcmp(up->user, cv->owner) != 0 ||		 	  (perm & cv->perm) != perm) {				unlock(&cv->r.lk);				unlock(&p->l);				error(Eperm);			}		}		cv->r.ref++;		if(cv->r.ref == 1) {			memmove(cv->owner, up->user, KNAMELEN);			cv->perm = 0660;		}		unlock(&cv->r.lk);		unlock(&p->l);		break;	case Qlisten:		p = &proto[PROTO(c->qid)];		lcv = p->conv[CONV(c->qid)];		sfd = so_accept(lcv->sfd, raddr, &rport);		cv = protoclone(p, up->user, sfd);		if(cv == 0) {			close(sfd);			error(Enodev);		}		ipmove(cv->raddr, raddr);		cv->rport = rport;		setladdr(cv);		cv->state = "Established";		c->qid.path = QID(p->x, cv->x, Qctl);		break;	}	c->mode = openmode(omode);	c->flag |= COPEN;	c->offset = 0;	return c;} voidipclose(Chan *c){	Conv *cc; 	switch(TYPE(c->qid)) {	case Qcs:		csclose(c);		break;	case Qdata:	case Qctl:		if((c->flag & COPEN) == 0)			break;		cc = proto[PROTO(c->qid)].conv[CONV(c->qid)];		if(decref(&cc->r) != 0)			break;		strcpy(cc->owner, network);		cc->perm = 0666;		cc->state = "Closed";		ipzero(cc->laddr);		ipzero(cc->raddr);		cc->lport = 0;		cc->rport = 0;		close(cc->sfd);		break;	}} longipread(Chan *ch, void *a, long n, vlong offset){	int r;	Conv *c;	Proto *x;	uchar ip[IPaddrlen];	char buf[128], *p; /*print("ipread %s %lux\n", chanpath(ch), (long)ch->qid.path);*/	p = a;	switch(TYPE(ch->qid)) {	default:		error(Eperm);	case Qcs:		return csread(ch, a, n, offset);	case Qprotodir:	case Qtopdir:	case Qconvdir:		return devdirread(ch, a, n, 0, 0, ipgen);	case Qctl:		sprint(buf, "%d", CONV(ch->qid));		return readstr(offset, p, n, buf);	case Qremote:		c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];		ipmove(ip, c->raddr);		sprint(buf, "%I!%d\n", ip, c->rport);		return readstr(offset, p, n, buf);	case Qlocal:		c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];		ipmove(ip, c->laddr);		sprint(buf, "%I!%d\n", ip, c->lport);		return readstr(offset, p, n, buf);	case Qstatus:		x = &proto[PROTO(ch->qid)];		c = x->conv[CONV(ch->qid)];		sprint(buf, "%s/%d %d %s \n",			c->p->name, c->x, c->r.ref, c->state);		return readstr(offset, p, n, buf);	case Qdata:		c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];		r = so_recv(c->sfd, a, n, 0);		if(r < 0){			oserrstr();			nexterror();		}		return r;	}} static voidsetladdr(Conv *c){	so_getsockname(c->sfd, c->laddr, &c->lport);} static voidsetlport(Conv *c){	if(c->restricted == 0 && c->lport == 0)		return; 	if(c->sfd == -1)		c->sfd = so_socket(c->p->stype, c->laddr); 	so_bind(c->sfd, c->restricted, c->lport, c->laddr);} static voidsetladdrport(Conv *c, char *str){	char *p;	uchar addr[IPaddrlen]; 	p = strchr(str, '!');	if(p == 0) {		p = str;		ipzero(c->laddr);	}	else {		*p++ = 0;		parseip(addr, str);		ipmove(c->laddr, addr);	}	if(*p == '*')		c->lport = 0;	else		c->lport = atoi(p); 	setlport(c);} static char*setraddrport(Conv *c, char *str){	char *p;	uchar addr[IPaddrlen]; 	p = strchr(str, '!');	if(p == 0)		return "malformed address";	*p++ = 0;	parseip(addr, str);	ipmove(c->raddr, addr);	c->rport = atoi(p);	p = strchr(p, '!');	if(p) {		if(strcmp(p, "!r") == 0)			c->restricted = 1;	}	return 0;

Lines 1–500 of 870.