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

📄 tcp.c

📁 udp,tcp/ip在智能家居芯片上的代码实现.包括芯片NE64的网络驱动源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
#include <debug.h>
#include <datatypes.h>
#include <timers.h>
#include <ethernet.h>

#if defined(IPv6)
	#include <ipv6.h>
	extern struct _in6_addr LocalIP;
#else
	#include <ip.h>
#endif

#include <tcp_ip.h>
#include <system.h>

/**	\brief Used for storing field information about the received TCP packet
 *	
 *	Various fields from the TCP packet are stored in this variable. These
 *	values are then used to perform the necessary actions as defined 
 *	by the TCP specification: correctnes of the received TCP packet is
 *	checked by analyzing these fields, appropriate socket data is adjusted
 *	and/or control packet is sent based on it. See tcp_frame definition 
 * 	for struct information.
 */
struct tcp_frame received_tcp_packet;

/** \brief TCP table holding connection parameters for every TCP socket 
 *
 *	TCP table is an array of tcp_socket structures holding all of the 
 * necessary information about the state, timers, timeouts and sequence
 *	and port numbers of the TCP sockets opened. Number of TCP sockets
 *	that can be opened at any given time is defined by the #NO_OF_TCPSOCKETS
 *	and may be changed in order to change the amount of used RAM memory.
 *	See tcb definition for more information about the structure itself.
 *
 *	\note As seen in the code, an array size is actually bigger for one
 *	than the #NO_OF_TCPSOCKETS defines. The last entry is used for sending
 *	control packets as answers to incoming TCP packets that do not map 
 *	to any existing TCP sockets.
 */
struct tcb tcp_socket[NO_OF_TCPSOCKETS + 1]; 

UINT8 tcp_tempbuf[MIN_TCP_HLEN + 1]; /**< Temporary buffer used for sending TCP control packets */


/***********************************************************************/
/*******	TCP API functions									********/
/***********************************************************************/

/** \brief Allocate a free socket in TCP socket pool
 *  \ingroup tcp_app_api
 * 	\author 
 *		\li Jari Lahti (jari.lahti@violasystems.com)
 *	\date 21.07.2002
 *	\param soctype type of socket wanted. Can take one of the following
 *		values:
 *		\li #TCP_TYPE_NONE
 *		\li #TCP_TYPE_SERVER
 *		\li #TCP_TYPE_CLIENT
 *		\li #TCP_TYPE_CLIENT_SERVER
 *	\param tos type of service for socket. For now only #TCP_TOS_NORMAL.
 *	\param tout Timeout of socket in seconds. Defines after how many seconds
 *		of inactivity (application not sending and/or receiving any data
 *		over TCP connection) will the TCP socket automatically be closed.
 *	\param listener pointer to callback function that will be invoked by
 *		the TCP/IP stack to inform socket application of certain events. See
 *		tcpc_demo_eventlistener() and tcps_demo_eventlistener() for more
 *		information on events and possible actions.
 *	\return 
 *		\li -1 - Error getting requested socket
 *		\li >=0 - Handle to reserved socket
 *
 *	Invoke this function to try to obtain a free socket from TCP socket pool.
 *	Function returns a handle to the free socket that is later used for 
 *	accessing the allocated socket (opening, connecting, sending data,
 *	closing, aborting, etc.).
 */
#ifdef IPv6
INT8 tcp_getsocket (UINT8 soctype, UINT8 tos, UINT16 tout, INT32 (*listener)(INT8, UINT8, IPv6Addr*, UINT32) )
#else
INT8 tcp_getsocket (UINT8 soctype, UINT8 tos, UINT16 tout, INT32 (*listener)(INT8, UINT8, UINT32, UINT32) )
#endif
{
	INT8 i;
	struct tcb* soc;
	
	if( NO_OF_TCPSOCKETS < 0 )
		return(-1);
	
	if( NO_OF_TCPSOCKETS == 0 )
		return(-1);
	
	if( (soctype != TCP_TYPE_SERVER) &&
		(soctype != TCP_TYPE_CLIENT) &&
		(soctype != TCP_TYPE_CLIENT_SERVER) &&
		(soctype != TCP_TYPE_NONE)				) {
		TCP_DEBUGOUT("Invalid socket type requested\r\n");
		return(-1);
	}
	
	if(listener == 0) {
		TCP_DEBUGOUT("ERROR:Event listener function not specified\r\n");
		return(-1);
	}
	
	TCP_DEBUGOUT("Searching for free TCP socket...\r\n");
	
	for(i=0; i < NO_OF_TCPSOCKETS; i++)	{
		soc = &tcp_socket[i];			/* Get Socket	*/
	
		if(soc->state == TCP_STATE_FREE) {
			/* We found it	*/
			
			TCP_DEBUGOUT("Free socket found\r\n");
			
			soc->state = TCP_STATE_RESERVED;
			soc->type = soctype;
			soc->tos = tos;
			soc->event_listener = listener;
#ifdef IPv6
//			memset (&soc->rem_ip->u.byte[0],0,sizeof(IPv6Addr));
			soc->rem_ip = (void *)0x0000;
#else
			soc->rem_ip = 0;
#endif	
			soc->remport = 0;
			soc->locport = 0;
			soc->flags = 0;
			soc->tout = tout*TIMERTIC;
			
			return(i);
		}
	
	}
	
	/* We are there so no socket found	*/
	
	TCP_DEBUGOUT("No socket found\r\n");
	return(-1);

}

