www.pudn.com > tcpipstack.rar > TINYTC4.C


/* TINYTC4.C - Tiny-TCP source fragment 
	Part 4 of the TCP layer. 
 
 * 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." 
 
|===================================================================| 
|  The author of this code hereby licenses all duplication and/or   | 
|  modification of this code, in whole or in part, consistent with  | 
|  the terms of the GNU Library General Public License.             | 
|              - Geoffrey H. Cooper 10/29/97                        | 
|===================================================================| 
 
|===================================================================| 
|  My changes can be considered public domain.  Geof's statement    | 
|  will cover everything.                                           | 
|              - Rick Rodman 09/02/97                               | 
|===================================================================| 
 
	941012	rr	split into fragments 
*/ 
 
#include "tinytcp.h" 
 
#include  
 
#ifdef PC 
#include  
#endif 
 
/* ----- globals from tinytcp.c ------------------------------------- */ 
 
extern	IP_Address	local_IP_address;	/* local IP address */ 
 
extern	int		tcp_id;			/* TCP ID, gets incremented */ 
 
extern	struct tcp_Socket *	tcp_allsocs;	/* socket linklist */ 
 
 
/* ----- Write data to a connection. -------------------------------- */ 
  
	/* Returns number of bytes written, == 0 when connection is not in 
 		established state. */ 
 
int tcp_Write( s, dp, len ) 
	struct tcp_Socket *s; 
	Byte *dp; 
	int len; 
{ 
	S8	int	x; 
 
	/* if the connection is not established, don't send anything */ 
 
	if( s -> state != TS_ESTAB ) return 0; 
 
	/* figure out how much I can move */ 
 
	if( len > ( x = TCP_MAXDATA - s -> dataSize ) ) len = x; 
	if( len > 0 ) {  
		Move( dp, &s -> data[ s -> dataSize ], len ); 
		s -> dataSize += len; 
		tcp_Flush( s ); 
	} 
 
	return len;	/* return count of bytes sent */ 
} 
 
/* ----- Send pending data ------------------------------------------ */ 
 
Void tcp_Flush( s ) struct tcp_Socket *s; { 
 
	if(( s -> state == 0 ) || ( s -> state == TS_CLOSED )) 
		return; 
 
	if( s -> dataSize > 0 ) { 
		s -> flags |= TCPF_PUSH; 
		tcp_Send( s ); 
	} 
} 
 
/* ----- Handler for incoming packets. ------------------------------ */ 
 
