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

📄 tcp.cc

📁 南京航空航天大学开发的一个类Unix和Linux的操作系统,好不好看看就知道了,
💻 CC
字号:
#include "root.h" #include <init/ctor.h>#include <mm/allockm.h>#include <kern/sched.h>#include <dev/net/eth.h>#include "tcp.h"#include "ip.h"static Q(all, tcpsock_t) allq;typedef Q(lhash, tcpsock_t) lhashq_t;typedef Q(fhash, tcpsock_t) fhashq_t;typedef Q(fhash, tcpsock_t) listenhashq_t;static int hashsize, hashmask;static lhashq_t *lhashtab;static fhashq_t *fhashtab;static listenhashq_t *listenhashtab;__ctor(PRINET, SUBANY, inittcphash){	construct(&allq);	hashsize = 32;	hashmask = hashsize - 1;	lhashtab = (lhashq_t*) allocbm(hashsize * sizeof(lhashq_t));	construct(lhashtab, hashsize);	fhashtab = (fhashq_t*) allocbm(hashsize * sizeof(fhashq_t));	construct(fhashtab, hashsize);	listenhashtab = (fhashq_t*) allocbm(hashsize * sizeof(fhashq_t));	construct(listenhashtab, hashsize);}static inline lhashq_t * lhashfunc(u16_t lport){	return lhashtab + (ntohs(lport) & hashmask);}/* a busy server has many connections which has the same local port,    so we use the foreign port as the hash key */static inline fhashq_t * fhashfunc(u16_t fport){	return fhashtab + (ntohs(fport) & hashmask);}static inline listenhashq_t * listenhashfunc(u16_t lport){	return listenhashtab + (ntohs(lport) & hashmask);}static bool exist(u32_t laddr, u16_t lport, bool reuseaddr){	lhashq_t * lhashq = lhashfunc(lport);	tcpsock_t * s;	foreach (s, *lhashq) { 		if ((s->laddr == INADDRANY || laddr == INADDRANY || s->laddr == laddr) &&		    (s->lport == lport) && 		    !(reuseaddr && s->state == tcpsock_t::STIMEWAIT))			return true;	}	return false;}static u16_t newtcpport(){	/* well known ports ranges from 0 to 1023 */	static u16_t begin = USERSOCK;	while (exist(INADDRANY, begin, false))		if (!++begin) /* overflow */			begin = USERSOCK;	return htons(begin);}void tcphdr_t::dump(){	printf("sport:%d dport:%d seq:%u ack:%u wnd:%d\n", 	       ntohs(sport), ntohs(dport), ntohl(seq), ntohl(ack), ntohs(wnd));	printf("fin:%d syn:%d rst:%d psh:%d ack:%d urg:%d\n",                 flags & TCPFFIN, flags & TCPFSYN, flags & TCPFRST,                 flags & TCPFPSH, flags & TCPFACK, flags & TCPFURG);}int tcpsock_t::rcvwnd(){	if (currcvbuf < LINKIPTCPHLEN + mss)		return 0;	return currcvbuf;}/* <-- (seq=1 len=1 ack=1) (seq=2 len=0 ack=2) (seq=2 len=0 ack=3) --- */void tcpsock_t::updatesndwnd(tcphdr_t *th){	u32_t seq = ntohl(th->seq);	u32_t ack = ntohl(th->ack);	u16_t newsndwnd = ntohs(th->wnd);	if (seqlt(lastseq, seq) ||	    seqeq(lastseq, seq) && (th->flags & TCPFACK) && seqlt(lastack, ack) ||	    (th->flags & TCPFACK) && seqeq(lastack, ack) && (sndwnd < newsndwnd)) {		lastseq = seq;		lastack = ack;		sndwnd = newsndwnd;	} else		debug(TCPDBG, "update sndwnd:lastseq=%u lastack=%u seq=%u ack=%u\n", 		      lastseq, lastack, seq, ack);}static char * statstr[] = {"CLOSED", "LISTEN", "SYNSENT", "SYNRECV", "ESTAB", "FINWAIT1", "FINWAIT2", "TIMEWAIT", "CLOSEWAIT", "LASTACK", "CLOSING"};void tcpsock_t::dump(){	printf("%s [%s::%d] [%s::%d] ", statstr[state], inetntoa(laddr), 	       ntohs(lport), inetntoa(faddr), ntohs(fport));	printf("sndnxt=%u sndwnd=%d rcvnxt=%u rcvwnd=%d\n", sndnxt, sndwnd, rcvnxt, 	       rcvwnd());}void tcpsock_t::check(){	return;#if DEBUG	pkt_t * p;	if (p = unackedq.tail()) {		if (p->endseq != sndnxt)			printf("%x %u %u %u\n", this, p->startseq, p->endseq, sndnxt);		assert(p->endseq == sndnxt);	}	if (p = recvq.tail())		assert(p->endseq == rcvnxt);	if (p = oosrecvq.head())		assert(seqlt(rcvnxt, p->startseq));	if (unackedq.empty()) {		//assert(cursndbuf == maxsndbuf);	}	if (recvq.empty() && oosrecvq.empty()) 	{		//printf("%d %d\n", currcvbuf, maxrcvbuf); 		//assert(currcvbuf == maxrcvbuf);	}#endif}void tcpsock_t::change(tcpstate_t newstate){	debug(TCPDBG, "%s-->%s\n", statstr[state], statstr[newstate]);	state = newstate;}/* ready to send syn bit */void tcpsock_t::initiss(){	static u32_t tmp = 123;	iss = sndnxt = lastack = tmp;	tmp += passedtick;}/* recv peer's syn bit */void tcpsock_t::initirs(tcphdr_t *th){	irs = lastseq = ntohl(th->seq);	rcvnxt = seqadd(irs, 1);	sndwnd = ntohs(th->wnd);	mss = ETHMTU - (sizeof(iphdr_t) + sizeof(tcphdr_t));	parseopt(th);}void tcpsock_t::changelocal(u32_t newladdr){	laddr = newladdr;}void tcpsock_t::changelocal(u32_t newladdr, u16_t newlport){	laddr = newladdr;	lport = newlport;	unlinklhash();	lhashfunc(newlport)->enqtail(this);}void tcpsock_t::changeforeign(u32_t newfaddr, u16_t newfport){	faddr = newfaddr;	fport = newfport;	unlinkfhash();	fhashfunc(newfport)->enqtail(this);}void tcpsock_t::initaddr(u32_t laddr_, u16_t lport_, u32_t faddr_, u16_t fport_){	nextall = prevall = NULL; 	allq.enqtail(this);         nextincoming = previncoming = listening = NULL; 	laddr = laddr_;	lport = lport_;	nextlhash = prevlhash = NULL; 	lhashfunc(lport)->enqtail(this); 	faddr = faddr_;	fport = fport_;	nextfhash = prevfhash = NULL; 	fhashfunc(fport)->enqtail(this);}tcpsock_t::tcpsock_t(){	state = SCLOSED;	initaddr(INADDRANY, newtcpport(), INADDRANY, 0);	mss = ETHMTU - (sizeof(iphdr_t) + sizeof(tcphdr_t));	assert(mss == 1460);	iss = sndnxt = lastack = 0;	irs = rcvnxt = lastseq = 0;	finrecved = false;	sndwnd = 0;	congwnd = 0;	slowstartthresh = 0;	nrexmit = 0;	ndelack = 0;	inittimer();}/* the listening socket will create a new socket on accept the connection    @l - the listening socket  */tcpsock_t::tcpsock_t(tcpsock_t * l, iphdr_t *ih, tcphdr_t *th){	state = SLISTEN;	initaddr(ih->daddr, th->dport, ih->saddr, th->sport);	listening = l;	l->incomingq.enqtail(this);	initiss();	initirs(th);	finrecved = false;		congwnd = 0;	slowstartthresh = 0;	nrexmit = 0;	ndelack = 0;	stoptimer();	inittimer();}void tcpsock_t::lose(){	assert(refcnt > 0);	if (--refcnt)		return;	shutdown(2);	destroytm.start();}tcpsock_t::~tcpsock_t(){	if (nextall)		allq.unlink(this);	if (nextlhash)		unlinklhash();	if (nextfhash)		unlinkfhash();	if (nextincoming)		unlinkincoming();	unackedq.zapall();	recvq.zapall();	oosrecvq.zapall();}/* the bind operation succeed in case that:   1) bind the socket(named A) to a port that is not used.   2) bind the socket(named A) to a port that is already used by       another socket(named B), but       - the socket A has SO_REUSEADDR flags set on      - the socket B is in the TIME_WAIT state */int tcpsock_t::bind(sockaddr_t *me_, socklen_t myaddrlen){	sockaddrin_t * me = (sockaddrin_t*) me_;	if (state != SCLOSED)		return EINVAL;	if (myaddrlen != sizeof(sockaddrin_t))		return EINVAL;	if (me->port < USERSOCK && !suser())		return EACCES;	if (exist(me->addr, me->port, soreuseaddr))		return EADDRINUSE;	changelocal(me->addr, me->port);        return 0;}int tcpsock_t::listen(int backlog_){	backlog = backlog_;	if (state != SCLOSED)		return EINVAL;	/* register the socket into the listening hash table */	state = SLISTEN;	unlinkfhash();	listenhashfunc(lport)->enqtail(this);        return 0;}int tcpsock_t::connect(sockaddr_t *serv_, socklen_t socklen){	if (state != SCLOSED || faddr)		return EISCONN;	sockaddrin_t * serv = (sockaddrin_t*) serv_;	netdev_t *netdev;	u32_t nexthop;	int e = selectroute(serv->addr, &netdev, &nexthop);	if (e)		return EHOSTUNREACH;	changelocal(netdev->praddr);	changeforeign(serv->addr, serv->port);	initiss();	sndwnd = 8096; /* assume the peer socket's send buffer */        sendflagsmss(TCPFSYN);	change(SSYNSENT);        while (state != SESTAB)                WAIT(waitq);        return 0;}tcpsock_t* tcpsock_t::fetchclient(){	tcpsock_t *t;	foreach (t, incomingq) {		if (t->state == SESTAB) {			incomingq.unlink(t);			assert(t->listening == this);			t->listening = NULL;			return t;		}	}	return NULL;}/* 1) listening socket wait for SYN    2) new socket wait for ACK */int tcpsock_t::accept(sockaddr_t *sa, socklen_t *salen){	if (sa && *salen != sizeof(sockaddrin_t))		return EINVAL;	tcpsock_t * client;	while ((client = fetchclient()) == NULL)		WAIT(waitq);	if (sa)		client->getsockname(sa, salen);	int e = curr->fdvec->put(client);	if (e < 0)		delete client;	return e;}int tcpsock_t::getname(sockaddr_t *name, socklen_t *namelen, int peer){	if (*namelen != sizeof(sockaddrin_t))		return EINVAL;	sockaddrin_t *sin = (sockaddrin_t *) name;	sin->family = AFINET;	if (peer) {		sin->port = fport;		sin->addr = faddr;	} else {		sin->port = lport;		sin->addr = laddr;	}	 *namelen = sizeof(sockaddrin_t);	return 0;}int tcpsock_t::getsockname(sockaddr_t *name, socklen_t *namelen){	return getname(name, namelen, 0);}int tcpsock_t::getpeername(sockaddr_t *name, socklen_t *namelen){	return getname(name, namelen, 1);}/* send a fin without close the socket */int tcpsock_t::shutdown(int how){	tcpstate_t newstate;	if (state == SESTAB)		newstate = SFINWAIT1;	else if (state == SCLOSEWAIT)		newstate = SLASTACK;	else		return ENOTCONN;	sendflags(TCPFFIN | TCPFACK);	change(newstate);        return 0;}int tcpsock_t::setsockopt(int level, int optname, void *optval, socklen_t optlen){        return 0;}int tcpsock_t::getsockopt(int level, int optname, void *optval, socklen_t *optlen){        return 0;}/* mss sndbuf sndwnd */int tcpsock_t::send(void *buf, size_t buflen, int flags){	if (state < SESTAB)		return ENOTCONN;	check();	int left = buflen;	while (left) {		int once = min(mss, left);		int e = output(AUSER, TCPFACK | TCPFPSH, buf, once);		if (e)			return e;		left -= once, buf += once;	}	return buflen;}int tcpsock_t::sendto(void *buf, size_t len, int flags, sockaddr_t *to_,    socklen_t tolen){	sockaddrin_t * to = (sockaddrin_t*) to_;	if (tolen != sizeof(sockaddrin_t))		return EINVAL;	if (to->family != AFINET || to->addr != faddr || to->port != fport)		return EINVAL;	return send(buf, len, flags);}int tcpsock_t::sendmsg(const msghdr_t *mh, int flags){	return 0;}int tcpsock_t::recv(void *buf, size_t len, int flags){	if (state < SESTAB)		return ENOTCONN;	while (recvq.empty()) {		if (finrecved)			return 0;		WAIT(waitq);	}	check();	if (flags & MSGPEEK)		return recvq.peek(buf, len);	int freedroom;	int e = recvq.fetch(buf, len, &freedroom);	freercvbuf(freedroom);	return e;}int tcpsock_t::recvfrom(void *buf, size_t len, int flags, sockaddr_t *from_,     socklen_t *fromlen){	sockaddrin_t * from = (sockaddrin_t*) from_;	if (from) {		if (*fromlen != sizeof(sockaddrin_t))			return EINVAL;		from->family = AFINET;		from->addr = faddr;		from->port = fport;	}        return recv(buf, len, flags);}int tcpsock_t::recvmsg(msghdr_t *mh, int flags){	return 0;}void tcpinput(pkt_t *pkt){	iphdr_t * ih = (iphdr_t *) pkt->data;	pkt->delhead(ih->headlen());	tcphdr_t * th = (tcphdr_t *) pkt->data;	pkt->delhead(th->getheadlen());	if (tcpchksum(ih->saddr, ih->daddr, ih->datalen(), ih->data)) {		printd("tcp check sum failed\n");		delpkt(pkt);		return;	}#define localmatch ((s->laddr == INADDRANY || s->laddr == ih->daddr) \	&& (s->lport == th->dport))#define foreignmatch ((s->faddr == ih->saddr) && (s->fport == th->sport))	/* lookup for perfect match, use th->sport as the key */	tcpsock_t * s;	fhashq_t * fhashq = fhashfunc(th->sport);	foreach (s, *fhashq) {		if (s->state == tcpsock_t::SCLOSED || s->state == tcpsock_t::STIMEWAIT)			continue;		if (localmatch && foreignmatch) {			s->input(pkt, ih, th);			return;		}	}	/* lookup for half match, use th->dport as the key */	listenhashq_t * listenhashq = listenhashfunc(th->dport);	foreach (s, *listenhashq) {		assert(s->state == tcpsock_t::SLISTEN);		if (localmatch) {			s->input(pkt, ih, th);			return;		}	}        delpkt(pkt);}

⌨️ 快捷键说明

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