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