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

📄 tcp.c

📁 本附件为嵌入式Web的相关资料
💻 C
📖 第 1 页 / 共 4 页
字号:
/*********************************************************************
 *
 *	Transmission Control Protocol (TCP) Communications Layer
 *  Module for Microchip TCP/IP Stack
 *	 -Provides reliable, handshaked transport of application stream 
 *    oriented data with flow control
 *	 -Reference: RFC 793
 *
 *********************************************************************
 * FileName:        TCP.c
 * Dependencies:    string.h
 *                  StackTsk.h
 *                  Helpers.h
 *                  IP.h
 *                  MAC.h
 *                  ARP.h
 *                  Tick.h
 *                  TCP.h
 * Processor:       PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F
 * Complier:        Microchip C18 v3.02 or higher
 *					Microchip C30 v2.01 or higher
 * Company:         Microchip Technology, Inc.
 *
 * Software License Agreement
 *
 * This software is owned by Microchip Technology Inc. ("Microchip") 
 * and is supplied to you for use exclusively as described in the 
 * associated software agreement.  This software is protected by 
 * software and other intellectual property laws.  Any use in 
 * violation of the software license may subject the user to criminal 
 * sanctions as well as civil liability.  Copyright 2006 Microchip
 * Technology Inc.  All rights reserved.
 *
 * This software is provided "AS IS."  MICROCHIP DISCLAIMS ALL 
 * WARRANTIES, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, NOT LIMITED 
 * TO MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND 
 * INFRINGEMENT.  Microchip shall in no event be liable for special, 
 * incidental, or consequential damages.
 *
 *
 * Author               Date    	Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Nilesh Rajbharti     5/8/01  	Original        (Rev 1.0)
 * Howard Schlunder		12/11/06	Changed almost everything to 
 *									better meet RFC 793.
 ********************************************************************/
#define __TCP_C

#include "mchp_tcp_ip\tcpip.h"

#if defined(STACK_USE_TCP)


#define MAX_TCP_DATA_LEN			(MAC_TX_BUFFER_SIZE - sizeof(TCP_HEADER) - sizeof(IP_HEADER) - sizeof(ETHER_HEADER))

// TCP Timeout and retransmit numbers
#define TCP_START_TIMEOUT_VAL   	((TICK)TICK_SECOND * (TICK)1)
#define TCP_TIME_WAIT_TIMEOUT_VAL   ((TICK)TICK_SECOND * (TICK)0)
#define MAX_RETRY_COUNTS    (5u)

// TCP Flags defined in RFC
#define FIN     (0x01)
#define SYN     (0x02)
#define RST     (0x04)
#define PSH     (0x08)
#define ACK     (0x10)
#define URG     (0x20)

// TCP Header
typedef struct _TCP_HEADER
{
	WORD    SourcePort;
	WORD    DestPort;
	DWORD   SeqNumber;
	DWORD   AckNumber;

	struct
	{
		unsigned char Reserved3      : 4;
		unsigned char Val            : 4;
	} DataOffset;

	union
	{
		struct
		{
			unsigned char flagFIN    : 1;
			unsigned char flagSYN    : 1;
			unsigned char flagRST    : 1;
			unsigned char flagPSH    : 1;
			unsigned char flagACK    : 1;
			unsigned char flagURG    : 1;
			unsigned char Reserved2  : 2;
		} bits;
		BYTE byte;
	} Flags;

	WORD    Window;
	WORD    Checksum;
	WORD    UrgentPointer;
} __attribute__((packed))  TCP_HEADER;

// TCP Options as defined by RFC
#define TCP_OPTIONS_END_OF_LIST     (0x00u)
#define TCP_OPTIONS_NO_OP           (0x01u)
#define TCP_OPTIONS_MAX_SEG_SIZE    (0x02u)
typedef struct _TCP_OPTIONS
{
	BYTE        Kind;
	BYTE        Length;
	WORD_VAL    MaxSegSize;
} __attribute__((packed)) TCP_OPTIONS;

#define SwapPseudoTCPHeader(h)  (h.TCPLength = swaps(h.TCPLength))

// IP pseudo header as defined by RFC 793
typedef struct _PSEUDO_HEADER
{
	IP_ADDR SourceAddress;
	IP_ADDR DestAddress;
	BYTE Zero;
	BYTE Protocol;
	WORD TCPLength;
} __attribute__((packed)) PSEUDO_HEADER;

