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

📄 tinytcp.c

📁 在89C51上实现TCPIP协议
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * Copyright (C) 2002 by TechiZ. All rights reserved.
 *
 * This program was written in Korean(Comment and some more).
 *
 * This program was developed by TechiZ(The Company name).
 * TechiZ want to share this program with you who loves the 8051 & the TCP/IP.
 * 
 * You MUST DOWNLOAD THIS CODE from TechiZ Homepage.
 * You DO NOT USE THIS CODE FOR COMMERCIAL PURPOSE.
 * This code is ONLY FREE FOR THE STUDY.
 * If you want more, send me E-mail.
 *
 * E-mail: techiz@techiz.com
 * ( Subject is : [T89C51RD2 & TinyTCP] bla~ bla bla.... )
 *
 * Homepage: http://www.techiz.com
 * 
 * You DO NOT DELETE THIS COPYRIGHT MESSAGE IN THE USING OF THIS CODE.
 *
 * In the using of this code, TechiZ does NOT GUARANTEE ABOUT WORKING WITHOUT ERROR.
 */

/*
 * tinytcp.c - Tiny Implementation of the Transmission Control Protocol
 *
 * Written March 28, 1986 by Geoffrey Cooper, IMAGEN Corporation.
 *
 * This code is a small implementation of the TCP and IP protocols, suitable
 * for burning into ROM.  The implementation is bare-bones and represents
 * two days' coding efforts.  A timer and an ethernet board are assumed.  The
 * implementation is based on busy-waiting, but the tcp_handler procedure
 * could easily be integrated into an interrupt driven scheme.
 *
 * IP routing is accomplished on active opens by broadcasting the tcp SYN
 * packet when ARP mapping fails.  If anyone answers, the ethernet address
 * used is saved for future use.  This also allows IP routing on incoming
 * connections.
 * 
 * The TCP does not implement urgent pointers (easy to add), and discards
 * segments that are received out of order.  It ignores the received window
 * and always offers a fixed window size on input (i.e., it is not flow
 * controlled).
 *
 * Special care is taken to access the ethernet buffers only in word
 * mode.  This is to support boards that only allow word accesses.
 *
 * Copyright (C) 1986, IMAGEN Corporation
 *  "This code may be duplicated in whole or in part provided that [1] there
 *   is no commercial gain involved in the duplication, and [2] that this
 *   copyright notice is preserved on all copies.  Any other duplication
 *   requires written notice of the author (Geoffrey H. Cooper)."
 */

#include "tinytcp.h"
#include "include.h"

#define WARNING
/*  Local IP address  */
//in_HwAddress sin_lclINAddr;
/* IP identification numbers */

WORD tcp_id;
tcp_Socket *tcp_allsocs;

		extern void putb_ser(byte byte_data);
		
/* Timer definitions */
#define tcp_RETRANSMITTIME 100     /* interval at which retransmitter is called */
#define tcp_LONGTIMEOUT 3100       /* timeout for opens */
#define tcp_TIMEOUT 1000           /* timeout during a connection */

#ifdef DEBUG
/** Primitive logging facility **/
#define tcp_LOGPACKETS 1        /* log packet headers */
WORD tcp_logState;
#endif
void tcp_ProcessData(tcp_Socket *s, tcp_Header *tp, WORD len);
int checksum(WORD *dp, WORD length);
void tcp_Send(tcp_Socket *s);
void tcp_Unthread(tcp_Socket *ds);
void tcp_Handler( in_Header *ip );
void tcp_Flush(tcp_Socket *s);
void tcp_Abort(tcp_Socket *s);
void tcp_Retransmitter(void);
void tcp_Reset( in_Header *ip, tcp_Header *tp );

in_Header *ip_tcp;
DWORD timeout_tcp, start_tcp;
DWORD x_tcp;


//extern WORD i_test;		//	from test_application
//extern BYTE tbuf_test[80];

extern WORD i_hand;

extern BYTE *sed_IsPacket(void);
extern BYTE *sed_FormatPacket( BYTE *destEAddr, WORD ethType );
extern BYTE sed_Send( WORD pkLengthInOctets );
extern sar_MapIn2Eth(DWORD ina, eth_HwAddress *ethap );
extern BYTE sed_Receive( BYTE *buf );
extern BYTE sed_CheckPacket( BYTE *BufLocation, WORD expectedType );
extern void sar_CheckPacket(arp_Header *ap);
extern WORD test_dataHandler( tcp_Socket *s, BYTE *dp, WORD len );
extern WORD test_application( void );
extern void print(BYTE *ch);