/** \brief Release a TCP socket
 *  \ingroup tcp_app_api
 * 	\author 
 *		\li Jari Lahti (jari.lahti@violasystems.com)
 *	\date 21.07.2002
 *	\param sochandle handle to socket to be released
 *	\return 
 *		\li -1 - Error releasing the socket (Wrong socket handle or socket
 *		not in proper state to be released)
 *		\li >=0 - handle of the released socket (can not be used any more
 *		untill allocated again with tcp_getsocket()).
 *
 *	Once the application does not need the TCP socket any more it can invoke
 *	this function in order to release it. This is usefull if there is a very
 *	limited number of sockets (in order to save some memory) shared among
 *	several applications.
 */
INT8 tcp_releasesocket (INT8 sochandle)
{
	struct tcb* soc;
	
	if( NO_OF_TCPSOCKETS < 0 )
		return(-1);
	
	if( NO_OF_TCPSOCKETS == 0 )
		return(-1);
	
	if( sochandle > NO_OF_TCPSOCKETS ) {
		TCP_DEBUGOUT("Socket handle non-valid\r\n");
		return(-1);
	}
	
	if( sochandle < 0 ) {
		TCP_DEBUGOUT("Socket handle non-valid\r\n");
		return(-1);
	}
	
	soc = &tcp_socket[sochandle];		/* Get referense	*/
	
	if( (soc->state != TCP_STATE_FREE) &&
		(soc->state != TCP_STATE_RESERVED) &&
		(soc->state != TCP_STATE_CLOSED)		) {
		TCP_DEBUGOUT("Socket is not on valid state to be released\r\n");
		return(-1);
	}
	
	/* We are there so all OK	*/
	
	soc->state = TCP_STATE_FREE;
	soc->type = TCP_TYPE_NONE;
	soc->tos = 0;
	soc->event_listener = 0;
	soc->rem_ip = 0;
	soc->remport = 0;
	soc->locport = 0;
	soc->flags = 0;
	
	return(sochandle);

}

/** \brief Put TCP socket to listen on a given port
 *  \ingroup tcp_app_api
 * 	\author 
 *		\li Jari Lahti (jari.lahti@violasystems.com)
 *	\date 21.07.2002
 *	\param sochandle handle to socket to be placed to listen state
 *	\param port TCP port number on which it should listen
 *	\return
 *		\li -1 - Error
 *		\li >=0 - OK (Socket put to listening state. Handle to 
 *		socket returned)
 *
 *	This function will attempt to put socket to listening state. This
 *	is only possible if socket was defined as either #TCP_TYPE_SERVER or
 *	#TCP_TYPE_CLIENT_SERVER. If basic correctness checks pass, socket is 
 *	put to listening mode and corresponding tcb entry is initialized.
 *
 */
INT8 tcp_listen (INT8 sochandle, UINT16 port)
{
	struct tcb* soc;

	if( NO_OF_TCPSOCKETS < 0 )
		return(-1);
	
	if( NO_OF_TCPSOCKETS == 0 )
		return(-1);
	
	if( sochandle > NO_OF_TCPSOCKETS ) {
		TCP_DEBUGOUT("Socket handle non-valid\r\n");
		return(-1);
	}
	
	if( sochandle < 0 ) {
		TCP_DEBUGOUT("Socket handle non-valid\r\n");
		return(-1);
	}
	
	soc = &tcp_socket[sochandle];		/* Get referense	*/
		
	if( (soc->type & TCP_TYPE_SERVER) == 0 ) {
		TCP_DEBUGOUT("Socket has no server properties\r\n");
		return(-1);
	}
	
	if( soc->event_listener == 0) {
		TCP_DEBUGOUT("ERROR:No event listener function specified\r\n");
		return(-1);
	}
	
	
	if( (soc->state != TCP_STATE_RESERVED) &&
		(soc->state != TCP_STATE_LISTENING)	&&
		(soc->state != TCP_STATE_CLOSED) &&		
		(soc->state != TCP_STATE_TIMED_WAIT)		) {
		TCP_DEBUGOUT("Not possible to listen, socket on connected state\r\n");
		return(-1);
	
	}
	
			
	/* Init socket		*/
				
	soc->state = TCP_STATE_LISTENING;
	/*soc->type = TCP_TYPE_SERVER;*/
	soc->flags = 0;
	soc->rem_ip = 0;
	soc->remport = 0;
	soc->locport = port;
	soc->send_unacked = 0;
	soc->myflags = 0;
	soc->send_next = 0xFFFFFFFF;
	soc->send_mtu = TCP_DEF_MTU;
	soc->receive_next = 0;
	soc->retries_left = 0;
			
	TCP_DEBUGOUT("TCP listening socket created\r\n");
			
	return(sochandle);

}


