banan-os/kernel/include/kernel/Networking/TCPSocket.h

182 lines
4.8 KiB
C++

#pragma once
#include <BAN/Endianness.h>
#include <BAN/Queue.h>
#include <kernel/Lock/Mutex.h>
#include <kernel/Memory/VirtualRange.h>
#include <kernel/Networking/NetworkInterface.h>
#include <kernel/Networking/NetworkSocket.h>
#include <kernel/Process.h>
#include <kernel/ThreadBlocker.h>
namespace Kernel
{
enum TCPFlags : uint8_t
{
FIN = 0x01,
SYN = 0x02,
RST = 0x04,
PSH = 0x08,
ACK = 0x10,
URG = 0x20,
ECE = 0x40,
CWR = 0x80,
};
struct TCPHeader
{
BAN::NetworkEndian<uint16_t> src_port { 0 };
BAN::NetworkEndian<uint16_t> dst_port { 0 };
BAN::NetworkEndian<uint32_t> seq_number { 0 };
BAN::NetworkEndian<uint32_t> ack_number { 0 };
uint8_t reserved : 4 { 0 };
uint8_t data_offset : 4 { 0 };
uint8_t flags { };
BAN::NetworkEndian<uint16_t> window_size { 0 };
BAN::NetworkEndian<uint16_t> checksum { 0 };
BAN::NetworkEndian<uint16_t> urgent_pointer { 0 };
uint8_t options[0];
};
static_assert(sizeof(TCPHeader) == 20);
class TCPSocket final : public NetworkSocket
{
public:
static constexpr size_t m_tcp_options_bytes = 4;
public:
static BAN::ErrorOr<BAN::RefPtr<TCPSocket>> create(NetworkLayer&, const Info&);
~TCPSocket();
virtual NetworkProtocol protocol() const override { return NetworkProtocol::TCP; }
virtual size_t protocol_header_size() const override { return sizeof(TCPHeader) + m_tcp_options_bytes; }
virtual void add_protocol_header(BAN::ByteSpan packet, uint16_t dst_port, PseudoHeader) override;
protected:
virtual BAN::ErrorOr<long> accept_impl(sockaddr*, socklen_t*, int) override;
virtual BAN::ErrorOr<void> connect_impl(const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<void> listen_impl(int) override;
virtual BAN::ErrorOr<void> bind_impl(const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<size_t> sendto_impl(BAN::ConstByteSpan, const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<size_t> recvfrom_impl(BAN::ByteSpan, sockaddr*, socklen_t*) override;
virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) override;
virtual bool can_read_impl() const override;
virtual bool can_write_impl() const override;
virtual bool has_error_impl() const override { return false; }
private:
enum class State
{
Closed = 0,
Listen,
SynSent,
SynReceived,
Established,
FinWait1,
FinWait2,
CloseWait,
Closing,
LastAck,
TimeWait,
};
struct RecvWindowInfo
{
uint32_t start_seq { 0 }; // sequence number of first byte in buffer
bool has_ghost_byte { false };
uint32_t data_size { 0 }; // number of bytes in this buffer
BAN::UniqPtr<VirtualRange> buffer;
};
struct SendWindowInfo
{
uint32_t mss { 0 }; // maximum segment size
uint16_t non_scaled_size { 0 }; // window size without scaling
uint8_t scale { 0 }; // window scale
uint32_t scaled_size() const { return (uint32_t)non_scaled_size << scale; }
uint32_t start_seq { 0 }; // sequence number of first byte in buffer
uint32_t current_seq { 0 }; // sequence number of next send
uint32_t current_ack { 0 }; // sequence number aknowledged by connection
uint64_t last_send_ms { 0 }; // last send time, used for retransmission timeout
bool has_ghost_byte { false };
uint32_t data_size { 0 }; // number of bytes in this buffer
BAN::UniqPtr<VirtualRange> buffer;
};
struct ConnectionInfo
{
sockaddr_storage address;
socklen_t address_len;
};
struct PendingConnection
{
ConnectionInfo target;
uint32_t target_start_seq;
};
struct ListenKey
{
ListenKey(const sockaddr* addr, socklen_t addr_len);
ListenKey(BAN::IPv4Address addr, uint16_t port)
: address(addr), port(port)
{}
bool operator==(const ListenKey& other) const;
BAN::IPv4Address address { 0 };
uint16_t port { 0 };
};
struct ListenKeyHash
{
BAN::hash_t operator()(ListenKey key) const;
};
private:
TCPSocket(NetworkLayer&, const Info&);
void process_task();
void start_close_sequence();
void set_connection_as_closed();
void remove_listen_child(BAN::RefPtr<TCPSocket>);
BAN::ErrorOr<size_t> return_with_maybe_zero();
private:
State m_state = State::Closed;
State m_next_state { State::Closed };
uint8_t m_next_flags { 0 };
Process* m_process { nullptr };
uint64_t m_time_wait_start_ms { 0 };
ThreadBlocker m_thread_blocker;
RecvWindowInfo m_recv_window;
SendWindowInfo m_send_window;
bool m_has_connected { false };
bool m_has_sent_zero { false };
BAN::Optional<ConnectionInfo> m_connection_info;
BAN::Queue<PendingConnection> m_pending_connections;
BAN::RefPtr<TCPSocket> m_listen_parent;
BAN::HashMap<ListenKey, BAN::RefPtr<TCPSocket>, ListenKeyHash> m_listen_children;
friend class BAN::RefPtr<TCPSocket>;
};
}