/************** Initialize the tcp implementation   ********************************/

void tcp_Init(void)
{
	//extern eth_HwAddress sed_lclEthAddr;

	/* initialize ethernet interface */
	ethernet_init();
	print("Ethernet initialize..\r\n");
	//sed_Init();

	tcp_allsocs = NIL;
	tcp_id = 0;

	/* hack - assume the network number */
	sin_lclINAddr = LOCAL_IP_ADDR;
	
}

/*
 * Actively open a TCP connection to a particular destination.
 */
#ifndef WARNING
//void tcp_Open(tcp_Socket *s, WORD lport, in_HwAddress ina, WORD port, procref datahandler)
void tcp_Open(tcp_Socket *s, WORD lport, in_HwAddress ina, WORD port,procref datahandler) 
{
	//extern eth_HwAddress sed_ethBcastAddr;

	s->state = tcp_StateSYNSENT;
	s->timeout = tcp_LONGTIMEOUT;
	if ( lport == 0 ) lport = clock_ValueRough();
	s->myport = lport;
	if ( ! sar_MapIn2Eth(ina, &s->hisethaddr[0]) ) {
#ifdef DEBUG
		print(" : defaulting ethernet address to broadcast\r\n\r");
#endif
		Move(&sed_ethBcastAddr[0], &s->hisethaddr[0], sizeof(eth_HwAddress));
	}
	s->hisaddr = ina;
	s->hisport = port;
	s->seqnum = 0;
	s->dataSize = 0;
	s->flags = tcp_FlagSYN;
	s->unhappy = true;
	s->dataHandler = datahandler;
	s->next = tcp_allsocs;
	tcp_allsocs = s;
	tcp_Send(s);
}
#endif

/*
 * Passive open: listen for a connection on a particular port
 */
//void tcp_Listen(tcp_Socket *s, WORD port, procref datahandler, DWORD timeout)
void tcp_Listen(tcp_Socket *s, WORD port, DWORD timeout)
{
	s->state = tcp_StateLISTEN;
	if ( timeout == 0 ) s->timeout = 0x7ffffff; /* forever... */
	else s->timeout = timeout;
	s->myport = port;
	s->hisport = 0;
	s->seqnum = 0;
	s->dataSize = 0;
	s->flags = 0;
	s->unhappy = 0;
	//s->dataHandler = datahandler;
//	s->dataHandler = (void *)test_dataHandler( (tcp_Socket *)s, (BYTE *)0, (WORD)0);
	
	s->next = tcp_allsocs;
	tcp_allsocs = s;
}

/*
 * Send a FIN on a particular port -- only works if it is open
 */

#ifndef WARNING 
void tcp_Close(tcp_Socket *s)
{
	if ( s->state == tcp_StateESTAB || s->state == tcp_StateSYNREC ) {
		s->flags = tcp_FlagACK | tcp_FlagFIN;
		s->state = tcp_StateFINWT1;
		s->unhappy = true;
		tcp_Send(s);
	}
}
#endif
/*
 * Abort a tcp connection
 */

void tcp_Abort(tcp_Socket *s)
{
	if ( s->state != tcp_StateLISTEN && s->state != tcp_StateCLOSED ) {
		s->flags = tcp_FlagRST | tcp_FlagACK;
		tcp_Send(s);
	}
	s->unhappy = 0;
	s->dataSize = 0;
	s->state = tcp_StateCLOSED;
//	s->dataHandler((tcp_Socket*)s,(BYTE *)0, (WORD *)-1); 
	DATAHANDLER( (tcp_Socket *)s,(BYTE *)0, (WORD *)0 ) ;

//	s->dataHandler(0,0,0); 
	tcp_Unthread(s);
}

/*
 * Retransmitter - called periodically to perform tcp retransmissions
 */
void tcp_Retransmitter(void)
{
	tcp_Socket *s;
	BOOL x;

	for ( s = tcp_allsocs; s; s = s->next ) {
		x = false;
		if ( s->dataSize > 0 || s->unhappy ) {	/* if we didn't received ack( dataSize > 0 ) or unhappy, then re-xmit it */
			tcp_Send(s);
			x = true;
		}
		if ( x || s->state != tcp_StateESTAB )
			s->timeout -= tcp_RETRANSMITTIME;
		if ( s->timeout <= 0 ) {
			if ( s->state == tcp_StateTIMEWT ) {
#ifdef DEBUG
				print("Closed.    \r\n");
#endif
				s->state = tcp_StateCLOSED;
//				s->dataHandler((tcp_Socket *)s,(BYTE *)0, (WORD *)0);
				DATAHANDLER((tcp_Socket *)s,(BYTE *)0, 0);
				tcp_Unthread(s);
			} else {
#ifdef DEBUG
				print(" : Timeout, aborting\r\n");
#endif
				tcp_Abort(s);
			}
		}
	}
}

