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);

}