/** \brief Initialize connection establishment towards remote IP&port
 *  \ingroup tcp_app_api
 * 	\author 
 *		\li Jari Lahti (jari.lahti@violasystems.com)
 *	\date 21.07.2002
 *	\param sochandle handle to socket to be used for connection establishment
 *	\param ip remote IP address to connect to 
 *	\param rport remote port number to connect to
 *	\param myport local port to use for connection. This value can be
 *		specified directly or, if a value of 0 is given, TCP module will
 *		determine local TCP port automatically.
 *	\return 
 *		\li -1 - Error
 *		\li >=0 - OK (Connection establishment procedure started. Socket handle
 *			returned.)
 *
 *	Invoke this function to start connection establishment procedure towards
 *	remote host over some socket. This is only possible if socket was
 *	defined as either #TCP_TYPE_CLIENT or #TCP_TYPE_CLIENT_SERVER. Function 
 *	will make some basic checks and if everything is OK, corresponding tcb
 *	socket entry will be initialized and connection procedure started.
 */
#ifdef IPv6
INT8 tcp_connect (INT8 sochandle, struct _in6_addr* ip, UINT16 rport, UINT16 myport )
#else
INT8 tcp_connect (INT8 sochandle, UINT32 ip, UINT16 rport, UINT16 myport )
#endif
{
	struct tcb* soc;
	
	TCP_DEBUGOUT("FUNCTION: tcp_connect\r\n");

	if( NO_OF_TCPSOCKETS < 0 )
		return(-1);
	
	if( NO_OF_TCPSOCKETS == 0 )
		return(-1);
	
	if( sochandle > NO_OF_TCPSOCKETS ) {
		TCP_DEBUGOUT("Socket handle non-valid\r\n");
		return(-1);
	}
	
	if( sochandle < 0 ) {
		TCP_DEBUGOUT("Socket handle non-valid\r\n");
		return(-1);
	}
	
	/* Is the local port defined	*/
	
	if( myport == 0 )
		myport = tcp_getfreeport();
	
	if( myport == 0 )
		return(-1);
	
	soc = &tcp_socket[sochandle];		/* Get referense	*/
	
	/* Do we have client properties?	*/
	
	if( (soc->type & TCP_TYPE_CLIENT) == 0 ) {
		TCP_DEBUGOUT("Socket has no client properties\r\n");
		return(-1);
	}
	
	if( soc->event_listener == 0) {
		TCP_DEBUGOUT("ERROR:No event listener function specified\r\n");
		return(-1);
	}
	
	/* Are we on LISTENING, RESERVED or CLOSED state	*/
	
	if( (soc->state != TCP_STATE_RESERVED) &&
		(soc->state != TCP_STATE_LISTENING) &&
		(soc->state != TCP_STATE_CLOSED)		) {
		TCP_DEBUGOUT("Socket on unvalid state to initialize CONNECT\r\n");
		return(-1);
	}
	
	/* Then just set parameters and send SYN	*/
	
	soc->rem_ip = ip;
	soc->remport = rport;
	soc->locport = myport;
	soc->flags = 0;
	soc->send_mtu = TCP_DEF_MTU;
	
	/* get initial sequence number	*/
	
	soc->send_unacked = tcp_initseq(); 
	soc->send_next = soc->send_unacked + 1;
	soc->myflags = TCP_FLAG_SYN;
	tcp_sendcontrol(sochandle);
	tcp_newstate(soc, TCP_STATE_SYN_SENT);
	
	return(sochandle);
}



