From abe94ece524d43d69d05ba80da4b93501b192df5 Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Sat, 13 Feb 2016 22:45:11 -0800 Subject: [PATCH] Allow asking whether segment was acked --- include/tins/tcp_ip/ack_tracker.h | 8 ++++++++ include/tins/tcp_ip/flow.h | 12 ++++++++++++ src/tcp_ip/ack_tracker.cpp | 28 ++++++++++++++++++++++++++++ src/tcp_ip/flow.cpp | 11 +++++++++++ tests/src/tcp_ip.cpp | 14 +++++++++++++- 5 files changed, 72 insertions(+), 1 deletion(-) diff --git a/include/tins/tcp_ip/ack_tracker.h b/include/tins/tcp_ip/ack_tracker.h index ae5d873..4ff8c25 100644 --- a/include/tins/tcp_ip/ack_tracker.h +++ b/include/tins/tcp_ip/ack_tracker.h @@ -129,6 +129,14 @@ public: * \brief Retrieves all acked intervals by Selective ACKs */ const interval_set_type& acked_intervals() const; + + /** + * \brief Indicates whether the given segment has been already ACKed + * + * \param sequence_number The segment's sequence number + * \param length The segment's length + */ + bool is_segment_acked(uint32_t sequence_number, uint32_t length) const; private: void process_sack(const std::vector& sack); void cleanup_sacked_intervals(uint32_t old_ack, uint32_t new_ack); diff --git a/include/tins/tcp_ip/flow.h b/include/tins/tcp_ip/flow.h index 945ddf4..8b2845e 100644 --- a/include/tins/tcp_ip/flow.h +++ b/include/tins/tcp_ip/flow.h @@ -282,6 +282,18 @@ public: * \brief Indicates whether ACK number tracking is enabled */ bool ack_tracking_enabled() const; + + #ifdef HAVE_ACK_TRACKER + /** + * Retrieves the ACK tracker for this Flow (const) + */ + const AckTracker& ack_tracker() const; + + /** + * Retrieves the ACK tracker for this Flow + */ + AckTracker& ack_tracker(); + #endif // HAVE_ACK_TRACKER private: // Compress all flags into just one struct using bitfields struct flags { diff --git a/src/tcp_ip/ack_tracker.cpp b/src/tcp_ip/ack_tracker.cpp index 9cdd9ab..ba2c0bd 100644 --- a/src/tcp_ip/ack_tracker.cpp +++ b/src/tcp_ip/ack_tracker.cpp @@ -38,11 +38,23 @@ using std::vector; using std::numeric_limits; +using boost::icl::interval_bounds; +using boost::icl::contains; + using Tins::Internals::seq_compare; namespace Tins { namespace TCPIP { +uint32_t interval_end(const AckedRange::interval_type& interval) { + if (interval.bounds() == interval_bounds::right_open()) { + return interval.upper() - 1; + } + else { + return interval.upper(); + } +} + // AckedRange AckedRange::AckedRange(uint32_t first, uint32_t last) @@ -140,6 +152,22 @@ const AckTracker::interval_set_type& AckTracker::acked_intervals() const { return acked_intervals_; } +bool AckTracker::is_segment_acked(uint32_t sequence_number, uint32_t length) const { + if (length == 0) { + return true; + } + AckedRange range(sequence_number, sequence_number + length - 1); + while (range.has_next()) { + AckedRange::interval_type interval = range.next(); + const int comparison = seq_compare(interval_end(interval), ack_number_); + // Only check for SACKed intervals if the segment finishes after our ACK number + if (comparison >= 0 && !contains(acked_intervals_, interval)) { + return false; + } + } + return true; +} + } // TCPIP } // Tins diff --git a/src/tcp_ip/flow.cpp b/src/tcp_ip/flow.cpp index 15f79b5..01d8f81 100644 --- a/src/tcp_ip/flow.cpp +++ b/src/tcp_ip/flow.cpp @@ -319,6 +319,17 @@ bool Flow::ack_tracking_enabled() const { return flags_.ack_tracking; } +#ifdef HAVE_ACK_TRACKER +const AckTracker& Flow::ack_tracker() const { + return ack_tracker_; +} + +AckTracker& Flow::ack_tracker() { + return ack_tracker_; +} + +#endif // HAVE_ACK_TRACKER + } // TCPIP } // Tins diff --git a/tests/src/tcp_ip.cpp b/tests/src/tcp_ip.cpp index a0342f4..5863fb3 100644 --- a/tests/src/tcp_ip.cpp +++ b/tests/src/tcp_ip.cpp @@ -601,9 +601,14 @@ TEST_F(AckTrackerTest, AckedRange_WrapAround) { TEST_F(AckTrackerTest, AckingTcp1) { AckTracker tracker(0, false); - EXPECT_EQ(0, tracker.ack_number()); + EXPECT_EQ(0, tracker.ack_number()); tracker.process_packet(make_tcp_ack(100)); EXPECT_EQ(100, tracker.ack_number()); + EXPECT_TRUE(tracker.is_segment_acked(0, 10)); + EXPECT_TRUE(tracker.is_segment_acked(50, 10)); + EXPECT_TRUE(tracker.is_segment_acked(99, 1)); + EXPECT_FALSE(tracker.is_segment_acked(90, 20)); + EXPECT_FALSE(tracker.is_segment_acked(99, 2)); tracker.process_packet(make_tcp_ack(50)); EXPECT_EQ(100, tracker.ack_number()); tracker.process_packet(make_tcp_ack(150)); @@ -635,6 +640,9 @@ TEST_F(AckTrackerTest, AckingTcp_Sack1) { AckTracker tracker(0, true); tracker.process_packet(make_tcp_ack(0, make_pair(2, 5), make_pair(9, 11))); EXPECT_EQ(3 + 2, tracker.acked_intervals().size()); + EXPECT_TRUE(tracker.is_segment_acked(2, 3)); + EXPECT_TRUE(tracker.is_segment_acked(9, 2)); + EXPECT_FALSE(tracker.is_segment_acked(2, 9)); tracker.process_packet(make_tcp_ack(9)); EXPECT_EQ(1, tracker.acked_intervals().size()); @@ -652,6 +660,10 @@ TEST_F(AckTrackerTest, AckingTcp_Sack2) { make_pair(0, 10) )); EXPECT_EQ(3 + 10, tracker.acked_intervals().size()); + EXPECT_TRUE(tracker.is_segment_acked(maximum - 12, 2)); + EXPECT_TRUE(tracker.is_segment_acked(maximum - 2, 1)); + EXPECT_TRUE(tracker.is_segment_acked(2, 3)); + EXPECT_FALSE(tracker.is_segment_acked(maximum - 10, 10)); tracker.process_packet(make_tcp_ack(maximum - 2)); EXPECT_EQ(1 + 10, tracker.acked_intervals().size());