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

📄 tinytcp.c

📁 在89C51上实现TCPIP协议
💻 C
📖 第 1 页 / 共 2 页
字号:
	tp = (tcp_Header *)((BYTE *)ip + len);
	len = ip->length - len;

	/* demux to active sockets */
	for ( s = tcp_allsocs; s; s = s->next )
		if ( s->hisport != 0 &&
		tp->dstPort == s->myport &&
		tp->srcPort == s->hisport &&
		ip->source == s->hisaddr ) break;
	if ( s == NIL ) {
		/* demux to passive sockets */
		for ( s = tcp_allsocs; s; s = s->next )
		if ( s->hisport == 0 && tp->dstPort == s->myport ) break;
	}
	if ( s == NIL ) {
		tcp_Reset( ip, tp );
#ifdef DEBUG
		if ( tcp_logState & tcp_LOGPACKETS ) tcp_DumpHeader(ip, tp, "Discarding");
#endif
		return;
	}

#ifdef DEBUG
	if ( tcp_logState & tcp_LOGPACKETS )
		tcp_DumpHeader(ip, tp, "Received");
#endif

	/* save his ethernet address */
	Move(&((((eth_Header *)ip) - 1)->source[0]), &s->hisethaddr[0], sizeof(eth_HwAddress));

	ph.src = ip->source;
	ph.dst = ip->destination;
	ph.mbz = 0;
	ph.protocol = 6;
	ph.length = len;
	ph.checksum = checksum((WORD *)tp, len);
	if ( checksum((WORD *)&ph, sizeof ph) != 0xFFFF )
	{
#ifdef DEBUG
		print("bad tcp checksum, received anyway\r\n");
#endif
	}

	flags = tp->flags;
	if ( flags & tcp_FlagRST ) {
#ifdef DEBUG
		print("connection reset\r\n");
#endif
		s->state = tcp_StateCLOSED;
//		s->dataHandler((tcp_Socket *)s,(BYTE*) 0, (WORD *)-1);
		DATAHANDLER((tcp_Socket *)s,(BYTE*) 0,-1);
		tcp_Unthread(s);
		return;
	}

	switch ( s->state ) {
		case tcp_StateLISTEN:
			if ( flags & tcp_FlagSYN ) {
				s->acknum = tp->seqnum + 1;
				s->hisport = tp->srcPort;
				s->hisaddr = ip->source;
				s->flags = tcp_FlagSYN | tcp_FlagACK;
				tcp_Send(s);
				s->state = tcp_StateSYNREC;
				s->unhappy = true;
				s->timeout = tcp_TIMEOUT;
#ifdef DEBUG
				print("Syn from 0x%x#%d (seq 0x%x)\r\n", s->hisaddr, s->hisport, tp->seqnum);
#endif
	        	}
			break;

		case tcp_StateSYNSENT:
			if ( flags & tcp_FlagSYN ) {
				s->acknum++;
				s->flags = tcp_FlagACK;
				s->timeout = tcp_TIMEOUT;
				if ( (flags & tcp_FlagACK) && tp->acknum == (s->seqnum + 1) ) {
#ifdef DEBUG
					print("Open\r\n");
#endif
					s->state = tcp_StateESTAB;
					s->seqnum++;
					s->acknum = tp->seqnum + 1;
					s->unhappy = false;
				} else {
					s->state = tcp_StateSYNREC;
				}
			}
			break;

		case tcp_StateSYNREC:
			if ( flags & tcp_FlagSYN ) {
				s->flags = tcp_FlagSYN | tcp_FlagACK;
				tcp_Send(s);
				s->timeout = tcp_TIMEOUT;
#ifdef DEBUG
				print(" retransmit of original syn\r\n");
#endif				
			}
			if ( (flags & tcp_FlagACK) && tp->acknum == (s->seqnum + 1) ) {
				s->flags = tcp_FlagACK;
				tcp_Send(s);
				s->seqnum++;
				s->unhappy = false;
            			s->state = tcp_StateESTAB;
				s->timeout = tcp_TIMEOUT;
#ifdef DEBUG
				print("Synack received - connection established\r\n");
#endif
			}
			break;

		case tcp_StateESTAB:
			if ( (flags & tcp_FlagACK) == 0 ) return;
			/* process ack value in packet */
			diff = tp->acknum - s->seqnum;
			if ( diff > 0 ) {
				Move(&s->datas[diff], &s->datas[0], diff);
				s->dataSize -= diff;
				s->seqnum += diff;
			}
			s->flags = tcp_FlagACK;
			tcp_ProcessData(s, tp, len);
			break;

		case tcp_StateFINWT1:
			if ( (flags & tcp_FlagACK) == 0 ) return;
			diff = tp->acknum - s->seqnum - 1;
			s->flags = tcp_FlagACK | tcp_FlagFIN;

			/*
			 * This is modified by Jun-Ku.
			 * If we send data and it's unacked. then send FIN. the receiver send diff = dataSize+1 (and it's ACK on FIN ).
			 * if ( diff == 0 ) {
			 */

			if ( diff == 0 || diff == s->dataSize ) {
				s->state = tcp_StateFINWT2;
				s->flags = tcp_FlagACK;
				s->seqnum += (diff+1);
				s->dataSize -= diff;
#ifdef DEBUG
				print("finack received.\r\n");
#endif
			}
			
			tcp_ProcessData(s, tp, len);
			break;

		case tcp_StateFINWT2:
			s->flags = tcp_FlagACK;
			tcp_ProcessData(s, tp, len);
			break;

		case tcp_StateCLOSING:
			if ( tp->acknum == (s->seqnum + 1) ) {
				s->state = tcp_StateTIMEWT;
				s->timeout = tcp_TIMEOUT;
			}
			break;

		case tcp_StateLASTACK:
			if ( tp->acknum == (s->seqnum + 1) ) {
				s->state = tcp_StateCLOSED;
				s->unhappy = false;
				s->dataSize = 0;
//				s->dataHandler((tcp_Socket *)s,(BYTE *)0, (WORD *)0);
				DATAHANDLER((tcp_Socket *)s,(BYTE *)0,0);
				tcp_Unthread(s);
#ifdef DEBUG
				print("Closed.    \r\n");
#endif
			} else {
				s->flags = tcp_FlagACK | tcp_FlagFIN;
				tcp_Send(s);
				s->timeout = tcp_TIMEOUT;
#ifdef DEBUG
				print("retransmitting FIN\r\n");
#endif
			}
			break;

		case tcp_StateTIMEWT:
			s->flags = tcp_FlagACK;
			tcp_Send(s);
	}
}

