refactor and comment
This commit is contained in:
parent
6dd84564cf
commit
b60b909a19
@ -21,35 +21,30 @@ size_t TCPConnection::unassembled_bytes() const { return _receiver.unassembled_b
|
|||||||
size_t TCPConnection::time_since_last_segment_received() const { return _time_last_segment_received; }
|
size_t TCPConnection::time_since_last_segment_received() const { return _time_last_segment_received; }
|
||||||
|
|
||||||
void TCPConnection::segment_received(const TCPSegment &seg) {
|
void TCPConnection::segment_received(const TCPSegment &seg) {
|
||||||
if (!_active)
|
// god knows whether it should be active or not initially
|
||||||
return;
|
|
||||||
_time_last_segment_received = 0;
|
_time_last_segment_received = 0;
|
||||||
if (seg.header().rst) {
|
if (seg.header().rst) {
|
||||||
_sender.stream_in().set_error();
|
_set_rst();
|
||||||
_receiver.stream_out().set_error();
|
|
||||||
_active = false;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bool send_ack = seg.length_in_sequence_space();
|
|
||||||
_receiver.segment_received(seg);
|
_receiver.segment_received(seg);
|
||||||
if (seg.header().ack && _receiver.ackno().has_value()) {
|
if (seg.header().ack && _receiver.ackno().has_value()) {
|
||||||
// filter out acks before syn
|
// filter out acks before syn
|
||||||
_sender.ack_received(seg.header().ackno, seg.header().win);
|
_sender.ack_received(seg.header().ackno, seg.header().win);
|
||||||
// _sender.fill_window();
|
// _sender.fill_window(); !! This should be done in ack_received
|
||||||
if (!_sender.segments_out().empty()) send_ack = false;
|
|
||||||
}
|
}
|
||||||
// std::cerr << seg.header().to_string();
|
// if the inbound seg has len it should be responded
|
||||||
// std::cerr << _receiver.stream_out().bytes_written() << " " << _receiver.unassembled_bytes() << std::endl;
|
// except that ack_received() has send a seg, so no more is needed
|
||||||
// std::cerr << seg.payload().size() << std::endl;
|
if (seg.length_in_sequence_space() && _sender.segments_out().empty()) {
|
||||||
|
_sender.fill_window(); // it is necessary to repond to SYN with a SYNACK
|
||||||
if (send_ack) {
|
|
||||||
_sender.fill_window();
|
|
||||||
if (_sender.segments_out().empty()) {
|
if (_sender.segments_out().empty()) {
|
||||||
_sender.send_empty_segment();
|
_sender.send_empty_segment();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_send_all();
|
_send_all();
|
||||||
// TODO: Keep-alive but it seems to be use
|
// TODO: Keep-alive but it seems to be use
|
||||||
|
// recver in FIN_RECV
|
||||||
|
// sender in SYN_ACKED
|
||||||
if (_receiver.stream_out().input_ended() && !_sender.stream_in().eof()) {
|
if (_receiver.stream_out().input_ended() && !_sender.stream_in().eof()) {
|
||||||
_linger_after_streams_finish = false;
|
_linger_after_streams_finish = false;
|
||||||
}
|
}
|
||||||
@ -70,30 +65,19 @@ void TCPConnection::tick(const size_t ms_since_last_tick) {
|
|||||||
_time_last_segment_received += ms_since_last_tick;
|
_time_last_segment_received += ms_since_last_tick;
|
||||||
_sender.tick(ms_since_last_tick);
|
_sender.tick(ms_since_last_tick);
|
||||||
if (_sender.consecutive_retransmissions() > TCPConfig::MAX_RETX_ATTEMPTS) {
|
if (_sender.consecutive_retransmissions() > TCPConfig::MAX_RETX_ATTEMPTS) {
|
||||||
_sender.send_empty_segment();
|
_send_rst();
|
||||||
auto &seg_queue = _sender.segments_out();
|
_set_rst();
|
||||||
auto seg = seg_queue.front();
|
|
||||||
seg_queue.pop();
|
|
||||||
if (_receiver.ackno().has_value()) {
|
|
||||||
seg.header().ack = true;
|
|
||||||
seg.header().ackno = _receiver.ackno().value();
|
|
||||||
}
|
|
||||||
seg.header().win = _receiver.window_size();
|
|
||||||
seg.header().rst = true;
|
|
||||||
_segments_out.push(seg);
|
|
||||||
_sender.stream_in().set_error();
|
|
||||||
_receiver.stream_out().set_error();
|
|
||||||
_active = false;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_send_all();
|
_send_all();
|
||||||
if (!_sender.bytes_in_flight() && _sender.stream_in().eof() && _receiver.stream_out().input_ended() &&
|
// actually, this long if could be represented by TCP states
|
||||||
!_receiver.unassembled_bytes()) {
|
// for sender, it is the FIN_ACKED state
|
||||||
if (!_linger_after_streams_finish) {
|
// for recver, it is the FIN_RECV state
|
||||||
|
// and plus linger
|
||||||
|
if ((!_sender.bytes_in_flight() && _sender.stream_in().eof()) &&
|
||||||
|
(_receiver.stream_out().input_ended() && !_receiver.unassembled_bytes()) &&
|
||||||
|
(!_linger_after_streams_finish || _time_last_segment_received >= 10 * _cfg.rt_timeout)) {
|
||||||
_active = false;
|
_active = false;
|
||||||
} else if (_time_last_segment_received >= 10 * _cfg.rt_timeout) {
|
|
||||||
_active = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,20 +96,8 @@ TCPConnection::~TCPConnection() {
|
|||||||
try {
|
try {
|
||||||
if (active()) {
|
if (active()) {
|
||||||
cerr << "Warning: Unclean shutdown of TCPConnection\n";
|
cerr << "Warning: Unclean shutdown of TCPConnection\n";
|
||||||
_sender.send_empty_segment();
|
_send_rst();
|
||||||
auto &seg_queue = _sender.segments_out();
|
_set_rst();
|
||||||
auto seg = seg_queue.front();
|
|
||||||
seg_queue.pop();
|
|
||||||
if (_receiver.ackno().has_value()) {
|
|
||||||
seg.header().ack = true;
|
|
||||||
seg.header().ackno = _receiver.ackno().value();
|
|
||||||
}
|
|
||||||
seg.header().win = _receiver.window_size();
|
|
||||||
seg.header().rst = true;
|
|
||||||
_segments_out.push(seg);
|
|
||||||
_sender.stream_in().set_error();
|
|
||||||
_receiver.stream_out().set_error();
|
|
||||||
_active = false;
|
|
||||||
// Your code here: need to send a RST segment to the peer
|
// Your code here: need to send a RST segment to the peer
|
||||||
}
|
}
|
||||||
} catch (const exception &e) {
|
} catch (const exception &e) {
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include "tcp_receiver.hh"
|
#include "tcp_receiver.hh"
|
||||||
#include "tcp_sender.hh"
|
#include "tcp_sender.hh"
|
||||||
#include "tcp_state.hh"
|
#include "tcp_state.hh"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
@ -22,8 +23,17 @@ class TCPConnection {
|
|||||||
//! for 10 * _cfg.rt_timeout milliseconds after both streams have ended,
|
//! for 10 * _cfg.rt_timeout milliseconds after both streams have ended,
|
||||||
//! in case the remote TCPConnection doesn't know we've received its whole stream?
|
//! in case the remote TCPConnection doesn't know we've received its whole stream?
|
||||||
bool _linger_after_streams_finish{true};
|
bool _linger_after_streams_finish{true};
|
||||||
|
|
||||||
|
//! Private state for time_since_last_segment_received()
|
||||||
size_t _time_last_segment_received{0};
|
size_t _time_last_segment_received{0};
|
||||||
|
|
||||||
|
//! Private state for active()
|
||||||
bool _active{true};
|
bool _active{true};
|
||||||
|
|
||||||
|
//!\name Internal helper procedures
|
||||||
|
//!@{
|
||||||
|
|
||||||
|
//!\brief Send all available outbound segments
|
||||||
void _send_all() {
|
void _send_all() {
|
||||||
auto &seg_queue = _sender.segments_out();
|
auto &seg_queue = _sender.segments_out();
|
||||||
while (!seg_queue.empty()) {
|
while (!seg_queue.empty()) {
|
||||||
@ -33,10 +43,38 @@ class TCPConnection {
|
|||||||
seg.header().ack = true;
|
seg.header().ack = true;
|
||||||
seg.header().ackno = _receiver.ackno().value();
|
seg.header().ackno = _receiver.ackno().value();
|
||||||
}
|
}
|
||||||
seg.header().win = std::min(_receiver.window_size(), static_cast<size_t>(std::numeric_limits<uint16_t>::max()));
|
seg.header().win =
|
||||||
|
std::min(_receiver.window_size(), static_cast<size_t>(std::numeric_limits<uint16_t>::max()));
|
||||||
_segments_out.push(seg);
|
_segments_out.push(seg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//!\brief Deprecate all other packets in the queue, and send a RST segment
|
||||||
|
void _send_rst() {
|
||||||
|
auto &seg_queue = _sender.segments_out();
|
||||||
|
while (!seg_queue.empty()) {
|
||||||
|
seg_queue.pop();
|
||||||
|
}
|
||||||
|
_sender.send_empty_segment();
|
||||||
|
auto seg = seg_queue.front();
|
||||||
|
seg_queue.pop();
|
||||||
|
if (_receiver.ackno().has_value()) {
|
||||||
|
seg.header().ack = true;
|
||||||
|
seg.header().ackno = _receiver.ackno().value();
|
||||||
|
}
|
||||||
|
seg.header().win = _receiver.window_size();
|
||||||
|
seg.header().rst = true;
|
||||||
|
_segments_out.push(seg);
|
||||||
|
}
|
||||||
|
|
||||||
|
//!\brief Set connection to Dead State
|
||||||
|
void _set_rst() {
|
||||||
|
_sender.stream_in().set_error();
|
||||||
|
_receiver.stream_out().set_error();
|
||||||
|
_active = false;
|
||||||
|
}
|
||||||
|
//!@}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//! \name "Input" interface for the writer
|
//! \name "Input" interface for the writer
|
||||||
//!@{
|
//!@{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user