diff --git a/libsponge/tcp_receiver.cc b/libsponge/tcp_receiver.cc index 640f925..3a11f9c 100644 --- a/libsponge/tcp_receiver.cc +++ b/libsponge/tcp_receiver.cc @@ -10,8 +10,37 @@ void DUMMY_CODE(Targs &&.../* unused */) {} using namespace std; -void TCPReceiver::segment_received(const TCPSegment &seg) { DUMMY_CODE(seg); } +void TCPReceiver::segment_received(const TCPSegment &seg) { + if (seg.header().syn) { + _syn = true; + // there's no way to know whether connection has been established from bytestream status, + // so a special member is needed + _isn = seg.header().seqno; + } + if (!_syn) + return; // abandon packets before SYN + uint64_t checkpoint = stream_out().bytes_written() ? stream_out().bytes_written() - 1 : 0; + // special case for initial SYN + uint64_t abs_seqno = unwrap(seg.header().seqno, _isn, checkpoint); + // In your TCP implementation, you’ll use the index of the last reassembled byte as the checkpoint. + // So, the bytes_written-1 (Stream Indices) should be this value + // Watch out for the case when no bytes have been assembled + if (abs_seqno == 0 && !seg.header().syn) + return; + // assertion: when abs_seqno is 0, this packet must be syn + uint64_t index = abs_seqno - (abs_seqno ? 1 : 0); // special case for SYN&FIN + _reassembler.push_substring(seg.payload().copy(), index, seg.header().fin); + _abs_ackno = stream_out().bytes_written() + 1 + (stream_out().input_ended() ? 1 : 0); + _ackno = wrap(_abs_ackno, _isn); +} -optional TCPReceiver::ackno() const { return {}; } +optional TCPReceiver::ackno() const { + if (_syn) + return _ackno; + return {}; +} -size_t TCPReceiver::window_size() const { return {}; } +size_t TCPReceiver::window_size() const { + // capacity minus the number of bytes holding in the byte stream + return _capacity - stream_out().buffer_size(); +} diff --git a/libsponge/tcp_receiver.hh b/libsponge/tcp_receiver.hh index 5b92180..68d8d3c 100644 --- a/libsponge/tcp_receiver.hh +++ b/libsponge/tcp_receiver.hh @@ -19,9 +19,10 @@ class TCPReceiver { //! The maximum number of bytes we'll store. size_t _capacity; - WrappingInt32 _seqno{0}; + WrappingInt32 _isn{0}; WrappingInt32 _ackno{0}; - bool _is_start{}; + uint64_t _abs_ackno{0}; + bool _syn{}; public: //! \brief Construct a TCP receiver diff --git a/libsponge/wrapping_integers.cc b/libsponge/wrapping_integers.cc index f08e552..846e13b 100644 --- a/libsponge/wrapping_integers.cc +++ b/libsponge/wrapping_integers.cc @@ -47,4 +47,10 @@ uint64_t unwrap(WrappingInt32 n, WrappingInt32 isn, uint64_t checkpoint) { return tmp + MODULO; } } + // actually, here is a tricky edge case: + // what if two possible unwraps have the same distance to checkpoint? + // For example, when n=2^16,isn=0,checkpoint=2^32 + // I thought about this, and came up with a possible solution: + // Mathematically, it is a problem, but in TCP's case, it is okay in that + // it is impossible that window size reaches 2^16. }