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

📄 tcp.c

📁 RTL8019以太网开发板资料
💻 C
📖 第 1 页 / 共 2 页
字号:
		}
		p1 = p2;
	}
}


//------------------------------------------------------------------------
// This handles incoming TCP messages and manages the TCP state machine
// Note - both the SYN and FIN flags consume a sequence number.
// See "TCP/IP Illustrated, Volume 1" Sect 18.6 for info on TCP states
// See "TCP/IP Illustrated, Volume 1" Sect 17.3 for info on flags
//------------------------------------------------------------------------
void TCPReceive(void)
{
   UWORK8 i, j,nr;
   UWORK16 result, header_len, data_len, len;
   ST_IP_HEAD_FORMAT StrIp;
   ST_TCP_FORMAT strTcp;
   UWORK16 sum, TcpFlag;		   //TcpFlag为TCP的标志位,是偏移量后6位
   UWORK32 RcvIPAdrr;				//接收的IP地址
   UWORK8 *pucTCPData;
   
    if(FALSE == gbHaveFragment)
    {                             // 没有分片的数据 
	   memcpy((UWORK8 *)&StrIp.ucVerAndLen, (UWORK8 *)&gstaRevEthernet.ucaPacket[0], 20);	  //读取IP头数据
       memcpy((UWORK8 *)&strTcp.usSourcePort, (UWORK8 *)&gstaRevEthernet.ucaPacket[20], 20);  //读取TCP头数据
	}
    else
    {                             // 分片的数据 
		memcpy((UWORK8 *)&StrIp.ucVerAndLen, (UWORK8 *)&gucaSegTemp[0], 20);	  //读取IP头数据
        memcpy((UWORK8 *)&strTcp.usSourcePort, (UWORK8 *)&gucaSegTemp[20], 20);  //读取TCP头数据
	}
	len = StrIp.usTotalLen;
	len -= 20;		 //长度是IC的总数据长度减去IP头的长度。其实就是IP数据包的长度.
	//计算TCP的校验和。是从IP的数据加上源IP和目标IP的值.而IP头的后8位就是源IP和目标IP,所以从12位开始
	sum = cksum((UWORK8 *)&gstaRevEthernet.ucaPacket[12], (8 + len));
	sum += 0x0006;     			 //计算的校验和加上TCP协议的值
	sum += len;					 //计算的校验和加上TCP包的长度
	result = (UWORK16)(sum + (sum >> 16));		   // In case there was a carry, add it back around
		
	if (result != 0xFFFF)			//如果校验和不对就返回
	{
		return;
    }

   SourcePort = NetParameter.Port_Local;		//本地端口号 
   DesPort = strTcp.usSourcePort;		    //在接收的TCP数据包中,源端口就是发送方的端口 
   memcpy((UWORK8 *)&RcvIPAdrr,(UWORK8 *)&StrIp.ucSourceIP[0],IP_LEN);          //回复TCP时,目标IP就是接收时的IP中的源IP,也就是对方的IP
   TcpFlag = strTcp.ucMOVENUM & 0x003f;		   //TCP的标志位
  
   nr = 0xff;
   for (i=0; i < 2; i++)	   //判断IP及端口号是否相同
   {
      if ((RcvIPAdrr == StrConnection_buf[i].ipaddr) && (DesPort == StrConnection_buf[i].usDesPort))
      {   
         nr = i;
         break;
      }       
   }
   if(i == 2)		//表示此连接不在这里面
   {
		if (TcpFlag & FLG_SYN)		   //表示接收的同步标志位
		{
			for (j=0; j < 2; j++)
			{
				if (StrConnection_buf[j].ipaddr == 0)	 //表示此连接为空
				{
					nr = j;
					StrConnection_buf[nr].state = STATE_LISTEN;	   //初始化连接点
					break;
				}
			}
         	if (j == 2) return;	   //表示连接用完了
      	}
	}
	if(nr > 1)
	{
		return;
	}
	memcpy((UWORK8 *)&StrConnection_buf[nr].ipaddr,(UWORK8 *)&StrIp.ucSourceIP[0],IP_LEN);          //回复TCP时,目标IP就是接收时的IP中的源IP,也就是对方的IP
    StrConnection_buf[nr].usDesPort = strTcp.usSourcePort;		    //在接收的TCP数据包中,源端口就是发送方的端口 

   if (strTcp.ucSERIESNUM > 0xFFFFFF00L) 
   {
		StrConnection_buf[nr].ipaddr = 0;
		tcp_ReBack(FLG_RST, 20, NO_CONNECTION);			//回复结束的确认位
		return;		
   }

   if (TcpFlag & FLG_RST)		   //接收到重置位,不回复
   {
      // An RST does not depend on state at all.  And it does
      // not count as data so do not send an ACK here.  Close
      // connection
      StrConnection_buf[nr].ipaddr = 0;
      return;
   }
	else if (TcpFlag & FLG_SYN)		   //接收到同步位
	{
	   // A SYN segment only makes sense if connection is in LISTEN 
	   if ((StrConnection_buf[nr].state != STATE_LISTEN) &&			//不是监听或结束位
          (StrConnection_buf[nr].state != STATE_CLOSED))
		{
			StrConnection_buf[nr].ipaddr = 0;			
		  	tcp_ReBack(FLG_RST, 20, NO_CONNECTION);			   //并发送重置位
		  	return;		
		}
	}
	else if ((TcpFlag & FLG_ACK) == 0)		   //表示收到确认位就不用理它
	{
		// Incoming segments except SYN or RST must have ACK bit set
	 	// See TCP/IP Illustrated, Vol 2, Page 965
      // Drop segment but do not send a reset
//		if (debug) serial_send("TCP: Error, rcvd segment has no ACK\r");
		return;
	}

   header_len =  (strTcp.ucMOVENUM & 0xF000) >> 10;	 //记算TCP头的长度   data_len = len - header_len;						 //len在上面已算过是总个TCP的长度
   switch(StrConnection_buf[nr].state)
   {
   		case STATE_CLOSED:   			  // 监听来自远方TCP端口的连接请求
		case STATE_LISTEN:   			  // 监听来自远方TCP端口的连接请求
			if ((TcpFlag & FLG_SYN) && ((TcpFlag & FLG_ACK) == 0))			//收到同步信号
			{
				// Capture his starting sequence number and generate
				// my starting sequence number
				// Fill in connection information
				StrConnection_buf[nr].state = STATE_LISTEN;
				StrConnection_buf[nr].His_SERIESNUM = strTcp.ucSERIESNUM + 1;	   //接收的确认号等于序列号
				StrConnection_buf[nr].his_TRUECODE = strTcp.ucTRUECODE;   //接收的序列号等确认号
				// Use system clock for initial sequence number
				EA = 0;
				StrConnection_buf[nr].My_SERIESNUM = initial_sequence_nr;
				initial_sequence_nr += 64000L;
				EA = 1;                  
				
				// Send header options with the next message
				// Since timestamps are optional and we do not use
				// them, do not have to send them 
				// After sending the SYN ACK the client browser will
				// blast me with 2 messages, an ACK, and a HTTP GET
				tcp_ReBack(FLG_SYN | FLG_ACK, 28, nr);
				
				// My SYN flag increments my sequence number
				// My sequence number is always updated to point to 
				// the next byte to be sent.  So the incoming ack
				// number should equal my sequence number  
				StrConnection_buf[nr].My_SERIESNUM++;
				StrConnection_buf[nr].state = STATE_SYN_RECEIVED;
//				if (debug) serial_send("TCP: Entered SYN RCVD state\r");
			}
			else 
			{
				// Sender is out of sync so send reset
				StrConnection_buf[nr].ipaddr = 0;

				tcp_ReBack(FLG_RST, 20, NO_CONNECTION);  
			} 
			break;
		case STATE_SYN_RECEIVED:
			// He may already be sending me data - should process it
			StrConnection_buf[nr].His_SERIESNUM += data_len;
			StrConnection_buf[nr].his_TRUECODE = strTcp.ucTRUECODE;
			StrConnection_buf[nr].My_SERIESNUM = strTcp.ucTRUECODE;
			if (TcpFlag & FLG_FIN)
			{
				// His FIN counts as a byte of data
				StrConnection_buf[nr].His_SERIESNUM++;
				tcp_ReBack(FLG_ACK, 20, nr);
				StrConnection_buf[nr].state = STATE_CLOSE_WAIT;
//				if (debug) serial_send("TCP: Entered CLOSE_WAIT state\r");
				
				// At this point we would normally wait for the	application
				// to close.  For now, send FIN right away.
				tcp_ReBack(FLG_FIN | FLG_ACK, 20, nr);
				StrConnection_buf[nr].My_SERIESNUM++;   // For my FIN
				StrConnection_buf[nr].state = STATE_LAST_ACK;
//				if (debug) serial_send("TCP: Entered LAST ACK state\r");
			}
			// Make sure he is ACKing my SYN
			else if (strTcp.ucTRUECODE == StrConnection_buf[nr].My_SERIESNUM)
			{
				StrConnection_buf[nr].state = STATE_ESTABLISHED;
//				if (debug) serial_send("TCP: Entered ESTABLISHED state\r");
				// If sender sent data ignore it and he will resend
				// Do not send response because we received no
				// data... wait for client to send something to me 
			}
      		break;
		case STATE_SYN_SEND:	 		  //作为客户端时有效
			break;
		case STATE_ESTABLISHED:
			StrConnection_buf[nr].his_TRUECODE = strTcp.ucTRUECODE;

			if (TcpFlag & FLG_FIN)		   //表示结束
			{
				// His FIN counts as a byte of data
				StrConnection_buf[nr].His_SERIESNUM++;
				tcp_ReBack(FLG_ACK, 20, nr);
				StrConnection_buf[nr].state = STATE_CLOSE_WAIT;
//				if (debug) serial_send("TCP: Entered CLOSE_WAIT state\r");
				
				// At this point we would normally wait for the	application
				// to close.  For now, send FIN immediately.
				tcp_ReBack(FLG_FIN | FLG_ACK, 20, nr);
				StrConnection_buf[nr].My_SERIESNUM++;   // For my FIN
				StrConnection_buf[nr].state = STATE_LAST_ACK;
//				if (debug) serial_send("TCP: Entered LAST ACK state\r");
			}
			else if((TcpFlag & FLG_ACK) && (TcpFlag & FLG_PSH))		   //收到数据位
			{
				// Received normal TCP segment from sender with data
				// Send an ACK immediately and pass the data on to
				// the application
				StrConnection_buf[nr].His_SERIESNUM += data_len;
				tcp_ReBack(FLG_ACK, 20, nr); 		// Send ACK
				if(FALSE == gbHaveFragment)                                           // 没有分片的数据 
		        {
		            pucTCPData = &gstaRevEthernet.ucaPacket[header_len + 20];		  //表示TCP的包头长度
		        }
		        else
		        {
		            pucTCPData = &gucaSegTemp[header_len + 20];                     //表示TCP的包头长度 
		        }
				if(data_len != 0)
				{
					SerialSendbuf(pucTCPData,data_len);		   //发送给串口
				}

				// Send pointer to start of TCP payload
				// http_server increments my sequence number when 
				// sending so don't worry about it here
//				result = http_server(inbuf, header_len, nr, 0);
				
				// Start timer to close conxn if no activity
				StrConnection_buf[nr].inactivity = INACTIVITY_TIME;
			}
			else if (TcpFlag & FLG_ACK)		   //表示发送数据后收到的确认信号
			{
				StrConnection_buf[nr].My_SERIESNUM += StrConnection_buf[nr].SLen;
			}	

			break;
      	case STATE_CLOSE_WAIT:
      // With this code, should not get here
//     		if (debug) serial_send("TCP: Oops! Rcvd unexpected message\r");
      		break;
		case STATE_LAST_ACK:
			StrConnection_buf[nr].his_TRUECODE = strTcp.ucTRUECODE;
			// If he ACK's my FIN then close
			if (strTcp.ucTRUECODE == StrConnection_buf[nr].My_SERIESNUM)
			{
				StrConnection_buf[nr].state = STATE_CLOSED;
				StrConnection_buf[nr].ipaddr = 0;  // Free up struct area
				just_closed = TRUE;
			}
			break;
		case STATE_FIN_WAIT_1:
			// He may still be sending me data - should process it
			StrConnection_buf[nr].His_SERIESNUM += data_len;
			StrConnection_buf[nr].his_TRUECODE = strTcp.ucTRUECODE;
			
			if (TcpFlag & FLG_FIN)
			{
				// His FIN counts as a byte of data
				StrConnection_buf[nr].His_SERIESNUM++;
				tcp_ReBack(FLG_ACK, 20, nr);
				
				// If he has ACK'd my FIN then we can close connection
				if (strTcp.ucTRUECODE == StrConnection_buf[nr].My_SERIESNUM)
				{
					StrConnection_buf[nr].state = STATE_TIME_WAIT;
//					if (debug) serial_send("TCP: Entered TIME_WAIT state\r");
					StrConnection_buf[nr].state = STATE_CLOSED;
					StrConnection_buf[nr].ipaddr = 0;  // Free up connection
					just_closed = TRUE;
				}
				else
				{
					// He has not ACK'd my FIN.  This happens when there is a simultaneous
					// close - I got his FIN but he has not yet ACK'd my FIN
					StrConnection_buf[nr].state = STATE_CLOSING;
//					if (debug) serial_send("TCP: Entered CLOSING state\r");
				}
			}
			else if(strTcp.ucTRUECODE == StrConnection_buf[nr].My_SERIESNUM)
			{
				// He has ACK'd my FIN but has not sent a FIN yet himself
				StrConnection_buf[nr].state = STATE_FIN_WAIT_2;
//				if (debug) serial_send("TCP: Entered FIN_WAIT_2 state\r");
			}
			break;
		case STATE_FIN_WAIT_2:
			// He may still be sending me data - should process it
			StrConnection_buf[nr].His_SERIESNUM += data_len;
			StrConnection_buf[nr].his_TRUECODE = strTcp.ucTRUECODE;
			
			if (TcpFlag & FLG_FIN)
			{
				StrConnection_buf[nr].His_SERIESNUM++; // For his FIN flag
				tcp_ReBack(FLG_ACK, 20, nr);
				StrConnection_buf[nr].state = STATE_TIME_WAIT;
//				if (debug) serial_send("TCP: Entered TIME_WAIT state\r");
				StrConnection_buf[nr].state = STATE_CLOSED;
				StrConnection_buf[nr].ipaddr = 0;  // Free up struct area
				just_closed = TRUE;
			}
			break;
		case STATE_TIME_WAIT:
		// With this code, should not get here
//		if (debug) serial_send("TCP: Oops! In TIME_WAIT state\r");
			break;
		case STATE_CLOSING:
			// Simultaneous close has happened. I have received his FIN
			// but he has not yet ACK'd my FIN.  Waiting for ACK.
			// Will not receive data in this state
			StrConnection_buf[nr].his_TRUECODE = strTcp.ucTRUECODE;
			if (strTcp.ucTRUECODE == StrConnection_buf[nr].My_SERIESNUM)
			{
				StrConnection_buf[nr].state = STATE_TIME_WAIT;
	//			if (debug) serial_send("TCP: Entered TIME_WAIT state\r");
			
			// Do not send any response to his ACK
				StrConnection_buf[nr].state = STATE_CLOSED;
				StrConnection_buf[nr].ipaddr = 0;  // Free up struct area
				just_closed = TRUE;
			}
			break;
		default:
//			if (debug) serial_send("TCP: Error, no handler\r");
			break;
      }
//SerialSendbuf(&StrConnection_buf[nr].state, 1);
//SerialSendbuf((unsigned char *)&strTcp.ucSERIESNUM, 4);
//SerialSendbuf((unsigned char *)&strTcp.ucTRUECODE, 4);
//SerialSendbuf((unsigned char *)&StrConnection_buf[nr].My_SERIESNUM, 4);
//SerialSendbuf((unsigned char *)&StrConnection_buf[nr].His_SERIESNUM, 4);
//SerialSendbuf((unsigned char *)&StrConnection_buf[nr].his_TRUECODE, 4);
}

⌨️ 快捷键说明

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