#define LOCAL_PORT_START_NUMBER (1024u)
#define LOCAL_PORT_END_NUMBER   (5000u)


// Local temp port numbers.
#ifdef STACK_CLIENT_MODE
#ifdef __PIC32MX__
static WORD NextPort;
#else
static WORD NextPort __attribute__((persistent));
#endif
#endif

// The TCB array is very large.  With the C18 compiler, one must 
// modify the linker script to make an array that spans more than 
// one memory bank.  To do this, make the necessary changes to your 
// processor's linker script (.lkr).  Here is an example showing 
// gpr11 and 128 bytes of gpr12 being combined into one 384 byte 
// block used exclusively by the TCB_MEM data section:
// ...
// //DATABANK   NAME=gpr11      START=0xB00          END=0xBFF
// //DATABANK   NAME=gpr12      START=0xC00          END=0xCFF
// DATABANK   NAME=gpr11b     START=0xB00          END=0xC7F           PROTECTED
// DATABANK   NAME=gpr12      START=0xC80          END=0xCFF
// ...
// SECTION    NAME=TCP_TCB_RAM    RAM=gpr11b
// ...
#pragma udata TCB_uRAM
TCB_STUB TCBStubs[MAX_TCP_SOCKETS];
#pragma udata					// Return to any other RAM section

static TCB MyTCB;
static TCP_SOCKET hCurrentTCB = 0;


static void HandleTCPSeg(TCP_SOCKET hTCP, TCP_HEADER *h, WORD len);
static void SendTCP(TCP_SOCKET hTCP, BYTE flags);
static TCP_SOCKET FindMatchingSocket(TCP_HEADER *h, NODE_INFO *remote);
static void SwapTCPHeader(TCP_HEADER* header);
static void CloseSocket(TCP_SOCKET hTCP);
static void LoadTCB(TCP_SOCKET hTCP);
static void SaveTCB(TCP_SOCKET hTCP);



static void LoadTCB(TCP_SOCKET hTCP)
{
	WORD PtrSave;
//	if(hCurrentTCB == hTCP)
//		return;

	// Load up the new TCB
	hCurrentTCB = hTCP;
	PtrSave = MACSetReadPtr(TCBStubs[hTCP].bufferTxStart - sizeof(MyTCB));
	MACGetArray((BYTE*)&MyTCB, sizeof(MyTCB));
	MACSetReadPtr(PtrSave);
}

static void SaveTCB(TCP_SOCKET hTCP)
{
	WORD PtrSave;

	hCurrentTCB = hTCP;

	// Save the current TCB
	PtrSave = MACSetWritePtr(TCBStubs[hTCP].bufferTxStart - sizeof(MyTCB));
	MACPutArray((BYTE*)&MyTCB, sizeof(MyTCB));
	MACSetWritePtr(PtrSave);
}


/*********************************************************************
* Function:        void TCPInit(void)
*
* PreCondition:    None
*
* Input:           None
*
* Output:          TCP is initialized.
*
* Side Effects:    None
*
* Overview:        Initialize all socket states
*
* Note:            This function is called only once during lifetime
*                  of the application.
********************************************************************/
void TCPInit(void)
{
	TCP_SOCKET hTCP;
	TCB_STUB *ps;
	
	// Initialize all sockets.
	for(hTCP = 0; hTCP < MAX_TCP_SOCKETS; hTCP++)
	{
		ps = &TCBStubs[hTCP];

		ps->smState			= TCP_CLOSED;
		ps->bufferTxStart	= BASE_TCB_ADDR + sizeof(TCB) + hTCP*(sizeof(TCB) + (TCP_TX_FIFO_SIZE+1) + (TCP_RX_FIFO_SIZE + 1));
		ps->bufferRxStart	= ps->bufferTxStart + TCP_TX_FIFO_SIZE+1;
		ps->bufferEnd		= ps->bufferRxStart + TCP_RX_FIFO_SIZE;
		ps->Flags.bServer	= FALSE;
		ps->Flags.bTimerEnabled = FALSE;
	}

	// Initialize random number generator
	srand((WORD)TickGet());
}



