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

📄 tcp.c

📁 在S3C2440上运行的"电子日历“(支持平年,闰年,星期自动调整). 开发环境是RVDS2.2
💻 C
📖 第 1 页 / 共 2 页
字号:
	TcpHead[14] = (v16 >> 8);	TcpHead[15] = (uint8)v16;
	
	v32 = This->Seq;			// 序列号
	TcpHead[16] = (v32 >> 24);	TcpHead[17] = (v32 >> 16);
	TcpHead[18] = (v32 >> 8);	TcpHead[19] = (uint8)v32;
	
	v32 = This->Ack;			// 确认号
	TcpHead[20] = (v32 >> 24);	TcpHead[21] = (v32 >> 16);
	TcpHead[22] = (v32 >> 8);	TcpHead[23] = (uint8)v32;
	
	TcpHead[24] = ((20 + OLength) << 2) & 0xf0;		// 头部长
	TcpHead[25] = 0x00 | (Flag & 0x3f);				// 代码位	

	/*
	if(This->hook != NULL)
	{
		//v16 = 1460;
		//v16 = 3072;
		v16 = 4096;
		//v16 = 8192;
	}
	else
	{
		v16 = This->RxWindow.Size;	// 窗口
	}*/
	#if	TCP_RXWINDOW_SIZE > 0
	v16 = This->RxWindow.Size;
	#else
	v16 = 4096;	
	#endif
	
	TcpHead[26] = (v16 >> 8);	TcpHead[27] = (uint8)v16;
	
	TcpHead[28] = 0;			TcpHead[29] = 0;	// 校验和
	TcpHead[30] = 0;			TcpHead[31] = 0;	// 紧急指针

	// 计算校验和
	v16 = ~TcpCheckSum(&Head);
	TcpHead[28] = (uint8)v16;	TcpHead[29] = (v16 >> 8);
	
	// 丢开伪头部,发送数据包
	Head.Data   = TcpHead + 12;
	Head.Length = 20;
	//Head.Next   = &Opt;
	
	NetLayer.SendPacket(IPF_TCP,This->DestAddr,&Head);		
}

/********************************************************************************************
*** 函数名称:	TcpHeadProcess		
*** 函数描述:	TCP 头部处理:主要是根据收到的确认号进行状态转换	
*** 入    口:	Socket:接口指针	Head:头部指针		DataLength:数据段长度	
*** 出    口:	1:TCP包包含新数据,	0:TCP包不包含新数据		
********************************************************************************************/
static	uint8	TcpHeadProcess(TCP_SOCKET	*Socket,uint8 *Head,uint16 DataLength)
{
	uint32		Ack = 0,Tmp = 0,Seq = 0;
	uint8		*ptr,len,dat;
	uint16		v16;
	uint8		Flag;

	// 提取对方窗口大小
	v16  = Head[14];	v16 <<= 8;
	v16 |= Head[15];
	Socket->DestSize = v16;
	
	// 提取TCP包序列号 Seq
	Tmp = Head[4];		Tmp <<= 24;	Seq |= Tmp;
	Tmp = Head[5];		Tmp <<= 16;	Seq |= Tmp;
	Tmp = Head[6];		Tmp <<=  8;	Seq |= Tmp;
	Tmp = Head[7];					Seq |= Tmp;
		
	// 提取FLAG 标志
	Flag = Head[13] & 0x3f;	
	// 设置确认号	
	if(Flag & TCPFLAG_SYN)	Socket->Ack = Seq + DataLength + 1;	
	else					Socket->Ack = Seq + DataLength;	
	
	// 为发送通道产生状态迁移
	if(Flag & TCPFLAG_ACK)
	{
		// 提取TCP包确认号 Ack
		Tmp = Head[ 8];	Tmp <<= 24;	Ack |= Tmp;
		Tmp = Head[ 9];	Tmp <<= 16;	Ack |= Tmp;
		Tmp = Head[10];	Tmp <<=  8;	Ack |= Tmp;
		Tmp = Head[11];				Ack |= Tmp;	
		// 设置序列号			
		Socket->Seq = Ack;				
		
		switch(Socket->TXS)
		{
			case	SOCKS_TXSYN:
				Socket->TXS = SOCKS_SYNACK;
				break;
			case	SOCKS_SENDING:
				if(Socket->LastRcvAck > Ack)
				{
					v16 = Ack + (0xffffffff - Socket->LastRcvAck);
				}
				else
				{
					v16 = Ack - Socket->LastRcvAck;
				}
				WindowDel(&Socket->TxWindow,v16);
				Socket->TXS = SOCKS_SENDACK;
				break;
			case	SOCKS_TXFIN:
				Socket->TXS = SOCKS_FINACK;
				break;
			default:	break;
		}
	}
	
	// 为接收通道状态机产生状态迁移
	if(Flag & TCPFLAG_SYN)
	{
		Socket->RXS = SOCKS_RXSYN;
		// 接收到 SYN ,记录对方的MRU到本地的MTU
		ptr = Head + 20;
		len = (Head[12] & 0xf0) >> 2;
		len = len - 20;
		while(len--)
		{
			dat = *ptr++;
			switch(dat)
			{
				case	0x02:
					dat = *ptr++;
					if(dat != 0x04)	break;
					v16 = *ptr++;	
					v16 <<= 8;
					v16 = v16 | *ptr++;	
					Socket->MTU = v16;
					len = 0;					
					break;				
				case	0x01:	break;				
				case	0x03:	ptr = ptr + 3;	break;				
				case	0x04:	ptr++;	break;
				default:		break;						
			}
		}		
	}
	if(Flag & TCPFLAG_FIN)
	{
		if(Socket->RXS != SOCKS_CLOSED)
		{
			Socket->RXS = SOCKS_RXFIN;
		}
	}	
	if(Flag & TCPFLAG_RST)
	{
		TcpSendPacket(Socket,NULL,0,(TCPFLAG_RST|TCPFLAG_ACK),0);
		/*
		Socket->RXS = SOCKS_CLOSED;
		Socket->TXS = SOCKS_CLOSED;
		*/
		Socket->RXS = SOCKS_CLOSED;
		//Socket->TXS = SOCKS_RESET;
		Socket->TXS = SOCKS_CLOSED;
		//Printf("[Connection is reseted:TOT=%d]\r\n",Socket->TOT);
	}
	
	Socket->LastRcvAck = Ack;
	if(Seq == Socket->LastRcvSeq)	return	0;
	Socket->LastRcvSeq = Seq;		return	1;
}
#endif

