forked from vikshanker/sponge
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfsm_retx_win.cc
131 lines (103 loc) · 4.86 KB
/
fsm_retx_win.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include "fsm_retx.hh"
#include "tcp_config.hh"
#include "util.hh"
#include <algorithm>
#include <cstdlib>
#include <iostream>
using namespace std;
using State = TCPTestHarness::State;
int main() {
try {
TCPConfig cfg{};
cfg.recv_capacity = 65000;
auto rd = get_random_generator();
// multiple segments with intervening ack
{
WrappingInt32 tx_ackno(rd());
TCPTestHarness test_2 = TCPTestHarness::in_established(cfg, tx_ackno - 1, tx_ackno - 1);
string d1 = "asdf";
string d2 = "qwer";
test_2.execute(Write{d1});
test_2.execute(Tick(1));
test_2.execute(Tick(20));
test_2.execute(Write{d2});
test_2.execute(Tick(1));
test_2.execute(ExpectSegmentAvailable{}, "test 2 failed: cannot read after write()s");
check_segment(test_2, d1, true, __LINE__);
check_segment(test_2, d2, false, __LINE__);
test_2.execute(Tick(cfg.rt_timeout - 23));
test_2.execute(ExpectNoSegment{}, "test 2 failed: re-tx too fast");
test_2.execute(Tick(4));
check_segment(test_2, d1, false, __LINE__);
test_2.execute(Tick(2 * cfg.rt_timeout - 2));
test_2.execute(ExpectNoSegment{}, "test 2 failed: re-tx too fast");
test_2.send_ack(tx_ackno, tx_ackno + 4); // make sure RTO timer restarts on successful ACK
test_2.execute(Tick(cfg.rt_timeout - 2));
test_2.execute(ExpectNoSegment{}, "test 2 failed: re-tx of 2nd seg after ack for 1st seg too fast");
test_2.execute(Tick(3));
check_segment(test_2, d2, false, __LINE__);
}
// multiple segments without intervening ack
{
WrappingInt32 tx_ackno(rd());
TCPTestHarness test_3 = TCPTestHarness::in_established(cfg, tx_ackno - 1, tx_ackno - 1);
string d1 = "asdf";
string d2 = "qwer";
test_3.execute(Write{d1});
test_3.execute(Tick(1));
test_3.execute(Tick(20));
test_3.execute(Write{d2});
test_3.execute(Tick(1));
test_3.execute(ExpectSegmentAvailable{}, "test 3 failed: cannot read after write()s");
check_segment(test_3, d1, true, __LINE__);
check_segment(test_3, d2, false, __LINE__);
test_3.execute(Tick(cfg.rt_timeout - 23));
test_3.execute(ExpectNoSegment{}, "test 3 failed: re-tx too fast");
test_3.execute(Tick(4));
check_segment(test_3, d1, false, __LINE__);
test_3.execute(Tick(2 * cfg.rt_timeout - 2));
test_3.execute(ExpectNoSegment{}, "test 3 failed: re-tx of 2nd seg too fast");
test_3.execute(Tick(3));
check_segment(test_3, d1, false, __LINE__);
}
// check that ACK of new data resets exponential backoff and restarts timer
auto backoff_test = [&](const unsigned int num_backoffs) {
WrappingInt32 tx_ackno(rd());
TCPTestHarness test_4 = TCPTestHarness::in_established(cfg, tx_ackno - 1, tx_ackno - 1);
string d1 = "asdf";
string d2 = "qwer";
test_4.execute(Write{d1});
test_4.execute(Tick(1));
test_4.execute(Tick(20));
test_4.execute(Write{d2});
test_4.execute(Tick(1));
test_4.execute(ExpectSegmentAvailable{}, "test 4 failed: cannot read after write()s");
check_segment(test_4, d1, true, __LINE__);
check_segment(test_4, d2, false, __LINE__);
test_4.execute(Tick(cfg.rt_timeout - 23));
test_4.execute(ExpectNoSegment{}, "test 4 failed: re-tx too fast");
test_4.execute(Tick(4));
check_segment(test_4, d1, false, __LINE__);
for (unsigned i = 1; i < num_backoffs; ++i) {
test_4.execute(Tick((cfg.rt_timeout << i) - i)); // exponentially increasing delay length
test_4.execute(ExpectNoSegment{}, "test 4 failed: re-tx too fast after timeout");
test_4.execute(Tick(i));
check_segment(test_4, d1, false, __LINE__);
}
test_4.send_ack(tx_ackno, tx_ackno + 4); // make sure RTO timer restarts on successful ACK
test_4.execute(Tick(cfg.rt_timeout - 2));
test_4.execute(ExpectNoSegment{},
"test 4 failed: re-tx of 2nd seg after ack for 1st seg too fast after " +
to_string(num_backoffs) + " backoffs");
test_4.execute(Tick(3));
check_segment(test_4, d2, false, __LINE__);
};
for (unsigned int i = 0; i < TCPConfig::MAX_RETX_ATTEMPTS; ++i) {
backoff_test(i);
}
} catch (const exception &e) {
cerr << e.what() << endl;
return 1;
}
return EXIT_SUCCESS;
}