You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2021/01/07 14:43:36 UTC
[incubator-nuttx-apps] branch master updated: netutils/iperf: Add
iperf example.
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx-apps.git
The following commit(s) were added to refs/heads/master by this push:
new 756dc32 netutils/iperf: Add iperf example.
756dc32 is described below
commit 756dc32fd093ca4285f3cd88c5561f41be651cf3
Author: chenwen <ch...@espressif.com>
AuthorDate: Fri Dec 4 16:16:12 2020 +0800
netutils/iperf: Add iperf example.
system/argtable3: Add an ANSI C library for command-line parsing.
---
netutils/iperf/Kconfig | 37 +++
netutils/iperf/Make.defs | 24 ++
netutils/iperf/Makefile | 35 +++
netutils/iperf/README.md | 87 ++++++
netutils/iperf/iperf.c | 722 ++++++++++++++++++++++++++++++++++++++++++++
netutils/iperf/iperf.h | 97 ++++++
netutils/iperf/iperf_main.c | 230 ++++++++++++++
system/argtable3/.gitignore | 2 +
system/argtable3/Kconfig | 18 ++
system/argtable3/Make.defs | 27 ++
system/argtable3/Makefile | 54 ++++
11 files changed, 1333 insertions(+)
diff --git a/netutils/iperf/Kconfig b/netutils/iperf/Kconfig
new file mode 100644
index 0000000..0c4f008
--- /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 0000000..13effb7
--- /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 0000000..437675c
--- /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 0000000..ea95f13
--- /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 0000000..b24764d
--- /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 <sys/socket.h>
+#include <sys/time.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#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 0000000..7a9dbfd
--- /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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#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 0000000..7e29314
--- /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 <nuttx/config.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#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 <ip>] [-p <port>]\
+ [-i <interval>] [-t <time>]\n", progname);
+ printf("iperf command:\n");
+ printf(" -c, --client=<ip> run in client mode,\
+ connecting to <host>\n");
+ printf(" -s, --server run in server mode\n");
+ printf(" -u, --udp use UDP rather than TCP\n");
+ printf(" -p, --port=<port> server port to listen on/connect to\n");
+ printf(" -i, --interval=<interval>\
+ seconds between periodic bandwidth reports\n");
+ printf(" -t, --time=<time>\
+ time in seconds to transmit for (default 10 secs)\n");
+ printf(" -a, --abort abort running iperf\n");
+ printf("\n");
+ exit(exitcode);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int main(int argc, FAR char *argv[])
+{
+ struct wifi_iperf_t iperf_args;
+ struct iperf_cfg_t cfg;
+ struct in_addr addr;
+ int nerrors;
+
+ bzero(&addr, sizeof(struct in_addr));
+ bzero(&cfg, sizeof(cfg));
+
+ iperf_args.ip = arg_str0("c", "client", "<ip>",
+ "run in client mode, connecting to <host>");
+ iperf_args.server = arg_lit0("s", "server", "run in server mode");
+ iperf_args.udp = arg_lit0("u", "udp", "use UDP rather than TCP");
+ iperf_args.port = arg_int0("p", "port", "<port>",
+ "server port to listen on/connect to");
+ iperf_args.interval = arg_int0("i", "interval", "<interval>",
+ "seconds between periodic bandwidth reports");
+ iperf_args.time = arg_int0("t", "time", "<time>",
+ "time in seconds to transmit for (default 10 secs)");
+ iperf_args.abort = arg_lit0("a", "abort", "abort running iperf");
+ iperf_args.end = arg_end(1);
+
+ nerrors = arg_parse(argc, argv, (void**) &iperf_args);
+ if (nerrors != 0)
+ {
+ arg_print_errors(stderr, iperf_args.end, argv[0]);
+ iperf_showusage(argv[0], 0);
+ }
+
+ if (iperf_args.abort->count != 0)
+ {
+ iperf_stop();
+ printf("ERROR: abort->count: %d\n", iperf_args.abort->count);
+ iperf_showusage(argv[0], 0);
+ }
+
+ if (((iperf_args.ip->count == 0) && (iperf_args.server->count == 0)) ||
+ ((iperf_args.ip->count != 0) && (iperf_args.server->count != 0)))
+ {
+ printf("ERROR: should specific client/server mode\n");
+ iperf_showusage(argv[0], 0);
+ }
+
+ if (iperf_args.ip->count == 0)
+ {
+ cfg.flag |= IPERF_FLAG_SERVER;
+ }
+ else
+ {
+ cfg.dip = inet_addr(iperf_args.ip->sval[0]);
+ cfg.flag |= IPERF_FLAG_CLIENT;
+ }
+
+ addr.s_addr = 0;
+ netlib_get_ipv4addr(DEVNAME, &addr);
+ if (addr.s_addr == 0)
+ {
+ printf("ERROR: access IP is 0x00 \n");
+ return -1;
+ }
+
+ printf(" IP: %s\n", inet_ntoa(addr));
+
+ cfg.sip = addr.s_addr;
+
+ if (iperf_args.udp->count == 0)
+ {
+ cfg.flag |= IPERF_FLAG_TCP;
+ }
+ else
+ {
+ cfg.flag |= IPERF_FLAG_UDP;
+ }
+
+ if (iperf_args.port->count == 0)
+ {
+ cfg.sport = IPERF_DEFAULT_PORT;
+ cfg.dport = IPERF_DEFAULT_PORT;
+ }
+ else
+ {
+ if (cfg.flag & IPERF_FLAG_SERVER)
+ {
+ cfg.sport = iperf_args.port->ival[0];
+ cfg.dport = IPERF_DEFAULT_PORT;
+ }
+ else
+ {
+ cfg.sport = IPERF_DEFAULT_PORT;
+ cfg.dport = iperf_args.port->ival[0];
+ }
+ }
+
+ if (iperf_args.interval->count == 0)
+ {
+ cfg.interval = IPERF_DEFAULT_INTERVAL;
+ }
+ else
+ {
+ cfg.interval = iperf_args.interval->ival[0];
+ if (cfg.interval <= 0)
+ {
+ cfg.interval = IPERF_DEFAULT_INTERVAL;
+ }
+ }
+
+ if (iperf_args.time->count == 0)
+ {
+ cfg.time = IPERF_DEFAULT_TIME;
+ }
+ else
+ {
+ cfg.time = iperf_args.time->ival[0];
+ if (cfg.time <= cfg.interval)
+ {
+ cfg.time = cfg.interval;
+ }
+ }
+
+ printf("\n mode=%s-%s sip=%d.%d.%d.%d:%d,\
+ dip=%d.%d.%d.%d:%d, interval=%d, time=%d\n",
+ cfg.flag & IPERF_FLAG_TCP ?"tcp":"udp",
+ cfg.flag & IPERF_FLAG_SERVER ?"server":"client",
+ cfg.sip & 0xff, (cfg.sip >> 8) & 0xff, (cfg.sip >> 16) & 0xff,
+ (cfg.sip >> 24) & 0xff, cfg.sport,
+ cfg.dip & 0xff, (cfg.dip >> 8) & 0xff, (cfg.dip >> 16) & 0xff,
+ (cfg.dip >> 24) & 0xff, cfg.dport,
+ cfg.interval, cfg.time);
+ iperf_start(&cfg);
+
+ return 0;
+}
diff --git a/system/argtable3/.gitignore b/system/argtable3/.gitignore
new file mode 100644
index 0000000..71fd725
--- /dev/null
+++ b/system/argtable3/.gitignore
@@ -0,0 +1,2 @@
+/argtable3*
+/v*.tar.gz
diff --git a/system/argtable3/Kconfig b/system/argtable3/Kconfig
new file mode 100644
index 0000000..acaa3ca
--- /dev/null
+++ b/system/argtable3/Kconfig
@@ -0,0 +1,18 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+config SYSTEM_ARGTABLE3
+ bool "ARGTABLE3 library"
+ default n
+ ---help---
+ Enables the ARGTABLE3 library.
+
+if SYSTEM_ARGTABLE3
+
+config SYSTEM_ARGTABLE3_VERSION
+ string "ARGTABLE3 Version"
+ default "3.0.0"
+
+endif
diff --git a/system/argtable3/Make.defs b/system/argtable3/Make.defs
new file mode 100644
index 0000000..5c7a759
--- /dev/null
+++ b/system/argtable3/Make.defs
@@ -0,0 +1,27 @@
+############################################################################
+# apps/system/argtable3/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_SYSTEM_ARGTABLE3),)
+CONFIGURED_APPS += $(APPDIR)/system/argtable3
+
+CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" "$(APPDIR)/system/argtable3/argtable3/"}
+CXXFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" "$(APPDIR)/system/argtable3/argtable3/"}
+endif
diff --git a/system/argtable3/Makefile b/system/argtable3/Makefile
new file mode 100644
index 0000000..c696ed6
--- /dev/null
+++ b/system/argtable3/Makefile
@@ -0,0 +1,54 @@
+############################################################################
+# apps/system/argtable3/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
+
+ARGTABLE3_VERSION := $(patsubst "%",%,$(CONFIG_SYSTEM_ARGTABLE3_VERSION))
+ARGTABLE3_TARBALL = v$(ARGTABLE3_VERSION).tar.gz
+ARGTABLE3_UNPACK = argtable3
+ARGTABLE3_SRCDIR = $(ARGTABLE3_UNPACK)
+
+DEPPATH += --dep-path $(ARGTABLE3_SRCDIR)
+VPATH += :$(ARGTABLE3_SRCDIR)
+
+CSRCS := $(notdir $(wildcard $(ARGTABLE3_SRCDIR)$(DELIM)argtable3.c))
+
+$(ARGTABLE3_TARBALL):
+ $(Q) echo "Downloading argtable3-$(ARGTABLE3_VERSION)"
+ $(Q) echo "$(ARGTABLE3_SRCDIR)"
+ $(Q) echo "$(ARGTABLE3_TARBALL)--$(ARGTABLE3_UNPACK)"
+ $(Q) wget https://github.com/argtable/argtable3/archive/$(ARGTABLE3_TARBALL)
+
+$(ARGTABLE3_UNPACK): $(ARGTABLE3_TARBALL)
+ $(Q) tar zxf $(ARGTABLE3_TARBALL)
+ $(Q) mv argtable3-$(ARGTABLE3_VERSION) $(ARGTABLE3_UNPACK)
+ $(Q) echo "Patching $(ARGTABLE3_UNPACK)"
+ $(Q) patch -p0 < argtable3.patch
+
+$(ARGTABLE3_UNPACK)/.patch: $(ARGTABLE3_UNPACK)
+ $(Q) touch $(ARGTABLE3_UNPACK)/.patch
+
+context:: $(ARGTABLE3_UNPACK)/.patch
+
+distclean::
+ $(call DELFILE, $(ARGTABLE3_TARBALL))
+ $(call DELDIR, $(ARGTABLE3_UNPACK))
+
+include $(APPDIR)/Application.mk