/********************************************************************************************
*** 函数名称:  TcpReceiveTask
*** 函数描述:  
*** 入    口:  
*** 出    口:  
********************************************************************************************/
void	TcpReceiveTask(void)
{
	#if	MAX_TCP_SOCKETS > 0
	TCP_SOCKET	*Socket;
	uint8		*TcpData;
	uint16		TcpDataLength;
	uint16		DestPort;
	uint16		SourcePort;
	uint8		SourceIp[4];
	uint8		TcpHeadLength;
	
	TcpHeadLength = *NetLayer.Rxd;	
	TcpHeadLength = (TcpHeadLength & 0x0f) << 2;// 获取IP 包头部长度
	TcpData = NetLayer.Rxd + TcpHeadLength;		// 指向TCP包
	
	// 计算TCP包数据段总长
	TcpDataLength   = NetLayer.Rxd[2];			// 获取IP包总长
	TcpDataLength <<= 8;
	TcpDataLength  |= NetLayer.Rxd[3];

	TcpDataLength  -= TcpHeadLength;			// 减去IP头部长	
	TcpHeadLength   = (TcpData[12] & 0xf0) >> 2;// 获取TCP头部长度
	TcpDataLength  -= TcpHeadLength;			// 减去TCP头部长
	
	// 取 IP 包源地址
	SourceIp[0] = NetLayer.Rxd[12];
	SourceIp[1] = NetLayer.Rxd[13];
	SourceIp[2] = NetLayer.Rxd[14];
	SourceIp[3] = NetLayer.Rxd[15];
	
	// 取 TCP 包源端口
	SourcePort   = TcpData[0];
	SourcePort <<= 8;
	SourcePort  |= TcpData[1];	
	
	// 取 TCP 包目的端口
	DestPort   = TcpData[2];
	DestPort <<= 8;
	DestPort  |= TcpData[3];	

	// 搜索匹配的TCP连接
	Socket = TcpFirstSocket;
	while(Socket != NULL)
	{

		if(		(DestPort == Socket->LocalPort) 			// IP包目的端口与Socket的源端口匹配
			&&	(SourcePort == Socket->DestPort)			// IP包的源端口与Socket目的端口匹配
			&&	(InetMemCmp(SourceIp,Socket->DestAddr,4))	// IP包的源地址与Socket目的地址匹配
			)
		{
			// TCP数据包过滤规则 Added by Yan Zhangjian(C) @ 2008-05-24 
			/*
			if(Socket->TXS == SOCKS_CLOSED && Socket->RXS == SOCKS_CLOSED)
			{
				
			}*/
			
			
			
			
			
			TcpHeadProcess(Socket,TcpData,TcpDataLength);
			if(TcpDataLength)
			{
				TcpData = TcpData + TcpHeadLength;

				#if	TCP_RXWINDOW_SIZE > 0
				WindowPush(&Socket->RxWindow,TcpData,TcpDataLength);
				#endif
				
				Socket->Rxd = TcpData;
				Socket->Rxl = TcpDataLength;
				if(Socket->hook != NULL)
				{
					Socket->hook(Socket);
				}				
			
				TcpSendPacket(Socket,NULL,0,TCPFLAG_ACK,0);
			}		
			break;	
		}
		Socket = Socket->Next;
	}
	#endif
}


