📄 tcp.c
字号:
/**---------------------版权 (c)----------------------------------------------------------***
*** 作者:颜章健 ***
*** 邮件:jenkinyan@163.com ***
*** ***
***---------------------File Info---------------------------------------------------------***
*** 创 建 人: 颜章健 ***
*** 创建日期: 2008-03-27 ***
*** 创建版本: ***
*** 文件描述: TCP(传输控制协议) ***
***---------------------------------------------------------------------------------------***
*** 修 订 人: 颜章健 ***
*** 修订日期: 2008-04-14 ***
*** 修订版本: ***
*** 修订描述: 修改TCP Socket结构:使用hook的时候不申请接收窗口缓存 ***
***---------------------------------------------------------------------------------------***
*** 修 订 人: 颜章健 ***
*** 修订日期: 2008-05-04 ***
*** 修订版本: ***
*** 修订描述: 修改TCP Socket结构:省去接收窗口,去掉函数指针,发送窗口使用固定 ***
*** 缓冲区 ***
***---------------------------------------------------------------------------------------***
*** 修 订 人: 颜章健 ***
*** 修订日期: 2008-05-16 ***
*** 修订版本: ***
*** 修订描述: 增加条件编译,允许配置使用与发送窗口等长的接收窗口 ***
***---------------------------------------------------------------------------------------**/
#include "config.h"
#include <math.h>
#if MAX_TCP_SOCKETS > 0
static TCP_SOCKET *TcpFirstSocket; // TCP 客户端接口链表第一个接口
static uint8 TcpTxWindowBuffer[MAX_TCP_SOCKETS][TCP_TXWINDOW_SIZE];
#if TCP_RXWINDOW_SIZE > 0
static uint8 TcpRxWindowBuffer[MAX_TCP_SOCKETS][TCP_RXWINDOW_SIZE];
#endif
// 函数声明
static void TcpSendPacket(TCP_SOCKET *This,uint8 *Option, uint8 OLength,uint8 Flag,uint8 DatEnable);
#endif
#if MAX_TCP_SOCKETS > 0
/********************************************************************************************
*** 函数名称: WindowPush
*** 函数描述:
*** 入 口:
*** 出 口: 返回实际压入的数据长度
********************************************************************************************/
static uint16 WindowPush(TCP_WINDOW *win,uint8 *src, uint16 len)
{
uint32 i;
uint16 ret;
ret = win->BufLen - win->DatLen;
if(ret > len)
{
ret=len;
}
i = ret;
while(i--)
{
*win->In++ = *src++;
if( win->In > win->End)
{
win->In = win->Start;
}
}
win->DatLen += ret;
win->Size = win->BufLen - win->DatLen;
return ret;
}
/********************************************************************************************
*** 函数名称: WindowPop
*** 函数描述:
*** 入 口:
*** 出 口: 实际弹出的数据长度
********************************************************************************************/
/*
static uint16 WindowPop(TCP_WINDOW *win,uint8 *dst,uint16 len)
{
uint32 i;
uint16 ret;
ret = win->DatLen;
if(ret > len)
{
ret = len;
}
i = ret;
while(i--)
{
*dst++ = *win->Out++;
if(win->Out > win->End)
{
win->Out = win->Start;
}
}
win->DatLen -= ret;
win->Size = win->BufLen - win->DatLen;
return ret;
}*/
/********************************************************************************************
*** 函数名称: WindowGetPacket
*** 函数描述:
*** 入 口:
*** 出 口: 实际读出的数据长度
********************************************************************************************/
static uint16 WindowGetPacket(TCP_WINDOW *win,uint16 ofs,NET_PKT *pkt,uint16 Length)
{
static NET_PKT pkt2;
uint8 *dat;
uint16 len;
if(ofs >= win->DatLen)
{
pkt->Data = NULL;
pkt->Length = 0;
pkt->Next = NULL;
return 0;
}
len = win->DatLen - ofs;
if(len > Length)
{
len = Length;
}
dat = win->Out + ofs;
if(dat > win->End)
{
dat = win->Start + (dat - win->End) - 1;
}
pkt->Data = dat;
if((dat + len) > win->End)
{
pkt->Length = win->End - dat + 1;
if(pkt->Next != NULL)
{
pkt->Next->Data = win->Start;
pkt->Next->Length = len - pkt->Length;
pkt->Next->Next = NULL;
}
else
{
pkt->Next = &pkt2;
pkt2.Data = win->Start;
pkt2.Length = len - pkt->Length;
pkt2.Next = NULL;
}
}
else
{
pkt->Length = len;
pkt->Next = NULL;
}
return len;
}
/********************************************************************************************
*** 函数名称: WindowDel
*** 函数描述:
*** 入 口:
*** 出 口:
********************************************************************************************/
static void WindowDel(TCP_WINDOW *win,uint16 len)
{
if(len > win->DatLen)
{
len = win->DatLen;
}
win->Out += len;
if(win->Out > win->End)
{
win->Out = win->Start + (win->Out - win->End - 1);
}
win->DatLen -= len;
}
/********************************************************************************************
*** 函数名称:
*** 函数描述:
*** 入 口:
*** 出 口:
********************************************************************************************/
static void WindowCreate(TCP_WINDOW *Window,uint8 *Buffer,uint16 BufLen)
{
Window->Start = Buffer;
Window->End = Buffer + BufLen - 1;
Window->BufLen = BufLen;
Window->In = Buffer;
Window->Out = Buffer;
Window->DatLen = 0;
Window->Size = BufLen;
}
/********************************************************************************************
*** 函数名称:
*** 函数描述:
*** 入 口:
*** 出 口:
********************************************************************************************/
uint16 TcpSocketSend(TCP_SOCKET *This,uint8 *src,uint16 len)
{
This->UREQ = UREQ_SEND;
return WindowPush(&This->TxWindow,src,len);
}
/********************************************************************************************
*** 函数名称:
*** 函数描述:
*** 入 口:
*** 出 口:
********************************************************************************************/
uint16 TcpSocketRecv(TCP_SOCKET *This,uint8 *dst,uint16 len)
{
//return WindowPop(&This->RxWindow,dst,len); // Changed by Yan Zhangjian(C) @ 2008-04-14
/*
if(This->hook == NULL)
{
return WindowPop(&This->RxWindow,dst,len);
}
else*/
//{
if(This->Rxl > 0)
{
uint16 i,n=0;
for(i=len; i>0; i--)
{
*dst++ = *This->Rxd++;
n++;
if((This->Rxl--) == 0)
{
break;
}
}
return n;
}
else
{
return 0;
}
//}
}
/********************************************************************************************
*** 函数名称: SocketConnect
*** 函数描述: 主动发起TCP连接
*** 入 口:
*** 出 口:
********************************************************************************************/
void TcpSocketConnect(TCP_SOCKET *This)
{
This->UREQ = UREQ_CONN;
}
/********************************************************************************************
*** 函数名称: SocketClose
*** 函数描述: 主动关闭TCP连接
*** 入 口:
*** 出 口:
********************************************************************************************/
void TcpSocketClose(TCP_SOCKET *This)
{
This->UREQ = UREQ_CLOSE;
}
/********************************************************************************************
*** 函数名称: TcpSocketCreate
*** 函数描述: 创建TCP接口
*** 入 口:
*** 出 口:
********************************************************************************************/
//TCP_SOCKET *TcpSocketCreate
uint8 TcpSocketCreate
( TCP_SOCKET *Socket,
uint8 *DestAddr, uint16 DestPort,
uint16 LocalPort, void (*RecvHook)(TCP_SOCKET *)
)
{
int i;
// 搜索窗口缓冲区
{
uint8 success;
TCP_SOCKET *sock;
for(i=0; i<MAX_TCP_SOCKETS; i++)
{
success = 1;
sock = TcpFirstSocket;
while(sock != NULL)
{
if(sock->TxWindow.Start == TcpTxWindowBuffer[i])
{
success = 0;
break;
}
else
{
sock = sock->Next;
}
}
if(success == 1)
{
WindowCreate(&Socket->TxWindow,TcpTxWindowBuffer[i],TCP_TXWINDOW_SIZE);
#if TCP_RXWINDOW_SIZE > 0
WindowCreate(&Socket->RxWindow,TcpRxWindowBuffer[i],TCP_RXWINDOW_SIZE);
#endif
break;
}
}
}
if(i == MAX_TCP_SOCKETS)
{
return TCP_ERR_USER;
}
Socket->TOT = 0;
Socket->RTT = 750; // RTT初始化为 750 ms,采样后自动调整
Socket->DEV = 0; // 平均方差初始化为0 added by Yan Zhangjian(C) @ 2008-04-12
Socket->Timeout = 1500; // 超时时间初始化为1500ms,采样后自动调整
Socket->TXS = SOCKS_CLOSED;
Socket->RXS = SOCKS_CLOSED;
Socket->UREQ = UREQ_NONE;
// 设置Socket属性
for(i=0; i<4; i++)
{
Socket->DestAddr[i] = *DestAddr++; // 设置目的地址
}
Socket->DestPort = DestPort; // 设置目的端口
Socket->LocalPort = LocalPort; // 设置本地端口
if(TCP_RXWINDOW_SIZE > 1400)
{
Socket->MRU = 1400;
}
else
{
Socket->MRU = TCP_RXWINDOW_SIZE;
}
Socket->MTU = 500; // 初始化MTU为500字节,连接建立后自动调整
Socket->DestSize = 500; // 初始化对方窗口大小为500字节,连接建立后自动调整
Socket->Seq = (uint32)rand();
Socket->Ack = 0;
Socket->LastRcvSeq = Socket->Seq - 2;
Socket->LastRcvSeq = 0;
Socket->hook = RecvHook;
// 将Socket插入链表
Socket->Next = TcpFirstSocket;
TcpFirstSocket = Socket;
return TCP_ERR_NONE;
}
/********************************************************************************************
*** 函数名称: TcpSocketDelete
*** 函数描述: 删除已经创建的TCP接口
*** 入 口: Socket :要删除的接口
*** 出 口: 无
********************************************************************************************/
void TcpSocketDelete(TCP_SOCKET *Socket)
{
TCP_SOCKET *sock,*next;
if(TcpFirstSocket == NULL) // 链表为空,直接返回
{
return;
}
if(Socket == TcpFirstSocket) // 要删除的接口是链表中的第一个接口
{
Socket->TxWindow.Start = NULL;
TcpFirstSocket = TcpFirstSocket->Next;
return;
}
if(TcpFirstSocket->Next == NULL) // 链表只有一个接口,但不是要删除的接口
{
return;
}
// 链表有多个接口,搜索要删除的接口
sock = TcpFirstSocket;
next = sock->Next;
while(next != NULL)
{
if(next == Socket)
{
sock->TxWindow.Start = NULL; // Added by Yan Zhangjian(R) @ 2008-05-04
sock->Next = next->Next;
break;
}
next = next->Next;
sock = sock->Next;
}
}
/********************************************************************************************
*** 函数名称: TcpSocketReset
*** 函数描述: 复位TCP连接
*** 入 口:
*** 出 口:
********************************************************************************************/
void TcpSocketReset(TCP_SOCKET *Socket)
{
TcpSendPacket(Socket,NULL,0,TCPFLAG_RST,0);
Socket->TXS = SOCKS_CLOSED;
Socket->RXS = SOCKS_CLOSED;
}
/********************************************************************************************
*** 函数名称: TcpCheckSum
*** 函数描述: TCP校验值计算
*** 入 口:
*** 出 口:
********************************************************************************************/
static uint16 TcpCheckSum(NET_PKT *Packet)
{
__packed uint16 *_ptr;
uint16 i,len;
uint32 sum = 0;
_ptr = (__packed uint16 *)Packet->Data;
while(Packet != NULL)
{
_ptr = (__packed uint16 *)Packet->Data;
len = Packet->Length >> 1;
for(i=0; i<len; i++)
{
sum += *_ptr++;
}
if(Packet->Next == NULL)
{
break;
}
Packet = Packet->Next;
}
if(Packet->Length & 0x0001)
{
sum += ((*_ptr)&0xff);
}
sum = (sum & 0xffff) + ((sum>>16)&0xffff);
if(sum&0xffff0000) sum++;
return (uint16)(sum & 0xffff);
}
/********************************************************************************************
*** 函数名称: TcpSendPacket
*** 函数描述: 运输层发送 TCP 数据包
*** 入 口: This :Socket接口
*** Data :用户数据缓冲区指针
*** Length :用户数据长度
*** DatEnable : 0,不允许携带数据; 1,允许携带数据
*** 出 口: 无
********************************************************************************************/
static void TcpSendPacket(
TCP_SOCKET *This,
uint8 *Option, uint8 OLength,
uint8 Flag, uint8 DatEnable)
{
uint8 TcpHead[32];
NET_PKT Head,Opt,Data;
uint16 v16;
uint32 v32;
int i;
// 设置链表(包含伪头部):用于计算校验和
Head.Data = TcpHead;
Head.Length = 32;
Head.Next = &Opt;
Opt.Data = Option;
Opt.Length = OLength;
Opt.Next = &Data;
Data.Next = NULL;
// 填充数据
v16 = This->TxWindow.DatLen;
if(v16 > This->MTU) // 限制发送数据不大于对方MTU
{
v16 = This->MTU;
}
if(v16 > This->DestSize) // 限制发送数据不大于对方窗口
{
v16 = This->DestSize;
}
//if(This->TXS < SOCKS_SENDREQ)
if(DatEnable == 0)
{
v16 = 0;
}
v16 = WindowGetPacket(&This->TxWindow,0,&Data,v16);
v16 = v16 + OLength + 20; // 计算TCP数据包总长
// 填充伪头部内容 TcpHead[] 的前12字节
for(i=0; i<4; i++)
{
TcpHead[i] = LinkLayer.Config.Ip[i]; // 本地地址
TcpHead[i+4] = This->DestAddr[i]; // 目的地址
}
TcpHead[ 8] = 0; TcpHead[ 9] = 6;
TcpHead[10] = (v16 >> 8); TcpHead[11] = (uint8)v16;
// 填充头部内容 TcpHead[] 的后20字节
v16 = This->LocalPort; // 本地端口
TcpHead[12] = (v16 >> 8); TcpHead[13] = (uint8)v16;
v16 = This->DestPort; // 目的端口
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -