Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions src/core/net/tcp.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* @file tcp.cc
* @brief TCP header implementation.
*/

#include <tcp.h>

namespace juggler {
namespace net {

std::string Tcp::ToString() const {
return juggler::utils::Format(
"[TCP: src_port %zu, dst_port %zu, seq %u, ack %u, "
"offset %u, flags %s, win %zu, cksum 0x%04x, urg %zu]",
src_port.port.value(), dst_port.port.value(), seq_num.value(),
ack_num.value(), GetDataOffset(), FlagsToString().c_str(),
window.value(), cksum.value(), urgent_ptr.value());
}

std::string Tcp::FlagsToString() const {
std::string result;
if (HasFlag(kFin)) result += "FIN|";
if (HasFlag(kSyn)) result += "SYN|";
if (HasFlag(kRst)) result += "RST|";
if (HasFlag(kPsh)) result += "PSH|";
if (HasFlag(kAck)) result += "ACK|";
if (HasFlag(kUrg)) result += "URG|";
if (HasFlag(kEce)) result += "ECE|";
if (HasFlag(kCwr)) result += "CWR|";

// Remove trailing '|' if present
if (!result.empty() && result.back() == '|') {
result.pop_back();
}

if (result.empty()) {
result = "NONE";
}

return result;
}

} // namespace net
} // namespace juggler
133 changes: 133 additions & 0 deletions src/include/flow_key.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
/**
* @file flow_key.h
* @brief Flow key definitions for UDP and TCP flows.
*/
#ifndef SRC_INCLUDE_FLOW_KEY_H_
#define SRC_INCLUDE_FLOW_KEY_H_

#include <ipv4.h>
#include <tcp.h>
#include <udp.h>

namespace juggler {
namespace net {

/**
* @enum Protocol
* @brief Transport protocol identifier for flow keys.
*/
enum class Protocol : uint8_t {
kUdp = Ipv4::Proto::kUdp, // UDP protocol (17)
kTcp = Ipv4::Proto::kTcp, // TCP protocol (6)
};

namespace flow {

struct Listener {
Expand Down Expand Up @@ -101,6 +113,110 @@ struct Key {
static_assert(sizeof(Key) == 12, "Flow key size is not 12 bytes.");

} // namespace flow

/**
* @namespace tcp_flow
* @brief TCP-specific flow key definitions.
*/
namespace tcp_flow {

/**
* @struct Listener
* @brief TCP listener endpoint (IP address and port).
*/
struct Listener {
using Ipv4 = juggler::net::Ipv4;
using Tcp = juggler::net::Tcp;
Listener(const Listener& other) = default;

/**
* @brief Construct a new Listener object.
*
* @param local_addr Local IP address (in network byte order).
* @param local_port Local TCP port (in network byte order).
*/
Listener(const Ipv4::Address& local_addr, const Tcp::Port& local_port)
: addr(local_addr), port(local_port) {}

/**
* @brief Construct a new Listener object.
*
* @param local_addr Local IP address (in host byte order).
* @param local_port Local TCP port (in host byte order).
*/
Listener(const uint32_t local_addr, const uint16_t local_port)
: addr(local_addr), port(local_port) {}

bool operator==(const Listener& other) const {
return addr == other.addr && port == other.port;
}

const Ipv4::Address addr;
const Tcp::Port port;
};
static_assert(sizeof(Listener) == 6, "TCP Listener size is not 6 bytes.");

/**
* @struct Key
* @brief TCP flow key: corresponds to the 5-tuple (TCP is the protocol).
*/
struct Key {
using Ipv4 = juggler::net::Ipv4;
using Tcp = juggler::net::Tcp;
Key(const Key& other) = default;

/**
* @brief Construct a new Key object.
*
* @param local_addr Local IP address (in network byte order).
* @param local_port Local TCP port (in network byte order).
* @param remote_addr Remote IP address (in network byte order).
* @param remote_port Remote TCP port (in network byte order).
*/
Key(const Ipv4::Address& local_addr, const Tcp::Port& local_port,
const Ipv4::Address& remote_addr, const Tcp::Port& remote_port)
: local_addr(local_addr),
local_port(local_port),
remote_addr(remote_addr),
remote_port(remote_port) {}

/**
* @brief Construct a new Key object.
*
* @param local_addr Local IP address (in host byte order).
* @param local_port Local TCP port (in host byte order).
* @param remote_addr Remote IP address (in host byte order).
* @param remote_port Remote UDP port (in host byte order).
*/
Key(const uint32_t local_addr, const uint16_t local_port,
const uint32_t remote_addr, const uint16_t remote_port)
: local_addr(local_addr),
local_port(local_port),
remote_addr(remote_addr),
remote_port(remote_port) {}

bool operator==(const Key& other) const {
return local_addr == other.local_addr && local_port == other.local_port &&
remote_addr == other.remote_addr && remote_port == other.remote_port;
}

std::string ToString() const {
return utils::Format("[TCP %s:%hu <-> %s:%hu]",
remote_addr.ToString().c_str(),
remote_port.port.value(),
local_addr.ToString().c_str(),
local_port.port.value());
}

const Ipv4::Address local_addr;
const Tcp::Port local_port;
const Ipv4::Address remote_addr;
const Tcp::Port remote_port;
};
static_assert(sizeof(Key) == 12, "TCP flow key size is not 12 bytes.");

} // namespace tcp_flow

} // namespace net
} // namespace juggler

Expand All @@ -127,6 +243,23 @@ struct hash<juggler::net::flow::Key> {
}
};

// TCP flow hash specializations
template <>
struct hash<juggler::net::tcp_flow::Listener> {
size_t operator()(const juggler::net::tcp_flow::Listener& listener) const {
return juggler::utils::hash<uint64_t>(
reinterpret_cast<const char*>(&listener), sizeof(listener));
}
};

template <>
struct hash<juggler::net::tcp_flow::Key> {
size_t operator()(const juggler::net::tcp_flow::Key& key) const {
return juggler::utils::hash<uint64_t>(reinterpret_cast<const char*>(&key),
sizeof(key));
}
};

} // namespace std

#endif // SRC_INCLUDE_FLOW_KEY_H_
180 changes: 180 additions & 0 deletions src/include/tcp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/**
* @file tcp.h
* @brief TCP (Transmission Control Protocol) header definition.
*/

#ifndef SRC_INCLUDE_TCP_H_
#define SRC_INCLUDE_TCP_H_

#include <types.h>
#include <utils.h>

#include <cstdint>

namespace juggler {
namespace net {

/**
* @struct Tcp
* @brief TCP header structure (RFC 793).
*
* The TCP header is 20 bytes without options:
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Source Port | Destination Port |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Sequence Number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Acknowledgment Number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Data | |U|A|P|R|S|F| |
* | Offset| Reserved |R|C|S|S|Y|I| Window |
* | | |G|K|H|T|N|N| |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Checksum | Urgent Pointer |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
struct __attribute__((packed)) Tcp {
static constexpr uint8_t kMinHeaderLen = 20;
static constexpr uint8_t kMaxHeaderLen = 60;

/**
* @struct Port
* @brief TCP port wrapper (identical to UDP port structure for consistency).
*/
struct __attribute__((packed)) Port {
static const uint8_t kSize = 2;
Port() = default;
Port(uint16_t tcp_port) { port = be16_t(tcp_port); }
bool operator==(const Port &rhs) const { return port == rhs.port; }
bool operator==(be16_t rhs) const { return rhs == port; }
bool operator!=(const Port &rhs) const { return port != rhs.port; }
bool operator!=(be16_t rhs) const { return rhs != port; }

be16_t port;
};

/**
* @enum Flags
* @brief TCP control flags.
*/
enum Flags : uint8_t {
kFin = 0x01, // Finish - no more data from sender
kSyn = 0x02, // Synchronize - initiate connection
kRst = 0x04, // Reset - abort connection
kPsh = 0x08, // Push - push data to application
kAck = 0x10, // Acknowledgment field is valid
kUrg = 0x20, // Urgent pointer field is valid
kEce = 0x40, // ECN-Echo (RFC 3168)
kCwr = 0x80, // Congestion Window Reduced (RFC 3168)
};

/**
* @brief Get the data offset (header length) in 32-bit words.
* @return Header length in 32-bit words (5-15).
*/
uint8_t GetDataOffset() const { return (data_offset_reserved >> 4) & 0x0F; }

/**
* @brief Get the header length in bytes.
* @return Header length in bytes (20-60).
*/
uint8_t GetHeaderLength() const { return GetDataOffset() * 4; }

/**
* @brief Set the data offset (header length) in 32-bit words.
* @param offset Header length in 32-bit words (5-15).
*/
void SetDataOffset(uint8_t offset) {
data_offset_reserved = (offset << 4) | (data_offset_reserved & 0x0F);
}

/**
* @brief Get TCP flags.
* @return TCP flags byte.
*/
uint8_t GetFlags() const { return flags; }

/**
* @brief Set TCP flags.
* @param f Flags to set.
*/
void SetFlags(uint8_t f) { flags = f; }

/**
* @brief Check if a specific flag is set.
* @param flag Flag to check.
* @return true if flag is set, false otherwise.
*/
bool HasFlag(Flags flag) const { return (flags & flag) != 0; }

/**
* @brief Set a specific flag.
* @param flag Flag to set.
*/
void SetFlag(Flags flag) { flags |= flag; }

/**
* @brief Clear a specific flag.
* @param flag Flag to clear.
*/
void ClearFlag(Flags flag) { flags &= ~flag; }

/**
* @brief Convert TCP header to human-readable string.
* @return String representation of the TCP header.
*/
std::string ToString() const;

/**
* @brief Get string representation of TCP flags.
* @return String with flag names.
*/
std::string FlagsToString() const;

// TCP Header Fields
Port src_port; // Source port
Port dst_port; // Destination port
be32_t seq_num; // Sequence number
be32_t ack_num; // Acknowledgment number
uint8_t data_offset_reserved; // Data offset (4 bits) + Reserved (4 bits)
uint8_t flags; // Control flags
be16_t window; // Window size
be16_t cksum; // Checksum
be16_t urgent_ptr; // Urgent pointer
};

static_assert(sizeof(Tcp) == 20, "TCP header size must be 20 bytes");

/**
* @brief Bitwise OR operator for TCP flags.
*/
inline Tcp::Flags operator|(Tcp::Flags lhs, Tcp::Flags rhs) {
return static_cast<Tcp::Flags>(static_cast<uint8_t>(lhs) |
static_cast<uint8_t>(rhs));
}

/**
* @brief Bitwise AND operator for TCP flags.
*/
inline Tcp::Flags operator&(Tcp::Flags lhs, Tcp::Flags rhs) {
return static_cast<Tcp::Flags>(static_cast<uint8_t>(lhs) &
static_cast<uint8_t>(rhs));
}

} // namespace net
} // namespace juggler

namespace std {
template <>
struct hash<juggler::net::Tcp::Port> {
std::size_t operator()(const juggler::net::Tcp::Port &port) const {
return juggler::utils::hash<uint32_t>(
reinterpret_cast<const char *>(&port.port),
sizeof(port.port.raw_value()));
}
};
} // namespace std

#endif // SRC_INCLUDE_TCP_H_
Loading
Loading