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