?? 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 + -