📄 tinytcp.c
字号:
/*
* 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 + -