source: mainline/uspace/srv/net/tcp/test/ucall.c

Last change on this file was 7c3fb9b, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Fix block comment formatting (ccheck).

  • Property mode set to 100644
File size: 9.0 KB
Line 
1/*
2 * Copyright (c) 2017 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <errno.h>
30#include <inet/endpoint.h>
31#include <io/log.h>
32#include <pcut/pcut.h>
33
34#include "../conn.h"
35#include "../rqueue.h"
36#include "../ucall.h"
37
38PCUT_INIT;
39
40PCUT_TEST_SUITE(ucall);
41
42static void test_cstate_change(tcp_conn_t *, void *, tcp_cstate_t);
43static void test_conns_establish(tcp_conn_t **, tcp_conn_t **);
44static void test_conns_tear_down(tcp_conn_t *, tcp_conn_t *);
45
46static tcp_rqueue_cb_t test_rqueue_cb = {
47 .seg_received = tcp_as_segment_arrived
48};
49
50static tcp_cb_t test_conn_cb = {
51 .cstate_change = test_cstate_change
52};
53
54static tcp_conn_status_t cconn_status;
55static tcp_conn_status_t sconn_status;
56
57static FIBRIL_MUTEX_INITIALIZE(cst_lock);
58static FIBRIL_CONDVAR_INITIALIZE(cst_cv);
59
60PCUT_TEST_BEFORE
61{
62 errno_t rc;
63
64 /* We will be calling functions that perform logging */
65 rc = log_init("test-tcp");
66 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
67
68 rc = tcp_conns_init();
69 PCUT_ASSERT_ERRNO_VAL(EOK, rc);
70
71 tcp_rqueue_init(&test_rqueue_cb);
72 tcp_rqueue_fibril_start();
73
74 /* Enable internal loopback */
75 tcp_conn_lb = tcp_lb_segment;
76}
77
78PCUT_TEST_AFTER
79{
80 tcp_rqueue_fini();
81 tcp_conns_fini();
82}
83
84/** Test creating a listening passive connection and then deleting it. */
85PCUT_TEST(listen_delete)
86{
87 tcp_conn_t *conn;
88 inet_ep2_t epp;
89 tcp_error_t trc;
90 tcp_conn_status_t cstatus;
91
92 inet_ep2_init(&epp);
93 inet_addr(&epp.local.addr, 127, 0, 0, 1);
94 epp.local.port = inet_port_user_lo;
95
96 conn = NULL;
97 trc = tcp_uc_open(&epp, ap_passive, tcp_open_nonblock, &conn);
98 PCUT_ASSERT_INT_EQUALS(TCP_EOK, trc);
99 PCUT_ASSERT_NOT_NULL(conn);
100
101 tcp_uc_status(conn, &cstatus);
102 PCUT_ASSERT_INT_EQUALS(st_listen, cstatus.cstate);
103
104 trc = tcp_uc_close(conn);
105 PCUT_ASSERT_INT_EQUALS(TCP_EOK, trc);
106 tcp_uc_delete(conn);
107}
108
109/** Test trying to connect to endpoint that sends RST back */
110PCUT_TEST(connect_rst)
111{
112 tcp_conn_t *conn;
113 inet_ep2_t epp;
114 tcp_error_t trc;
115
116 inet_ep2_init(&epp);
117 inet_addr(&epp.local.addr, 127, 0, 0, 1);
118 inet_addr(&epp.remote.addr, 127, 0, 0, 1);
119 epp.remote.port = inet_port_user_lo;
120
121 conn = NULL;
122 trc = tcp_uc_open(&epp, ap_active, 0, &conn);
123 PCUT_ASSERT_INT_EQUALS(TCP_ERESET, trc);
124 PCUT_ASSERT_NULL(conn);
125}
126
127/** Test establishing a connection */
128PCUT_TEST(conn_establish)
129{
130 tcp_conn_t *cconn, *sconn;
131
132 test_conns_establish(&cconn, &sconn);
133 test_conns_tear_down(cconn, sconn);
134}
135
136/** Test establishing and then closing down a connection first on one side,
137 * then on_the other.
138 */
139PCUT_TEST(conn_est_close_seq)
140{
141 tcp_conn_t *cconn, *sconn;
142 tcp_error_t trc;
143
144 log_msg(LOG_DEFAULT, LVL_NOTE, "conn_est_close_seq: establish");
145 /* Establish */
146 test_conns_establish(&cconn, &sconn);
147
148 log_msg(LOG_DEFAULT, LVL_NOTE, "conn_est_close_seq: close cconn");
149 /* Close client side */
150 trc = tcp_uc_close(cconn);
151 PCUT_ASSERT_INT_EQUALS(TCP_EOK, trc);
152
153 log_msg(LOG_DEFAULT, LVL_NOTE, "conn_est_close_seq: wait cconn = fin-wait-2");
154 /* Wait for cconn to go to Fin-Wait-2 */
155 fibril_mutex_lock(&cst_lock);
156 tcp_uc_status(cconn, &cconn_status);
157 while (cconn_status.cstate != st_fin_wait_2)
158 fibril_condvar_wait(&cst_cv, &cst_lock);
159 fibril_mutex_unlock(&cst_lock);
160
161 log_msg(LOG_DEFAULT, LVL_NOTE, "conn_est_close_seq: wait sconn = close-wait");
162 /* Wait for sconn to go to Close-Wait */
163 fibril_mutex_lock(&cst_lock);
164 tcp_uc_status(sconn, &sconn_status);
165 while (sconn_status.cstate != st_close_wait)
166 fibril_condvar_wait(&cst_cv, &cst_lock);
167 fibril_mutex_unlock(&cst_lock);
168
169 log_msg(LOG_DEFAULT, LVL_NOTE, "conn_est_close_seq: close sconn");
170 /* Close server side */
171 trc = tcp_uc_close(sconn);
172 PCUT_ASSERT_INT_EQUALS(TCP_EOK, trc);
173
174 log_msg(LOG_DEFAULT, LVL_NOTE, "conn_est_close_seq: wait cconn = time-wait");
175 /* Wait for cconn to go to Time-Wait */
176 fibril_mutex_lock(&cst_lock);
177 tcp_uc_status(cconn, &cconn_status);
178 while (cconn_status.cstate != st_time_wait)
179 fibril_condvar_wait(&cst_cv, &cst_lock);
180 fibril_mutex_unlock(&cst_lock);
181
182 log_msg(LOG_DEFAULT, LVL_NOTE, "conn_est_close_seq: wait sconn = closed");
183 /* Wait for sconn to go to Closed */
184 fibril_mutex_lock(&cst_lock);
185 tcp_uc_status(sconn, &sconn_status);
186 while (sconn_status.cstate != st_closed) {
187 log_msg(LOG_DEFAULT, LVL_NOTE, "conn_est_close_seq: sconn.status == %d", sconn_status.cstate);
188 fibril_condvar_wait(&cst_cv, &cst_lock);
189 }
190 fibril_mutex_unlock(&cst_lock);
191
192 log_msg(LOG_DEFAULT, LVL_NOTE, "conn_est_close_seq: tear down");
193 /* Tear down */
194 test_conns_tear_down(cconn, sconn);
195}
196
197/** Test establishing and then simultaneously closing down a connection. */
198PCUT_TEST(conn_est_close_simult)
199{
200 tcp_conn_t *cconn, *sconn;
201 tcp_error_t trc;
202
203 /* Establish */
204 test_conns_establish(&cconn, &sconn);
205
206 /* Close both sides simultaneously */
207 trc = tcp_uc_close(cconn);
208 PCUT_ASSERT_INT_EQUALS(TCP_EOK, trc);
209 trc = tcp_uc_close(sconn);
210 PCUT_ASSERT_INT_EQUALS(TCP_EOK, trc);
211
212 /* Wait for cconn to go to Time-Wait */
213 fibril_mutex_lock(&cst_lock);
214 tcp_uc_status(cconn, &cconn_status);
215 while (cconn_status.cstate != st_time_wait)
216 fibril_condvar_wait(&cst_cv, &cst_lock);
217 fibril_mutex_unlock(&cst_lock);
218
219 /*
220 * Wait for sconn to go to Closed or Time-Wait. The connection
221 * goes to Closed if we managed to call tcp_uc_close() before
222 * sconn received FIN. Otherwise it goes to Time-Wait.
223 *
224 * XXX We may want to add delay to the loopback here to be
225 * absolutely sure that we go to Closing -> Time-Wait.
226 */
227 fibril_mutex_lock(&cst_lock);
228 tcp_uc_status(sconn, &sconn_status);
229 while (sconn_status.cstate != st_time_wait &&
230 sconn_status.cstate != st_closed)
231 fibril_condvar_wait(&cst_cv, &cst_lock);
232 fibril_mutex_unlock(&cst_lock);
233
234 /* Tear down */
235 test_conns_tear_down(cconn, sconn);
236}
237
238static void test_cstate_change(tcp_conn_t *conn, void *arg,
239 tcp_cstate_t old_state)
240{
241 tcp_conn_status_t *status = (tcp_conn_status_t *)arg;
242
243 fibril_mutex_lock(&cst_lock);
244 tcp_uc_status(conn, status);
245 fibril_mutex_unlock(&cst_lock);
246 fibril_condvar_broadcast(&cst_cv);
247}
248
249/** Establish client-server connection */
250static void test_conns_establish(tcp_conn_t **rcconn, tcp_conn_t **rsconn)
251{
252 tcp_conn_t *cconn, *sconn;
253 inet_ep2_t cepp, sepp;
254 tcp_conn_status_t cstatus;
255 tcp_error_t trc;
256
257 /* Client EPP */
258 inet_ep2_init(&cepp);
259 inet_addr(&cepp.local.addr, 127, 0, 0, 1);
260 inet_addr(&cepp.remote.addr, 127, 0, 0, 1);
261 cepp.remote.port = inet_port_user_lo;
262
263 /* Server EPP */
264 inet_ep2_init(&sepp);
265 inet_addr(&sepp.local.addr, 127, 0, 0, 1);
266 sepp.local.port = inet_port_user_lo;
267
268 /* Server side of the connection */
269 sconn = NULL;
270 trc = tcp_uc_open(&sepp, ap_passive, tcp_open_nonblock, &sconn);
271 PCUT_ASSERT_INT_EQUALS(TCP_EOK, trc);
272 PCUT_ASSERT_NOT_NULL(sconn);
273
274 tcp_uc_set_cb(sconn, &test_conn_cb, &sconn_status);
275 PCUT_ASSERT_EQUALS(&sconn_status, tcp_uc_get_userptr(sconn));
276
277 tcp_uc_status(sconn, &cstatus);
278 PCUT_ASSERT_INT_EQUALS(st_listen, cstatus.cstate);
279
280 /* Client side of the connection */
281
282 cconn = NULL;
283 trc = tcp_uc_open(&cepp, ap_active, 0, &cconn);
284 PCUT_ASSERT_INT_EQUALS(TCP_EOK, trc);
285 PCUT_ASSERT_NOT_NULL(cconn);
286
287 tcp_uc_set_cb(cconn, &test_conn_cb, &cconn_status);
288 PCUT_ASSERT_EQUALS(&cconn_status, tcp_uc_get_userptr(cconn));
289
290 /* The client side of the connection should be established by now */
291
292 tcp_uc_status(cconn, &cstatus);
293 PCUT_ASSERT_INT_EQUALS(st_established, cstatus.cstate);
294
295 /* Need to wait for server side */
296
297 fibril_mutex_lock(&cst_lock);
298 tcp_uc_status(sconn, &sconn_status);
299 while (sconn_status.cstate != st_established)
300 fibril_condvar_wait(&cst_cv, &cst_lock);
301 fibril_mutex_unlock(&cst_lock);
302
303 *rcconn = cconn;
304 *rsconn = sconn;
305}
306
307/* Tear down client-server connection. */
308static void test_conns_tear_down(tcp_conn_t *cconn, tcp_conn_t *sconn)
309{
310 tcp_uc_abort(cconn);
311 tcp_uc_delete(cconn);
312
313 tcp_uc_abort(sconn);
314 tcp_uc_delete(sconn);
315}
316
317PCUT_EXPORT(ucall);
Note: See TracBrowser for help on using the repository browser.