📄 tcp.c
字号:
* Overview: None
*
* Note: None
********************************************************************/
void TCPDisconnect(TCP_SOCKET s)
{
SOCKET_INFO *ps;
ps = &TCB[s];
/*
* If socket is not connected, may be it is already closed
* or in process of closing. Since user has called this
* explicitly, close it forcefully.
*/
if ( ps->smState != TCP_EST )
{
CloseSocket(ps);
return;
}
/*
* Discard any outstanding data that is to be read.
*/
TCPDiscard(s);
/*
* Send FIN message.
*/
SendTCP(&ps->remote,
ps->localPort,
ps->remotePort,
ps->SND_SEQ,
ps->SND_ACK,
FIN | ACK);
ps->SND_SEQ++;
ps->smState = TCP_FIN_WAIT_1;
return;
}
/*********************************************************************
* Function: BOOL TCPFlush(TCP_SOCKET s)
*
* PreCondition: TCPInit() is already called.
*
* Input: s - Socket whose data is to be transmitted.
*
* Output: All and any data associated with this socket
* is marked as ready for transmission.
*
* Side Effects: None
*
* Overview: None
*
* Note: None
********************************************************************/
BOOL TCPFlush(TCP_SOCKET s)
{
SOCKET_INFO *ps;
ps = &TCB[s];
// Make sure that this already a TxBuffer assigned to this
// socket.
if ( ps->TxBuffer == INVALID_BUFFER )
return FALSE;
if ( ps->Flags.bIsPutReady == FALSE )
return FALSE;
TransmitTCP(&ps->remote,
ps->localPort,
ps->remotePort,
ps->SND_SEQ,
ps->SND_ACK,
ACK,
ps->TxBuffer,
ps->TxCount);
ps->SND_SEQ += (DWORD)ps->TxCount;
ps->Flags.bIsPutReady = FALSE;
ps->Flags.bIsTxInProgress = FALSE;
#ifdef TCP_NO_WAIT_FOR_ACK
MACDiscardTx(ps->TxBuffer);
ps->TxBuffer = INVALID_BUFFER;
ps->Flags.bIsPutReady = TRUE;
#endif
return TRUE;
}
/*********************************************************************
* Function: BOOL TCPIsPutReady(TCP_SOCKET s)
*
* PreCondition: TCPInit() is already called.
*
* Input: s - socket to test
*
* Output: TRUE if socket 's' is free to transmit
* FALSE if socket 's' is not free to transmit.
*
* Side Effects: None
*
* Overview: None
*
* Note: Each socket maintains only transmit buffer.
* Hence until a data packet is acknowledeged by
* remote node, socket will not be ready for
* next transmission.
* All control transmission such as Connect,
* Disconnect do not consume/reserve any transmit
* buffer.
********************************************************************/
BOOL TCPIsPutReady(TCP_SOCKET s)
{
if ( TCB[s].TxBuffer == INVALID_BUFFER )
return IPIsTxReady();
else
return TCB[s].Flags.bIsPutReady;
}
/*********************************************************************
* Function: BOOL TCPPut(TCP_SOCKET s, BYTE byte)
*
* PreCondition: TCPIsPutReady() == TRUE
*
* Input: s - socket to use
* byte - a data byte to send
*
* Output: TRUE if given byte was put in transmit buffer
* FALSE if transmit buffer is full.
*
* Side Effects: None
*
* Overview: None
*
* Note: None
********************************************************************/
BOOL TCPPut(TCP_SOCKET s, BYTE byte)
{
WORD tempTxCount; // This is a fix for HITECH bug
SOCKET_INFO* ps;
ps = &TCB[s];
if ( ps->TxBuffer == INVALID_BUFFER )
{
ps->TxBuffer = MACGetTxBuffer();
// This function is used to transmit data only. And every data packet
// must be ack'ed by remote node. Until this packet is ack'ed by
// remote node, we must preserve its content so that we can retransmit
// if we need to.
MACReserveTxBuffer(ps->TxBuffer);
ps->TxCount = 0;
IPSetTxBuffer(ps->TxBuffer, sizeof(TCP_HEADER));
}
/*
* HITECH does not seem to compare ps->TxCount as it is.
* Copying it to local variable and then comparing seems to work.
*/
tempTxCount = ps->TxCount;
if ( tempTxCount >= MAX_TCP_DATA_LEN )
return FALSE;
ps->Flags.bIsTxInProgress = TRUE;
MACPut(byte);
// REMOVE
//tempTxCount = ps->TxCount;
tempTxCount++;
ps->TxCount = tempTxCount;
//ps->TxCount++;
//tempTxCount = ps->TxCount;
if ( tempTxCount >= MAX_TCP_DATA_LEN )
TCPFlush(s);
//if ( TCB[s].TxCount >= MAX_TCP_DATA_LEN )
// TCPFlush(s);
return TRUE;
}
/*********************************************************************
* Function: BOOL TCPDiscard(TCP_SOCKET s)
*
* PreCondition: TCPInit() is already called.
*
* Input: s - socket
*
* Output: TRUE if socket received data was discarded
* FALSE if socket received data was already
* discarded.
*
* Side Effects: None
*
* Overview: None
*
* Note: None
********************************************************************/
BOOL TCPDiscard(TCP_SOCKET s)
{
SOCKET_INFO* ps;
ps = &TCB[s];
/*
* This socket must contain data for it to be discarded.
*/
if ( !ps->Flags.bIsGetReady )
return FALSE;
MACDiscardRx();
ps->Flags.bIsGetReady = FALSE;
return TRUE;
}
/*********************************************************************
* Function: WORD TCPGetArray(TCP_SOCKET s, BYTE *buffer,
* WORD count)
*
* PreCondition: TCPInit() is already called AND
* TCPIsGetReady(s) == TRUE
*
* Input: s - socket
* buffer - Buffer to hold received data.
* count - Buffer length
*
* Output: Number of bytes loaded into buffer.
*
* Side Effects: None
*
* Overview: None
*
* Note: None
********************************************************************/
WORD TCPGetArray(TCP_SOCKET s, BYTE *buffer, WORD count)
{
SOCKET_INFO *ps;
ps = &TCB[s];
if ( ps->Flags.bIsGetReady )
{
if ( ps->Flags.bFirstRead )
{
// Position read pointer to begining of correct
// buffer.
IPSetRxBuffer(sizeof(TCP_HEADER));
ps->Flags.bFirstRead = FALSE;
}
ps->Flags.bIsTxInProgress = TRUE;
return MACGetArray(buffer, count);
}
else
return 0;
}
/*********************************************************************
* Function: BOOL TCPGet(TCP_SOCKET s, BYTE *byte)
*
* PreCondition: TCPInit() is already called AND
* TCPIsGetReady(s) == TRUE
*
* Input: s - socket
* byte - Pointer to a byte.
*
* Output: TRUE if a byte was read.
* FALSE if byte was not read.
*
* Side Effects: None
*
* Overview: None
*
* Note: None
********************************************************************/
BOOL TCPGet(TCP_SOCKET s, BYTE *byte)
{
SOCKET_INFO* ps;
ps = &TCB[s];
if ( ps->Flags.bIsGetReady )
{
if ( ps->Flags.bFirstRead )
{
// Position read pointer to begining of correct
// buffer.
IPSetRxBuffer(sizeof(TCP_HEADER));
ps->Flags.bFirstRead = FALSE;
}
if ( ps->RxCount == 0 )
{
MACDiscardRx();
ps->Flags.bIsGetReady = FALSE;
return FALSE;
}
ps->RxCount--;
*byte = MACGet();
return TRUE;
}
return FALSE;
}
/*********************************************************************
* Function: BOOL TCPIsGetReady(TCP_SOCKET s)
*
* PreCondition: TCPInit() is already called.
*
* Input: s - socket to test
*
* Output: TRUE if socket 's' contains any data.
* FALSE if socket 's' does not contain any data.
*
* Side Effects: None
*
* Overview: None
*
* Note: None
********************************************************************/
BOOL TCPIsGetReady(TCP_SOCKET s)
{
/*
* A socket is said to be "Get" ready when it has already
* received some data. Sometime, a socket may be closed,
* but it still may contain data. Thus in order to ensure
* reuse of a socket, caller must make sure that it reads
* a socket, if is ready.
*/
return (TCB[s].Flags.bIsGetReady );
}
/*********************************************************************
* Function: void TCPTick(void)
*
* PreCondition: TCPInit() is already called.
*
* Input: None
*
* Output: Each socket FSM is executed for any timeout
* situation.
*
* Side Effects: None
*
* Overview: None
*
* Note: None
********************************************************************/
void TCPTick(void)
{
#if 1 //!defined(TCP_NO_WAIT_FOR_ACK)
TCP_SOCKET s;
TICK diffTicks;
TICK tick;
SOCKET_INFO* ps;
DWORD seq;
BYTE flags;
flags = 0x00;
/*
* Periodically all "not closed" sockets must perform timed operation.
*/
for ( s = 0; s < MAX_SOCKETS; s++ )
{
ps = &TCB[s];
if ( ps->Flags.bIsGetReady || ps->Flags.bIsTxInProgress )
continue;
/*
* Closed or Passively Listening socket do not care
* about timeout conditions.
*/
if ( (ps->smState == TCP_CLOSED) ||
(ps->smState == TCP_LISTEN &&
ps->Flags.bServer == TRUE) )
continue;
tick = TickGet();
// Calculate timeout value for this socket.
diffTicks = TickGetDiff(tick, ps->startTick);
// If timeout has not occured, do not do anything.
if ( diffTicks <= ps->TimeOut )
continue;
/*
* All states require retransmission, so check for transmitter
* availability right here - common for all.
*/
if ( !IPIsTxReady() )
return;
// Restart timeout reference.
ps->startTick = TickGet();
// Update timeout value if there is need to wait longer.
ps->TimeOut <<= 1;
// This will be one more attempt.
ps->RetryCount++;
/*
* A timeout has occured. Respond to this timeout condition
* depending on what state this socket is in.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -