Charles.Forsyth20060303644188019 years agoHistory
1408 lines · 26.6 KB · C
RawDownload
#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"../port/error.h" #include	"ip.h" enum				/* Connection state */{	Ilclosed,	Ilsyncer,	Ilsyncee,	Ilestablished,	Illistening,	Ilclosing,	Ilopening,		/* only for file server */}; char	*ilstates[] = { 	"Closed",	"Syncer",	"Syncee",	"Established",	"Listen",	"Closing",	"Opening",		/* only for file server */}; enum				/* Packet types */{	Ilsync,	Ildata,	Ildataquery,	Ilack,	Ilquery,	Ilstate,	Ilclose,}; char	*iltype[] = {		"sync",	"data",	"dataquery",	"ack",	"query",	"state",	"close" }; enum{	Seconds		= 1000,	Iltickms 	= 50,		/* time base */	AckDelay	= 2*Iltickms,	/* max time twixt message rcvd & ack sent */	MaxTimeout 	= 30*Seconds,	/* max time between rexmit */	QueryTime	= 10*Seconds,	/* time between subsequent queries */	DeathTime	= 30*QueryTime, 	MaxRexmit 	= 16,		/* max retransmissions before hangup */	Defaultwin	= 20, 	LogAGain	= 3,	AGain		= 1<<LogAGain,	LogDGain	= 2,	DGain		= 1<<LogDGain, 	DefByteRate	= 100,		/* assume a megabit link */	DefRtt		= 50,		/* cross country on a great day */ 	Maxrq		= 64*1024,}; enum{	Nqt=	8,}; typedef struct Ilcb Ilcb;struct Ilcb			/* Control block */{	int	state;		/* Connection state */	Conv	*conv;	QLock	ackq;		/* Unacknowledged queue */	Block	*unacked;	Block	*unackedtail;	ulong	unackedbytes;	QLock	outo;		/* Out of order packet queue */	Block	*outoforder;	ulong	next;		/* Id of next to send */	ulong	recvd;		/* Last packet received */	ulong	acksent;	/* Last packet acked */	ulong	start;		/* Local start id */	ulong	rstart;		/* Remote start id */	int	window;		/* Maximum receive window */	int	rxquery;	/* number of queries on this connection */	int	rxtot;		/* number of retransmits on this connection */	int	rexmit;		/* number of retransmits of *unacked */	ulong	qt[Nqt+1];	/* state table for query messages */	int	qtx;		/* ... index into qt */ 	/* if set, fasttimeout causes a connection request to terminate after 4*Iltickms */	int	fasttimeout; 	/* timers */	ulong	lastxmit;	/* time of last xmit */	ulong	lastrecv;	/* time of last recv */	ulong	timeout;	/* retransmission time for *unacked */	ulong	acktime;	/* time to send next ack */	ulong	querytime;	/* time to send next query */ 	/* adaptive measurements */	int	delay;		/* Average of the fixed rtt delay */	int	rate;		/* Average uchar rate */	int	mdev;		/* Mean deviation of rtt */	int	maxrtt;		/* largest rtt seen */	ulong	rttack;		/* The ack we are waiting for */	int	rttlen;		/* Length of rttack packet */	uvlong	rttstart;	/* Time we issued rttack packet */}; enum{	IL_IPSIZE 	= 20,	IL_HDRSIZE	= 18,		IL_LISTEN	= 0,	IL_CONNECT	= 1,	IP_ILPROTO	= 40,}; typedef struct Ilhdr Ilhdr;struct Ilhdr{	uchar	vihl;		/* Version and header length */	uchar	tos;		/* Type of service */	uchar	length[2];	/* packet length */	uchar	id[2];		/* Identification */	uchar	frag[2];	/* Fragment information */	uchar	ttl;		/* Time to live */	uchar	proto;		/* Protocol */	uchar	cksum[2];	/* Header checksum */	uchar	src[4];		/* Ip source */	uchar	dst[4];		/* Ip destination */	uchar	ilsum[2];	/* Checksum including header */	uchar	illen[2];	/* Packet length */	uchar	iltype;		/* Packet type */	uchar	ilspec;		/* Special */	uchar	ilsrc[2];	/* Src port */	uchar	ildst[2];	/* Dst port */	uchar	ilid[4];	/* Sequence id */	uchar	ilack[4];	/* Acked sequence */}; enum{	InMsgs,	OutMsgs,	CsumErrs,		/* checksum errors */	HlenErrs,		/* header length error */	LenErrs,		/* short packet */	OutOfOrder,		/* out of order */	Retrans,		/* retransmissions */	DupMsg,	DupBytes,	DroppedMsgs, 	Nstats,}; static char *statnames[] ={[InMsgs]	"InMsgs",[OutMsgs]	"OutMsgs",[CsumErrs]	"CsumErrs",[HlenErrs]	"HlenErr",[LenErrs]	"LenErrs",[OutOfOrder]	"OutOfOrder",[Retrans]	"Retrans",[DupMsg]	"DupMsg",[DupBytes]	"DupBytes",[DroppedMsgs]	"DroppedMsgs",}; typedef struct Ilpriv Ilpriv;struct Ilpriv{	Ipht	ht; 	ulong	stats[Nstats]; 	ulong	csumerr;		/* checksum errors */	ulong	hlenerr;		/* header length error */	ulong	lenerr;			/* short packet */	ulong	order;			/* out of order */	ulong	rexmit;			/* retransmissions */	ulong	dup;	ulong	dupb; 	/* keeping track of the ack kproc */	int	ackprocstarted;	QLock	apl;}; /* state for query/dataquery messages */  void	ilrcvmsg(Conv*, Block*);void	ilsendctl(Conv*, Ilhdr*, int, ulong, ulong, int);void	ilackq(Ilcb*, Block*);void	ilprocess(Conv*, Ilhdr*, Block*);void	ilpullup(Conv*);void	ilhangup(Conv*, char*);void	ilfreeq(Ilcb*);void	ilrexmit(Ilcb*);void	ilbackoff(Ilcb*);void	ilsettimeout(Ilcb*);char*	ilstart(Conv*, int, int);void	ilackproc(void*);void	iloutoforder(Conv*, Ilhdr*, Block*);void	iliput(Proto*, Ipifc*, Block*);void	iladvise(Proto*, Block*, char*);int	ilnextqt(Ilcb*);void	ilcbinit(Ilcb*);int	later(ulong, ulong, char*);void	ilreject(Fs*, Ilhdr*);void	illocalclose(Conv *c);	int 	ilcksum = 1;static 	int 	initseq = 25001;static	ulong	scalediv, scalemul;static	char	*etime = "connection timed out"; static char*ilconnect(Conv *c, char **argv, int argc){	char *e, *p;	int fast; 	/* huge hack to quickly try an il connection */	fast = 0;	if(argc > 1){		p = strstr(argv[1], "!fasttimeout");		if(p != nil){			*p = 0;			fast = 1;		}	} 	e = Fsstdconnect(c, argv, argc);	if(e != nil)		return e;	return ilstart(c, IL_CONNECT, fast);} static intilstate(Conv *c, char *state, int n){	Ilcb *ic; 	ic = (Ilcb*)(c->ptcl);	return snprint(state, n, "%s qin %d qout %d del %5.5d Br %5.5d md %5.5d una %5.5lud rex %5.5d rxq %5.5d max %5.5d",		ilstates[ic->state],		c->rq ? qlen(c->rq) : 0,		c->wq ? qlen(c->wq) : 0,		ic->delay>>LogAGain, ic->rate>>LogAGain, ic->mdev>>LogDGain,		ic->unackedbytes, ic->rxtot, ic->rxquery, ic->maxrtt);} static intilinuse(Conv *c){	Ilcb *ic; 	ic = (Ilcb*)(c->ptcl);	return ic->state != Ilclosed; } /* called with c locked */static char*ilannounce(Conv *c, char **argv, int argc){	char *e; 	e = Fsstdannounce(c, argv, argc);	if(e != nil)		return e;	e = ilstart(c, IL_LISTEN, 0);	if(e != nil)		return e;	Fsconnected(c, nil); 	return nil;} voidillocalclose(Conv *c){	Ilcb *ic;	Ilpriv *ipriv; 	ipriv = c->p->priv;	ic = (Ilcb*)c->ptcl;	ic->state = Ilclosed;	iphtrem(&ipriv->ht, c);	ipmove(c->laddr, IPnoaddr);	c->lport = 0;} static voidilclose(Conv *c){	Ilcb *ic; 	ic = (Ilcb*)c->ptcl; 	qclose(c->rq);	qclose(c->wq);	qclose(c->eq); 	switch(ic->state) {	case Ilclosing:	case Ilclosed:		break;	case Ilsyncer:	case Ilsyncee:	case Ilestablished:		ic->state = Ilclosing;		ilsettimeout(ic);		ilsendctl(c, nil, Ilclose, ic->next, ic->recvd, 0);		break;	case Illistening:		illocalclose(c);		break;	}	ilfreeq(ic);} voidilkick(void *x, Block *bp){	Conv *c = x;	Ilhdr *ih;	Ilcb *ic;	int dlen;	ulong id, ack;	Fs *f;	Ilpriv *priv; 	f = c->p->f;	priv = c->p->priv;	ic = (Ilcb*)c->ptcl; 	if(bp == nil)		return; 	switch(ic->state) {	case Ilclosed:	case Illistening:	case Ilclosing:		freeblist(bp);		qhangup(c->rq, nil);		return;	} 	dlen = blocklen(bp); 	/* Make space to fit il & ip */	bp = padblock(bp, IL_IPSIZE+IL_HDRSIZE);	ih = (Ilhdr *)(bp->rp);	ih->vihl = IP_VER4; 	/* Ip fields */	ih->frag[0] = 0;	ih->frag[1] = 0;	v6tov4(ih->dst, c->raddr);	v6tov4(ih->src, c->laddr);	ih->proto = IP_ILPROTO; 	/* Il fields */	hnputs(ih->illen, dlen+IL_HDRSIZE);	hnputs(ih->ilsrc, c->lport);	hnputs(ih->ildst, c->rport); 	qlock(&ic->ackq);	id = ic->next++;	hnputl(ih->ilid, id);	ack = ic->recvd;	hnputl(ih->ilack, ack);	ic->acksent = ack;	ic->acktime = NOW + AckDelay;	ih->iltype = Ildata;	ih->ilspec = 0;	ih->ilsum[0] = 0;	ih->ilsum[1] = 0; 	/* Checksum of ilheader plus data (not ip & no pseudo header) */	if(ilcksum)		hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, dlen+IL_HDRSIZE)); 	ilackq(ic, bp);	qunlock(&ic->ackq); 	/* Start the round trip timer for this packet if the timer is free */	if(ic->rttack == 0) {		ic->rttack = id;		ic->rttstart = fastticks(nil);		ic->rttlen = dlen + IL_IPSIZE + IL_HDRSIZE;	} 	if(later(NOW, ic->timeout, nil))		ilsettimeout(ic);	ipoput4(f, bp, 0, c->ttl, c->tos, c);	priv->stats[OutMsgs]++;} static voidilcreate(Conv *c){	c->rq = qopen(Maxrq, 0, 0, c);	c->wq = qbypass(ilkick, c);} intilxstats(Proto *il, char *buf, int len){	Ilpriv *priv;	char *p, *e;	int i; 	priv = il->priv;	p = buf;	e = p+len;	for(i = 0; i < Nstats; i++)		p = seprint(p, e, "%s: %lud\n", statnames[i], priv->stats[i]);	return p - buf;} voidilackq(Ilcb *ic, Block *bp){	Block *np;	int n; 	n = blocklen(bp); 	/* Enqueue a copy on the unacked queue in case this one gets lost */	np = copyblock(bp, n);	if(ic->unacked)		ic->unackedtail->list = np;	else		ic->unacked = np;	ic->unackedtail = np;	np->list = nil;	ic->unackedbytes += n;} staticvoidilrttcalc(Ilcb *ic, Block *bp){	int rtt, tt, pt, delay, rate; 	rtt = fastticks(nil) - ic->rttstart;	rtt = (rtt*scalemul)/scalediv;	delay = ic->delay;	rate = ic->rate; 	/* Guard against zero wrap */	if(rtt > 120000 || rtt < 0)		return; 	/* this block had to be transmitted after the one acked so count its size */	ic->rttlen += blocklen(bp)  + IL_IPSIZE + IL_HDRSIZE; 	if(ic->rttlen < 256){		/* guess fixed delay as rtt of small packets */		delay += rtt - (delay>>LogAGain);		if(delay < AGain)			delay = AGain;		ic->delay = delay;	} else {		/* if packet took longer than avg rtt delay, recalc rate */		tt = rtt - (delay>>LogAGain);		if(tt > 0){			rate += ic->rttlen/tt - (rate>>LogAGain);			if(rate < AGain)				rate = AGain;			ic->rate = rate;		}	} 	/* mdev */	pt = ic->rttlen/(rate>>LogAGain) + (delay>>LogAGain);	ic->mdev += abs(rtt-pt) - (ic->mdev>>LogDGain); 	if(rtt > ic->maxrtt)		ic->maxrtt = rtt;

Lines 1–500 of 1408.