//..............................................................................
//
// TCP (transmission control protocol) defitions
//

namespace io {

//! \addtogroup proto-tcp
//! @{

//..............................................................................

bitflag enum TcpFlags: uint8_t {
	Fin,
	Syn,
	Rst,
	Psh,
	Ack,
	Urg,
	Bog,
}

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

string_t formatTcpFlagString(TcpFlags flags) {
	return $"%c%c%c%c%c%c%c"(
		(flags & TcpFlags.Fin) ? 'F' : '.',
		(flags & TcpFlags.Syn) ? 'S' : '.',
		(flags & TcpFlags.Rst) ? 'R' : '.',
		(flags & TcpFlags.Psh) ? 'P' : '.',
		(flags & TcpFlags.Ack) ? 'A' : '.',
		(flags & TcpFlags.Urg) ? 'U' : '.',
		(flags & TcpFlags.Bog) ? 'B' : '.'
	);
}

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

[
	displayName = "TCP",
	formatDigestFunc = formatTcpDigest
]
struct TcpHdr {
	[ displayName = "Source port" ]
	bigendian uint16_t m_srcPort;

	[ displayName = "Destination port" ]
	bigendian uint16_t m_dstPort;

	[ displayName = "Sequence number" ]
	bigendian uint32_t m_seqNumber;

	[ displayName = "Acknowledgement number" ]
	bigendian uint32_t m_ackNumber;

	[ displayName = "Padding" ]
	uint8_t m_reserved   : 4;

	[ displayName = "Header length" ]
	uint8_t m_dataOffset : 4;

	[ displayName = "Flags" ]
	TcpFlags m_flags;

	[ displayName = "Window size" ]
	bigendian uint16_t m_window;

	[
		displayName = "Checksum",
		formatSpec = "0x%04X"
	]
	bigendian uint16_t m_checksum;

	[ displayName = "Urgent pointer" ]
	bigendian uint16_t m_urgentData;
}

// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

string_t formatTcpDigest(void const* p) {
	TcpHdr const* hdr = (TcpHdr const*)p;
	return $"%1 \u2192 %2 [%3]" (
		hdr.m_srcPort,
		hdr.m_dstPort,
		formatTcpFlagString(hdr.m_flags)
	);
}

//..............................................................................

//! @}

} // namespace io
