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

📄 tcp.c

📁 本附件为嵌入式Web的相关资料
💻 C
📖 第 1 页 / 共 4 页
字号:
					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 + -