⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcp.c

📁 在S3C2440上运行的"电子日历“(支持平年,闰年,星期自动调整). 开发环境是RVDS2.2
💻 C
📖 第 1 页 / 共 2 页
字号:
/**---------------------版权 (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 + -