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

📄 tcp.c

📁 单片机c语言程序设计100例--基于PIC+PROTEUS
💻 C
📖 第 1 页 / 共 3 页
字号:

		// Check to make sure that we received a TX Buffer
		if(ps->TxBuffer == INVALID_BUFFER)
			return FALSE;

		ps->TxCount = 0;

		IPSetTxBuffer(ps->TxBuffer, sizeof(TCP_HEADER));
	}

	ps->Flags.bIsTxInProgress = TRUE;

	MACPut(byte);
	ps->RemoteWindow--;

	if(++ps->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 TCP data
			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)
{
	TCP_SOCKET s;
	TICK diffTicks;
	TICK tick;
	SOCKET_INFO* ps;
	DWORD seq;
	BYTE flags;

	flags = 0x00;
	// Periodically all "not closed" sockets must perform timed operations
	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;

		// Most states require retransmission, so check for transmitter
		// availability right here - common for all.
		if(!IPIsTxReady(TRUE))
			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.
		switch(ps->smState)
		{
		case TCP_SYN_SENT:
			// Keep sending SYN until we hear from remote node.
			// This may be for infinite time, in that case
			// caller must detect it and do something.
			// Bug Fix: 11/1/02
			flags = SYN;
			break;

		case TCP_SYN_RECEIVED:
			// We must receive ACK before timeout expires.
			// If not, resend SYN+ACK.
			// Abort, if maximum attempts counts are reached.
			if(ps->RetryCount <= MAX_RETRY_COUNTS)
			{
				flags = SYN | ACK;
			}
			else
			{
				if(ps->Flags.bServer)
				{
					ps->smState = TCP_LISTEN;
				}
				else
				{
					flags = SYN;
					ps->smState = TCP_SYN_SENT;
				}
			}
			break;

		case TCP_ESTABLISHED:
#if !defined(TCP_NO_WAIT_FOR_ACK)
			// Don't let this connection idle for very long time.
			// If we did not receive or send any message before timeout
			// expires, close this connection.
			if(ps->RetryCount <= MAX_RETRY_COUNTS)
			{
				if(ps->TxBuffer != INVALID_BUFFER)
				{
					MACSetTxBuffer(ps->TxBuffer, 0);
					MACFlush();
				}
				else
					flags = ACK;
			}
			else
			{
				// Forget about previous transmission.
				if(ps->TxBuffer != INVALID_BUFFER)
				{
					MACDiscardTx(ps->TxBuffer);
					ps->TxBuffer = INVALID_BUFFER;
				}

#endif
				// Request closure.
				flags = FIN | ACK;
				DebugPrint("!");

				ps->smState = TCP_FIN_WAIT_1;
#if !defined(TCP_NO_WAIT_FOR_ACK)
			}
#endif
			break;

		case TCP_FIN_WAIT_1:
			if(ps->RetryCount <= MAX_RETRY_COUNTS)
			{
					// Send another FIN
					flags = FIN;
			}
			else
			{
				// Close on our own, we can't seem to communicate 
				// with the remote node anymore
				CloseSocket(ps);
			}
			break;

		case TCP_FIN_WAIT_2:
		case TCP_CLOSING:
			// Close on our own, we can't seem to communicate 
			// with the remote node anymore
			CloseSocket(ps);
			break;

		case TCP_TIME_WAIT:
			// Wait around for a while (2MSL) and then goto closed state
			CloseSocket(ps);
			break;
		
		case TCP_CLOSE_WAIT:
			flags = FIN;
			ps->smState = TCP_LAST_ACK;
			break;

		case TCP_LAST_ACK:
			// Send some more FINs or close anyway
			if(ps->RetryCount <= MAX_RETRY_COUNTS)
				flags = FIN;
			else
				CloseSocket(ps);
			break;
		}


		if(flags)
		{
			if(flags & ACK)
				seq = ps->SND_SEQ;
			else
				seq = ps->SND_SEQ++;

			SendTCP(&ps->remote,
				ps->localPort,
				ps->remotePort,
				seq,
				ps->SND_ACK,
				flags);
		}
	}
}



/*********************************************************************
* 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.  Note that the endianness is different.
	if(checksum1.v[0] != checksum2.v[1] || checksum1.v[1] != checksum2.v[0])
	{
		MACDiscardRx();
		return TRUE;
	}

	// Retrieve TCP header.
	IPSetRxBuffer(0);
	MACGetArray((BYTE*)&TCPHeader, sizeof(TCPHeader));
	SwapTCPHeader(&TCPHeader);


	// Skip over options and retrieve all data bytes.
	optionsSize = (BYTE)((TCPHeader.DataOffset.Val << 2)-
		sizeof(TCPHeader));
	len = len - optionsSize - sizeof(TCPHeader);

	// Position packet read pointer to start of data area.
	IPSetRxBuffer((TCPHeader.DataOffset.Val << 2));

	// Find matching socket.
	socket = FindMatchingSocket(&TCPHeader, remote);
	if(socket != INVALID_SOCKET)
	{
		HandleTCPSeg(socket, remote, &TCPHeader, len);
	}
	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();
		
//		// Send a RESET to the remote node is it knows that we 
//		// are not available
//		TCPHeader.AckNumber += len;
//		if( TCPHeader.Flags.bits.flagSYN ||
//			TCPHeader.Flags.bits.flagFIN )
//			TCPHeader.AckNumber++;
//		
//		SendTCP(remote,
//			TCPHeader.DestPort,
//			TCPHeader.SourcePort,
//			TCPHeader.AckNumber,
//			TCPHeader.SeqNumber,
//			RST);
	}

	return TRUE;
}


/*********************************************************************
* Function:        static void TransmitTCP(NODE_INFO* remote
*                                          TCP_PORT localPort,
*                                          TCP_PORT remotePort,
*                                          DWORD seq,
*                                          DWORD ack,
*                                          BYTE flags,
*                                          BUFFER buffer,
*                                          WORD len)
*
* PreCondition:    TCPInit() is already called     AND
*                  TCPIsPutReady() == TRUE
*
* Input:           remote      - Remote node info
*                  localPort   - Source port number
*                  remotePort  - Destination port number
*                  seq         - Segment sequence number
*                  ack         - Segment acknowledge number
*                  flags       - Segment flags
*                  buffer      - Buffer to which this segment
*                                is to be transmitted
*                  len         - Total data length for this segment.
*
* Output:          A TCP segment is assembled and put to transmit.
*
* Side Effects:    None
*
* Overview:        None
*
* Note:            None
********************************************************************/
static void TransmitTCP(NODE_INFO *remote,
						TCP_PORT localPort,
						TCP_PORT remotePort,
						DWORD tseq,
						DWORD tack,
						BYTE flags,
						BUFFER buffer,
						WORD len)
{
	WORD_VAL        checkSum;
	TCP_HEADER      header;
	TCP_OPTIONS     options;
	PSEUDO_HEADER   pseudoHeader;

	//  Make sure that this Tx buffer isn't currently being transmitted
	while( !IPIsTxReady(TRUE) );	//TODO: This may need to be conditionally false

	// Obtain an AutoFree buffer if this packet is a control packet 
	// only (contains no application data in an already allocated 
	// buffer)
	if(buffer == INVALID_BUFFER)
		buffer = MACGetTxBuffer(TRUE);

	if(buffer == INVALID_BUFFER)
		return;

	IPSetTxBuffer(buffer, 0);

	header.SourcePort           = localPort;
	header.DestPort             = remotePort;
	header.SeqNumber            = tseq;
	header.AckNumber            = tack;
	header.Flags.bits.Reserved2 = 0;
	header.DataOffset.Reserved3 = 0;
	header.Flags.byte           = flags;
	// Receive window = MAC Free buffer size - TCP header (20) - IP header (20)
	//                  - ETHERNET header (14 if using NIC) .
	header.Window               = MACGetFreeRxSize();
#if !defined(STACK_USE_SLIP)
	/*
	* Limit one segment at a time from remote host.
	* This limit increases overall throughput as remote host does not
	* flood us with packets and later retry with significant delay.
	*/
	if ( header.Window >= MAC_RX_BUFFER_SIZE )
		header.Window = MAC_RX_BUFFER_SIZE;

	else if ( header.Window > 54 )
	{
		header.Window -= 54;
	}
	else
		header.Window = 0;
#else
	if ( header.Window > 40 )
	{
		header.Window -= 40;
	}
	else
		header.Window = 0;
#endif

	header.Checksum             = 0;
	header.UrgentPointer        = 0;

	SwapTCPHeader(&header);

	len += sizeof(header);

⌨️ 快捷键说明

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