/*********************************************************************
* Function:        TCP_SOCKET TCPListen(WORD port)
*
* PreCondition:    TCPInit() is already called.
*
* Input:           port    - A TCP port to be opened.
*
* Output:          Given port is opened and returned on success
*                  INVALID_SOCKET if no more sockets left.
*
* Side Effects:    None
*
* Overview:        None
*
* Note:            None
********************************************************************/
TCP_SOCKET TCPListen(WORD port)
{
	TCP_SOCKET hTCP;
	TCB_STUB *ps;

	for(hTCP = 0; hTCP < MAX_TCP_SOCKETS; hTCP++)
	{
		ps = &TCBStubs[hTCP];

		if(ps->smState == TCP_CLOSED)
		{
			ps->Flags.bServer = TRUE;
			ps->smState = TCP_LISTEN;
			ps->remoteHash.Val = port;
			ps->txTail = ps->bufferTxStart;
			ps->txHead = ps->bufferTxStart;
			ps->rxTail = ps->bufferRxStart;
			ps->rxHead = ps->bufferRxStart;

			MyTCB.localPort.Val = port;
			MyTCB.txUnackedTail = ps->bufferTxStart;
			((DWORD_VAL*)(&MyTCB.MySEQ))->w[0] = rand();
			((DWORD_VAL*)(&MyTCB.MySEQ))->w[1] = rand();
			SaveTCB(hTCP);
			
			return hTCP;
		}
	}

	return INVALID_SOCKET;
}


/*********************************************************************
* FunctionL		BOOL TCPGetRemoteInfo(TCP_SOCKET hTCP, SOCKET_INFO *RemoteInfo)
*
* PreCondition:	TCPInit() is already called.
*
* Input:		hTCP      - Handle of socket to read
*
* Output:		A new socket is created, connection request is
*				sent and socket handle is returned.
*
* Side Effects:	None
*
* Overview:		None
*
* Note:			None
*
********************************************************************/
SOCKET_INFO* TCPGetRemoteInfo(TCP_SOCKET hTCP)
{
	static SOCKET_INFO	RemoteInfo;

	LoadTCB(hTCP);
	memcpy((void*)&RemoteInfo.remote, (void*)&MyTCB.remote, sizeof(NODE_INFO));
	RemoteInfo.remotePort.Val = MyTCB.remotePort.Val;

	return &RemoteInfo;
}


/*********************************************************************
* Function:        TCP_SOCKET TCPConnect(NODE_INFO* remote,
*                                      WORD remotePort)
*
* PreCondition:    TCPInit() is already called.
*
* Input:           remote      - Remote node address info
*                  remotePort  - remote port to be connected.
*
* Output:          A new socket is created, connection request is
*                  sent and socket handle is returned.
*
* Side Effects:    None
*
* Overview:        None
*
* Note:            By default this function is not included in
*                  source.  You must define STACK_CLIENT_MODE to
*                  be able to use this function.
********************************************************************/
#ifdef STACK_CLIENT_MODE
TCP_SOCKET TCPConnect(NODE_INFO *remote, WORD remotePort)
{
	TCP_SOCKET hTCP;
	TCB_STUB *ps;

	// Find an available socket
	for(hTCP = 0; hTCP < MAX_TCP_SOCKETS; hTCP++)
	{
		ps = &TCBStubs[hTCP];

		if(ps->smState != TCP_CLOSED)
			continue;

		// Zero out the TCB
		memset((BYTE*)&MyTCB, 0x00, sizeof(MyTCB));

		// Each new socket that is opened by this node, gets the 
		// next sequential port number.
		if(NextPort < LOCAL_PORT_START_NUMBER || NextPort > LOCAL_PORT_END_NUMBER)
			NextPort = LOCAL_PORT_START_NUMBER;
		
		// Set the non-zero TCB fields
		MyTCB.localPort.Val = NextPort++;
		MyTCB.remotePort.Val = remotePort;
		memcpy((void*)&MyTCB.remote, (void*)remote, sizeof(NODE_INFO));
		((DWORD_VAL*)(&MyTCB.MySEQ))->w[0] = rand();
		((DWORD_VAL*)(&MyTCB.MySEQ))->w[1] = rand();
		MyTCB.retryCount = 0;
		MyTCB.retryInterval = TCP_START_TIMEOUT_VAL;

		// Zero out the buffer contents
		MyTCB.txUnackedTail	= ps->bufferTxStart;
		ps->txHead			= ps->bufferTxStart;
		ps->txTail			= ps->bufferTxStart;
		ps->rxHead			= ps->bufferRxStart;
		ps->rxTail			= ps->bufferRxStart;
		
		// Update the TCB Stub
		ps->remoteHash.Val = (remote->IPAddr.w[1]+remote->IPAddr.w[0] + remotePort) ^ MyTCB.localPort.Val;
		ps->smState = TCP_SYN_SENT;
		ps->eventTime = TickGet() + TCP_START_TIMEOUT_VAL;
		ps->Flags.bTimerEnabled = TRUE;

		// Save the TCB
		SaveTCB(hTCP);

		// Send TCP SYNchronize (connect) request
		SendTCP(hTCP, SYN);

		return hTCP;
	}

	// If there is no socket available, return error.
	return INVALID_SOCKET;
}
#endif



