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

📄 tcp.c

📁 我的网口控制程序
💻 C
📖 第 1 页 / 共 2 页
字号:
	struct STCB DT_XDATA *pNewTCB;
	struct SIPHead  DT_XDATA *pIPHead;
	struct STCPHead DT_XDATA *pTCPHead;

	pTCPHead = (struct STCPHead DT_XDATA *)(MemHead->pStart );
	pIPHead	 = (struct SIPHead  DT_XDATA *)(MemHead->pStart - IP_HEAD_MIN_LEN);

	/*
	 * begain renew tcb values
	 */

	/* dest windows size renew.*/
	pTCB->WndHis = pTCPHead->WndSize;

	/* after dest windows renew is it possible to send a packet in unsend queue now ?*/
	TCPSendUnsendQ(pTCB);
		
	/* His Sequence renew */
	TCPDataSize = ntohs(pIPHead->TotalLen) - IP_HEAD_MIN_LEN 
		- TCP_HEAD_LEN(pTCPHead);
	if((pTCPHead->flag & TCP_SYN)  || (pTCPHead->flag & TCP_FIN))
	{
		pTCB->SeqHis += TCPDataSize + 1;
	}
	else
	{
		pTCB->SeqHis += TCPDataSize;
	}

	/* NeedAck? */
	if(TCPDataSize != 0)
	{
		pTCB->bNeedAck = TRUE;
		pTCB->DelayAckTimer = TCP_DELAY_ACK_TIME_OUT;
	}
	
	/* if This packet acked packet in unacked queue */
	if((pTCPHead->flag & TCP_ACK) != 0)
	{	
		while(pTCB->QUnacked != NULL &&
			TCP_SEQ_COMPARE(pTCB->QUnacked->Seq,pTCPHead->AckSeq) < 0)
		{
			MemFree(pTCB->QUnacked->MemHead); 
			TCPOutQ(&(pTCB->QUnacked));	
			
			/* timer for retran restore */
			pTCB->RetranTimer = TCP_RETRAN_TIME_OUT;
			pTCB->RetranTimes = 0;
		}
	}
	
	/*
	 * deal refer to tcb.state and tcp flag
	 */
	switch(pTCB->TCPState)
	{
	case TCP_STATE_CLOSED:
		break;
	case TCP_STATE_LISTEN:
		/* syn: to TCP_STATE_SYNSENT, send syn+ack */
		if(pTCPHead->flag == TCP_SYN)
		{
			/* create a new tcb and it is going to deal with 
			this connection. */
			if((pNewTCB = TCPSocket(htonl(pTCB->IPScr))) == NULL)
			{
				MemFree(MemHead);
				return;
			}

			/* insert this tcb to tcb list isn't need. because
			this tcb is already insert at TCPSocket()*/

			/* initial new tcb value*/
			pNewTCB->TCPState	= TCP_STATE_SYNRECVD;
			pNewTCB->IPDest		= pIPHead->IPScr;
			pNewTCB->PortDest	= pTCPHead->PortScr;
			pNewTCB->PortScr	= pTCPHead->PortDest;

			pNewTCB->SeqHis = pTCPHead->Seq + 1;	/* syn is use 1 
													sequence */
			pNewTCB->WndHis = pTCPHead->WndSize;

			/* set accept function. when pNewTCB accept this
			connection call pTCB->accetp */
			pNewTCB->accept = pTCB->accept;			

			/* send syn+ack */
			TCPSendSeg(pNewTCB,TCPAllocate(0),TCP_SYN | TCP_ACK);
		}
		break;
	case TCP_STATE_SYNRECVD:

		/* ack: to TCP_STATE_ESTABLISHED */
		if((pTCPHead->flag & TCP_ACK) != 0)
			pTCB->TCPState = TCP_STATE_ESTABLISHED;

		/* call accept. Let user to know and deal more */
		pTCB->accept(pTCB);

		break;
	case TCP_STATE_SYNSENT:
		switch(pTCPHead->flag)
		{
		case TCP_SYN:
			/* syn: to TCP_STATE_SYNRECVD send syn+ack */

			pTCB->TCPState = TCP_STATE_SYNRECVD;

			/* ackseq initial */
			pTCB->SeqHis = pTCPHead->Seq + 1;	/* syn use 1 sequence */

			TCPSendSeg(pTCB,TCPAllocate(0),	TCP_SYN | TCP_ACK);
			break;
		case TCP_SYN | TCP_ACK:	
			/* syn+ack: to TCP_STATE_ESTABLISHED send ack */
	
			pTCB->TCPState = TCP_STATE_ESTABLISHED;

			/* ackseq initial */
			pTCB->SeqHis = pTCPHead->Seq + 1;	/* syn use 1 sequence */

			TCPSendSeg(pTCB,TCPAllocate(0),TCP_ACK);
			break;
		case TCP_RST | TCP_ACK:
			/* rst: to closed */
			pTCB->TCPState = TCP_STATE_CLOSED;
			TCPRelease(pTCB);
			break;
		}
		break;
	case TCP_STATE_ESTABLISHED:
		/* fin:to closewait send ack */
		if((pTCPHead->flag & TCP_FIN) != 0)
		{
			pTCB->TCPState = TCP_STATE_CLOSEWAIT;
			TCPSendSeg(pTCB,TCPAllocate(0),	TCP_ACK);

			/* call ->close() let user to know he want to close connection 
			user should call TCPClose() to close the connection in ->close */
			pTCB->close(pTCB);
		}
		break;
	case TCP_STATE_CLOSEWAIT:
		/* he want to close, send a fin to close */
		pTCB->TCPState = TCP_STATE_LASTACK;
		pTCB->LastAckTimer = TCP_LASTACK_TIME_OUT;
		TCPSendSeg(pTCB,TCPAllocate(0),	TCP_FIN | TCP_ACK);
		break;
	case TCP_STATE_FINWAIT1:
		switch(pTCPHead->flag)
		{
		case TCP_FIN:
			/* fin: to TCP_STATE_CLOSING send ack */
			pTCB->TCPState = TCP_STATE_CLOSING;
			TCPSendSeg(pTCB,TCPAllocate(0),	TCP_ACK);
			break;
		case TCP_FIN | TCP_ACK:
			pTCB->TCPState = TCP_STATE_TIMEWAIT;
			pTCB->LastAckTimer = TCP_LASTACK_TIME_OUT;	/* start timer */
			TCPSendSeg(pTCB,TCPAllocate(0),	TCP_ACK);
			break;
		case TCP_ACK:
			pTCB->TCPState = TCP_STATE_FINWAIT2;
			break;
		}
		break;
	case TCP_STATE_CLOSING:
		/* ack:to TCP_STATE_CLOSED */
		if(pTCPHead->flag & TCP_ACK)
		{
			pTCB->TCPState = TCP_STATE_TIMEWAIT;
			pTCB->LastAckTimer = TCP_LASTACK_TIME_OUT;	/* start timer */
		}
		break;
	case TCP_STATE_FINWAIT2:
		if(pTCPHead->flag & TCP_FIN)
		{
			pTCB->TCPState = TCP_STATE_TIMEWAIT;
			pTCB->LastAckTimer = TCP_LASTACK_TIME_OUT;	/* start timer */
			TCPSendSeg(pTCB,TCPAllocate(0),	TCP_ACK);
		}
		break;
	}

	/*
	 * put tcp data to uper layer 
	 */
	if(TCPDataSize != 0)
	{
		pTCB->recv(MemHead->pStart + TCP_HEAD_LEN(pTCPHead),TCPDataSize);
	}

	/*
	 * free this packet 
	 */
	MemFree(MemHead);
}

