CS144 Lab checkpoint 3 starter code
This commit is contained in:
parent
87babd9d62
commit
e70095b9ff
35
libsponge/tcp_helpers/tcp_config.hh
Normal file
35
libsponge/tcp_helpers/tcp_config.hh
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#ifndef SPONGE_LIBSPONGE_TCP_CONFIG_HH
|
||||||
|
#define SPONGE_LIBSPONGE_TCP_CONFIG_HH
|
||||||
|
|
||||||
|
#include "address.hh"
|
||||||
|
#include "wrapping_integers.hh"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
//! Config for TCP sender and receiver
|
||||||
|
class TCPConfig {
|
||||||
|
public:
|
||||||
|
static constexpr size_t DEFAULT_CAPACITY = 64000; //!< Default capacity
|
||||||
|
static constexpr size_t MAX_PAYLOAD_SIZE = 1452; //!< Max TCP payload that fits in either IPv4 or UDP datagram
|
||||||
|
static constexpr uint16_t TIMEOUT_DFLT = 1000; //!< Default re-transmit timeout is 1 second
|
||||||
|
static constexpr unsigned MAX_RETX_ATTEMPTS = 8; //!< Maximum re-transmit attempts before giving up
|
||||||
|
|
||||||
|
uint16_t rt_timeout = TIMEOUT_DFLT; //!< Initial value of the retransmission timeout, in milliseconds
|
||||||
|
size_t recv_capacity = DEFAULT_CAPACITY; //!< Receive capacity, in bytes
|
||||||
|
size_t send_capacity = DEFAULT_CAPACITY; //!< Sender capacity, in bytes
|
||||||
|
std::optional<WrappingInt32> fixed_isn{};
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Config for classes derived from FdAdapter
|
||||||
|
class FdAdapterConfig {
|
||||||
|
public:
|
||||||
|
Address source{"0", 0}; //!< Source address and port
|
||||||
|
Address destination{"0", 0}; //!< Destination address and port
|
||||||
|
|
||||||
|
uint16_t loss_rate_dn = 0; //!< Downlink loss rate (for LossyFdAdapter)
|
||||||
|
uint16_t loss_rate_up = 0; //!< Uplink loss rate (for LossyFdAdapter)
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SPONGE_LIBSPONGE_TCP_CONFIG_HH
|
||||||
@ -13,3 +13,21 @@ string TCPState::state_summary(const TCPReceiver &receiver) {
|
|||||||
return TCPReceiverStateSummary::SYN_RECV;
|
return TCPReceiverStateSummary::SYN_RECV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string TCPState::state_summary(const TCPSender &sender) {
|
||||||
|
if (sender.stream_in().error()) {
|
||||||
|
return TCPSenderStateSummary::ERROR;
|
||||||
|
} else if (sender.next_seqno_absolute() == 0) {
|
||||||
|
return TCPSenderStateSummary::CLOSED;
|
||||||
|
} else if (sender.next_seqno_absolute() == sender.bytes_in_flight()) {
|
||||||
|
return TCPSenderStateSummary::SYN_SENT;
|
||||||
|
} else if (not sender.stream_in().eof()) {
|
||||||
|
return TCPSenderStateSummary::SYN_ACKED;
|
||||||
|
} else if (sender.next_seqno_absolute() < sender.stream_in().bytes_written() + 2) {
|
||||||
|
return TCPSenderStateSummary::SYN_ACKED;
|
||||||
|
} else if (sender.bytes_in_flight()) {
|
||||||
|
return TCPSenderStateSummary::FIN_SENT;
|
||||||
|
} else {
|
||||||
|
return TCPSenderStateSummary::FIN_ACKED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
#define SPONGE_LIBSPONGE_TCP_STATE
|
#define SPONGE_LIBSPONGE_TCP_STATE
|
||||||
|
|
||||||
#include "tcp_receiver.hh"
|
#include "tcp_receiver.hh"
|
||||||
|
#include "tcp_sender.hh"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@ -23,6 +24,9 @@ class TCPState {
|
|||||||
public:
|
public:
|
||||||
//! \brief Summarize the state of a TCPReceiver in a string
|
//! \brief Summarize the state of a TCPReceiver in a string
|
||||||
static std::string state_summary(const TCPReceiver &receiver);
|
static std::string state_summary(const TCPReceiver &receiver);
|
||||||
|
|
||||||
|
//! \brief Summarize the state of a TCPSender in a string
|
||||||
|
static std::string state_summary(const TCPSender &receiver);
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace TCPReceiverStateSummary {
|
namespace TCPReceiverStateSummary {
|
||||||
@ -32,4 +36,13 @@ const std::string SYN_RECV = "SYN received (ackno exists), and input to stream h
|
|||||||
const std::string FIN_RECV = "input to stream has ended";
|
const std::string FIN_RECV = "input to stream has ended";
|
||||||
} // namespace TCPReceiverStateSummary
|
} // namespace TCPReceiverStateSummary
|
||||||
|
|
||||||
|
namespace TCPSenderStateSummary {
|
||||||
|
const std::string ERROR = "error (connection was reset)";
|
||||||
|
const std::string CLOSED = "waiting for stream to begin (no SYN sent)";
|
||||||
|
const std::string SYN_SENT = "stream started but nothing acknowledged";
|
||||||
|
const std::string SYN_ACKED = "stream ongoing";
|
||||||
|
const std::string FIN_SENT = "stream finished (FIN sent) but not fully acknowledged";
|
||||||
|
const std::string FIN_ACKED = "stream finished and fully acknowledged";
|
||||||
|
} // namespace TCPSenderStateSummary
|
||||||
|
|
||||||
#endif // SPONGE_LIBSPONGE_TCP_STATE
|
#endif // SPONGE_LIBSPONGE_TCP_STATE
|
||||||
|
|||||||
38
libsponge/tcp_sender.cc
Normal file
38
libsponge/tcp_sender.cc
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include "tcp_sender.hh"
|
||||||
|
|
||||||
|
#include "tcp_config.hh"
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
// Dummy implementation of a TCP sender
|
||||||
|
|
||||||
|
// For Lab 3, please replace with a real implementation that passes the
|
||||||
|
// automated checks run by `make check_lab3`.
|
||||||
|
|
||||||
|
template <typename... Targs>
|
||||||
|
void DUMMY_CODE(Targs &&... /* unused */) {}
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
//! \param[in] capacity the capacity of the outgoing byte stream
|
||||||
|
//! \param[in] retx_timeout the initial amount of time to wait before retransmitting the oldest outstanding segment
|
||||||
|
//! \param[in] fixed_isn the Initial Sequence Number to use, if set (otherwise uses a random ISN)
|
||||||
|
TCPSender::TCPSender(const size_t capacity, const uint16_t retx_timeout, const std::optional<WrappingInt32> fixed_isn)
|
||||||
|
: _isn(fixed_isn.value_or(WrappingInt32{random_device()()}))
|
||||||
|
, _initial_retransmission_timeout{retx_timeout}
|
||||||
|
, _stream(capacity) {}
|
||||||
|
|
||||||
|
uint64_t TCPSender::bytes_in_flight() const { return {}; }
|
||||||
|
|
||||||
|
void TCPSender::fill_window() {}
|
||||||
|
|
||||||
|
//! \param ackno The remote receiver's ackno (acknowledgment number)
|
||||||
|
//! \param window_size The remote receiver's advertised window size
|
||||||
|
void TCPSender::ack_received(const WrappingInt32 ackno, const uint16_t window_size) { DUMMY_CODE(ackno, window_size); }
|
||||||
|
|
||||||
|
//! \param[in] ms_since_last_tick the number of milliseconds since the last call to this method
|
||||||
|
void TCPSender::tick(const size_t ms_since_last_tick) { DUMMY_CODE(ms_since_last_tick); }
|
||||||
|
|
||||||
|
unsigned int TCPSender::consecutive_retransmissions() const { return {}; }
|
||||||
|
|
||||||
|
void TCPSender::send_empty_segment() {}
|
||||||
92
libsponge/tcp_sender.hh
Normal file
92
libsponge/tcp_sender.hh
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#ifndef SPONGE_LIBSPONGE_TCP_SENDER_HH
|
||||||
|
#define SPONGE_LIBSPONGE_TCP_SENDER_HH
|
||||||
|
|
||||||
|
#include "byte_stream.hh"
|
||||||
|
#include "tcp_config.hh"
|
||||||
|
#include "tcp_segment.hh"
|
||||||
|
#include "wrapping_integers.hh"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
//! \brief The "sender" part of a TCP implementation.
|
||||||
|
|
||||||
|
//! Accepts a ByteStream, divides it up into segments and sends the
|
||||||
|
//! segments, keeps track of which segments are still in-flight,
|
||||||
|
//! maintains the Retransmission Timer, and retransmits in-flight
|
||||||
|
//! segments if the retransmission timer expires.
|
||||||
|
class TCPSender {
|
||||||
|
private:
|
||||||
|
//! our initial sequence number, the number for our SYN.
|
||||||
|
WrappingInt32 _isn;
|
||||||
|
|
||||||
|
//! outbound queue of segments that the TCPSender wants sent
|
||||||
|
std::queue<TCPSegment> _segments_out{};
|
||||||
|
|
||||||
|
//! retransmission timer for the connection
|
||||||
|
unsigned int _initial_retransmission_timeout;
|
||||||
|
|
||||||
|
//! outgoing stream of bytes that have not yet been sent
|
||||||
|
ByteStream _stream;
|
||||||
|
|
||||||
|
//! the (absolute) sequence number for the next byte to be sent
|
||||||
|
uint64_t _next_seqno{0};
|
||||||
|
|
||||||
|
public:
|
||||||
|
//! Initialize a TCPSender
|
||||||
|
TCPSender(const size_t capacity = TCPConfig::DEFAULT_CAPACITY,
|
||||||
|
const uint16_t retx_timeout = TCPConfig::TIMEOUT_DFLT,
|
||||||
|
const std::optional<WrappingInt32> fixed_isn = {});
|
||||||
|
|
||||||
|
//! \name "Input" interface for the writer
|
||||||
|
//!@{
|
||||||
|
ByteStream &stream_in() { return _stream; }
|
||||||
|
const ByteStream &stream_in() const { return _stream; }
|
||||||
|
//!@}
|
||||||
|
|
||||||
|
//! \name Methods that can cause the TCPSender to send a segment
|
||||||
|
//!@{
|
||||||
|
|
||||||
|
//! \brief A new acknowledgment was received
|
||||||
|
void ack_received(const WrappingInt32 ackno, const uint16_t window_size);
|
||||||
|
|
||||||
|
//! \brief Generate an empty-payload segment (useful for creating empty ACK segments)
|
||||||
|
void send_empty_segment();
|
||||||
|
|
||||||
|
//! \brief create and send segments to fill as much of the window as possible
|
||||||
|
void fill_window();
|
||||||
|
|
||||||
|
//! \brief Notifies the TCPSender of the passage of time
|
||||||
|
void tick(const size_t ms_since_last_tick);
|
||||||
|
//!@}
|
||||||
|
|
||||||
|
//! \name Accessors
|
||||||
|
//!@{
|
||||||
|
|
||||||
|
//! \brief How many sequence numbers are occupied by segments sent but not yet acknowledged?
|
||||||
|
//! \note count is in "sequence space," i.e. SYN and FIN each count for one byte
|
||||||
|
//! (see TCPSegment::length_in_sequence_space())
|
||||||
|
size_t bytes_in_flight() const;
|
||||||
|
|
||||||
|
//! \brief Number of consecutive retransmissions that have occurred in a row
|
||||||
|
unsigned int consecutive_retransmissions() const;
|
||||||
|
|
||||||
|
//! \brief TCPSegments that the TCPSender has enqueued for transmission.
|
||||||
|
//! \note These must be dequeued and sent by the TCPConnection,
|
||||||
|
//! which will need to fill in the fields that are set by the TCPReceiver
|
||||||
|
//! (ackno and window size) before sending.
|
||||||
|
std::queue<TCPSegment> &segments_out() { return _segments_out; }
|
||||||
|
//!@}
|
||||||
|
|
||||||
|
//! \name What is the next sequence number? (used for testing)
|
||||||
|
//!@{
|
||||||
|
|
||||||
|
//! \brief absolute seqno for the next byte to be sent
|
||||||
|
uint64_t next_seqno_absolute() const { return _next_seqno; }
|
||||||
|
|
||||||
|
//! \brief relative seqno for the next byte to be sent
|
||||||
|
WrappingInt32 next_seqno() const { return wrap(_next_seqno, _isn); }
|
||||||
|
//!@}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SPONGE_LIBSPONGE_TCP_SENDER_HH
|
||||||
@ -30,3 +30,10 @@ add_test_exec (recv_window)
|
|||||||
add_test_exec (recv_reorder)
|
add_test_exec (recv_reorder)
|
||||||
add_test_exec (recv_close)
|
add_test_exec (recv_close)
|
||||||
add_test_exec (recv_special)
|
add_test_exec (recv_special)
|
||||||
|
add_test_exec (send_connect)
|
||||||
|
add_test_exec (send_transmit)
|
||||||
|
add_test_exec (send_retx)
|
||||||
|
add_test_exec (send_ack)
|
||||||
|
add_test_exec (send_window)
|
||||||
|
add_test_exec (send_close)
|
||||||
|
add_test_exec (send_extra)
|
||||||
|
|||||||
29
writeups/lab3.md
Normal file
29
writeups/lab3.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
Lab 3 Writeup
|
||||||
|
=============
|
||||||
|
|
||||||
|
My name: [your name here]
|
||||||
|
|
||||||
|
My SUNet ID: [your sunetid here]
|
||||||
|
|
||||||
|
I collaborated with: [list sunetids here]
|
||||||
|
|
||||||
|
I would like to thank/reward these classmates for their help: [list sunetids here]
|
||||||
|
|
||||||
|
This lab took me about [n] hours to do. I [did/did not] attend the lab session.
|
||||||
|
|
||||||
|
Program Structure and Design of the TCPSender:
|
||||||
|
[]
|
||||||
|
|
||||||
|
Implementation Challenges:
|
||||||
|
[]
|
||||||
|
|
||||||
|
Remaining Bugs:
|
||||||
|
[]
|
||||||
|
|
||||||
|
- Optional: I had unexpected difficulty with: [describe]
|
||||||
|
|
||||||
|
- Optional: I think you could make this lab better by: [describe]
|
||||||
|
|
||||||
|
- Optional: I was surprised by: [describe]
|
||||||
|
|
||||||
|
- Optional: I'm not sure about: [describe]
|
||||||
Loading…
Reference in New Issue
Block a user