Bool TCPHandleValidSEQ(CTCPSocket *tcp_socket, CTCPHeader *header, U32 segment_seq_num, I64 length, U8 *data)
{// returns the value of must_ack, used later in TCPHandleSocket. Copies data to receive buffer.
	Bool must_ack = FALSE;
	I64  write_position;
	I64  next_position;
	I64  i;

//	tcp_socket->send_window = header->window_size;
	tcp_socket->send_window = EndianU16(header->window_size);
	// Shrine doesn't use EndianU16 (ntohs)? are these all being stored network byte order? ...

	switch (tcp_socket->state)
	{
		case TCP_STATE_ESTABLISHED:
		case TCP_STATE_FIN_WAIT1:
		case TCP_STATE_FIN_WAIT2: // FIN2 check is ommitted in Shrine, yet used in below logic. Adding.

			NetDebug("TCP HANDLE VALID SEQ: Updating data in receive buffer.");

			// TODO: review while loops, make sure we DO NOT HANG INTERRUPT HANDLER.
			write_position = tcp_socket->write_position;

			while (length && segment_seq_num != tcp_socket->next_recv_seq_num)
			{
				segment_seq_num = (segment_seq_num + 1) & 0xFFFFFFFF;
				data++;
				length--;
			}

			for (i = 0; i < length; i++)
			{
//				next_position = (write_position + 1) & (tcp_socket->receive_buffer_size - 1);
				next_position = (write_position + 1) % tcp_socket->receive_buffer_size;

				if (next_position == tcp_socket->read_position)
					break; // ...?

				tcp_socket->receive_buffer[write_position] = data[i];
				write_position = next_position;
			}

			tcp_socket->write_position = write_position;
			tcp_socket->next_recv_seq_num += i;

			if (i > 0)
				must_ack = TRUE;

			if (Bt(&header->flags, TCPf_FIN))
			{
				must_ack = TRUE;
				tcp_socket->next_recv_seq_num++;

				switch (tcp_socket->state)
				{
					case TCP_STATE_ESTABLISHED:
						tcp_socket->state = TCP_STATE_CLOSE_WAIT;
						break;
					case TCP_STATE_FIN_WAIT1:
					case TCP_STATE_FIN_WAIT2:
						tcp_socket->state = TCP_STATE_TIME_WAIT;
						break;
				} // review RFC, whether more state checks needed here.
			}


			break;

		default:
			break;
	}

	return must_ack;
}


Bool TCPHandleACK(CTCPSocket *tcp_socket, CIPV4Packet *packet, CTCPHeader *header,
				  U32 segment_seq_num, U32 segment_ack_num, U32 segment_length)
{ // returns the value of must_ack, used later in TCPHandleSocket
	I64  ack_relative;
	I64  ack_next_relative;

	if (Bt(&header->flags, TCPf_ACK))
	{
		ack_relative = (segment_ack_num - tcp_socket->first_unacked_seq) & 0xFFFFFFFF;
		ack_next_relative = (tcp_socket->next_send_seq_num - tcp_socket->first_unacked_seq) & 0xFFFFFFFF;

		// Shrine has comments here about RFC poor wording,
		// TODO: review RFC and implement more refined approach.
		if (ack_relative <= ack_next_relative)
		{
			TCPAcknowledgePacket(tcp_socket, segment_ack_num);

			// "Accept ACK"
			tcp_socket->first_unacked_seq = segment_ack_num;

			switch (tcp_socket->state)
			{
				case TCP_STATE_SYN_SENT:
					NetDebug("TCP HANDLE ACK: Acceptable ACK; state: SYN_SENT");
					if (!Bt(&header->flags, TCPf_SYN))
						break;
					// else, fall-through

				case TCP_STATE_SYN_RECEIVED:
					tcp_socket->state = TCP_STATE_ESTABLISHED;
					tcp_socket->srtt  = tS - tcp_socket->connection_time;
					break;

				default:
					break;
			}
			NetDebug("TCP HANDLE ACK: Acceptable ACK returning; state: 0x%0X", tcp_socket->state);
		}
		else
		{
			NetWarn("TCP HANDLE SOCKET: Invalid ACK.");

			switch (tcp_socket->state)
			{
				case TCP_STATE_LISTEN:
				case TCP_STATE_SYN_SENT:
				case TCP_STATE_SYN_RECEIVED:
					TCPSend(packet->destination_ip_address,
							EndianU16(header->destination_port),
							packet->source_ip_address,
							EndianU16(header->source_port),
							segment_ack_num,
							segment_seq_num + segment_length,
							TCPF_ACK | TCPF_RST);
					break;

				default:
					if (IsTCPStateSync(tcp_socket))
						return TRUE; // must ACK the packet.

					break;
			}
		}
	}

	return FALSE; // do not need to ACK the packet.
}

