📄 tcp.c
字号:
#include "C:\wql\tcpipsocket\target.h"
#include "C:\wql\tcpipsocket\tcp.h"
#include "C:\wql\tcpipsocket\func.h"
#include "C:\wql\tcpipsocket\ip.h"
#include <string.h>
#include <stdio.h>
UINT16 sender_tcpport;
UINT16 receiver_tcpport;
UINT8 sender_ipaddr[4];
extern UINT8 MY_IP[4];
extern IP_frame IP_IN;
UINT32 initial_sequence_nr;
CONNECTION xdata conxn[MAX_SOCKET_NUM];
UINT8 xdata opt[10] = {0x02, 0x04, 0x05, 0xB4,0x01, 0x01,0x04, 0x02};//最大片长0x05b4(1460)
//**************************************************************
void conxn_save_data(UINT8 nr,UINT8 *SRC,UINT16 data_len);
//*******************************************************************
// SRC_PORT本地端口号
// hdr_len TCP头长度
// nr 连接的号码
// flags TCP的标志字
void tcp_send(UINT16 flags, UINT16 hdr_len,UINT8 nr)
{
//UINT16 result;
UINT8 outbuf[50];
TCPLAYER *tcp;
UINT8 dest[4];
tcp = (TCPLAYER *)&outbuf[12];
// If no connection, then message is probably a reset
// message which goes back to the sender
// Otherwise, use information from the connection.
if (nr == NO_CONNECTION)
{
tcp->tcp_dest = sender_tcpport;
tcp->tcp_src = receiver_tcpport;
tcp->tcp_seq = 0;
tcp->tcp_ack = 0;
memcpy(dest,sender_ipaddr,4);
}
else //if (nr < NO_CONNECTION)
{
// This message is to connected port
tcp->tcp_src = conxn[nr].local_port; //SRC_PORT;
tcp->tcp_dest = conxn[nr].port;
tcp->tcp_seq = conxn[nr].my_sequence;
tcp->tcp_ack = conxn[nr].his_sequence;
memcpy(dest, conxn[nr].ipaddr,4);
}
// Total segment length = header length
// Insert header len
tcp->flags = (hdr_len << 10) | flags;
tcp->tcp_window = conxn[nr].local_window;
tcp->tcp_check = 0;
tcp->tcp_urgent = 0;
// Sending SYN with header options
if (hdr_len == 28)
{
memcpy(&outbuf[32],opt, 8);
}
// Compute checksum including 12 bytes of pseudoheader
// Must pre-fill 2 items in ip header to do this
memcpy(outbuf,dest,4);
memcpy(&outbuf[4],MY_IP,4);
outbuf[8] = 0;
outbuf[9] = 6; //proto is tcp
outbuf[10] = 0;
outbuf[11] = hdr_len;
// Sum source_ipaddr, dest_ipaddr, and entire TCP message
tcp->tcp_check = ~Check_sum(outbuf , 12 + hdr_len);
// tcp->tcp_check = 0;
IP_Send(&outbuf[12], hdr_len,dest, IP_TCP_PROT, 120);
if(flags != FLG_ACK)
{
conxn[nr].old_sequence = conxn[nr].my_sequence;
conxn[nr].my_sequence++;
conxn[nr].timer = TCP_TIMEOUT;
}
else
conxn[nr].timer = 0xff; //TCP_TIMEOUT;
}
//--------------------------------------------------------------------
void init_tcp(void)
{
memset((UINT8 *)&conxn[0], 0, sizeof(conxn));
initial_sequence_nr = 1;
}
//------------------------------------------------------------------------
// inbuf - a ip packet pointer
// 这个函数是接收一个TCP数据包,找到一个新的连接,或已有的连接,完成连接的状态迁移
// 并将TCP包的数据送到连接的输入缓冲区里,便于应用层操作。
// 另外当发送时出现丢包的现象,则对方会不停的发回上次的确认号,因此这个函数也可以根据
// 这个现象进行数据的冲传。
//*************************************************************************
void TCP_Interpret(UINT8 *inbuf, struct pseudotcp *tcp_chk)
{
TCPLAYER *tcp;
IPLAYER *ip;
UINT16 sum,data_len;
UINT8 TEMP[12];
UINT8 nr,i,header_len;
// IP headers = 20 bytes
tcp = (TCPLAYER *)(inbuf + 20);
ip = (IPLAYER *)inbuf ;
// If the checksum is zero it means that the sender did not compute
// it and we should not try to check it.
if (tcp->tcp_check != 0)
{
memcp(TEMP,inbuf+8,12);
memcp(inbuf+8,(UINT8 *)tcp_chk,12);
sum = Check_sum(inbuf + 8, ip->ip_tlen - 8); //the length contain pseudoheader
memcp(inbuf+8,TEMP,12); //reload the old ip packet
// if (sum != 0xFFFF) return;
}
// Capture sender's IP address and port number
memcp(sender_ipaddr, ip->ip_src,4);
sender_tcpport = tcp->tcp_src; //这里得到两个端口号是为了发送NO CONNECTION准备的.
receiver_tcpport = tcp->tcp_dest;
header_len = (tcp->flags & 0xF000) >> 10; //tcp header length
data_len = ip->ip_tlen - header_len - 20; //tcp data length
// look up same connection already ok?
for (i=0; i < MAX_SOCKET_NUM; i++)
{
if(conxn[i].state != STATE_CLOSED)
{
if (tcp->tcp_dest == conxn[i].local_port) //通过判断端口号来识别是否有连接等待此数据包.
{
nr = i;
break;
}
}
}
// If i = MAX_SOCKET_NUM,that means we are not connected.
// 发复位命令给对方并返回.
if (i == MAX_SOCKET_NUM)
{
tcp_send(FLG_RST,20,NO_CONNECTION);
return;
}
// By now we should have a connection number in range of 0-MAX_SOCKET_NUM
//if received a reset flag then clear connection and return
if (tcp->flags & FLG_RST)
{
printf("received rst\n");
//Init_cn(&conxn[nr]);
conxn[nr].state = STATE_CLOSED; //这里还不能将状态置为STATE_CLOSED,因为有可能是STATE_LISTEN
return; //解决的方法是在上层的轮询中,当置于LISTEN状态的变为了CLOSED,则将其变回LISTEN
}
else if ((tcp->flags & (FLG_ACK |FLG_SYN )) == 0) return; //no ack then return.
conxn[nr].inactivity = INACTIVITY_TIME; //收到数据就更新.
switch (conxn[nr].state)
{
case STATE_CLOSED:
//这里是不可能到的.
break;
case STATE_LISTEN:
if ((tcp->flags & FLG_SYN) && ((tcp->flags & FLG_ACK) == 0)) //only syn
{
memcp(conxn[nr].ipaddr, ip->ip_src,4); //此处建立了一个SOCKET连接
conxn[nr].port = tcp->tcp_src;
conxn[nr].his_sequence = 1 + tcp->tcp_seq;
conxn[nr].his_ack = tcp->tcp_ack;
conxn[nr].local_port = tcp->tcp_dest;
conxn[nr].my_sequence = initial_sequence_nr;
conxn[nr].his_window = tcp->tcp_window;
initial_sequence_nr += 64000L;
tcp_send(FLG_SYN | FLG_ACK, 28, nr); //send syn ack
conxn[nr].state = STATE_SYN_RCVD;
}
else
{
tcp_send(FLG_RST, 20, NO_CONNECTION);
}
break;
case STATE_SYN_RCVD:
// He may already be sending me data - should process it
conxn[nr].his_sequence += data_len;
conxn[nr].his_ack = tcp->tcp_ack;
if (tcp->flags & FLG_FIN)
{
conxn[nr].his_sequence++;
tcp_send(FLG_ACK, 20,nr);
conxn[nr].state = STATE_CLOSE_WAIT;
tcp_send(FLG_FIN | FLG_ACK, 20, nr);
conxn[nr].state = STATE_LAST_ACK;
// Entered LAST ACK state
}
else if (conxn[nr].his_ack == conxn[nr].my_sequence) //ack is for me?
{
conxn[nr].state = STATE_ESTABLISHED; //建立了被动连接
conxn[nr].his_window = tcp->tcp_window;
conxn[nr].timer = 0xff; //TCP_TIMEOUT;
}
break;
case STATE_ESTABLISHED: //在这里连接可能是由被动建立的也可能由主动建立的,因此要考虑周全
conxn[nr].his_ack = tcp->tcp_ack;
conxn[nr].his_window = tcp->tcp_window;
//if(conxn[nr].his_window != 0)
if (tcp->flags & FLG_FIN)
{
conxn[nr].his_sequence++;
tcp_send(FLG_ACK, 20, nr);
tcp_send(FLG_FIN | FLG_ACK, 20, nr);
conxn[nr].state = STATE_LAST_ACK;
break;
}
if (data_len != 0)
{
if(tcp->tcp_seq == conxn[nr].his_sequence) //如果对方的序号不对,则只向其发送上次的seq的ack
{
if((data_len ==1)&& (conxn[nr].local_window==0))
{
printf("data invalid\n");
break;
}
conxn_save_data(nr,inbuf+header_len+20,data_len);//把收到的数据存放到SOCKET的接收缓存中并调整窗口大小
conxn[nr].his_sequence += data_len; //调整
}
tcp_send(FLG_ACK, 20, nr); // Send ACK
}
if(conxn[nr].his_ack == conxn[nr].my_sequence) //peer ack is my sequence
{
conxn[nr].wait_ack_num = 0; //将等待ACK的TCP包的数量清0,表示每个包都收到了ACK
conxn[nr].S_R_ACK_NUM = 0;
conxn[nr].timer = 0xff; //TCP_TIMEOUT;
//conxn[nr].inactivity = INACTIVITY_TIME; //前面已经更新了
}
else if(conxn[nr].his_ack < conxn[nr].my_sequence) //是中间过程的ACK,要调整等待TCP包的标志
{
{
UINT8 i;
for(i=0;i<conxn[nr].wait_ack_num;i++)
{
if(conxn[nr].tcp_wait_ack[i].State == 1) //看这一包收到ACK了吗
{
if(conxn[nr].his_ack < conxn[nr].tcp_wait_ack[i].expect_ack)
{
if(conxn[nr].his_ack == conxn[nr].tcp_wait_ack[i].TCP_HEAD.tcp_seq) //这里是当连续收到同一个ACK时,表示要重传这一包后面的一包。
//这个判断可能是多余的,因为如果不等的话,就全乱了
{
conxn[nr].tcp_wait_ack[i].R_ACK_NUM++; //上一包接收到ACK的次数,说明本包是否需要重传
if(conxn[nr].tcp_wait_ack[i].R_ACK_NUM ==3)
{
printf("require repeat\n");
conxn[nr].tcp_wait_ack[i].R_ACK_NUM = 3;
conxn[nr].S_R_ACK_NUM = 3; //表示有需要重传的包
}
}
break; //已经调整完毕,跳出FOR循环
}
conxn[nr].tcp_wait_ack[i].State = 0; //置本包已经成功收到ACK标志。
conxn[nr].tcp_wait_ack[i].R_ACK_NUM = 0;
}
}
}
}
//else printf("his ack too big\n"); //这种情况是不可能出现的。
break;
case STATE_CLOSE_WAIT:
// With this code, should not get here
break;
case STATE_LAST_ACK: //这里是当被动连接收到一个FIN并发送了FIN ACK后,又收到了ACK,则将连接关闭
conxn[nr].his_ack = tcp->tcp_ack;
if (tcp->tcp_ack == conxn[nr].my_sequence)
{
printf("received last ack\n");
conxn[nr].state = STATE_CLOSED;
}
break;
case STATE_FIN_WAIT_1: //我方已经先发出了FIN命令,此时如果又收到对方的FIN则可以关闭连接了
conxn[nr].his_sequence += data_len;
conxn[nr].his_ack = tcp->tcp_ack;
if (tcp->flags & FLG_FIN)
{
conxn[nr].his_sequence++;
tcp_send(FLG_ACK, 20, nr);
if (tcp->tcp_ack == conxn[nr].my_sequence)
{
conxn[nr].state = STATE_CLOSED;
}
else conxn[nr].state = STATE_CLOSING;
}
else if (tcp->tcp_ack == conxn[nr].my_sequence) //如果没有收到FIN,而只是ACK
{
conxn[nr].state = STATE_FIN_WAIT_2;
}
break;
case STATE_FIN_WAIT_2: //我方发送了FIN但是对方还没有回FIN,还继续发送数据,则要处理他
conxn[nr].his_sequence += data_len;
conxn[nr].his_ack = tcp->tcp_ack;
if (tcp->flags & FLG_FIN)
{
conxn[nr].his_sequence++; // For his FIN flag
tcp_send(FLG_ACK, 20, nr);
conxn[nr].state = STATE_CLOSED;
}
break;
case STATE_CLOSING: //我先送FIN可对方回答的ACK不是我的,才进入这个状态,此时只等待ACK
conxn[nr].his_ack = tcp->tcp_ack;
if (tcp->tcp_ack == conxn[nr].my_sequence)
{
conxn[nr].state = STATE_CLOSED;
}
break;
case STATE_ACT_SYN_SENT: //active to establish the socket 已经发出了SYN命令,等待对方的SYN ACK
conxn[nr].his_ack = tcp->tcp_ack;
if((conxn[nr].his_ack == conxn[nr].my_sequence) &&(tcp->flags & FLG_SYN))
{
conxn[nr].his_sequence = 1 + tcp->tcp_seq;
conxn[nr].his_window = tcp->tcp_window;
tcp_send(FLG_ACK, 20, nr);
conxn[nr].state = STATE_ESTABLISHED; //tcp socket established
}
else
{
tcp_send(FLG_RST, 20, nr);
conxn[nr].state = STATE_CLOSED;
}
break;
default:
break;
}
}
//------------------------------------------------------------------------
//
// buf -- tcp data buffer存放TCP数据的缓冲区
// len -- TCP 数据长度
// nr -- connection number
// 返回实际传送的长度。
//------------------------------------------------------------------------
// 向第NR个连接发送长度为LEN的数据,数据存放在OUTBUF中,OUTBUF是一个IP型的PACKET。
UINT16 TCP_data_send(UINT8 *buf, UINT16 len, UINT8 nr)
{
UINT16 MIN_PACKET_SIZE;
UINT16 REMAINING; //剩余的
UINT16 SENT; //已经传送的数据长度
UINT16 one_send_len;
if(len==0) return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -