2025-10-10 16:07:00 +08:00

1142 lines
27 KiB
C

/**
* iperf-liked network performance tool
*
*/
#include <common/bk_include.h>
#include <os/mem.h>
#include <os/str.h>
#include <os/os.h>
#include "bk_cli.h"
#include "bk_fake_clock.h"
#include <lwip/sockets.h>
#include <stdlib.h>
#include <components/system.h>
#ifndef CONFIG_IPV6
#include <components/netif.h>
#include "net.h"
#endif
#include "bk_misc.h"
#define TAG "IPERF"
#define THREAD_SIZE (4 * 1024)
#define THREAD_PROIRITY 4
#define IPERF_REPORT_TASK_PRIORITY 3
#define IPERF_PORT 5001
#define IPERF_BUFSZ (8 * 1024)
#define IPERF_TX_TIMEOUT_SEC (3)
#define IPERF_RX_TIMEOUT_SEC (3)
#define IPERF_MAX_TX_RETRY 10
#define IPERF_MAX_RX_RETRY 10
#define IPERF_REPORT_INTERVAL 1
#define IPERF_INVALID_INDEX (-1)
#define IPERF_DEFAULT_SPEED_LIMIT (-1)
#define IPERF_REPORT_TASK_NAME "iperf_report_task"
#define IPERF_REPORT_TASK_STACK 2048
#define IPERF_UDP_FIN_MAX_RETRY_CNTS 10 /* UDP FIN or FINACK max retries */
#define IPERF_UDP_FIN_TO 250000 /* 250ms: select timeout for UDP FIN */
#define IPERF_UDP_FINACK_TO 1 /* 1s: select timeout for UDP FINACK */
#define IPERF_DEFAULT_TIME 30
#define UDP_HEADER_FLAG 0x80000000
#define IPERF_THOUSAND_UNIT 1000 /* 1000 */
#define IPERF_MILLION_UNIT 1000000 /* 1000 * 1000 */
#define IPERF_KILO_UNIT 0x400 /* 1024 */
#define IPERF_MEGA_UNIT 0x100000 /* 1024 * 1024 */
enum {
IPERF_STATE_STOPPED = 0,
IPERF_STATE_STOPPING,
IPERF_STATE_STARTED,
};
enum {
IPERF_MODE_NONE = 0,
IPERF_MODE_TCP_SERVER,
IPERF_MODE_TCP_CLIENT,
IPERF_MODE_UDP_SERVER,
IPERF_MODE_UDP_CLIENT,
IPERF_MODE_UNKNOWN,
};
typedef struct {
int32_t id;
uint32_t sec;
uint32_t usec;
} iperf_udp_hdr_t;
typedef struct {
int32_t flags;
int32_t totalLenH;
int32_t totalLenL;
int32_t endSec;
int32_t endUsec;
int32_t errCnt;
int32_t oooCnt;
int32_t datagrams;
int32_t jitterSec;
int32_t jitterUsec;
} iperf_udp_server_hdr_t;
typedef struct {
int state;
int mode;
char *host;
int port;
uint32_t interval;
} iperf_param_t;
static iperf_param_t s_param = {
IPERF_STATE_STOPPED,
IPERF_MODE_NONE, NULL,
IPERF_PORT,
IPERF_REPORT_INTERVAL
};
static uint32_t s_tick_last = 0;
static uint32_t s_tick_delta = 0;
static uint32_t s_pkt_delta = 0;
static uint32_t s_time = IPERF_DEFAULT_TIME;
//modifiable iperf parameters
//priority of iperf task
static uint32_t iperf_priority = THREAD_PROIRITY;
static uint32_t iperf_report_priority = IPERF_REPORT_TASK_PRIORITY;
//data size of iperf
static uint32_t iperf_size = IPERF_BUFSZ;
static int speed_limit = IPERF_DEFAULT_SPEED_LIMIT;
// TOS
static uint32_t iperf_tos = 0; // TOS_BE: 0, BK: 0x20, VI: 0xA0, VO: 0xD0
#if (CONFIG_TASK_WDT)
extern void bk_task_wdt_feed(void);
#endif
static void iperf_reset(void)
{
s_param.mode = IPERF_MODE_NONE;
if (s_param.host)
os_free(s_param.host);
s_param.host = NULL;
s_param.state = IPERF_STATE_STOPPED;
}
static void iperf_set_sock_opt(int sock)
{
struct timeval tv;
int flag = 1;
int tosval;
setsockopt(sock, IPPROTO_TCP, /* set option at TCP level */
TCP_NODELAY, /* name of option */
(void *)&flag, /* the cast is historical cruft */
sizeof(int)); /* length of option value */
tv.tv_sec = IPERF_TX_TIMEOUT_SEC;
tv.tv_usec = 0;
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
tv.tv_sec = IPERF_RX_TIMEOUT_SEC;
tv.tv_usec = 0;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
tosval = iperf_tos;
setsockopt(sock, IPPROTO_IP, IP_TOS, &tosval, sizeof(tosval));
}
static void printf_transfer_bw(uint64_t amount, float start, float end)
{
int unit;
char numeralSuffix = 'K';
char speedSuffix = 'K';
float trans;
float gaps = end - start;
if (amount > IPERF_MEGA_UNIT) {
numeralSuffix = 'M';
trans = amount / (float)IPERF_MEGA_UNIT;
} else {
trans = amount / (float)IPERF_KILO_UNIT;
}
if (((amount * 8) / gaps) >= (float)IPERF_MILLION_UNIT) {
unit = IPERF_MILLION_UNIT; /* Mbps */
speedSuffix = 'M';
} else {
unit = IPERF_THOUSAND_UNIT; /* Kbps */
}
os_printf("%4.1f-%4.1f sec %6.2f %cBytes %.2f %cbits/sec\r\n", start,end,
trans, numeralSuffix, (((float)amount * 8) / gaps / (float)unit), speedSuffix);
}
static int32_t iperf_udpServer_process_firstData(int sock,const struct sockaddr *from,socklen_t len)
{
if (connect(sock, from, len) < 0) {
os_printf("connect failed %d\r\n", errno);
return -1;
}
return 0;
}
static void iperf_send_ack_toFin(int sock, uint32_t *buffer ,uint64_t total_recvlen,uint32_t start, uint32_t end)
{
int32_t ret;
int32_t tries = 0;
fd_set rdSet;
struct timeval tmo;
iperf_udp_server_hdr_t *hdr = NULL;
uint32_t len = iperf_size;
float duration = end-start;
while (tries++ < IPERF_UDP_FIN_MAX_RETRY_CNTS) {
if (len >= (sizeof(iperf_udp_hdr_t) + sizeof(iperf_udp_server_hdr_t))) {
hdr = (iperf_udp_server_hdr_t *)((uint8_t *)buffer + sizeof(iperf_udp_hdr_t));
(void)os_memset(hdr, 0x0, sizeof(iperf_udp_server_hdr_t));
hdr->flags = htonl(UDP_HEADER_FLAG);
hdr->totalLenH = htonl((long)(total_recvlen >> 32)); /* 32: bits of int32_t */
hdr->totalLenL = htonl((long)(total_recvlen & 0xFFFFFFFF));
hdr->endSec = htonl((long)duration);
hdr->endUsec = htonl((long)((duration - (long)duration) * IPERF_MILLION_UNIT));
}
if (send(sock, buffer, iperf_size, 0) < 0) {
break;
}
FD_ZERO(&rdSet);
FD_SET(sock, &rdSet);
tmo.tv_sec = IPERF_UDP_FINACK_TO;
tmo.tv_usec = 0;
ret = select(sock + 1, &rdSet, NULL, NULL, &tmo);
if (ret < 0) {
break;
} else if (ret == 0) {
return;
} else {
ret = recv(sock, buffer, iperf_size, 0);
if (ret <= 0) {
return;
} else {
len = (uint32_t)ret;
}
}
}
}
static void iperf_process_udpServerHdr(uint32_t *buffer, uint32_t len)
{
if (len > sizeof(iperf_udp_hdr_t) + sizeof(iperf_udp_server_hdr_t)) {
iperf_udp_server_hdr_t *hdr = (iperf_udp_server_hdr_t *)((uint8_t *)buffer + sizeof(iperf_udp_hdr_t));
uint64_t totalLen;
float end;
end = ntohl(hdr->endSec);
end += ntohl(hdr->endUsec) / (float)IPERF_MILLION_UNIT;
totalLen = (((uint64_t)ntohl(hdr->totalLenH)) << 32) + ntohl(hdr->totalLenL); /* 32: bits of int32_t */
printf_transfer_bw(totalLen,0,end);
}
}
static void iperf_report_recv_bandwidth(uint64_t pkt_len)
{
if(s_param.state == IPERF_STATE_STOPPING)
{
if (pkt_len > 0)
{
uint64_t total_f;
total_f = pkt_len * 8;
total_f /= (1000 * s_tick_delta);
os_printf("[%d-%d] sec bandwidth: %llu Kbits/sec.\r\n",
0, s_tick_delta , total_f);
}
}
}
#ifndef CONFIG_IPV6
extern err_t
etharp_request(struct netif *netif, const ip4_addr_t *ipaddr);
extern void *net_get_sta_handle(void);
extern void *net_get_uap_handle(void);
struct netif * get_netif(ip4_addr_t *ipaddr)
{
struct wlan_ip_config sta_addr, ap_addr;
net_get_if_addr(&sta_addr, net_get_sta_handle());
net_get_if_addr(&ap_addr, net_get_uap_handle());
if ((sta_addr.ipv4.gw & 0xFFFFFFl) == (ipaddr->addr & 0xFFFFFFl)) {
return (struct netif *)net_get_sta_handle();
} else if ((ap_addr.ipv4.gw & 0xFFFFFFl) == (ipaddr->addr & 0xFFFFFFl)) {
return (struct netif *)net_get_uap_handle();
} else
return NULL;
}
#endif
static int iperf_bw_delay(int send_size)
{
int period_us = 0;
float pkts_per_tick = 0;
if (speed_limit > 0) {
pkts_per_tick = speed_limit * 1.0 / (send_size * 8) / 500;
period_us = 2000 / pkts_per_tick;
os_printf("iperf_size:%d, speed_limit:%d, period_us:%d pkts_per_tick:%d\n",
send_size, speed_limit, period_us, pkts_per_tick);
}
return period_us;
}
static void iperf_report_task_handler(void *arg)
{
uint32_t delay_interval = (s_param.interval * 1000);
beken_time_get_time(&s_tick_last);
s_tick_delta = 0;
s_pkt_delta = 0;
uint32_t tick_now = 0;
uint32_t average = 0;
int k = 1;
uint32_t count = 0;
while (s_param.state == IPERF_STATE_STARTED)
{
beken_time_get_time(&tick_now);
rtos_delay_milliseconds(delay_interval / 5);
int f;
f = s_pkt_delta / IPERF_KILO_UNIT * 8;
if (++count >= IPERF_REPORT_INTERVAL * 5) /* 5: schedule every 200ms */
{
count = 0;
if (s_pkt_delta >= 0)
{
os_printf("[%d-%d] sec bandwidth: %d Kbits/sec.\r\n",
s_tick_delta, s_tick_delta + IPERF_REPORT_INTERVAL, f);
}
s_tick_delta = s_tick_delta + IPERF_REPORT_INTERVAL;
average = ((average * (k - 1) / k) + (f / k));
k++;
s_tick_last = tick_now;
s_pkt_delta = 0;
}
if (s_param.mode == IPERF_MODE_TCP_CLIENT || s_param.mode == IPERF_MODE_UDP_CLIENT)
{
if (s_tick_delta >= s_time)
{
os_printf("[%d-%d] sec bandwidth: %d Kbits/sec.\r\n",
0, s_time, average);
break;
}
}
}
if (s_param.state == IPERF_STATE_STARTED)
{
s_param.state = IPERF_STATE_STOPPING;
}
rtos_delete_thread(NULL);
}
static err_t iperf_report_task_start(void)
{
int ret;
ret = rtos_create_thread(NULL, iperf_report_priority, IPERF_REPORT_TASK_NAME,
iperf_report_task_handler, IPERF_REPORT_TASK_STACK,
(beken_thread_arg_t) 0);
if (ret != kNoErr) {
BK_LOGE(TAG, "create task %s failed", IPERF_REPORT_TASK_NAME);
return BK_FAIL;
}
return BK_OK;
}
static void iperf_client(void *thread_param)
{
int i, sock, ret;
uint8_t *send_buf;
struct sockaddr_in addr;
uint32_t retry_cnt = 0;
int period_us = 0;
int fdelay_us = 0;
int64_t prev_time = 0;
int64_t send_time = 0;
uint32_t now_time = 0;
send_buf = (uint8_t *) os_malloc(iperf_size);
if (!send_buf)
goto _exit;
for (i = 0; i < iperf_size; i++)
send_buf[i] = i & 0xff;
period_us = iperf_bw_delay(iperf_size);
while (s_param.state == IPERF_STATE_STARTED) {
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0) {
os_printf("iperf: create socket failed, err=%d!\n", errno);
rtos_delay_milliseconds(1000);
continue;
}
addr.sin_family = PF_INET;
addr.sin_port = htons(s_param.port);
addr.sin_addr.s_addr = inet_addr((char *)s_param.host);
#ifndef CONFIG_IPV6
{
struct netif *netif;
netif = get_netif((ip4_addr_t *)&addr.sin_addr.s_addr);
if (netif) {
etharp_request(netif, (ip4_addr_t *)&addr.sin_addr.s_addr);
rtos_delay_milliseconds(1000);
}
}
#endif
ret = connect(sock, (const struct sockaddr *)&addr, sizeof(addr));
if (ret == -1) {
os_printf("iperf: connect failed, err=%d!\n", errno);
closesocket(sock);
rtos_delay_milliseconds(1000);
continue;
}
os_printf("iperf: connect to iperf server successful!\n");
iperf_set_sock_opt(sock);
iperf_report_task_start();
prev_time = rtos_get_time();
while (s_param.state == IPERF_STATE_STARTED) {
if (speed_limit > 0) {
send_time = rtos_get_time();
fdelay_us = period_us + (int32_t)(prev_time - send_time);
prev_time = send_time;
}
else if (speed_limit == 0) {
now_time = rtos_get_time();
if ((now_time - prev_time) / 1000 > 0) {
prev_time = now_time;
rtos_delay_milliseconds(4);
}
}
retry_cnt = 0;
_tx_retry:
ret = send(sock, send_buf, iperf_size, 0);
if (ret > 0) {
s_pkt_delta +=ret;
if (fdelay_us > 0) {
delay_us(fdelay_us);
}
}
else {
if (s_param.state != IPERF_STATE_STARTED)
break;
if (errno == EWOULDBLOCK) {
retry_cnt ++;
if (retry_cnt >= IPERF_MAX_TX_RETRY) {
os_printf("iperf: tx reaches max retry(%u)\n", retry_cnt);
break;
} else
goto _tx_retry;
}
break;
}
#if (CONFIG_TASK_WDT)
bk_task_wdt_feed();
#endif
}
closesocket(sock);
if (s_param.state != IPERF_STATE_STARTED)
break;
rtos_delay_milliseconds(1000 * 2);
}
_exit:
if (send_buf)
os_free(send_buf);
iperf_reset();
os_printf("iperf: is stopped\n");
rtos_delete_thread(NULL);
}
void iperf_server(void *thread_param)
{
uint8_t *recv_data;
uint32_t sin_size;
int sock = -1, connected, bytes_received;
struct sockaddr_in server_addr, client_addr;
uint32_t retry_cnt = 0;
uint64_t s_total_len_rcv = 0;
recv_data = (uint8_t *) os_malloc(iperf_size);
if (recv_data == NULL) {
os_printf("iperf: no memory\n");
goto __exit;
}
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
os_printf("iperf: socket error\n");
goto __exit;
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(s_param.port);
server_addr.sin_addr.s_addr = INADDR_ANY;
os_memset(&(server_addr.sin_zero), 0x0, sizeof(server_addr.sin_zero));
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
os_printf("iperf: unable to bind, err=%d\n", errno);
goto __exit;
}
if (listen(sock, 5) == -1) {
os_printf("iperf: listen error, err=%d\n", errno);
goto __exit;
}
iperf_set_sock_opt(sock);
while (s_param.state == IPERF_STATE_STARTED) {
sin_size = sizeof(struct sockaddr_in);
_accept_retry:
connected = accept(sock, (struct sockaddr *)&client_addr, &sin_size);
if (connected == -1) {
if (s_param.state != IPERF_STATE_STARTED)
break;
if (errno == EWOULDBLOCK)
goto _accept_retry;
}
os_printf("iperf: new client connected from (%s, %d)\n",
inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port));
iperf_set_sock_opt(connected);
iperf_report_task_start();
while (s_param.state == IPERF_STATE_STARTED) {
retry_cnt = 0;
_rx_retry:
bytes_received = recv(connected, recv_data, iperf_size, 0);
if (bytes_received < 0) {
if (s_param.state != IPERF_STATE_STARTED)
break;
if (errno == EWOULDBLOCK) {
retry_cnt ++;
if (retry_cnt >= IPERF_MAX_RX_RETRY) {
os_printf("iperf: rx reaches max retry(%d)\n", retry_cnt);
break;
} else
goto _rx_retry;
}
break;
}else if (bytes_received == 0){
s_param.state = IPERF_STATE_STOPPING;
break;
}else{
s_pkt_delta += bytes_received;
s_total_len_rcv +=bytes_received;
}
}
if (connected >= 0)
closesocket(connected);
connected = -1;
}
iperf_report_recv_bandwidth(s_total_len_rcv);
__exit:
if (sock >= 0)
closesocket(sock);
if (recv_data) {
os_free(recv_data);
recv_data = NULL;
}
iperf_reset();
os_printf("iperf: iperf is stopped\n");
rtos_delete_thread(NULL);
}
static void iperf_udp_client(void *thread_param)
{
int sock, ret;
uint32_t *buffer;
struct sockaddr_in server;
uint32_t tick, packet_count = 0;
uint32_t retry_cnt;
int send_size;
#if (CONFIG_SOC_BK7236XX || CONFIG_SOC_BK7239XX || CONFIG_SOC_BK7286XX) && !CONFIG_FREERTOS_SMP
int cycle = 7;
#endif
int period_us = 0;
int fdelay_us = 0;
int64_t prev_time = 0;
int64_t send_time = 0;
uint32_t now_time = 0;
int32_t tries = 0;
fd_set rdSet;
struct timeval tmo;
send_size = iperf_size > 1470 ? 1470 : iperf_size;
buffer = os_malloc(iperf_size);
if (buffer == NULL)
goto udp_exit;
os_memset(buffer, 0x00, iperf_size);
period_us = iperf_bw_delay(send_size);
while (IPERF_STATE_STARTED == s_param.state) {
sock = socket(PF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
os_printf("iperf: create socket failed, err=%d!\n", errno);
rtos_delay_milliseconds(1000);
continue;
}
server.sin_family = PF_INET;
server.sin_port = htons(s_param.port);
server.sin_addr.s_addr = inet_addr(s_param.host);
os_printf("iperf udp mode run...\n");
#ifndef CONFIG_IPV6
{
struct netif *netif;
netif = get_netif((ip4_addr_t *)&server.sin_addr.s_addr);
if (netif) {
etharp_request(netif, (ip4_addr_t *)&server.sin_addr.s_addr);
rtos_delay_milliseconds(1000);
}
}
#endif
prev_time = rtos_get_time();
iperf_report_task_start();
while (IPERF_STATE_STARTED == s_param.state) {
if (speed_limit > 0) {
send_time = rtos_get_time();
fdelay_us = period_us + (int32_t)(prev_time - send_time);
prev_time = send_time;
}
else if (speed_limit == 0) {
now_time = rtos_get_time();
if ((now_time - prev_time) / 1000 > 0) {
prev_time = now_time;
rtos_delay_milliseconds(4);
}
}
packet_count ++;
retry_cnt = 0;
tick = bk_get_tick();
buffer[0] = htonl(packet_count);
buffer[1] = htonl(tick / bk_get_ticks_per_second());
buffer[2] = htonl((tick % bk_get_ticks_per_second()) * 1000);
tx_retry:
ret = sendto(sock, buffer, send_size, 0, (struct sockaddr *)&server, sizeof(struct sockaddr_in));
if (ret) {
if(ret > 0){
s_pkt_delta +=ret;
}
if (fdelay_us > 0) {
delay_us(fdelay_us);
}
}
else {
retry_cnt ++;
if (IPERF_STATE_STARTED != s_param.state)
break;
if (retry_cnt > IPERF_MAX_TX_RETRY){
break;
}
goto tx_retry;
}
#if (CONFIG_TASK_WDT)
bk_task_wdt_feed();
#endif
#if (CONFIG_SOC_BK7236XX || CONFIG_SOC_BK7239XX || CONFIG_SOC_BK7286XX) && !CONFIG_FREERTOS_SMP
if (packet_count % cycle == 0)
rtos_delay_milliseconds(1);
#endif
}
if(s_param.state == IPERF_STATE_STOPPING){
tick = bk_get_tick();
buffer[0] = htonl(-(packet_count));
buffer[1] = htonl(tick / bk_get_ticks_per_second());
buffer[2] = htonl((tick % bk_get_ticks_per_second()) * 1000);
while (tries++ < IPERF_UDP_FIN_MAX_RETRY_CNTS){
ret = sendto(sock, buffer, send_size, 0, (struct sockaddr *)&server, sizeof(struct sockaddr_in));
if (ret < 0) {
break;
}
FD_ZERO(&rdSet);
FD_SET(sock, &rdSet);
tmo.tv_sec = 0;
tmo.tv_usec = IPERF_UDP_FIN_TO;
ret = select(sock + 1, &rdSet, NULL, NULL, &tmo);
if (ret < 0) {
break;
} else if (ret == 0) {
continue;
} else {
ret = recv(sock, buffer, iperf_size, 0);
if (ret < 0) {
break;
}
iperf_process_udpServerHdr(buffer, (uint32_t)ret);
break;
}
}
}
closesocket(sock);
if (IPERF_STATE_STARTED != s_param.state)
break;
rtos_delay_milliseconds(1000 * 2);
}
udp_exit:
if (buffer) {
os_free(buffer);
buffer = NULL;
}
iperf_reset();
os_printf("iperf_udp: is stopped\n");
rtos_delete_thread(NULL);
}
static void iperf_udp_server(void *thread_param)
{
int sock;
uint32_t *buffer;
struct sockaddr_in server;
struct sockaddr_in sender;
int sender_len, r_size;
uint32_t pcount = 0, last_pcount = 0;
uint64_t s_total_len = 0;
uint32_t lost, total;
uint64_t tick1, tick2;
struct timeval timeout;
uint32_t start;
uint32_t end;
struct sockaddr *from = (struct sockaddr *)&sender;
socklen_t slen = sizeof(struct sockaddr);
socklen_t *fromLen = &slen;
bool udp_start = false;
buffer = os_malloc(iperf_size);
if (buffer == NULL)
return;
sock = socket(PF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
os_printf("can't create socket!! exit\n");
goto userver_exit;
}
server.sin_family = PF_INET;
server.sin_port = htons(s_param.port);
server.sin_addr.s_addr = inet_addr("0.0.0.0");
timeout.tv_sec = 2;
timeout.tv_usec = 0;
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) == -1) {
os_printf("setsockopt failed!!");
goto userver_exit;
}
if (bind(sock, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) {
os_printf("iperf server bind failed!! exit\n");
goto userver_exit;
}
while (s_param.state == IPERF_STATE_STARTED) {
tick1 = bk_get_tick();
tick2 = tick1;
lost = 0;
total = 0;
while (s_param.state == IPERF_STATE_STARTED){
r_size = recvfrom(sock, buffer, iperf_size, 0, (struct sockaddr *)&sender, (socklen_t *)&sender_len);
if (r_size > 12 ){
break;
}
}
if(!udp_start)
{
iperf_udpServer_process_firstData(sock, from, *fromLen);
start = ntohl(buffer[1]);
udp_start = true;
}
iperf_report_task_start();
while ((s_param.state == IPERF_STATE_STARTED) && ((tick2 - tick1) < (bk_get_ticks_per_second() * 999))) {
r_size = recvfrom(sock, buffer, iperf_size, 0, (struct sockaddr *)&sender, (socklen_t *)&sender_len);
if (r_size > 12) {
pcount = ntohl(buffer[0]);
if (last_pcount < pcount) {
lost += pcount - last_pcount - 1;
total += pcount - last_pcount;
} else
last_pcount = pcount;
last_pcount = pcount;
s_pkt_delta +=r_size;
s_total_len +=r_size;
if ((int32_t)(pcount) < 0) {
s_param.state = IPERF_STATE_STOPPING;
break;
}
}
tick2 = bk_get_tick();
#if (CONFIG_TASK_WDT)
bk_task_wdt_feed();
#endif
}
end = ntohl(buffer[1]) ;
if (s_param.state == IPERF_STATE_STOPPING){
iperf_send_ack_toFin(sock, buffer,s_total_len,start,end);
}
iperf_report_recv_bandwidth(s_total_len);
}
userver_exit:
if (sock >= 0)
closesocket(sock);
if (buffer) {
os_free(buffer);
buffer = NULL;
}
iperf_reset();
os_printf("iperf_udp: iperf is stopped\n");
rtos_delete_thread(NULL);
}
int iperf_param_find_id(int argc, char **argv, char *param)
{
int i;
int index;
index = IPERF_INVALID_INDEX;
if (NULL == param)
goto find_over;
for (i = 1; i < argc; i ++) {
if (os_strcmp(argv[i], param) == 0) {
index = i;
break;
}
}
find_over:
return index;
}
int iperf_param_find(int argc, char **argv, char *param)
{
int id;
int find_flag = 0;
id = iperf_param_find_id(argc, argv, param);
if (IPERF_INVALID_INDEX != id)
find_flag = 1;
return find_flag;
}
void iperf_usage(void)
{
os_printf("Usage: iperf [-s|-c host] [options]\n");
os_printf(" iperf [-h|--stop]\n");
os_printf("\n");
os_printf("Client/Server:\n");
os_printf(" -p # server port to listen on/connect to\n");
os_printf("\n");
os_printf("Server specific:\n");
os_printf(" -s run in server mode\n");
os_printf("\n");
os_printf("Client specific:\n");
os_printf(" -c <host> run in client mode, connecting to <host>\n");
os_printf("\n");
os_printf("Miscellaneous:\n");
os_printf(" -u udp support, and the default mode is tcp\n");
os_printf(" -t #[time] time in seconds to transmit for (default 30 secs)\n");
os_printf(" -h print this message and quit\n");
os_printf(" --stop stop iperf program\n");
return;
}
static void iperf_stop(void)
{
if (s_param.state == IPERF_STATE_STARTED) {
s_param.state = IPERF_STATE_STOPPING;
os_printf("iperf: iperf is stopping...\n");
}
}
static void iperf_start(int mode, char *host, int port)
{
if (s_param.state == IPERF_STATE_STOPPED) {
s_param.state = IPERF_STATE_STARTED;
s_param.mode = mode;
s_param.port = port;
if (s_param.host) {
os_free(s_param.host);
s_param.host = NULL;
}
if (host)
s_param.host = os_strdup(host);
if (mode == IPERF_MODE_TCP_CLIENT) {
#ifdef CONFIG_FREERTOS_SMP
rtos_create_thread_with_affinity(NULL, -1, iperf_priority, "iperf_tcp_c",
iperf_client, THREAD_SIZE,
(beken_thread_arg_t) 0);
#else
rtos_create_thread(NULL, iperf_priority, "iperf_tcp_c",
iperf_client, THREAD_SIZE,
(beken_thread_arg_t) 0);
#endif
} else if (mode == IPERF_MODE_TCP_SERVER) {
#ifdef CONFIG_FREERTOS_SMP
rtos_create_thread_with_affinity(NULL, -1, iperf_priority, "iperf_tcp_s",
iperf_server, THREAD_SIZE,
(beken_thread_arg_t) 0);
#else
rtos_create_thread(NULL, iperf_priority, "iperf_tcp_s",
iperf_server, THREAD_SIZE,
(beken_thread_arg_t) 0);
#endif
} else if (mode == IPERF_MODE_UDP_CLIENT) {
#ifdef CONFIG_FREERTOS_SMP
rtos_create_thread_with_affinity(NULL, -1, iperf_priority, "iperf_udp_c",
iperf_udp_client, THREAD_SIZE,
(beken_thread_arg_t) 0);
#else
rtos_create_thread(NULL, iperf_priority, "iperf_udp_c",
iperf_udp_client, THREAD_SIZE,
(beken_thread_arg_t) 0);
#endif
} else if (mode == IPERF_MODE_UDP_SERVER) {
#ifdef CONFIG_FREERTOS_SMP
rtos_create_thread_with_affinity(NULL, -1, iperf_priority, "iperf_udp_s",
iperf_udp_server, THREAD_SIZE,
(beken_thread_arg_t) 0);
#else
rtos_create_thread(NULL, iperf_priority, "iperf_udp_s",
iperf_udp_server, THREAD_SIZE,
(beken_thread_arg_t) 0);
#endif
} else
os_printf("iperf: invalid iperf mode=%d\n", mode);
} else if (s_param.state == IPERF_STATE_STOPPING)
os_printf("iperf: iperf is stopping, try again later!\n");
else
os_printf("iperf: iperf is running, stop first!\n");
}
void iperf_config(int argc, char **argv)
{
if (os_strcmp(argv[1], "config"))
{
return;
}
if(os_strcmp(argv[2], "-pri") == 0)
{
iperf_priority = os_strtoul(argv[3], NULL, 10);
os_printf("iperf config iperf_priority to %d !\n", iperf_priority);
}
else if(os_strcmp(argv[2], "-ips") == 0)
{
iperf_size = os_strtoul(argv[3], NULL, 10);
os_printf("iperf config iperf_size to %d !\n", iperf_size);
}
else if(os_strcmp(argv[2], "-tos") == 0)
{
iperf_tos = os_strtoul(argv[3], NULL, 10);
os_printf("iperf config iperf_tos to %d !\n", iperf_tos);
}
else
{
os_printf("iperf config INVALID PRAMATER !\n");
}
}
static void iperf_set_defaults(void) {
iperf_size = IPERF_BUFSZ;
speed_limit = IPERF_DEFAULT_SPEED_LIMIT;
}
void iperf(char *pcWriteBuffer, int xWriteBufferLen, int argc, char **argv)
{
int id, mode;
char *host = NULL;
int is_udp_flag = 0;
int port = IPERF_PORT;
int is_server_mode, is_client_mode;
uint32_t value;
iperf_set_defaults();
/* check parameters of command line*/
if (iperf_param_find(argc, argv, "-h") || (argc == 1))
goto __usage;
else if (iperf_param_find(argc, argv, "--stop")
|| iperf_param_find(argc, argv, "-stop")) {
iperf_stop();
return;
}
else if(iperf_param_find(argc, argv, "config"))
{
iperf_config(argc, argv);
return;
}
is_server_mode = iperf_param_find(argc, argv, "-s");
is_client_mode = iperf_param_find(argc, argv, "-c");
if ((is_client_mode && is_server_mode)
|| ((0 == is_server_mode) && (0 == is_client_mode)))
goto __usage;
if (iperf_param_find(argc, argv, "-u"))
is_udp_flag = 1;
/* config iperf operation mode*/
if (is_udp_flag) {
if (is_server_mode)
mode = IPERF_MODE_UDP_SERVER;
else
mode = IPERF_MODE_UDP_CLIENT;
} else {
if (is_server_mode)
mode = IPERF_MODE_TCP_SERVER;
else
mode = IPERF_MODE_TCP_CLIENT;
}
/* config protocol port*/
id = iperf_param_find_id(argc, argv, "-p");
if (IPERF_INVALID_INDEX != id) {
port = atoi(argv[id + 1]);
if (argc - 1 < id + 1)
goto __usage;
}
if (is_client_mode) {
id = iperf_param_find_id(argc, argv, "-c");
if (IPERF_INVALID_INDEX != id) {
host = argv[id + 1];
if (argc - 1 < id + 1)
goto __usage;
}
}
id = iperf_param_find_id(argc, argv, "-l");
if (IPERF_INVALID_INDEX != id) {
iperf_size = atoi(argv[id + 1]);
if ((iperf_size == 0) || argc - 1 < id + 1)
goto __usage;
}
if (is_client_mode) {
id = iperf_param_find_id(argc, argv, "-t");
if (IPERF_INVALID_INDEX != id) {
s_time = atoi(argv[id + 1]);
if(s_time == 0){
s_time = IPERF_DEFAULT_TIME;
}
if (argc - 1 < id + 1)
goto __usage;
}
}
id = iperf_param_find_id(argc, argv, "-b");
if (IPERF_INVALID_INDEX != id) {
if (argv[id + 1] == NULL) {
speed_limit = 0;
}
else {
speed_limit = atoi(argv[id + 1]);
if ((speed_limit == 0) || argc - 1 < id + 1)
goto __usage;
value = strlen(argv[id + 1]);
if (value > 1) {
if (argv[id + 1][value - 1] == 'k') {
speed_limit *= 1000;
} else if (argv[id + 1][value - 1] == 'K') {
speed_limit *= 1024;
} else if (argv[id + 1][value - 1] == 'm') {
speed_limit *= 1000 * 1000;
} else if (argv[id + 1][value - 1] == 'M') {
speed_limit *= 1024 * 1024;
} else {
goto __usage;
}
}
}
}
iperf_start(mode, host, port);
return;
__usage:
iperf_usage();
return;
}
// eof