/** \brief Send user data over TCP using given TCP socket
 *  \ingroup tcp_app_api
 * 	\author 
 *		\li Jari Lahti (jari.lahti@violasystems.com)
 *	\date 25.07.2002
 *	\param sockethandle handle to TCP socket to be used for sending data
 *	\param buf pointer to data buffer (start of user data)
 *	\param blen buffer length in bytes (without space reserved at the
 *		beginning of buffer for headers)
 *	\param dlen length of user data to be sent (in bytes)
 *	\return 
 *		\li -1 - Error
 *		\li >0 - OK (number represents number of bytes actually sent)
 *
 *	\warning
 *		\li <i>buf</i> parameter is a pointer to data to be sent in 
 *		user buffer. But note that there <b>MUST</b> be sufficient
 *		free buffer space before that data for TCP header (of #MIN_TCP_HLEN
 *		size). 
 *
 *	Invoke this function to initiate data sending over TCP connection
 *	established over a TCP socket. Since data is not buffered (in order
 *	to reduce RAM memory consumption) new data can not be sent until
 *	data that was previously sent is acknowledged. So, application knows when
 *	it can send new data either by:
 *		\li waiting for TCP_EVENT_ACK in event_listener function
 *		\li invoking tcp_check_send() function to check if it is possible
 *			to send data
 *
 */
INT16 tcp_send (INT8 sockethandle, UINT8* buf, UINT16 blen, UINT16 dlen)
{
	struct tcb* soc;
	
	TCP_DEBUGOUT("Entering to send TCP data packet\r\n");
	
	kick_WD();
	
	if( sockethandle < 0 ) {
		TCP_DEBUGOUT("ERROR:Socket Handle not valid (<0)\r\n");
		return(-1);
	}
	
	if( sockethandle > NO_OF_TCPSOCKETS ) {
		TCP_DEBUGOUT("ERROR:Socket Handle not valid (>NO_OF_TCPSOCKETS)\r\n");
		return(-1);
	}
	
	soc = &tcp_socket[sockethandle];				/* Get socket	*/
	
	if(soc->state != TCP_STATE_CONNECTED) {
		TCP_DEBUGOUT("TCP is not connected!!\r\n");
		return(-1);
	}
	
	if(soc->send_unacked != soc->send_next) {
		TCP_DEBUGOUT("TCP contains unacked data, cannot send more\r\n");
		return(-1);
	}
	
	if( dlen > blen )
		dlen = blen;
	
	if(dlen + MIN_TCP_HLEN > soc->send_mtu) {
		if(soc->send_mtu > MIN_TCP_HLEN)
			dlen = soc->send_mtu - MIN_TCP_HLEN;
		else
			return(-1);
	}
	
	soc->send_next += dlen;
	
	soc->myflags = TCP_FLAG_ACK | TCP_FLAG_PUSH;
	process_tcp_out(sockethandle, buf - MIN_TCP_HLEN, blen + MIN_TCP_HLEN + 1, dlen);
	
	return(dlen);
}


/** \brief Initiate TCP connection closing procedure
 *  \ingroup tcp_app_api
 * 	\author 
 *		\li Jari Lahti (jari.lahti@violasystems.com)
 *	\date 21.07.2002
 *	\param sochandle handle to socket on which TCP connection is to be closed
 *	\return 
 *		\li -2 - there is unacked data on this socket. Try again later.
 *		\li -1 - Error
 *		\li >=0 - OK (connection closing procedure started. Handle to socket
 *			returned)
 *
 *	Invoke this function to start connetion closing procedure over a given
 *	socket. Note that connection is not immediately closed. It may take some
 *	time for that to happen. Event_listener function will be invoked with 
 *	appropriate event when that really happens.
 */
INT8 tcp_close (INT8 sochandle)
{
	struct tcb* soc;
	
	TCP_DEBUGOUT("FUNCTION: tcp_close\r\n");

	if( NO_OF_TCPSOCKETS < 0 )
		return(-1);
	
	if( NO_OF_TCPSOCKETS == 0 )
		return(-1);
	
	if( sochandle > NO_OF_TCPSOCKETS ) {
		TCP_DEBUGOUT("Socket handle non-valid\r\n");
		return(-1);
	}
	
	if( sochandle < 0 ) {
		TCP_DEBUGOUT("Socket handle non-valid\r\n");
		return(-1);
	}
	
	soc = &tcp_socket[sochandle];		/* Get referense	*/	
	
	switch(soc->state) {
		case TCP_STATE_LISTENING:
			tcp_newstate(soc, TCP_STATE_CLOSED);
			break;
		
		case TCP_STATE_SYN_RECEIVED:
			soc->myflags = TCP_FLAG_ACK | TCP_FLAG_FIN;
			soc->send_unacked++;
			soc->send_next++;
			tcp_sendcontrol(sochandle);
			tcp_newstate(soc, TCP_STATE_FINW1);
			break;
		
		case TCP_STATE_SYN_SENT:

⌨️ 快捷键说明

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