📄 tcp.c
字号:
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));
}
}
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);
}
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);
}
BOOL TCPConnect(struct STCB DT_XDATA * pTCB, DWORD DestIP, WORD DestPort,
void (DT_CODE * recv)(void DT_XDATA * buf,WORD size) REENTRANT_MUL,
void (DT_CODE * close)(struct STCB DT_XDATA * pSocket) REENTRANT_MUL) REENTRANT_SIG
{
/* is it in closed state? */
if(pTCB->TCPState != TCP_STATE_CLOSED)
return FALSE;
/* tcb renew */
pTCB->IPDest = htonl(DestIP);
pTCB->PortDest = htons(DestPort);
pTCB->recv = recv;
pTCB->close = close;
/* send syn */
if(TCPSendSeg(pTCB,TCPAllocate(0),TCP_SYN) == TRUE)
{
pTCB->TCPState = TCP_STATE_SYNSENT;
/* wait for establish */
while(TRUE)
{
switch(pTCB->TCPState)
{
case TCP_STATE_ESTABLISHED:
return TRUE;
case TCP_STATE_CLOSED:
/* 1. if receive a rst packet from him
2. retransmittimes exceed sreshold */
return FALSE;
}
}
}
else
return FALSE;
}
/* call this func to innitiate closing a connection. connection
will not close unless peer send a fin also.*/
void TCPClose(struct STCB DT_XDATA *pTCB) REENTRANT_MUL
{
if(pTCB->TCPState != TCP_STATE_CLOSED)
{
switch(pTCB->TCPState)
{
case TCP_STATE_LISTEN:
/* close right now */
pTCB->TCPState = TCP_STATE_CLOSED;
break;
case TCP_STATE_SYNRECVD:
/* close when peer send a fin */
pTCB->TCPState = TCP_STATE_FINWAIT1;
TCPSendSeg(pTCB,TCPAllocate(0),TCP_FIN | TCP_ACK);
break;
case TCP_STATE_SYNSENT:
/* close right now */
pTCB->TCPState = TCP_STATE_CLOSED;
TCPRelease(pTCB);
break;
case TCP_STATE_ESTABLISHED:
/* close when peer send a fin */
pTCB->TCPState = TCP_STATE_FINWAIT1;
TCPSendSeg(pTCB,TCPAllocate(0),TCP_FIN | TCP_ACK);
break;
case TCP_STATE_CLOSEWAIT:
/* close when lastack time out */
pTCB->TCPState = TCP_STATE_LASTACK;
pTCB->LastAckTimer = TCP_LASTACK_TIME_OUT;
TCPSendSeg(pTCB,TCPAllocate(0),TCP_FIN | TCP_ACK);
break;
}
}
}
BOOL TCPListen(struct STCB DT_XDATA *pTCB,WORD ScrPort,
void (DT_CODE * accept)(struct STCB DT_XDATA *pNewTCB) REENTRANT_MUL) REENTRANT_MUL
{
struct STCB DT_XDATA *pTCBt;
/* is it in closed state? */
if(pTCB->TCPState != TCP_STATE_CLOSED)
return FALSE;
ScrPort = htons(ScrPort);
/* is there any other socket already listen in this port? */
for(pTCBt = TCBList; pTCBt != NULL; pTCBt = pTCBt->pNext)
{
if(pTCBt->PortScr == ScrPort)
return FALSE;
}
/* renew tcb */
pTCB->PortScr = ScrPort;
pTCB->TCPState = TCP_STATE_LISTEN;
pTCB->accept = accept;
return TRUE;
}
struct STCB DT_XDATA * TCPSocket(IP_ADDR ScrIP) REENTRANT_SIG
{
struct STCB DT_XDATA * pTCB;
struct STCB DT_XDATA * pTCBt;
WORD MaxScrPort; /* max port number in use */
/* get a tcb */
if((pTCB = TCPGetTCB()) == NULL)
{
return NULL;
}
/* allocate a scrport. that is number of
the highest number of port in use add 1 */
for(pTCBt = TCBList,MaxScrPort = TCP_DEFAULT_PORT;
pTCBt != NULL; pTCBt = pTCBt->pNext)
{
if(ntohs(pTCBt->PortScr) > MaxScrPort)
MaxScrPort = ntohs(pTCBt->PortScr);
}
pTCB->PortScr = htons((WORD)(MaxScrPort + 1));
/* other tcb set */
pTCB->TCPState = TCP_STATE_CLOSED;
pTCB->IPScr = htonl(ScrIP);
pTCB->WndMine = MemFreeSize();
pTCB->bNeedAck = FALSE;
pTCB->QExceedSeq = NULL;
pTCB->QUnacked = NULL;
pTCB->QUnSend = NULL;
/* Insert int tcb */
TCPInsertTCB(pTCB);
return pTCB;
}
/* reclaim TCB */
void TCPAbort(struct STCB DT_XDATA *pTCB) REENTRANT_SIG
{
struct STCB DT_XDATA *pTCBt;
TCPRelease(pTCB);
/*
* search through the tcb list and delete it from list
*/
/* if it is the hear of the list */
if(TCBList == pTCB)
{
TCBList = TCBList->pNext;
}
else
{
/* else search start from the second one */
for(pTCBt = TCBList; pTCBt != NULL; pTCBt = pTCBt->pNext)
{
if(pTCBt->pNext == pTCB)
{
pTCBt->pNext = pTCB->pNext;
break;
}
}
}
/* reclaim it. link it to TCBFreelist */
pTCB->pNext = TCBFreeList;
TCBFreeList = pTCB;
}
/* this func is called by user to allocate a packet and pstart
point to TCPplayload */
struct SMemHead DT_XDATA *TCPAllocate(WORD size) REENTRANT_SIG
{
struct SMemHead DT_XDATA * MemHead;
if((MemHead = MemAllocate((WORD)(ALL_HEAD_SIZE + size))) == NULL)
return NULL;
else
{
/* point to the tcp data */
MemHead->pStart += ALL_HEAD_SIZE;
return MemHead;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -