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

📄 tcp.c

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

	if ( flags & SYN )
	{
		len += sizeof(options);
		options.Kind = TCP_OPTIONS_MAX_SEG_SIZE;
		options.Length = 0x04;

		// Load MSS in already swapped order.
		options.MaxSegSize.v[0]  = (MAC_RX_BUFFER_SIZE >> 8); // 0x05;
		options.MaxSegSize.v[1]  = (MAC_RX_BUFFER_SIZE & 0xff); // 0xb4;

		header.DataOffset.Val   = (sizeof(header) + sizeof(options)) >> 2;
	}
	else
		header.DataOffset.Val   = sizeof(header) >> 2;


	// Calculate IP pseudoheader checksum.
	pseudoHeader.SourceAddress	= AppConfig.MyIPAddr;
	pseudoHeader.DestAddress    = remote->IPAddr;
	pseudoHeader.Zero           = 0x0;
	pseudoHeader.Protocol       = IP_PROT_TCP;
	pseudoHeader.TCPLength      = len;

	SwapPseudoTCPHeader(pseudoHeader);

	header.Checksum = ~CalcIPChecksum((BYTE*)&pseudoHeader,
		sizeof(pseudoHeader));
	checkSum.Val = header.Checksum;

	// Write IP header.
	IPPutHeader(remote, IP_PROT_TCP, len);
	IPPutArray((BYTE*)&header, sizeof(header));

	if ( flags & SYN )
		IPPutArray((BYTE*)&options, sizeof(options));

	IPSetTxBuffer(buffer, 0);

	checkSum.Val = CalcIPBufferChecksum(len);

	// Update the checksum.
	IPSetTxBuffer(buffer, 16);
	MACPut(checkSum.v[1]);
	MACPut(checkSum.v[0]);
	MACSetTxBuffer(buffer, 0);

	MACFlush();

#if !defined(TCP_NO_WAIT_FOR_ACK) && !defined(DEBUG)
	// If we send the packet again, the remote node might think that we timed 
	// out and retransmitted.  It could thus immediately send back an ACK and 
	// dramatically improve throuput.
	while(!IPIsTxReady(TRUE));
	MACFlush();
#endif
}



/*********************************************************************
* 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)
{
	SOCKET_INFO *ps;
	TCP_SOCKET s;
	TCP_SOCKET partialMatch;

	partialMatch = INVALID_SOCKET;

	for ( s = 0; s < MAX_SOCKETS; s++ )
	{
		ps = &TCB[s];

		if ( ps->smState != TCP_CLOSED )
		{
			if ( ps->localPort == h->DestPort )
			{
				if ( ps->smState == TCP_LISTEN )
					partialMatch = s;

				if ( ps->remotePort == h->SourcePort &&
					ps->remote.IPAddr.Val == remote->IPAddr.Val )
				{
					return s;
				}
			}
		}
	}

	// We are not listening on this port
	if(partialMatch == INVALID_SOCKET)
		return INVALID_SOCKET;

	// Copy the remote node IP/MAC address and source TCP port 
	// number into our TCB and return this socket to the caller
	ps = &TCB[partialMatch];
	memcpy((void*)&ps->remote, (void*)remote, sizeof(*remote));
	ps->remotePort          = h->SourcePort;
	ps->Flags.bIsGetReady   = FALSE;
	if(ps->TxBuffer != INVALID_BUFFER)
	{
		MACDiscardTx(ps->TxBuffer);
		ps->TxBuffer        = INVALID_BUFFER;
	}
	ps->Flags.bIsPutReady   = TRUE;
	
	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(SOCKET_INFO* ps)
*
* PreCondition:    TCPInit() is already called
*
* Input:           ps  - Pointer to a socket info that is to be
*                          closed.
*
* Output:          Given socket information is reset and any
*                  buffer held by this socket is discarded.
*
* Side Effects:    None
*
* Overview:        None
*
* Note:            None
********************************************************************/
static void CloseSocket(SOCKET_INFO* ps)
{
	if(ps->TxBuffer != INVALID_BUFFER)
	{
		MACDiscardTx(ps->TxBuffer);
		ps->TxBuffer            = INVALID_BUFFER;
		ps->Flags.bIsPutReady   = TRUE;
	}

	ps->remote.IPAddr.Val = 0x00;
	ps->remotePort = 0x00;
	if(ps->Flags.bIsGetReady)
	{
		MACDiscardRx();
	}
	ps->Flags.bIsGetReady       = FALSE;
	ps->TimeOut                 = TCP_START_TIMEOUT_VAL;

	ps->Flags.bIsTxInProgress   = FALSE;

	if(ps->Flags.bServer)
	{
		ps->smState = TCP_LISTEN;
	}
	else
	{
		ps->smState = TCP_CLOSED;
	}

	ps->TxCount = 0;

	return;
}



