diff --git a/include/tins/tcp_ip/data_tracker.h b/include/tins/tcp_ip/data_tracker.h index 07013e8..9736687 100644 --- a/include/tins/tcp_ip/data_tracker.h +++ b/include/tins/tcp_ip/data_tracker.h @@ -87,7 +87,30 @@ public: */ bool process_payload(uint32_t seq, payload_type payload); - /** + /** + * \brief Skip forward to a sequence number + * + * This allows to recover from packetloss, if we just do not see all packets of + * an original stream. This recovery can only sensibly triggered from the application + * layer. + * + * The method does nothing, if the sequence number is smaller or equal to the + * current number. + * + * This method is particularly useful to call from an out of order callback, if + * the application wants to skip forward to this out of order block. The application + * will then get the normal data callback! + * + * The method cleans the buffer from all no longer needed fragments. + * + * IMPORTANT: If you call this method with a sequence number that is not exactly a + * TCP fragment boundary, the flow will never recover from this. + * + * \param seq The seqeunce number to skip to. + */ + void advance_sequence(uint32_t seq); + + /** * Retrieves the current sequence number */ uint32_t sequence_number() const; diff --git a/include/tins/tcp_ip/flow.h b/include/tins/tcp_ip/flow.h index 3d90562..81c65f9 100644 --- a/include/tins/tcp_ip/flow.h +++ b/include/tins/tcp_ip/flow.h @@ -165,6 +165,24 @@ public: */ void process_packet(PDU& pdu); + /** + * \brief Skip forward to a sequence number + * + * This allows to recover from packet loss, if we just do not see all packets of + * an original stream. This recovery can only sensibly triggered from the application + * layer. + * + * This method is particularly useful to call from an out of order callback, if + * the application wants to skip forward to this out of order block. The application + * will then get the normal data callback! + * + * IMPORTANT: If you call this method with a sequence number that is not exactly a + * TCP fragment boundary, the flow will never recover from this. + * + * \param seq The sequence number to skip to. + */ + void advance_sequence(uint32_t seq); + /** * Indicates whether this flow uses IPv6 addresses */ diff --git a/src/tcp_ip/data_tracker.cpp b/src/tcp_ip/data_tracker.cpp index 0a5dcbc..8b922c4 100644 --- a/src/tcp_ip/data_tracker.cpp +++ b/src/tcp_ip/data_tracker.cpp @@ -108,6 +108,23 @@ bool DataTracker::process_payload(uint32_t seq, payload_type payload) { return added_some; } +void DataTracker::advance_sequence(uint32_t seq) { + if (seq_compare(seq, seq_number_) <= 0) { + return; + } + + for (auto it = buffered_payload_.begin(); it != buffered_payload_.end();) { + if (seq_compare(it->first, seq) <= 0) { + total_buffered_bytes_ -= it->second.size(); + it = buffered_payload_.erase(it); + } else { + it++; + } + } + + seq_number_ = seq; +} + uint32_t DataTracker::sequence_number() const { return seq_number_; } diff --git a/src/tcp_ip/flow.cpp b/src/tcp_ip/flow.cpp index 4d3cd76..2aeee4a 100644 --- a/src/tcp_ip/flow.cpp +++ b/src/tcp_ip/flow.cpp @@ -110,24 +110,27 @@ void Flow::process_packet(PDU& pdu) { } const uint32_t chunk_end = tcp->seq() + raw->payload_size(); const uint32_t current_seq = data_tracker_.sequence_number(); - // If the end of the chunk ends after our current sequence number, process it. - if (seq_compare(chunk_end, current_seq) >= 0) { - uint32_t seq = tcp->seq(); - // If we're going to buffer this and we have a buffering callback, execute it - if (seq > current_seq && on_out_of_order_callback_) { - on_out_of_order_callback_(*this, seq, raw->payload()); - } - if (data_tracker_.process_payload(seq, move(raw->payload()))) { - if (on_data_callback_) { - on_data_callback_(*this); - } + // If the end of the chunk ends before the current sequence number or + // if we're going to buffer this and we have a buffering callback, execute it + if (seq_compare(chunk_end, current_seq) < 0 || + seq_compare(tcp->seq(), current_seq) > 0){ + if (on_out_of_order_callback_) { + on_out_of_order_callback_(*this, tcp->seq(), raw->payload()); } } - else if (on_out_of_order_callback_) { - on_out_of_order_callback_(*this, tcp->seq(), raw->payload()); + + // can process either way, since it will abort immediately if not needed + if (data_tracker_.process_payload(tcp->seq(), move(raw->payload()))) { + if (on_data_callback_) { + on_data_callback_(*this); + } } } +void Flow::advance_sequence(uint32_t seq) { + data_tracker_.advance_sequence(seq); +} + void Flow::update_state(const TCP& tcp) { if ((tcp.flags() & TCP::FIN) != 0) { state_ = FIN_SENT;