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

📄 tcp.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 5 页
字号:
		switch(version){		case V4:			tcb->protohdr.tcp4hdr.vihl = IP_VER4;			hbp = htontcp4(&seg, bp, &tcb->protohdr.tcp4hdr, tcb);			if(hbp == nil) {				freeblist(bp);				return;			}			break;		case V6:			tcb->protohdr.tcp6hdr.vcf[0] = IP_VER6;			hbp = htontcp6(&seg, bp, &tcb->protohdr.tcp6hdr, tcb);			if(hbp == nil) {				freeblist(bp);				return;			}			break;		default:			hbp = nil;	/* to suppress a warning */			panic("tcpoutput: version %d", version);		}		/* Start the transmission timers if there is new data and we		 * expect acknowledges		 */		if(ssize != 0){			if(tcb->timer.state != TcptimerON)				tcpgo(tpriv, &tcb->timer);			/*  If round trip timer isn't running, start it.			 *  measure the longest packet only in case the			 *  transmission time dominates RTT			 */			if(tcb->rtt_timer.state != TcptimerON)			if(ssize == tcb->mss) {				tcpgo(tpriv, &tcb->rtt_timer);				tcb->rttseq = tcb->snd.ptr;			}		}		tpriv->stats[OutSegs]++;		/* put off the next keep alive */		tcpgo(tpriv, &tcb->katimer);		switch(version){		case V4:			if(ipoput4(f, hbp, 0, s->ttl, s->tos, s) < 0){				/* a negative return means no route */				localclose(s, "no route");			}			break;		case V6:			if(ipoput6(f, hbp, 0, s->ttl, s->tos, s) < 0){				/* a negative return means no route */				localclose(s, "no route");			}			break;		default:			panic("tcpoutput2: version %d", version);		}		if((msgs%4) == 1){			qunlock(s);			sched();			qlock(s);		}	}}/* *  the BSD convention (hack?) for keep alives.  resend last uchar acked. */voidtcpsendka(Conv *s){	Tcp seg;	Tcpctl *tcb;	Block *hbp,*dbp;	tcb = (Tcpctl*)s->ptcl;	dbp = nil;	seg.urg = 0;	seg.source = s->lport;	seg.dest = s->rport;	seg.flags = ACK|PSH;	seg.mss = 0;	seg.ws = 0;	if(tcpporthogdefense)		seg.seq = tcb->snd.una-(1<<30)-nrand(1<<20);	else		seg.seq = tcb->snd.una-1;	seg.ack = tcb->rcv.nxt;	tcb->rcv.una = 0;	seg.wnd = tcb->rcv.wnd;	if(tcb->state == Finwait2){		seg.flags |= FIN;	} else {		dbp = allocb(1);		dbp->wp++;	}	if(isv4(s->raddr)) {		/* Build header, link data and compute cksum */		tcb->protohdr.tcp4hdr.vihl = IP_VER4;		hbp = htontcp4(&seg, dbp, &tcb->protohdr.tcp4hdr, tcb);		if(hbp == nil) {			freeblist(dbp);			return;		}		ipoput4(s->p->f, hbp, 0, s->ttl, s->tos, s);	}	else {		/* Build header, link data and compute cksum */		tcb->protohdr.tcp6hdr.vcf[0] = IP_VER6;		hbp = htontcp6(&seg, dbp, &tcb->protohdr.tcp6hdr, tcb);		if(hbp == nil) {			freeblist(dbp);			return;		}		ipoput6(s->p->f, hbp, 0, s->ttl, s->tos, s);	}}/* *  set connection to time out after 12 minutes */voidtcpsetkacounter(Tcpctl *tcb){	tcb->kacounter = (12 * 60 * 1000) / (tcb->katimer.start*MSPTICK);	if(tcb->kacounter < 3)		tcb->kacounter = 3;}/* *  if we've timed out, close the connection *  otherwise, send a keepalive and restart the timer */voidtcpkeepalive(void *v){	Tcpctl *tcb;	Conv *s;	s = v;	tcb = (Tcpctl*)s->ptcl;	if(waserror()){		qunlock(s);		nexterror();	}	qlock(s);	if(tcb->state != Closed){		if(--(tcb->kacounter) <= 0) {			localclose(s, Etimedout);		} else {			tcpsendka(s);			tcpgo(s->p->priv, &tcb->katimer);		}	}	qunlock(s);	poperror();}/* *  start keepalive timer */char*tcpstartka(Conv *s, char **f, int n){	Tcpctl *tcb;	int x;	tcb = (Tcpctl*)s->ptcl;	if(tcb->state != Established)		return "connection must be in Establised state";	if(n > 1){		x = atoi(f[1]);		if(x >= MSPTICK)			tcb->katimer.start = x/MSPTICK;	}	tcpsetkacounter(tcb);	tcpgo(s->p->priv, &tcb->katimer);	return nil;}/* *  turn checksums on/off */char*tcpsetchecksum(Conv *s, char **f, int){	Tcpctl *tcb;	tcb = (Tcpctl*)s->ptcl;	tcb->nochecksum = !atoi(f[1]);	return nil;}voidtcprxmit(Conv *s){	Tcpctl *tcb;	tcb = (Tcpctl*)s->ptcl;	tcb->flags |= RETRAN|FORCE;	tcb->snd.ptr = tcb->snd.una;	/*	 *  We should be halving the slow start threshhold (down to one	 *  mss) but leaving it at mss seems to work well enough	 */ 	tcb->ssthresh = tcb->mss;	/*	 *  pull window down to a single packet	 */	tcb->cwind = tcb->mss;	tcpoutput(s);}voidtcptimeout(void *arg){	Conv *s;	Tcpctl *tcb;	int maxback;	Tcppriv *tpriv;	s = (Conv*)arg;	tpriv = s->p->priv;	tcb = (Tcpctl*)s->ptcl;	if(waserror()){		qunlock(s);		nexterror();	}	qlock(s);	switch(tcb->state){	default:		tcb->backoff++;		if(tcb->state == Syn_sent)			maxback = MAXBACKMS/2;		else			maxback = MAXBACKMS;		tcb->backedoff += tcb->timer.start * MSPTICK;		if(tcb->backedoff >= maxback) {			localclose(s, Etimedout);			break;		}		netlog(s->p->f, Logtcprxmt, "timeout rexmit 0x%lux %d/%d\n", tcb->snd.una, tcb->timer.start, NOW);		tcpsettimer(tcb);		tcprxmit(s);		tpriv->stats[RetransTimeouts]++;		tcb->snd.dupacks = 0;		break;	case Time_wait:		localclose(s, nil);		break;	case Closed:		break;	}	qunlock(s);	poperror();}intinwindow(Tcpctl *tcb, int seq){	return seq_within(seq, tcb->rcv.nxt, tcb->rcv.nxt+tcb->rcv.wnd-1);}/* *  set up state for a received SYN (or SYN ACK) packet */voidprocsyn(Conv *s, Tcp *seg){	Tcpctl *tcb;	tcb = (Tcpctl*)s->ptcl;	tcb->flags |= FORCE;	tcb->rcv.nxt = seg->seq + 1;	tcb->rcv.urg = tcb->rcv.nxt;	tcb->irs = seg->seq;	/* our sending max segment size cannot be bigger than what he asked for */	if(seg->mss != 0 && seg->mss < tcb->mss)		tcb->mss = seg->mss;	/* the congestion window always starts out as a single segment */	tcb->snd.wnd = seg->wnd;	tcb->cwind = tcb->mss;}intaddreseq(Tcpctl *tcb, Tcppriv *tpriv, Tcp *seg, Block *bp, ushort length){	Reseq *rp, *rp1;	int i, rqlen;	static int once;	rp = malloc(sizeof(Reseq));	if(rp == nil){		freeblist(bp);	/* bp always consumed by add_reseq */		return 0;	}	rp->seg = *seg;	rp->bp = bp;	rp->length = length;	/* Place on reassembly list sorting by starting seq number */	rp1 = tcb->reseq;	if(rp1 == nil || seq_lt(seg->seq, rp1->seg.seq)) {		rp->next = rp1;		tcb->reseq = rp;		if(rp->next != nil)			tpriv->stats[OutOfOrder]++;		return 0;	}	rqlen = 0;	for(i = 0;; i++) {		rqlen += rp1->length;		if(rp1->next == nil || seq_lt(seg->seq, rp1->next->seg.seq)) {			rp->next = rp1->next;			rp1->next = rp;			if(rp->next != nil)				tpriv->stats[OutOfOrder]++;			break;		}		rp1 = rp1->next;	}	if(rqlen > QMAX && once++ == 0){		print("very long tcp resequence queue: %d\n", rqlen);		for(rp1 = tcb->reseq, i = 0; i < 10 && rp1 != nil; rp1 = rp1->next, i++)			print("0x%lux 0x%lux 0x%ux\n", rp1->seg.seq, rp1->seg.ack,				rp1->seg.flags);		return -1;	}	return 0;}voidgetreseq(Tcpctl *tcb, Tcp *seg, Block **bp, ushort *length){	Reseq *rp;	rp = tcb->reseq;	if(rp == nil)		return;	tcb->reseq = rp->next;	*seg = rp->seg;	*bp = rp->bp;	*length = rp->length;	free(rp);}inttcptrim(Tcpctl *tcb, Tcp *seg, Block **bp, ushort *length){	ushort len;	uchar accept;	int dupcnt, excess;	accept = 0;	len = *length;	if(seg->flags & SYN)		len++;	if(seg->flags & FIN)		len++;	if(tcb->rcv.wnd == 0) {		if(len == 0 && seg->seq == tcb->rcv.nxt)			return 0;	}	else {		/* Some part of the segment should be in the window */		if(inwindow(tcb,seg->seq))			accept++;		else		if(len != 0) {			if(inwindow(tcb, seg->seq+len-1) ||			seq_within(tcb->rcv.nxt, seg->seq,seg->seq+len-1))				accept++;		}	}	if(!accept) {		freeblist(*bp);		return -1;	}	dupcnt = tcb->rcv.nxt - seg->seq;	if(dupcnt > 0){		tcb->rerecv += dupcnt;		if(seg->flags & SYN){			seg->flags &= ~SYN;			seg->seq++;			if(seg->urg > 1)				seg->urg--;			else				seg->flags &= ~URG;			dupcnt--;		}		if(dupcnt > 0){			pullblock(bp, (ushort)dupcnt);			seg->seq += dupcnt;			*length -= dupcnt;			if(seg->urg > dupcnt)				seg->urg -= dupcnt;			else {				seg->flags &= ~URG;				seg->urg = 0;			}		}	}	excess = seg->seq + *length - (tcb->rcv.nxt + tcb->rcv.wnd);	if(excess > 0) {		tcb->rerecv += excess;		*length -= excess;		*bp = trimblock(*bp, 0, *length);		if(*bp == nil)			panic("presotto is a boofhead");		seg->flags &= ~FIN;	}	return 0;}voidtcpadvise(Proto *tcp, Block *bp, char *msg){	Tcp4hdr *h4;	Tcp6hdr *h6;	Tcpctl *tcb;	uchar source[IPaddrlen];	uchar dest[IPaddrlen];	ushort psource, pdest;	Conv *s, **p;	h4 = (Tcp4hdr*)(bp->rp);	h6 = (Tcp6hdr*)(bp->rp);	if((h4->vihl&0xF0)==IP_VER4) {		v4tov6(dest, h4->tcpdst);		v4tov6(source, h4->tcpsrc);		psource = nhgets(h4->tcpsport);		pdest = nhgets(h4->tcpdport);	}	else {		ipmove(dest, h6->tcpdst);		ipmove(source, h6->tcpsrc);		psource = nhgets(h6->tcpsport);		pdest = nhgets(h6->tcpdport);	}	/* Look for a connection */	qlock(tcp);	for(p = tcp->conv; *p; p++) {		s = *p;		tcb = (Tcpctl*)s->ptcl;		if(s->rport == pdest)		if(s->lport == psource)		if(tcb->state != Closed)		if(ipcmp(s->raddr, dest) == 0)		if(ipcmp(s->laddr, source) == 0){			qlock(s);			qunlock(tcp);			switch(tcb->state){			case Syn_sent:				localclose(s, msg);				break;			}			qunlock(s);			freeblist(bp);			return;		}	}	qunlock(tcp);	freeblist(bp);}static char*tcpporthogdefensectl(char *val){	if(strcmp(val, "on") == 0)		tcpporthogdefense = 1;	else if(strcmp(val, "off") == 0)		tcpporthogdefense = 0;	else		return "unknown value for tcpporthogdefense";	return nil;}/* called with c qlocked */char*tcpctl(Conv* c, char** f, int n){	if(n == 1 && strcmp(f[0], "hangup") == 0)		return tcphangup(c);	if(n >= 1 && strcmp(f[0], "keepalive") == 0)		return tcpstartka(c, f, n);	if(n >= 1 && strcmp(f[0], "checksum") == 0)		return tcpsetchecksum(c, f, n);	if(n >= 1 && strcmp(f[0], "tcpporthogdefense") == 0)		return tcpporthogdefensectl(f[1]);	return "unknown control request";}inttcpstats(Proto *tcp, char *buf, int len){	Tcppriv *priv;	char *p, *e;	int i;	priv = tcp->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;}/* *  garbage collect any stale conversations: *	- SYN received but no SYN-ACK after 5 seconds (could be the SYN attack) *	- Finwait2 after 5 minutes * *  this is called whenever we run out of channels.  Both checks are *  of questionable validity so we try to use them only when we're *  up against the wall. */inttcpgc(Proto *tcp){	Conv *c, **pp, **ep;	int n;	Tcpctl *tcb;	n = 0;	ep = &tcp->conv[tcp->nc];	for(pp = tcp->conv; pp < ep; pp++) {		c = *pp;		if(c == nil)			break;		if(!canqlock(c))			continue;		tcb = (Tcpctl*)c->ptcl;		switch(tcb->state){		case Syn_received:			if(NOW - tcb->time > 5000){				localclose(c, "timed out");				n++;			}			break;		case Finwait2:			if(NOW - tcb->time > 5*60*1000){				localclose(c, "timed out");				n++;			}			break;		}		qunlock(c);	}	return n;}voidtcpsettimer(Tcpctl *tcb){	int x;	/* round trip dependency */	x = backoff(tcb->backoff) *		(tcb->mdev + (tcb->srtt>>LOGAGAIN) + MSPTICK) / MSPTICK;	/* bounded twixt 1/2 and 64 seconds */	if(x < 500/MSPTICK)		x = 500/MSPTICK;	else if(x > (64000/MSPTICK))		x = 64000/MSPTICK;	tcb->timer.start = x;}voidtcpinit(Fs *fs){	Proto *tcp;	Tcppriv *tpriv;	tcp = smalloc(sizeof(Proto));	tpriv = tcp->priv = smalloc(sizeof(Tcppriv));	tcp->name = "tcp";	tcp->connect = tcpconnect;	tcp->announce = tcpannounce;	tcp->ctl = tcpctl;	tcp->state = tcpstate;	tcp->create = tcpcreate;	tcp->close = tcpclose;	tcp->rcv = tcpiput;	tcp->advise = tcpadvise;	tcp->stats = tcpstats;	tcp->inuse = tcpinuse;	tcp->gc = tcpgc;	tcp->ipproto = IP_TCPPROTO;	tcp->nc = scalednconv();	tcp->ptclsize = sizeof(Tcpctl);	tpriv->stats[MaxConn] = tcp->nc;	Fsproto(fs, tcp);}voidtcpsetscale(Conv *s, Tcpctl *tcb, ushort rcvscale, ushort sndscale){	if(rcvscale){		tcb->rcv.scale = rcvscale & 0xff;		tcb->snd.scale = sndscale & 0xff;		tcb->window = QMAX<<tcb->snd.scale;		qsetlimit(s->rq, tcb->window);	} else {		tcb->rcv.scale = 0;		tcb->snd.scale = 0;		tcb->window 

⌨️ 快捷键说明

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