iperf.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. /* Iperf Example - iperf implementation
  2. This example code is in the Public Domain (or CC0 licensed, at your option.)
  3. /
  4. Unless required by applicable law or agreed to in writing, this
  5. software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  6. CONDITIONS OF ANY KIND, either express or implied.
  7. */
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <sys/param.h>
  11. #include <sys/socket.h>
  12. #include <inttypes.h>
  13. #include "freertos/FreeRTOS.h"
  14. #include "freertos/task.h"
  15. #include "esp_check.h"
  16. #include "esp_log.h"
  17. #include "esp_rom_sys.h"
  18. #include "esp_timer.h"
  19. #include "iperf.h"
  20. #include "wifi_stats.h"
  21. typedef struct {
  22. iperf_cfg_t cfg;
  23. bool finish;
  24. uint32_t actual_len;
  25. uint32_t buffer_len;
  26. uint8_t *buffer;
  27. uint32_t sockfd;
  28. } iperf_ctrl_t;
  29. static bool s_iperf_is_running = false;
  30. static iperf_ctrl_t s_iperf_ctrl;
  31. static const char *TAG = "iperf";
  32. inline static bool iperf_is_udp_client(void)
  33. {
  34. return ((s_iperf_ctrl.cfg.flag & IPERF_FLAG_CLIENT) && (s_iperf_ctrl.cfg.flag & IPERF_FLAG_UDP));
  35. }
  36. inline static bool iperf_is_udp_server(void)
  37. {
  38. return ((s_iperf_ctrl.cfg.flag & IPERF_FLAG_SERVER) && (s_iperf_ctrl.cfg.flag & IPERF_FLAG_UDP));
  39. }
  40. inline static bool iperf_is_tcp_client(void)
  41. {
  42. return ((s_iperf_ctrl.cfg.flag & IPERF_FLAG_CLIENT) && (s_iperf_ctrl.cfg.flag & IPERF_FLAG_TCP));
  43. }
  44. inline static bool iperf_is_tcp_server(void)
  45. {
  46. return ((s_iperf_ctrl.cfg.flag & IPERF_FLAG_SERVER) && (s_iperf_ctrl.cfg.flag & IPERF_FLAG_TCP));
  47. }
  48. static int iperf_get_socket_error_code(int sockfd)
  49. {
  50. return errno;
  51. }
  52. static int iperf_show_socket_error_reason(const char *str, int sockfd)
  53. {
  54. int err = errno;
  55. if (err != 0) {
  56. ESP_LOGW(TAG, "%s error, error code: %d, reason: %s", str, err, strerror(err));
  57. }
  58. return err;
  59. }
  60. static void iperf_report_task(void *arg)
  61. {
  62. uint32_t interval = s_iperf_ctrl.cfg.interval;
  63. uint32_t time = s_iperf_ctrl.cfg.time;
  64. TickType_t delay_interval = (interval * 1000) / portTICK_PERIOD_MS;
  65. uint32_t cur = 0;
  66. double average = 0;
  67. double actual_bandwidth = 0;
  68. int k = 1;
  69. const double coefficient[3] = {1048576.0, 1024.0, 1.0};
  70. const char unit[3] = {'M', 'K', '\0'};
  71. iperf_output_format format = s_iperf_ctrl.cfg.format;
  72. printf("\n%16s %s\n", "Interval", "Bandwidth");
  73. while (!s_iperf_ctrl.finish) {
  74. vTaskDelay(delay_interval);
  75. actual_bandwidth = (s_iperf_ctrl.actual_len / coefficient[format] * 8) / interval;
  76. printf("%4" PRIi32 "-%4" PRIi32 " sec %.2f %cbits/sec\n", cur, cur + interval,
  77. actual_bandwidth, unit[format]);
  78. cur += interval;
  79. average = ((average * (k - 1) / k) + (actual_bandwidth / k));
  80. k++;
  81. s_iperf_ctrl.actual_len = 0;
  82. if (cur >= time) {
  83. printf("%4d-%4" PRIu32 " sec %.2f %cbits/sec\n", 0, time,
  84. average, unit[format]);
  85. break;
  86. }
  87. }
  88. s_iperf_ctrl.finish = true;
  89. vTaskDelete(NULL);
  90. }
  91. static esp_err_t iperf_start_report(void)
  92. {
  93. int ret;
  94. ret = xTaskCreatePinnedToCore(iperf_report_task, IPERF_REPORT_TASK_NAME, IPERF_REPORT_TASK_STACK, NULL, IPERF_REPORT_TASK_PRIORITY, NULL, portNUM_PROCESSORS - 1);
  95. if (ret != pdPASS) {
  96. ESP_LOGE(TAG, "create task %s failed", IPERF_REPORT_TASK_NAME);
  97. return ESP_FAIL;
  98. }
  99. return ESP_OK;
  100. }
  101. static void IRAM_ATTR socket_recv(int recv_socket, struct sockaddr_storage listen_addr, uint8_t type)
  102. {
  103. bool iperf_recv_start = true;
  104. uint8_t *buffer;
  105. int want_recv = 0;
  106. int actual_recv = 0;
  107. #ifdef CONFIG_LWIP_IPV6
  108. socklen_t socklen = (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
  109. #else
  110. socklen_t socklen = sizeof(struct sockaddr_in);
  111. #endif
  112. const char *error_log = (type == IPERF_TRANS_TYPE_TCP) ? "tcp server recv" : "udp server recv";
  113. buffer = s_iperf_ctrl.buffer;
  114. want_recv = s_iperf_ctrl.buffer_len;
  115. while (!s_iperf_ctrl.finish) {
  116. actual_recv = recvfrom(recv_socket, buffer, want_recv, 0, (struct sockaddr *)&listen_addr, &socklen);
  117. if (actual_recv < 0) {
  118. iperf_show_socket_error_reason(error_log, recv_socket);
  119. s_iperf_ctrl.finish = true;
  120. break;
  121. } else {
  122. if (iperf_recv_start) {
  123. iperf_start_report();
  124. iperf_recv_start = false;
  125. }
  126. s_iperf_ctrl.actual_len += actual_recv;
  127. }
  128. }
  129. }
  130. static void IRAM_ATTR socket_send(int send_socket, struct sockaddr_storage dest_addr, uint8_t type, int bw_lim)
  131. {
  132. uint8_t *buffer;
  133. uint32_t *pkt_id_p;
  134. uint32_t pkt_cnt = 0;
  135. int actual_send = 0;
  136. int want_send = 0;
  137. int period_us = -1;
  138. int delay_us = 0;
  139. int64_t prev_time = 0;
  140. int64_t send_time = 0;
  141. int err = 0;
  142. #ifdef CONFIG_LWIP_IPV6
  143. const socklen_t socklen = (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
  144. #else
  145. const socklen_t socklen = sizeof(struct sockaddr_in);
  146. #endif
  147. const char *error_log = (type == IPERF_TRANS_TYPE_TCP) ? "tcp client send" : "udp client send";
  148. buffer = s_iperf_ctrl.buffer;
  149. pkt_id_p = (uint32_t *)s_iperf_ctrl.buffer;
  150. want_send = s_iperf_ctrl.buffer_len;
  151. iperf_start_report();
  152. if (bw_lim > 0) {
  153. period_us = want_send * 8 / bw_lim;
  154. }
  155. while (!s_iperf_ctrl.finish) {
  156. if (period_us > 0) {
  157. send_time = esp_timer_get_time();
  158. if (actual_send > 0){
  159. // Last packet "send" was successful, check how much off the previous loop duration was to the ideal send period. Result will adjust the
  160. // next send delay.
  161. delay_us += period_us + (int32_t)(prev_time - send_time);
  162. } else {
  163. // Last packet "send" was not successful. Ideally we should try to catch up the whole previous loop duration (e.g. prev_time - send_time).
  164. // However, that's not possible since the most probable reason why the send was unsuccessful is the HW was not able to process the packet.
  165. // Hence, we cannot queue more packets with shorter (or no) delay to catch up since we are already at the performance edge. The best we
  166. // can do is to reset the send delay (which is probably big negative number) and start all over again.
  167. delay_us = 0;
  168. }
  169. prev_time = send_time;
  170. }
  171. *pkt_id_p = htonl(pkt_cnt++); // datagrams need to be sequentially numbered
  172. actual_send = sendto(send_socket, buffer, want_send, 0, (struct sockaddr *)&dest_addr, socklen);
  173. if (actual_send != want_send) {
  174. if (type == IPERF_TRANS_TYPE_UDP) {
  175. err = iperf_get_socket_error_code(send_socket);
  176. // ENOMEM is expected under heavy load => do not print it
  177. if (err != ENOMEM) {
  178. iperf_show_socket_error_reason(error_log, send_socket);
  179. }
  180. } else if (type == IPERF_TRANS_TYPE_TCP) {
  181. iperf_show_socket_error_reason(error_log, send_socket);
  182. break;
  183. }
  184. } else {
  185. s_iperf_ctrl.actual_len += actual_send;
  186. }
  187. // The send delay may be negative, it indicates we are trying to catch up and hence to not delay the loop at all.
  188. if (delay_us > 0) {
  189. esp_rom_delay_us(delay_us);
  190. }
  191. }
  192. }
  193. static esp_err_t iperf_run_tcp_server(void)
  194. {
  195. int listen_socket = -1;
  196. int client_socket = -1;
  197. int opt = 1;
  198. int err = 0;
  199. esp_err_t ret = ESP_OK;
  200. struct sockaddr_in remote_addr;
  201. struct timeval timeout = { 0 };
  202. socklen_t addr_len = sizeof(struct sockaddr);
  203. struct sockaddr_storage listen_addr = { 0 };
  204. struct sockaddr_in listen_addr4 = { 0 };
  205. #ifdef CONFIG_LWIP_IPV6
  206. struct sockaddr_in6 listen_addr6 = { 0 };
  207. ESP_GOTO_ON_FALSE((s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6 || s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4), ESP_FAIL, exit, TAG, "Ivalid AF types");
  208. #else
  209. ESP_GOTO_ON_FALSE((s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4), ESP_FAIL, exit, TAG, "Invalid AF types");
  210. #endif
  211. #ifdef CONFIG_LWIP_IPV6
  212. if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6) {
  213. // The TCP server listen at the address "::", which means all addresses can be listened to.
  214. inet6_aton("::", &listen_addr6.sin6_addr);
  215. listen_addr6.sin6_family = AF_INET6;
  216. listen_addr6.sin6_port = htons(s_iperf_ctrl.cfg.sport);
  217. listen_socket = socket(AF_INET6, SOCK_STREAM, IPPROTO_IPV6);
  218. ESP_GOTO_ON_FALSE((listen_socket >= 0), ESP_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
  219. setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
  220. setsockopt(listen_socket, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
  221. ESP_LOGI(TAG, "Socket created");
  222. err = bind(listen_socket, (struct sockaddr *)&listen_addr6, sizeof(listen_addr6));
  223. ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Socket unable to bind: errno %d, IPPROTO: %d", errno, AF_INET6);
  224. err = listen(listen_socket, 1);
  225. ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Error occurred during listen: errno %d", errno);
  226. memcpy(&listen_addr, &listen_addr6, sizeof(listen_addr6));
  227. } else
  228. #endif
  229. if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4) {
  230. listen_addr4.sin_family = AF_INET;
  231. listen_addr4.sin_port = htons(s_iperf_ctrl.cfg.sport);
  232. listen_addr4.sin_addr.s_addr = s_iperf_ctrl.cfg.source_ip4;
  233. listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  234. ESP_GOTO_ON_FALSE((listen_socket >= 0), ESP_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
  235. setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
  236. ESP_LOGI(TAG, "Socket created");
  237. err = bind(listen_socket, (struct sockaddr *)&listen_addr4, sizeof(listen_addr4));
  238. ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Socket unable to bind: errno %d, IPPROTO: %d", errno, AF_INET);
  239. err = listen(listen_socket, 5);
  240. ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Error occurred during listen: errno %d", errno);
  241. memcpy(&listen_addr, &listen_addr4, sizeof(listen_addr4));
  242. }
  243. timeout.tv_sec = IPERF_SOCKET_RX_TIMEOUT;
  244. setsockopt(listen_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
  245. client_socket = accept(listen_socket, (struct sockaddr *)&remote_addr, &addr_len);
  246. ESP_GOTO_ON_FALSE((client_socket >= 0), ESP_FAIL, exit, TAG, "Unable to accept connection: errno %d", errno);
  247. ESP_LOGI(TAG, "accept: %s,%d", inet_ntoa(remote_addr.sin_addr), htons(remote_addr.sin_port));
  248. timeout.tv_sec = IPERF_SOCKET_RX_TIMEOUT;
  249. setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
  250. #if CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS
  251. wifi_cmd_clr_tx_statistics(0, NULL);
  252. #endif
  253. #if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS
  254. wifi_cmd_clr_rx_statistics(0, NULL);
  255. #endif
  256. socket_recv(client_socket, listen_addr, IPERF_TRANS_TYPE_TCP);
  257. #if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS
  258. wifi_cmd_get_rx_statistics(0, NULL);
  259. #endif
  260. #if CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS
  261. wifi_cmd_get_tx_statistics(0, NULL);
  262. #endif
  263. exit:
  264. if (client_socket != -1) {
  265. close(client_socket);
  266. }
  267. if (listen_socket != -1) {
  268. shutdown(listen_socket, 0);
  269. close(listen_socket);
  270. ESP_LOGI(TAG, "TCP Socket server is closed.");
  271. }
  272. s_iperf_ctrl.finish = true;
  273. return ret;
  274. }
  275. static esp_err_t iperf_run_tcp_client(void)
  276. {
  277. int client_socket = -1;
  278. int err = 0;
  279. esp_err_t ret = ESP_OK;
  280. struct sockaddr_storage dest_addr = { 0 };
  281. struct sockaddr_in dest_addr4 = { 0 };
  282. struct timeval timeout = { 0 };
  283. #ifdef CONFIG_LWIP_IPV6
  284. struct sockaddr_in6 dest_addr6 = { 0 };
  285. ESP_GOTO_ON_FALSE((s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6 || s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4), ESP_FAIL, exit, TAG, "Ivalid AF types");
  286. #else
  287. ESP_GOTO_ON_FALSE((s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4), ESP_FAIL, exit, TAG, "Invalid AF types");
  288. #endif
  289. #ifdef CONFIG_LWIP_IPV6
  290. if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6) {
  291. client_socket = socket(AF_INET6, SOCK_STREAM, IPPROTO_IPV6);
  292. ESP_GOTO_ON_FALSE((client_socket >= 0), ESP_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
  293. inet6_aton(s_iperf_ctrl.cfg.destination_ip6, &dest_addr6.sin6_addr);
  294. dest_addr6.sin6_family = AF_INET6;
  295. dest_addr6.sin6_port = htons(s_iperf_ctrl.cfg.dport);
  296. err = connect(client_socket, (struct sockaddr *)&dest_addr6, sizeof(struct sockaddr_in6));
  297. ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Socket unable to connect: errno %d", errno);
  298. ESP_LOGI(TAG, "Successfully connected");
  299. memcpy(&dest_addr, &dest_addr6, sizeof(dest_addr6));
  300. } else
  301. #endif
  302. if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4) {
  303. client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  304. ESP_GOTO_ON_FALSE((client_socket >= 0), ESP_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
  305. dest_addr4.sin_family = AF_INET;
  306. dest_addr4.sin_port = htons(s_iperf_ctrl.cfg.dport);
  307. dest_addr4.sin_addr.s_addr = s_iperf_ctrl.cfg.destination_ip4;
  308. err = connect(client_socket, (struct sockaddr *)&dest_addr4, sizeof(struct sockaddr_in));
  309. ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Socket unable to connect: errno %d", errno);
  310. ESP_LOGI(TAG, "Successfully connected");
  311. memcpy(&dest_addr, &dest_addr4, sizeof(dest_addr4));
  312. }
  313. timeout.tv_sec = IPERF_SOCKET_TCP_TX_TIMEOUT;
  314. setsockopt(client_socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
  315. #if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS
  316. wifi_cmd_clr_rx_statistics(0, NULL);
  317. #endif
  318. #if CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS
  319. wifi_cmd_clr_tx_statistics(0, NULL);
  320. #endif
  321. socket_send(client_socket, dest_addr, IPERF_TRANS_TYPE_TCP, s_iperf_ctrl.cfg.bw_lim);
  322. #if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS
  323. wifi_cmd_get_rx_statistics(0, NULL);
  324. #endif
  325. #if CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS
  326. wifi_cmd_get_tx_statistics(0, NULL);
  327. #endif
  328. exit:
  329. if (client_socket != -1) {
  330. shutdown(client_socket, 0);
  331. close(client_socket);
  332. ESP_LOGI(TAG, "TCP Socket client is closed.");
  333. }
  334. s_iperf_ctrl.finish = true;
  335. return ret;
  336. }
  337. static esp_err_t iperf_run_udp_server(void)
  338. {
  339. int listen_socket = -1;
  340. int opt = 1;
  341. int err = 0;
  342. esp_err_t ret = ESP_OK;
  343. struct timeval timeout = { 0 };
  344. struct sockaddr_storage listen_addr = { 0 };
  345. struct sockaddr_in listen_addr4 = { 0 };
  346. #ifdef CONFIG_LWIP_IPV6
  347. struct sockaddr_in6 listen_addr6 = { 0 };
  348. ESP_GOTO_ON_FALSE((s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6 || s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4), ESP_FAIL, exit, TAG, "Ivalid AF types");
  349. #else
  350. ESP_GOTO_ON_FALSE((s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4), ESP_FAIL, exit, TAG, "Ivalid AF types");
  351. #endif
  352. #ifdef CONFIG_LWIP_IPV6
  353. if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6) {
  354. // The UDP server listen at the address "::", which means all addresses can be listened to.
  355. inet6_aton("::", &listen_addr6.sin6_addr);
  356. listen_addr6.sin6_family = AF_INET6;
  357. listen_addr6.sin6_port = htons(s_iperf_ctrl.cfg.sport);
  358. listen_socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
  359. ESP_GOTO_ON_FALSE((listen_socket >= 0), ESP_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
  360. ESP_LOGI(TAG, "Socket created");
  361. setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
  362. err = bind(listen_socket, (struct sockaddr *)&listen_addr6, sizeof(struct sockaddr_in6));
  363. ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Socket unable to bind: errno %d", errno);
  364. ESP_LOGI(TAG, "Socket bound, port %" PRIu16, listen_addr6.sin6_port);
  365. memcpy(&listen_addr, &listen_addr6, sizeof(listen_addr6));
  366. } else
  367. #endif
  368. if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4) {
  369. listen_addr4.sin_family = AF_INET;
  370. listen_addr4.sin_port = htons(s_iperf_ctrl.cfg.sport);
  371. listen_addr4.sin_addr.s_addr = s_iperf_ctrl.cfg.source_ip4;
  372. listen_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  373. ESP_GOTO_ON_FALSE((listen_socket >= 0), ESP_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
  374. ESP_LOGI(TAG, "Socket created");
  375. setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
  376. err = bind(listen_socket, (struct sockaddr *)&listen_addr4, sizeof(struct sockaddr_in));
  377. ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Socket unable to bind: errno %d", errno);
  378. ESP_LOGI(TAG, "Socket bound, port %d", listen_addr4.sin_port);
  379. memcpy(&listen_addr, &listen_addr4, sizeof(listen_addr4));
  380. }
  381. timeout.tv_sec = IPERF_SOCKET_RX_TIMEOUT;
  382. setsockopt(listen_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
  383. #if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS
  384. wifi_cmd_clr_rx_statistics(0, NULL);
  385. #endif
  386. socket_recv(listen_socket, listen_addr, IPERF_TRANS_TYPE_UDP);
  387. #if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS
  388. wifi_cmd_get_rx_statistics(0, NULL);
  389. #endif
  390. exit:
  391. if (listen_socket != -1) {
  392. shutdown(listen_socket, 0);
  393. close(listen_socket);
  394. }
  395. ESP_LOGI(TAG, "Udp socket server is closed.");
  396. s_iperf_ctrl.finish = true;
  397. return ret;
  398. }
  399. static esp_err_t iperf_run_udp_client(void)
  400. {
  401. int client_socket = -1;
  402. int opt = 1;
  403. esp_err_t ret = ESP_OK;
  404. struct sockaddr_storage dest_addr = { 0 };
  405. struct sockaddr_in dest_addr4 = { 0 };
  406. #ifdef CONFIG_LWIP_IPV6
  407. struct sockaddr_in6 dest_addr6 = { 0 };
  408. ESP_GOTO_ON_FALSE((s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6 || s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4), ESP_FAIL, exit, TAG, "Ivalid AF types");
  409. #else
  410. ESP_GOTO_ON_FALSE((s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4), ESP_FAIL, exit, TAG, "Ivalid AF types");
  411. #endif
  412. #ifdef CONFIG_LWIP_IPV6
  413. if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6) {
  414. inet6_aton(s_iperf_ctrl.cfg.destination_ip6, &dest_addr6.sin6_addr);
  415. dest_addr6.sin6_family = AF_INET6;
  416. dest_addr6.sin6_port = htons(s_iperf_ctrl.cfg.dport);
  417. client_socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IPV6);
  418. ESP_GOTO_ON_FALSE((client_socket >= 0), ESP_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
  419. ESP_LOGI(TAG, "Socket created, sending to %s:%" PRIu16, s_iperf_ctrl.cfg.destination_ip6, s_iperf_ctrl.cfg.dport);
  420. setsockopt(client_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
  421. memcpy(&dest_addr, &dest_addr6, sizeof(dest_addr6));
  422. } else
  423. #endif
  424. if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV4) {
  425. dest_addr4.sin_family = AF_INET;
  426. dest_addr4.sin_port = htons(s_iperf_ctrl.cfg.dport);
  427. dest_addr4.sin_addr.s_addr = s_iperf_ctrl.cfg.destination_ip4;
  428. client_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  429. ESP_GOTO_ON_FALSE((client_socket >= 0), ESP_FAIL, exit, TAG, "Unable to create socket: errno %d", errno);
  430. ESP_LOGI(TAG, "Socket created, sending to %d.%d.%d.%d:%" PRIu16,
  431. (uint16_t) s_iperf_ctrl.cfg.destination_ip4 & 0xFF,
  432. (uint16_t) (s_iperf_ctrl.cfg.destination_ip4 >> 8) & 0xFF,
  433. (uint16_t) (s_iperf_ctrl.cfg.destination_ip4 >> 16) & 0xFF,
  434. (uint16_t) (s_iperf_ctrl.cfg.destination_ip4 >> 24) & 0xFF,
  435. s_iperf_ctrl.cfg.dport);
  436. setsockopt(client_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
  437. memcpy(&dest_addr, &dest_addr4, sizeof(dest_addr4));
  438. }
  439. #if CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS
  440. wifi_cmd_clr_tx_statistics(0, NULL);
  441. #endif
  442. socket_send(client_socket, dest_addr, IPERF_TRANS_TYPE_UDP, s_iperf_ctrl.cfg.bw_lim);
  443. #if CONFIG_ESP_WIFI_ENABLE_WIFI_TX_STATS
  444. wifi_cmd_get_tx_statistics(0, NULL);
  445. #endif
  446. exit:
  447. if (client_socket != -1) {
  448. shutdown(client_socket, 0);
  449. close(client_socket);
  450. }
  451. s_iperf_ctrl.finish = true;
  452. ESP_LOGI(TAG, "UDP Socket client is closed");
  453. return ret;
  454. }
  455. static void iperf_task_traffic(void *arg)
  456. {
  457. if (iperf_is_udp_client()) {
  458. iperf_run_udp_client();
  459. } else if (iperf_is_udp_server()) {
  460. iperf_run_udp_server();
  461. } else if (iperf_is_tcp_client()) {
  462. iperf_run_tcp_client();
  463. } else {
  464. iperf_run_tcp_server();
  465. }
  466. if (s_iperf_ctrl.buffer) {
  467. free(s_iperf_ctrl.buffer);
  468. s_iperf_ctrl.buffer = NULL;
  469. }
  470. ESP_LOGI(TAG, "iperf exit");
  471. s_iperf_is_running = false;
  472. vTaskDelete(NULL);
  473. }
  474. static uint32_t iperf_get_buffer_len(void)
  475. {
  476. if (iperf_is_udp_client()) {
  477. #ifdef CONFIG_LWIP_IPV6
  478. if (s_iperf_ctrl.cfg.len_send_buf) {
  479. return s_iperf_ctrl.cfg.len_send_buf;
  480. } else if (s_iperf_ctrl.cfg.type == IPERF_IP_TYPE_IPV6) {
  481. return IPERF_DEFAULT_IPV6_UDP_TX_LEN;
  482. } else {
  483. return IPERF_DEFAULT_IPV4_UDP_TX_LEN;
  484. }
  485. #else
  486. return (s_iperf_ctrl.cfg.len_send_buf == 0 ? IPERF_DEFAULT_IPV4_UDP_TX_LEN : s_iperf_ctrl.cfg.len_send_buf);
  487. #endif
  488. } else if (iperf_is_udp_server()) {
  489. return IPERF_DEFAULT_UDP_RX_LEN;
  490. } else if (iperf_is_tcp_client()) {
  491. return (s_iperf_ctrl.cfg.len_send_buf == 0 ? IPERF_DEFAULT_TCP_TX_LEN : s_iperf_ctrl.cfg.len_send_buf);
  492. } else {
  493. return IPERF_DEFAULT_TCP_RX_LEN;
  494. }
  495. return 0;
  496. }
  497. esp_err_t iperf_start(iperf_cfg_t *cfg)
  498. {
  499. BaseType_t ret;
  500. if (!cfg) {
  501. return ESP_FAIL;
  502. }
  503. if (s_iperf_is_running) {
  504. ESP_LOGW(TAG, "iperf is running");
  505. return ESP_FAIL;
  506. }
  507. memset(&s_iperf_ctrl, 0, sizeof(s_iperf_ctrl));
  508. memcpy(&s_iperf_ctrl.cfg, cfg, sizeof(*cfg));
  509. s_iperf_is_running = true;
  510. s_iperf_ctrl.finish = false;
  511. s_iperf_ctrl.buffer_len = iperf_get_buffer_len();
  512. s_iperf_ctrl.buffer = (uint8_t *)malloc(s_iperf_ctrl.buffer_len);
  513. if (!s_iperf_ctrl.buffer) {
  514. ESP_LOGE(TAG, "create buffer: not enough memory");
  515. return ESP_FAIL;
  516. }
  517. memset(s_iperf_ctrl.buffer, 0, s_iperf_ctrl.buffer_len);
  518. ret = xTaskCreatePinnedToCore(iperf_task_traffic, IPERF_TRAFFIC_TASK_NAME, IPERF_TRAFFIC_TASK_STACK, NULL, IPERF_TRAFFIC_TASK_PRIORITY, NULL, portNUM_PROCESSORS - 1);
  519. if (ret != pdPASS) {
  520. ESP_LOGE(TAG, "create task %s failed", IPERF_TRAFFIC_TASK_NAME);
  521. free(s_iperf_ctrl.buffer);
  522. s_iperf_ctrl.buffer = NULL;
  523. return ESP_FAIL;
  524. }
  525. return ESP_OK;
  526. }
  527. esp_err_t iperf_stop(void)
  528. {
  529. if (s_iperf_is_running) {
  530. s_iperf_ctrl.finish = true;
  531. }
  532. while (s_iperf_is_running) {
  533. ESP_LOGI(TAG, "wait current iperf to stop ...");
  534. vTaskDelay(300 / portTICK_PERIOD_MS);
  535. }
  536. return ESP_OK;
  537. }