Bool TCPHandleReset(CTCPSocket *tcp_socket, CTCPHeader *header, Bool is_seq_valid)
{ // returns whether or not to stop overall TCP procedure.
	if (Bt(&header->flags, TCPf_RST))
	{
		switch (tcp_socket->state)
		{
			case TCP_STATE_SYN_SENT:
				if (tcp_socket->first_unacked_seq == tcp_socket->next_send_seq_num)
				{
					NetWarn("TCP HANDLE SOCKET: Got RST, socket state SYN_SENT. Connection refused.");
					tcp_socket->state = TCP_STATE_CLOSED;
					return TRUE;
				}
				break;

			default:
				if (is_seq_valid)
				{
					NetWarn("TCP HANDLE SOCKET: Got RST, connection refused by remote host.");
					tcp_socket->state = TCP_STATE_CLOSED;
					return TRUE;
				}
		}
	}

	return FALSE;
}

U0 TCPHandleSocketListen(CTCPSocket *tcp_socket, CIPV4Packet *packet, CTCPHeader *header, U32 segment_seq_num)
{ // if SYN and socket listening, queue up the connection in the socket's accept queue.
	CTCPAcceptQueue *new_connection;

	if (Bt(&header->flags, TCPf_SYN) && QueueSize(tcp_socket->accept_queue) < tcp_socket->accept_queue_limit)
	{
		NetDebug("TCP HANDLE SOCKET LISTEN: Adding new connection to Socket accept queue");
		new_connection = CAlloc(sizeof(CTCPAcceptQueue));

		new_connection->segment_seq_num = segment_seq_num;
		new_connection->ipv4_address	= packet->source_ip_address;
		new_connection->port			= header->source_port;

		QueueInsertRev(new_connection, tcp_socket->accept_queue);
	}
	else
	{ // refuse
		NetDebug("TCP HANDLE SOCKET LISTEN: Header flags not SYN or Queue full, REFUSING CONNECTION");
		TCPSend(packet->destination_ip_address,
				EndianU16(header->destination_port),
				packet->source_ip_address,
				EndianU16(header->source_port),
				segment_seq_num + 1,
				segment_seq_num + 1,
				TCPF_ACK | TCPF_RST);
	}
}

U0 TCPHandleSocket(CTCPSocket *tcp_socket, CIPV4Packet *packet, CTCPHeader *header, U8 *data, I64 length)
{
	U32  segment_length		= length;
	U32  segment_seq_num	= EndianU32(header->seq_num);
	U32  segment_ack_num	= EndianU32(header->ack_num);
	Bool must_ack			= FALSE;
	Bool is_seq_valid		= FALSE;
	I64  seq_relative;
	I64  seq_end_relative;

	if (Bt(&header->flags, TCPf_FIN))
		segment_length++;
	if (Bt(&header->flags, TCPf_SYN))
		segment_length++;

	switch (tcp_socket->state)
	{
		case TCP_STATE_LISTEN:
			NetDebug("TCP HANDLE SOCKET: Running TCP HANDLE SOCKET LISTEN");
			TCPHandleSocketListen(tcp_socket, packet, header, segment_seq_num);
			return;

		case TCP_STATE_CLOSED:
			NetErr("TCP HANDLE SOCKET: Received packet but TCP Socket is CLOSED.");
			return;

		default:
			if (Bt(&header->flags, TCPf_SYN))
			{
				tcp_socket->next_recv_seq_num = ++segment_seq_num;

				must_ack = TRUE;
			}

			if (segment_length == 0 && tcp_socket->receive_window == 0)
			{
				NetDebug("TCP HANDLE SOCKET: segment length == 0 && receive window == 0, SEQ valid if seq == next recv seq");
				is_seq_valid = (segment_seq_num == tcp_socket->next_recv_seq_num);
			}
			else
			{
				seq_relative = (segment_seq_num - tcp_socket->next_recv_seq_num) & 0xFFFFFFFF;
				seq_end_relative = (segment_seq_num + segment_length - 1 - tcp_socket->next_recv_seq_num) & 0xFFFFFFFF;

				is_seq_valid = (seq_relative < tcp_socket->receive_window ||
								seq_end_relative < tcp_socket->receive_window);
			}

			if (!is_seq_valid)
				NetWarn("TCP HANDLE SOCKET: Invalid SEQ.");

			must_ack |= TCPHandleACK(tcp_socket, packet, header, segment_seq_num, segment_ack_num, segment_length);


			if (TCPHandleReset(tcp_socket, header, is_seq_valid))
				return;

			if (is_seq_valid)
				must_ack |= TCPHandleValidSEQ(tcp_socket, header, segment_seq_num, length, data);

			if (must_ack)
				TCPSendFlags(tcp_socket, TCPF_ACK);
	}

}

I64 TCPHandleRefuse(CIPV4Packet *packet, CTCPHeader *header, I64 length)
{
	I64 de_index;
	U32 ack_num = EndianU32(header->ack_num);
	U32 seq_num = EndianU32(header->seq_num);

	no_warn length; // TODO: Will reset generation need length ?

	ack_num = ++seq_num;
	seq_num = 0;

	// review RFC Reset-Generation ...

	de_index = TCPSend(packet->destination_ip_address,
					   EndianU16(header->destination_port),
					   packet->source_ip_address,
					   EndianU16(header->source_port),
					   seq_num,
					   ack_num,
					   TCPF_RST | TCPF_ACK);
	if (de_index < 0)
	{
		NetErr("TCP Handler Refuse: TCP Send failed.");
		return de_index;
	}

	return 0;
}

I64 TCPHandler(CIPV4Packet *packet)
{
	CTCPHeader		*header;
	U16				 destination_port;
	U8				*data;
	I64				 length;
	CTCPTreeNode	*head = tcp_globals.bound_socket_tree;
	CTCPTreeNode	*node;
	CTCPTreeQueue	*queue;
	CTCPSocket		*tcp_socket;
	I64				 error = TCPPacketParse(&header, &data, &length, packet);

	if (error < 0)
	{
		NetErr("TCP HANDLER: Packet Parse Error.");
		return error;
	}

	NetDebug("TCP HANDLER: Caught packet with dest port of %0X (B.E.)", header->destination_port);

	destination_port = EndianU16(header->destination_port); // B.E. -> L.E.
	NetDebug("TCP HANDLER: Caught packet with dest port of %0X (L.E.)", destination_port);

	if (head)
	{
		node = TCPTreeNodeFind(destination_port, head);

		if (node)
		{
			NetDebug("TCP HANDLER: Found node for port, looking for address %0X (L.E.)", packet->source_ip_address);
			queue = TCPTreeNodeQueueIPV4Find(packet->source_ip_address, node); // TODO: make sure bit order is correct here!!
			if (queue)
			{
				tcp_socket = queue->socket;
				NetLog("TCP HANDLER: Port and Address are in bound tree.");
			}
			else
			{
				NetWarn("TCP HANDLER: Found node for port, but address is not in node queue.");
				NetWarn("             TCP source ip: 0x%0X.", packet->source_ip_address);

				NetWarn("TCP HANDLER: Sending TCP RST ACK packet. Refusing connection.");
				TCPHandleRefuse(packet, header, length);
				return -1;
			}
		}
		else
		{
			NetDebug("TCP HANDLER: NODE SEARCH FAILURE: PORT %0X", destination_port);
			NetWarn("TCP HANDLER: Node for Port is not in tree.");
			NetWarn("TCP HANDLER: Sending TCP RST ACK packet. Refusing connection.");
			TCPHandleRefuse(packet, header, length);
			return -1;
		}

	}
	else
	{
		NetWarn("TCP HANDLER: Socket tree is currently empty.");
		NetWarn("TCP HANDLER: Sending TCP RST ACK packet. Refusing connection.");
		TCPHandleRefuse(packet, header, length);
		return -1;
	}

	// at this point, tcp_socket is set, otherwise has already returned -1.

	NetDebug("TCP HANDLER: Running TCP HANDLE SOCKET");
	TCPHandleSocket(tcp_socket, packet, header, data, length);

}