Void tcp_Handler( ip ) struct in_Header *ip; { 
 
	S8	struct tcp_Header *	tp; 
	S8	struct tcp_Pseudoheader ph; 
	S8	int			len; 
	S8	int			diff; 
	S8	struct tcp_Socket *	s; 
	S8	Word			flags; 
	S8	Longword		lw; 
 
	len = IP_HBYTES( ip ); 
	tp = ( struct tcp_Header * )(( Byte * ) ip + len ); 
	len = rev_word( ip -> length ) - len; 
 
	/* demux to active sockets */ 
 
	for( s = tcp_allsocs; s; s = s -> next ) 
		if(( s -> hisport != 0 ) 
			&& ( rev_word( tp -> dstPort ) == s -> myport ) 
			&& ( rev_word( tp -> srcPort ) == s -> hisport ) 
			&& ( rev_longword( ip -> source ) 
				== s -> hisaddr )) 
			break; 
 
	if( s == 0 ) {	/* didn't find an matching socket */ 
 
		/* demux to passive sockets */ 
 
		for ( s = tcp_allsocs; s; s = s -> next ) 
			if(( s -> hisport == 0 ) 
				&& ( rev_word( tp -> dstPort ) 
					== s -> myport )) 
				break; 
	} 
 
	if( s == 0 ) {	/* Still didn't find a matching socket */ 
#ifdef DEBUG_TCP 
		tcp_DumpHeader( ip, tp, "Discarding" ); 
#endif 
		return; 
	} 
 
#ifdef DEBUG_TCP 
	tcp_DumpHeader( ip, tp, "Received" ); 
#endif 
 
#ifdef ETHERNET 
	/* save his ethernet address */ 
 
	Move( ( Byte * ) &(((( struct eth_Header * ) ip ) - 1) -> source[0]), 
		( Byte * ) &s -> hisethaddr[0], sizeof(Ethernet_Address)); 
#endif 
 
	ph.src = ip -> source; 
	ph.dst = ip -> destination; 
	ph.mbz = 0; 
	ph.protocol = 6; 
	ph.length = rev_word( len ); 
 
	lw = lchecksum( ( Word * ) &ph, sizeof ph - 2 ); 
	while( lw & 0xFFFF0000L ) 
		lw = ( lw & 0xFFFFL ) + (( lw >> 16L ) & 0xFFFFL ); 
	lw += lchecksum( ( Word * ) tp, len ); 
	while( lw & 0xFFFF0000L ) 
		lw = ( lw & 0xFFFFL ) + (( lw >> 16L ) & 0xFFFFL ); 
 
	if( lw != 0x0000FFFFL ) 
		printf( "bad tcp checksum (%lx), received anyway\n", lw ); 
 
	flags = rev_word( tp -> flags ); 
 
	if( flags & TCPF_RST ) { 
		printf("connection reset\n"); 
 
		s -> state = TS_CLOSED; 
		if( s -> dataHandler != 0 )		/* cast removed */ 
			( s -> dataHandler )(( void * ) s, ( Byte * ) 0, -1); 
		else	printf( "got close, no handler\n" ); 
 
		tcp_Unthread( s ); 
		return; 
	} 
 
	switch( s -> state ) { 
 
	case TS_LISTEN: 
		/* Initial state of a Listen port */ 
 
		if( flags & TCPF_SYN ) { 
			/* We expect to get Syn back */ 
 
			s -> acknum = rev_longword( tp -> seqnum ) + 1; 
			s -> hisport = rev_word( tp -> srcPort ); 
			s -> hisaddr = rev_longword( ip -> source ); 
			s -> flags = TCPF_SYN | TCPF_ACK; 
 
			tcp_Send( s ); 
 
			s -> state = TS_RSYN; 
			s -> unhappy = True; 
			s -> timeout = tcp_TIMEOUT; 
 
#ifdef DEBUG_TCP 
			printf("Syn from 0x%x#%d (seq 0x%lx)\n", 
				s -> hisaddr, s -> hisport, 
				rev_longword( tp -> seqnum )); 
#endif 
		} 
		break; 
 
	case TS_SSYN: 
		/* Initial state of a Open port */ 
 
		if( flags & TCPF_SYN ) { 
			s -> acknum++; 
			s -> flags = TCPF_ACK; 
			s -> timeout = tcp_TIMEOUT; 
 
			if(( flags & TCPF_ACK ) 
				&& rev_longword( tp -> acknum ) 
					== ( s -> seqnum + 1 ) ) { 
 
				printf( "--- Open! ---\n" ); 
 
				s -> state = TS_ESTAB; 
				s -> seqnum++; 
				s -> acknum = rev_longword( tp -> seqnum ) 
					+ 1; 
				s -> unhappy = False; 
			} else { 
				s -> state = TS_RSYN; 
			} 
		} else { 
#ifdef DEBUG_TCP 
			printf( "Sent Syn, didn't get Syn back\n" ); 
#endif 
			/* This sounds to rr like the half-open 
				condition in fig. 10, p. 74 (sec. 3.4). */ 
 
			s -> flags = TCPF_RST; 
			s -> seqnum = rev_longword( tp -> acknum ); 
			tcp_Send( s ); 
			printf( "Sent RST!\n" ); 
 
			/* We expect no response. Reset the flags to send 
				SYN when the timeout occurs. */ 
 
			s -> flags = TCPF_SYN; 
			s -> timeout = tcp_TIMEOUT; 
			s -> seqnum = 0;	/* Start over */  
 
			/* Stay in SYNSENT and wait for timeout. */ 
		} 
		break; 
 
	case TS_RSYN: 
		if( flags & TCPF_SYN ) { 
			s -> flags = TCPF_SYN | TCPF_ACK; 
			tcp_Send(s); 
			s -> timeout = tcp_TIMEOUT; 
 
			printf(" retransmit of original syn\n"); 
		} 
		if(( flags & TCPF_ACK ) 
			&& rev_longword( tp -> acknum ) 
				== ( s -> seqnum + 1L ) ) { 
 
			s -> flags = TCPF_ACK; 
			tcp_Send( s ); 
			s -> seqnum++; 
			s -> unhappy = False; 
			s -> state = TS_ESTAB; 
			s -> timeout = tcp_TIMEOUT; 
 
			printf( "Synack received - connection established\n" ); 
		} else { 
#ifdef DEBUG_TCP 
			printf( "Wrong syn. flags %04x ack %ld seq %ld\n", 
				flags, 
				rev_longword( tp -> acknum ), 
				s -> seqnum + 1L ); 
#endif 
		} 
		break; 
 
	case TS_ESTAB: 
		if(( flags & TCPF_ACK ) == 0 ) return; 
 
		/* process ack value in packet */ 
 
		diff = ( int )( rev_longword( tp -> acknum ) 
			- s -> seqnum ); 
 
		if( diff > 0 ) { 
 
			/* The diff value is the number of bytes of MY data 
				which he is acknowledging. */ 
 
			if( diff > TCP_MAXDATA ) diff = TCP_MAXDATA; 
			else { 
				Move( &s -> data[ diff ], 
					&s -> data[ 0 ], 
					TCP_MAXDATA - diff ); 
			} 
 
			s -> dataSize -= diff;	/* bytes to send remaining */ 
			s -> seqnum += diff;	/* my next sequence number */ 
		} 
		s -> flags = ( Word ) TCPF_ACK; 
 
		tcp_ProcessData( s, tp, len ); 
		break; 
 
	case TS_SFIN: 
		if(( flags & TCPF_ACK ) == 0 ) return; 
		diff = ( int )( rev_longword( tp -> acknum ) 
			- s -> seqnum - 1 ); 
		s -> flags = ( Word )( TCPF_ACK | TCPF_FIN ); 
		if( diff == 0 ) { 
			s -> state = TS_AFIN; 
			s -> flags = TCPF_ACK; 
			printf("finack received.\n"); 
		} 
		tcp_ProcessData(s, tp, len); 
		break; 
 
	case TS_AFIN: 
		s -> flags = TCPF_ACK; 
		tcp_ProcessData( s, tp, len ); 
		break; 
 
	case TS_RFIN: 
		if( rev_longword( tp -> acknum ) == (s -> seqnum + 1) ) { 
			s -> state = TS_TIMEWT; 
			s -> timeout = tcp_TIMEOUT; 
		} 
		break; 
 
	case TS_LASTACK: 
		if( rev_longword( tp -> acknum ) == (s -> seqnum + 1) ) { 
			s -> state = TS_CLOSED; 
			s -> unhappy = False; 
			s -> dataSize = 0; 
 
			if( s -> dataHandler != 0 )	/* cast removed */ 
				( s -> dataHandler )(( void * ) s, 
					( Byte * ) 0, 0 ); 
			else	printf( "got close, no handler\n" ); 
 
			tcp_Unthread( s ); 
 
			printf( "Closed. [626]\n" ); 
		} else { 
			s -> flags = TCPF_ACK | TCPF_FIN; 
			tcp_Send( s ); 
			s -> timeout = tcp_TIMEOUT; 
 
			printf( "retransmitting FIN\n" ); 
		} 
		break; 
 
	case TS_TIMEWT: 
		s -> flags = TCPF_ACK; 
		tcp_Send(s); 
	} 
} 
 
/* end of tinytc4.c */