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

📄 tcp.c

📁 Keil_C51程序,C8051实现的TCP/IP功能源码
💻 C
📖 第 1 页 / 共 2 页
字号:
   
   	// If i = 5, we are not connected. If it is a SYN then assign
  	// a temporary conection  to it for processing
   	if (i == 5)
   	{
    	if (tcp->flags & FLG_SYN)
      	{
        	// Find first unused connection (one with IP = 0) 
        	for (j=0; j < 5; j++)
         	{
            	if (conxn[j].ipaddr == 0)
            	{
               		nr = j;
               	// Initialize new connection
               		conxn[nr].state = STATE_LISTEN;
               		break;
            	}
         	}
      
         	// If all connections are used then drop msg
         	if (j == 5) return;
         
         	if (debug)
         	{
            	SendCommString("TCP: New connection ");
            	memset(text, 0, 10);
            	itoa((UINT)nr, text, 10);
            	SendCommString(text);
			   	SendCommString("\r");
         	}
      	}
	}


	// By now we should have a connection number in range of 0-4
	// Do a check to avoid any chance of exceeding size of struct
	if (nr > 4)
   	{
      	if (debug) SendCommString("TCP: Error in assigning conxn number\r");
      	return;
   	}

   	// Eventually put in protection against wrapping sequence
   	// numbers, for now make the client start over if his
   	// sequence number is close to wrapping
	// 保护
   	if (tcp->sequence > 0xFFFFFF00L) 
   	{
      	if (debug) SendCommString("TCP: Rcvd a high sequence number\r");
		conxn[nr].ipaddr = 0;			
		tcp_send(FLG_RST, 20, NO_CONNECTION);
		return;		
   	}
           
   	// Handle messages whose action is mostly independent of state
   	// such as RST, SYN, and segment with no ACK.  That way the
	// state machine below does not need to worry about it.
   	if (tcp->flags & FLG_RST)
   	{
   		// An RST does not depend on state at all.  And it does
      	// not count as data so do not send an ACK here.  Close
      	// connection
 		if (debug) SendCommString("TCP: Rcvd a reset\r");
      	conxn[nr].ipaddr = 0;
      	return;
   	}
	
	else if (tcp->flags & FLG_SYN)
	{
	   	// A SYN segment only makes sense if connection is in LISTEN 
	   	if ((conxn[nr].state != STATE_LISTEN) && (conxn[nr].state != STATE_CLOSED))
		{
			if (debug) SendCommString("TCP: Error, rcvd bogus SYN\r");
			conxn[nr].ipaddr = 0;			
		  	tcp_send(FLG_RST, 20, NO_CONNECTION);
		  	return;		
		}
	}
	
	else if ((tcp->flags & FLG_ACK) == 0)
	{
		// Incoming segments except SYN or RST must have ACK bit set
	 	// See TCP/IP Illustrated, Vol 2, Page 965
      // Drop segment but do not send a reset
		if (debug) SendCommString("TCP: Error, rcvd segment has no ACK\r");
		return;
	}
	   
  	// Compute length of header including options, and from that
   	// compute length of actual data
   	header_len =  (tcp->flags & 0xF000) >> 10;
   	data_len = len - header_len;


         
   	// Handle TCP state machine for this connection
   	switch (conxn[nr].state)
   	{
      	case STATE_CLOSED://
      	case STATE_LISTEN://
            
      	// If incoming segment contains SYN and no ACK, then handle 
      	if ((tcp->flags & FLG_SYN) && ((tcp->flags & FLG_ACK) == 0))
      	{
         	// Capture his starting sequence number and generate
         	// my starting sequence number
         	// Fill in connection information
         	conxn[nr].ipaddr = ip->source_ipaddr;
         	conxn[nr].port = tcp->source_port;
         	conxn[nr].state = STATE_LISTEN;
         	conxn[nr].his_sequence = 1 + tcp->sequence;
         	conxn[nr].his_ack = tcp->ack_number;
         
         	// Use system clock for initial sequence number
         	EA = 0;
         	conxn[nr].my_sequence = initial_sequence_nr;
         	initial_sequence_nr += 64000L;
         	EA = 1;                  
                  
         	// Send header options with the next message
         	// Since timestamps are optional and we do not use
         	// them, do not have to send them 
         	// After sending the SYN ACK the client browser will
         	// blast me with 2 messages, an ACK, and a HTTP GET
         	tcp_send(FLG_SYN | FLG_ACK, 28, nr);
         
         	// My SYN flag increments my sequence number
         	// My sequence number is always updated to point to 
         	// the next byte to be sent.  So the incoming ack
         	// number should equal my sequence number  
         	conxn[nr].my_sequence++;
      	
        	conxn[nr].state = STATE_SYN_RCVD;
        	if (debug) SendCommString("TCP: Entered SYN RCVD state\r");
      	}
		else 
      	{
         	// Sender is out of sync so send reset
         	conxn[nr].ipaddr = 0;
         	tcp_send(FLG_RST, 20, NO_CONNECTION);   
      	} 
		break;


      	case STATE_SYN_RCVD://
      	// He may already be sending me data - should process it
		conxn[nr].his_sequence += data_len;
      	conxn[nr].his_ack = tcp->ack_number;
            
      	if (tcp->flags & FLG_FIN)
		{
		   // His FIN counts as a byte of data
         	conxn[nr].his_sequence++;
         	tcp_send(FLG_ACK, 20, nr);
         	conxn[nr].state = STATE_CLOSE_WAIT;
         	if (debug) SendCommString("TCP: Entered CLOSE_WAIT state\r");
               
        	// At this point we would normally wait for the	application
         	// to close.  For now, send FIN right away.
         	tcp_send(FLG_FIN | FLG_ACK, 20, nr);
         	conxn[nr].my_sequence++;   // For my FIN
         	conxn[nr].state = STATE_LAST_ACK;
         	if (debug) SendCommString("TCP: Entered LAST ACK state\r");
      	}

		// Make sure he is ACKing my SYN
		else if (tcp->ack_number == conxn[nr].my_sequence)
      	{
        	conxn[nr].state = STATE_ESTABLISHED;
         	if (debug) SendCommString("TCP: Entered ESTABLISHED state\r");
         	// If sender sent data ignore it and he will resend
         	// Do not send response because we received no
         	// data... wait for client to send something to me 
      	}
      	break;

      	case STATE_ESTABLISHED: //
		conxn[nr].his_ack = tcp->ack_number;
           
      	if (tcp->flags & FLG_FIN)
		{
		   	// His FIN counts as a byte of data
         	conxn[nr].his_sequence++;
         	tcp_send(FLG_ACK, 20, nr);
         	conxn[nr].state = STATE_CLOSE_WAIT;
         	if (debug) SendCommString("TCP: Entered CLOSE_WAIT state\r");
               
        	// At this point we would normally wait for the	application
         	// to close.  For now, send FIN immediately.
         	tcp_send(FLG_FIN | FLG_ACK, 20, nr);
         	conxn[nr].my_sequence++;   // For my FIN
         	conxn[nr].state = STATE_LAST_ACK;
         	if (debug) SendCommString("TCP: Entered LAST ACK state\r");
      	}
		else if (data_len != 0)
      	{
			// Received normal TCP segment from sender with data
      		// Send an ACK immediately and pass the data on to
			// the application
			conxn[nr].his_sequence += data_len;
         	tcp_send(FLG_ACK, 20, nr); 		// Send ACK
      	  
      	      	      	 									
			// Send pointer to start of TCP payload
			// http_server increments my sequence number when 
         	// sending so don't worry about it here
         	result = http_server(inbuf, header_len, nr, 0);
								
			// Start timer to close conxn if no activity
			conxn[nr].inactivity = INACTIVITY_TIME;
		}
	   	break;


      	case STATE_CLOSE_WAIT://
      	// With this code, should not get here
      	if (debug) SendCommString("TCP: Oops! Rcvd unexpected message\r");
	   	break;

      
      	case STATE_LAST_ACK:
      	conxn[nr].his_ack = tcp->ack_number;
            
      	// If he ACK's my FIN then close
      	if (tcp->ack_number == conxn[nr].my_sequence)
      	{
         	conxn[nr].state = STATE_CLOSED;
         	conxn[nr].ipaddr = 0;  // Free up struct area
         	just_closed = TRUE;
      	}
      	break;

      
      	case STATE_FIN_WAIT_1:
      	// He may still be sending me data - should process it
		conxn[nr].his_sequence += data_len;
    	conxn[nr].his_ack = tcp->ack_number;
                  
      	if (tcp->flags & FLG_FIN)
      	{
         	// His FIN counts as a byte of data
         	conxn[nr].his_sequence++;
         	tcp_send(FLG_ACK, 20, nr);
         
         	// If he has ACK'd my FIN then we can close connection
         	if (tcp->ack_number == conxn[nr].my_sequence)
			{
         		conxn[nr].state = STATE_TIME_WAIT;
         		if (debug) SendCommString("TCP: Entered TIME_WAIT state\r");
               
         		conxn[nr].state = STATE_CLOSED;
         		conxn[nr].ipaddr = 0;  // Free up connection
         		just_closed = TRUE;
      		}
			else
			{
				// He has not ACK'd my FIN.  This happens when there is a simultaneous
				// close - I got his FIN but he has not yet ACK'd my FIN
				conxn[nr].state = STATE_CLOSING;
				if (debug) SendCommString("TCP: Entered CLOSING state\r");
			}
		}
      	else if (tcp->ack_number == conxn[nr].my_sequence)
      	{
         	// He has ACK'd my FIN but has not sent a FIN yet himself
         	conxn[nr].state = STATE_FIN_WAIT_2;
         	if (debug) SendCommString("TCP: Entered FIN_WAIT_2 state\r");
      	}
      	break;

      
      	case STATE_FIN_WAIT_2:
      	// He may still be sending me data - should process it
		conxn[nr].his_sequence += data_len;
      	conxn[nr].his_ack = tcp->ack_number;
      
      	if (tcp->flags & FLG_FIN)
      	{
         	conxn[nr].his_sequence++; // For his FIN flag
         	tcp_send(FLG_ACK, 20, nr);
         	conxn[nr].state = STATE_TIME_WAIT;
         	if (debug) SendCommString("TCP: Entered TIME_WAIT state\r");
         	conxn[nr].state = STATE_CLOSED;
         	conxn[nr].ipaddr = 0;  // Free up struct area
         	just_closed = TRUE;
      	}
      	break;
            
            
      	case STATE_TIME_WAIT:
      	// With this code, should not get here
      	if (debug) SendCommString("TCP: Oops! In TIME_WAIT state\r");
      	break;

      
      	case STATE_CLOSING://关闭状态机
      	// Simultaneous close has happened. I have received his FIN
      	// but he has not yet ACK'd my FIN.  Waiting for ACK.
		// Will not receive data in this state
		conxn[nr].his_ack = tcp->ack_number;
      		
		if (tcp->ack_number == conxn[nr].my_sequence)
      	{
		  	conxn[nr].state = STATE_TIME_WAIT;
         	if (debug) SendCommString("TCP: Entered TIME_WAIT state\r");
         
        	// Do not send any response to his ACK
        	conxn[nr].state = STATE_CLOSED;
        	conxn[nr].ipaddr = 0;  // Free up struct area
        	just_closed = TRUE;
      	}
      	break;

      
	    default:
    	if (debug) SendCommString("TCP: Error, no handler\r");
    	break;
   	}
   
   	// This is for debug, to see when conxn closes
   	if (just_closed)
   	{
      	just_closed = FALSE;
      	if (debug)
      	{
         	SendCommString("TCP: Closed connection ");
         	memset(text, 0, 10);
         	itoa((UINT)nr, text, 10);
		   	SendCommString(text);
		   	SendCommString("\r");
      	}
   	}
}



⌨️ 快捷键说明

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