lwiperf.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841
  1. /**
  2. * @file
  3. * lwIP iPerf server implementation
  4. */
  5. /**
  6. * @defgroup iperf Iperf server
  7. * @ingroup apps
  8. *
  9. * This is a simple performance measuring client/server to check your bandwith using
  10. * iPerf2 on a PC as server/client.
  11. * It is currently a minimal implementation providing a TCP client/server only.
  12. *
  13. * @todo:
  14. * - implement UDP mode
  15. * - protect combined sessions handling (via 'related_master_state') against reallocation
  16. * (this is a pointer address, currently, so if the same memory is allocated again,
  17. * session pairs (tx/rx) can be confused on reallocation)
  18. */
  19. /*
  20. * Copyright (c) 2014 Simon Goldschmidt
  21. * All rights reserved.
  22. *
  23. * Redistribution and use in source and binary forms, with or without modification,
  24. * are permitted provided that the following conditions are met:
  25. *
  26. * 1. Redistributions of source code must retain the above copyright notice,
  27. * this list of conditions and the following disclaimer.
  28. * 2. Redistributions in binary form must reproduce the above copyright notice,
  29. * this list of conditions and the following disclaimer in the documentation
  30. * and/or other materials provided with the distribution.
  31. * 3. The name of the author may not be used to endorse or promote products
  32. * derived from this software without specific prior written permission.
  33. *
  34. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
  35. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  36. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
  37. * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  38. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
  39. * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  40. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  41. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  42. * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
  43. * OF SUCH DAMAGE.
  44. *
  45. * This file is part of the lwIP TCP/IP stack.
  46. *
  47. * Author: Simon Goldschmidt
  48. */
  49. #include "lwip/apps/lwiperf.h"
  50. #include "lwip/tcp.h"
  51. #include "lwip/sys.h"
  52. #include <string.h>
  53. /* Currently, only TCP is implemented */
  54. #if LWIP_TCP && LWIP_CALLBACK_API
  55. /** Specify the idle timeout (in seconds) after that the test fails */
  56. #ifndef LWIPERF_TCP_MAX_IDLE_SEC
  57. #define LWIPERF_TCP_MAX_IDLE_SEC 10U
  58. #endif
  59. #if LWIPERF_TCP_MAX_IDLE_SEC > 255
  60. #error LWIPERF_TCP_MAX_IDLE_SEC must fit into an u8_t
  61. #endif
  62. /** Change this if you don't want to lwiperf to listen to any IP version */
  63. #ifndef LWIPERF_SERVER_IP_TYPE
  64. #define LWIPERF_SERVER_IP_TYPE IPADDR_TYPE_ANY
  65. #endif
  66. /* File internal memory allocation (struct lwiperf_*): this defaults to
  67. the heap */
  68. #ifndef LWIPERF_ALLOC
  69. #define LWIPERF_ALLOC(type) mem_malloc(sizeof(type))
  70. #define LWIPERF_FREE(type, item) mem_free(item)
  71. #endif
  72. /** If this is 1, check that received data has the correct format */
  73. #ifndef LWIPERF_CHECK_RX_DATA
  74. #define LWIPERF_CHECK_RX_DATA 0
  75. #endif
  76. /** This is the Iperf settings struct sent from the client */
  77. typedef struct _lwiperf_settings {
  78. #define LWIPERF_FLAGS_ANSWER_TEST 0x80000000
  79. #define LWIPERF_FLAGS_ANSWER_NOW 0x00000001
  80. u32_t flags;
  81. u32_t num_threads; /* unused for now */
  82. u32_t remote_port;
  83. u32_t buffer_len; /* unused for now */
  84. u32_t win_band; /* TCP window / UDP rate: unused for now */
  85. u32_t amount; /* pos. value: bytes?; neg. values: time (unit is 10ms: 1/100 second) */
  86. } lwiperf_settings_t;
  87. /** Basic connection handle */
  88. struct _lwiperf_state_base;
  89. typedef struct _lwiperf_state_base lwiperf_state_base_t;
  90. struct _lwiperf_state_base {
  91. /* linked list */
  92. lwiperf_state_base_t *next;
  93. /* 1=tcp, 0=udp */
  94. u8_t tcp;
  95. /* 1=server, 0=client */
  96. u8_t server;
  97. /* master state used to abort sessions (e.g. listener, main client) */
  98. lwiperf_state_base_t *related_master_state;
  99. };
  100. /** Connection handle for a TCP iperf session */
  101. typedef struct _lwiperf_state_tcp {
  102. lwiperf_state_base_t base;
  103. struct tcp_pcb *server_pcb;
  104. struct tcp_pcb *conn_pcb;
  105. u32_t time_started;
  106. lwiperf_report_fn report_fn;
  107. void *report_arg;
  108. u8_t poll_count;
  109. u8_t next_num;
  110. /* 1=start server when client is closed */
  111. u8_t client_tradeoff_mode;
  112. u32_t bytes_transferred;
  113. lwiperf_settings_t settings;
  114. u8_t have_settings_buf;
  115. u8_t specific_remote;
  116. ip_addr_t remote_addr;
  117. } lwiperf_state_tcp_t;
  118. /** List of active iperf sessions */
  119. static lwiperf_state_base_t *lwiperf_all_connections;
  120. /** A const buffer to send from: we want to measure sending, not copying! */
  121. static const u8_t lwiperf_txbuf_const[1600] = {
  122. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  123. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  124. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  125. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  126. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  127. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  128. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  129. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  130. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  131. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  132. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  133. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  134. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  135. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  136. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  137. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  138. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  139. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  140. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  141. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  142. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  143. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  144. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  145. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  146. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  147. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  148. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  149. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  150. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  151. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  152. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  153. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  154. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  155. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  156. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  157. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  158. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  159. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  160. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  161. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  162. };
  163. static err_t lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb);
  164. static void lwiperf_tcp_err(void *arg, err_t err);
  165. static err_t lwiperf_start_tcp_server_impl(const ip_addr_t *local_addr, u16_t local_port,
  166. lwiperf_report_fn report_fn, void *report_arg,
  167. lwiperf_state_base_t *related_master_state, lwiperf_state_tcp_t **state);
  168. /** Add an iperf session to the 'active' list */
  169. static void
  170. lwiperf_list_add(lwiperf_state_base_t *item)
  171. {
  172. item->next = lwiperf_all_connections;
  173. lwiperf_all_connections = item;
  174. }
  175. /** Remove an iperf session from the 'active' list */
  176. static void
  177. lwiperf_list_remove(lwiperf_state_base_t *item)
  178. {
  179. lwiperf_state_base_t *prev = NULL;
  180. lwiperf_state_base_t *iter;
  181. for (iter = lwiperf_all_connections; iter != NULL; prev = iter, iter = iter->next) {
  182. if (iter == item) {
  183. if (prev == NULL) {
  184. lwiperf_all_connections = iter->next;
  185. } else {
  186. prev->next = iter->next;
  187. }
  188. /* @debug: ensure this item is listed only once */
  189. for (iter = iter->next; iter != NULL; iter = iter->next) {
  190. LWIP_ASSERT("duplicate entry", iter != item);
  191. }
  192. break;
  193. }
  194. }
  195. }
  196. static lwiperf_state_base_t *
  197. lwiperf_list_find(lwiperf_state_base_t *item)
  198. {
  199. lwiperf_state_base_t *iter;
  200. for (iter = lwiperf_all_connections; iter != NULL; iter = iter->next) {
  201. if (iter == item) {
  202. return item;
  203. }
  204. }
  205. return NULL;
  206. }
  207. /** Call the report function of an iperf tcp session */
  208. static void
  209. lwip_tcp_conn_report(lwiperf_state_tcp_t *conn, enum lwiperf_report_type report_type)
  210. {
  211. if ((conn != NULL) && (conn->report_fn != NULL)) {
  212. u32_t now, duration_ms, bandwidth_kbitpsec;
  213. now = sys_now();
  214. duration_ms = now - conn->time_started;
  215. if (duration_ms == 0) {
  216. bandwidth_kbitpsec = 0;
  217. } else {
  218. bandwidth_kbitpsec = (conn->bytes_transferred / duration_ms) * 8U;
  219. }
  220. conn->report_fn(conn->report_arg, report_type,
  221. &conn->conn_pcb->local_ip, conn->conn_pcb->local_port,
  222. &conn->conn_pcb->remote_ip, conn->conn_pcb->remote_port,
  223. conn->bytes_transferred, duration_ms, bandwidth_kbitpsec);
  224. }
  225. }
  226. /** Close an iperf tcp session */
  227. static void
  228. lwiperf_tcp_close(lwiperf_state_tcp_t *conn, enum lwiperf_report_type report_type)
  229. {
  230. err_t err;
  231. lwiperf_list_remove(&conn->base);
  232. lwip_tcp_conn_report(conn, report_type);
  233. if (conn->conn_pcb != NULL) {
  234. tcp_arg(conn->conn_pcb, NULL);
  235. tcp_poll(conn->conn_pcb, NULL, 0);
  236. tcp_sent(conn->conn_pcb, NULL);
  237. tcp_recv(conn->conn_pcb, NULL);
  238. tcp_err(conn->conn_pcb, NULL);
  239. err = tcp_close(conn->conn_pcb);
  240. if (err != ERR_OK) {
  241. /* don't want to wait for free memory here... */
  242. tcp_abort(conn->conn_pcb);
  243. }
  244. } else {
  245. /* no conn pcb, this is the listener pcb */
  246. err = tcp_close(conn->server_pcb);
  247. LWIP_ASSERT("error", err == ERR_OK);
  248. }
  249. LWIPERF_FREE(lwiperf_state_tcp_t, conn);
  250. }
  251. /** Try to send more data on an iperf tcp session */
  252. static err_t
  253. lwiperf_tcp_client_send_more(lwiperf_state_tcp_t *conn)
  254. {
  255. int send_more;
  256. err_t err;
  257. u16_t txlen;
  258. u16_t txlen_max;
  259. void *txptr;
  260. u8_t apiflags;
  261. LWIP_ASSERT("conn invalid", (conn != NULL) && conn->base.tcp && (conn->base.server == 0));
  262. do {
  263. send_more = 0;
  264. if (conn->settings.amount & PP_HTONL(0x80000000)) {
  265. /* this session is time-limited */
  266. u32_t now = sys_now();
  267. u32_t diff_ms = now - conn->time_started;
  268. u32_t time = (u32_t) - (s32_t)lwip_htonl(conn->settings.amount);
  269. u32_t time_ms = time * 10;
  270. if (diff_ms >= time_ms) {
  271. /* time specified by the client is over -> close the connection */
  272. lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT);
  273. return ERR_OK;
  274. }
  275. } else {
  276. /* this session is byte-limited */
  277. u32_t amount_bytes = lwip_htonl(conn->settings.amount);
  278. /* @todo: this can send up to 1*MSS more than requested... */
  279. if (amount_bytes >= conn->bytes_transferred) {
  280. /* all requested bytes transferred -> close the connection */
  281. lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT);
  282. return ERR_OK;
  283. }
  284. }
  285. if (conn->bytes_transferred < 24) {
  286. /* transmit the settings a first time */
  287. txptr = &((u8_t *)&conn->settings)[conn->bytes_transferred];
  288. txlen_max = (u16_t)(24 - conn->bytes_transferred);
  289. apiflags = TCP_WRITE_FLAG_COPY;
  290. } else if (conn->bytes_transferred < 48) {
  291. /* transmit the settings a second time */
  292. txptr = &((u8_t *)&conn->settings)[conn->bytes_transferred - 24];
  293. txlen_max = (u16_t)(48 - conn->bytes_transferred);
  294. apiflags = TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE;
  295. send_more = 1;
  296. } else {
  297. /* transmit data */
  298. /* @todo: every x bytes, transmit the settings again */
  299. txptr = LWIP_CONST_CAST(void *, &lwiperf_txbuf_const[conn->bytes_transferred % 10]);
  300. txlen_max = TCP_MSS;
  301. if (conn->bytes_transferred == 48) { /* @todo: fix this for intermediate settings, too */
  302. txlen_max = TCP_MSS - 24;
  303. }
  304. apiflags = 0; /* no copying needed */
  305. send_more = 1;
  306. }
  307. txlen = txlen_max;
  308. do {
  309. err = tcp_write(conn->conn_pcb, txptr, txlen, apiflags);
  310. if (err == ERR_MEM) {
  311. txlen /= 2;
  312. }
  313. } while ((err == ERR_MEM) && (txlen >= (TCP_MSS / 2)));
  314. if (err == ERR_OK) {
  315. conn->bytes_transferred += txlen;
  316. } else {
  317. send_more = 0;
  318. }
  319. } while (send_more);
  320. tcp_output(conn->conn_pcb);
  321. return ERR_OK;
  322. }
  323. /** TCP sent callback, try to send more data */
  324. static err_t
  325. lwiperf_tcp_client_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
  326. {
  327. lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg;
  328. /* @todo: check 'len' (e.g. to time ACK of all data)? for now, we just send more... */
  329. LWIP_ASSERT("invalid conn", conn->conn_pcb == tpcb);
  330. LWIP_UNUSED_ARG(tpcb);
  331. LWIP_UNUSED_ARG(len);
  332. conn->poll_count = 0;
  333. return lwiperf_tcp_client_send_more(conn);
  334. }
  335. /** TCP connected callback (active connection), send data now */
  336. static err_t
  337. lwiperf_tcp_client_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
  338. {
  339. lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg;
  340. LWIP_ASSERT("invalid conn", conn->conn_pcb == tpcb);
  341. LWIP_UNUSED_ARG(tpcb);
  342. if (err != ERR_OK) {
  343. lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE);
  344. return ERR_OK;
  345. }
  346. conn->poll_count = 0;
  347. conn->time_started = sys_now();
  348. return lwiperf_tcp_client_send_more(conn);
  349. }
  350. /** Start TCP connection back to the client (either parallel or after the
  351. * receive test has finished.
  352. */
  353. static err_t
  354. lwiperf_tx_start_impl(const ip_addr_t *remote_ip, u16_t remote_port, lwiperf_settings_t *settings, lwiperf_report_fn report_fn,
  355. void *report_arg, lwiperf_state_base_t *related_master_state, lwiperf_state_tcp_t **new_conn)
  356. {
  357. err_t err;
  358. lwiperf_state_tcp_t *client_conn;
  359. struct tcp_pcb *newpcb;
  360. ip_addr_t remote_addr;
  361. LWIP_ASSERT("remote_ip != NULL", remote_ip != NULL);
  362. LWIP_ASSERT("remote_ip != NULL", settings != NULL);
  363. LWIP_ASSERT("new_conn != NULL", new_conn != NULL);
  364. *new_conn = NULL;
  365. client_conn = (lwiperf_state_tcp_t *)LWIPERF_ALLOC(lwiperf_state_tcp_t);
  366. if (client_conn == NULL) {
  367. return ERR_MEM;
  368. }
  369. newpcb = tcp_new_ip_type(IP_GET_TYPE(remote_ip));
  370. if (newpcb == NULL) {
  371. LWIPERF_FREE(lwiperf_state_tcp_t, client_conn);
  372. return ERR_MEM;
  373. }
  374. memset(client_conn, 0, sizeof(lwiperf_state_tcp_t));
  375. client_conn->base.tcp = 1;
  376. client_conn->base.related_master_state = related_master_state;
  377. client_conn->conn_pcb = newpcb;
  378. client_conn->time_started = sys_now(); /* @todo: set this again on 'connected' */
  379. client_conn->report_fn = report_fn;
  380. client_conn->report_arg = report_arg;
  381. client_conn->next_num = 4; /* initial nr is '4' since the header has 24 byte */
  382. client_conn->bytes_transferred = 0;
  383. memcpy(&client_conn->settings, settings, sizeof(*settings));
  384. client_conn->have_settings_buf = 1;
  385. tcp_arg(newpcb, client_conn);
  386. tcp_sent(newpcb, lwiperf_tcp_client_sent);
  387. tcp_poll(newpcb, lwiperf_tcp_poll, 2U);
  388. tcp_err(newpcb, lwiperf_tcp_err);
  389. ip_addr_copy(remote_addr, *remote_ip);
  390. err = tcp_connect(newpcb, &remote_addr, remote_port, lwiperf_tcp_client_connected);
  391. if (err != ERR_OK) {
  392. lwiperf_tcp_close(client_conn, LWIPERF_TCP_ABORTED_LOCAL);
  393. return err;
  394. }
  395. lwiperf_list_add(&client_conn->base);
  396. *new_conn = client_conn;
  397. return ERR_OK;
  398. }
  399. static err_t
  400. lwiperf_tx_start_passive(lwiperf_state_tcp_t *conn)
  401. {
  402. err_t ret;
  403. lwiperf_state_tcp_t *new_conn = NULL;
  404. u16_t remote_port = (u16_t)lwip_htonl(conn->settings.remote_port);
  405. ret = lwiperf_tx_start_impl(&conn->conn_pcb->remote_ip, remote_port, &conn->settings, conn->report_fn, conn->report_arg,
  406. conn->base.related_master_state, &new_conn);
  407. if (ret == ERR_OK) {
  408. LWIP_ASSERT("new_conn != NULL", new_conn != NULL);
  409. new_conn->settings.flags = 0; /* prevent the remote side starting back as client again */
  410. }
  411. return ret;
  412. }
  413. /** Receive data on an iperf tcp session */
  414. static err_t
  415. lwiperf_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
  416. {
  417. u8_t tmp;
  418. u16_t tot_len;
  419. u32_t packet_idx;
  420. struct pbuf *q;
  421. lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg;
  422. LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb);
  423. LWIP_UNUSED_ARG(tpcb);
  424. if (err != ERR_OK) {
  425. lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE);
  426. return ERR_OK;
  427. }
  428. if (p == NULL) {
  429. /* connection closed -> test done */
  430. if (conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) {
  431. if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_NOW)) == 0) {
  432. /* client requested transmission after end of test */
  433. lwiperf_tx_start_passive(conn);
  434. }
  435. }
  436. lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_SERVER);
  437. return ERR_OK;
  438. }
  439. tot_len = p->tot_len;
  440. conn->poll_count = 0;
  441. if ((!conn->have_settings_buf) || ((conn->bytes_transferred - 24) % (1024 * 128) == 0)) {
  442. /* wait for 24-byte header */
  443. if (p->tot_len < sizeof(lwiperf_settings_t)) {
  444. lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR);
  445. pbuf_free(p);
  446. return ERR_OK;
  447. }
  448. if (!conn->have_settings_buf) {
  449. if (pbuf_copy_partial(p, &conn->settings, sizeof(lwiperf_settings_t), 0) != sizeof(lwiperf_settings_t)) {
  450. lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL);
  451. pbuf_free(p);
  452. return ERR_OK;
  453. }
  454. conn->have_settings_buf = 1;
  455. if (conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) {
  456. if (conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_NOW)) {
  457. /* client requested parallel transmission test */
  458. err_t err2 = lwiperf_tx_start_passive(conn);
  459. if (err2 != ERR_OK) {
  460. lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_TXERROR);
  461. pbuf_free(p);
  462. return ERR_OK;
  463. }
  464. }
  465. }
  466. } else {
  467. if (conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) {
  468. if (pbuf_memcmp(p, 0, &conn->settings, sizeof(lwiperf_settings_t)) != 0) {
  469. lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR);
  470. pbuf_free(p);
  471. return ERR_OK;
  472. }
  473. }
  474. }
  475. conn->bytes_transferred += sizeof(lwiperf_settings_t);
  476. if (conn->bytes_transferred <= 24) {
  477. conn->time_started = sys_now();
  478. tcp_recved(tpcb, p->tot_len);
  479. pbuf_free(p);
  480. return ERR_OK;
  481. }
  482. conn->next_num = 4; /* 24 bytes received... */
  483. tmp = pbuf_remove_header(p, 24);
  484. LWIP_ASSERT("pbuf_remove_header failed", tmp == 0);
  485. LWIP_UNUSED_ARG(tmp); /* for LWIP_NOASSERT */
  486. }
  487. packet_idx = 0;
  488. for (q = p; q != NULL; q = q->next) {
  489. #if LWIPERF_CHECK_RX_DATA
  490. const u8_t *payload = (const u8_t *)q->payload;
  491. u16_t i;
  492. for (i = 0; i < q->len; i++) {
  493. u8_t val = payload[i];
  494. u8_t num = val - '0';
  495. if (num == conn->next_num) {
  496. conn->next_num++;
  497. if (conn->next_num == 10) {
  498. conn->next_num = 0;
  499. }
  500. } else {
  501. lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR);
  502. pbuf_free(p);
  503. return ERR_OK;
  504. }
  505. }
  506. #endif
  507. packet_idx += q->len;
  508. }
  509. LWIP_ASSERT("count mismatch", packet_idx == p->tot_len);
  510. conn->bytes_transferred += packet_idx;
  511. tcp_recved(tpcb, tot_len);
  512. pbuf_free(p);
  513. return ERR_OK;
  514. }
  515. /** Error callback, iperf tcp session aborted */
  516. static void
  517. lwiperf_tcp_err(void *arg, err_t err)
  518. {
  519. lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg;
  520. LWIP_UNUSED_ARG(err);
  521. lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE);
  522. }
  523. /** TCP poll callback, try to send more data */
  524. static err_t
  525. lwiperf_tcp_poll(void *arg, struct tcp_pcb *tpcb)
  526. {
  527. lwiperf_state_tcp_t *conn = (lwiperf_state_tcp_t *)arg;
  528. LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb);
  529. LWIP_UNUSED_ARG(tpcb);
  530. if (++conn->poll_count >= LWIPERF_TCP_MAX_IDLE_SEC) {
  531. lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL);
  532. return ERR_OK; /* lwiperf_tcp_close frees conn */
  533. }
  534. if (!conn->base.server) {
  535. lwiperf_tcp_client_send_more(conn);
  536. }
  537. return ERR_OK;
  538. }
  539. /** This is called when a new client connects for an iperf tcp session */
  540. static err_t
  541. lwiperf_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
  542. {
  543. lwiperf_state_tcp_t *s, *conn;
  544. if ((err != ERR_OK) || (newpcb == NULL) || (arg == NULL)) {
  545. return ERR_VAL;
  546. }
  547. s = (lwiperf_state_tcp_t *)arg;
  548. LWIP_ASSERT("invalid session", s->base.server);
  549. LWIP_ASSERT("invalid listen pcb", s->server_pcb != NULL);
  550. LWIP_ASSERT("invalid conn pcb", s->conn_pcb == NULL);
  551. if (s->specific_remote) {
  552. LWIP_ASSERT("s->base.related_master_state != NULL", s->base.related_master_state != NULL);
  553. if (!ip_addr_cmp(&newpcb->remote_ip, &s->remote_addr)) {
  554. /* this listener belongs to a client session, and this is not the correct remote */
  555. return ERR_VAL;
  556. }
  557. } else {
  558. LWIP_ASSERT("s->base.related_master_state == NULL", s->base.related_master_state == NULL);
  559. }
  560. conn = (lwiperf_state_tcp_t *)LWIPERF_ALLOC(lwiperf_state_tcp_t);
  561. if (conn == NULL) {
  562. return ERR_MEM;
  563. }
  564. memset(conn, 0, sizeof(lwiperf_state_tcp_t));
  565. conn->base.tcp = 1;
  566. conn->base.server = 1;
  567. conn->base.related_master_state = &s->base;
  568. conn->conn_pcb = newpcb;
  569. conn->time_started = sys_now();
  570. conn->report_fn = s->report_fn;
  571. conn->report_arg = s->report_arg;
  572. /* setup the tcp rx connection */
  573. tcp_arg(newpcb, conn);
  574. tcp_recv(newpcb, lwiperf_tcp_recv);
  575. tcp_poll(newpcb, lwiperf_tcp_poll, 2U);
  576. tcp_err(conn->conn_pcb, lwiperf_tcp_err);
  577. if (s->specific_remote) {
  578. /* this listener belongs to a client, so make the client the master of the newly created connection */
  579. conn->base.related_master_state = s->base.related_master_state;
  580. /* if dual mode or (tradeoff mode AND client is done): close the listener */
  581. if (!s->client_tradeoff_mode || !lwiperf_list_find(s->base.related_master_state)) {
  582. /* prevent report when closing: this is expected */
  583. s->report_fn = NULL;
  584. lwiperf_tcp_close(s, LWIPERF_TCP_ABORTED_LOCAL);
  585. }
  586. }
  587. lwiperf_list_add(&conn->base);
  588. return ERR_OK;
  589. }
  590. /**
  591. * @ingroup iperf
  592. * Start a TCP iperf server on the default TCP port (5001) and listen for
  593. * incoming connections from iperf clients.
  594. *
  595. * @returns a connection handle that can be used to abort the server
  596. * by calling @ref lwiperf_abort()
  597. */
  598. void *
  599. lwiperf_start_tcp_server_default(lwiperf_report_fn report_fn, void *report_arg)
  600. {
  601. return lwiperf_start_tcp_server(IP_ADDR_ANY, LWIPERF_TCP_PORT_DEFAULT,
  602. report_fn, report_arg);
  603. }
  604. /**
  605. * @ingroup iperf
  606. * Start a TCP iperf server on a specific IP address and port and listen for
  607. * incoming connections from iperf clients.
  608. *
  609. * @returns a connection handle that can be used to abort the server
  610. * by calling @ref lwiperf_abort()
  611. */
  612. void *
  613. lwiperf_start_tcp_server(const ip_addr_t *local_addr, u16_t local_port,
  614. lwiperf_report_fn report_fn, void *report_arg)
  615. {
  616. err_t err;
  617. lwiperf_state_tcp_t *state = NULL;
  618. err = lwiperf_start_tcp_server_impl(local_addr, local_port, report_fn, report_arg,
  619. NULL, &state);
  620. if (err == ERR_OK) {
  621. return state;
  622. }
  623. return NULL;
  624. }
  625. static err_t lwiperf_start_tcp_server_impl(const ip_addr_t *local_addr, u16_t local_port,
  626. lwiperf_report_fn report_fn, void *report_arg,
  627. lwiperf_state_base_t *related_master_state, lwiperf_state_tcp_t **state)
  628. {
  629. err_t err;
  630. struct tcp_pcb *pcb;
  631. lwiperf_state_tcp_t *s;
  632. LWIP_ASSERT_CORE_LOCKED();
  633. LWIP_ASSERT("state != NULL", state != NULL);
  634. if (local_addr == NULL) {
  635. return ERR_ARG;
  636. }
  637. s = (lwiperf_state_tcp_t *)LWIPERF_ALLOC(lwiperf_state_tcp_t);
  638. if (s == NULL) {
  639. return ERR_MEM;
  640. }
  641. memset(s, 0, sizeof(lwiperf_state_tcp_t));
  642. s->base.tcp = 1;
  643. s->base.server = 1;
  644. s->base.related_master_state = related_master_state;
  645. s->report_fn = report_fn;
  646. s->report_arg = report_arg;
  647. pcb = tcp_new_ip_type(LWIPERF_SERVER_IP_TYPE);
  648. if (pcb == NULL) {
  649. return ERR_MEM;
  650. }
  651. err = tcp_bind(pcb, local_addr, local_port);
  652. if (err != ERR_OK) {
  653. return err;
  654. }
  655. s->server_pcb = tcp_listen_with_backlog(pcb, 1);
  656. if (s->server_pcb == NULL) {
  657. if (pcb != NULL) {
  658. tcp_close(pcb);
  659. }
  660. LWIPERF_FREE(lwiperf_state_tcp_t, s);
  661. return ERR_MEM;
  662. }
  663. pcb = NULL;
  664. tcp_arg(s->server_pcb, s);
  665. tcp_accept(s->server_pcb, lwiperf_tcp_accept);
  666. lwiperf_list_add(&s->base);
  667. *state = s;
  668. return ERR_OK;
  669. }
  670. /**
  671. * @ingroup iperf
  672. * Start a TCP iperf client to the default TCP port (5001).
  673. *
  674. * @returns a connection handle that can be used to abort the client
  675. * by calling @ref lwiperf_abort()
  676. */
  677. void* lwiperf_start_tcp_client_default(const ip_addr_t* remote_addr,
  678. lwiperf_report_fn report_fn, void* report_arg)
  679. {
  680. return lwiperf_start_tcp_client(remote_addr, LWIPERF_TCP_PORT_DEFAULT, LWIPERF_CLIENT,
  681. report_fn, report_arg);
  682. }
  683. /**
  684. * @ingroup iperf
  685. * Start a TCP iperf client to a specific IP address and port.
  686. *
  687. * @returns a connection handle that can be used to abort the client
  688. * by calling @ref lwiperf_abort()
  689. */
  690. void* lwiperf_start_tcp_client(const ip_addr_t* remote_addr, u16_t remote_port,
  691. enum lwiperf_client_type type, lwiperf_report_fn report_fn, void* report_arg)
  692. {
  693. err_t ret;
  694. lwiperf_settings_t settings;
  695. lwiperf_state_tcp_t *state = NULL;
  696. memset(&settings, 0, sizeof(settings));
  697. switch (type) {
  698. case LWIPERF_CLIENT:
  699. /* Unidirectional tx only test */
  700. settings.flags = 0;
  701. break;
  702. case LWIPERF_DUAL:
  703. /* Do a bidirectional test simultaneously */
  704. settings.flags = htonl(LWIPERF_FLAGS_ANSWER_TEST | LWIPERF_FLAGS_ANSWER_NOW);
  705. break;
  706. case LWIPERF_TRADEOFF:
  707. /* Do a bidirectional test individually */
  708. settings.flags = htonl(LWIPERF_FLAGS_ANSWER_TEST);
  709. break;
  710. default:
  711. /* invalid argument */
  712. return NULL;
  713. }
  714. settings.num_threads = htonl(1);
  715. settings.remote_port = htonl(LWIPERF_TCP_PORT_DEFAULT);
  716. /* TODO: implement passing duration/amount of bytes to transfer */
  717. settings.amount = htonl((u32_t)-1000);
  718. ret = lwiperf_tx_start_impl(remote_addr, remote_port, &settings, report_fn, report_arg, NULL, &state);
  719. if (ret == ERR_OK) {
  720. LWIP_ASSERT("state != NULL", state != NULL);
  721. if (type != LWIPERF_CLIENT) {
  722. /* start corresponding server now */
  723. lwiperf_state_tcp_t *server = NULL;
  724. ret = lwiperf_start_tcp_server_impl(&state->conn_pcb->local_ip, LWIPERF_TCP_PORT_DEFAULT,
  725. report_fn, report_arg, (lwiperf_state_base_t *)state, &server);
  726. if (ret != ERR_OK) {
  727. /* starting server failed, abort client */
  728. lwiperf_abort(state);
  729. return NULL;
  730. }
  731. /* make this server accept one connection only */
  732. server->specific_remote = 1;
  733. server->remote_addr = state->conn_pcb->remote_ip;
  734. if (type == LWIPERF_TRADEOFF) {
  735. /* tradeoff means that the remote host connects only after the client is done,
  736. so keep the listen pcb open until the client is done */
  737. server->client_tradeoff_mode = 1;
  738. }
  739. }
  740. return state;
  741. }
  742. return NULL;
  743. }
  744. /**
  745. * @ingroup iperf
  746. * Abort an iperf session (handle returned by lwiperf_start_tcp_server*())
  747. */
  748. void
  749. lwiperf_abort(void *lwiperf_session)
  750. {
  751. lwiperf_state_base_t *i, *dealloc, *last = NULL;
  752. LWIP_ASSERT_CORE_LOCKED();
  753. for (i = lwiperf_all_connections; i != NULL; ) {
  754. if ((i == lwiperf_session) || (i->related_master_state == lwiperf_session)) {
  755. dealloc = i;
  756. i = i->next;
  757. if (last != NULL) {
  758. last->next = i;
  759. }
  760. LWIPERF_FREE(lwiperf_state_tcp_t, dealloc); /* @todo: type? */
  761. } else {
  762. last = i;
  763. i = i->next;
  764. }
  765. }
  766. }
  767. #endif /* LWIP_TCP && LWIP_CALLBACK_API */