/*********************************************************************
* Function:        BOOL TCPIsConnected(TCP_SOCKET hTCP)
*
* PreCondition:    TCPInit() is already called.
*
* Input:           hTCP    - Socket to be checked for connection.
*
* Output:          TRUE    if given socket is connected
*                  FALSE   if given socket is not connected.
*
* Side Effects:    None
*
* Overview:        None
*
* Note:            A socket is said to be connected only if it is in 
*				   the TCP_ESTABLISHED state
********************************************************************/
BOOL TCPIsConnected(TCP_SOCKET hTCP)
{
	return TCBStubs[hTCP].smState == TCP_ESTABLISHED;
}



/*********************************************************************
* Function:        void TCPDisconnect(TCP_SOCKET hTCP)
*
* PreCondition:    TCPInit() is already called
*
* Input:           hTCP - Socket to be disconnected.
*
* Output:          A disconnect request is sent for given socket.  
*				   This function does nothing if the socket isn't 
*				   currently connected.
*
* Side Effects:    None
*
* Overview:        None
*
* Note:            None
********************************************************************/
void TCPDisconnect(TCP_SOCKET hTCP)
{

	TCB_STUB *ps;

	ps = &TCBStubs[hTCP];
	LoadTCB(hTCP);

	switch(ps->smState)
	{
		//case TCP_CLOSED:
		//case TCP_LISTEN:
		//case TCP_LAST_ACK:
		//case TCP_FIN_WAIT_1:
		//case TCP_FIN_WAIT_2:
		//case TCP_CLOSING:
		//case TCP_TIME_WAIT:
		//	return;

		case TCP_SYN_SENT:
			CloseSocket(hTCP);
			break;

		case TCP_SYN_RECEIVED:
		case TCP_ESTABLISHED:
			MyTCB.MySEQ++;
			SendTCP(hTCP, FIN | ACK);
			ps->smState = TCP_FIN_WAIT_1;
			// Clear timeout info
			MyTCB.retryCount  = 0;
			MyTCB.retryInterval = TCP_START_TIMEOUT_VAL;
			ps->eventTime = TickGet() + TCP_START_TIMEOUT_VAL;
			ps->Flags.bTimerEnabled = TRUE;
			break;

		case TCP_CLOSE_WAIT:
			MyTCB.MySEQ++;
			SendTCP(hTCP, FIN | ACK);
			ps->smState = TCP_LAST_ACK;
			// Clear timeout info
			MyTCB.retryCount  = 0;
			MyTCB.retryInterval = TCP_START_TIMEOUT_VAL;
			ps->eventTime = TickGet() + TCP_START_TIMEOUT_VAL;
			ps->Flags.bTimerEnabled = TRUE;
			break;
	}
	
	SaveTCB(hTCP);
}

/*********************************************************************
* Function:        void TCPFlush(TCP_SOCKET hTCP)
*
* PreCondition:    TCPInit() is already called.
*
* Input:           s       - Socket whose data is to be transmitted.
*
* Output:          None
*
* Side Effects:    None
*
* Overview:        None
*
* Note:            None
********************************************************************/
void TCPFlush(TCP_SOCKET hTCP)
{
	TCB_STUB *ps;

⌨️ 快捷键说明

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