/********************************************************************************************
*** 函数名称:  TcpFsmTask
*** 函数描述:  TCP有限状态机处理任务
*** 入    口:  无
*** 出    口:  无
********************************************************************************************/
void	TcpFsmTask(void)
{
	#if	MAX_TCP_SOCKETS > 0
	TCP_SOCKET	*Socket;
	uint32		time;
	int32		DIFF;

	if(LinkLayer.State != PPPS_OPENED)	return;
	

	Socket = TcpFirstSocket;
	while(Socket != NULL)
	{	
		
		#ifdef	USE_TCP_DEBUGER
		{
			static	uint8	RXS = SOCKS_CLOSED;
			static	uint8	TXS = SOCKS_CLOSED;
			
			if(RXS != Socket->RXS || TXS != Socket->TXS)
			{
				RXS = Socket->RXS;
				TXS = Socket->TXS;
				Printf("[RXS=0x%02x,TXS=0x%02x]\r\n",RXS,TXS);
			}
		}
		#endif
		
		
		
		time = NET_TICK_COUNTER;	// 采样当前时间
		if(time < Socket->Time)
		{
			time = time + NET_TICK_LIMITED;
		}

		// 超时服务、采样RTT
		switch(Socket->TXS)
		{
			case	SOCKS_TXSYN:	
				if((time - Socket->Time) > Socket->Timeout)	
				{	// 同步超时服务	
					if(Socket->TOT <= 3)
					{	// 超时不超过3次,重新请求
						Socket->TXS = SOCKS_CONNREQ;
						Socket->TOT = Socket->TOT + 1;
					}
					else
					{	// 超时大于3次返回关闭状态
						//Printf("[TOT=%d]\r\n",Socket->TOT);
						Socket->TXS = SOCKS_CLOSED;
						Socket->RXS = SOCKS_CLOSED;
						Socket->TOT = 0;					
					}
				}
				break;			
			case	SOCKS_SENDREQ:
				if(		((time - Socket->Time) > Socket->RTT)	
					||	(Socket->TxWindow.DatLen > 500) 
				  )
				{	// 填充数据字节数大于500或者填充数据后时间超过RTT
					Socket->TXS = SOCKS_SENDSTART;
					Socket->TOT = 0;
				}
				break;
			case	SOCKS_SENDING:
				if((time - Socket->Time) > Socket->Timeout)
				{	// 发送超时服务
					if(Socket->TOT < 10)
					{	// 超时不超过10次,重新请求
						Socket->TXS = SOCKS_SENDSTART;
						Socket->TOT = Socket->TOT + 1;
					}
					else
					{	// 超时大于10次返回关闭状态
						//Printf("[TOT=%d]\r\n",Socket->TOT);
						Socket->TXS = SOCKS_CLOSED;
						Socket->RXS = SOCKS_CLOSED;
						Socket->TOT = 0;	
						TcpSendPacket(Socket,NULL,0,(TCPFLAG_RST|TCPFLAG_ACK),0);					
					}
				}
				break;			
			case	SOCKS_TXFIN:	
				if((time - Socket->Time) > Socket->Timeout)	
				{	// 关闭超时服务	
					if(Socket->TOT <= 3)
					{	// 超时不超过3次,重新请求
						Socket->TXS = SOCKS_CLOSEREQ;
						Socket->TOT = Socket->TOT + 1;
					}
					else
					{	// 超时大于3次返回关闭状态
						Socket->TXS = SOCKS_CLOSED;
						Socket->TOT = 0;					
					}
				}
				break;	
			
			case	SOCKS_RESTART:		// Added by Yan Zhangjian(C) @ 2008-05-24
				if((time - Socket->Time) > 10)
				{
					Socket->TXS = SOCKS_CLOSED;
				}
				break;	
				
			default:break;
		}// end of switch(Socket->TXS)		
		
		// 发送通道状态迁移
		switch(Socket->TXS)
		{
			case	SOCKS_CLOSED:
				if(Socket->UREQ == UREQ_CONN)
				{
					Socket->UREQ = UREQ_NONE;
					Socket->TXS  = SOCKS_CONNREQ;
				}
				//Socket->TOT = 0;
				break;
			case	SOCKS_CONNREQ:
				{
					uint8	Option[4] = {0x02,0x04,0x00,0x00};
					Option[2] = Socket->MRU >> 8;
					Option[3] = Socket->MRU;
					TcpSendPacket(Socket,Option,4,TCPFLAG_SYN,0);
				}					
				Socket->Time = NET_TICK_COUNTER;
				Socket->TXS  = SOCKS_TXSYN;
				break;				
			case	SOCKS_SYNACK:
				Socket->TXS = SOCKS_OPENED;
				//Socket->TOT = 0;
				break;
			case	SOCKS_OPENED:
				if(Socket->UREQ == UREQ_SEND)
				{
					Socket->UREQ = UREQ_NONE;
					Socket->TXS = SOCKS_SENDREQ;
				}
				else if(Socket->UREQ == UREQ_CLOSE)
				{
					Socket->UREQ = UREQ_NONE;
					Socket->TXS = SOCKS_CLOSEREQ;
				}
				//Socket->TOT = 0;
				break;	
			case	SOCKS_SENDSTART:			// 开始发送				
				Socket->SampRTT = NET_TICK_COUNTER;	// 开始采样RTT
				TcpSendPacket(Socket,NULL,0,(TCPFLAG_ACK|TCPFLAG_PSH),1);
				Socket->Time = NET_TICK_COUNTER;
				Socket->TXS = SOCKS_SENDING;	
				break;
			case	SOCKS_SENDACK:
				time = NET_TICK_COUNTER;		// 结束采样RTT
				if(time < Socket->Time)
				{
					time += NET_TICK_LIMITED;
				} 
				Socket->SampRTT = time - Socket->SampRTT;
				if(Socket->SampRTT < 1)			// RTT下限:1ms
				{
					Socket->SampRTT = 1;
				}
				if(Socket->SampRTT > 10000)		// RTT上限:10s
				{
					Socket->SampRTT = 10000;
				}
				DIFF = Socket->SampRTT - Socket->RTT;
				Socket->RTT = Socket->RTT + 0.125 * DIFF;
				Socket->DEV = Socket->DEV + 0.25 * (abs(DIFF) - Socket->DEV);
				Socket->Timeout = Socket->RTT + 3 * Socket->DEV;
				Socket->TXS = SOCKS_OPENED;
				//Socket->TOT = 0;
				break;
			case	SOCKS_CLOSEREQ:
				TcpSendPacket(Socket,NULL,0,TCPFLAG_FIN,1);
				Socket->Time = NET_TICK_COUNTER;
				Socket->TXS = SOCKS_TXFIN;
				break;
				
				
			case	SOCKS_RESET:		// Added by Yan Zhangjian(C) @ 2008-05-24
				Socket->Time = NET_TICK_COUNTER;
				Socket->TXS  = SOCKS_RESTART;
				break;
				
				
			default:	break;
			
		}// end of switch(Socket->TXS)
		
		// 接收通道状态迁移
		switch(Socket->RXS)
		{
			case	SOCKS_RXSYN:
				if(Socket->TXS == SOCKS_OPENED)
				{
					TcpSendPacket(Socket,NULL,0,TCPFLAG_ACK,0);
				}
				else
				{
					TcpSendPacket(Socket,NULL,0,(TCPFLAG_SYN|TCPFLAG_ACK),0);
				}
				Socket->RXS = SOCKS_OPENED;
				break;
			case	SOCKS_RXFIN:
				TcpSendPacket(Socket,NULL,0,TCPFLAG_ACK,0);
				TcpSendPacket(Socket,NULL,0,TCPFLAG_FIN|TCPFLAG_ACK,0);
				Socket->RXS = SOCKS_CLOSED;
				//Socket->TXS = SOCKS_CLOSED;	// added by Yan Zhangjian(C) @ 2008-04-08 18:27
				break;
			default:	break;
		}// end of switch(Socket->RXS)
		
		if((Socket->TxWindow.DatLen == 0) && (Socket->UREQ == UREQ_SEND))
		{
			Socket->UREQ = UREQ_NONE;
		}

		if(Socket->TxWindow.DatLen > 0)
		{
			if(Socket->TXS == SOCKS_CLOSED)
			{
				//Socket->UREQ = UREQ_CONN;
			}
			if(Socket->TXS == SOCKS_OPENED)
			{
				Socket->UREQ = UREQ_SEND;
			}
		}	

		if(		(Socket->RXS == SOCKS_CLOSED) 
			&&	(Socket->TXS == SOCKS_OPENED)
			&&	(Socket->TxWindow.DatLen == 0))
		{
			TcpSendPacket(Socket,NULL,0,(TCPFLAG_RST|TCPFLAG_ACK),0);
			Socket->TXS = SOCKS_CLOSED;
		}

				
		Socket = Socket->Next;	
	}// end of while(Socket != NULL)
	#endif	
}

/********************************************************************************************
*** 函数名称:  
*** 函数描述:  
*** 入    口:  
*** 出    口:  
********************************************************************************************/
void	TcpInitial(void)
{
	#if	MAX_TCP_SOCKETS > 0
	TcpFirstSocket = NULL;
	#endif
}



/********************************************************************************************
***                     文件结束                                                          ***
********************************************************************************************/

⌨️ 快捷键说明

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