sdk-hwV1.3/lichee/xr806/appos/project/common/iperf/iperf.c

989 lines
26 KiB
C
Executable File

/*
* Copyright (C) 2017 XRADIO TECHNOLOGY CO., LTD. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* 3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if PRJCONF_NET_EN
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include "kernel/os/os_thread.h"
#include "kernel/os/os_errno.h"
#include "lwip/sockets.h"
#include "lwip/netif.h"
#include "iperf.h"
#include "iperf_debug.h"
#define iperf_errno OS_GetErrno()
#define iperf_msleep(msec) OS_MSleep(msec)
#define IPERF_PORT 5001
#define IPERF_BUF_SIZE (1500)
#define IPERF_UDP_SEND_DATA_LEN (1470) // UDP: 1470 + 8 + 20 = 1498
#define IPERF_TCP_SEND_DATA_LEN (1460) // TCP: 1460 + 20 + 20 = 1500
#define IPERF_THREAD_STACK_SIZE (2 * 1024)
iperf_arg *g_iperf_arg_handle[IPERF_ARG_HANDLE_MAX] = {NULL};
// in 1ms
#define IPERF_TIME_PER_SEC 1000
#define IPERF_TIME() OS_GetTicks()
#define IPERF_SEC_2_INTERVAL(sec) ((sec) * IPERF_TIME_PER_SEC)
#define IPERF_SELECT_TIMEOUT 100
typedef struct {
uint32_t run_time;
uint32_t run_beg_tm;
uint32_t run_end_tm;
uint32_t beg_tm;
uint32_t end_tm;
uint32_t cur_tm;
#if IPERF_OPT_BANDWIDTH
uint32_t send_tm;
uint32_t run_tm;
#endif
uint32_t data_cnt;
uint64_t data_total_cnt;
} iperf_state;
static void iperf_speed_log(iperf_arg *arg, uint64_t bytes, uint32_t time,
int8_t is_end)
{
uint64_t speed;
uint32_t integer_part, decimal_part;
char str[16];
if (arg->flags & IPERF_FLAG_FORMAT) {
/* KBytes/sec */
speed = bytes * IPERF_TIME_PER_SEC * 100 / 1024 / time;
} else {
/* Mbits/sec */
speed = bytes * 8 * IPERF_TIME_PER_SEC * 100 / 1000 / 1000 / time;
}
integer_part = speed / 100;
decimal_part = speed % 100;
if (integer_part >= 100) {
snprintf(str, sizeof(str), "%u", integer_part);
} else if (integer_part >= 10) {
snprintf(str, sizeof(str), "%u.%u", integer_part, decimal_part / 10);
} else {
snprintf(str, sizeof(str), "%u.%02u", integer_part, decimal_part);
}
IPERF_LOG(1, "[%d] %s%s %s\n", arg->handle, is_end ? "TEST END: " : "",
str, (arg->flags & IPERF_FLAG_FORMAT) ? "KB/s" : "Mb/s");
}
static __inline void iperf_udp_seq_set(uint32_t *p, uint32_t seq)
{
*p = htonl(seq);
}
static int iperf_sock_create(int sock_type, short local_port, int do_bind)
{
int local_sock;
struct sockaddr_in local_addr;
int ret, tmp;
local_sock = socket(AF_INET, sock_type, 0);
if (local_sock < 0) {
IPERF_ERR("socket() return %d\n", local_sock);
return local_sock;
}
if (!do_bind)
return local_sock;
tmp = 1;
ret = setsockopt(local_sock, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(int));
if (ret != 0) {
IPERF_ERR("setsockopt(SO_REUSEADDR) failed, err %d\n", iperf_errno);
closesocket(local_sock);
return -1;
}
if (sock_type == SOCK_STREAM) {
tmp = 1;
ret = setsockopt(local_sock, SOL_SOCKET, SO_KEEPALIVE, &tmp, sizeof(int));
if (ret != 0) {
IPERF_ERR("setsockopt(SO_KEEPALIVE) failed, err %d\n", iperf_errno);
closesocket(local_sock);
return -1;
}
}
/* bind socket to port */
memset(&local_addr, 0, sizeof(struct sockaddr_in));
local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
local_addr.sin_port = htons(local_port);
local_addr.sin_family = AF_INET;
ret = bind(local_sock, (struct sockaddr *)&local_addr, sizeof(struct sockaddr_in));
if (ret < 0) {
IPERF_ERR("Failed to bind socket %d, err %d\n", local_sock, iperf_errno);
closesocket(local_sock);
return -1;
}
return local_sock;
}
static int iperf_set_sock_opt(int sock, iperf_arg *idata)
{
int ret;
#if IPERF_OPT_TOS
/* set IP TOS (type-of-service) field */
if (idata->tos > 0) {
int tos = idata->tos;
ret = setsockopt(sock, IPPROTO_IP, IP_TOS, (void *)&tos, sizeof(tos));
if (ret != 0) {
IPERF_ERR("setsockopt(IP_TOS) failed, err %d\n", iperf_errno);
return -1;
}
}
#endif
return 0;
}
static uint8_t *iperf_buf_new(uint32_t size)
{
uint32_t i;
uint8_t *data_buf = malloc(size);
if (data_buf == NULL) {
IPERF_ERR("malloc() failed!\n");
} else {
for (i = 0; i < size; ++i) {
data_buf[i] = '0' + i % 10;
}
}
return data_buf;
}
static __inline int iperf_loop_init(iperf_state *state, iperf_arg *idata)
{
state->run_time = IPERF_SEC_2_INTERVAL(idata->run_time);
state->run_beg_tm = IPERF_TIME();
state->run_end_tm = state->run_beg_tm + state->run_time;
state->beg_tm = state->run_beg_tm;
state->end_tm = state->beg_tm + IPERF_SEC_2_INTERVAL(idata->interval);
state->data_cnt = 0;
state->data_total_cnt = 0;
return 0;
}
static __inline void iperf_calc_speed(iperf_state *state, iperf_arg *idata, int32_t data_len)
{
state->data_cnt += data_len;
state->data_total_cnt += data_len;
state->cur_tm = IPERF_TIME();
if (state->cur_tm > state->end_tm) {
iperf_speed_log(idata, state->data_cnt, state->cur_tm - state->beg_tm, 0);
state->data_cnt = 0;
state->beg_tm = IPERF_TIME();
state->end_tm = state->beg_tm + IPERF_SEC_2_INTERVAL(idata->interval);
}
if (idata->mode_time) {
if (state->run_time && state->cur_tm > state->run_end_tm) {
idata->flags |= IPERF_FLAG_STOP;
}
} else {
if (idata->amount > data_len) {
idata->amount -= data_len;
} else {
idata->amount = 0;
idata->flags |= IPERF_FLAG_STOP;
}
}
if (idata->flags & IPERF_FLAG_STOP) {
iperf_speed_log(idata, state->data_total_cnt, state->cur_tm - state->run_beg_tm, 1);
}
}
static __inline void iperf_calc_speed_fin(iperf_state *state, iperf_arg *idata, int32_t data_len)
{
state->cur_tm = IPERF_TIME();
state->data_total_cnt += data_len;
iperf_speed_log(idata, state->data_total_cnt, state->cur_tm - state->run_beg_tm, 1);
}
#if IPERF_OPT_BANDWIDTH
static __inline void iperf_adjust_bandwidth(iperf_state *state, iperf_arg *idata)
{
if (idata->bandwidth != 0) {
state->run_tm = IPERF_TIME() - state->run_beg_tm;
state->send_tm = state->data_total_cnt * 8 * 1000 / idata->bandwidth;
if (state->send_tm > state->run_tm) {
iperf_msleep(state->send_tm - state->run_tm);
}
}
}
#endif
/* -------------------------------------------------------------------
* Send a datagram on the socket. The datagram's contents should signify
* a FIN to the application. Keep re-transmitting until an
* acknowledgement datagram is received.
* ------------------------------------------------------------------- */
void write_UDP_FIN(int local_sock,
struct sockaddr *remote_addr,
uint8_t *data_buf)
{
int rc;
fd_set readSet;
struct timeval timeout;
struct UDP_datagram *mBuf_UDP = (struct UDP_datagram *) data_buf;
int count = 0;
int packetid;
while (count < 10) {
count++;
// write data
sendto(local_sock, data_buf, IPERF_UDP_SEND_DATA_LEN, 0,
remote_addr, sizeof(*remote_addr));
// decrement the packet count
packetid = ntohl(mBuf_UDP->id);
packetid--;
mBuf_UDP->id = htonl(packetid);
// wait until the socket is readable, or our timeout expires
FD_ZERO(&readSet);
FD_SET(local_sock, &readSet);
timeout.tv_sec = 0;
timeout.tv_usec = 250000; // quarter second, 250 ms
rc = select(local_sock + 1, &readSet, NULL, NULL, &timeout);
if (rc == 0) {
// select timed out
continue;
} else {
// socket ready to read
rc = recvfrom(local_sock, data_buf, IPERF_BUF_SIZE, 0, NULL, 0);
if (rc < 0)
break;
return;
}
}
IPERF_WARN("did not receive ack of last datagram after %d tries.\n", count);
}
/* -------------------------------------------------------------------
* Send an AckFIN (a datagram acknowledging a FIN) on the socket,
* then select on the socket for some time. If additional datagrams
* come in, probably our AckFIN was lost and they are re-transmitted
* termination datagrams, so re-transmit our AckFIN.
* ------------------------------------------------------------------- */
void write_UDP_AckFIN(int local_sock,
struct sockaddr *remote_addr,
uint8_t *data_buf) {
int rc;
fd_set readSet;
FD_ZERO(&readSet);
struct timeval timeout;
int count = 0;
while (count < 10) {
count++;
// write data
sendto(local_sock, data_buf, IPERF_UDP_SEND_DATA_LEN, 0,
remote_addr, sizeof(*remote_addr));
// wait until the socket is readable, or our timeout expires
FD_SET(local_sock, &readSet);
timeout.tv_sec = 1;
timeout.tv_usec = 0;
rc = select(local_sock + 1, &readSet, NULL, NULL, &timeout);
if (rc == 0) {
// select timed out
return;
} else {
// socket ready to read
rc = recvfrom(local_sock, data_buf, IPERF_BUF_SIZE, 0, NULL, 0);
if (rc <= 0) {
// Connection closed or errored
// Stop using it.
return;
}
}
}
IPERF_WARN("ack of last datagram failed after %d tries.\n", count);
}
void iperf_udp_send_task(void *arg)
{
int local_sock = -1;
struct sockaddr_in remote_addr;
iperf_arg *idata = (iperf_arg *)arg;
iperf_state istate;
uint32_t port = idata->port;
uint8_t *data_buf = NULL;
int32_t data_len;
int packetID = 0;
struct UDP_datagram *mBuf_UDP;
local_sock = iperf_sock_create(SOCK_DGRAM, 0, 1);
if (local_sock < 0) {
IPERF_ERR("socket() return %d\n", local_sock);
goto socket_error;
}
iperf_set_sock_opt(local_sock, idata);
data_buf = iperf_buf_new(IPERF_BUF_SIZE);
if (data_buf == NULL) {
IPERF_ERR("malloc() failed!\n");
goto socket_error;
}
memset(&remote_addr, 0, sizeof(struct sockaddr_in));
inet_aton(idata->remote_ip, &remote_addr.sin_addr);
remote_addr.sin_port = htons(port);
remote_addr.sin_family = AF_INET;
IPERF_DBG("iperf: UDP send to %s:%d\n", idata->remote_ip, port);
mBuf_UDP = (struct UDP_datagram *) data_buf;
mBuf_UDP->id = htonl(packetID);
iperf_loop_init(&istate, idata);
while (!(idata->flags & IPERF_FLAG_STOP)) {
#if IPERF_OPT_BANDWIDTH
iperf_adjust_bandwidth(&istate, idata);
#endif
data_len = sendto(local_sock, data_buf, IPERF_UDP_SEND_DATA_LEN, 0,
(struct sockaddr *)&remote_addr, sizeof(remote_addr));
if (data_len > 0) {
packetID++;
mBuf_UDP->id = htonl(packetID);
} else {
data_len = 0;
}
iperf_calc_speed(&istate, idata, data_len);
}
mBuf_UDP->id = htonl(-packetID);
write_UDP_FIN(local_sock, (struct sockaddr *)&remote_addr, data_buf);
socket_error:
if (data_buf)
free(data_buf);
if (local_sock >= 0)
closesocket(local_sock);
OS_Thread_t thread = idata->iperf_thread;
iperf_handle_free(idata->handle);
IPERF_DBG("%s() [%d] exit!\n", __func__, idata->handle);
OS_ThreadDelete(&thread);
}
void iperf_udp_recv_task(void *arg)
{
int local_sock = -1;
struct sockaddr_in remote_addr;
socklen_t addr_len = sizeof(remote_addr);
iperf_arg *idata = (iperf_arg *)arg;
iperf_state istate;
uint32_t port = idata->port;
uint8_t *data_buf = NULL;
int32_t data_len;
int timeout = IPERF_SELECT_TIMEOUT; //ms
int packetID = 0;
struct UDP_datagram *mBuf_UDP;
uint8_t wait = 1;
if (port == 0) {
port = IPERF_PORT;
}
local_sock = iperf_sock_create(SOCK_DGRAM, port, 1);
if (local_sock < 0) {
IPERF_ERR("socket() return %d\n", local_sock);
goto socket_error;
}
iperf_set_sock_opt(local_sock, idata);
data_buf = iperf_buf_new(IPERF_BUF_SIZE);
if (data_buf == NULL) {
IPERF_ERR("malloc() failed!\n");
goto socket_error;
}
IPERF_DBG("iperf: UDP recv at port %d\n", port);
#if IPERF_OPT_NUM
idata->mode_time = 1;
#endif
if (setsockopt(local_sock, SOL_SOCKET, SO_RCVTIMEO,
(char *)&timeout, sizeof(timeout)) < 0) {
IPERF_ERR("set socket option err %d\n", iperf_errno);
goto socket_error;
}
mBuf_UDP = (struct UDP_datagram *)data_buf;
iperf_loop_init(&istate, idata);
while (!(idata->flags & IPERF_FLAG_STOP)) {
data_len = recvfrom(local_sock, data_buf, IPERF_BUF_SIZE, 0,
(struct sockaddr *)&remote_addr, &addr_len);
if (data_len > 0) {
if (wait) {
wait = 0;
iperf_loop_init(&istate, idata); // reinitialization time
IPERF_DBG("iperf udp_recv_task reinit time and reclocking\n");
}
} else {
data_len = 0;
}
packetID = ntohl(mBuf_UDP->id);
if (packetID < 0) {
iperf_calc_speed_fin(&istate, idata, data_len);
IPERF_DBG("iperf udp_recv_task receive a FIN datagram\n");
write_UDP_AckFIN(local_sock, (struct sockaddr *)&remote_addr,
data_buf);
break;
}
iperf_calc_speed(&istate, idata, data_len);
}
socket_error:
if (data_buf)
free(data_buf);
if (local_sock >= 0)
closesocket(local_sock);
OS_Thread_t thread = idata->iperf_thread;
iperf_handle_free(idata->handle);
IPERF_DBG("%s() [%d] exit!\n", __func__, idata->handle);
OS_ThreadDelete(&thread);
}
void iperf_tcp_send_task(void *arg)
{
int local_sock = -1;
struct sockaddr_in remote_addr;
iperf_arg *idata = (iperf_arg *)arg;
iperf_state istate;
uint32_t port = idata->port;
uint8_t *data_buf = NULL;
int32_t data_len;
int ret;
fd_set fdw;
struct timeval tv;
// OS_MSleep(1); // enable task create function return
local_sock = iperf_sock_create(SOCK_STREAM, 0, 0);
if (local_sock < 0) {
IPERF_ERR("socket() return %d\n", local_sock);
goto socket_error;
}
iperf_set_sock_opt(local_sock, idata);
data_buf = iperf_buf_new(IPERF_BUF_SIZE);
if (data_buf == NULL) {
IPERF_ERR("malloc() failed!\n");
goto socket_error;
}
uint32_t i = 1;
ret = ioctlsocket(local_sock, FIONBIO, &i);
if (ret < 0) {
IPERF_ERR("ioctlsocket() return %d\n", ret);
goto socket_error;
}
memset(&remote_addr, 0, sizeof(struct sockaddr_in));
inet_aton(idata->remote_ip, &remote_addr.sin_addr);
remote_addr.sin_port = htons(port);
remote_addr.sin_family = AF_INET;
ret = connect(local_sock, (struct sockaddr *)&remote_addr, sizeof(remote_addr));
if (ret != 0) {
if (errno != EINPROGRESS) {
IPERF_ERR("connect() return %d\n", ret);
goto socket_error;
} else {
while (!(idata->flags & IPERF_FLAG_STOP)) {
FD_ZERO(&fdw);
FD_SET(local_sock, &fdw);
tv.tv_sec = 0;
tv.tv_usec = 100000; //100ms
ret = select(local_sock + 1, NULL, &fdw, NULL, &tv);
if (ret > 0) {
if (FD_ISSET(local_sock, &fdw)) {
break;
}
} else if (ret < 0) {
IPERF_ERR("socket select err! errno:%d\n", errno);
goto socket_error;
} else if (ret == 0) {
continue;
}
}
if (idata->flags & IPERF_FLAG_STOP)
goto socket_error;
}
}
IPERF_DBG("iperf: TCP send to %s:%d\n", idata->remote_ip, port);
iperf_loop_init(&istate, idata);
while (!(idata->flags & IPERF_FLAG_STOP)) {
FD_ZERO(&fdw);
FD_SET(local_sock, &fdw);
tv.tv_sec = 0;
tv.tv_usec = 100000; //100ms
ret = select(local_sock + 1, NULL, &fdw, NULL, &tv);
if (ret > 0) {
if (FD_ISSET(local_sock, &fdw)) {
data_len = send(local_sock, data_buf, IPERF_TCP_SEND_DATA_LEN, 0);
if (data_len <= 0) {
IPERF_WARN("send return %d, err %d\n", data_len, iperf_errno);
break;
}
iperf_calc_speed(&istate, idata, data_len);
}
} else if (ret < 0) {
IPERF_ERR("socket select err! errno:%d\n", errno);
goto socket_error;
} else if (ret == 0) {
continue;
}
}
socket_error:
if (data_buf)
free(data_buf);
if (local_sock >= 0)
closesocket(local_sock);
OS_Thread_t thread = idata->iperf_thread;
iperf_handle_free(idata->handle);
IPERF_DBG("%s() [%d] exit!\n", __func__, idata->handle);
OS_ThreadDelete(&thread);
}
void iperf_tcp_recv_task(void *arg)
{
int local_sock = -1;
int remote_sock = -1;
struct sockaddr_in remote_addr;
iperf_arg *idata = (iperf_arg *)arg;
iperf_state istate;
uint32_t port = idata->port;
uint8_t *data_buf = NULL;
int32_t data_len;
int ret;
int timeout = IPERF_SELECT_TIMEOUT; //ms
local_sock = iperf_sock_create(SOCK_STREAM, port, 1);
if (local_sock < 0) {
IPERF_ERR("socket() return %d\n", local_sock);
goto socket_error;
}
iperf_set_sock_opt(local_sock, idata);
data_buf = iperf_buf_new(IPERF_BUF_SIZE);
if (data_buf == NULL) {
IPERF_ERR("malloc() failed!\n");
goto socket_error;
}
IPERF_DBG("iperf: TCP listen at port %d\n", port);
ret = listen(local_sock, 5);
if (ret < 0) {
IPERF_ERR("Failed to listen socket %d, err %d\n", local_sock, iperf_errno);
goto socket_error;
}
ret = sizeof(struct sockaddr_in);
/* Set the recv timeout to set the accept timeout */
if (setsockopt(local_sock, SOL_SOCKET, SO_RCVTIMEO,
(char *)&timeout, sizeof(timeout)) < 0) {
IPERF_ERR("set socket option err %d\n", iperf_errno);
goto socket_error;
}
while (!(idata->flags & IPERF_FLAG_STOP)) {
remote_sock = accept(local_sock, (struct sockaddr *)&remote_addr,
(socklen_t *)&ret);
if (remote_sock >= 0) {
iperf_set_sock_opt(remote_sock, idata);
break;
}
}
if (!(idata->flags & IPERF_FLAG_STOP)) {
IPERF_DBG("iperf: client from %s:%d\n", inet_ntoa(remote_addr.sin_addr),
ntohs(remote_addr.sin_port));
}
#if IPERF_OPT_NUM
idata->mode_time = 1;
#endif
iperf_loop_init(&istate, idata);
while (!(idata->flags & IPERF_FLAG_STOP)) {
data_len = recv(remote_sock, data_buf, IPERF_BUF_SIZE, 0);
if (data_len <= 0) {
iperf_calc_speed_fin(&istate, idata, data_len);
IPERF_WARN("recv return %d, err %d\n", data_len, iperf_errno);
break;
}
iperf_calc_speed(&istate, idata, data_len);
}
socket_error:
if (remote_sock)
closesocket(remote_sock);
if (data_buf)
free(data_buf);
if (local_sock >= 0)
closesocket(local_sock);
OS_Thread_t thread = idata->iperf_thread;
iperf_handle_free(idata->handle);
IPERF_DBG("%s() [%d] exit!\n", __func__, idata->handle);
OS_ThreadDelete(&thread);
}
static const OS_ThreadEntry_t iperf_thread_entry[IPERF_MODE_NUM] = {
iperf_udp_send_task,
iperf_udp_recv_task,
iperf_tcp_send_task,
iperf_tcp_recv_task,
}; /* index by enum IPERF_MODE */
int iperf_handle_start(struct netif *nif, int handle)
{
if (nif == NULL || handle < 0 || handle >= IPERF_ARG_HANDLE_MAX)
return -1;
if (OS_ThreadIsValid(&(g_iperf_arg_handle[handle]->iperf_thread))) {
IPERF_ERR("iperf task is running\n");
return -1;
}
g_iperf_arg_handle[handle]->flags &= ~IPERF_FLAG_STOP; /* clean stop flag */
if (OS_ThreadCreate(&(g_iperf_arg_handle[handle]->iperf_thread),
"iperf",
iperf_thread_entry[g_iperf_arg_handle[handle]->mode],
(void *)g_iperf_arg_handle[handle],
OS_THREAD_PRIO_APP,
IPERF_THREAD_STACK_SIZE) != OS_OK) {
IPERF_ERR("iperf task create failed\n");
return -1;
}
return 0;
}
int iperf_handle_stop(int handle)
{
if ((handle < 0) || (handle >= IPERF_ARG_HANDLE_MAX))
return -1;
if (g_iperf_arg_handle[handle] != NULL) {
if (OS_ThreadIsValid(&(g_iperf_arg_handle[handle]->iperf_thread))) {
g_iperf_arg_handle[handle]->flags |= IPERF_FLAG_STOP;
} else {
IPERF_ERR("iperf task %d not exist.\n", handle);
return -1;
}
}
return 0;
}
int iperf_start(struct netif *nif, int handle)
{
return iperf_handle_start(nif, handle);
}
int iperf_stop(char *arg)
{
int i;
int handle = 0;
if (strcmp("a", arg) == 0) {
for (i = 0; i < IPERF_ARG_HANDLE_MAX; i++) {
if (g_iperf_arg_handle[i] != NULL) {
iperf_handle_stop(i);
}
}
return 0;
}
handle = atoi(arg);
if (handle < 0 || handle >= IPERF_ARG_HANDLE_MAX ||
(handle == 0 && strcmp("0", arg))) {
IPERF_DBG("handle '%s' input err\n", arg);
return -1;
}
return iperf_handle_stop(handle);
}
int iperf_handle_new(iperf_arg *arg)
{
int i = 0, pos = 0, find = 0;
if (arg == NULL)
return -1;
for (i = 0; i < IPERF_ARG_HANDLE_MAX; i++) {
if (g_iperf_arg_handle[i] == NULL) {
if (!find) {
find = 1;
pos = i;
if ((arg->mode & IPERF_MODE_TCP_SEND) ||
(arg->mode & IPERF_MODE_UDP_SEND))
break;
}
} else {
if ((arg->mode & IPERF_MODE_TCP_RECV) ||
(arg->mode & IPERF_MODE_UDP_RECV)) {
if (g_iperf_arg_handle[i]->port == arg->port) {
IPERF_DBG("the port %d has been used\n", arg->port);
return -1;
}
}
}
}
if (find) {
g_iperf_arg_handle[pos] = malloc(sizeof(iperf_arg));
if (g_iperf_arg_handle[pos] == NULL) {
IPERF_ERR("iperf malloc faild\n");
return -1;
}
memcpy(g_iperf_arg_handle[pos], arg, sizeof(iperf_arg));
g_iperf_arg_handle[pos]->handle = pos;
return pos;
}
IPERF_DBG("cannot new more handle, buf is full\n");
return -1;
}
int iperf_handle_free(int handle)
{
if (handle < 0 || handle >= IPERF_ARG_HANDLE_MAX)
return -1;
if (g_iperf_arg_handle[handle] != NULL) {
free(g_iperf_arg_handle[handle]);
g_iperf_arg_handle[handle] = NULL;
}
return 0;
}
static const char *iperf_mode_str[IPERF_MODE_NUM] = {
"udp-send",
"udp-recv",
"tcp-send",
"tcp-recv",
};
int iperf_show_list(void)
{
int i = 0;
int run_num = 0;
for (i = 0; i < IPERF_ARG_HANDLE_MAX; i++) {
if (g_iperf_arg_handle[i] != NULL) {
run_num++;
IPERF_LOG(1, "\nhandle = %d\n", i);
IPERF_LOG(1, "mode = %s\n",
iperf_mode_str[g_iperf_arg_handle[i]->mode]);
IPERF_LOG(1, "remote ip = %s\n", g_iperf_arg_handle[i]->remote_ip);
IPERF_LOG(1, "port = %u\n", g_iperf_arg_handle[i]->port);
IPERF_LOG(1, "run time = %u\n", g_iperf_arg_handle[i]->run_time);
IPERF_LOG(1, "interval = %u\n\n", g_iperf_arg_handle[i]->interval);
}
}
if (!run_num)
return -1;
return 0;
}
int iperf_parse_argv(int argc, char *argv[])
{
iperf_arg iperf_arg_t;
uint32_t port;
int opt = 0;
char *short_opts = "LusQ:c:f:p:t:i:b:n:S:";
memset(&iperf_arg_t, 0, sizeof(iperf_arg_t));
#if IPERF_OPT_BANDWIDTH
iperf_arg_t.bandwidth = 1000 * 1000; /* default to 1Mbits/sec */
#endif
#if IPERF_OPT_NUM
iperf_arg_t.mode_time = 1;
#endif
optind = 0; /* reset the index */
//opterr = 0; /* close the "invalid option" warning */
while ((opt = getopt(argc, argv, short_opts)) != -1) {
//IPERF_DBG("opt=%c\n", opt);
switch (opt) {
case 'f':
if (strcmp("m", optarg) == 0)
iperf_arg_t.flags &= ~IPERF_FLAG_FORMAT;
else if (strcmp("K", optarg) == 0)
iperf_arg_t.flags |= IPERF_FLAG_FORMAT;
else {
IPERF_ERR("invalid format arg '%s'\n", optarg);
return -1;
}
break;
case 'p':
port = (uint32_t)atoi(optarg);
if (port > 65535 || port == 0) {
IPERF_ERR("invalid port arg '%s'\n", optarg);
return -1;
} else {
iperf_arg_t.port = port;
iperf_arg_t.flags |= IPERF_FLAG_PORT;
}
break;
case 'u':
iperf_arg_t.flags |= IPERF_FLAG_UDP;
break;
case 's':
iperf_arg_t.flags |= IPERF_FLAG_SERVER;
break;
case 'c':
if (inet_addr(optarg) == INADDR_NONE) {
IPERF_ERR("invalid ip arg '%s'\n", optarg);
return -1;
} else {
snprintf(iperf_arg_t.remote_ip, IPERF_ADDR_STRLEN_MAX, optarg);
iperf_arg_t.flags |= IPERF_FLAG_CLINET;
}
break;
case 'i':
iperf_arg_t.interval = (uint32_t)atoi(optarg);
break;
case 't':
iperf_arg_t.run_time = (uint32_t)atoi(optarg);
break;
case 'Q':
iperf_stop(optarg);
return -2;
case 'L':
if (iperf_show_list())
IPERF_DBG("no task running\n");
return -2;
#if IPERF_OPT_BANDWIDTH
case 'b': {
float value;
char suffix = '\0';
sscanf(optarg, "%f%c", &value, &suffix);
if (suffix == 'm' || suffix == 'M') {
value *= 1000 * 1000;
} else if (suffix == 'k' || suffix == 'K') {
value *= 1000;
}
iperf_arg_t.bandwidth = value;
break;
}
#endif
#if IPERF_OPT_NUM
case 'n': {
uint32_t value;
char suffix = '\0';
sscanf(optarg, "%u%c", &value, &suffix);
iperf_arg_t.mode_time = 0;
iperf_arg_t.amount = value;
if (suffix == 'm' || suffix == 'M') {
iperf_arg_t.amount *= 1024 * 1024;
} else if (suffix == 'k' || suffix == 'K') {
iperf_arg_t.amount *= 1024;
}
break;
}
#endif
#if IPERF_OPT_TOS
case 'S':
iperf_arg_t.tos = (uint16_t)strtol(optarg, NULL, 0);
break;
#endif
default:
return -1;
}
}
/* set the default interval time 1 second */
if (!iperf_arg_t.interval)
iperf_arg_t.interval = 1;
/* Cannot be client and server simultaneously */
uint32_t flag = IPERF_FLAG_SERVER | IPERF_FLAG_CLINET;
if ((iperf_arg_t.flags & flag) == 0 || (~iperf_arg_t.flags & flag) == 0) {
IPERF_ERR("invalid iperf cmd\n");
return -1;
}
if (iperf_arg_t.port == 0)
iperf_arg_t.port = IPERF_PORT;
if ((iperf_arg_t.flags & IPERF_FLAG_UDP) == IPERF_FLAG_UDP) {
if ((iperf_arg_t.flags & IPERF_FLAG_SERVER) == IPERF_FLAG_SERVER)
iperf_arg_t.mode = IPERF_MODE_UDP_RECV;
else
iperf_arg_t.mode = IPERF_MODE_UDP_SEND;
} else {
if ((iperf_arg_t.flags & IPERF_FLAG_SERVER) == IPERF_FLAG_SERVER)
iperf_arg_t.mode = IPERF_MODE_TCP_RECV;
else
iperf_arg_t.mode = IPERF_MODE_TCP_SEND;
}
int handle = iperf_handle_new(&iperf_arg_t);
return handle;
}
#endif /* PRJCONF_NET_EN */