Tools/NetTest - Move common test code
[tpg/acess2.git] / Tools / NetTest_Runner / test_tcp.c
1 /*
2  * Acess2 Network Stack Tester
3  * - By John Hodge (thePowersGang)
4  *
5  * test_tcp.c
6  * - Tests for the behavior of the "Transmission Control Protocol"
7  */
8 #include "test.h"
9 #include "tests.h"
10 #include "net.h"
11 #include "stack.h"
12 #include "arp.h"
13 #include "tcp.h"
14 #include <string.h>
15
16 #define TEST_TIMERS     0
17
18 static const int        ERX_TIMEOUT = 1000;     // Expect RX timeout (timeout=failure)
19 static const int        NRX_TIMEOUT = 250;      // Not expect RX timeout (timeout=success)
20 static const int        RETX_TIMEOUT = 1000;    // OS PARAM - Retransmit timeout
21 static const int        LOST_TIMEOUT = 1000;    // OS PARAM - Time before sending an ACK 
22 static const int        DACK_TIMEOUT = 500;     // OS PARAM - Timeout for delayed ACKs
23 static const size_t     DACK_BYTES = 4096;      // OS PARAM - Threshold for delayed ACKs
24
25 bool Test_TCP_Basic(void)
26 {
27         TEST_HEADER;
28
29         tTCPConn        testconn = {
30                 .IFNum = 0, .AF = 4,
31                 .RAddr = BLOB(TEST_IP),
32                 .LAddr = BLOB(HOST_IP),
33                 .RPort = 80,
34                 .LPort = 11200,
35                 .Window = 0x1000,
36                 .LSeq = 0x1000,
37                 .RSeq = 0,
38         };
39
40         const char testblob[] = "HelloWorld, this is some random testing data for TCP\xFF\x00\x66\x12\x12.";
41         const size_t    testblob_len = sizeof(testblob);
42
43         // TODO: Check checksum failures        
44
45         // 1. Test packets to closed port
46         // > RFC793 Pg.65
47         
48         // 1.1. Send SYN packet
49         TEST_STEP("1.1. Send SYN packet to CLOSED");
50         TCP_SendC(&testconn, TCP_SYN, testblob_len, testblob);
51         testconn.RSeq = 0;
52         testconn.LSeq += testblob_len;
53         // Expect RST,ACK with SEQ=0
54         TEST_ASSERT_rx();
55         TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_RST|TCP_ACK) );
56         TEST_ASSERT_REL(ofs, ==, rxlen);
57         
58         // 1.2. Send a SYN,ACK packet
59         TEST_STEP("1.2. Send SYN,ACK packet to CLOSED");
60         testconn.RSeq = 12345;
61         TCP_SendC(&testconn, TCP_SYN|TCP_ACK, 0, NULL);
62         // Expect a TCP_RST with SEQ=ACK
63         TEST_ASSERT_rx();
64         TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_RST) );
65         TEST_ASSERT_REL(ofs, ==, rxlen);
66         testconn.LSeq ++;
67         
68         // 1.3. Send a RST packet
69         TEST_STEP("1.2. Send RST packet to CLOSED");
70         TCP_SendC(&testconn, TCP_RST, 0, NULL);
71         // Expect nothing
72         TEST_ASSERT_no_rx();
73         testconn.LSeq ++;
74         
75         // 1.3. Send a RST,ACK packet
76         TCP_SendC(&testconn, TCP_RST|TCP_ACK, 0, NULL);
77         // Expect nothing
78         TEST_ASSERT_no_rx();
79         testconn.LSeq ++;
80
81         
82         // 2. Establishing connection with a server
83         testconn.RPort = 7;
84         testconn.LPort = 11239;
85         Stack_SendCommand("tcp_echo_server %i", testconn.RPort);
86
87         // >>> STATE: LISTEN
88
89         // 2.1. Send RST
90         TCP_SendC(&testconn, TCP_RST, 0, NULL);
91         // - Expect nothing
92         TEST_ASSERT_no_rx();
93         // 2.2. Send ACK
94         TCP_SendC(&testconn, TCP_ACK, 0, NULL);
95         // - Expect RST
96         TEST_ASSERT_rx();
97         TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_RST) );
98         TEST_ASSERT_REL(ofs, ==, rxlen);
99
100         // 2.3. Begin hanshake (SYN)
101         // TODO: Test "If the SYN bit is set, check the security."
102         TCP_SendC(&testconn, TCP_SYN, 0, NULL);
103         testconn.LSeq ++;
104         // - Expect SYN,ACK with ACK == SEQ+1
105         TEST_ASSERT_rx();
106         TCP_SkipCheck_Seq(true);
107         TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_SYN|TCP_ACK) );
108         testconn.RSeq = TCP_Pkt_GetSeq(rxlen, rxbuf, testconn.AF) + 1;
109
110         // >>> STATE: SYN-RECEIVED
111         // TODO: Test other transitions from SYN-RECEIVED
112         
113         // 2.4. Complete handshake, TCP ACK
114         TCP_SendC(&testconn, TCP_ACK, 0, NULL);
115         // - Expect nothing
116         TEST_ASSERT_no_rx();
117
118         // >>> STATE: ESTABLISHED
119         
120         // 2.5. Send data
121         TCP_SendC(&testconn, TCP_ACK|TCP_PSH, testblob_len, testblob);
122         testconn.LSeq += testblob_len;
123
124         // Expect echoed reponse with ACK
125         TEST_ASSERT_rx();
126         TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_ACK|TCP_PSH) );
127         TEST_ASSERT_REL( len, ==, testblob_len );
128         TEST_ASSERT( memcmp(rxbuf + ofs, testblob, testblob_len) == 0 );
129         testconn.RSeq += testblob_len;
130
131         // Send something short
132         const char testblob2[] = "test blob two.";
133         const size_t    testblob2_len = sizeof(testblob2);
134         TCP_SendC(&testconn, TCP_ACK|TCP_PSH, testblob2_len, testblob2);
135         testconn.LSeq += testblob2_len;
136         // Expect response with data and ACK
137         TEST_ASSERT_rx();
138         TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_ACK|TCP_PSH) );
139         TEST_ASSERT_REL( len, ==, testblob2_len );
140         TEST_ASSERT( memcmp(rxbuf + ofs, testblob2, testblob2_len) == 0 );
141         
142         // Wait for just under retransmit time, expecting nothing
143         #if TEST_TIMERS
144         TEST_ASSERT( 0 == Net_Receive(0, sizeof(rxbuf), rxbuf, RETX_TIMEOUT-100) );
145         // Now expect the previous message
146         TEST_ASSERT_rx();
147         TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_ACK|TCP_PSH) );
148         TEST_ASSERT_REL( len, ==, testblob2_len );
149         TEST_ASSERT( memcmp(rxbuf + ofs, testblob2, testblob2_len) == 0 );
150         #else
151         TEST_WARN("Not testing retransmit timer");
152         #endif
153         testconn.RSeq += testblob2_len;
154         
155         // Send explicit acknowledgement
156         TCP_SendC(&testconn, TCP_ACK, 0, NULL);
157         TEST_ASSERT_no_rx();
158         
159         // TODO: Test delayed ACKs (Timeout and data)
160         // > Requires inhibiting the server's echo response?
161         
162         // === Test out-of-order packets ===
163         testconn.LSeq += testblob2_len; // raise sequence number
164         TCP_SendC(&testconn, TCP_ACK|TCP_PSH, testblob_len, testblob);
165         // - previous data has not been sent, expect no response for ()
166         // TODO: Should this ACK be delayed?
167         //TEST_ASSERT_no_rx();
168         // - Expect an ACK of the highest received packet
169         testconn.LSeq -= testblob2_len;
170         TEST_ASSERT_rx();
171         TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_ACK) );
172         TEST_ASSERT_REL( len, ==, 0 );
173         // - Send missing data
174         TCP_SendC(&testconn, TCP_ACK, testblob2_len, testblob2);
175         testconn.LSeq += testblob_len+testblob2_len;    // raise sequence number
176         // - Expect echo response with all sent data
177         TEST_ASSERT_rx();
178         TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_ACK|TCP_PSH) );
179         TEST_ASSERT_REL( len, ==, testblob_len+testblob2_len );
180         TEST_ASSERT( memcmp(rxbuf + ofs, testblob2, testblob2_len) == 0 );
181         TEST_ASSERT( memcmp(rxbuf + ofs+testblob2_len, testblob, testblob_len) == 0 );
182         testconn.RSeq += len;
183         
184         // 2.6. Close connection (TCP FIN)
185         TCP_SendC(&testconn, TCP_ACK|TCP_FIN, 0, NULL);
186         testconn.LSeq ++;       // Empty = 1 byte
187         // Expect ACK? (Does Acess do delayed ACKs here?)
188         TEST_ASSERT_rx();
189         TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_ACK) );
190         TEST_ASSERT_REL( len, ==, 0 );
191         // >>> STATE: CLOSE WAIT
192         
193         // Expect FIN
194         TEST_ASSERT_rx();
195         TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_FIN) );
196         TEST_ASSERT_REL( len, ==, 0 );
197         
198         // >>> STATE: LAST-ACK
199
200         // 2.7 Send ACK of FIN
201         TCP_SendC(&testconn, TCP_ACK, 0, NULL);
202         // Expect no response
203         TEST_ASSERT_no_rx();
204         
205         // >>> STATE: CLOSED
206         
207         return true;
208 }
209
210 bool Test_TCP_int_OpenConnection(tTCPConn *Conn)
211 {
212         RX_HEADER;
213         // >> SYN
214         TCP_SendC(Conn, TCP_SYN, 0, NULL);
215         Conn->LSeq ++;
216         TEST_ASSERT_rx();
217         // << SYN|ACK (save remote sequence number)
218         TCP_SkipCheck_Seq(true);
219         TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, Conn, TCP_SYN|TCP_ACK) );
220         TEST_ASSERT_REL(len, ==, 0);
221         Conn->RSeq = TCP_Pkt_GetSeq(rxlen, rxbuf, Conn->AF) + 1;
222         // >> ACK
223         TCP_SendC(Conn, TCP_ACK, 0, NULL);
224         TEST_ASSERT_no_rx();
225         return true;
226 }
227
228 #if 0
229 bool Test_TCP_SYN_RECEIVED(void)
230 {
231         TEST_HEADER;
232         
233         // 1. Get into SYN-RECEIVED
234         TCP_SendC(&testconn, TCP_SYN, 0, NULL);
235         
236         // 2. Send various non-ACK packets
237         return false;
238 }
239 #endif
240
241 bool Test_TCP_Reset(void)
242 {
243         TEST_HEADER;
244         
245         tTCPConn        testconn = {
246                 .IFNum = 0,
247                 .AF = 4,
248                 .LAddr = BLOB(HOST_IP),
249                 .RAddr = BLOB(TEST_IP),
250                 .LPort = 44359,
251                 .RPort = 9,
252                 .LSeq = 0x600,
253                 .RSeq = 0x600,
254                 .Window = 128
255         };
256
257         Stack_SendCommand("tcp_echo_server %i", testconn.RPort);
258
259         // 1. Response in listen-based SYN-RECEIVED
260         // >> SYN
261         TCP_SendC(&testconn, TCP_SYN, 0, NULL);
262         testconn.LSeq ++;
263         // << SYN|ACK :: Now in SYN-RECEIVED
264         TEST_ASSERT_rx();
265         TCP_SkipCheck_Seq(true);
266         TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_SYN|TCP_ACK) );
267         TEST_ASSERT_REL(len, ==, 0);
268         testconn.RSeq = TCP_Pkt_GetSeq(rxlen, rxbuf, testconn.AF) + 1;
269         // >> RST (not ACK)
270         TCP_SendC(&testconn, TCP_RST, 0, NULL);
271         // << nothing (connection should now be dead)
272         TEST_ASSERT_no_rx();
273         // >> ACK (this should be to a closed conneciton, see LISTEN[ACK] above)
274         TCP_SendC(&testconn, TCP_ACK, 0, NULL);
275         // << RST
276         TEST_ASSERT_rx();
277         TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_RST) );
278         TEST_ASSERT_REL(len, ==, 0);
279         
280         // 2. Response in open-based SYN-RECEIVED? (What is that?)
281         TEST_WARN("TODO: RFC793 pg70 mentions OPEN-based SYN-RECEIVED");
282         
283         testconn.LPort += 1234;
284         // ESTABLISHED[RST] - RFC793:Pg70
285         // 2. Response in ESTABLISHED 
286         TEST_ASSERT( Test_TCP_int_OpenConnection(&testconn) );
287         // >> RST
288         TCP_SendC(&testconn, TCP_RST, 0, NULL);
289         // << no response, connection closed
290         TEST_ASSERT_no_rx();
291         // >> ACK (LISTEN[ACK])
292         TCP_SendC(&testconn, TCP_ACK, 0, NULL);
293         // << RST
294         TEST_ASSERT_rx();
295         TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_RST) );
296         TEST_ASSERT_REL(len, ==, 0);
297         
298         return true;
299 }
300
301 bool Test_TCP_WindowSizes(void)
302 {
303         TEST_HEADER;
304         tTCPConn        testconn = {
305                 .IFNum = 0,
306                 .AF = 4,
307                 .LAddr = BLOB(HOST_IP),
308                 .RAddr = BLOB(TEST_IP),
309                 .LPort = 44359,
310                 .RPort = 9,
311                 .LSeq = 0x600,
312                 .RSeq = 0x600,
313                 .Window = 128
314         };
315         char    testdata[152];
316         memset(testdata, 0xAB, sizeof(testdata));
317         
318         Stack_SendCommand("tcp_echo_server %i", testconn.RPort);
319         // > Open Connection
320         TEST_ASSERT( Test_TCP_int_OpenConnection(&testconn) );
321         
322         // 1. Test remote respecting our transmission window (>=1 byte)
323         // > Send more data than our RX window
324         TCP_SendC(&testconn, TCP_PSH, sizeof(testdata), testdata);
325         testconn.LSeq += sizeof(testdata);
326         // Expect our RX window back
327         TEST_ASSERT_rx();
328         TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_ACK|TCP_PSH) );
329         TEST_ASSERT_REL(len, ==, testconn.Window);
330         testconn.RSeq += len;
331         // > Send ACK and reduce window to 1 byte
332         testconn.Window = 1;
333         TCP_SendC(&testconn, TCP_ACK, 0, NULL);
334         testconn.LSeq += sizeof(testdata);
335         // > Expect 1 byte back
336         TEST_ASSERT_rx();
337         TEST_ASSERT( TCP_Pkt_CheckC(rxlen, rxbuf, &ofs, &len, &testconn, TCP_ACK|TCP_PSH) );
338         TEST_ASSERT_REL(len, ==, 1);
339         testconn.RSeq += len;
340         // 2. Test remote handling our window being 0 (should only send ACKs)
341         // 3. Test that remote drops data outside of its RX window
342         // 3.1. Ensure that data that wraps the end of the RX window is handled correctly
343         return false;
344 }

UCC git Repository :: git.ucc.asn.au