📄 tcp.c
字号:
//-----------------------------------tcp.c-----------------------------
//#define DEBUG
#include<string.h>
#include"includes.h"
typedef enum {
CLOSED = 0, // 没有连接
LISTEN = 1, // 收到被动打开;等待SYN
SYN_SENT = 2, // 已经发送SYN;等待ACK
SYN_RCVD = 3, // 已发送SYN+ACK;等待ACK
ESTABLISHED = 4, // 连接已建立;数据传输在进行
FIN_WAIT1 = 5, // 第一个FIN已经发送;等ACK
FIN_WAIT2 = 6, // 第一个FIN的ACK已收到;等第二个FIN
CLOSE_WAIT = 7, // 收到第一个FIN,已发送ACK;等待应用程序关闭
TIME_WAIT = 8, // 收到第二个FIN,已发送ACK;等待2MSL超时
LAST_ACK = 9, // 已发送第二个FIN;等待ACK
CLOSING = 10 // 双方都已决定同时关闭
} TCPState;
ulong idata isn;
uint xdata sender_tcpport,MinePort;
static ulong xdata sender_ipaddr;
TCB xdata conn[NO_CONN];
//Options: MSS (4 bytes), NOPS (2 bytes), Selective ACK (2 bytes)
uchar code opt[10] = {
0x02, 0x04, 0x05, 0xB4,
0x01, 0x01,
0x04, 0x02};
/*****************************************
初始化TCP
******************************************/
void init_tcp(void)
{
memset(conn, 0, sizeof(conn));
isn = 1;
}
/*****************************************
TCP发送
******************************************/
void tcp_send(uint flags, uint hdr_len, uchar cn_id)
{
ulong idata sum, dest;
uint idata result;
Tcp_Header xdata * tcp;
Ip_Header xdata * ip;
tcp = (Tcp_Header xdata *)(outbuf + 34); //14以太网头 + 20IP头
ip = (Ip_Header xdata *)(outbuf + 14);
if (cn_id == NO_CONN)
{
tcp->source_port = MinePort;
tcp->dest_port = sender_tcpport;
tcp->sn = 0;
tcp->ack_sn = 0;
dest = sender_ipaddr;
}
else if (cn_id < 5)
{
tcp->source_port = MinePort;
tcp->dest_port = conn[cn_id].port;
tcp->sn = conn[cn_id].my_sn;
tcp->ack_sn = conn[cn_id].his_sn;
dest = conn[cn_id].ipaddr;
}
else
{
return; //连接数超限
}
tcp->flags = (hdr_len << 10) | flags;
tcp->window = 1024;
tcp->checksum = 0;
tcp->urgent_ptr = 0;
// Sending SYN with header options
if (hdr_len == 28)
{
memcpy(&tcp->options, opt, 8);
}
ip->dest_ipaddr = dest;
ip->source_ipaddr = myipaddr;
//伪首部源地址和目标地址
sum = (ulong)cksum(outbuf + 26, 8 + hdr_len);
//伪首部协议,首部长度
sum += (ulong)0x0006;
sum += (ulong)hdr_len;
//进位
result = (uint)(sum + (sum >> 16));
tcp->checksum = ~result;
ip_send(outbuf, dest, TCP_TYPE, hdr_len);
//(Re)start TCP retransmit timer
conn[cn_id].timer = TCP_TIMEOUT;
}
/*****************************************
tcp重传
******************************************/
void tcp_resend(void)
{
static uchar idata retries = 0;
uchar idata cn_id;
//扫描活动连接
for (cn_id = 0; cn_id < 5; cn_id++)
{
if ((conn[cn_id].ipaddr != 0) && (conn[cn_id].timer))
{
conn[cn_id].timer--;
if (conn[cn_id].timer == 0)
{
if (conn[cn_id].state != ESTABLISHED)
{
tcp_send(FLG_RST, 20, cn_id);
conn[cn_id].ipaddr = 0;
return;
}
else
{
if (conn[cn_id].his_ack > conn[cn_id].my_sn)
{
tcp_send(FLG_RST, 20, cn_id);
conn[cn_id].ipaddr = 0;
return;
}
if (conn[cn_id].his_ack < conn[cn_id].my_sn)
{
retries++;
if (retries <= 2)
{
http_server(conn[cn_id].query, 0, cn_id, 1);
conn[cn_id].inactivity = INACTIVITY_TIME;
}
else
{
tcp_send(FLG_RST, 20, cn_id);
conn[cn_id].ipaddr = 0;
}
}
}
}
}
}
}
/*****************************************
关闭不活动的连接
******************************************/
void tcp_inactivity(void)
{
uchar idata cn_id;
for (cn_id = 0; cn_id < 5; cn_id++)
{
if ((conn[cn_id].ipaddr != 0) &&
(conn[cn_id].state == ESTABLISHED) &&
(conn[cn_id].inactivity))
{
conn[cn_id].inactivity--;
if (conn[cn_id].inactivity == 0)
{
tcp_send((FLG_ACK | FLG_FIN), 20, cn_id);
conn[cn_id].my_sn++;
conn[cn_id].state = FIN_WAIT1;
TRACE("CONNECT CLOSED",&cn_id,1,0);
}
}
}
}
/*****************************************
查找连接
若连接已经建立返回连接1
连接没建立返回空记录0
连接已满NO_CONN
******************************************/
uchar conn_search(ulong IPSrc,uint PortSrc,uchar * cn_id)
{
uchar i;
for (i=0; i < NO_CONN; i++)
{
if( (IPSrc == conn[i].ipaddr) && (PortSrc == conn[i].port) )
{
*cn_id = i;
return (1);
}
}
/*连接没建立查找空记录*/
for (i=0; i < NO_CONN; i++)
{
if( conn[i].ipaddr == 0 )
{
*cn_id = i;
return (0);
}
}
/*连接已满*/
return NO_CONN;
}
void tcp_receive(uchar xdata * inbuf, uint len)
{
uchar cn_id,res;
ulong idata sum=0L;
uint idata result, head_len, data_len;
Ip_Header xdata * ip;
Tcp_Header xdata * tcp;
ip = (Ip_Header xdata *)(inbuf + 14);
tcp = (Tcp_Header xdata *)(inbuf + 34);
//加上伪首部计算校验和
sum = (ulong)cksum(inbuf + 26, 8 + len);//伪首部源地址和目标地址
sum += (ulong)0x0006; //伪首部协议,TCP总长度
sum += (ulong)len; //TCP总长度
result = (uint)(sum + (sum >> 16)); //进位处理
if (result != 0xFFFF) //比较
return;
//请求的端口不被接受
if (tcp->dest_port != HTTP_PORT && tcp->dest_port != CUSTOM_PORT)
{
tcp_send(FLG_RST, 20, NO_CONN);//修改该函数添加源端口和目的端口
TRACE("tcp->dest_port Err",NULL,0,0);
return;
}
MinePort = tcp->dest_port;
res = conn_search(ip->source_ipaddr,tcp->source_port,&cn_id);
if(res == NO_CONN)
return;
if( (res == 0) && (tcp->flags & FLG_SYN) )//建立连接
{
conn[cn_id].state = LISTEN;
TRACE("NEW CONN ID = ",&cn_id,1,0);
}
if (tcp->sn > 0xFFFFFF00L) //序号太大
{
TRACE("EXCEED SN",NULL,0,0);
conn[cn_id].ipaddr = 0;
conn[cn_id].state = CLOSED;
tcp_send(FLG_RST, 20, NO_CONN);
return;
}
if (tcp->flags & FLG_RST)//收到RST报文
{
conn[cn_id].ipaddr = 0;
conn[cn_id].state = CLOSED;
TRACE("R: FLG_RST STATE = CLOSED",NULL,0,0);
return;
}
else if (tcp->flags & FLG_SYN)
{
TRACE("R: FLG_SYN",NULL,0,0);
//服务器被动打开初始态为LISTEN,收到SYN会转换到RCVD
if ( (conn[cn_id].state != LISTEN) && (conn[cn_id].state != CLOSED) ) //非法SYN
{
conn[cn_id].ipaddr = 0;
conn[cn_id].state = CLOSED;
tcp_send(FLG_RST, 20, NO_CONN);
TRACE("INVALID SYN STATE = CLOSED",NULL,0,0);
return;
}
}
else if ((tcp->flags & FLG_ACK) == 0) //除RST、SYN报文外都要设置ACK位
{
return;
}
//首部长度包括选项=高4位 X 4
head_len = (tcp->flags & 0xF000) >> 10;
data_len = len - head_len;
switch (conn[cn_id].state)
{
case CLOSED:
case LISTEN:
if ((tcp->flags & FLG_SYN) && ((tcp->flags & FLG_ACK) == 0)) //收到SYN报文段
{
TRACE("R: SYN @LISTEN HIS_SN = ",CP &tcp->sn,4,0);
conn[cn_id].ipaddr = ip->source_ipaddr;
conn[cn_id].port = tcp->source_port;
conn[cn_id].state = LISTEN;
conn[cn_id].his_sn = tcp->sn + 1; //将接收到的序号加1用作ack
conn[cn_id].his_ack = tcp->ack_sn;
conn[cn_id].my_sn = isn;
isn += 64000L;
tcp_send(FLG_SYN | FLG_ACK, 28, cn_id);
TRACE("T: SYN+ACK MY_SN = ",CP &conn[cn_id].my_sn,4,0);
TRACE("T: SYN+ACK ACK_SN = ",CP &conn[cn_id].his_sn,4,0);
conn[cn_id].my_sn++;
conn[cn_id].state = SYN_RCVD;
TRACE("STATE = SYN_RCVD",NULL,0,0);
}
else
{
conn[cn_id].ipaddr = 0;
tcp_send(FLG_RST, 20, NO_CONN);
TRACE("T: RST @LISTEN",NULL,0,0);
}
break;
//已发送SYN+ACK;等待ACK
case SYN_RCVD:
conn[cn_id].his_sn += data_len;
conn[cn_id].his_ack = tcp->ack_sn;
if (tcp->ack_sn == conn[cn_id].my_sn) //收到ACK
{
conn[cn_id].state = ESTABLISHED;
TRACE("R: ACK @SYN_RCVD ACK_SN = ",CP &tcp->ack_sn,4,0);
TRACE("STATE = ESTABLISHED",NULL,0,0);
}
else
{
tcp_send(FLG_RST, 20, NO_CONN);
}
break;
//连接已建立;数据传输在进行
case ESTABLISHED:
conn[cn_id].his_ack = tcp->ack_sn;
if (tcp->flags & FLG_FIN)
{
TRACE("R: FIN @ESTABLISHED",NULL,0,0);
conn[cn_id].his_sn++;
// tcp_send(FLG_ACK, 20, cn_id);
// TRACE("T: ACK @ESTABLISHED",NULL,0,0);
// conn[cn_id].state = CLOSE_WAIT;
// TRACE("STATE = CLOSE_WAIT",NULL,0,0);
tcp_send(FLG_FIN | FLG_ACK, 20, cn_id);
TRACE("T: FIN+ACK @ESTABLISHED",NULL,0,0);
conn[cn_id].my_sn++;
conn[cn_id].state = LAST_ACK;
TRACE("STATE = LAST_ACK",NULL,0,0);
}
else if (data_len != 0)
{
TRACE("data_len = ",CP &data_len,2,0);
// TRACE("R: DATA @ESTABLISHED DATA = ",inbuf+header_len+34,data_len);
conn[cn_id].his_sn += data_len;
tcp_send(FLG_ACK, 20, cn_id);
result = http_server(inbuf, head_len, cn_id, 0);
TRACE("T: ACK @ESTABLISHED ACK_SN = ",CP &conn[cn_id].his_sn,4,0);
#ifdef OSCAR_DEBUG
if(data_len < 20)
TRACE("TcpData = ",inbuf+head_len+34,data_len,0);
else
TRACE("TcpData len is too long,NO output",0,0,0);
#endif
#ifdef OSCAR_DEBUG
// memcpy(&outbuf, inbuf, len);//接收到数据返回
// conn[cn_id].his_sn += data_len;
// tcp_send(FLG_ACK | FLG_PSH, len, cn_id);
#endif
conn[cn_id].inactivity = INACTIVITY_TIME;
}
break;
//收到第一个FIN,已发送ACK;等待应用程序关闭
case CLOSE_WAIT:
break;
//已发送第二个FIN;等待ACK
case LAST_ACK:
conn[cn_id].his_ack = tcp->ack_sn;
if (tcp->ack_sn == conn[cn_id].my_sn)
{
TRACE("R: ACK @LAST_ACK ACK_SN =",CP &tcp->ack_sn,4,0);
conn[cn_id].state = CLOSED;
conn[cn_id].ipaddr = 0;
TRACE("CONNECT CLOSED",NULL,0,0);
}
break;
//第一个FIN已经发送;等ACK
case FIN_WAIT1:
conn[cn_id].his_sn += data_len;
conn[cn_id].his_ack = tcp->ack_sn;
if (tcp->flags & FLG_FIN) //收到FIN报文
{
conn[cn_id].his_sn++;
tcp_send(FLG_ACK, 20, cn_id);
if (tcp->ack_sn == conn[cn_id].my_sn) //收到FIN + ACK
{
conn[cn_id].state = TIME_WAIT;
conn[cn_id].state = CLOSED;
conn[cn_id].ipaddr = 0;
TRACE("R: FIN+ACK @FIN_WAIT1 ACK_SN = ",CP &tcp->ack_sn,4,0);
TRACE("CONNECT CLOSED",NULL,0,0);
}
else
{
conn[cn_id].state = CLOSING;
TRACE("R: FIN @FIN_WAIT1 ENTER CLOSING",NULL,0,0);
}
}
else if (tcp->ack_sn == conn[cn_id].my_sn) //收到ACK
{
conn[cn_id].state = FIN_WAIT2;
TRACE("R: ACK @FIN_WAIT1 ACK_SN = ",CP &tcp->ack_sn,4,0);
}
break;
//第一个FIN的ACK已收到;等第二个FIN
case FIN_WAIT2:
conn[cn_id].his_sn += data_len;
conn[cn_id].his_ack = tcp->ack_sn;
if (tcp->flags & FLG_FIN)
{
conn[cn_id].his_sn++;
tcp_send(FLG_ACK, 20, cn_id);
conn[cn_id].state = TIME_WAIT;
conn[cn_id].state = CLOSED;
conn[cn_id].ipaddr = 0;
TRACE("R: FIN @FIN_WAIT2 SEND:ACK_SN = ",CP &conn[cn_id].his_sn,4,0);
}
break;
//收到第二个FIN,已发送ACK;等待2MSL超时
case TIME_WAIT:
break;
case CLOSING:
conn[cn_id].his_ack = tcp->ack_sn;
if (tcp->ack_sn == conn[cn_id].my_sn)
{
conn[cn_id].state = TIME_WAIT;
conn[cn_id].state = CLOSED;
conn[cn_id].ipaddr = 0; // Free up struct area
TRACE("R: ACK @CLOSING",CP &tcp->ack_sn,4,0);
TRACE("CONNECT CLOSED",NULL,0,0);
}
break;
default:
break;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -