CS144 Lab checkpoint 3 starter code

This commit is contained in:
Keith Winstein 2021-09-28 17:01:21 -07:00
parent 87babd9d62
commit e70095b9ff
7 changed files with 232 additions and 0 deletions

View 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

View File

@ -13,3 +13,21 @@ string TCPState::state_summary(const TCPReceiver &receiver) {
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;
}
}

View File

@ -2,6 +2,7 @@
#define SPONGE_LIBSPONGE_TCP_STATE
#include "tcp_receiver.hh"
#include "tcp_sender.hh"
#include <string>
@ -23,6 +24,9 @@ class TCPState {
public:
//! \brief Summarize the state of a TCPReceiver in a string
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 {
@ -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";
} // 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

38
libsponge/tcp_sender.cc Normal file
View 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
View 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

View File

@ -30,3 +30,10 @@ add_test_exec (recv_window)
add_test_exec (recv_reorder)
add_test_exec (recv_close)
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
View 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]