forked from vikshanker/sponge
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfsm_ack_rst_relaxed.cc
150 lines (117 loc) · 5.84 KB
/
fsm_ack_rst_relaxed.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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#include "tcp_config.hh"
#include "tcp_expectation.hh"
#include "tcp_fsm_test_harness.hh"
#include "tcp_header.hh"
#include "tcp_segment.hh"
#include <cstdint>
#include <cstdlib>
#include <exception>
#include <iostream>
using namespace std;
using State = TCPTestHarness::State;
// in LISTEN, send ACK
static void ack_listen_test(const TCPConfig &cfg,
const WrappingInt32 seqno,
const WrappingInt32 ackno,
const int lineno) {
try {
TCPTestHarness test = TCPTestHarness::in_listen(cfg);
// any ACK should result in a RST
test.send_ack(seqno, ackno);
test.execute(ExpectState{State::LISTEN});
test.execute(ExpectNoSegment{}, "test 3 failed: ACKs in LISTEN should be ignored");
} catch (const exception &e) {
throw runtime_error(string(e.what()) + " (ack_listen_test called from line " + to_string(lineno) + ")");
}
}
// in SYN_SENT, send ACK and maybe RST
static void ack_rst_syn_sent_test(const TCPConfig &cfg,
const WrappingInt32 base_seq,
const WrappingInt32 seqno,
const WrappingInt32 ackno,
const int lineno) {
try {
TCPTestHarness test = TCPTestHarness::in_syn_sent(cfg, base_seq);
// unacceptable ACKs should be ignored
test.send_ack(seqno, ackno);
test.execute(ExpectState{State::SYN_SENT});
test.execute(ExpectNoSegment{}, "test 3 failed: bad ACKs in SYN_SENT should be ignored");
} catch (const exception &e) {
throw runtime_error(string(e.what()) + " (ack_rst_syn_sent_test called from line " + to_string(lineno) + ")");
}
}
int main() {
try {
TCPConfig cfg{};
const WrappingInt32 base_seq(1 << 31);
// test #1: in ESTABLISHED, send unacceptable segments and ACKs
{
cerr << "Test 1" << endl;
TCPTestHarness test_1 = TCPTestHarness::in_established(cfg, base_seq - 1, base_seq - 1);
// acceptable ack---no response
test_1.send_ack(base_seq, base_seq);
test_1.execute(ExpectNoSegment{}, "test 1 failed: ACK after acceptable ACK");
// ack in the past---no response
test_1.send_ack(base_seq, base_seq - 1);
test_1.execute(ExpectNoSegment{}, "test 1 failed: ACK after past ACK");
/* remove requirement for corrective ACKs
// ack in the future---should get ACK back
test_1.send_ack(base_seq, base_seq + 1);
test_1.execute(ExpectOneSegment{}.with_ack(true).with_ackno(base_seq), "test 1 failed: bad ACK");
*/
// segment out of the window---should get an ACK
test_1.send_byte(base_seq - 1, base_seq, 1);
test_1.execute(ExpectUnassembledBytes{0}, "test 1 failed: seg queued on early seqno");
test_1.execute(ExpectOneSegment{}.with_ack(true).with_ackno(base_seq), "test 1 failed: bad ACK");
// segment out of the window---should get an ACK
test_1.send_byte(base_seq + cfg.recv_capacity, base_seq, 1);
test_1.execute(ExpectUnassembledBytes{0}, "test 1 failed: seg queued on late seqno");
test_1.execute(ExpectOneSegment{}.with_ack(true).with_ackno(base_seq),
"test 1 failed: bad ACK on late seqno");
// packet next byte in the window - ack should advance and data should be readable
test_1.send_byte(base_seq, base_seq, 1);
test_1.execute(ExpectData{}, "test 1 failed: pkt not processed on next seqno");
test_1.execute(ExpectOneSegment{}.with_ack(true).with_ackno(base_seq + 1), "test 1 failed: bad ACK");
test_1.send_rst(base_seq + 1);
test_1.execute(ExpectState{State::RESET});
}
// test #2: in LISTEN, send RSTs
{
cerr << "Test 2" << endl;
TCPTestHarness test_2 = TCPTestHarness::in_listen(cfg);
// all RSTs should be ignored in LISTEN
test_2.send_rst(base_seq);
test_2.send_rst(base_seq - 1);
test_2.send_rst(base_seq + cfg.recv_capacity);
test_2.execute(ExpectNoSegment{}, "test 2 failed: RST was not ignored in LISTEN");
}
// test 3: ACKs in LISTEN
cerr << "Test 3" << endl;
ack_listen_test(cfg, base_seq, base_seq, __LINE__);
ack_listen_test(cfg, base_seq - 1, base_seq, __LINE__);
ack_listen_test(cfg, base_seq, base_seq - 1, __LINE__);
ack_listen_test(cfg, base_seq - 1, base_seq, __LINE__);
ack_listen_test(cfg, base_seq - 1, base_seq - 1, __LINE__);
ack_listen_test(cfg, base_seq + cfg.recv_capacity, base_seq, __LINE__);
ack_listen_test(cfg, base_seq, base_seq + cfg.recv_capacity, __LINE__);
ack_listen_test(cfg, base_seq + cfg.recv_capacity, base_seq, __LINE__);
ack_listen_test(cfg, base_seq + cfg.recv_capacity, base_seq + cfg.recv_capacity, __LINE__);
// test 4: ACK and RST in SYN_SENT
{
cerr << "Test 4" << endl;
TCPTestHarness test_4 = TCPTestHarness::in_syn_sent(cfg, base_seq);
// good ACK with RST should result in a RESET but no RST segment sent
test_4.send_rst(base_seq, base_seq + 1);
test_4.execute(ExpectState{State::RESET});
test_4.execute(ExpectNoSegment{}, "test 4 failed: RST with good ackno should RESET the connection");
}
// test 5: ack/rst in SYN_SENT
cerr << "Test 5" << endl;
ack_rst_syn_sent_test(cfg, base_seq, base_seq, base_seq, __LINE__);
ack_rst_syn_sent_test(cfg, base_seq, base_seq, base_seq + 2, __LINE__);
} catch (const exception &e) {
cerr << e.what() << endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}