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

📄 tcp.c

📁 RTL8019以太网开发板资料
💻 C
📖 第 1 页 / 共 3 页
字号:
//-----------------------------------------------------------------------------
// 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
#include "http.h"		// toupper

// These structures keep track of connection information
Str_CONNECTION xdata StrConnection_buf[5];	  //设置可以同时接收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)
{
   memset(StrConnection_buf, 0, sizeof(StrConnection_buf));
   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)
{
   UWORK8 idata nr;
   
   // Look for active connections in the established state
   for (nr = 0; nr < 5; 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)
         {
            // Inactivity timer has just timed out.
            // Initiate close of connection
            tcp_ReBack((FLG_ACK | FLG_FIN), 20, nr);
            StrConnection_buf[nr].state = STATE_FIN_WAIT_1;
         }
      }
   }
}


//------------------------------------------------------------------------
// 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 nr;
   // Scan through all active connections 
   for (nr = 0; nr < 5; nr++)
   {
      if ((StrConnection_buf[nr].ipaddr != 0) && (StrConnection_buf[nr].timer) && (StrConnection_buf[nr].ReSendNum != 0))
      {
         // Decrement the timer and see if it hit 0
         StrConnection_buf[nr].timer--;
         if (StrConnection_buf[nr].timer == 0)
         {
       		 StrConnection_buf[nr].ReSendNum--;
			// 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)
            {
               tcp_ReBack(FLG_RST, 20, nr);		 // Send reset and close connection
               StrConnection_buf[nr].ipaddr = 0;
               return;
            }
            else
            {
			   	StrConnection_buf[nr].ucSERIESNUM = StrConnection_buf[nr].ucRESERIESNUM; 
			   switch(StrConnection_buf[nr].HttpFlag)
			   {
			   		case TCP_COM:		 //重复发送TCP命令
						tcp_ReSendBack(StrConnection_buf[nr].SendLen, nr);
						break;
					case TCP_TDATA:		//重复发送数据
						tcp_ReSend(StrConnection_buf[nr].SendLen, nr);
						break;
					case TCP_HTTP:
						break;
					default:
						break;
               	}
            }
			if(StrConnection_buf[nr].ReSendNum == 0)
			{
	            StrConnection_buf[nr].inactivity = INACTIVITY_TIME;		   //转入下一级15秒定时
			}
         }
      }
   }
}


/*********************************************************************
函数名:       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;
   UWORK8 destIP_buf[4];

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

    strTcp->usSourcePort = SourcePort;				//源端口
    strTcp->usDesPort = DesPort;			//目标端口,在接收TCP时已附值
	strTcp->ucSERIESNUM = StrConnection_buf[nr].ucSERIESNUM;	 //序号为0
	strTcp->ucTRUECODE = StrConnection_buf[nr].ucTRUECODE;	 //确认号为0
	memcpy(destIP_buf,(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选择附值过去
   } 
   //下面是给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 = 0x20;                                                   //校验和计算完毕,重赋TTL值 
    memcpy(&MAC_Remote_buf[0],&gstaRevEthernet.ucaSourceNodID[0],MAC_LEN);    // 目的MAC 
//    memcpy((UWORK8 *)&MAC_Remote_buf[4],&gstaRevEthernet.ucaDestNodID[0],MAC_LEN);    // 目的MAC 
//	memcpy(&MAC_Remote_buf[0],&ArpCache_Buf[0].ucaMAC[0],MAC_LEN);          // 远程MAC */
	IpSend();
   // (Re)start TCP retransmit timer
    StrConnection_buf[nr].timer = TCP_TIMEOUT;
	StrConnection_buf[nr].HttpFlag = TCP_COM;
	StrConnection_buf[nr].inactivity = 0;
	StrConnection_buf[nr].ucRESERIESNUM = StrConnection_buf[nr].ucSERIESNUM;
	StrConnection_buf[nr].SendLen = TCPHead_len;
	StrConnection_buf[nr].ReSendNum = 3;
	memcpy((UWORK8 *)&StrConnection_buf[nr].query[0], (UWORK8 *)&NetSend_buf[20], TCPHead_len);
}

/*********************************************************************
函数名:      void tcp_ReSendBack(UWORK16 TCPHead_len, UWORK8 nr)
功能:         重新发送TCP
输入:        flags: TCP的标志位, hdr_len: TCP的长度,nr:是接收的次数  
输出:         None
返回:         None
日期:         2004/02/04
*********************************************************************/
void tcp_ReSendBack(UWORK16 TCPHead_len, UWORK8 nr)
{
	memcpy((UWORK8 *)&NetSend_buf[20], (UWORK8 *)&StrConnection_buf[nr].query[0],TCPHead_len);
    gstIphead.ucVerAndLen = 0x45;                       //版本号和长度,各占4位
    gstIphead.ucDs = 0;                        //区分服务
    gstIphead.usTotalLen = IP_HEAD_LEN + TCPHead_len;                        //头加后面的数据
    gstIphead.usID = ++LocalIpID;
    gstIphead.usSegOffset = 0;

    gstIphead.ucprotocol = TCP;
    gstIphead.usCheckSum = TCPHead_len;                                   //在计算TCP的校验位时,TCP的长度要算两次,此时是借IP的校验位来做第二个TCP的长度
	gstIphead.ucTTL = 0x20;                                                   //校验和计算完毕,重赋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)

⌨️ 快捷键说明

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