/*********************************************************************
* Function:        static void HandleTCPSeg(TCP_SOCKET s,
*                                      NODE_INFO *remote,
*                                      TCP_HEADER* h,
*                                      WORD len)
*
* PreCondition:    TCPInit() is already called     AND
*                  TCPProcess() is the caller.
*
* Input:           s           - Socket that owns this segment
*                  remote      - Remote node info
*                  h           - TCP Header
*                  len         - Total buffer length.
*
* Output:          TCP FSM is executed on given socket with
*                  given TCP segment.
*
* Side Effects:    None
*
* Overview:        None
*
* Note:            None
********************************************************************/
static void HandleTCPSeg(TCP_SOCKET s,
						 NODE_INFO *remote,
						 TCP_HEADER *h,
						 WORD len)
{
	DWORD ack;
	DWORD seq;
	DWORD prevAck, prevSeq;
	SOCKET_INFO *ps;
	BYTE flags;

	ps = &TCB[s];

	flags = 0x00;

	// Clear timeout info
	ps->RetryCount  = 0;
	ps->startTick   = TickGet();
	ps->TimeOut = TCP_START_TIMEOUT_VAL;

	// Reset FSM, if RST is received.
	if(h->Flags.bits.flagRST)
	{
		MACDiscardRx();
		ps->smState = ps->Flags.bServer ? TCP_LISTEN : TCP_SYN_SENT;
		return;
	}

	seq = ps->SND_SEQ;
	
	// ack is just a temporary variable
	ack = h->Window - (seq - h->AckNumber) - ps->TxCount;
	if((signed long)ack < 0)
		ps->RemoteWindow = 0;
	else
		ps->RemoteWindow = ack;


#ifdef STACK_CLIENT_MODE
	// Handle TCP_SYN_SENT state
	// The TCP_SYN_SENT state occurs when an application 
	// calls TCPConnect().  After an initial SYN is sent,
	// we expect a SYN + ACK before establishing the 
	// connection.
	if(ps->smState == TCP_SYN_SENT)
	{
		// Check if this is a SYN packet.  Unsynchronized, we cannot
		// handle any other packet types.
		if(!h->Flags.bits.flagSYN)
		{
			MACDiscardRx();

			// Send out a RESET if the remote node thinks a connection is already established
		    if(h->Flags.bits.flagACK)
		    {
				flags = RST;
				goto SendTCPControlPacket;
	        }

			return;
		}

		// We now have a sequence number for the remote node
		ps->SND_ACK = h->SeqNumber + len + 1;
		ack = ps->SND_ACK;

		// If there is no ACK, we must go to TCP_SYN_RECEIVED.  With an ACK, 
		// we can establish the connection now.
		if(!h->Flags.bits.flagACK)
		{
			ps->smState = TCP_SYN_RECEIVED;
			MACDiscardRx();
			// Send out a SYN+ACK for simultaneous connection open
			flags = SYN | ACK;
			goto SendTCPControlPacket;
		}

		// We received SYN+ACK, establish the connection now
		ps->smState = TCP_ESTABLISHED;
		// Send out an ACK
		flags = ACK;

		ps->RemoteWindow = h->Window;

		// Check for application data and make it 
		// available, if present
		if(len)
		{
			ps->Flags.bIsGetReady   = TRUE;
			ps->RxCount             = len;
			ps->Flags.bFirstRead    = TRUE;
		}
		else	// No application data in this packet
		{
			MACDiscardRx();
		}
		goto SendTCPControlPacket;
	}
#endif

	// Handle TCP_LISTEN state
	if(ps->smState == TCP_LISTEN )
	{
		MACDiscardRx();

		// Send a RST if this isn't a SYN packet
		if(!h->Flags.bits.flagSYN)
		{
			flags = RST;
			goto SendTCPControlPacket;
		}

		ps->SND_ACK = h->SeqNumber + len + 1;
		ps->RemoteWindow = h->Window;

		// This socket has received connection request (SYN).
		// Remember calling node, assign next segment seq. number
		// for this potential connection.
		memcpy((void*)&ps->remote, (const void*)remote, sizeof(*remote));
		ps->remotePort = h->SourcePort;

		// Grant connection request.
		ps->smState = TCP_SYN_RECEIVED;
		seq = ps->SND_SEQ++;
		ack =  ps->SND_ACK;
		flags = SYN | ACK;
		goto SendTCPControlPacket;
	}


	// Remember current seq and ack for our connection so that if
	// we have to silently discard this packet, we can go back to
	// previous ack and seq numbers.
	prevAck = ps->SND_ACK;
	prevSeq = ps->SND_SEQ;

	ack = h->SeqNumber;
	ack += (DWORD)len;
	seq = ps->SND_SEQ;

	// State is something other than TCP_LISTEN, handle it.
	{
		// Check to see if the incomming sequence number is what 
		// we expect (last transmitted ACK value).  Throw this packet 
		// away if it is wrong.
		if(h->SeqNumber == prevAck)
		{
			// After receiving a SYNchronization request, we expect an 
			// ACK to our transmitted SYN
			if(ps->smState == TCP_SYN_RECEIVED)
			{
				if(h->Flags.bits.flagACK)
				{
					// ACK received as expected, this connection is 
					// now established
					ps->SND_ACK = ack;
					ps->smState = TCP_ESTABLISHED;

					// Check if this first packet has application data 
					// in it.  Make it available if so.
					if(len)
					{
						ps->Flags.bIsGetReady   = TRUE;
						ps->RxCount             = len;
						ps->Flags.bFirstRead    = TRUE;
					}
					else
						MACDiscardRx();
				}
				else	// No ACK to our SYN
				{
					MACDiscardRx();
				}
			}
			// Connection is established, closing, or otherwise
			else
			{

				// Save the seq+len value of the packet for our future 
				// ACK transmission, and so out of sequence packets 
				// can be detected in the future.
				ps->SND_ACK = ack;

				// Handle packets received while connection established.
				if(ps->smState == TCP_ESTABLISHED)
				{
					// If this packet has the ACK set, mark all 
					// previous TX packets as no longer needed for 
					// possible retransmission.
					// TODO: Make this more sophisticated so that partial ACKs due to fragmentation are handled correctly.  i.e. Keep a real output stream buffer with slidable window capability.
					if(h->Flags.bits.flagACK && !ps->Flags.bIsPutReady)
					{
						if(ps->TxBuffer != INVALID_BUFFER)
						{
							MACDiscardTx(ps->TxBuffer);
							ps->TxBuffer            = INVALID_BUFFER;
							ps->Flags.bIsPutReady   = TRUE;
						}
					}

					// Check if the remote node is closing the connection
					if(h->Flags.bits.flagFIN)
					{
						DebugPrint("|");
						flags = FIN | ACK;
						seq = ps->SND_SEQ++;
						ack = ++ps->SND_ACK;
						ps->smState = TCP_LAST_ACK;
					}

					// Check if there is any application data in 
					// this packet.
					if(len)
					{
						// There is data.  Make it available if we 
						// don't already have data available.
						if(!ps->Flags.bIsGetReady)
						{
							ps->Flags.bIsGetReady   = TRUE;
							ps->RxCount             = len;
							ps->Flags.bFirstRead    = TRUE;

							// 4/1/02
							flags |= ACK;
						}
						// There is data, but we cannot handle it at this time.
						else
						{
							DebugPrint("D");
							// Since we cannot accept this packet,
							// restore to previous seq and ack.
							// and do not send anything back.
							// Host has to resend this packet when
							// we are ready.
							ps->SND_SEQ = prevSeq;
							ps->SND_ACK = prevAck;

							MACDiscardRx();
						}
					}
					// There is no data in this packet, and thus it 
					// can be thrown away.
					else
					{
						MACDiscardRx();
					}
				}
				// Connection is not established; check if we've sent 
				// a FIN and expect our last ACK
				else if(ps->smState == TCP_LAST_ACK)
				{
					MACDiscardRx();

					if(h->Flags.bits.flagACK)
					{
						CloseSocket(ps);
					}
				}
				else if(ps->smState == TCP_FIN_WAIT_1)
				{
					MACDiscardRx();

					if(h->Flags.bits.flagFIN)
					{
						flags = ACK;
						ack = ++ps->SND_ACK;
						if(h->Flags.bits.flagACK)
						{
							CloseSocket(ps);
						}
						else
						{
							ps->smState = TCP_CLOSING;
						}
					}
					else if(h->Flags.bits.flagACK)
					{
						ps->smState = TCP_FIN_WAIT_2;
					}
				}
				else if(ps->smState == TCP_FIN_WAIT_2)
				{
					MACDiscardRx();

					if(h->Flags.bits.flagFIN)
					{
						flags = ACK;
						ack = ++ps->SND_ACK;
						CloseSocket(ps);
					}
				}
				else if ( ps->smState == TCP_CLOSING )
				{
					MACDiscardRx();

					if ( h->Flags.bits.flagACK )
					{
						CloseSocket(ps);
					}
				}
			}
		}
		// This packet's sequence number does not match what we were 
		// expecting (the last value we ACKed).  Throw this packet 
		// away.  This may happen if packets are delivered out of order.
		// Not enough memory is available on our PIC or Ethernet 
		// controller to implement a robust stream reconstruction 
		// buffer.  As a result, the remote node will just have to 
		// retransmit its packets starting with the proper sequence number.
		else
		{
			MACDiscardRx();

			// Send a new ACK out in case if the previous one was lost 
			// (ACKs aren't ACKed).  This is required to prevent an 
			// unlikely but possible situation which would cause the 
			// connection to time out if the ACK was lost and the 
			// remote node keeps sending us older data than we are 
			// expecting.
			flags = ACK;	
			ack = prevAck;
		}
	}

SendTCPControlPacket:
	if(flags)
	{
		SendTCP(remote,
			h->DestPort,
			h->SourcePort,
			seq,
			ack,
			flags);
	}
}


#endif //#if defined(STACK_USE_TCP)

⌨️ 快捷键说明

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