📄 tcp.c
字号:
//-----------------------------------------------------------------------------
// 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 + -