xref: /nrf52832-nimble/rt-thread/components/net/lwip-2.1.0/test/sockets/sockets_stresstest.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /**
2*10465441SEvalZero  * @file
3*10465441SEvalZero  * Sockets stresstest
4*10465441SEvalZero  *
5*10465441SEvalZero  * This file uses the lwIP socket API to do stress tests that should test the
6*10465441SEvalZero  * stability when used in many different situations, with many concurrent
7*10465441SEvalZero  * sockets making concurrent transfers in different manners.
8*10465441SEvalZero  *
9*10465441SEvalZero  * - test rely on loopback sockets for now, so netif drivers are not tested
10*10465441SEvalZero  * - all enabled functions shall be used
11*10465441SEvalZero  * - parallelism of the tests depend on enough resources being available
12*10465441SEvalZero  *   (configure your lwipopts.h settings high enough)
13*10465441SEvalZero  * - test should also be able to run in a real target
14*10465441SEvalZero  *
15*10465441SEvalZero  * TODO:
16*10465441SEvalZero  * - full duplex
17*10465441SEvalZero  * - add asserts about internal socket/netconn/pcb state?
18*10465441SEvalZero  */
19*10465441SEvalZero 
20*10465441SEvalZero  /*
21*10465441SEvalZero  * Copyright (c) 2017 Simon Goldschmidt
22*10465441SEvalZero  * All rights reserved.
23*10465441SEvalZero  *
24*10465441SEvalZero  * Redistribution and use in source and binary forms, with or without modification,
25*10465441SEvalZero  * are permitted provided that the following conditions are met:
26*10465441SEvalZero  *
27*10465441SEvalZero  * 1. Redistributions of source code must retain the above copyright notice,
28*10465441SEvalZero  *    this list of conditions and the following disclaimer.
29*10465441SEvalZero  * 2. Redistributions in binary form must reproduce the above copyright notice,
30*10465441SEvalZero  *    this list of conditions and the following disclaimer in the documentation
31*10465441SEvalZero  *    and/or other materials provided with the distribution.
32*10465441SEvalZero  * 3. The name of the author may not be used to endorse or promote products
33*10465441SEvalZero  *    derived from this software without specific prior written permission.
34*10465441SEvalZero  *
35*10465441SEvalZero  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
36*10465441SEvalZero  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
37*10465441SEvalZero  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
38*10465441SEvalZero  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
39*10465441SEvalZero  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
40*10465441SEvalZero  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
41*10465441SEvalZero  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
42*10465441SEvalZero  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
43*10465441SEvalZero  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
44*10465441SEvalZero  * OF SUCH DAMAGE.
45*10465441SEvalZero  *
46*10465441SEvalZero  * This file is part of the lwIP TCP/IP stack.
47*10465441SEvalZero  *
48*10465441SEvalZero  * Author: Simon Goldschmidt <[email protected]>
49*10465441SEvalZero  *
50*10465441SEvalZero  */
51*10465441SEvalZero 
52*10465441SEvalZero #include "lwip/opt.h"
53*10465441SEvalZero #include "sockets_stresstest.h"
54*10465441SEvalZero 
55*10465441SEvalZero #include "lwip/sockets.h"
56*10465441SEvalZero #include "lwip/sys.h"
57*10465441SEvalZero 
58*10465441SEvalZero #include "lwip/mem.h"
59*10465441SEvalZero 
60*10465441SEvalZero #include <stdio.h>
61*10465441SEvalZero #include <string.h>
62*10465441SEvalZero 
63*10465441SEvalZero #if LWIP_SOCKET && LWIP_IPV4 /* this uses IPv4 loopback sockets, currently */
64*10465441SEvalZero 
65*10465441SEvalZero #ifndef TEST_SOCKETS_STRESS
66*10465441SEvalZero #define TEST_SOCKETS_STRESS   LWIP_DBG_OFF
67*10465441SEvalZero #endif
68*10465441SEvalZero 
69*10465441SEvalZero #define TEST_TIME_SECONDS     10
70*10465441SEvalZero #define TEST_TXRX_BUFSIZE     (TCP_MSS * 2)
71*10465441SEvalZero #define TEST_MAX_RXWAIT_MS    50
72*10465441SEvalZero #define TEST_MAX_CONNECTIONS  50
73*10465441SEvalZero 
74*10465441SEvalZero #define TEST_SOCK_READABLE    0x01
75*10465441SEvalZero #define TEST_SOCK_WRITABLE    0x02
76*10465441SEvalZero #define TEST_SOCK_ERR         0x04
77*10465441SEvalZero 
78*10465441SEvalZero #define TEST_MODE_SELECT      0x01
79*10465441SEvalZero #define TEST_MODE_POLL        0x02
80*10465441SEvalZero #define TEST_MODE_NONBLOCKING 0x04
81*10465441SEvalZero #define TEST_MODE_WAIT        0x08
82*10465441SEvalZero #define TEST_MODE_RECVTIMEO   0x10
83*10465441SEvalZero #define TEST_MODE_SLEEP       0x20
84*10465441SEvalZero 
85*10465441SEvalZero static int sockets_stresstest_numthreads;
86*10465441SEvalZero 
87*10465441SEvalZero struct test_settings {
88*10465441SEvalZero   struct sockaddr_storage addr;
89*10465441SEvalZero   int start_client;
90*10465441SEvalZero   int loop_cnt;
91*10465441SEvalZero };
92*10465441SEvalZero 
93*10465441SEvalZero struct sockets_stresstest_fullduplex {
94*10465441SEvalZero   int s;
95*10465441SEvalZero   volatile int closed;
96*10465441SEvalZero };
97*10465441SEvalZero 
98*10465441SEvalZero static void
fill_test_data(void * buf,size_t buf_len_bytes)99*10465441SEvalZero fill_test_data(void *buf, size_t buf_len_bytes)
100*10465441SEvalZero {
101*10465441SEvalZero   u8_t *p = (u8_t*)buf;
102*10465441SEvalZero   u16_t i, chk;
103*10465441SEvalZero 
104*10465441SEvalZero   LWIP_ASSERT("buffer too short", buf_len_bytes >= 4);
105*10465441SEvalZero   LWIP_ASSERT("buffer too big", buf_len_bytes <= 0xFFFF);
106*10465441SEvalZero   /* store the total number of bytes */
107*10465441SEvalZero   p[0] = (u8_t)(buf_len_bytes >> 8);
108*10465441SEvalZero   p[1] = (u8_t)buf_len_bytes;
109*10465441SEvalZero 
110*10465441SEvalZero   /* fill buffer with random */
111*10465441SEvalZero   chk = 0;
112*10465441SEvalZero   for (i = 4; i < buf_len_bytes; i++) {
113*10465441SEvalZero     u8_t rnd = (u8_t)LWIP_RAND();
114*10465441SEvalZero     p[i] = rnd;
115*10465441SEvalZero     chk += rnd;
116*10465441SEvalZero   }
117*10465441SEvalZero   /* store checksum */
118*10465441SEvalZero   p[2] = (u8_t)(chk >> 8);
119*10465441SEvalZero   p[3] = (u8_t)chk;
120*10465441SEvalZero }
121*10465441SEvalZero 
122*10465441SEvalZero static size_t
check_test_data(const void * buf,size_t buf_len_bytes)123*10465441SEvalZero check_test_data(const void *buf, size_t buf_len_bytes)
124*10465441SEvalZero {
125*10465441SEvalZero   u8_t *p = (u8_t*)buf;
126*10465441SEvalZero   u16_t i, chk, chk_rx, len_rx;
127*10465441SEvalZero 
128*10465441SEvalZero   LWIP_ASSERT("buffer too short", buf_len_bytes >= 4);
129*10465441SEvalZero   len_rx = (((u16_t)p[0]) << 8) | p[1];
130*10465441SEvalZero   LWIP_ASSERT("len too short", len_rx >= 4);
131*10465441SEvalZero   if (len_rx > buf_len_bytes) {
132*10465441SEvalZero     /* not all data received in this segment */
133*10465441SEvalZero     LWIP_DEBUGF(TEST_SOCKETS_STRESS | LWIP_DBG_TRACE, ("check-\n"));
134*10465441SEvalZero     return buf_len_bytes;
135*10465441SEvalZero   }
136*10465441SEvalZero   chk_rx = (((u16_t)p[2]) << 8) | p[3];
137*10465441SEvalZero   /* calculate received checksum */
138*10465441SEvalZero   chk = 0;
139*10465441SEvalZero   for (i = 4; i < len_rx; i++) {
140*10465441SEvalZero     chk += p[i];
141*10465441SEvalZero   }
142*10465441SEvalZero   LWIP_ASSERT("invalid checksum", chk == chk_rx);
143*10465441SEvalZero   if (len_rx < buf_len_bytes) {
144*10465441SEvalZero     size_t data_left = buf_len_bytes - len_rx;
145*10465441SEvalZero     memmove(p, &p[len_rx], data_left);
146*10465441SEvalZero     return data_left;
147*10465441SEvalZero   }
148*10465441SEvalZero   /* if we come here, we received exactly one chunk
149*10465441SEvalZero      -> next offset is 0 */
150*10465441SEvalZero   return 0;
151*10465441SEvalZero }
152*10465441SEvalZero 
153*10465441SEvalZero static size_t
recv_and_check_data_return_offset(int s,char * rxbuf,size_t rxbufsize,size_t rxoff,int * closed,const char * dbg)154*10465441SEvalZero recv_and_check_data_return_offset(int s, char *rxbuf, size_t rxbufsize, size_t rxoff, int *closed, const char *dbg)
155*10465441SEvalZero {
156*10465441SEvalZero   ssize_t ret;
157*10465441SEvalZero 
158*10465441SEvalZero   ret = lwip_read(s, &rxbuf[rxoff], rxbufsize - rxoff);
159*10465441SEvalZero   if (ret == 0) {
160*10465441SEvalZero     *closed = 1;
161*10465441SEvalZero     return rxoff;
162*10465441SEvalZero   }
163*10465441SEvalZero   *closed = 0;
164*10465441SEvalZero   LWIP_DEBUGF(TEST_SOCKETS_STRESS | LWIP_DBG_TRACE, ("%s %d rx %d\n", dbg, s, (int)ret));
165*10465441SEvalZero   if (ret == -1) {
166*10465441SEvalZero     /* TODO: for this to work, 'errno' has to support multithreading... */
167*10465441SEvalZero     int err = errno;
168*10465441SEvalZero     if (err == ENOTCONN) {
169*10465441SEvalZero       *closed = 1;
170*10465441SEvalZero       return 0;
171*10465441SEvalZero     }
172*10465441SEvalZero     LWIP_ASSERT("err == 0", err == 0);
173*10465441SEvalZero   }
174*10465441SEvalZero   LWIP_ASSERT("ret > 0", ret > 0);
175*10465441SEvalZero   return check_test_data(rxbuf, rxoff + ret);
176*10465441SEvalZero }
177*10465441SEvalZero 
178*10465441SEvalZero #if LWIP_SOCKET_SELECT
179*10465441SEvalZero static int
sockets_stresstest_wait_readable_select(int s,int timeout_ms)180*10465441SEvalZero sockets_stresstest_wait_readable_select(int s, int timeout_ms)
181*10465441SEvalZero {
182*10465441SEvalZero   int ret;
183*10465441SEvalZero   struct timeval tv;
184*10465441SEvalZero   fd_set fs_r;
185*10465441SEvalZero   fd_set fs_w;
186*10465441SEvalZero   fd_set fs_e;
187*10465441SEvalZero 
188*10465441SEvalZero   FD_ZERO(&fs_r);
189*10465441SEvalZero   FD_ZERO(&fs_w);
190*10465441SEvalZero   FD_ZERO(&fs_e);
191*10465441SEvalZero 
192*10465441SEvalZero   FD_SET(s, &fs_r);
193*10465441SEvalZero   FD_SET(s, &fs_e);
194*10465441SEvalZero 
195*10465441SEvalZero   tv.tv_sec = timeout_ms / 1000;
196*10465441SEvalZero   tv.tv_usec = (timeout_ms - (tv.tv_sec * 1000)) * 1000;
197*10465441SEvalZero   ret = lwip_select(s + 1, &fs_r, &fs_w, &fs_e, &tv);
198*10465441SEvalZero   LWIP_ASSERT("select error", ret >= 0);
199*10465441SEvalZero   if (ret) {
200*10465441SEvalZero     /* convert poll flags to our flags */
201*10465441SEvalZero     ret = 0;
202*10465441SEvalZero     if (FD_ISSET(s, &fs_r)) {
203*10465441SEvalZero       ret |= TEST_SOCK_READABLE;
204*10465441SEvalZero     }
205*10465441SEvalZero     if (FD_ISSET(s, &fs_w)) {
206*10465441SEvalZero       ret |= TEST_SOCK_WRITABLE;
207*10465441SEvalZero     }
208*10465441SEvalZero     if (FD_ISSET(s, &fs_e)) {
209*10465441SEvalZero       ret |= TEST_SOCK_ERR;
210*10465441SEvalZero     }
211*10465441SEvalZero     return ret;
212*10465441SEvalZero   }
213*10465441SEvalZero   return 0;
214*10465441SEvalZero }
215*10465441SEvalZero #endif
216*10465441SEvalZero 
217*10465441SEvalZero #if LWIP_SOCKET_POLL
218*10465441SEvalZero static int
sockets_stresstest_wait_readable_poll(int s,int timeout_ms)219*10465441SEvalZero sockets_stresstest_wait_readable_poll(int s, int timeout_ms)
220*10465441SEvalZero {
221*10465441SEvalZero   int ret;
222*10465441SEvalZero   struct pollfd pfd;
223*10465441SEvalZero 
224*10465441SEvalZero   pfd.fd = s;
225*10465441SEvalZero   pfd.revents = 0;
226*10465441SEvalZero   pfd.events = POLLIN | POLLERR;
227*10465441SEvalZero 
228*10465441SEvalZero   ret = lwip_poll(&pfd, 1, timeout_ms);
229*10465441SEvalZero   if (ret) {
230*10465441SEvalZero     /* convert poll flags to our flags */
231*10465441SEvalZero     ret = 0;
232*10465441SEvalZero     if (pfd.revents & POLLIN) {
233*10465441SEvalZero       ret |= TEST_SOCK_READABLE;
234*10465441SEvalZero     }
235*10465441SEvalZero     if (pfd.revents & POLLOUT) {
236*10465441SEvalZero       ret |= TEST_SOCK_WRITABLE;
237*10465441SEvalZero     }
238*10465441SEvalZero     if (pfd.revents & POLLERR) {
239*10465441SEvalZero       ret |= TEST_SOCK_ERR;
240*10465441SEvalZero     }
241*10465441SEvalZero     return ret;
242*10465441SEvalZero   }
243*10465441SEvalZero   return 0;
244*10465441SEvalZero }
245*10465441SEvalZero #endif
246*10465441SEvalZero 
247*10465441SEvalZero #if LWIP_SO_RCVTIMEO
248*10465441SEvalZero static int
sockets_stresstest_wait_readable_recvtimeo(int s,int timeout_ms)249*10465441SEvalZero sockets_stresstest_wait_readable_recvtimeo(int s, int timeout_ms)
250*10465441SEvalZero {
251*10465441SEvalZero   int ret;
252*10465441SEvalZero   char buf;
253*10465441SEvalZero #if LWIP_SO_SNDRCVTIMEO_NONSTANDARD
254*10465441SEvalZero   int opt_on = timeout_ms;
255*10465441SEvalZero   int opt_off = 0;
256*10465441SEvalZero #else
257*10465441SEvalZero   struct timeval opt_on, opt_off;
258*10465441SEvalZero   opt_on.tv_sec = timeout_ms / 1000;
259*10465441SEvalZero   opt_on.tv_usec = (timeout_ms - (opt_on.tv_sec * 1000)) * 1000;
260*10465441SEvalZero   opt_off.tv_sec = 0;
261*10465441SEvalZero   opt_off.tv_usec = 0;
262*10465441SEvalZero #endif
263*10465441SEvalZero 
264*10465441SEvalZero   /* enable receive timeout */
265*10465441SEvalZero   ret = lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &opt_on, sizeof(opt_on));
266*10465441SEvalZero   LWIP_ASSERT("setsockopt error", ret == 0);
267*10465441SEvalZero 
268*10465441SEvalZero   /* peek for one byte with timeout */
269*10465441SEvalZero   ret = lwip_recv(s, &buf, 1, MSG_PEEK);
270*10465441SEvalZero 
271*10465441SEvalZero   /* disable receive timeout */
272*10465441SEvalZero   ret = lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &opt_off, sizeof(opt_off));
273*10465441SEvalZero   LWIP_ASSERT("setsockopt error", ret == 0);
274*10465441SEvalZero 
275*10465441SEvalZero   if (ret == 1) {
276*10465441SEvalZero     return TEST_SOCK_READABLE;
277*10465441SEvalZero   }
278*10465441SEvalZero   if (ret == 0) {
279*10465441SEvalZero     return 0;
280*10465441SEvalZero   }
281*10465441SEvalZero   if (ret == -1) {
282*10465441SEvalZero     return TEST_SOCK_ERR;
283*10465441SEvalZero   }
284*10465441SEvalZero   LWIP_ASSERT("invalid return value", 0);
285*10465441SEvalZero   return TEST_SOCK_ERR;
286*10465441SEvalZero }
287*10465441SEvalZero #endif
288*10465441SEvalZero 
289*10465441SEvalZero static int
sockets_stresstest_wait_readable_wait_peek(int s,int timeout_ms)290*10465441SEvalZero sockets_stresstest_wait_readable_wait_peek(int s, int timeout_ms)
291*10465441SEvalZero {
292*10465441SEvalZero   int ret;
293*10465441SEvalZero   char buf;
294*10465441SEvalZero 
295*10465441SEvalZero   LWIP_UNUSED_ARG(timeout_ms); /* cannot time out here */
296*10465441SEvalZero 
297*10465441SEvalZero   /* peek for one byte */
298*10465441SEvalZero   ret = lwip_recv(s, &buf, 1, MSG_PEEK);
299*10465441SEvalZero 
300*10465441SEvalZero   if (ret == 1) {
301*10465441SEvalZero     return TEST_SOCK_READABLE;
302*10465441SEvalZero   }
303*10465441SEvalZero   if (ret == 0) {
304*10465441SEvalZero     return 0;
305*10465441SEvalZero   }
306*10465441SEvalZero   if (ret == -1) {
307*10465441SEvalZero     return TEST_SOCK_ERR;
308*10465441SEvalZero   }
309*10465441SEvalZero   LWIP_ASSERT("invalid return value", 0);
310*10465441SEvalZero   return TEST_SOCK_ERR;
311*10465441SEvalZero }
312*10465441SEvalZero 
313*10465441SEvalZero static int
sockets_stresstest_wait_readable_nonblock(int s,int timeout_ms)314*10465441SEvalZero sockets_stresstest_wait_readable_nonblock(int s, int timeout_ms)
315*10465441SEvalZero {
316*10465441SEvalZero   int ret;
317*10465441SEvalZero   char buf;
318*10465441SEvalZero   u32_t wait_until = sys_now() + timeout_ms;
319*10465441SEvalZero 
320*10465441SEvalZero   while(sys_now() < wait_until) {
321*10465441SEvalZero     /* peek for one byte */
322*10465441SEvalZero     ret = lwip_recv(s, &buf, 1, MSG_PEEK | MSG_DONTWAIT);
323*10465441SEvalZero 
324*10465441SEvalZero     if (ret == 1) {
325*10465441SEvalZero       return TEST_SOCK_READABLE;
326*10465441SEvalZero     }
327*10465441SEvalZero     if (ret == -1) {
328*10465441SEvalZero       /* TODO: for this to work, 'errno' has to support multithreading... */
329*10465441SEvalZero       int err = errno;
330*10465441SEvalZero       if (err != EWOULDBLOCK) {
331*10465441SEvalZero         return TEST_SOCK_ERR;
332*10465441SEvalZero       }
333*10465441SEvalZero     }
334*10465441SEvalZero     /* TODO: sleep? */
335*10465441SEvalZero   }
336*10465441SEvalZero   return 0;
337*10465441SEvalZero }
338*10465441SEvalZero 
sockets_stresstest_rand_mode(int allow_wait,int allow_rx)339*10465441SEvalZero static int sockets_stresstest_rand_mode(int allow_wait, int allow_rx)
340*10465441SEvalZero {
341*10465441SEvalZero   u32_t random_value = LWIP_RAND();
342*10465441SEvalZero #if LWIP_SOCKET_SELECT
343*10465441SEvalZero   if (random_value & TEST_MODE_SELECT) {
344*10465441SEvalZero     return TEST_MODE_SELECT;
345*10465441SEvalZero   }
346*10465441SEvalZero #endif
347*10465441SEvalZero #if LWIP_SOCKET_POLL
348*10465441SEvalZero   if (random_value & TEST_MODE_POLL) {
349*10465441SEvalZero     return TEST_MODE_POLL;
350*10465441SEvalZero   }
351*10465441SEvalZero #endif
352*10465441SEvalZero   if (!allow_rx) {
353*10465441SEvalZero     return TEST_MODE_SLEEP;
354*10465441SEvalZero   }
355*10465441SEvalZero #if LWIP_SO_RCVTIMEO
356*10465441SEvalZero   if (random_value & TEST_MODE_RECVTIMEO) {
357*10465441SEvalZero     return TEST_MODE_RECVTIMEO;
358*10465441SEvalZero   }
359*10465441SEvalZero #endif
360*10465441SEvalZero   if (allow_wait) {
361*10465441SEvalZero     if (random_value & TEST_MODE_RECVTIMEO) {
362*10465441SEvalZero       return TEST_MODE_RECVTIMEO;
363*10465441SEvalZero     }
364*10465441SEvalZero   }
365*10465441SEvalZero   return TEST_MODE_NONBLOCKING;
366*10465441SEvalZero }
367*10465441SEvalZero 
368*10465441SEvalZero static int
sockets_stresstest_wait_readable(int mode,int s,int timeout_ms)369*10465441SEvalZero sockets_stresstest_wait_readable(int mode, int s, int timeout_ms)
370*10465441SEvalZero {
371*10465441SEvalZero   switch(mode)
372*10465441SEvalZero   {
373*10465441SEvalZero #if LWIP_SOCKET_SELECT
374*10465441SEvalZero   case TEST_MODE_SELECT:
375*10465441SEvalZero     return sockets_stresstest_wait_readable_select(s, timeout_ms);
376*10465441SEvalZero #endif
377*10465441SEvalZero #if LWIP_SOCKET_POLL
378*10465441SEvalZero   case TEST_MODE_POLL:
379*10465441SEvalZero     return sockets_stresstest_wait_readable_poll(s, timeout_ms);
380*10465441SEvalZero #endif
381*10465441SEvalZero #if LWIP_SO_RCVTIMEO
382*10465441SEvalZero   case TEST_MODE_RECVTIMEO:
383*10465441SEvalZero     return sockets_stresstest_wait_readable_recvtimeo(s, timeout_ms);
384*10465441SEvalZero #endif
385*10465441SEvalZero   case TEST_MODE_WAIT:
386*10465441SEvalZero     return sockets_stresstest_wait_readable_wait_peek(s, timeout_ms);
387*10465441SEvalZero   case TEST_MODE_NONBLOCKING:
388*10465441SEvalZero     return sockets_stresstest_wait_readable_nonblock(s, timeout_ms);
389*10465441SEvalZero   case TEST_MODE_SLEEP:
390*10465441SEvalZero     {
391*10465441SEvalZero       sys_msleep(timeout_ms);
392*10465441SEvalZero       return 1;
393*10465441SEvalZero     }
394*10465441SEvalZero   default:
395*10465441SEvalZero     LWIP_ASSERT("invalid mode", 0);
396*10465441SEvalZero     break;
397*10465441SEvalZero   }
398*10465441SEvalZero   return 0;
399*10465441SEvalZero }
400*10465441SEvalZero 
401*10465441SEvalZero #if LWIP_NETCONN_FULLDUPLEX
402*10465441SEvalZero static void
sockets_stresstest_conn_client_r(void * arg)403*10465441SEvalZero sockets_stresstest_conn_client_r(void *arg)
404*10465441SEvalZero {
405*10465441SEvalZero   struct sockets_stresstest_fullduplex *fd = (struct sockets_stresstest_fullduplex *)arg;
406*10465441SEvalZero   int s = fd->s;
407*10465441SEvalZero   size_t rxoff = 0;
408*10465441SEvalZero   char rxbuf[TEST_TXRX_BUFSIZE];
409*10465441SEvalZero 
410*10465441SEvalZero   while (1) {
411*10465441SEvalZero     int closed;
412*10465441SEvalZero     if (fd->closed) {
413*10465441SEvalZero       break;
414*10465441SEvalZero     }
415*10465441SEvalZero     rxoff = recv_and_check_data_return_offset(s, rxbuf, sizeof(rxbuf), rxoff, &closed, "cli");
416*10465441SEvalZero     if (fd->closed) {
417*10465441SEvalZero       break;
418*10465441SEvalZero     }
419*10465441SEvalZero     if (closed) {
420*10465441SEvalZero       lwip_close(s);
421*10465441SEvalZero       break;
422*10465441SEvalZero     }
423*10465441SEvalZero   }
424*10465441SEvalZero 
425*10465441SEvalZero   SYS_ARCH_DEC(sockets_stresstest_numthreads, 1);
426*10465441SEvalZero   LWIP_ASSERT("", sockets_stresstest_numthreads >= 0);
427*10465441SEvalZero }
428*10465441SEvalZero #endif
429*10465441SEvalZero 
430*10465441SEvalZero static void
sockets_stresstest_conn_client(void * arg)431*10465441SEvalZero sockets_stresstest_conn_client(void *arg)
432*10465441SEvalZero {
433*10465441SEvalZero   struct sockaddr_storage addr;
434*10465441SEvalZero   struct sockaddr_in *addr_in;
435*10465441SEvalZero   int s, ret;
436*10465441SEvalZero   char txbuf[TEST_TXRX_BUFSIZE];
437*10465441SEvalZero   char rxbuf[TEST_TXRX_BUFSIZE];
438*10465441SEvalZero   size_t rxoff = 0;
439*10465441SEvalZero   u32_t max_time = sys_now() + (TEST_TIME_SECONDS * 1000);
440*10465441SEvalZero   int do_rx = 1;
441*10465441SEvalZero   struct sockets_stresstest_fullduplex *data = NULL;
442*10465441SEvalZero 
443*10465441SEvalZero   memcpy(&addr, arg, sizeof(addr));
444*10465441SEvalZero   LWIP_ASSERT("", addr.ss_family == AF_INET);
445*10465441SEvalZero   addr_in = (struct sockaddr_in *)&addr;
446*10465441SEvalZero   addr_in->sin_addr.s_addr = inet_addr("127.0.0.1");
447*10465441SEvalZero 
448*10465441SEvalZero   /* sleep a random time between 1 and 2 seconds */
449*10465441SEvalZero   sys_msleep(1000 + (LWIP_RAND() % 1000));
450*10465441SEvalZero 
451*10465441SEvalZero   /* connect to the server */
452*10465441SEvalZero   s = lwip_socket(addr.ss_family, SOCK_STREAM, 0);
453*10465441SEvalZero   LWIP_ASSERT("s >= 0", s >= 0);
454*10465441SEvalZero 
455*10465441SEvalZero #if LWIP_NETCONN_FULLDUPLEX
456*10465441SEvalZero   if (LWIP_RAND() & 1) {
457*10465441SEvalZero     sys_thread_t t;
458*10465441SEvalZero     data = (struct sockets_stresstest_fullduplex*)mem_malloc(sizeof(struct sockets_stresstest_fullduplex));
459*10465441SEvalZero     LWIP_ASSERT("data != NULL", data != 0);
460*10465441SEvalZero     SYS_ARCH_INC(sockets_stresstest_numthreads, 1);
461*10465441SEvalZero     data->s = s;
462*10465441SEvalZero     data->closed = 0;
463*10465441SEvalZero     t = sys_thread_new("sockets_stresstest_conn_client_r", sockets_stresstest_conn_client_r, data, 0, 0);
464*10465441SEvalZero     LWIP_ASSERT("thread != NULL", t != 0);
465*10465441SEvalZero     do_rx = 0;
466*10465441SEvalZero   }
467*10465441SEvalZero #endif
468*10465441SEvalZero 
469*10465441SEvalZero   /* @todo: nonblocking connect? */
470*10465441SEvalZero   ret = lwip_connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_storage));
471*10465441SEvalZero   LWIP_ASSERT("ret == 0", ret == 0);
472*10465441SEvalZero 
473*10465441SEvalZero   while (sys_now() < max_time) {
474*10465441SEvalZero     int closed;
475*10465441SEvalZero     int mode = sockets_stresstest_rand_mode(0, do_rx);
476*10465441SEvalZero     int timeout_ms = LWIP_RAND() % TEST_MAX_RXWAIT_MS;
477*10465441SEvalZero     ret = sockets_stresstest_wait_readable(mode, s, timeout_ms);
478*10465441SEvalZero     if (ret) {
479*10465441SEvalZero       if (do_rx) {
480*10465441SEvalZero         /* read some */
481*10465441SEvalZero         LWIP_ASSERT("readable", ret == TEST_SOCK_READABLE);
482*10465441SEvalZero         rxoff = recv_and_check_data_return_offset(s, rxbuf, sizeof(rxbuf), rxoff, &closed, "cli");
483*10465441SEvalZero         LWIP_ASSERT("client got closed", !closed);
484*10465441SEvalZero       }
485*10465441SEvalZero     } else {
486*10465441SEvalZero       /* timeout, send some */
487*10465441SEvalZero       size_t send_len = (LWIP_RAND() % (sizeof(txbuf) - 4)) + 4;
488*10465441SEvalZero       fill_test_data(txbuf, send_len);
489*10465441SEvalZero       LWIP_DEBUGF(TEST_SOCKETS_STRESS | LWIP_DBG_TRACE, ("cli %d tx %d\n", s, (int)send_len));
490*10465441SEvalZero       ret = lwip_write(s, txbuf, send_len);
491*10465441SEvalZero       if (ret == -1) {
492*10465441SEvalZero         /* TODO: for this to work, 'errno' has to support multithreading... */
493*10465441SEvalZero         int err = errno;
494*10465441SEvalZero         LWIP_ASSERT("err == 0", err == 0);
495*10465441SEvalZero       }
496*10465441SEvalZero       LWIP_ASSERT("ret == send_len", ret == (int)send_len);
497*10465441SEvalZero     }
498*10465441SEvalZero   }
499*10465441SEvalZero   if (data) {
500*10465441SEvalZero     data->closed = 1;
501*10465441SEvalZero   }
502*10465441SEvalZero   ret = lwip_close(s);
503*10465441SEvalZero   LWIP_ASSERT("ret == 0", ret == 0);
504*10465441SEvalZero 
505*10465441SEvalZero   SYS_ARCH_DEC(sockets_stresstest_numthreads, 1);
506*10465441SEvalZero   LWIP_ASSERT("", sockets_stresstest_numthreads >= 0);
507*10465441SEvalZero }
508*10465441SEvalZero 
509*10465441SEvalZero static void
sockets_stresstest_conn_server(void * arg)510*10465441SEvalZero sockets_stresstest_conn_server(void *arg)
511*10465441SEvalZero {
512*10465441SEvalZero   int s, ret;
513*10465441SEvalZero   char txbuf[TEST_TXRX_BUFSIZE];
514*10465441SEvalZero   char rxbuf[TEST_TXRX_BUFSIZE];
515*10465441SEvalZero   size_t rxoff = 0;
516*10465441SEvalZero 
517*10465441SEvalZero   s = (int)arg;
518*10465441SEvalZero 
519*10465441SEvalZero   while (1) {
520*10465441SEvalZero     int closed;
521*10465441SEvalZero     int mode = sockets_stresstest_rand_mode(1, 1);
522*10465441SEvalZero     int timeout_ms = LWIP_RAND() % TEST_MAX_RXWAIT_MS;
523*10465441SEvalZero     ret = sockets_stresstest_wait_readable(mode, s, timeout_ms);
524*10465441SEvalZero     if (ret) {
525*10465441SEvalZero       if (ret & TEST_SOCK_ERR) {
526*10465441SEvalZero         /* closed? */
527*10465441SEvalZero         break;
528*10465441SEvalZero       }
529*10465441SEvalZero       /* read some */
530*10465441SEvalZero       LWIP_ASSERT("readable", ret == TEST_SOCK_READABLE);
531*10465441SEvalZero       rxoff = recv_and_check_data_return_offset(s, rxbuf, sizeof(rxbuf), rxoff, &closed, "srv");
532*10465441SEvalZero       if (closed) {
533*10465441SEvalZero         break;
534*10465441SEvalZero       }
535*10465441SEvalZero     } else {
536*10465441SEvalZero       /* timeout, send some */
537*10465441SEvalZero       size_t send_len = (LWIP_RAND() % (sizeof(txbuf) - 4)) + 4;
538*10465441SEvalZero       fill_test_data(txbuf, send_len);
539*10465441SEvalZero       LWIP_DEBUGF(TEST_SOCKETS_STRESS | LWIP_DBG_TRACE, ("srv %d tx %d\n", s, (int)send_len));
540*10465441SEvalZero       ret = lwip_write(s, txbuf, send_len);
541*10465441SEvalZero       if (ret == -1) {
542*10465441SEvalZero         /* TODO: for this to work, 'errno' has to support multithreading... */
543*10465441SEvalZero         int err = errno;
544*10465441SEvalZero         if (err == ECONNRESET) {
545*10465441SEvalZero           break;
546*10465441SEvalZero         }
547*10465441SEvalZero         if (err == ENOTCONN) {
548*10465441SEvalZero           break;
549*10465441SEvalZero         }
550*10465441SEvalZero         LWIP_ASSERT("unknown error", 0);
551*10465441SEvalZero       }
552*10465441SEvalZero       LWIP_ASSERT("ret == send_len", ret == (int)send_len);
553*10465441SEvalZero     }
554*10465441SEvalZero   }
555*10465441SEvalZero   ret = lwip_close(s);
556*10465441SEvalZero   LWIP_ASSERT("ret == 0", ret == 0);
557*10465441SEvalZero 
558*10465441SEvalZero   SYS_ARCH_DEC(sockets_stresstest_numthreads, 1);
559*10465441SEvalZero   LWIP_ASSERT("", sockets_stresstest_numthreads >= 0);
560*10465441SEvalZero }
561*10465441SEvalZero 
562*10465441SEvalZero static int
sockets_stresstest_start_clients(const struct sockaddr_storage * remote_addr)563*10465441SEvalZero sockets_stresstest_start_clients(const struct sockaddr_storage *remote_addr)
564*10465441SEvalZero {
565*10465441SEvalZero   /* limit the number of connections */
566*10465441SEvalZero   const int max_connections = LWIP_MIN(TEST_MAX_CONNECTIONS, MEMP_NUM_TCP_PCB/3);
567*10465441SEvalZero   int i;
568*10465441SEvalZero 
569*10465441SEvalZero   for (i = 0; i < max_connections; i++) {
570*10465441SEvalZero     sys_thread_t t;
571*10465441SEvalZero     SYS_ARCH_INC(sockets_stresstest_numthreads, 1);
572*10465441SEvalZero     t = sys_thread_new("sockets_stresstest_conn_client", sockets_stresstest_conn_client, (void*)remote_addr, 0, 0);
573*10465441SEvalZero     LWIP_ASSERT("thread != NULL", t != 0);
574*10465441SEvalZero   }
575*10465441SEvalZero   return max_connections;
576*10465441SEvalZero }
577*10465441SEvalZero 
578*10465441SEvalZero static void
sockets_stresstest_listener(void * arg)579*10465441SEvalZero sockets_stresstest_listener(void *arg)
580*10465441SEvalZero {
581*10465441SEvalZero   int slisten;
582*10465441SEvalZero   int ret;
583*10465441SEvalZero   struct sockaddr_storage addr;
584*10465441SEvalZero   socklen_t addr_len;
585*10465441SEvalZero   struct test_settings *settings = (struct test_settings *)arg;
586*10465441SEvalZero   int num_clients, num_servers = 0;
587*10465441SEvalZero 
588*10465441SEvalZero   slisten = lwip_socket(AF_INET, SOCK_STREAM, 0);
589*10465441SEvalZero   LWIP_ASSERT("slisten >= 0", slisten >= 0);
590*10465441SEvalZero 
591*10465441SEvalZero   memcpy(&addr, &settings->addr, sizeof(struct sockaddr_storage));
592*10465441SEvalZero   ret = lwip_bind(slisten, (struct sockaddr *)&addr, sizeof(addr));
593*10465441SEvalZero   LWIP_ASSERT("ret == 0", ret == 0);
594*10465441SEvalZero 
595*10465441SEvalZero   ret = lwip_listen(slisten, 0);
596*10465441SEvalZero   LWIP_ASSERT("ret == 0", ret == 0);
597*10465441SEvalZero 
598*10465441SEvalZero   addr_len = sizeof(addr);
599*10465441SEvalZero   ret = lwip_getsockname(slisten, (struct sockaddr *)&addr, &addr_len);
600*10465441SEvalZero   LWIP_ASSERT("ret == 0", ret == 0);
601*10465441SEvalZero 
602*10465441SEvalZero   num_clients = sockets_stresstest_start_clients(&addr);
603*10465441SEvalZero 
604*10465441SEvalZero   while (num_servers < num_clients) {
605*10465441SEvalZero     struct sockaddr_storage aclient;
606*10465441SEvalZero     socklen_t aclient_len = sizeof(aclient);
607*10465441SEvalZero     int sclient = lwip_accept(slisten, (struct sockaddr *)&aclient, &aclient_len);
608*10465441SEvalZero #if 1
609*10465441SEvalZero     /* using server threads */
610*10465441SEvalZero     {
611*10465441SEvalZero       sys_thread_t t;
612*10465441SEvalZero       SYS_ARCH_INC(sockets_stresstest_numthreads, 1);
613*10465441SEvalZero       num_servers++;
614*10465441SEvalZero       t = sys_thread_new("sockets_stresstest_conn_server", sockets_stresstest_conn_server, (void*)sclient, 0, 0);
615*10465441SEvalZero       LWIP_ASSERT("thread != NULL", t != 0);
616*10465441SEvalZero     }
617*10465441SEvalZero #else
618*10465441SEvalZero     /* using server select */
619*10465441SEvalZero #endif
620*10465441SEvalZero   }
621*10465441SEvalZero   LWIP_DEBUGF(TEST_SOCKETS_STRESS | LWIP_DBG_STATE, ("sockets_stresstest_listener: all %d connections established\n", num_clients));
622*10465441SEvalZero 
623*10465441SEvalZero   /* accepted all clients */
624*10465441SEvalZero   while (sockets_stresstest_numthreads > 0) {
625*10465441SEvalZero     sys_msleep(1);
626*10465441SEvalZero   }
627*10465441SEvalZero 
628*10465441SEvalZero   ret = lwip_close(slisten);
629*10465441SEvalZero   LWIP_ASSERT("ret == 0", ret == 0);
630*10465441SEvalZero 
631*10465441SEvalZero   LWIP_DEBUGF(TEST_SOCKETS_STRESS |LWIP_DBG_STATE, ("sockets_stresstest_listener: done\n"));
632*10465441SEvalZero }
633*10465441SEvalZero 
634*10465441SEvalZero static void
sockets_stresstest_listener_loop(void * arg)635*10465441SEvalZero sockets_stresstest_listener_loop(void *arg)
636*10465441SEvalZero {
637*10465441SEvalZero   int i;
638*10465441SEvalZero   struct test_settings *settings = (struct test_settings *)arg;
639*10465441SEvalZero 
640*10465441SEvalZero   if (settings->loop_cnt) {
641*10465441SEvalZero     for (i = 0; i < settings->loop_cnt; i++) {
642*10465441SEvalZero       LWIP_DEBUGF(TEST_SOCKETS_STRESS |LWIP_DBG_STATE, ("sockets_stresstest_listener_loop: iteration %d\n", i));
643*10465441SEvalZero       sockets_stresstest_listener(arg);
644*10465441SEvalZero       sys_msleep(2);
645*10465441SEvalZero     }
646*10465441SEvalZero     LWIP_DEBUGF(TEST_SOCKETS_STRESS |LWIP_DBG_STATE, ("sockets_stresstest_listener_loop: done\n"));
647*10465441SEvalZero   } else {
648*10465441SEvalZero     for (i = 0; ; i++) {
649*10465441SEvalZero       LWIP_DEBUGF(TEST_SOCKETS_STRESS |LWIP_DBG_STATE, ("sockets_stresstest_listener_loop: iteration %d\n", i));
650*10465441SEvalZero       sockets_stresstest_listener(arg);
651*10465441SEvalZero       sys_msleep(2);
652*10465441SEvalZero     }
653*10465441SEvalZero   }
654*10465441SEvalZero }
655*10465441SEvalZero 
656*10465441SEvalZero void
sockets_stresstest_init_loopback(int addr_family)657*10465441SEvalZero sockets_stresstest_init_loopback(int addr_family)
658*10465441SEvalZero {
659*10465441SEvalZero   sys_thread_t t;
660*10465441SEvalZero   struct test_settings *settings = (struct test_settings *)mem_malloc(sizeof(struct test_settings));
661*10465441SEvalZero 
662*10465441SEvalZero   LWIP_ASSERT("OOM", settings != NULL);
663*10465441SEvalZero   memset(settings, 0, sizeof(struct test_settings));
664*10465441SEvalZero #if LWIP_IPV4 && LWIP_IPV6
665*10465441SEvalZero   LWIP_ASSERT("invalid addr_family", (addr_family == AF_INET) || (addr_family == AF_INET6));
666*10465441SEvalZero #endif
667*10465441SEvalZero   settings->addr.ss_family = (sa_family_t)addr_family;
668*10465441SEvalZero   LWIP_UNUSED_ARG(addr_family);
669*10465441SEvalZero   settings->start_client = 1;
670*10465441SEvalZero 
671*10465441SEvalZero   t = sys_thread_new("sockets_stresstest_listener_loop", sockets_stresstest_listener_loop, settings, 0, 0);
672*10465441SEvalZero   LWIP_ASSERT("thread != NULL", t != 0);
673*10465441SEvalZero }
674*10465441SEvalZero 
675*10465441SEvalZero void
sockets_stresstest_init_server(int addr_family,u16_t server_port)676*10465441SEvalZero sockets_stresstest_init_server(int addr_family, u16_t server_port)
677*10465441SEvalZero {
678*10465441SEvalZero   sys_thread_t t;
679*10465441SEvalZero   struct test_settings *settings = (struct test_settings *)mem_malloc(sizeof(struct test_settings));
680*10465441SEvalZero 
681*10465441SEvalZero   LWIP_ASSERT("OOM", settings != NULL);
682*10465441SEvalZero   memset(settings, 0, sizeof(struct test_settings));
683*10465441SEvalZero #if LWIP_IPV4 && LWIP_IPV6
684*10465441SEvalZero   LWIP_ASSERT("invalid addr_family", (addr_family == AF_INET) || (addr_family == AF_INET6));
685*10465441SEvalZero   settings->addr.ss_family = (sa_family_t)addr_family;
686*10465441SEvalZero #endif
687*10465441SEvalZero   LWIP_UNUSED_ARG(addr_family);
688*10465441SEvalZero   ((struct sockaddr_in *)(&settings->addr))->sin_port = server_port;
689*10465441SEvalZero 
690*10465441SEvalZero   t = sys_thread_new("sockets_stresstest_listener", sockets_stresstest_listener, settings, 0, 0);
691*10465441SEvalZero   LWIP_ASSERT("thread != NULL", t != 0);
692*10465441SEvalZero }
693*10465441SEvalZero 
694*10465441SEvalZero void
sockets_stresstest_init_client(const char * remote_ip,u16_t remote_port)695*10465441SEvalZero sockets_stresstest_init_client(const char *remote_ip, u16_t remote_port)
696*10465441SEvalZero {
697*10465441SEvalZero #if LWIP_IPV4
698*10465441SEvalZero   ip4_addr_t ip4;
699*10465441SEvalZero #endif
700*10465441SEvalZero #if LWIP_IPV6
701*10465441SEvalZero   ip6_addr_t ip6;
702*10465441SEvalZero #endif
703*10465441SEvalZero   struct sockaddr_storage *addr = (struct sockaddr_storage *)mem_malloc(sizeof(struct sockaddr_storage));
704*10465441SEvalZero 
705*10465441SEvalZero   LWIP_ASSERT("OOM", addr != NULL);
706*10465441SEvalZero   memset(addr, 0, sizeof(struct test_settings));
707*10465441SEvalZero #if LWIP_IPV4
708*10465441SEvalZero   if (ip4addr_aton(remote_ip, &ip4)) {
709*10465441SEvalZero     addr->ss_family = AF_INET;
710*10465441SEvalZero     ((struct sockaddr_in *)addr)->sin_addr.s_addr = ip4_addr_get_u32(&ip4);
711*10465441SEvalZero   }
712*10465441SEvalZero #endif
713*10465441SEvalZero #if LWIP_IPV4 && LWIP_IPV6
714*10465441SEvalZero   else
715*10465441SEvalZero #endif
716*10465441SEvalZero #if LWIP_IPV6
717*10465441SEvalZero   if (ip6addr_aton(remote_ip, &ip6)) {
718*10465441SEvalZero     addr->ss_family = AF_INET6;
719*10465441SEvalZero     /* todo: copy ipv6 address */
720*10465441SEvalZero   }
721*10465441SEvalZero #endif
722*10465441SEvalZero   ((struct sockaddr_in *)addr)->sin_port = remote_port;
723*10465441SEvalZero   sockets_stresstest_start_clients(addr);
724*10465441SEvalZero }
725*10465441SEvalZero 
726*10465441SEvalZero #endif /* LWIP_SOCKET && LWIP_IPV4 */
727