/*
 * Unthread a socket from the socket list, if it's there 
 */
void tcp_Unthread(tcp_Socket *ds)
{
	tcp_Socket *s, **sp;

	sp = &tcp_allsocs;
	for (;;) {
		s = *sp;
		if ( s == ds ) {
			*sp = s->next;
			break;
		}
		if ( s == NIL ) break;
		sp = &s->next;
	}
}

/*
 * busy-wait loop for tcp.  Also calls an "application proc"
 */
//void tcp(procref application)
void tcp(void) reentrant
{
	unsigned char i ;
	char *ptr ;
	
	//in_Header *ip;
	//DWORD timeout, start;
	//DWORD x;

	sed_Receive(0);

	timeout_tcp = clock_ValueRough() + tcp_RETRANSMITTIME;
	while ( tcp_allsocs ) {
		start_tcp = clock_ValueRough();
		ip_tcp = (in_Header *)sed_IsPacket();

		/* Modified by junku 
		 * Retransmitter is on this 
		 */
		if ( ip_tcp == NIL ) {
			if ( clock_ValueRough() > timeout_tcp ) {
				tcp_Retransmitter();
				timeout_tcp = clock_ValueRough() + tcp_RETRANSMITTIME;
			}

			//application();
			//print("before test_application\n\r");
			test_application();
			//print("after test_application\n\r");
			continue;
		}
		
		if ( sed_CheckPacket(ip_tcp, 0x806) == 1 ) {
#ifdef DEBUG
			/* do arp */
			print("arp packet") ;
			for ( i=0,ptr=(char *)ip_tcp ; i<sizeof( arp_Header ); i++) {
				putb_ser( *ptr++ ) ;
			}
			print("\r\n") ;
#endif
			sar_CheckPacket(ip_tcp);
		} else if ( sed_CheckPacket(ip_tcp, 0x800) == 1 ) {
#ifdef	DEBUG		/* do IP */
			print("ip packet : ") ;
			for ( i=0,ptr=(char *)ip_tcp ; i<sizeof( in_Header ); i++) {
				putb_ser( *ptr++ ) ;
				print("#");
			}
			print("\r\n") ;
#endif
			if ( ip_tcp->destination == sin_lclINAddr && in_GetProtocol(ip_tcp) == 6 
				&& checksum((WORD *)ip_tcp, in_GetHdrlenBytes(ip_tcp)) == 0xFFFF )
			{
					//print("it's our ip\r\n") ;
					tcp_Handler(ip_tcp);
					//print("\n\r1");
			} 
		}
	        /* recycle buffer */
        	sed_Receive(ip_tcp);
			//print("\n\r2");
        	x_tcp = clock_ValueRough() - start_tcp;
        	timeout_tcp -= x_tcp;
        }
	return;
}

/*
 * Write data to a connection.
 * Returns number of bytes written, == 0 when connection is not in
 * established state.
 */
//void tcp_Write( tcp_Socket *s, BYTE *dp, WORD len )
WORD tcp_Write( tcp_Socket *s, BYTE *dp, WORD len )
{
	WORD x;

	if ( s->state != tcp_StateESTAB ) len = 0;
	if ( len > (x = tcp_MaxData - s->dataSize) ) len = x;
	if ( len > 0 ) {
		Move(dp, &s->datas[s->dataSize], len);
		s->dataSize += len;
		tcp_Flush(s);
	}

	return ( len );
}

/*
 * Send pending data
 */
void tcp_Flush(tcp_Socket *s)
{
    if ( s->dataSize > 0 ) {
        s->flags |= tcp_FlagPUSH;
        tcp_Send(s);
    }
}

/*
 * Handler for incoming packets.
 */
void tcp_Handler( in_Header *ip )
{
	tcp_Header *tp;
	tcp_PseudoHeader ph;
	WORD len;
	BYTE *dp;
	WORD x, diff;
	tcp_Socket *s;
	WORD flags;

	len = in_GetHdrlenBytes(ip);

⌨️ 快捷键说明

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