/* tcp packet in.*/
void TCPInput(struct SMemHead DT_XDATA *MemHead) REENTRANT_SIG
{
	struct SIPHead  DT_XDATA *pIPHead;
	struct STCPHead DT_XDATA *pTCPHead;
	struct STCB		DT_XDATA *pNewTCB;
	struct STCB	DT_XDATA *pTCB;
	
	pTCPHead = (struct STCPHead DT_XDATA *)(MemHead->pStart);
	pIPHead	 = (struct SIPHead  DT_XDATA *)(MemHead->pStart - sizeof(struct SIPHead));

	/*
	 * is check sum ok? 
	 */
	if(TCPCheckSum(pIPHead,ntohs(pIPHead->TotalLen) - IP_HEAD_MIN_LEN) != 0)
	{		
		MemFree(MemHead);
		return;
	}

	/* 
	 * is there a connection can accept this tcp packet?
	 */

	/* if is syn packet. a tcb in listen can accept it. */
	if(pTCPHead->flag == TCP_SYN)
	{
		for(pTCB = TCBList; pTCB != NULL; pTCB = pTCB->pNext)
		{
			if(pTCB->TCPState == TCP_STATE_LISTEN &&
				pTCB->PortScr == pTCPHead->PortDest)
			{
				break;
			}
		}
	}
	else
	{
		/* search active connections. TCBState must not the 
		closed and listen state */
		for(pTCB = TCBList; pTCB != NULL; pTCB = pTCB->pNext)
		{
			/* and the source ip, dest ip, source port, dest port
				must equal */				
			if(pTCB->PortScr == pTCPHead->PortDest &&
				pTCB->PortDest == pTCPHead->PortScr &&
				pTCB->TCPState != TCP_STATE_LISTEN &&
				pTCB->TCPState != TCP_STATE_CLOSED &&
				pTCB->IPScr  == pIPHead->IPDest &&
				pTCB->IPDest == pIPHead->IPScr)
				break;
			
		}
	}

	/* can't find, and send a rst */
	if(pTCB == NULL)
	{
		/* allocate a temp tcb for use */
		pNewTCB = TCPSocket(ntohl(pIPHead->IPDest));
		pNewTCB->IPDest 	= pIPHead->IPScr;
		pNewTCB->PortDest 	= pTCPHead->PortScr;
		pNewTCB->PortScr	= pTCPHead->PortDest;
		
		/* set MemFree DataSize to 0 */
		MemHead->pStart = MemHead->pEnd;

		TCPSendSeg(pNewTCB,TCPAllocate(0),TCP_ACK | TCP_RST);

		MemFree(MemHead);
		TCPAbort(pNewTCB);
		return;
	}

	/* 
	 *  is it a expected packet? 
	 */
	/* first change all necessary part to host order */
 #ifndef HOST_ORDER_AS_NET
	pTCPHead->AckSeq	= ntohl(pTCPHead->AckSeq);
	pTCPHead->Seq		= ntohl(pTCPHead->Seq);
	pTCPHead->WndSize	= ntohs(pTCPHead->WndSize);
#endif

	/* if it is the first packet from him, don't check sequence.
	   in connection case: a syn or syn+ack packet. in listen case
	   : a syn packet. so pass all packet contain syn flag */
	if((pTCPHead->flag & TCP_SYN) == 0)
	{
		/* sequence ok? */
		if(pTCB->SeqHis != pTCPHead->Seq)
		{
			/* if this a packet fall within rev window */
			if(TCP_SEQ_COMPARE(pTCPHead->Seq,pTCB->SeqHis) > 0
				&& TCP_SEQ_COMPARE(pTCPHead->Seq,pTCB->SeqHis) < pTCB->WndMine)
			{
				/* write it to QExceedSeq for late receive */
				TCPInsertQ(&(pTCB->QExceedSeq),MemHead,pTCPHead->Seq);
				return;
			}
			else
			{
				/* packet fall outof window, drop it. and send a ack back, because 
				this is probably ocurr when our pre send ack is lose.*/
				MemFree(MemHead);
				TCPSendSeg(pTCB,TCPAllocate(0),TCP_ACK);
				return;
			}
		}/* else sequence equal. ok */
	}/* else is syn packet */
	
	/* deal incoming packet */
	TCPRecvSeg(pTCB,MemHead);

	/* if seg in ExceedSeq can receive now? */
	while(pTCB->QExceedSeq != NULL &&
		pTCB->SeqHis == pTCB->QExceedSeq->Seq)
	{
		TCPRecvSeg(pTCB,pTCB->QExceedSeq->MemHead);
		TCPOutQ(&(pTCB->QExceedSeq));
	}
}
/*
功能:快速发送数据。在使用 TCPSend  函数时,你首先需要将数据放入 buf  指向的内 
存中,然后调用 TCPSend 函数,接着该函数会将buf 指向的内存区数据拷贝到TCP 缓冲区 
中。使用 TCPSendEx()时你首先用TCPAllocate(DATA_SIZE)获得一个 TCP 缓冲区,然后直 
接将数据放入 TCP 缓冲区中,从而比 TCPSend  函数少一次数据拷贝,提高发送速度。 

数:发送数据的 TCP 连接是套接字指针pTCB 对应的连接,发送的数据放在 TCP 缓 

存 MemHead  中。发送成功返回 TRUE,否则返回FALSE。*/ 

