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