1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-23 10:45:57 +01:00

Allow asking whether segment was acked

This commit is contained in:
Matias Fontanini
2016-02-13 22:45:11 -08:00
parent 2498ebf7d6
commit abe94ece52
5 changed files with 72 additions and 1 deletions

View File

@@ -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<uint32_t>& sack);
void cleanup_sacked_intervals(uint32_t old_ack, uint32_t new_ack);

View File

@@ -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 {

View File

@@ -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

View File

@@ -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

View File

@@ -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());