⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 devip.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"../port/error.h"#include	"../ip/ip.h"enum{	Qtopdir=	1,		/* top level directory */	Qtopbase,	Qarp=		Qtopbase,	Qbootp,	Qndb,	Qiproute,	Qipselftab,	Qlog,	Qprotodir,			/* directory for a protocol */	Qprotobase,	Qclone=		Qprotobase,	Qstats,	Qconvdir,			/* directory for a conversation */	Qconvbase,	Qctl=		Qconvbase,	Qdata,	Qerr,	Qlisten,	Qlocal,	Qremote,	Qstatus,	Qsnoop,	Logtype=	5,	Masktype=	(1<<Logtype)-1,	Logconv=	12,	Maskconv=	(1<<Logconv)-1,	Shiftconv=	Logtype,	Logproto=	8,	Maskproto=	(1<<Logproto)-1,	Shiftproto=	Logtype + Logconv,	Nfs=		128,};#define TYPE(x) 	( ((ulong)(x).path) & Masktype )#define CONV(x) 	( (((ulong)(x).path) >> Shiftconv) & Maskconv )#define PROTO(x) 	( (((ulong)(x).path) >> Shiftproto) & Maskproto )#define QID(p, c, y) 	( ((p)<<(Shiftproto)) | ((c)<<Shiftconv) | (y) )static char network[] = "network";QLock	fslock;Fs	*ipfs[Nfs];	/* attached fs's */Queue	*qlog;extern	void nullmediumlink(void);extern	void pktmediumlink(void);	long ndbwrite(Fs *f, char *a, ulong off, int n);static intip3gen(Chan *c, int i, Dir *dp){	Qid q;	Conv *cv;	char *p;	cv = ipfs[c->dev]->p[PROTO(c->qid)]->conv[CONV(c->qid)];	if(cv->owner == nil)		kstrdup(&cv->owner, eve);	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", qlen(cv->rq), cv->owner, cv->perm, dp);		return 1;	case Qerr:		devdir(c, q, "err", qlen(cv->eq), 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 Qsnoop:		if(strcmp(cv->p->name, "ipifc") != 0)			return -1;		devdir(c, q, "snoop", qlen(cv->sq), cv->owner, 0400, dp);		return 1;	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;	case Qstats:		mkqid(&q, QID(PROTO(c->qid), 0, Qstats), 0, QTFILE);		devdir(c, q, "stats", 0, network, 0444, dp);		return 1;	}	return -1;}static intip1gen(Chan *c, int i, Dir *dp){	Qid q;	char *p;	int prot;	int len = 0;	Fs *f;	extern ulong	kerndate;	f = ipfs[c->dev];	prot = 0666;	mkqid(&q, QID(0, 0, i), 0, QTFILE);	switch(i) {	default:		return -1;	case Qarp:		p = "arp";		prot = 0664;		break;	case Qbootp:		p = "bootp";		break;	case Qndb:		p = "ndb";		len = strlen(f->ndb);		q.vers = f->ndbvers;		break;	case Qiproute:		p = "iproute";		prot = 0664;		break;	case Qipselftab:		p = "ipselftab";		prot = 0444;		break;	case Qlog:		p = "log";		break;	}	devdir(c, q, p, len, network, prot, dp);	if(i == Qndb && f->ndbmtime > kerndate)		dp->mtime = f->ndbmtime;	return 1;}static intipgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp){	Qid q;	Conv *cv;	Fs *f;	f = ipfs[c->dev];	switch(TYPE(c->qid)) {	case Qtopdir:		if(s == DEVDOTDOT){			mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);			sprint(up->genbuf, "#I%lud", c->dev);			devdir(c, q, up->genbuf, 0, network, 0555, dp);			return 1;		}		if(s < f->np) {			if(f->p[s]->connect == nil)				return 0;	/* protocol with no user interface */			mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);			devdir(c, q, f->p[s]->name, 0, network, 0555, dp);			return 1;		}		s -= f->np;		return ip1gen(c, s+Qtopbase, dp);	case Qarp:	case Qbootp:	case Qndb:	case Qlog:	case Qiproute:	case Qipselftab:		return ip1gen(c, TYPE(c->qid), dp);	case Qprotodir:		if(s == DEVDOTDOT){			mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);			sprint(up->genbuf, "#I%lud", c->dev);			devdir(c, q, up->genbuf, 0, network, 0555, dp);			return 1;		}		if(s < f->p[PROTO(c->qid)]->ac) {			cv = f->p[PROTO(c->qid)]->conv[s];			sprint(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 -= f->p[PROTO(c->qid)]->ac;		return ip2gen(c, s+Qprotobase, dp);	case Qclone:	case Qstats:		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, f->p[s]->name, 0, network, 0555, dp);			return 1;		}		return ip3gen(c, s+Qconvbase, dp);	case Qctl:	case Qdata:	case Qerr:	case Qlisten:	case Qlocal:	case Qremote:	case Qstatus:	case Qsnoop:		return ip3gen(c, TYPE(c->qid), dp);	}	return -1;}static voidipreset(void){	nullmediumlink();	pktmediumlink();	fmtinstall('i', eipfmt);	fmtinstall('I', eipfmt);	fmtinstall('E', eipfmt);	fmtinstall('V', eipfmt);	fmtinstall('M', eipfmt);}static Fs*ipgetfs(int dev){	extern void (*ipprotoinit[])(Fs*);	Fs *f;	int i;	if(dev >= Nfs)		return nil;	qlock(&fslock);	if(ipfs[dev] == nil){		f = smalloc(sizeof(Fs));		ip_init(f);		arpinit(f);		netloginit(f);		for(i = 0; ipprotoinit[i]; i++)			ipprotoinit[i](f);		f->dev = dev;		ipfs[dev] = f;	}	qunlock(&fslock);	return ipfs[dev];}IPaux*newipaux(char *owner, char *tag){	IPaux *a;	int n;	a = smalloc(sizeof(*a));	kstrdup(&a->owner, owner);	memset(a->tag, ' ', sizeof(a->tag));	n = strlen(tag);	if(n > sizeof(a->tag))		n = sizeof(a->tag);	memmove(a->tag, tag, n);	return a;}#define ATTACHER(c) (((IPaux*)((c)->aux))->owner)static Chan*ipattach(char* spec){	Chan *c;	int dev;	dev = atoi(spec);	if(dev >= Nfs)		error("bad specification");	ipgetfs(dev);	c = devattach('I', spec);	mkqid(&c->qid, QID(0, 0, Qtopdir), 0, QTDIR);	c->dev = dev;	c->aux = newipaux(commonuser(), "none");	return c;}static Walkqid*ipwalk(Chan* c, Chan *nc, char **name, int nname){	IPaux *a = c->aux;	Walkqid* w;	w = devwalk(c, nc, name, nname, nil, 0, ipgen);	if(w != nil && w->clone != nil)		w->clone->aux = newipaux(a->owner, a->tag);	return w;}static intipstat(Chan* c, uchar* db, int n){	return devstat(c, db, n, nil, 0, ipgen);}static intincoming(void* arg){	Conv *conv;	conv = arg;	return conv->incall != nil;}static int m2p[] = {	[OREAD]		4,	[OWRITE]	2,	[ORDWR]		6};static Chan*ipopen(Chan* c, int omode){	Conv *cv, *nc;	Proto *p;	int perm;	Fs *f;	perm = m2p[omode&3];	f = ipfs[c->dev];	switch(TYPE(c->qid)) {	default:		break;	case Qndb:		if(omode & (OWRITE|OTRUNC) && !iseve())			error(Eperm);		if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC))			f->ndb[0] = 0;		break;	case Qlog:		netlogopen(f);		break;	case Qiproute:	case Qarp:		if(omode != OREAD && !iseve())			error(Eperm);		break;	case Qtopdir:	case Qprotodir:	case Qconvdir:	case Qstatus:	case Qremote:	case Qlocal:	case Qstats:	case Qbootp:	case Qipselftab:		if(omode != OREAD)			error(Eperm);		break;	case Qsnoop:		if(omode != OREAD)			error(Eperm);		p = f->p[PROTO(c->qid)];		cv = p->conv[CONV(c->qid)];		if(strcmp(ATTACHER(c), cv->owner) != 0 && !iseve())			error(Eperm);		incref(&cv->snoopers);		break;	case Qclone:		p = f->p[PROTO(c->qid)];		qlock(p);		if(waserror()){			qunlock(p);			nexterror();		}		cv = Fsprotoclone(p, ATTACHER(c));		qunlock(p);		poperror();		if(cv == nil) {			error(Enodev);			break;		}		mkqid(&c->qid, QID(p->x, cv->x, Qctl), 0, QTFILE);		break;	case Qdata:	case Qctl:	case Qerr:		p = f->p[PROTO(c->qid)];		qlock(p);		cv = p->conv[CONV(c->qid)];		qlock(cv);		if(waserror()) {			qunlock(cv);			qunlock(p);			nexterror();		}		if((perm & (cv->perm>>6)) != perm) {			if(strcmp(ATTACHER(c), cv->owner) != 0)				error(Eperm);		 	if((perm & cv->perm) != perm)				error(Eperm);		}		cv->inuse++;		if(cv->inuse == 1){			kstrdup(&cv->owner, ATTACHER(c));			cv->perm = 0660;		}		qunlock(cv);		qunlock(p);		poperror();		break;	case Qlisten:		cv = f->p[PROTO(c->qid)]->conv[CONV(c->qid)];		if((perm & (cv->perm>>6)) != perm) {			if(strcmp(ATTACHER(c), cv->owner) != 0)				error(Eperm);		 	if((perm & cv->perm) != perm)				error(Eperm);		}		if(cv->state != Announced)			error("not announced");		if(waserror()){			closeconv(cv);			nexterror();		}		qlock(cv);		cv->inuse++;		qunlock(cv);		nc = nil;		while(nc == nil) {			/* give up if we got a hangup */			if(qisclosed(cv->rq))				error("listen hungup");			qlock(&cv->listenq);			if(waserror()) {				qunlock(&cv->listenq);				nexterror();			}			/* wait for a connect */			sleep(&cv->listenr, incoming, cv);			qlock(cv);			nc = cv->incall;			if(nc != nil){				cv->incall = nc->next;				mkqid(&c->qid, QID(PROTO(c->qid), nc->x, Qctl), 0, QTFILE);				kstrdup(&cv->owner, ATTACHER(c));			}			qunlock(cv);			qunlock(&cv->listenq);			poperror();		}		closeconv(cv);		poperror();		break;	}	c->mode = openmode(omode);	c->flag |= COPEN;	c->offset = 0;	return c;}static voidipcreate(Chan*, char*, int, ulong){	error(Eperm);}static voidipremove(Chan*){	error(Eperm);}static intipwstat(Chan *c, uchar *dp, int n){	Dir d;	Conv *cv;	Fs *f;	Proto *p;	f = ipfs[c->dev];	switch(TYPE(c->qid)) {	default:		error(Eperm);		break;	case Qctl:	case Qdata:		break;	}	n = convM2D(dp, n, &d, nil);	if(n > 0){		p = f->p[PROTO(c->qid)];		cv = p->conv[CONV(c->qid)];		if(!iseve() && strcmp(ATTACHER(c), cv->owner) != 0)			error(Eperm);		if(d.uid[0])			kstrdup(&cv->owner, d.uid);		cv->perm = d.mode & 0777;	}	return n;}voidcloseconv(Conv *cv){	Conv *nc;	Ipmulti *mp;	qlock(cv);	if(--cv->inuse > 0) {		qunlock(cv);		return;	}	/* close all incoming calls since no listen will ever happen */	for(nc = cv->incall; nc; nc = cv->incall){		cv->incall = nc->next;		closeconv(nc);	}	cv->incall = nil;	kstrdup(&cv->owner, network);	cv->perm = 0660;	while((mp = cv->multi) != nil)		ipifcremmulti(cv, mp->ma, mp->ia);	cv->r = nil;	cv->rgen = 0;	cv->p->close(cv);	cv->state = Idle;	qunlock(cv);}static voidipclose(Chan* c){	Fs *f;	f = ipfs[c->dev];	switch(TYPE(c->qid)) {	default:		break;	case Qlog:		if(c->flag & COPEN)			netlogclose(f);		break;	case Qdata:	case Qctl:	case Qerr:		if(c->flag & COPEN)			closeconv(f->p[PROTO(c->qid)]->conv[CONV(c->qid)]);		break;	case Qsnoop:		if(c->flag & COPEN)			decref(&f->p[PROTO(c->qid)]->conv[CONV(c->qid)]->snoopers);		break;	}	free(((IPaux*)c->aux)->owner);	free(c->aux);}enum{	Statelen=	32*1024,};static longipread(Chan *ch, void *a, long n, vlong off){	Conv *c;	Proto *x;	char *buf, *p;	long rv;	Fs *f;	ulong offset = off;	f = ipfs[ch->dev];	p = a;	switch(TYPE(ch->qid)) {	default:		error(Eperm);	case Qtopdir:	case Qprotodir:	case Qconvdir:		return devdirread(ch, a, n, 0, 0, ipgen);	case Qarp:		return arpread(f->arp, a, offset, n); 	case Qbootp: 		return bootpread(a, offset, n); 	case Qndb:		return readstr(offset, a, n, f->ndb);	case Qiproute:		return routeread(f, a, offset, n);	case Qipselftab:		return ipselftabread(f, a, offset, n);	case Qlog:		return netlogread(f, a, offset, n);	case Qctl:		buf = smalloc(16);		sprint(buf, "%lud", CONV(ch->qid));		rv = readstr(offset, p, n, buf);		free(buf);		return rv;	case Qremote:		buf = smalloc(Statelen);		x = f->p[PROTO(ch->qid)];		c = x->conv[CONV(ch->qid)];		if(x->remote == nil) {			sprint(buf, "%I!%d\n", c->raddr, c->rport);		} else {			(*x->remote)(c, buf, Statelen-2);		}		rv = readstr(offset, p, n, buf);		free(buf);		return rv;	case Qlocal:		buf = smalloc(Statelen);		x = f->p[PROTO(ch->qid)];		c = x->conv[CONV(ch->qid)];		if(x->local == nil) {			sprint(buf, "%I!%d\n", c->laddr, c->lport);		} else {			(*x->local)(c, buf, Statelen-2);		}		rv = readstr(offset, p, n, buf);		free(buf);		return rv;	case Qstatus:		buf = smalloc(Statelen);		x = f->p[PROTO(ch->qid)];		c = x->conv[CONV(ch->qid)];		(*x->state)(c, buf, Statelen-2);		rv = readstr(offset, p, n, buf);		free(buf);		return rv;	case Qdata:		c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];		return qread(c->rq, a, n);	case Qerr:		c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];		return qread(c->eq, a, n);	case Qsnoop:		c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];		return qread(c->sq, a, n);	case Qstats:		x = f->p[PROTO(ch->qid)];		if(x->stats == nil)			error("stats not implemented");		buf = smalloc(Statelen);		(*x->stats)(x, buf, Statelen);		rv = readstr(offset, p, n, buf);		free(buf);		return rv;	}}static Block*

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -