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

📄 tcp.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 5 页
字号:
}voidtcpackproc(void *a){	Tcptimer *t, *tp, *timeo;	Proto *tcp;	Tcppriv *priv;	int loop;	tcp = a;	priv = tcp->priv;	for(;;) {		tsleep(&up->sleep, return0, 0, MSPTICK);		qlock(&priv->tl);		timeo = nil;		loop = 0;		for(t = priv->timers; t != nil; t = tp) {			if(loop++ > 10000)				panic("tcpackproc1");			tp = t->next; 			if(t->state == TcptimerON) {				t->count--;				if(t->count == 0) {					timerstate(priv, t, TcptimerDONE);					t->readynext = timeo;					timeo = t;				}			}		}		qunlock(&priv->tl);		loop = 0;		for(t = timeo; t != nil; t = t->readynext) {			if(loop++ > 10000)				panic("tcpackproc2");			if(t->state == TcptimerDONE && t->func != nil && !waserror()){				(*t->func)(t->arg);				poperror();			}		}		limborexmit(tcp);	}}voidtcpgo(Tcppriv *priv, Tcptimer *t){	if(t == nil || t->start == 0)		return;	qlock(&priv->tl);	t->count = t->start;	timerstate(priv, t, TcptimerON);	qunlock(&priv->tl);}voidtcphalt(Tcppriv *priv, Tcptimer *t){	if(t == nil)		return;	qlock(&priv->tl);	timerstate(priv, t, TcptimerOFF);	qunlock(&priv->tl);}intbackoff(int n){	return 1 << n;}voidlocalclose(Conv *s, char *reason)	/* called with tcb locked */{	Tcpctl *tcb;	Reseq *rp,*rp1;	Tcppriv *tpriv;	tpriv = s->p->priv;	tcb = (Tcpctl*)s->ptcl;	iphtrem(&tpriv->ht, s);	tcphalt(tpriv, &tcb->timer);	tcphalt(tpriv, &tcb->rtt_timer);	tcphalt(tpriv, &tcb->acktimer);	tcphalt(tpriv, &tcb->katimer);	/* Flush reassembly queue; nothing more can arrive */	for(rp = tcb->reseq; rp != nil; rp = rp1) {		rp1 = rp->next;		freeblist(rp->bp);		free(rp);	}	tcb->reseq = nil;	if(tcb->state == Syn_sent)		Fsconnected(s, reason);	if(s->state == Announced)		wakeup(&s->listenr);	qhangup(s->rq, reason);	qhangup(s->wq, reason);	tcpsetstate(s, Closed);}/* mtu (- TCP + IP hdr len) of 1st hop */inttcpmtu(Proto *tcp, uchar *addr, int version, int *scale){	Ipifc *ifc;	int mtu;	ifc = findipifc(tcp->f, addr, 0);	switch(version){	default:	case V4:		mtu = DEF_MSS;		if(ifc != nil)			mtu = ifc->maxtu - ifc->m->hsize - (TCP4_PKT + TCP4_HDRSIZE);		break;	case V6:		mtu = DEF_MSS6;		if(ifc != nil)			mtu = ifc->maxtu - ifc->m->hsize - (TCP6_PKT + TCP6_HDRSIZE);		break;	}	if(ifc != nil){		if(ifc->mbps > 100)			*scale = HaveWS | 3;		else if(ifc->mbps > 10)			*scale = HaveWS | 1;		else			*scale = HaveWS | 0;	} else		*scale = HaveWS | 0;	return mtu;}voidinittcpctl(Conv *s, int mode){	Tcpctl *tcb;	Tcp4hdr* h4;	Tcp6hdr* h6;	int mss;	tcb = (Tcpctl*)s->ptcl;	memset(tcb, 0, sizeof(Tcpctl));	tcb->ssthresh = 65535;	tcb->srtt = tcp_irtt<<LOGAGAIN;	tcb->mdev = 0;	/* setup timers */	tcb->timer.start = tcp_irtt / MSPTICK;	tcb->timer.func = tcptimeout;	tcb->timer.arg = s;	tcb->rtt_timer.start = MAX_TIME;	tcb->acktimer.start = TCP_ACK / MSPTICK;	tcb->acktimer.func = tcpacktimer;	tcb->acktimer.arg = s;	tcb->katimer.start = DEF_KAT / MSPTICK;	tcb->katimer.func = tcpkeepalive;	tcb->katimer.arg = s;	mss = DEF_MSS;	/* create a prototype(pseudo) header */	if(mode != TCP_LISTEN){		if(ipcmp(s->laddr, IPnoaddr) == 0)			findlocalip(s->p->f, s->laddr, s->raddr);		switch(s->ipversion){		case V4:			h4 = &tcb->protohdr.tcp4hdr;			memset(h4, 0, sizeof(*h4));			h4->proto = IP_TCPPROTO;			hnputs(h4->tcpsport, s->lport);			hnputs(h4->tcpdport, s->rport);			v6tov4(h4->tcpsrc, s->laddr);			v6tov4(h4->tcpdst, s->raddr);			break;		case V6:			h6 = &tcb->protohdr.tcp6hdr;			memset(h6, 0, sizeof(*h6));			h6->proto = IP_TCPPROTO;			hnputs(h6->tcpsport, s->lport);			hnputs(h6->tcpdport, s->rport);			ipmove(h6->tcpsrc, s->laddr);			ipmove(h6->tcpdst, s->raddr);			mss = DEF_MSS6;			break;		default:			panic("inittcpctl: version %d", s->ipversion);		}	}	tcb->mss = tcb->cwind = mss;	/* default is no window scaling */	tcb->window = QMAX;	tcb->rcv.wnd = QMAX;	tcb->rcv.scale = 0;	tcb->snd.scale = 0;	qsetlimit(s->rq, QMAX);}/* *  called with s qlocked */voidtcpstart(Conv *s, int mode){	Tcpctl *tcb;	Tcppriv *tpriv;	char kpname[KNAMELEN];	tpriv = s->p->priv;	if(tpriv->ackprocstarted == 0){		qlock(&tpriv->apl);		if(tpriv->ackprocstarted == 0){			sprint(kpname, "#I%dtcpack", s->p->f->dev);			kproc(kpname, tcpackproc, s->p);			tpriv->ackprocstarted = 1;		}		qunlock(&tpriv->apl);	}	tcb = (Tcpctl*)s->ptcl;	inittcpctl(s, mode);	iphtadd(&tpriv->ht, s);	switch(mode) {	case TCP_LISTEN:		tpriv->stats[PassiveOpens]++;		tcb->flags |= CLONE;		tcpsetstate(s, Listen);		break;	case TCP_CONNECT:		tpriv->stats[ActiveOpens]++;		tcb->flags |= ACTIVE;		tcpsndsyn(s, tcb);		tcpsetstate(s, Syn_sent);		tcpoutput(s);		break;	}}static char*tcpflag(ushort flag){	static char buf[128];	sprint(buf, "%d", flag>>10);	/* Head len */	if(flag & URG)		strcat(buf, " URG");	if(flag & ACK)		strcat(buf, " ACK");	if(flag & PSH)		strcat(buf, " PSH");	if(flag & RST)		strcat(buf, " RST");	if(flag & SYN)		strcat(buf, " SYN");	if(flag & FIN)		strcat(buf, " FIN");	return buf;}Block *htontcp6(Tcp *tcph, Block *data, Tcp6hdr *ph, Tcpctl *tcb){	int dlen;	Tcp6hdr *h;	ushort csum;	ushort hdrlen, optpad = 0;	uchar *opt;	hdrlen = TCP6_HDRSIZE;	if(tcph->flags & SYN){		if(tcph->mss)			hdrlen += MSS_LENGTH;		if(tcph->ws)			hdrlen += WS_LENGTH;		optpad = hdrlen & 3;		if(optpad)			optpad = 4 - optpad;		hdrlen += optpad;	}	if(data) {		dlen = blocklen(data);		data = padblock(data, hdrlen + TCP6_PKT);		if(data == nil)			return nil;	}	else {		dlen = 0;		data = allocb(hdrlen + TCP6_PKT + 64);	/* the 64 pad is to meet mintu's */		if(data == nil)			return nil;		data->wp += hdrlen + TCP6_PKT;	}	/* copy in pseudo ip header plus port numbers */	h = (Tcp6hdr *)(data->rp);	memmove(h, ph, TCP6_TCBPHDRSZ);	/* compose pseudo tcp header, do cksum calculation */	hnputl(h->vcf, hdrlen + dlen);	h->ploadlen[0] = h->ploadlen[1] = h->proto = 0;	h->ttl = ph->proto;	/* copy in variable bits */	hnputl(h->tcpseq, tcph->seq);	hnputl(h->tcpack, tcph->ack);	hnputs(h->tcpflag, (hdrlen<<10) | tcph->flags);	hnputs(h->tcpwin, tcph->wnd>>(tcb != nil ? tcb->snd.scale : 0));	hnputs(h->tcpurg, tcph->urg);	if(tcph->flags & SYN){		opt = h->tcpopt;		if(tcph->mss != 0){			*opt++ = MSSOPT;			*opt++ = MSS_LENGTH;			hnputs(opt, tcph->mss);			opt += 2;		}		if(tcph->ws != 0){			*opt++ = WSOPT;			*opt++ = WS_LENGTH;			*opt++ = tcph->ws;		}		while(optpad-- > 0)			*opt++ = NOOPOPT;	}	if(tcb != nil && tcb->nochecksum){		h->tcpcksum[0] = h->tcpcksum[1] = 0;	} else {		csum = ptclcsum(data, TCP6_IPLEN, hdrlen+dlen+TCP6_PHDRSIZE);		hnputs(h->tcpcksum, csum);	}	/* move from pseudo header back to normal ip header */	memset(h->vcf, 0, 4);	h->vcf[0] = IP_VER6;	hnputs(h->ploadlen, hdrlen+dlen);	h->proto = ph->proto;	return data;}Block *htontcp4(Tcp *tcph, Block *data, Tcp4hdr *ph, Tcpctl *tcb){	int dlen;	Tcp4hdr *h;	ushort csum;	ushort hdrlen, optpad = 0;	uchar *opt;	hdrlen = TCP4_HDRSIZE;	if(tcph->flags & SYN){		if(tcph->mss)			hdrlen += MSS_LENGTH;		if(tcph->ws)			hdrlen += WS_LENGTH;		optpad = hdrlen & 3;		if(optpad)			optpad = 4 - optpad;		hdrlen += optpad;	}	if(data) {		dlen = blocklen(data);		data = padblock(data, hdrlen + TCP4_PKT);		if(data == nil)			return nil;	}	else {		dlen = 0;		data = allocb(hdrlen + TCP4_PKT + 64);	/* the 64 pad is to meet mintu's */		if(data == nil)			return nil;		data->wp += hdrlen + TCP4_PKT;	}	/* copy in pseudo ip header plus port numbers */	h = (Tcp4hdr *)(data->rp);	memmove(h, ph, TCP4_TCBPHDRSZ);	/* copy in variable bits */	hnputs(h->tcplen, hdrlen + dlen);	hnputl(h->tcpseq, tcph->seq);	hnputl(h->tcpack, tcph->ack);	hnputs(h->tcpflag, (hdrlen<<10) | tcph->flags);	hnputs(h->tcpwin, tcph->wnd>>(tcb != nil ? tcb->snd.scale : 0));	hnputs(h->tcpurg, tcph->urg);	if(tcph->flags & SYN){		opt = h->tcpopt;		if(tcph->mss != 0){			*opt++ = MSSOPT;			*opt++ = MSS_LENGTH;			hnputs(opt, tcph->mss);			opt += 2;		}		if(tcph->ws != 0){			*opt++ = WSOPT;			*opt++ = WS_LENGTH;			*opt++ = tcph->ws;		}		while(optpad-- > 0)			*opt++ = NOOPOPT;	}	if(tcb != nil && tcb->nochecksum){		h->tcpcksum[0] = h->tcpcksum[1] = 0;	} else {		csum = ptclcsum(data, TCP4_IPLEN, hdrlen+dlen+TCP4_PHDRSIZE);		hnputs(h->tcpcksum, csum);	}	return data;}intntohtcp6(Tcp *tcph, Block **bpp){	Tcp6hdr *h;	uchar *optr;	ushort hdrlen;	ushort optlen;	int n;	*bpp = pullupblock(*bpp, TCP6_PKT+TCP6_HDRSIZE);	if(*bpp == nil)		return -1;	h = (Tcp6hdr *)((*bpp)->rp);	tcph->source = nhgets(h->tcpsport);	tcph->dest = nhgets(h->tcpdport);	tcph->seq = nhgetl(h->tcpseq);	tcph->ack = nhgetl(h->tcpack);	hdrlen = (h->tcpflag[0]>>2) & ~3;	if(hdrlen < TCP6_HDRSIZE) {		freeblist(*bpp);		return -1;	}	tcph->flags = h->tcpflag[1];	tcph->wnd = nhgets(h->tcpwin);	tcph->urg = nhgets(h->tcpurg);	tcph->mss = 0;	tcph->ws = 0;	tcph->len = nhgets(h->ploadlen) - hdrlen;	*bpp = pullupblock(*bpp, hdrlen+TCP6_PKT);	if(*bpp == nil)		return -1;	optr = h->tcpopt;	n = hdrlen - TCP6_HDRSIZE;	while(n > 0 && *optr != EOLOPT) {		if(*optr == NOOPOPT) {			n--;			optr++;			continue;		}		optlen = optr[1];		if(optlen < 2 || optlen > n)			break;		switch(*optr) {		case MSSOPT:			if(optlen == MSS_LENGTH)				tcph->mss = nhgets(optr+2);			break;		case WSOPT:			if(optlen == WS_LENGTH && *(optr+2) <= 14)				tcph->ws = HaveWS | *(optr+2);			break;		}		n -= optlen;		optr += optlen;	}	return hdrlen;}intntohtcp4(Tcp *tcph, Block **bpp){	Tcp4hdr *h;	uchar *optr;	ushort hdrlen;	ushort optlen;	int n;	*bpp = pullupblock(*bpp, TCP4_PKT+TCP4_HDRSIZE);	if(*bpp == nil)		return -1;	h = (Tcp4hdr *)((*bpp)->rp);	tcph->source = nhgets(h->tcpsport);	tcph->dest = nhgets(h->tcpdport);	tcph->seq = nhgetl(h->tcpseq);	tcph->ack = nhgetl(h->tcpack);	hdrlen = (h->tcpflag[0]>>2) & ~3;	if(hdrlen < TCP4_HDRSIZE) {		freeblist(*bpp);		return -1;	}	tcph->flags = h->tcpflag[1];	tcph->wnd = nhgets(h->tcpwin);	tcph->urg = nhgets(h->tcpurg);	tcph->mss = 0;	tcph->ws = 0;	tcph->len = nhgets(h->length) - (hdrlen + TCP4_PKT);	*bpp = pullupblock(*bpp, hdrlen+TCP4_PKT);	if(*bpp == nil)		return -1;	optr = h->tcpopt;	n = hdrlen - TCP4_HDRSIZE;	while(n > 0 && *optr != EOLOPT) {		if(*optr == NOOPOPT) {			n--;			optr++;			continue;		}		optlen = optr[1];		if(optlen < 2 || optlen > n)			break;		switch(*optr) {		case MSSOPT:			if(optlen == MSS_LENGTH)				tcph->mss = nhgets(optr+2);			break;		case WSOPT:			if(optlen == WS_LENGTH && *(optr+2) <= 14)				tcph->ws = HaveWS | *(optr+2);			break;		}		n -= optlen;		optr += optlen;	}	return hdrlen;}/* *  For outgiing calls, generate an initial sequence *  number and put a SYN on the send queue */voidtcpsndsyn(Conv *s, Tcpctl *tcb){	tcb->iss = (nrand(1<<16)<<16)|nrand(1<<16);	tcb->rttseq = tcb->iss;	tcb->snd.wl2 = tcb->iss;	tcb->snd.una = tcb->iss;	tcb->snd.ptr = tcb->rttseq;	tcb->snd.nxt = tcb->rttseq;	tcb->flgcnt++;	tcb->flags |= FORCE;	tcb->sndsyntime = NOW;	/* set desired mss and scale */	tcb->mss = tcpmtu(s->p, s->laddr, s->ipversion, &tcb->scale);}voidsndrst(Proto *tcp, uchar *source, uchar *dest, ushort length, Tcp *seg, uchar version, char *reason){	Block *hbp;	uchar rflags;	Tcppriv *tpriv;	Tcp4hdr ph4;	Tcp6hdr ph6;	netlog(tcp->f, Logtcp, "sndrst: %s", reason);	tpriv = tcp->priv;	if(seg->flags & RST)		return;	/* make pseudo header */	switch(version) {	case V4:		memset(&ph4, 0, sizeof(ph4));		ph4.vihl = IP_VER4;		v6tov4(ph4.tcpsrc, dest);		v6tov4(ph4.tcpdst, source);		ph4.proto = IP_TCPPROTO;		hnputs(ph4.tcplen, TCP4_HDRSIZE);		hnputs(ph4.tcpsport, seg->dest);		hnputs(ph4.tcpdport, seg->source);		break;	case V6:		memset(&ph6, 0, sizeof(ph6));		ph6.vcf[0] = IP_VER6;		ipmove(ph6.tcpsrc, dest);		ipmove(ph6.tcpdst, source);		ph6.proto = IP_TCPPROTO;		hnputs(ph6.ploadlen, TCP6_HDRSIZE);		hnputs(ph6.tcpsport, seg->dest);		hnputs(ph6.tcpdport, seg->source);		break;	default:		panic("sndrst: version %d", version);	}	tpriv->stats[OutRsts]++;	rflags = RST;	/* convince the other end that this reset is in band */	if(seg->flags & ACK) {		seg->seq = seg->ack;

⌨️ 快捷键说明

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