BOOL TCPSendEx(struct STCB DT_XDATA * pTCB,struct SMemHead DT_XDATA *MemHead) REENTRANT_MUL
{
	/* if state is "closed, listen, syn recvd, syn sent", 
	need connected first */
	if(pTCB->TCPState <= TCP_STATE_SYNSENT)
	{
		MemFree(MemHead);
		return FALSE;
	}
	
	/* if unsend queue is empty */
	if(pTCB->QUnSend == NULL)
	{
		/* if this packet send completely? */
		if(TCPSendSegJudgeWnd(pTCB,MemHead) == FALSE)
		{
			/* insert the remain for later sending */
			return TCPInsertQ(&(pTCB->QUnSend),MemHead,0);
		}
		else
			return TRUE;
	}
	else
		return TCPInsertQ(&(pTCB->QUnSend),MemHead,0);
}
/*
TCPSend()------------------------------------------------------------
功能:发送数据。发送数据的 TCP 连接是套接字指针pTCB 对应的连接,发送的数据 
的起始地址为buf,大小为 DataSize。发送成功返回 TRUE,否则返回FALSE。 */

BOOL TCPSend(struct STCB DT_XDATA * pTCB,void DT_XDATA *buf,WORD DataSize) REENTRANT_MUL
{
	struct SMemHead DT_XDATA *MemHead;

	/* allocate */
	if((MemHead = TCPAllocate(DataSize)) == NULL)
		return FALSE;

	/* copy */
	MemCopy(MemHead->pStart,buf,DataSize);
	

	return TCPSendEx(pTCB,MemHead);
}


/*
TCPConnect()------------------------------------
向IP 地址为DestIP的服务器的DestPort 端口发起连接。参数recv 和 close 用于 
设置当接收到数据包和对方要求关闭 TCP  
接时应该调用的回调函数指针。

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -