forked from vikshanker/sponge
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
27 changed files
with
2,106 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
#include "tcp_header.hh" | ||
|
||
#include <sstream> | ||
|
||
using namespace std; | ||
|
||
//! \param[in,out] p is a NetParser from which the TCP fields will be extracted | ||
//! \returns a ParseResult indicating success or the reason for failure | ||
//! \details It is important to check for (at least) the following potential errors | ||
//! (but note that NetParser inherently checks for certain errors; | ||
//! use that fact to your advantage!): | ||
//! | ||
//! - data stream inside the NetParser is too short to contain a header | ||
//! - the header's `doff` field is shorter than the minimum allowed | ||
//! - there is less data in the header than the `doff` field claims | ||
//! - the checksum is bad | ||
ParseResult TCPHeader::parse(NetParser &p) { | ||
sport = p.u16(); // source port | ||
dport = p.u16(); // destination port | ||
seqno = WrappingInt32{p.u32()}; // sequence number | ||
ackno = WrappingInt32{p.u32()}; // ack number | ||
doff = p.u8() >> 4; // data offset | ||
|
||
const uint8_t fl_b = p.u8(); // byte including flags | ||
urg = static_cast<bool>(fl_b & 0b0010'0000); // binary literals and ' digit separator since C++14!!! | ||
ack = static_cast<bool>(fl_b & 0b0001'0000); | ||
psh = static_cast<bool>(fl_b & 0b0000'1000); | ||
rst = static_cast<bool>(fl_b & 0b0000'0100); | ||
syn = static_cast<bool>(fl_b & 0b0000'0010); | ||
fin = static_cast<bool>(fl_b & 0b0000'0001); | ||
|
||
win = p.u16(); // window size | ||
cksum = p.u16(); // checksum | ||
uptr = p.u16(); // urgent pointer | ||
|
||
if (doff < 5) { | ||
return ParseResult::HeaderTooShort; | ||
} | ||
|
||
// skip any options or anything extra in the header | ||
p.remove_prefix(doff * 4 - TCPHeader::LENGTH); | ||
|
||
if (p.error()) { | ||
return p.get_error(); | ||
} | ||
|
||
return ParseResult::NoError; | ||
} | ||
|
||
//! Serialize the TCPHeader to a string (does not recompute the checksum) | ||
string TCPHeader::serialize() const { | ||
// sanity check | ||
if (doff < 5) { | ||
throw runtime_error("TCP header too short"); | ||
} | ||
|
||
string ret; | ||
ret.reserve(4 * doff); | ||
|
||
NetUnparser::u16(ret, sport); // source port | ||
NetUnparser::u16(ret, dport); // destination port | ||
NetUnparser::u32(ret, seqno.raw_value()); // sequence number | ||
NetUnparser::u32(ret, ackno.raw_value()); // ack number | ||
NetUnparser::u8(ret, doff << 4); // data offset | ||
|
||
const uint8_t fl_b = (urg ? 0b0010'0000 : 0) | (ack ? 0b0001'0000 : 0) | (psh ? 0b0000'1000 : 0) | | ||
(rst ? 0b0000'0100 : 0) | (syn ? 0b0000'0010 : 0) | (fin ? 0b0000'0001 : 0); | ||
NetUnparser::u8(ret, fl_b); // flags | ||
NetUnparser::u16(ret, win); // window size | ||
|
||
NetUnparser::u16(ret, cksum); // checksum | ||
|
||
NetUnparser::u16(ret, uptr); // urgent pointer | ||
|
||
ret.resize(4 * doff); // expand header to advertised size | ||
|
||
return ret; | ||
} | ||
|
||
//! \returns A string with the header's contents | ||
string TCPHeader::to_string() const { | ||
stringstream ss{}; | ||
ss << hex << boolalpha << "TCP source port: " << +sport << '\n' | ||
<< "TCP dest port: " << +dport << '\n' | ||
<< "TCP seqno: " << seqno << '\n' | ||
<< "TCP ackno: " << ackno << '\n' | ||
<< "TCP doff: " << +doff << '\n' | ||
<< "Flags: urg: " << urg << " ack: " << ack << " psh: " << psh << " rst: " << rst << " syn: " << syn | ||
<< " fin: " << fin << '\n' | ||
<< "TCP winsize: " << +win << '\n' | ||
<< "TCP cksum: " << +cksum << '\n' | ||
<< "TCP uptr: " << +uptr << '\n'; | ||
return ss.str(); | ||
} | ||
|
||
string TCPHeader::summary() const { | ||
stringstream ss{}; | ||
ss << "Header(flags=" << (syn ? "S" : "") << (ack ? "A" : "") << (rst ? "R" : "") << (fin ? "F" : "") | ||
<< ",seqno=" << seqno << ",ack=" << ackno << ",win=" << win << ")"; | ||
return ss.str(); | ||
} | ||
|
||
bool TCPHeader::operator==(const TCPHeader &other) const { | ||
// TODO(aozdemir) more complete check (right now we omit cksum, src, dst | ||
return seqno == other.seqno && ackno == other.ackno && doff == other.doff && urg == other.urg && ack == other.ack && | ||
psh == other.psh && rst == other.rst && syn == other.syn && fin == other.fin && win == other.win && | ||
uptr == other.uptr; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
#ifndef SPONGE_LIBSPONGE_TCP_HEADER_HH | ||
#define SPONGE_LIBSPONGE_TCP_HEADER_HH | ||
|
||
#include "parser.hh" | ||
#include "wrapping_integers.hh" | ||
|
||
//! \brief [TCP](\ref rfc::rfc793) segment header | ||
//! \note TCP options are not supported | ||
struct TCPHeader { | ||
static constexpr size_t LENGTH = 20; //!< [TCP](\ref rfc::rfc793) header length, not including options | ||
|
||
//! \struct TCPHeader | ||
//! ~~~{.txt} | ||
//! 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 | | ||
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
//! | Options | Padding | | ||
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
//! | data | | ||
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
//! ~~~ | ||
|
||
//! \name TCP Header fields | ||
//!@{ | ||
uint16_t sport = 0; //!< source port | ||
uint16_t dport = 0; //!< destination port | ||
WrappingInt32 seqno{0}; //!< sequence number | ||
WrappingInt32 ackno{0}; //!< ack number | ||
uint8_t doff = LENGTH / 4; //!< data offset | ||
bool urg = false; //!< urgent flag | ||
bool ack = false; //!< ack flag | ||
bool psh = false; //!< push flag | ||
bool rst = false; //!< rst flag | ||
bool syn = false; //!< syn flag | ||
bool fin = false; //!< fin flag | ||
uint16_t win = 0; //!< window size | ||
uint16_t cksum = 0; //!< checksum | ||
uint16_t uptr = 0; //!< urgent pointer | ||
//!@} | ||
|
||
//! Parse the TCP fields from the provided NetParser | ||
ParseResult parse(NetParser &p); | ||
|
||
//! Serialize the TCP fields | ||
std::string serialize() const; | ||
|
||
//! Return a string containing a header in human-readable format | ||
std::string to_string() const; | ||
|
||
//! Return a string containing a human-readable summary of the header | ||
std::string summary() const; | ||
|
||
bool operator==(const TCPHeader &other) const; | ||
}; | ||
|
||
#endif // SPONGE_LIBSPONGE_TCP_HEADER_HH |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#include "tcp_segment.hh" | ||
|
||
#include "parser.hh" | ||
#include "util.hh" | ||
|
||
#include <variant> | ||
|
||
using namespace std; | ||
|
||
//! \param[in] buffer string/Buffer to be parsed | ||
//! \param[in] datagram_layer_checksum pseudo-checksum from the lower-layer protocol | ||
ParseResult TCPSegment::parse(const Buffer buffer, const uint32_t datagram_layer_checksum) { | ||
InternetChecksum check(datagram_layer_checksum); | ||
check.add(buffer); | ||
if (check.value()) { | ||
return ParseResult::BadChecksum; | ||
} | ||
|
||
NetParser p{buffer}; | ||
_header.parse(p); | ||
_payload = p.buffer(); | ||
return p.get_error(); | ||
} | ||
|
||
size_t TCPSegment::length_in_sequence_space() const { | ||
return payload().str().size() + (header().syn ? 1 : 0) + (header().fin ? 1 : 0); | ||
} | ||
|
||
//! \param[in] datagram_layer_checksum pseudo-checksum from the lower-layer protocol | ||
BufferList TCPSegment::serialize(const uint32_t datagram_layer_checksum) const { | ||
TCPHeader header_out = _header; | ||
header_out.cksum = 0; | ||
|
||
// calculate checksum -- taken over entire segment | ||
InternetChecksum check(datagram_layer_checksum); | ||
check.add(header_out.serialize()); | ||
check.add(_payload); | ||
header_out.cksum = check.value(); | ||
|
||
BufferList ret; | ||
ret.append(header_out.serialize()); | ||
ret.append(_payload); | ||
|
||
return ret; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#ifndef SPONGE_LIBSPONGE_TCP_SEGMENT_HH | ||
#define SPONGE_LIBSPONGE_TCP_SEGMENT_HH | ||
|
||
#include "buffer.hh" | ||
#include "tcp_header.hh" | ||
|
||
#include <cstdint> | ||
|
||
//! \brief [TCP](\ref rfc::rfc793) segment | ||
class TCPSegment { | ||
private: | ||
TCPHeader _header{}; | ||
Buffer _payload{}; | ||
|
||
public: | ||
//! \brief Parse the segment from a string | ||
ParseResult parse(const Buffer buffer, const uint32_t datagram_layer_checksum = 0); | ||
|
||
//! \brief Serialize the segment to a string | ||
BufferList serialize(const uint32_t datagram_layer_checksum = 0) const; | ||
|
||
//! \name Accessors | ||
//!@{ | ||
const TCPHeader &header() const { return _header; } | ||
TCPHeader &header() { return _header; } | ||
|
||
const Buffer &payload() const { return _payload; } | ||
Buffer &payload() { return _payload; } | ||
//!@} | ||
|
||
//! \brief Segment's length in sequence space | ||
//! \note Equal to payload length plus one byte if SYN is set, plus one byte if FIN is set | ||
size_t length_in_sequence_space() const; | ||
}; | ||
|
||
#endif // SPONGE_LIBSPONGE_TCP_SEGMENT_HH |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#include "tcp_state.hh" | ||
|
||
using namespace std; | ||
|
||
string TCPState::state_summary(const TCPReceiver &receiver) { | ||
if (receiver.stream_out().error()) { | ||
return TCPReceiverStateSummary::ERROR; | ||
} else if (not receiver.ackno().has_value()) { | ||
return TCPReceiverStateSummary::LISTEN; | ||
} else if (receiver.stream_out().input_ended()) { | ||
return TCPReceiverStateSummary::FIN_RECV; | ||
} else { | ||
return TCPReceiverStateSummary::SYN_RECV; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#ifndef SPONGE_LIBSPONGE_TCP_STATE | ||
#define SPONGE_LIBSPONGE_TCP_STATE | ||
|
||
#include "tcp_receiver.hh" | ||
|
||
#include <string> | ||
|
||
//! \brief Summary of a TCPConnection's internal state | ||
//! | ||
//! Most TCP implementations have a global per-connection state | ||
//! machine, as described in the [TCP](\ref rfc::rfc793) | ||
//! specification. Sponge is a bit different: we have factored the | ||
//! connection into two independent parts (the sender and the | ||
//! receiver). The TCPSender and TCPReceiver maintain their interval | ||
//! state variables independently (e.g. next_seqno, number of bytes in | ||
//! flight, or whether each stream has ended). There is no notion of a | ||
//! discrete state machine or much overarching state outside the | ||
//! sender and receiver. To test that Sponge follows the TCP spec, we | ||
//! use this class to compare the "official" states with Sponge's | ||
//! sender/receiver states and two variables that belong to the | ||
//! overarching TCPConnection object. | ||
class TCPState { | ||
public: | ||
//! \brief Summarize the state of a TCPReceiver in a string | ||
static std::string state_summary(const TCPReceiver &receiver); | ||
}; | ||
|
||
namespace TCPReceiverStateSummary { | ||
const std::string ERROR = "error (connection was reset)"; | ||
const std::string LISTEN = "waiting for SYN: ackno is empty"; | ||
const std::string SYN_RECV = "SYN received (ackno exists), and input to stream hasn't ended"; | ||
const std::string FIN_RECV = "input to stream has ended"; | ||
} // namespace TCPReceiverStateSummary | ||
|
||
#endif // SPONGE_LIBSPONGE_TCP_STATE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#include "tcp_receiver.hh" | ||
|
||
// Dummy implementation of a TCP receiver | ||
|
||
// For Lab 2, please replace with a real implementation that passes the | ||
// automated checks run by `make check_lab2`. | ||
|
||
template <typename... Targs> | ||
void DUMMY_CODE(Targs &&... /* unused */) {} | ||
|
||
using namespace std; | ||
|
||
void TCPReceiver::segment_received(const TCPSegment &seg) { | ||
DUMMY_CODE(seg); | ||
} | ||
|
||
optional<WrappingInt32> TCPReceiver::ackno() const { return {}; } | ||
|
||
size_t TCPReceiver::window_size() const { return {}; } |
Oops, something went wrong.