diff --git a/netutils/iperf/Kconfig b/netutils/iperf/Kconfig new file mode 100644 index 000000000..0c4f0082b --- /dev/null +++ b/netutils/iperf/Kconfig @@ -0,0 +1,37 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config EXAMPLES_IPERF + bool "iperf example" + default n + depends on NET + select NETUTILS_NETLIB + select LIBC_FLOATINGPOINT + select SYSTEM_ARGTABLE3 + ---help--- + Enable the \"iperf example\" + +if EXAMPLES_IPERF + +config EXAMPLES_IPERF_PROGNAME + string "Program name" + default "iperf" + ---help--- + This is the name of the program that will be used when the NSH ELF + program is installed. + +config EXAMPLES_IPERF_PRIORITY + int "iperf task priority" + default 100 + +config EXAMPLES_IPERF_STACKSIZE + int "iperf stack size" + default DEFAULT_TASK_STACKSIZE + +config EXAMPLES_IPERFTEST_DEVNAME + string "Wi-Fi Network device" + default "wlan0" + +endif diff --git a/netutils/iperf/Make.defs b/netutils/iperf/Make.defs new file mode 100644 index 000000000..13effb790 --- /dev/null +++ b/netutils/iperf/Make.defs @@ -0,0 +1,24 @@ +############################################################################ +# apps/netutils/iperf/Make.defs +# Adds selected applications to apps/ build +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +ifneq ($(CONFIG_EXAMPLES_IPERF),) +CONFIGURED_APPS += $(APPDIR)/netutils/iperf +endif diff --git a/netutils/iperf/Makefile b/netutils/iperf/Makefile new file mode 100644 index 000000000..437675c70 --- /dev/null +++ b/netutils/iperf/Makefile @@ -0,0 +1,35 @@ +############################################################################ +# apps/netutils/iperf/Makefile +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(APPDIR)/Make.defs + +# iperf example! built-in application info + +PROGNAME = $(CONFIG_EXAMPLES_IPERF_PROGNAME) +PRIORITY = $(CONFIG_EXAMPLES_IPERF_PRIORITY) +STACKSIZE = $(CONFIG_EXAMPLES_IPERF_STACKSIZE) +MODULE = $(CONFIG_EXAMPLES_IPERF) + +# Iperf Example + +CSRCS += iperf.c +MAINSRC = iperf_main.c + +include $(APPDIR)/Application.mk diff --git a/netutils/iperf/README.md b/netutils/iperf/README.md new file mode 100644 index 000000000..ea95f1352 --- /dev/null +++ b/netutils/iperf/README.md @@ -0,0 +1,87 @@ +Configuring NuttX to use your Wireless Router (aka Access Point) +================================================================ + + Since you are already in the root of NuttX/ repository, execute + make menuconfig to define your Wireless Router and your password: + + $ make menuconfig + + Browser the menus this way: + + Application Configuration ---> + Network Utilities ---> + Networking Configuration ---> + WAPI Configuration ---> + (myApSSID) SSID + (mySSIDpassphrase) Passprhase + + Replace the SSID from myApSSID with your wireless router name and + the Passprhase with your WiFi password. + + Exit and save your configuration. + +iperf Test Example +=================================== + +To set up, do `make menuconfig` and select the Apps > netutils > iperf example. By default, NuttX will the be the client +which sends data; and the host computer (Linux, macOS, or Windows) will be the server. + +Set up networking so the NuttX computer can ping the host, and the host can ping NuttX. Now you are ready to run the +test. + +If you are using a wireless network card, you must first connect to the router: + +On host: + + $ iperf -s -p 5471 -i 1 -w 416K + ------------------------------------------------------------ + Server listening on TCP port 5471 + TCP window size: 416 KByte + ------------------------------------------------------------ + +On NuttX: + + nsh> iperf -c 192.168.1.181 -p 5471 -i 1 -t 10 + mode=tcp-client sip=192.168.1.198:5001, dip=192.168.1.181:5471, interval=1, time=10 + + Interval Bandwidth + + 0- 1 sec, 0.39 Mbits/sec + 1- 2 sec, 0.26 Mbits/sec + 2- 3 sec, 0.39 Mbits/sec + 3- 4 sec, 0.26 Mbits/sec + 4- 5 sec, 0.26 Mbits/sec + 5- 6 sec, 0.26 Mbits/sec + 6- 7 sec, 0.26 Mbits/sec + 7- 8 sec, 0.26 Mbits/sec + 8- 9 sec, 0.26 Mbits/sec + 9- 10 sec, 0.26 Mbits/sec + 0- 10 sec, 0.28 Mbits/sec + +Now on the host you should see something like: + + $ iperf -s -p 5471 -i 1 -w 416K + ------------------------------------------------------------ + Server listening on TCP port 5471 + TCP window size: 416 KByte + ------------------------------------------------------------ + [ 5] local 192.168.1.181 port 5471 connected with 192.168.1.198 port 4210 + [ 5] 0.0- 1.0 sec 60.8 KBytes 498 Kbits/sec + [ 5] 1.0- 2.0 sec 34.9 KBytes 286 Kbits/sec + [ 5] 2.0- 3.0 sec 33.7 KBytes 276 Kbits/sec + [ 5] 3.0- 4.0 sec 33.4 KBytes 274 Kbits/sec + [ 5] 4.0- 5.0 sec 32.0 KBytes 262 Kbits/sec + [ 5] 5.0- 6.0 sec 32.0 KBytes 262 Kbits/sec + [ 5] 6.0- 7.0 sec 33.4 KBytes 274 Kbits/sec + [ 5] 7.0- 8.0 sec 32.0 KBytes 262 Kbits/sec + [ 5] 8.0- 9.0 sec 32.0 KBytes 262 Kbits/sec + [ 5] 9.0-10.0 sec 33.4 KBytes 274 Kbits/sec + [ 5] 0.0-10.3 sec 368 KBytes 292 Kbits/sec + + +This will tell you the link speed in Kbits/sec – kilobits per second. If you want kilobytes, divide by 8. + + + + + diff --git a/netutils/iperf/iperf.c b/netutils/iperf/iperf.c new file mode 100644 index 000000000..b24764dc7 --- /dev/null +++ b/netutils/iperf/iperf.c @@ -0,0 +1,722 @@ +/**************************************************************************** + * apps/netutils/iperf/iperf.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include "iperf.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define IPERF_TRAFFIC_TASK_NAME "iperf_traffic" +#define IPERF_TRAFFIC_TASK_PRIORITY 100 +#define IPERF_TRAFFIC_TASK_STACK 4096 +#define IPERF_REPORT_TASK_NAME "iperf_report" +#define IPERF_REPORT_TASK_PRIORITY 100 +#define IPERF_REPORT_TASK_STACK 4096 +#define IPERF_REPORT_TASK_NAME "iperf_report" + +#define IPERF_UDP_TX_LEN (1472) +#define IPERF_UDP_RX_LEN (16 << 10) +#define IPERF_TCP_TX_LEN (16 << 10) +#define IPERF_TCP_RX_LEN (16 << 10) + +#define IPERF_MAX_DELAY 64 +#define IPERF_SOCKET_RX_TIMEOUT 10 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct iperf_ctrl_t +{ + struct iperf_cfg_t cfg; + bool finish; + uint32_t total_len; + uint32_t buffer_len; + uint8_t *buffer; + uint32_t sockfd; +}; + +struct iperf_udp_pkt_t +{ + int32_t id; + uint32_t sec; + uint32_t usec; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static bool s_iperf_is_running = false; +static struct iperf_ctrl_t s_iperf_ctrl; + +/**************************************************************************** + * Private Functions Prototypes + ****************************************************************************/ + +inline static bool iperf_is_udp_client(void); +inline static bool iperf_is_udp_server(void); +inline static bool iperf_is_tcp_client(void); +inline static bool iperf_is_tcp_server(void); +static int iperf_get_socket_error_code(int sockfd); +static int iperf_show_socket_error_reason(const char *str, int sockfd); +static void iperf_report_task(void *arg); +static int iperf_start_report(void); +static int iperf_run_tcp_server(void); +static int iperf_run_udp_server(void); +static int iperf_run_udp_client(void); +static int iperf_run_tcp_client(void); +static void iperf_task_traffic(void *arg); +static uint32_t iperf_get_buffer_len(void); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: iperf_is_udp_client + * + * Description: + * Check if it is a udp client + * + ****************************************************************************/ + +inline static bool iperf_is_udp_client(void) +{ + return ((s_iperf_ctrl.cfg.flag & IPERF_FLAG_CLIENT) + && (s_iperf_ctrl.cfg.flag & IPERF_FLAG_UDP)); +} + +/**************************************************************************** + * Name: iperf_is_udp_server + * + * Description: + * Check if it is a udp server + * + ****************************************************************************/ + +inline static bool iperf_is_udp_server(void) +{ + return ((s_iperf_ctrl.cfg.flag & IPERF_FLAG_SERVER) + && (s_iperf_ctrl.cfg.flag & IPERF_FLAG_UDP)); +} + +/**************************************************************************** + * Name: iperf_is_tcp_client + * + * Description: + * Check if it is a tcp client + * + ****************************************************************************/ + +inline static bool iperf_is_tcp_client(void) +{ + return ((s_iperf_ctrl.cfg.flag & IPERF_FLAG_CLIENT) + && (s_iperf_ctrl.cfg.flag & IPERF_FLAG_TCP)); +} + +/**************************************************************************** + * Name: iperf_is_tcp_server + * + * Description: + * Check if it is a tcp server + * + ****************************************************************************/ + +inline static bool iperf_is_tcp_server(void) +{ + return ((s_iperf_ctrl.cfg.flag & IPERF_FLAG_SERVER) + && (s_iperf_ctrl.cfg.flag & IPERF_FLAG_TCP)); +} + +/**************************************************************************** + * Name: iperf_get_socket_error_code + * + * Description: + * Get reason of socket error. + * + ****************************************************************************/ + +static int iperf_get_socket_error_code(int sockfd) +{ + return errno; +} + +/**************************************************************************** + * Name: iperf_show_socket_error_reason + * + * Description: + * Show reason of socket error. + * + ****************************************************************************/ + +static int iperf_show_socket_error_reason(const char *str, int sockfd) +{ + int err = errno; + if (err != 0) + { + printf("%s error, error code: %d, reason: %s", + str, err, strerror(err)); + } + + return err; +} + +/**************************************************************************** + * Name: iperf_report_task + * + * Description: + * Start iperf report task + * + ****************************************************************************/ + +static void iperf_report_task(void *arg) +{ + uint32_t interval = s_iperf_ctrl.cfg.interval; + uint32_t time = s_iperf_ctrl.cfg.time; + uint32_t last_len = 0; + uint32_t cur = 0; + + printf("\n%16s %s\n", "Interval", "Bandwidth\n"); + while (!s_iperf_ctrl.finish) + { + sleep(interval); + printf("%4d-%4d sec, %.2f Mbits/sec\n", cur, cur + interval, + (double)((s_iperf_ctrl.total_len - last_len) * 8) / interval / 1e6); + cur += interval; + last_len = s_iperf_ctrl.total_len; + if (cur >= time) + { + break; + } + } + + if (cur != 0) + { + printf("%4d-%4d sec, %.2f Mbits/sec\n", 0, time, + (double)(s_iperf_ctrl.total_len * 8) / cur / 1e6); + } + + s_iperf_ctrl.finish = true; + + pthread_exit(NULL); +} + +/**************************************************************************** + * Name: iperf_start_report + * + * Description: + * Start iperf report + * + ****************************************************************************/ + +static int iperf_start_report(void) +{ + int ret; + pthread_t thread; + struct sched_param param; + pthread_attr_t attr; + + pthread_attr_init(&attr); + param.sched_priority = IPERF_REPORT_TASK_PRIORITY; + pthread_attr_setschedparam(&attr, ¶m); + pthread_attr_setstacksize(&attr, IPERF_REPORT_TASK_STACK); + + ret = pthread_create(&thread, &attr, (void *)iperf_report_task, + IPERF_REPORT_TASK_NAME); + if (ret != 0) + { + printf("iperf_thread: pthread_create failed: %d, %s\n", + ret, IPERF_REPORT_TASK_NAME); + return -1; + } + + return 0; +} + +/**************************************************************************** + * Name: iperf_run_tcp_server + * + * Description: + * Start tcp server + * + ****************************************************************************/ + +static int iperf_run_tcp_server(void) +{ + socklen_t addr_len = sizeof(struct sockaddr); + struct sockaddr_in remote_addr; + struct sockaddr_in addr; + int actual_recv = 0; + int want_recv = 0; + uint8_t *buffer; + int listen_socket; + struct timeval t; + int sockfd; + int opt; + + listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (listen_socket < 0) + { + iperf_show_socket_error_reason("tcp server create", listen_socket); + return -1; + } + + setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + addr.sin_family = AF_INET; + addr.sin_port = htons(s_iperf_ctrl.cfg.sport); + addr.sin_addr.s_addr = s_iperf_ctrl.cfg.sip; + if (bind(listen_socket, (struct sockaddr *)&addr, sizeof(addr)) != 0) + { + iperf_show_socket_error_reason("tcp server bind", listen_socket); + close(listen_socket); + return -1; + } + + if (listen(listen_socket, 5) < 0) + { + iperf_show_socket_error_reason("tcp server listen", listen_socket); + close(listen_socket); + return -1; + } + + buffer = s_iperf_ctrl.buffer; + want_recv = s_iperf_ctrl.buffer_len; + while (!s_iperf_ctrl.finish) + { + /* TODO need to change to non-block mode */ + + sockfd = accept(listen_socket, (struct sockaddr *)&remote_addr, + &addr_len); + if (sockfd < 0) + { + iperf_show_socket_error_reason("tcp server listen", listen_socket); + close(listen_socket); + return -1; + } + else + { + printf("accept: %s,%d\n", inet_ntoa(remote_addr.sin_addr), + htons(remote_addr.sin_port)); + iperf_start_report(); + + t.tv_sec = IPERF_SOCKET_RX_TIMEOUT; + setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t)); + } + + while (!s_iperf_ctrl.finish) + { + actual_recv = recv(sockfd, buffer, want_recv, 0); + if (actual_recv < 0) + { + iperf_show_socket_error_reason("tcp server recv", + listen_socket); + s_iperf_ctrl.finish = true; + break; + } + else + { + s_iperf_ctrl.total_len += actual_recv; + } + } + + close(sockfd); + } + + s_iperf_ctrl.finish = true; + close(listen_socket); + + return 0; +} + +/**************************************************************************** + * Name: iperf_run_udp_server + * + * Description: + * Start udp server + * + ****************************************************************************/ + +static int iperf_run_udp_server(void) +{ + socklen_t addr_len = sizeof(struct sockaddr_in); + struct sockaddr_in addr; + int actual_recv = 0; + struct timeval t; + int want_recv = 0; + uint8_t *buffer; + int sockfd; + int opt; + bool udp_recv_start = true; + + sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sockfd < 0) + { + iperf_show_socket_error_reason("udp server create", sockfd); + return -1; + } + + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + + addr.sin_family = AF_INET; + addr.sin_port = htons(s_iperf_ctrl.cfg.sport); + addr.sin_addr.s_addr = s_iperf_ctrl.cfg.sip; + if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) != 0) + { + iperf_show_socket_error_reason("udp server bind", sockfd); + return -1; + } + + addr.sin_family = AF_INET; + addr.sin_port = htons(s_iperf_ctrl.cfg.sport); + addr.sin_addr.s_addr = s_iperf_ctrl.cfg.sip; + + buffer = s_iperf_ctrl.buffer; + want_recv = s_iperf_ctrl.buffer_len; + printf("want recv=%d", want_recv); + + t.tv_sec = IPERF_SOCKET_RX_TIMEOUT; + setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t)); + + while (!s_iperf_ctrl.finish) + { + actual_recv = recvfrom(sockfd, buffer, want_recv, 0, + (struct sockaddr *)&addr, &addr_len); + if (actual_recv < 0) + { + iperf_show_socket_error_reason("udp server recv", sockfd); + } + else + { + if (udp_recv_start == true) + { + iperf_start_report(); + udp_recv_start = false; + } + + s_iperf_ctrl.total_len += actual_recv; + } + } + + s_iperf_ctrl.finish = true; + close(sockfd); + + return 0; +} + +/**************************************************************************** + * Name: iperf_run_udp_client + * + * Description: + * Start udp client + * + ****************************************************************************/ + +static int iperf_run_udp_client(void) +{ + struct sockaddr_in addr; + struct iperf_udp_pkt_t *udp; + int actual_send = 0; + bool retry = false; + uint32_t delay = 1; + int want_send = 0; + uint8_t *buffer; + int sockfd; + int opt; + int err; + int id; + + sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sockfd < 0) + { + iperf_show_socket_error_reason("udp client create", sockfd); + return -1; + } + + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + + addr.sin_family = AF_INET; + addr.sin_port = htons(s_iperf_ctrl.cfg.dport); + addr.sin_addr.s_addr = s_iperf_ctrl.cfg.dip; + + iperf_start_report(); + buffer = s_iperf_ctrl.buffer; + udp = (struct iperf_udp_pkt_t *)buffer; + want_send = s_iperf_ctrl.buffer_len; + id = 0; + + while (!s_iperf_ctrl.finish) + { + if (false == retry) + { + id++; + udp->id = htonl(id); + delay = 1; + } + + retry = false; + actual_send = sendto(sockfd, buffer, want_send, 0, + (struct sockaddr *)&addr, sizeof(addr)); + + if (actual_send != want_send) + { + err = iperf_get_socket_error_code(sockfd); + if (err == ENOMEM) + { + usleep(delay * 10000); + if (delay < IPERF_MAX_DELAY) + { + delay <<= 1; + } + + retry = true; + continue; + } + else + { + printf("udp client send abort: err=%d", err); + break; + } + } + else + { + s_iperf_ctrl.total_len += actual_send; + } + } + + s_iperf_ctrl.finish = true; + close(sockfd); + + return 0; +} + +/**************************************************************************** + * Name: iperf_run_tcp_client + * + * Description: + * Start tcp client + * + ****************************************************************************/ + +static int iperf_run_tcp_client(void) +{ + struct sockaddr_in remote_addr; + int actual_send = 0; + int want_send = 0; + uint8_t *buffer; + int sockfd; + + sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sockfd < 0) + { + iperf_show_socket_error_reason("tcp client create", sockfd); + return -1; + } + + memset(&remote_addr, 0, sizeof(remote_addr)); + remote_addr.sin_family = AF_INET; + remote_addr.sin_port = htons(s_iperf_ctrl.cfg.dport); + remote_addr.sin_addr.s_addr = s_iperf_ctrl.cfg.dip; + if (connect(sockfd, (struct sockaddr *)&remote_addr, + sizeof(remote_addr)) < 0) + { + iperf_show_socket_error_reason("tcp client connect", sockfd); + return -1; + } + + iperf_start_report(); + buffer = s_iperf_ctrl.buffer; + want_send = s_iperf_ctrl.buffer_len; + + while (!s_iperf_ctrl.finish) + { + actual_send = send(sockfd, buffer, want_send, 0); + if (actual_send <= 0) + { + iperf_show_socket_error_reason("tcp client send", sockfd); + break; + } + else + { + s_iperf_ctrl.total_len += actual_send; + } + } + + s_iperf_ctrl.finish = true; + close(sockfd); + + return 0; +} + +/**************************************************************************** + * Name: iperf_task_traffic + * + * Description: + * Select to run tcp or udp. + * + ****************************************************************************/ + +static void iperf_task_traffic(void *arg) +{ + if (iperf_is_udp_client()) + { + iperf_run_udp_client(); + } + else if (iperf_is_udp_server()) + { + iperf_run_udp_server(); + } + else if (iperf_is_tcp_client()) + { + iperf_run_tcp_client(); + } + else + { + iperf_run_tcp_server(); + } + + if (s_iperf_ctrl.buffer) + { + free(s_iperf_ctrl.buffer); + s_iperf_ctrl.buffer = NULL; + } + + printf("iperf exit"); + s_iperf_is_running = false; + + pthread_exit(NULL); +} + +static uint32_t iperf_get_buffer_len(void) +{ + if (iperf_is_udp_client()) + { + return IPERF_UDP_TX_LEN; + } + else if (iperf_is_udp_server()) + { + return IPERF_UDP_RX_LEN; + } + else if (iperf_is_tcp_client()) + { + return IPERF_TCP_TX_LEN; + } + else + { + return IPERF_TCP_RX_LEN; + } + + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: iperf_start + * + * Description: + * Start iperf task. + * + ****************************************************************************/ + +int iperf_start(struct iperf_cfg_t *cfg) +{ + int ret; + struct sched_param param; + pthread_t thread; + pthread_attr_t attr; + + if (!cfg) + { + return -1; + } + + if (s_iperf_is_running) + { + printf("iperf is running\n"); + return -1; + } + + memset(&s_iperf_ctrl, 0, sizeof(s_iperf_ctrl)); + memcpy(&s_iperf_ctrl.cfg, cfg, sizeof(*cfg)); + s_iperf_is_running = true; + s_iperf_ctrl.finish = false; + s_iperf_ctrl.buffer_len = iperf_get_buffer_len(); + s_iperf_ctrl.buffer = (uint8_t *)malloc(s_iperf_ctrl.buffer_len); + if (!s_iperf_ctrl.buffer) + { + printf("create buffer: not enough memory\n"); + return -1; + } + + memset(s_iperf_ctrl.buffer, 0, s_iperf_ctrl.buffer_len); + pthread_attr_init(&attr); + param.sched_priority = IPERF_TRAFFIC_TASK_PRIORITY; + pthread_attr_setschedparam(&attr, ¶m); + pthread_attr_setstacksize(&attr, IPERF_TRAFFIC_TASK_STACK); + ret = pthread_create(&thread, &attr, (void *)iperf_task_traffic, + IPERF_TRAFFIC_TASK_NAME); + + if (ret != 0) + { + printf("iperf_task_traffic: create task failed: %d\n", ret); + free(s_iperf_ctrl.buffer); + s_iperf_ctrl.buffer = NULL; + return -1; + } + + return 0; +} + +/**************************************************************************** + * Name: iperf_stop + * + * Description: + * Stop iperf task. + * + ****************************************************************************/ + +int iperf_stop(void) +{ + if (s_iperf_is_running) + { + s_iperf_ctrl.finish = true; + } + + while (s_iperf_is_running) + { + printf("wait current iperf to stop ...\n"); + usleep(300 * 1000); + } + + return 0; +} diff --git a/netutils/iperf/iperf.h b/netutils/iperf/iperf.h new file mode 100644 index 000000000..7a9dbfdaf --- /dev/null +++ b/netutils/iperf/iperf.h @@ -0,0 +1,97 @@ +/**************************************************************************** + * apps/netutils/iperf/iperf.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __IPERF_H_ +#define __IPERF_H_ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define IPERF_FLAG_CLIENT (1) +#define IPERF_FLAG_SERVER (1 << 1) +#define IPERF_FLAG_TCP (1 << 2) +#define IPERF_FLAG_UDP (1 << 3) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct iperf_cfg_t +{ + uint32_t flag; + uint32_t dip; + uint32_t sip; + uint16_t dport; + uint16_t sport; + uint32_t interval; + uint32_t time; +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: iperf_start + * + * Description: + * Start iperf task. + * + ****************************************************************************/ + +int iperf_start(struct iperf_cfg_t *cfg); + +/**************************************************************************** + * Name: iperf_stop + * + * Description: + * Stop iperf task. + * + ****************************************************************************/ + +int iperf_stop(void); + +#ifdef __cplusplus +} +#endif +#undef EXTERN + +#endif /* __ASSEMBLY__ */ +#endif diff --git a/netutils/iperf/iperf_main.c b/netutils/iperf/iperf_main.c new file mode 100644 index 000000000..7e29314a5 --- /dev/null +++ b/netutils/iperf/iperf_main.c @@ -0,0 +1,230 @@ +/**************************************************************************** + * apps/netutils/iperf/iperf_main.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include "netutils/netlib.h" +#include "argtable3.h" +#include "iperf.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_EXAMPLES_IPERFTEST_DEVNAME +# define DEVNAME CONFIG_EXAMPLES_IPERFTEST_DEVNAME +#else +# define DEVNAME "wlan0" +#endif + +#define IPERF_DEFAULT_PORT 5001 +#define IPERF_DEFAULT_INTERVAL 3 +#define IPERF_DEFAULT_TIME 30 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct wifi_iperf_t +{ + struct arg_str *ip; + struct arg_lit *server; + struct arg_lit *udp; + struct arg_int *port; + struct arg_int *interval; + struct arg_int *time; + struct arg_lit *abort; + struct arg_end *end; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: iperf_showusage + * + * Description: + * Show usage of the demo program and exit + * + ****************************************************************************/ + +static void iperf_showusage(FAR const char *progname, int exitcode) +{ + printf("USAGE: %s [-sua] [-c ] [-p ]\ + [-i ] [-t