Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sockets_stresstest.c Source File

sockets_stresstest.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * Sockets stresstest
00004  *
00005  * This file uses the lwIP socket API to do stress tests that should test the
00006  * stability when used in many different situations, with many concurrent
00007  * sockets making concurrent transfers in different manners.
00008  *
00009  * - test rely on loopback sockets for now, so netif drivers are not tested
00010  * - all enabled functions shall be used
00011  * - parallelism of the tests depend on enough resources being available
00012  *   (configure your lwipopts.h settings high enough)
00013  * - test should also be able to run in a real target
00014  *
00015  * TODO:
00016  * - full duplex
00017  * - add asserts about internal socket/netconn/pcb state?
00018  */
00019  
00020  /*
00021  * Copyright (c) 2017 Simon Goldschmidt
00022  * All rights reserved.
00023  * 
00024  * Redistribution and use in source and binary forms, with or without modification, 
00025  * are permitted provided that the following conditions are met:
00026  *
00027  * 1. Redistributions of source code must retain the above copyright notice,
00028  *    this list of conditions and the following disclaimer.
00029  * 2. Redistributions in binary form must reproduce the above copyright notice,
00030  *    this list of conditions and the following disclaimer in the documentation
00031  *    and/or other materials provided with the distribution.
00032  * 3. The name of the author may not be used to endorse or promote products
00033  *    derived from this software without specific prior written permission. 
00034  *
00035  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
00036  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
00037  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
00038  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00039  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
00040  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
00041  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
00042  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
00043  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
00044  * OF SUCH DAMAGE.
00045  *
00046  * This file is part of the lwIP TCP/IP stack.
00047  * 
00048  * Author: Simon Goldschmidt <goldsimon@gmx.de>
00049  *
00050  */
00051 
00052 #include "lwip/opt.h"
00053 #include "sockets_stresstest.h"
00054 
00055 #include "lwip/sockets.h"
00056 #include "lwip/sys.h"
00057 
00058 #include "lwip/mem.h"
00059 
00060 #include <stdio.h>
00061 #include <string.h>
00062 
00063 #if LWIP_SOCKET && LWIP_IPV4 /* this uses IPv4 loopback sockets, currently */
00064 
00065 #ifndef TEST_SOCKETS_STRESS
00066 #define TEST_SOCKETS_STRESS   LWIP_DBG_OFF
00067 #endif
00068 
00069 #define TEST_TIME_SECONDS     10
00070 #define TEST_TXRX_BUFSIZE     (TCP_MSS * 2)
00071 #define TEST_MAX_RXWAIT_MS    50
00072 #define TEST_MAX_CONNECTIONS  50
00073 
00074 #define TEST_SOCK_READABLE    0x01
00075 #define TEST_SOCK_WRITABLE    0x02
00076 #define TEST_SOCK_ERR         0x04
00077 
00078 #define TEST_MODE_SELECT      0x01
00079 #define TEST_MODE_POLL        0x02
00080 #define TEST_MODE_NONBLOCKING 0x04
00081 #define TEST_MODE_WAIT        0x08
00082 #define TEST_MODE_RECVTIMEO   0x10
00083 #define TEST_MODE_SLEEP       0x20
00084 
00085 static int sockets_stresstest_numthreads;
00086 
00087 struct test_settings {
00088   struct sockaddr_storage addr;
00089   int start_client;
00090   int loop_cnt;
00091 };
00092 
00093 struct sockets_stresstest_fullduplex {
00094   int s;
00095   volatile int closed;
00096 };
00097 
00098 static void
00099 fill_test_data(void *buf, size_t buf_len_bytes)
00100 {
00101   u8_t *p = (u8_t*)buf;
00102   u16_t i, chk;
00103 
00104   LWIP_ASSERT("buffer too short", buf_len_bytes >= 4);
00105   LWIP_ASSERT("buffer too big", buf_len_bytes <= 0xFFFF);
00106   /* store the total number of bytes */
00107   p[0] = (u8_t)(buf_len_bytes >> 8);
00108   p[1] = (u8_t)buf_len_bytes;
00109 
00110   /* fill buffer with random */
00111   chk = 0;
00112   for (i = 4; i < buf_len_bytes; i++) {
00113     u8_t rnd = (u8_t)LWIP_RAND();
00114     p[i] = rnd;
00115     chk += rnd;
00116   }
00117   /* store checksum */
00118   p[2] = (u8_t)(chk >> 8);
00119   p[3] = (u8_t)chk;
00120 }
00121 
00122 static size_t
00123 check_test_data(const void *buf, size_t buf_len_bytes)
00124 {
00125   u8_t *p = (u8_t*)buf;
00126   u16_t i, chk, chk_rx, len_rx;
00127 
00128   LWIP_ASSERT("buffer too short", buf_len_bytes >= 4);
00129   len_rx = (((u16_t)p[0]) << 8) | p[1];
00130   LWIP_ASSERT("len too short", len_rx >= 4);
00131   if (len_rx > buf_len_bytes) {
00132     /* not all data received in this segment */
00133     LWIP_DEBUGF(TEST_SOCKETS_STRESS | LWIP_DBG_TRACE, ("check-\n"));
00134     return buf_len_bytes;
00135   }
00136   chk_rx = (((u16_t)p[2]) << 8) | p[3];
00137   /* calculate received checksum */
00138   chk = 0;
00139   for (i = 4; i < len_rx; i++) {
00140     chk += p[i];
00141   }
00142   LWIP_ASSERT("invalid checksum", chk == chk_rx);
00143   if (len_rx < buf_len_bytes) {
00144     size_t data_left = buf_len_bytes - len_rx;
00145     memmove(p, &p[len_rx], data_left);
00146     return data_left;
00147   }
00148   /* if we come here, we received exactly one chunk
00149      -> next offset is 0 */
00150   return 0;
00151 }
00152 
00153 static size_t
00154 recv_and_check_data_return_offset(int s, char *rxbuf, size_t rxbufsize, size_t rxoff, int *closed, const char *dbg)
00155 {
00156   ssize_t ret;
00157 
00158   ret = lwip_read(s, &rxbuf[rxoff], rxbufsize - rxoff);
00159   if (ret == 0) {
00160     *closed = 1;
00161     return rxoff;
00162   }
00163   *closed = 0;
00164   LWIP_DEBUGF(TEST_SOCKETS_STRESS | LWIP_DBG_TRACE, ("%s %d rx %d\n", dbg, s, (int)ret));
00165   if (ret == -1) {
00166     /* TODO: for this to work, 'errno' has to support multithreading... */
00167     int err = errno;
00168     if (err == ENOTCONN) {
00169       *closed = 1;
00170       return 0;
00171     }
00172     LWIP_ASSERT("err == 0", err == 0);
00173   }
00174   LWIP_ASSERT("ret > 0", ret > 0);
00175   return check_test_data(rxbuf, rxoff + ret);
00176 }
00177 
00178 #if LWIP_SOCKET_SELECT
00179 static int
00180 sockets_stresstest_wait_readable_select(int s, int timeout_ms)
00181 {
00182   int ret;
00183   struct timeval tv;
00184   fd_set fs_r;
00185   fd_set fs_w;
00186   fd_set fs_e;
00187 
00188   FD_ZERO(&fs_r);
00189   FD_ZERO(&fs_w);
00190   FD_ZERO(&fs_e);
00191 
00192   FD_SET(s, &fs_r);
00193   FD_SET(s, &fs_e);
00194 
00195   tv.tv_sec = timeout_ms / 1000;
00196   tv.tv_usec = (timeout_ms - (tv.tv_sec * 1000)) * 1000;
00197   ret = lwip_select(s + 1, &fs_r, &fs_w, &fs_e, &tv);
00198   LWIP_ASSERT("select error", ret >= 0);
00199   if (ret) {
00200     /* convert poll flags to our flags */
00201     ret = 0;
00202     if (FD_ISSET(s, &fs_r)) {
00203       ret |= TEST_SOCK_READABLE;
00204     }
00205     if (FD_ISSET(s, &fs_w)) {
00206       ret |= TEST_SOCK_WRITABLE;
00207     }
00208     if (FD_ISSET(s, &fs_e)) {
00209       ret |= TEST_SOCK_ERR;
00210     }
00211     return ret;
00212   }
00213   return 0;
00214 }
00215 #endif
00216 
00217 #if LWIP_SOCKET_POLL
00218 static int
00219 sockets_stresstest_wait_readable_poll(int s, int timeout_ms)
00220 {
00221   int ret;
00222   struct pollfd pfd;
00223 
00224   pfd.fd = s;
00225   pfd.revents = 0;
00226   pfd.events = POLLIN | POLLERR;
00227 
00228   ret = lwip_poll(&pfd, 1, timeout_ms);
00229   if (ret) {
00230     /* convert poll flags to our flags */
00231     ret = 0;
00232     if (pfd.revents & POLLIN) {
00233       ret |= TEST_SOCK_READABLE;
00234     }
00235     if (pfd.revents & POLLOUT) {
00236       ret |= TEST_SOCK_WRITABLE;
00237     }
00238     if (pfd.revents & POLLERR) {
00239       ret |= TEST_SOCK_ERR;
00240     }
00241     return ret;
00242   }
00243   return 0;
00244 }
00245 #endif
00246 
00247 #if LWIP_SO_RCVTIMEO
00248 static int
00249 sockets_stresstest_wait_readable_recvtimeo(int s, int timeout_ms)
00250 {
00251   int ret;
00252   char buf;
00253 #if LWIP_SO_SNDRCVTIMEO_NONSTANDARD
00254   int opt_on = timeout_ms;
00255   int opt_off = 0;
00256 #else
00257   struct timeval opt_on, opt_off;
00258   opt_on.tv_sec = timeout_ms / 1000;
00259   opt_on.tv_usec = (timeout_ms - (opt_on.tv_sec * 1000)) * 1000;
00260   opt_off.tv_sec = 0;
00261   opt_off.tv_usec = 0;
00262 #endif
00263 
00264   /* enable receive timeout */
00265   ret = lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &opt_on, sizeof(opt_on));
00266   LWIP_ASSERT("setsockopt error", ret == 0);
00267 
00268   /* peek for one byte with timeout */
00269   ret = lwip_recv(s, &buf, 1, MSG_PEEK);
00270 
00271   /* disable receive timeout */
00272   ret = lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &opt_off, sizeof(opt_off));
00273   LWIP_ASSERT("setsockopt error", ret == 0);
00274 
00275   if (ret == 1) {
00276     return TEST_SOCK_READABLE;
00277   }
00278   if (ret == 0) {
00279     return 0;
00280   }
00281   if (ret == -1) {
00282     return TEST_SOCK_ERR;
00283   }
00284   LWIP_ASSERT("invalid return value", 0);
00285   return TEST_SOCK_ERR;
00286 }
00287 #endif
00288 
00289 static int
00290 sockets_stresstest_wait_readable_wait_peek(int s, int timeout_ms)
00291 {
00292   int ret;
00293   char buf;
00294 
00295   LWIP_UNUSED_ARG(timeout_ms); /* cannot time out here */
00296 
00297   /* peek for one byte */
00298   ret = lwip_recv(s, &buf, 1, MSG_PEEK);
00299 
00300   if (ret == 1) {
00301     return TEST_SOCK_READABLE;
00302   }
00303   if (ret == 0) {
00304     return 0;
00305   }
00306   if (ret == -1) {
00307     return TEST_SOCK_ERR;
00308   }
00309   LWIP_ASSERT("invalid return value", 0);
00310   return TEST_SOCK_ERR;
00311 }
00312 
00313 static int
00314 sockets_stresstest_wait_readable_nonblock(int s, int timeout_ms)
00315 {
00316   int ret;
00317   char buf;
00318   u32_t wait_until = sys_now() + timeout_ms;
00319 
00320   while(sys_now() < wait_until) {
00321     /* peek for one byte */
00322     ret = lwip_recv(s, &buf, 1, MSG_PEEK | MSG_DONTWAIT);
00323 
00324     if (ret == 1) {
00325       return TEST_SOCK_READABLE;
00326     }
00327     if (ret == -1) {
00328       /* TODO: for this to work, 'errno' has to support multithreading... */
00329       int err = errno;
00330       if (err != EWOULDBLOCK) {
00331         return TEST_SOCK_ERR;
00332       }
00333     }
00334     /* TODO: sleep? */
00335   }
00336   return 0;
00337 }
00338 
00339 static int sockets_stresstest_rand_mode(int allow_wait, int allow_rx)
00340 {
00341   u32_t random_value = LWIP_RAND();
00342 #if LWIP_SOCKET_SELECT
00343   if (random_value & TEST_MODE_SELECT) {
00344     return TEST_MODE_SELECT;
00345   }
00346 #endif
00347 #if LWIP_SOCKET_POLL
00348   if (random_value & TEST_MODE_POLL) {
00349     return TEST_MODE_POLL;
00350   }
00351 #endif
00352   if (!allow_rx) {
00353     return TEST_MODE_SLEEP;
00354   }
00355 #if LWIP_SO_RCVTIMEO
00356   if (random_value & TEST_MODE_RECVTIMEO) {
00357     return TEST_MODE_RECVTIMEO;
00358   }
00359 #endif
00360   if (allow_wait) {
00361     if (random_value & TEST_MODE_RECVTIMEO) {
00362       return TEST_MODE_RECVTIMEO;
00363     }
00364   }
00365   return TEST_MODE_NONBLOCKING;
00366 }
00367 
00368 static int
00369 sockets_stresstest_wait_readable(int mode, int s, int timeout_ms)
00370 {
00371   switch(mode)
00372   {
00373 #if LWIP_SOCKET_SELECT
00374   case TEST_MODE_SELECT:
00375     return sockets_stresstest_wait_readable_select(s, timeout_ms);
00376 #endif
00377 #if LWIP_SOCKET_POLL
00378   case TEST_MODE_POLL:
00379     return sockets_stresstest_wait_readable_poll(s, timeout_ms);
00380 #endif
00381 #if LWIP_SO_RCVTIMEO
00382   case TEST_MODE_RECVTIMEO:
00383     return sockets_stresstest_wait_readable_recvtimeo(s, timeout_ms);
00384 #endif
00385   case TEST_MODE_WAIT:
00386     return sockets_stresstest_wait_readable_wait_peek(s, timeout_ms);
00387   case TEST_MODE_NONBLOCKING:
00388     return sockets_stresstest_wait_readable_nonblock(s, timeout_ms);
00389   case TEST_MODE_SLEEP:
00390     {
00391       sys_msleep(timeout_ms);
00392       return 1;
00393     }
00394   default:
00395     LWIP_ASSERT("invalid mode", 0);
00396     break;
00397   }
00398   return 0;
00399 }
00400 
00401 #if LWIP_NETCONN_FULLDUPLEX
00402 static void
00403 sockets_stresstest_conn_client_r(void *arg)
00404 {
00405   struct sockets_stresstest_fullduplex *fd = (struct sockets_stresstest_fullduplex *)arg;
00406   int s = fd->s;
00407   size_t rxoff = 0;
00408   char rxbuf[TEST_TXRX_BUFSIZE];
00409 
00410   while (1) {
00411     int closed;
00412     if (fd->closed) {
00413       break;
00414     }
00415     rxoff = recv_and_check_data_return_offset(s, rxbuf, sizeof(rxbuf), rxoff, &closed, "cli");
00416     if (fd->closed) {
00417       break;
00418     }
00419     if (closed) {
00420       lwip_close(s);
00421       break;
00422     }
00423   }
00424 
00425   SYS_ARCH_DEC(sockets_stresstest_numthreads, 1);
00426   LWIP_ASSERT("", sockets_stresstest_numthreads >= 0);
00427 }
00428 #endif
00429 
00430 static void
00431 sockets_stresstest_conn_client(void *arg)
00432 {
00433   struct sockaddr_storage addr;
00434   struct sockaddr_in *addr_in;
00435   int s, ret;
00436   char txbuf[TEST_TXRX_BUFSIZE];
00437   char rxbuf[TEST_TXRX_BUFSIZE];
00438   size_t rxoff = 0;
00439   u32_t max_time = sys_now() + (TEST_TIME_SECONDS * 1000);
00440   int do_rx = 1;
00441   struct sockets_stresstest_fullduplex *data = NULL;
00442 
00443   memcpy(&addr, arg, sizeof(addr));
00444   LWIP_ASSERT("", addr.ss_family == AF_INET);
00445   addr_in = (struct sockaddr_in *)&addr;
00446   addr_in->sin_addr.s_addr = inet_addr("127.0.0.1");
00447 
00448   /* sleep a random time between 1 and 2 seconds */
00449   sys_msleep(1000 + (LWIP_RAND() % 1000));
00450 
00451   /* connect to the server */
00452   s = lwip_socket(addr.ss_family, SOCK_STREAM, 0);
00453   LWIP_ASSERT("s >= 0", s >= 0);
00454 
00455 #if LWIP_NETCONN_FULLDUPLEX
00456   if (LWIP_RAND() & 1) {
00457     sys_thread_t t;
00458     data = (struct sockets_stresstest_fullduplex*)mem_malloc(sizeof(struct sockets_stresstest_fullduplex));
00459     LWIP_ASSERT("data != NULL", data != 0);
00460     SYS_ARCH_INC(sockets_stresstest_numthreads, 1);
00461     data->s = s;
00462     data->closed = 0;
00463     t = sys_thread_new("sockets_stresstest_conn_client_r", sockets_stresstest_conn_client_r, data, 0, 0);
00464     LWIP_ASSERT("thread != NULL", t != 0);
00465     do_rx = 0;
00466   }
00467 #endif
00468 
00469   /* @todo: nonblocking connect? */
00470   ret = lwip_connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_storage));
00471   LWIP_ASSERT("ret == 0", ret == 0);
00472 
00473   while (sys_now() < max_time) {
00474     int closed;
00475     int mode = sockets_stresstest_rand_mode(0, do_rx);
00476     int timeout_ms = LWIP_RAND() % TEST_MAX_RXWAIT_MS;
00477     ret = sockets_stresstest_wait_readable(mode, s, timeout_ms);
00478     if (ret) {
00479       if (do_rx) {
00480         /* read some */
00481         LWIP_ASSERT("readable", ret == TEST_SOCK_READABLE);
00482         rxoff = recv_and_check_data_return_offset(s, rxbuf, sizeof(rxbuf), rxoff, &closed, "cli");
00483         LWIP_ASSERT("client got closed", !closed);
00484       }
00485     } else {
00486       /* timeout, send some */
00487       size_t send_len = (LWIP_RAND() % (sizeof(txbuf) - 4)) + 4;
00488       fill_test_data(txbuf, send_len);
00489       LWIP_DEBUGF(TEST_SOCKETS_STRESS | LWIP_DBG_TRACE, ("cli %d tx %d\n", s, (int)send_len));
00490       ret = lwip_write(s, txbuf, send_len);
00491       if (ret == -1) {
00492         /* TODO: for this to work, 'errno' has to support multithreading... */
00493         int err = errno;
00494         LWIP_ASSERT("err == 0", err == 0);
00495       }
00496       LWIP_ASSERT("ret == send_len", ret == (int)send_len);
00497     }
00498   }
00499   if (data) {
00500     data->closed = 1;
00501   }
00502   ret = lwip_close(s);
00503   LWIP_ASSERT("ret == 0", ret == 0);
00504 
00505   SYS_ARCH_DEC(sockets_stresstest_numthreads, 1);
00506   LWIP_ASSERT("", sockets_stresstest_numthreads >= 0);
00507 }
00508 
00509 static void
00510 sockets_stresstest_conn_server(void *arg)
00511 {
00512   int s, ret;
00513   char txbuf[TEST_TXRX_BUFSIZE];
00514   char rxbuf[TEST_TXRX_BUFSIZE];
00515   size_t rxoff = 0;
00516 
00517   s = (int)arg;
00518 
00519   while (1) {
00520     int closed;
00521     int mode = sockets_stresstest_rand_mode(1, 1);
00522     int timeout_ms = LWIP_RAND() % TEST_MAX_RXWAIT_MS;
00523     ret = sockets_stresstest_wait_readable(mode, s, timeout_ms);
00524     if (ret) {
00525       if (ret & TEST_SOCK_ERR) {
00526         /* closed? */
00527         break;
00528       }
00529       /* read some */
00530       LWIP_ASSERT("readable", ret == TEST_SOCK_READABLE);
00531       rxoff = recv_and_check_data_return_offset(s, rxbuf, sizeof(rxbuf), rxoff, &closed, "srv");
00532       if (closed) {
00533         break;
00534       }
00535     } else {
00536       /* timeout, send some */
00537       size_t send_len = (LWIP_RAND() % (sizeof(txbuf) - 4)) + 4;
00538       fill_test_data(txbuf, send_len);
00539       LWIP_DEBUGF(TEST_SOCKETS_STRESS | LWIP_DBG_TRACE, ("srv %d tx %d\n", s, (int)send_len));
00540       ret = lwip_write(s, txbuf, send_len);
00541       if (ret == -1) {
00542         /* TODO: for this to work, 'errno' has to support multithreading... */
00543         int err = errno;
00544         if (err == ECONNRESET) {
00545           break;
00546         }
00547         if (err == ENOTCONN) {
00548           break;
00549         }
00550         LWIP_ASSERT("unknown error", 0);
00551       }
00552       LWIP_ASSERT("ret == send_len", ret == (int)send_len);
00553     }
00554   }
00555   ret = lwip_close(s);
00556   LWIP_ASSERT("ret == 0", ret == 0);
00557 
00558   SYS_ARCH_DEC(sockets_stresstest_numthreads, 1);
00559   LWIP_ASSERT("", sockets_stresstest_numthreads >= 0);
00560 }
00561 
00562 static int
00563 sockets_stresstest_start_clients(const struct sockaddr_storage *remote_addr)
00564 {
00565   /* limit the number of connections */
00566   const int max_connections = LWIP_MIN(TEST_MAX_CONNECTIONS, MEMP_NUM_TCP_PCB/3);
00567   int i;
00568 
00569   for (i = 0; i < max_connections; i++) {
00570     sys_thread_t t;
00571     SYS_ARCH_INC(sockets_stresstest_numthreads, 1);
00572     t = sys_thread_new("sockets_stresstest_conn_client", sockets_stresstest_conn_client, (void*)remote_addr, 0, 0);
00573     LWIP_ASSERT("thread != NULL", t != 0);
00574   }
00575   return max_connections;
00576 }
00577 
00578 static void
00579 sockets_stresstest_listener(void *arg)
00580 {
00581   int slisten;
00582   int ret;
00583   struct sockaddr_storage addr;
00584   socklen_t addr_len;
00585   struct test_settings *settings = (struct test_settings *)arg;
00586   int num_clients, num_servers = 0;
00587 
00588   slisten = lwip_socket(AF_INET, SOCK_STREAM, 0);
00589   LWIP_ASSERT("slisten >= 0", slisten >= 0);
00590 
00591   memcpy(&addr, &settings->addr, sizeof(struct sockaddr_storage));
00592   ret = lwip_bind(slisten, (struct sockaddr *)&addr, sizeof(addr));
00593   LWIP_ASSERT("ret == 0", ret == 0);
00594 
00595   ret = lwip_listen(slisten, 0);
00596   LWIP_ASSERT("ret == 0", ret == 0);
00597 
00598   addr_len = sizeof(addr);
00599   ret = lwip_getsockname(slisten, (struct sockaddr *)&addr, &addr_len);
00600   LWIP_ASSERT("ret == 0", ret == 0);
00601 
00602   num_clients = sockets_stresstest_start_clients(&addr);
00603 
00604   while (num_servers < num_clients) {
00605     struct sockaddr_storage aclient;
00606     socklen_t aclient_len = sizeof(aclient);
00607     int sclient = lwip_accept(slisten, (struct sockaddr *)&aclient, &aclient_len);
00608 #if 1
00609     /* using server threads */
00610     {
00611       sys_thread_t t;
00612       SYS_ARCH_INC(sockets_stresstest_numthreads, 1);
00613       num_servers++;
00614       t = sys_thread_new("sockets_stresstest_conn_server", sockets_stresstest_conn_server, (void*)sclient, 0, 0);
00615       LWIP_ASSERT("thread != NULL", t != 0);
00616     }
00617 #else
00618     /* using server select */
00619 #endif
00620   }
00621   LWIP_DEBUGF(TEST_SOCKETS_STRESS | LWIP_DBG_STATE, ("sockets_stresstest_listener: all %d connections established\n", num_clients));
00622 
00623   /* accepted all clients */
00624   while (sockets_stresstest_numthreads > 0) {
00625     sys_msleep(1);
00626   }
00627 
00628   ret = lwip_close(slisten);
00629   LWIP_ASSERT("ret == 0", ret == 0);
00630 
00631   LWIP_DEBUGF(TEST_SOCKETS_STRESS |LWIP_DBG_STATE, ("sockets_stresstest_listener: done\n"));
00632 }
00633 
00634 static void
00635 sockets_stresstest_listener_loop(void *arg)
00636 {
00637   int i;
00638   struct test_settings *settings = (struct test_settings *)arg;
00639 
00640   if (settings->loop_cnt) {
00641     for (i = 0; i < settings->loop_cnt; i++) {
00642       LWIP_DEBUGF(TEST_SOCKETS_STRESS |LWIP_DBG_STATE, ("sockets_stresstest_listener_loop: iteration %d\n", i));
00643       sockets_stresstest_listener(arg);
00644       sys_msleep(2);
00645     }
00646     LWIP_DEBUGF(TEST_SOCKETS_STRESS |LWIP_DBG_STATE, ("sockets_stresstest_listener_loop: done\n"));
00647   } else {
00648     for (i = 0; ; i++) {
00649       LWIP_DEBUGF(TEST_SOCKETS_STRESS |LWIP_DBG_STATE, ("sockets_stresstest_listener_loop: iteration %d\n", i));
00650       sockets_stresstest_listener(arg);
00651       sys_msleep(2);
00652     }
00653   }
00654 }
00655 
00656 void
00657 sockets_stresstest_init_loopback(int addr_family)
00658 {
00659   sys_thread_t t;
00660   struct test_settings *settings = (struct test_settings *)mem_malloc(sizeof(struct test_settings));
00661 
00662   LWIP_ASSERT("OOM", settings != NULL);
00663   memset(settings, 0, sizeof(struct test_settings));
00664 #if LWIP_IPV4 && LWIP_IPV6
00665   LWIP_ASSERT("invalid addr_family", (addr_family == AF_INET) || (addr_family == AF_INET6));
00666 #endif
00667   settings->addr.ss_family = (sa_family_t)addr_family;
00668   LWIP_UNUSED_ARG(addr_family);
00669   settings->start_client = 1;
00670 
00671   t = sys_thread_new("sockets_stresstest_listener_loop", sockets_stresstest_listener_loop, settings, 0, 0);
00672   LWIP_ASSERT("thread != NULL", t != 0);
00673 }
00674 
00675 void
00676 sockets_stresstest_init_server(int addr_family, u16_t server_port)
00677 {
00678   sys_thread_t t;
00679   struct test_settings *settings = (struct test_settings *)mem_malloc(sizeof(struct test_settings));
00680 
00681   LWIP_ASSERT("OOM", settings != NULL);
00682   memset(settings, 0, sizeof(struct test_settings));
00683 #if LWIP_IPV4 && LWIP_IPV6
00684   LWIP_ASSERT("invalid addr_family", (addr_family == AF_INET) || (addr_family == AF_INET6));
00685   settings->addr.ss_family = (sa_family_t)addr_family;
00686 #endif
00687   LWIP_UNUSED_ARG(addr_family);
00688   ((struct sockaddr_in *)(&settings->addr))->sin_port = server_port;
00689 
00690   t = sys_thread_new("sockets_stresstest_listener", sockets_stresstest_listener, settings, 0, 0);
00691   LWIP_ASSERT("thread != NULL", t != 0);
00692 }
00693 
00694 void
00695 sockets_stresstest_init_client(const char *remote_ip, u16_t remote_port)
00696 {
00697 #if LWIP_IPV4
00698   ip4_addr_t ip4;
00699 #endif
00700 #if LWIP_IPV6
00701   ip6_addr_t ip6;
00702 #endif
00703   struct sockaddr_storage *addr = (struct sockaddr_storage *)mem_malloc(sizeof(struct sockaddr_storage));
00704 
00705   LWIP_ASSERT("OOM", addr != NULL);
00706   memset(addr, 0, sizeof(struct test_settings));
00707 #if LWIP_IPV4
00708   if (ip4addr_aton(remote_ip, &ip4)) {
00709     addr->ss_family = AF_INET;
00710     ((struct sockaddr_in *)addr)->sin_addr.s_addr = ip4_addr_get_u32(&ip4);
00711   }
00712 #endif
00713 #if LWIP_IPV4 && LWIP_IPV6
00714   else
00715 #endif
00716 #if LWIP_IPV6
00717   if (ip6addr_aton(remote_ip, &ip6)) {
00718     addr->ss_family = AF_INET6;
00719     /* todo: copy ipv6 address */
00720   }
00721 #endif
00722   ((struct sockaddr_in *)addr)->sin_port = remote_port;
00723   sockets_stresstest_start_clients(addr);
00724 }
00725 
00726 #endif /* LWIP_SOCKET && LWIP_IPV4 */