// IP header is always 20 bytes so message starts at index 34
tcp = (TCP_HEADER xdata *)(inbuf + 34);
ip = (IP_HEADER xdata *)(inbuf + 14);
// Compute TCP checksum including 12 byte pseudoheader
// Sum source_ipaddr, dest_ipaddr, and entire TCP message
sum = (ULONG)cksum(inbuf + 26, 8 + len);
// Add in the rest of pseudoheader which is
// protocol id and TCP segment length
sum += (ULONG)0x0006;
sum += (ULONG)len;
// In case there was a carry, add it back around
result = (UINT)(sum + (sum >> 16));
if (result != 0xFFFF)
{
return;
}
// See if message is for http server
if (tcp->dest_port != HTTP_PORT)
{
tcp_send(FLG_RST, 20, NO_CONNECTION);
return;
}
// Capture sender's IP address and port number
sender_ipaddr = ip->source_ipaddr;
sender_tcpport = tcp->source_port;
// See if the TCP segment is from someone we are already
// connected to.
for (i=0; i < 5; i++)
{
if ((ip->source_ipaddr == conxn.ipaddr) &&
(tcp->source_port == conxn.port))
{
nr = i;
break;
}
}
// 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;
}
}
// 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)
{
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)
{
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
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))
{
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
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
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;
}
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;
// 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;
}
// Make sure he is ACKing my SYN
else if (tcp->ack_number == conxn[nr].my_sequence)
{
conxn[nr].state = STATE_ESTABLISHED;
// 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;
// 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;
}
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
;
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;
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;
}
}
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;
}
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;
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
;
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;
// 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:
;
break;
}
// This is for debug, to see when conxn closes
if (just_closed)
{
just_closed = FALSE;