/*
 * Process the data in an incoming packet.
 * Called from all states where incoming data can be received: established,
 * fin-wait-1, fin-wait-2
 */
void tcp_ProcessData(tcp_Socket *s, tcp_Header *tp, WORD len)
{
	short diff, x;
	WORD flags;
	BYTE *dp;

	flags = tp->flags;
	diff = s->acknum - tp->seqnum;
	if ( flags & tcp_FlagSYN ) diff--;
	x = tcp_GetDataOffset(tp) << 2;		/* x = hdrlen in bytes */
	dp = (BYTE *)tp + x;			/* get first pointer of data */
	len -= x;					/* len is data length now */
	if ( diff >= 0 ) {
		dp += diff;
		len -= diff;
		s->acknum += len;
//		s->dataHandler((tcp_Socket *)s,(BYTE *)dp, (WORD *)len);
		DATAHANDLER((tcp_Socket *)s,(BYTE *)dp,len);
		if ( flags & tcp_FlagFIN ) {
			s->acknum++;
#ifdef DEBUG
			print("consumed fin.\r\n");
#endif
			switch(s->state) {
				case tcp_StateESTAB:
					/* note: skip state CLOSEWT by automatically closing conn */
					x = tcp_StateLASTACK;
					s->flags |= tcp_FlagFIN;
					s->unhappy = true;
#ifdef DEBUG
					print("fin on estab.\r\n");
#endif
					break;
				case tcp_StateFINWT1:
					x = tcp_StateCLOSING;
					break;
				case tcp_StateFINWT2:
					x = tcp_StateTIMEWT;
					break;
			}
			s->state = x;
		}
	}
	s->timeout = tcp_TIMEOUT;
	tcp_Send(s);
}

/*
 * Format and send an outgoing segment
 */
void tcp_Send(tcp_Socket *s)
{
	tcp_PseudoHeader ph;
	struct _pkt {
		in_Header in;
		tcp_Header tcp;
		DWORD maxsegopt;
	} *pkt;
	BYTE *dp;

	pkt = (struct _pkt *)sed_FormatPacket(&s->hisethaddr[0], 0x800);
	dp = (BYTE *)&pkt->maxsegopt;

	pkt->in.length = sizeof(in_Header) + sizeof(tcp_Header) + s->dataSize;

	/* tcp header */
	pkt->tcp.srcPort = s->myport;
	pkt->tcp.dstPort = s->hisport;
	pkt->tcp.seqnum = s->seqnum;
	pkt->tcp.acknum = s->acknum;
	pkt->tcp.window = 1024;
	pkt->tcp.flags = s->flags | 0x5000;		/* Header length = 20bytes ;; no option */
	pkt->tcp.checksum = 0;
	pkt->tcp.urgentPointer = 0;
	if ( s->flags & tcp_FlagSYN ) {
		pkt->tcp.flags += 0x1000;
		pkt->in.length += 4;
		pkt->maxsegopt = 0x02040578; /* 1400 bytes */
		dp += 4;
	}
	Move(s->datas, dp, s->dataSize);		/* copy data to pointer which is next to tcp header */

	/* internet header */
	pkt->in.vht = 0x4500;   /* version 4, hdrlen 5, tos 0 */
	pkt->in.identification = tcp_id++;
	pkt->in.frag = 0;
	pkt->in.ttlProtocol = (250<<8) + 6;
	pkt->in.checksum = 0;
	pkt->in.source = sin_lclINAddr;
	pkt->in.destination = s->hisaddr;
	pkt->in.checksum = ~(checksum((WORD *)&pkt->in, sizeof(in_Header)));

	/* compute tcp checksum */
	ph.src = pkt->in.source;
	ph.dst = pkt->in.destination;
	ph.mbz = 0;
	ph.protocol = 6;
	ph.length = pkt->in.length - sizeof(in_Header);
	ph.checksum = checksum((WORD *)&pkt->tcp, ph.length);
	pkt->tcp.checksum = ~checksum((WORD *)&ph, sizeof ph);

	sed_Send(pkt->in.length);
}

/*
 * Format and send an outgoing reset segment
 */
void tcp_Reset( in_Header *ip, tcp_Header *tp )
{
	tcp_PseudoHeader ph;
	struct _pkt {
		in_Header in;
		tcp_Header tcp;
		DWORD maxsegopt;
	} *pkt;

	pkt = (struct _pkt *)sed_FormatPacket(&(((eth_Header *)ip)-1)->source[0], 0x800);
	pkt->in.length = sizeof(in_Header) + sizeof(tcp_Header);

	/* tcp header */
	pkt->tcp.srcPort = tp->dstPort;
	pkt->tcp.dstPort = tp->srcPort;
	pkt->tcp.seqnum = tp->seqnum;
	pkt->tcp.acknum = tp->acknum;
	pkt->tcp.window = 1024;
	pkt->tcp.flags = tcp_FlagRST | 0x5000;		/* Header length = 20bytes ;; no option */
	pkt->tcp.checksum = 0;
	pkt->tcp.urgentPointer = 0;

	/* internet header */
	pkt->in.vht = 0x4500;   /* version 4, hdrlen 5, tos 0 */
	pkt->in.identification = tcp_id++;
	pkt->in.frag = 0;
	pkt->in.ttlProtocol = (250<<8) + 6;
	pkt->in.checksum = 0;
	pkt->in.source = sin_lclINAddr;
	pkt->in.destination = ip->source;
	pkt->in.checksum = ~(checksum((WORD *)&pkt->in, sizeof(in_Header)));

	/* compute tcp checksum */
	ph.src = pkt->in.source;
	ph.dst = pkt->in.destination;
	ph.mbz = 0;
	ph.protocol = 6;
	ph.length = pkt->in.length - sizeof(in_Header);
	ph.checksum = checksum((WORD *)&pkt->tcp, ph.length);
	pkt->tcp.checksum = ~checksum((WORD *)&ph, sizeof ph);

	sed_Send(pkt->in.length);
}

/*
 * Do a one's complement checksum
 */
int checksum(WORD *dp, WORD length)
{
	WORD len;
	DWORD sum;

	len = length >> 1;
	sum = 0;
	while ( len-- > 0 ) sum += *dp++;
	if ( length & 1 ) sum += (*dp & 0xFF00);
	sum = (sum & 0xFFFF) + ((sum >> 16) & 0xFFFF);
	sum = (sum & 0xFFFF) + ((sum >> 16) & 0xFFFF);

	return ( sum );
}


/* Dump the tcp protocol header of a packet */
#ifdef DEBUG
void tcp_DumpHeader( in_Header *ip, tcp_Header *tp, BYTE *mesg )
{
	return;
	/*
	tcp_Header *tp = (tcp_Header *)((BYTE *)ip + in_GetHdrlenBytes(ip));
	static char *flags[] = { "FIN", "SYN", "RST", "PUSH", "ACK", "URG" };
	int len;
	WORD f;

	len =  ip->length - ((tcp_GetDataOffset(tp) + in_GetHdrlen(ip)) << 2);
	printf("TCP: %s packet:\r\nS: %x; D: %x; SN=%x ACK=%x W=%d DLen=%d\r\n",
           mesg, tp->srcPort, tp->dstPort, tp->seqnum, tp->acknum,
           tp->window, len);
	printf("DO=%d, C=%x U=%d",
           tcp_GetDataOffset(tp), tp->checksum, tp->urgentPointer);
    f = tp->flags;
    for ( len = 0; len < 6; len++ )
        if ( f & (1 << len) ) printf(" %s", flags[len]);
    printf("\r\n");
   */
}
#endif

⌨️ 快捷键说明

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