📄 tcp.c
字号:
SendTCP(hTCP, PSH | ACK);
MyTCB.MySEQ = SEQSave;
}
else
{
// No response back for too long, close connection
// This could happen, for instance, if the communication
// medium was lost
MyTCB.MySEQ++;
ps->smState = TCP_FIN_WAIT_1;
MyTCB.retryInterval = TCP_START_TIMEOUT_VAL;
MyTCB.retryCount = 0;
SendTCP(hTCP, FIN | ACK);
}
break;
case TCP_FIN_WAIT_1:
if(MyTCB.retryCount <= MAX_RETRY_COUNTS)
{
SEQSave = MyTCB.MySEQ;
// Roll back unacknowledged TX tail pointer
MyTCB.MySEQ -= (LONG)(SHORT)(MyTCB.txUnackedTail - ps->txTail);
if(MyTCB.txUnackedTail < ps->txTail)
MyTCB.MySEQ -= (LONG)(SHORT)(ps->bufferRxStart - ps->bufferTxStart);
MyTCB.txUnackedTail = ps->txTail;
// Send another FIN
SendTCP(hTCP, FIN | ACK);
MyTCB.MySEQ = SEQSave;
}
else
{
// Close on our own, we can't seem to communicate
// with the remote node anymore
SendTCP(hTCP, RST | ACK);
CloseSocket(hTCP);
}
break;
case TCP_FIN_WAIT_2:
// Close on our own, we can't seem to communicate
// with the remote node anymore
SendTCP(hTCP, RST | ACK);
CloseSocket(hTCP);
break;
case TCP_CLOSING:
if(MyTCB.retryCount <= MAX_RETRY_COUNTS)
{
SEQSave = MyTCB.MySEQ;
// Roll back unacknowledged TX tail pointer
MyTCB.MySEQ -= (LONG)(SHORT)(MyTCB.txUnackedTail - ps->txTail);
if(MyTCB.txUnackedTail < ps->txTail)
MyTCB.MySEQ -= (LONG)(SHORT)(ps->bufferRxStart - ps->bufferTxStart);
MyTCB.txUnackedTail = ps->txTail;
// Send another ACK
SendTCP(hTCP, ACK);
MyTCB.MySEQ = SEQSave;
}
else
{
// Close on our own, we can't seem to communicate
// with the remote node anymore
SendTCP(hTCP, RST | ACK);
CloseSocket(hTCP);
}
break;
case TCP_TIME_WAIT:
// Wait around for a while (2MSL) and then goto closed state
CloseSocket(hTCP);
break;
case TCP_CLOSE_WAIT:
if(MyTCB.retryCount <= MAX_RETRY_COUNTS)
{
SEQSave = MyTCB.MySEQ;
// Roll back unacknowledged TX tail pointer
MyTCB.MySEQ -= (LONG)(SHORT)(MyTCB.txUnackedTail - ps->txTail);
if(MyTCB.txUnackedTail < ps->txTail)
MyTCB.MySEQ -= (LONG)(SHORT)(ps->bufferRxStart - ps->bufferTxStart);
MyTCB.txUnackedTail = ps->txTail;
// Send ACK
SendTCP(hTCP, ACK);
MyTCB.MySEQ = SEQSave;
}
else
{
// We shouldn't get down here if the application properly closes the connection.
// However, if it doesn't, we still need to ensure socket reuse, so let's forcefully close the socket.
SendTCP(hTCP, RST | ACK);
CloseSocket(hTCP);
}
break;
case TCP_LAST_ACK:
// Send some more FINs or close anyway
if(MyTCB.retryCount <= MAX_RETRY_COUNTS)
{
SendTCP(hTCP, FIN | ACK);
}
else
{
SendTCP(hTCP, RST | ACK);
CloseSocket(hTCP);
}
break;
}
SaveTCB(hTCP);
}
}
/*********************************************************************
* Function: BOOL TCPProcess(NODE_INFO* remote,
* IP_ADDR *localIP,
* WORD len)
*
* PreCondition: TCPInit() is already called AND
* TCP segment is ready in MAC buffer
*
* Input: remote - Remote node info
* len - Total length of TCP semgent.
*
* Output: TRUE if this function has completed its task
* FALSE otherwise
*
* Side Effects: None
*
* Overview: None
*
* Note: None
********************************************************************/
BOOL TCPProcess(NODE_INFO *remote, IP_ADDR *localIP, WORD len)
{
TCP_HEADER TCPHeader;
PSEUDO_HEADER pseudoHeader;
TCP_SOCKET socket;
WORD_VAL checksum1;
WORD_VAL checksum2;
BYTE optionsSize;
// Calculate IP pseudoheader checksum.
pseudoHeader.SourceAddress = remote->IPAddr;
pseudoHeader.DestAddress = *localIP;
pseudoHeader.Zero = 0x0;
pseudoHeader.Protocol = IP_PROT_TCP;
pseudoHeader.TCPLength = len;
SwapPseudoTCPHeader(pseudoHeader);
checksum1.Val = ~CalcIPChecksum((BYTE*)&pseudoHeader,
sizeof(pseudoHeader));
// Now calculate TCP packet checksum in NIC RAM - should match
// pesudo header checksum
checksum2.Val = CalcIPBufferChecksum(len);
// Compare checksums.
if(checksum1.Val != checksum2.Val)
{
MACDiscardRx();
return TRUE;
}
// Retrieve TCP header.
IPSetRxBuffer(0);
MACGetArray((BYTE*)&TCPHeader, sizeof(TCPHeader));
SwapTCPHeader(&TCPHeader);
// Skip over options to retrieve data bytes
optionsSize = (BYTE)((TCPHeader.DataOffset.Val << 2)-
sizeof(TCPHeader));
len = len - optionsSize - sizeof(TCPHeader);
// Find matching socket.
socket = FindMatchingSocket(&TCPHeader, remote);
if(socket != INVALID_SOCKET)
{
HandleTCPSeg(socket, &TCPHeader, len);
SaveTCB(socket);
}
else
{
// If this is an unknown socket, or we don't have any
// listening sockets available, discard it. We can't
// process it right now.
MACDiscardRx();
}
return TRUE;
}
/*********************************************************************
* Function: static void SendTCP(TCP_SOCKET hTCP, BYTE flags)
*
* PreCondition: TCPInit() is already called
* LoadTCP() is called with the value of hTCP
*
* Input: hTCP: Handle of socket to send packet with
* flags: Additional TCP flags to include
*
* Output: A TCP segment is assembled and transmitted
*
* Side Effects: None
*
* Overview: None
*
* Note: Function does not save the MyTCB data. It is
* the caller's responsibility to save it.
********************************************************************/
static void SendTCP(TCP_SOCKET hTCP, BYTE flags)
{
TCB_STUB *ps;
WORD_VAL wVal;
TCP_HEADER header;
TCP_OPTIONS options;
PSEUDO_HEADER pseudoHeader;
WORD len;
ps = &TCBStubs[hTCP];
// Make sure that we can write to the MAC transmit area
while(!IPIsTxReady());
// Put all socket application data in the TX space
if(flags & SYN)
{
// Don't put any data for SYN messages
len = 0;
}
else
{
// Begin copying any application data over to the TX space
if(ps->txHead == MyTCB.txUnackedTail)
{
len = 0;
}
else if(ps->txHead > MyTCB.txUnackedTail)
{
len = ps->txHead - MyTCB.txUnackedTail;
if(len > MyTCB.remoteWindow)
len = MyTCB.remoteWindow;
MACMemCopyAsync(BASE_TX_ADDR+sizeof(ETHER_HEADER)+sizeof(IP_HEADER)+sizeof(TCP_HEADER), MyTCB.txUnackedTail, len);
MyTCB.txUnackedTail += len;
}
else
{
len = ps->bufferRxStart - MyTCB.txUnackedTail;
if(len > MyTCB.remoteWindow) //TODO: fix for new unacked bytes transmitted but not counted in the remoteWindow
len = MyTCB.remoteWindow;
MACMemCopyAsync(BASE_TX_ADDR+sizeof(ETHER_HEADER)+sizeof(IP_HEADER)+sizeof(TCP_HEADER), MyTCB.txUnackedTail, len);
pseudoHeader.TCPLength = len;
len += ps->txHead - ps->bufferTxStart;
if(len > MyTCB.remoteWindow) //TODO: fix for new unacked bytes transmitted but not counted in the remoteWindow
len = MyTCB.remoteWindow;
pseudoHeader.TCPLength = len - pseudoHeader.TCPLength;
// Copy any left over chunks of application data over
if(pseudoHeader.TCPLength)
{
MACMemCopyAsync(BASE_TX_ADDR+sizeof(ETHER_HEADER)+sizeof(IP_HEADER)+sizeof(TCP_HEADER)+(ps->bufferRxStart-MyTCB.txUnackedTail), ps->bufferTxStart, pseudoHeader.TCPLength);
}
MyTCB.txUnackedTail += len;
if(MyTCB.txUnackedTail >= ps->bufferRxStart)
MyTCB.txUnackedTail -= ps->bufferRxStart-ps->bufferTxStart;
}
}
header.SourcePort = MyTCB.localPort.Val;
header.DestPort = MyTCB.remotePort.Val;
if(flags & (SYN | FIN))
header.SeqNumber = MyTCB.MySEQ-1;
else
header.SeqNumber = MyTCB.MySEQ;
header.AckNumber = MyTCB.RemoteSEQ;
header.Flags.bits.Reserved2 = 0;
header.DataOffset.Reserved3 = 0;
header.Flags.byte = flags;
header.UrgentPointer = 0;
// For next time
MyTCB.MySEQ += (DWORD)len;
// Calculate the amount of free space in the RX buffer area of this socket
if(ps->rxHead >= ps->rxTail)
header.Window = (ps->bufferEnd - ps->bufferRxStart) - (ps->rxHead - ps->rxTail);
else
header.Window = ps->rxTail - ps->rxHead - 1;
// Calculate the amount of free space in the MAC RX buffer area and adjust window if needed
wVal.Val = MACGetFreeRxSize();
if(wVal.Val < 64)
wVal.Val = 0;
if(header.Window > wVal.Val)
header.Window = wVal.Val;
SwapTCPHeader(&header);
len += sizeof(header);
header.DataOffset.Val = sizeof(header) >> 2;
if(flags & SYN)
{
len += sizeof(options);
options.Kind = TCP_OPTIONS_MAX_SEG_SIZE;
options.Length = 0x04;
// Load MSS and swap to big endian
// options.MaxSegSize.Val = ps->bufferEnd - ps->bufferRxStart;
// options.MaxSegSize.v[0] ^= options.MaxSegSize.v[1];
// options.MaxSegSize.v[1] ^= options.MaxSegSize.v[0];
// options.MaxSegSize.v[0] ^= options.MaxSegSize.v[1];
options.MaxSegSize.Val = 0x4002; // 576
header.DataOffset.Val += sizeof(options) >> 2;
}
// Calculate IP pseudoheader checksum.
pseudoHeader.SourceAddress = AppConfig.MyIPAddr;
pseudoHeader.DestAddress = MyTCB.remote.IPAddr;
pseudoHeader.Zero = 0x0;
pseudoHeader.Protocol = IP_PROT_TCP;
pseudoHeader.TCPLength = len;
SwapPseudoTCPHeader(pseudoHeader);
header.Checksum = ~CalcIPChecksum((BYTE*)&pseudoHeader, sizeof(pseudoHeader));
MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER));
// Write IP header.
IPPutHeader(&MyTCB.remote, IP_PROT_TCP, len);
MACPutArray((BYTE*)&header, sizeof(header));
if(flags & SYN)
MACPutArray((BYTE*)&options, sizeof(options));
MACSetReadPtr(BASE_TX_ADDR + sizeof(ETHER_HEADER) + sizeof(IP_HEADER));
wVal.Val = CalcIPBufferChecksum(len);
// Update the TCP checksum and begin transmission of the packet
MACSetWritePtr(BASE_TX_ADDR + sizeof(ETHER_HEADER) + sizeof(IP_HEADER) + 16);
MACPutArray((BYTE*)&wVal, sizeof(WORD));
while(!MACIsMemCopyDone());
MACFlush();
}
/*********************************************************************
* Function: static TCP_SOCKET FindMatchingSocket(TCP_HEADER *h,
* NODE_INFO* remote)
*
* PreCondition: TCPInit() is already called
*
* Input: h - TCP Header to be matched against.
* remote - Node who sent this header.
*
* Output: A socket that matches with given header and remote
* node is searched.
* If such socket is found, its index is returned
* else INVALID_SOCKET is returned.
*
* Side Effects: None
*
* Overview: None
*
* Note: None
********************************************************************/
static TCP_SOCKET FindMatchingSocket(TCP_HEADER *h, NODE_INFO *remote)
{
TCB_STUB *ps;
TCP_SOCKET hTCP;
TCP_SOCKET partialMatch;
WORD hash;
partialMatch = INVALID_SOCKET;
hash = (remote->IPAddr.w[1]+remote->IPAddr.w[0] + h->SourcePort) ^ h->DestPort;
for(hTCP = 0; hTCP < MAX_TCP_SOCKETS; hTCP++ )
{
ps = &TCBStubs[hTCP];
if(ps->smState == TCP_CLOSED)
{
continue;
}
else if(ps->smState == TCP_LISTEN)
{
if(ps->remoteHash.Val == h->DestPort)
partialMatch = hTCP;
continue;
}
else if(ps->remoteHash.Val != hash)
{
continue;
}
LoadTCB(hTCP);
if( h->DestPort == MyTCB.localPort.Val &&
h->SourcePort == MyTCB.remotePort.Val &&
remote->IPAddr.Val == MyTCB.remote.IPAddr.Val)
{
return hTCP;
}
}
// We are not listening on this port, nor is a socket using it
if(partialMatch == INVALID_SOCKET)
return INVALID_SOCKET;
// Set up the extended TCB with the info needed to establish a
// connection and return this socket to the caller
ps = &TCBStubs[partialMatch];
ps->remoteHash.Val = hash;
ps->txHead = ps->bufferTxStart;
ps->txTail = ps->bufferTxStart;
ps->rxHead = ps->bufferRxStart;
ps->rxTail = ps->bufferRxStart;
ps->Flags.bTimerEnabled = FALSE;
memcpy((void*)&MyTCB.remote, (void*)remote, sizeof(NODE_INFO));
MyTCB.remotePort.Val = h->SourcePort;
MyTCB.localPort.Val = h->DestPort;
((DWORD_VAL*)(&MyTCB.MySEQ))->w[0] = rand();
((DWORD_VAL*)(&MyTCB.MySEQ))->w[1] = rand();
MyTCB.txUnackedTail = ps->bufferTxStart;
return partialMatch;
}
/*********************************************************************
* Function: static void SwapTCPHeader(TCP_HEADER* header)
*
* PreCondition: None
*
* Input: header - TCP Header to be swapped.
*
* Output: Given header is swapped.
*
* Side Effects: None
*
* Overview: None
*
* Note: None
********************************************************************/
static void SwapTCPHeader(TCP_HEADER* header)
{
header->SourcePort = swaps(header->SourcePort);
header->DestPort = swaps(header->DestPort);
header->SeqNumber = swapl(header->SeqNumber);
header->AckNumber = swapl(header->AckNumber);
header->Window = swaps(header->Window);
header->Checksum = swaps(header->Checksum);
header->UrgentPointer = swaps(header->UrgentPointer);
}
/*********************************************************************
* Function: static void CloseSocket(TCP_SOCKET hTCP)
*
* PreCondition: TCPInit() is already called
* LoadTCB() must be called with the value of hTCP
*
* Input: hTCP - Handle of socket to close/reinitialize
*
* Output: Given socket information is reset and any
* buffered bytes held by this socket are discarded.
*
* Side Effects: None
*
* Overview: None
*
* Note: Function does not save the MyTCB data. It is
* the caller's responsibility to save it.
********************************************************************/
static void CloseSocket(TCP_SOCKET hTCP)
{
TCB_STUB *ps;
ps = &TCBStubs[hTCP];
ps->smState = ps->Flags.bServer ? TCP_LISTEN : TCP_CLOSED;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -