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

📄 tcp.c

📁 RTL8019以太网开发板资料
💻 C
📖 第 1 页 / 共 2 页
字号:
//-----------------------------------------------------------------------------
// Net TCP.C
//
// This module handles TCP segments
// Refer to RFC 793, 896, 1122, 1323, 2018, 2581
//
// A "connection" is a unique combination of 4 items:  His IP address,
// his port number, my IP address, and my port number.
//
// Note that a SYN and a FIN count as a byte of data, but a RST does
// not count. Neither do any of the other flags.
// See "TCP/IP Illustrated, Volume 1" Sect 17.3 for info on flags
//-----------------------------------------------------------------------------
#include <string.h>
#include <stdlib.h>
#include <ctype.h>		// toupper
#include "main.h"		// toupper
#include "udp.h"		// toupper
#include "rs232.h"		// toupper
#include "tcp.h"		// toupper
#include "ip.h"		// toupper
#include "ARP.h"		// toupper
UWORK8 idata just_closed; // Keeps track of when a conxn closed
// These structures keep track of connection information
Str_CONNECTION xdata StrConnection_buf[2];	  //设置可以同时接收5组IP地址的TCP数据
UWORK32 initial_sequence_nr;				 //序列号
UWORK8 TcpStateFlag;				//TCP的状态标志位,是在各个过程中的状态 
char xdata text[];
// Options: MSS (4 bytes), NOPS (2 bytes), Selective ACK (2 bytes) 
UWORK8 code options_buf[10] = {0x02, 0x04, 0x05, 0xB4, 0x01, 0x01, 0x04, 0x02};
UWORK8 code optionsRe_buf[4] = {0x02, 0x04, 0x05, 0x78};	  //建立连接的TCP选项

UWORK8 HttpSendFlag;		//TCP有发送的数据

//------------------------------------------------------------------------
//  Initialize variables declared in this module
//
//------------------------------------------------------------------------
/*********************************************************************
函数名:       void init_tcp(void)
功能:         初始化TCP的接收缓存器
输入:         None 
输出:         None
返回:         None
日期:         2004/02/04
*********************************************************************/
void init_tcp(void)
{
   memset(StrConnection_buf, 0, sizeof(StrConnection_buf));
   just_closed = FALSE;
   initial_sequence_nr = 1;
}
//------------------------------------------------------------------------
// This runs every 0.5 seconds.  If the connection has had no activity
// it initiates closing the connection.
//
//------------------------------------------------------------------------
/*********************************************************************
函数名:       void tcp_inactivity(void)
功能:         判断TCP的状态
输入:         None 
输出:         None
返回:         None
日期:         2004/02/04
This runs every 0.5 seconds.  If the connection has had no activity
// it initiates closing the connection.
*********************************************************************/
//------------------------------------------------------------------------
// This runs every 0.5 seconds.  If the connection has had no activity
// it initiates closing the connection.
//
//------------------------------------------------------------------------
/*
void tcp_inactivity(void)
{
   UWORK8 idata nr;
   // Look for active connections in the established state
   for (nr = 0; nr < 2; nr++)
   {
      if ((StrConnection_buf[nr].ipaddr != 0) && (StrConnection_buf[nr].state == STATE_ESTABLISHED) && (StrConnection_buf[nr].inactivity))
      {
         // Decrement the timer and see if it hit 0
         StrConnection_buf[nr].inactivity--;
         if (StrConnection_buf[nr].inactivity == 0)
         {
            tcp_ReBack((FLG_ACK | FLG_FIN), 20, nr);
			StrConnection_buf[nr].My_SERIESNUM++;    // For my FIN
            StrConnection_buf[nr].state = STATE_FIN_WAIT_1;
 //           if (debug) serial_send("TCP: Entered FIN_WAIT_1 state\r");	
         }
      }
   }
}
*/
//------------------------------------------------------------------------
// This runs every 0.5 seconds.  If the other end has not ACK'd
// everyting we have sent, it re-sends it.  To save RAM space, we 
// regenerate a segment rather than keeping a bunch of segments 
// hanging around eating up RAM.  A connection should not be in an
// opening or closing state when this timer expires, so we simply
// send a reset.
//
//	If a connection is in the ESTABLISHED state when the timer expires
// then we have just sent a web page so re-send the page
//------------------------------------------------------------------------
/*
void tcp_retransmit(void)
{
   UWORK8 idata retries = 0;
   UWORK8 idata nr;

	// Scan through all active connections 
	for (nr = 0; nr < 2; nr++)
	{
		if ((StrConnection_buf[nr].ipaddr != 0) && (StrConnection_buf[nr].timer))
		{
			// Decrement the timer and see if it hit 0
			StrConnection_buf[nr].timer--;
			if (StrConnection_buf[nr].timer == 0)
			{
				// Socket just timed out. If we are not in ESTABLISHED state
				// something is amiss so send reset and close connection
				if (StrConnection_buf[nr].state != STATE_ESTABLISHED)
				{
	// Send reset and close connection
	//               if (debug) serial_send("TCP: Timeout, sending reset\r");
					tcp_ReBack(FLG_RST, 20, nr);
					StrConnection_buf[nr].ipaddr = 0;
					return;
				}
				else
				{
					// Socket is in ESTABLISHED state. First make sure his
					// ack number is not bogus.
					if (StrConnection_buf[nr].his_TRUECODE > StrConnection_buf[nr].My_SERIESNUM)
					{
						// Send reset and close connection
						//         if (debug) serial_send("TCP: Timeout, sending reset\r");
						tcp_ReBack(FLG_RST, 20, nr);
						StrConnection_buf[nr].ipaddr = 0;
						return;
					}
					
					// We always increment our sequence number immediately
					// after sending, so the ack number from the other end
					// should be equal to our sequence number.  If it is less,
					// it means he lost some of our data.
					if (StrConnection_buf[nr].his_TRUECODE < StrConnection_buf[nr].My_SERIESNUM)
					{
						retries++;
						if (retries <= 2)
						{
							// The only thing we send is a web page, and it looks
							// like other end did not get it, so resend
							// but do not increase my sequence number
							//         	if (debug) serial_send("TCP: Timeout, resending data\r");
//							http_server(StrConnection_buf[nr].query, 0, nr, 1);
							StrConnection_buf[nr].inactivity = INACTIVITY_TIME;
						}
						else
						{
	//						  	if (debug) serial_send("TCP: Giving up, sending reset\r");
							// Send reset and close connection
							tcp_ReBack(FLG_RST, 20, nr);
							StrConnection_buf[nr].ipaddr = 0;
						}
					}
				}
			}
		}
	}
}
 */
/*********************************************************************
函数名:       void IpReceive(void)
功能:         Ip处理,因为是接收一帧处理一帧,不用返回成功失败
输入:         接收的帧是Ip帧 
输出:         处理IP分组
返回:         None
日期:         2004/12/20
*********************************************************************/
UWORK16 cksum(UWORK8 xdata *check,UWORK16 length) //计算校验和
{
	UWORK32 sum=0;
	UWORK16 i;
	UWORK16 xdata *ptr; 
    ptr=(UWORK16 xdata *)check;
	for (i=0;i<(length)/2;i++)
	{
		sum+=*ptr++;
	}
	if (length&0x01)//表示长度为单数
	{
		sum=sum+((*ptr)&0xff00);
	}
	sum=(sum&0xffff)+((sum>>16)&0xffff);//高16位和低16位相加
	if(sum&0xffff0000)
	{//表示有进位
		sum++;
	}
	return ( (UWORK16)((sum)&0xffff));
//	return ( (UWORK16)(~((sum)&0xffff)));
}

/*********************************************************************
函数名:       void tcp_ReBack(UWORK16 flags,  UWORK16 hdr_len, UWORK8 nr)
功能:         发送TCP
输入:        flags: TCP的标志位, hdr_len: TCP的长度,nr:是接收的次数  
输出:         None
返回:         None
日期:         2004/02/04
*********************************************************************/
void tcp_ReBack(UWORK16 flags,  UWORK16 TCPHead_len, UWORK8 nr)
{
   ST_TCP_FORMAT *strTcp;

    strTcp = (ST_TCP_FORMAT *)&NetSend_buf[20];

    strTcp->usSourcePort = SourcePort;				//源端口
	strTcp->usDesPort = StrConnection_buf[nr].usDesPort;
	strTcp->ucSERIESNUM = StrConnection_buf[nr].My_SERIESNUM;	 //序号为0
	strTcp->ucTRUECODE = StrConnection_buf[nr].His_SERIESNUM;	 //确认号为0
	memcpy(&IPDestAddress_buf[0],(UWORK8 *)&StrConnection_buf[nr].ipaddr, 4);	//发送的目标IP地址在TCP接收中已附值

   strTcp->ucMOVENUM = (TCPHead_len << 10) | flags;		  //记算TCP的头长度及相关的标志位
   strTcp->ucWINDOWBIG = 1024;						  //设置窗口大小
   strTcp->ucTCPCHECK = 0;							  //先设置校验位为0
   strTcp->ucMUSGPOINT = 0;							  //紧急指针为0
   
	if (nr == NO_CONNECTION)
	{
		strTcp->ucSERIESNUM = 0;
		strTcp->ucTRUECODE = 0;
	}
	if (TCPHead_len == 28)							   //如果发送的字节为28,那么多余的部分为TCP的很选项
	{
		memcpy(&strTcp->options[0], options_buf, 8);		   //把默认的TCP选择附值过去
	} 

   //下面是给IP打包头
    gstIphead.ucVerAndLen = 0x45;                       //版本号和长度,各占4位
    gstIphead.ucDs = 0;                        //区分服务
    gstIphead.usTotalLen = IP_HEAD_LEN + TCPHead_len;                        //头加后面的数据
    gstIphead.usID = ++LocalIpID;
    gstIphead.usSegOffset = 0;

    gstIphead.ucTTL = 0;										 // max hops
    gstIphead.ucprotocol = TCP;
    gstIphead.usCheckSum = TCPHead_len;                                   //在计算TCP的校验位时,TCP的长度要算两次,此时是借IP的校验位来做第二个TCP的长度
    memcpy(&gstIphead.ucDestIP[0],&IPDestAddress_buf[0],IP_LEN);          // 目的IP 
    memcpy(&gstIphead.ucSourceIP[0],&IPLocalAddress_buf[0],IP_LEN);                // 源IP    
    memcpy(&NetSend_buf[0],&gstIphead,20);										  //把IP的头传给发送缓存区
	strTcp->ucTCPCHECK = 0;
	strTcp->ucTCPCHECK = CheckSum((UWORK16 *)&NetSend_buf[8],TCPHead_len + 12);   // 20 = 12个字节伪头 + 8个字节UDP头 

    gstIphead.ucTTL = 0x40;                                                   //校验和计算完毕,重赋TTL值 
    memcpy(&MAC_Remote_buf[0],&gstaRevEthernet.ucaSourceNodID[0],MAC_LEN);    // 目的MAC 
	IpSend();
    StrConnection_buf[nr].timer = TCP_TIMEOUT;
}


/*********************************************************************
函数名:       void SeriesToTcp(UWORK8 *pucAddr,UWORK16 usLen)
功能:         串口数据向TCP发送
输入:         None 
输出:         None
返回:         None
日期:         2004/02/04
*********************************************************************/
void tcp_Send(UWORK16 flags,  UWORK16 TCPHead_len, UWORK8 nr, UWORK8 *TData, UWORK16 TLen)
{
	ST_TCP_FORMAT *strTcp;
	UWORK8 *TempD;
	TempD = TData; 
	strTcp = (ST_TCP_FORMAT *)&NetSend_buf[20];
	
	strTcp->usSourcePort = SourcePort;				//源端口
	strTcp->usDesPort = StrConnection_buf[nr].usDesPort;			//目标端口,在接收TCP时已附值
	
	strTcp->ucSERIESNUM = StrConnection_buf[nr].My_SERIESNUM;	 //序号为0
	strTcp->ucTRUECODE = StrConnection_buf[nr].His_SERIESNUM;	 //确认号为0
	
	memcpy(&IPDestAddress_buf[0],(UWORK8 *)&StrConnection_buf[nr].ipaddr, 4);	//发送的目标IP地址在TCP接收中已附值
	
	strTcp->ucMOVENUM = (TCPHead_len << 10) | flags;		  //记算TCP的头长度及相关的标志位
	strTcp->ucWINDOWBIG = 1024;						  //设置窗口大小
	strTcp->ucTCPCHECK = 0;							  //先设置校验位为0
	strTcp->ucMUSGPOINT = 0;							  //紧急指针为0
   
   if (TCPHead_len == 24)							   //建立连接是的TCP的选项
   {
      memcpy(&strTcp->options[0], optionsRe_buf, 4);		   //把默认的TCP选择附值过去
   } 
   else if (TCPHead_len == 28)							   //如果发送的字节为28,那么多余的部分为TCP的很选项
   {
      memcpy(&strTcp->options[0], options_buf, 8);		   //把默认的TCP选择附值过去
   }
   memcpy((UWORK8 *)&NetSend_buf[(20 + TCPHead_len)], TData, TLen);		//把发送的数据传到发送缓存中 
   //下面是给IP打包头
    gstIphead.ucVerAndLen = 0x45;                       //版本号和长度,各占4位
    gstIphead.ucDs = 0;                        //区分服务
    gstIphead.usTotalLen = IP_HEAD_LEN + TCPHead_len + TLen;                        //头加后面的数据
    gstIphead.usID = ++LocalIpID;
    gstIphead.usSegOffset = 0;

    gstIphead.ucTTL = 0;										 // max hops
    gstIphead.ucprotocol = TCP;
    gstIphead.usCheckSum = TCPHead_len + TLen;                                   //在计算TCP的校验位时,TCP的长度要算两次,此时是借IP的校验位来做第二个TCP的长度
    memcpy(&gstIphead.ucDestIP[0],&IPDestAddress_buf[0],IP_LEN);          // 目的IP 
    memcpy(&gstIphead.ucSourceIP[0],&IPLocalAddress_buf[0],IP_LEN);                // 源IP    
    memcpy(&NetSend_buf[0],&gstIphead,20);										  //把IP的头传给发送缓存区
	strTcp->ucTCPCHECK = 0;
	strTcp->ucTCPCHECK = CheckSum((UWORK16 *)&NetSend_buf[8],TCPHead_len + TLen + 12);   // 20 = 12个字节伪头 + 8个字节UDP头 

    gstIphead.ucTTL = 0x40;                                                   //校验和计算完毕,重赋TTL值 
    memcpy(&MAC_Remote_buf[0],&gstaRevEthernet.ucaSourceNodID[0],MAC_LEN);    // 目的MAC 
	IpSend();
    StrConnection_buf[nr].timer = TCP_TIMEOUT;	     // (Re)start TCP retransmit timer
}


/*********************************************************************
函数名:       void SeriesToTcp(UWORK8 *pucAddr,UWORK16 usLen)
功能:         串口数据向TCP发送
输入:         None 
输出:         None
返回:         None
日期:         2004/02/04
*********************************************************************/
void TcpFromSeries(UWORK8 *pucAddr,UWORK16 usLen)
{
	UWORK8 p;
	UWORK8 *p1, *p2;
	p1 = pucAddr;
	p2 = pucAddr;  
	for(p = 0; p < 2; p++)		   //发现在一次没有连接,则一个IP为0
	{
		if((StrConnection_buf[p].ipaddr != 0) && (StrConnection_buf[p].state == STATE_ESTABLISHED))		 //如果IP地址不是0,就表示有相关的连接
		{
			tcp_Send(FLG_PSH | FLG_ACK,  20, p, p1, usLen);
			StrConnection_buf[p].SLen = usLen; 	

⌨️ 快捷键说明

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