/*! \file udp_test.c \brief UDP test for GD32W51x WiFi SDK \version 2021-10-30, V1.0.0, firmware for GD32W51x */ /* Copyright (c) 2021, GigaDevice Semiconductor Inc. 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 the copyright holder 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 HOLDER 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. */ #include #include #include "app_cfg.h" #include "app_type.h" #include "wrapper_os.h" #include "malloc.h" #include "debug_print.h" #include #include "lwip/stats.h" // #define DEBUG_DUAL_MODE #define HEADER_VERSION1 0x80000000 #define DUAL_MODE_RUN_NOW 0x00000001 #define ERROR_ALREADY_RUNNING 1 #define ERROR_NO_MEMORY -1 struct udp_data_t { void *task_hdl; int32_t srv_fd; int32_t cli_fd; uint8_t is_server; uint16_t srv_port; /* server port to listen on/connect to (default 5001) */ char srv_ip[16]; /* server ip to listen on/connect to */ uint8_t dualmode; /* Set dual mode, do a bidirectional test simultaneously */ uint8_t rsvd; uint16_t buf_len; /* length of buffer to read or write (default 1460 Bytes) */ uint8_t tos; /* type of service byte */ uint32_t rpt_intvl; /* ticks between periodic bandwidth reports (default 1000 ticks) */ uint32_t time_limit; /* time in ticks to transmit for (default 10000 ticks) */ uint64_t size_limit; /* number of buffer to transmit for (default use time) */ uint64_t bandwidth; /* for UDP, bandwidth to send at in bits/sec (default 1 Mbit/sec, implies -u) */ }; struct udp_datagram { int32_t id; uint32_t tv_sec; uint32_t tv_usec; }; struct client_hdr { int32_t flags; int32_t numThreads; int32_t mPort; int32_t bufferlen; int32_t mWindowSize; int32_t mAmount; int32_t mRate; int32_t mUDPRateUnits; }; static const long kKilo_to_Unit = 1024; static const long kMega_to_Unit = 1024 * 1024; static const long kGiga_to_Unit = 1024 * 1024 * 1024; static const long kkilo_to_Unit = 1000; static const long kmega_to_Unit = 1000 * 1000; static const long kgiga_to_Unit = 1000 * 1000 * 1000; static struct udp_data_t *udp_srv_data = NULL; static struct udp_data_t *udp_cli_data = NULL; static int32_t udp_terminate = 0; static void udp_task_func(void *param); static uint64_t byte_atoi(const char *inString) { double theNum; char suffix = '\0'; /* scan the number and any suffices */ sscanf(inString, "%lf%c", &theNum, &suffix); /* convert according to [Gg Mm Kk] */ switch ( suffix ) { case 'G': theNum *= kGiga_to_Unit; break; case 'M': theNum *= kMega_to_Unit; break; case 'K': theNum *= kKilo_to_Unit; break; case 'g': theNum *= kgiga_to_Unit; break; case 'm': theNum *= kmega_to_Unit; break; case 'k': theNum *= kkilo_to_Unit; break; default: break; } return (uint64_t)theNum; } #ifdef DEBUG_DUAL_MODE /*! \brief dump client header \param[in] h: pointer to the input client header structure \param[in] flags: a bitmap for different options \arg HEADER_VERSION1 0x80000000 \arg RUN_NOW 0x00000001 \arg UNITS_PPS 0x00000002 \param[in] numThreads: number of the client threads \param[in] mPort: port number of the client \param[in] bufferlen: buffer length of the client \param[in] mWindowSize: TCP window size of the client \param[in] mAmount: number of bytes to send \param[in] mRate: UDP data rate \param[in] mUDPRateUnits: UDP rate uinit (either bw or pps) \param[out] none \retval none */ /*! \brief dump client header \param[in] h: pointer to the input client header structure flags:(???) numThreads: mPort: bufferlen: mWindowSize: mAmount: mRate: mUDPRateUnits: \param[out] none \retval none */ static void client_header_dump(struct client_hdr *h) { DEBUGPRINT("\r\n========== dump client header ============\r\n"); DEBUGPRINT("flags = 0x%x, ntohl(flags) = 0x%x\r\n", h->flags, ntohl(h->flags)); DEBUGPRINT("numThreads = %d\r\n", ntohl(h->numThreads)); DEBUGPRINT("mPort = %d\r\n", ntohl(h->mPort)); DEBUGPRINT("bufferlen = %d\r\n", ntohl(h->bufferlen)); DEBUGPRINT("mWindowSize = %d\r\n", ntohl(h->mWindowSize)); DEBUGPRINT("mAmount = 0x%x (%d)\r\n", ntohl(h->mAmount), ntohl(h->mAmount)); DEBUGPRINT("mRate = %d\r\n", ntohl(h->mRate)); DEBUGPRINT("mUDPRateUnits = %d\r\n", ntohl(h->mUDPRateUnits)); DEBUGPRINT("========== dump client header end ============\r\n"); } /*! \brief dump udp data \param[in] udp_data: pointer to the input udp data structure task_hdl: task handle srv_fd: server socket file descriptor cli_fd: client socket file descriptor is_server: is server falg srv_port: server port to listen on/connect to (default 5001) srv_ip: server ip to listen on/connect to dualmode: Set dual mode, do a bidirectional test simultaneously rsvd: reserve buf_len: length of buffer to read or write (default 1472 Bytes) tos: type of service byte rpt_intvl: ticks between periodic bandwidth reports (default 1000 ticks) time_limit: time in ticks to transmit for (default 10000 ticks) size_limit: number of buffer to transmit for (default use time) bandwidth: for UDP, bandwidth to send at in bits/sec (default 1 Mbit/sec, implies -u) \param[out] none \retval none */ static void dump_udp_data(struct udp_data_t *udp_data) { DEBUGPRINT("\r\n========== dump udp data ============\r\n"); DEBUGPRINT("task_hdl = %p\r\n", udp_data->task_hdl); DEBUGPRINT("srv_fd = %d\r\n", udp_data->srv_fd); DEBUGPRINT("cli_fd = %d\r\n", udp_data->cli_fd); DEBUGPRINT("is_server = %d\r\n", udp_data->is_server); DEBUGPRINT("srv_port = %d\r\n", udp_data->srv_port); DEBUGPRINT("srv_ip = %s\r\n", udp_data->srv_ip); DEBUGPRINT("dualmode = %d\r\n", udp_data->dualmode); DEBUGPRINT("buf_len = %d\r\n", udp_data->buf_len); DEBUGPRINT("rpt_intvl = %d\r\n", udp_data->rpt_intvl); DEBUGPRINT("time_limit = %d\r\n", udp_data->time_limit); DEBUGPRINT("size_limit = %u\r\n", (uint32_t)udp_data->size_limit); DEBUGPRINT("bandwidth = %u\r\n", (uint32_t)udp_data->bandwidth); DEBUGPRINT("========== dump udp data end ============\r\n"); } #endif /*! \brief generate client header \param[in] udp_data: pointer to the input udp data structure task_hdl: task handle srv_fd: server socket file descriptor cli_fd: client socket file descriptor is_server: is server falg srv_port: server port to listen on/connect to (default 5001) srv_ip: server ip to listen on/connect to dualmode: Set dual mode, do a bidirectional test simultaneously rsvd: reserve buf_len: length of buffer to read or write (default 1472 Bytes) tos: type of service byte rpt_intvl: ticks between periodic bandwidth reports (default 1000 ticks) time_limit: time in ticks to transmit for (default 10000 ticks) size_limit: number of buffer to transmit for (default use time) bandwidth: for UDP, bandwidth to send at in bits/sec (default 1 Mbit/sec, implies -u) \param[in] buf: pointer to the input udp datagram structure id: number of id tv_sec: second vlaue tv_usec: microsecond vlaue \param[out] none \retval none */ static void client_header_generate(struct udp_data_t *udp_data, char *buf) { struct udp_datagram *udp_hdr = (struct udp_datagram *)buf; struct client_hdr *cli_hdr = (struct client_hdr *)(udp_hdr + 1); udp_hdr->id = 0; udp_hdr->tv_sec = 0; udp_hdr->tv_usec = 0; if (udp_data->dualmode == 1) { cli_hdr->flags = htonl(HEADER_VERSION1 | DUAL_MODE_RUN_NOW); // 0x01000080 } else { cli_hdr->flags = 0; } cli_hdr->numThreads = htonl(0x01); cli_hdr->mPort = htonl(udp_data->srv_port); cli_hdr->bufferlen = htonl(udp_data->buf_len); cli_hdr->mWindowSize = htonl(udp_data->bandwidth); if (udp_data->size_limit> 0) { cli_hdr->mAmount = udp_data->size_limit & 0x7FFFFFFF; cli_hdr->mAmount = htonl(cli_hdr->mAmount); } else { cli_hdr->mAmount = (int32_t)(udp_data->time_limit * 100 / OS_TICK_RATE_HZ); cli_hdr->mAmount = htonl(-cli_hdr->mAmount); } cli_hdr->mRate = htonl(udp_data->bandwidth); cli_hdr->mUDPRateUnits = 0; // kRate_BW #ifdef DEBUG_DUAL_MODE // buffer_dump("Client header:", cli_hdr, sizeof(struct client_hdr)); client_header_dump(cli_hdr); #endif } /*! \brief initialize client data \param[in] none \param[out] none \retval function run status \arg ERROR_ALREADY_RUNNING: tcp server is already running \arg ERROR_NO_MEMORY: No memory for tcp data \arg 0: run success */ static int client_data_init(void) { if (udp_cli_data) { if (udp_cli_data->task_hdl != NULL) { DEBUGPRINT("UDP: UDP client is already running.\r\n"); return ERROR_ALREADY_RUNNING; } } else { udp_cli_data = sys_malloc(sizeof(struct udp_data_t)); if (udp_cli_data == NULL) { DEBUGPRINT("UDP: No memory for udp_data.\r\n"); return ERROR_NO_MEMORY; } } sys_memset(udp_cli_data, 0, sizeof(struct udp_data_t)); udp_cli_data->cli_fd = -1; udp_cli_data->buf_len = 1460; udp_cli_data->srv_port = 5001; udp_cli_data->tos = 0; udp_cli_data->rpt_intvl = 1 * OS_TICK_RATE_HZ; // default 1s udp_cli_data->time_limit = 10 * OS_TICK_RATE_HZ + 100; // default 10s udp_cli_data->bandwidth = (1 * kMega_to_Unit) >> 8; // default 1Mbps return 0; } /*! \brief initialize server data \param[in] none \param[out] none \retval function run status \arg ERROR_ALREADY_RUNNING: tcp server is already running \arg ERROR_NO_MEMORY: No memory for tcp data \arg 0: run success */ static int server_data_init(void) { if (udp_srv_data) { if (udp_srv_data->task_hdl != NULL) { DEBUGPRINT("UDP WARNING: UDP server is already running.\r\n"); return ERROR_ALREADY_RUNNING; } } else { udp_srv_data = sys_malloc(sizeof(struct udp_data_t)); if (udp_srv_data == NULL) { DEBUGPRINT("UDP ERROR: No memory for udp_data.\r\n"); return ERROR_NO_MEMORY; } } sys_memset(udp_srv_data, 0, sizeof(struct udp_data_t)); udp_srv_data->is_server = 1; udp_srv_data->srv_fd = -1; udp_srv_data->cli_fd = -1; udp_srv_data->buf_len = 1460; udp_srv_data->srv_port = 5001; udp_srv_data->time_limit = 10 * OS_TICK_RATE_HZ; // default 10s udp_srv_data->rpt_intvl = 1 * OS_TICK_RATE_HZ; // default 1s return 0; } /*! \brief udp client function \param[in] udp_data: pointer to the input udp data structure task_hdl: task handle srv_fd: server socket file descriptor cli_fd: client socket file descriptor is_server: is server falg srv_port: server port to listen on/connect to (default 5001) srv_ip: server ip to listen on/connect to dualmode: Set dual mode, do a bidirectional test simultaneously rsvd: reserve buf_len: length of buffer to read or write (default 1472 Bytes) tos: type of service byte rpt_intvl: ticks between periodic bandwidth reports (default 1000 ticks) time_limit: time in ticks to transmit for (default 10000 ticks) size_limit: number of buffer to transmit for (default use time) bandwidth: for UDP, bandwidth to send at in bits/sec (default 1 Mbit/sec, implies -u) \param[out] none \retval none \retval function run status -1: allocate client buffer failed 0: run success */ static int udp_client(struct udp_data_t *udp_data) { struct sockaddr_in sAddr; socklen_t iAddrSize = sizeof(struct sockaddr_in); char *cBsdBuf = NULL; int iCounter, iStatus; uint32_t stime, etime, rpt_stime, bw_stime; // ticks uint32_t m; uint64_t rpt_sz = 0, tot_sz = 0, bw_sz = 0; uint32_t time = 0, tcnt = 0; // seconds uint32_t intvl_sec = udp_data->rpt_intvl / OS_TICK_RATE_HZ; struct udp_datagram *udp_hdr = NULL; uint32_t pkt_cnt = 0; #ifdef DEBUG_DUAL_MODE dump_udp_data(udp_data); #endif cBsdBuf = sys_malloc(udp_data->buf_len); if (NULL == cBsdBuf) { DEBUGPRINT("UDP ERROR: allocate client buffer failed (len = %d).\r\n", udp_data->buf_len); return -1; } for (iCounter = 0; iCounter < udp_data->buf_len; iCounter++) { cBsdBuf[iCounter] = (char)(iCounter % 10); } client_header_generate(udp_data, cBsdBuf); udp_hdr = (struct udp_datagram *)cBsdBuf; FD_ZERO(&sAddr); sAddr.sin_family = AF_INET; sAddr.sin_port = htons(udp_data->srv_port); sAddr.sin_addr.s_addr = inet_addr(udp_data->srv_ip); /* creating a UDP socket */ udp_data->cli_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (udp_data->cli_fd < 0) { DEBUGPRINT("UDP ERROR: create UDP client socket fd error!\r\n"); goto Exit; } /* Set IP TOS */ if (udp_data->tos) { m = udp_data->tos; if (setsockopt(udp_data->cli_fd, IPPROTO_IP, IP_TOS, &m, sizeof(m)) < 0) { DEBUGPRINT("UDP ERROR:set socket tos %d error, errno = %d!\r\n", m, errno); goto Exit; } } DEBUGPRINT("UDP: server IP=%s port=%d.\r\n", udp_data->srv_ip, udp_data->srv_port); DEBUGPRINT("UDP: create socket %d.\r\n", udp_data->cli_fd); bw_stime = rpt_stime = etime = stime = sys_current_time_get(); if (udp_data->size_limit != 0) { while (!udp_terminate && (tot_sz < udp_data->size_limit)) { iStatus = sendto(udp_data->cli_fd, cBsdBuf, udp_data->buf_len, 0, (struct sockaddr *)&sAddr, iAddrSize); if (iStatus <= 0) { /* low_level_output return ERR_MEM because wifi skb is not enough */ // DEBUGPRINT("UDP ERROR: UDP client send data error (iStatus = %d).\r\n", iStatus); } pkt_cnt++; udp_hdr->id = htonl(pkt_cnt); tot_sz += udp_data->buf_len; rpt_sz += udp_data->buf_len; bw_sz += udp_data->buf_len; etime = sys_current_time_get(); if ((bw_sz >= udp_data->bandwidth) && ((etime - bw_stime) < 1 * OS_TICK_RATE_HZ)) { sys_ms_sleep((1 * OS_TICK_RATE_HZ - (etime - bw_stime)) / OS_MS_PER_TICK); etime = sys_current_time_get(); bw_stime = etime; bw_sz = 0; } time = (etime - rpt_stime) * OS_MS_PER_TICK; if ((etime - rpt_stime) >= udp_data->rpt_intvl) { if (tcnt == 0) DEBUGPRINT("\t\tInterval\t\tTransfer\t\tBandwidth\r\n"); DEBUGPRINT("Send\t%4d - %4d sec\t\t%4d KBytes\t\t%5d Kbps\r\n", tcnt, (tcnt + intvl_sec), (uint32_t)(rpt_sz >> 10), (uint32_t)((rpt_sz << 3) / time)); tcnt += intvl_sec; rpt_stime = etime; rpt_sz = 0; bw_stime = etime; bw_sz = 0; } } } else { while (!udp_terminate && ((etime - stime) <= udp_data->time_limit)) { iStatus = sendto(udp_data->cli_fd, cBsdBuf, udp_data->buf_len, 0, (struct sockaddr *)&sAddr, iAddrSize); if (iStatus <= 0) { /* low_level_output return ERR_MEM because wifi skb is not enough */ // DEBUGPRINT("UDP ERROR: UDP client send data error (iStatus = %d).\r\n", iStatus); } pkt_cnt++; udp_hdr->id = htonl(pkt_cnt); tot_sz += udp_data->buf_len; rpt_sz += udp_data->buf_len; bw_sz += udp_data->buf_len; etime = sys_current_time_get(); if ((bw_sz >= udp_data->bandwidth) && ((etime - bw_stime) < OS_TICK_RATE_HZ)) { sys_ms_sleep((1 * OS_TICK_RATE_HZ - (etime - bw_stime)) / OS_MS_PER_TICK); etime = sys_current_time_get(); bw_stime = etime; bw_sz = 0; } time = (etime - rpt_stime) * OS_MS_PER_TICK; if ((etime - rpt_stime) >= udp_data->rpt_intvl) { // DEBUGPRINT("etime=%d stime=%d limit=%d\r\n", etime, stime, udp_data->time_limit); if (tcnt == 0) DEBUGPRINT("\t\tInterval\t\tTransfer\t\tBandwidth\r\n"); DEBUGPRINT("Send\t%4d - %4d sec\t\t%4d KBytes\t\t%5d Kbps\r\n", tcnt, (tcnt + intvl_sec), (uint32_t)(rpt_sz >> 10), (uint32_t)((rpt_sz << 3) / time)); tcnt += intvl_sec; rpt_stime = etime; rpt_sz = 0; bw_stime = etime; bw_sz = 0; } } } time = (etime - stime) * OS_MS_PER_TICK; DEBUGPRINT("Total\t%4d - %4d sec\t\t%4d KBytes\t\t%5d Kbps\r\n", 0, tcnt, (uint32_t)(tot_sz >> 10), (uint32_t)((tot_sz << 3) / time)); /* Inform server to end this transfer */ udp_hdr->id = -1; sendto(udp_data->cli_fd, cBsdBuf, sizeof(struct udp_datagram), 0, (struct sockaddr *)&sAddr, iAddrSize); sys_ms_sleep(100); close(udp_data->cli_fd); Exit: sys_mfree(cBsdBuf); return 0; } /*! \brief udp server function \param[in] udp_data: pointer to the input udp data structure task_hdl: task handle srv_fd: server socket file descriptor cli_fd: client socket file descriptor is_server: is server falg srv_port: server port to listen on/connect to (default 5001) srv_ip: server ip to listen on/connect to dualmode: Set dual mode, do a bidirectional test simultaneously rsvd: reserve buf_len: length of buffer to read or write (default 1472 Bytes) tos: type of service byte rpt_intvl: ticks between periodic bandwidth reports (default 1000 ticks) time_limit: time in ticks to transmit for (default 10000 ticks) size_limit: number of buffer to transmit for (default use time) bandwidth: for UDP, bandwidth to send at in bits/sec (default 1 Mbit/sec, implies -u) \param[out] none \retval none \retval function run status \arg -1: allocate server buffer failed \arg 0: run success */ static int udp_server(struct udp_data_t *udp_data) { struct sockaddr_in sLocalAddr; struct sockaddr_in sCliAddr; socklen_t iAddrSize = sizeof(sLocalAddr); int iCounter, iStatus, n = 1, recv_sz; char *cBsdBuf = NULL; uint32_t stime, etime, rpt_stime; // ticks uint64_t rpt_sz = 0, tot_sz = 0; uint32_t time, tcnt = 0; // ms uint32_t intvl_sec = udp_data->rpt_intvl / OS_TICK_RATE_HZ; struct udp_datagram udp_hdr; struct client_hdr header; #ifdef DEBUG_DUAL_MODE dump_udp_data(udp_data); #endif cBsdBuf = sys_malloc(udp_data->buf_len); if (NULL == cBsdBuf) { DEBUGPRINT("UDP ERROR: allocate server buffer failed (len = %d).\r\n", udp_data->buf_len); return -1; } for (iCounter = 0; iCounter < udp_data->buf_len; iCounter++) { cBsdBuf[iCounter] = (char)(iCounter % 10); } udp_data->srv_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (udp_data->srv_fd < 0) { goto Exit2; } DEBUGPRINT("UDP: create server socket %d.\r\n", udp_data->srv_fd); setsockopt(udp_data->srv_fd, SOL_SOCKET, SO_REUSEADDR, (const char *) &n, sizeof( n ) ); sys_memset((char *)&sLocalAddr, 0, sizeof(sLocalAddr)); sLocalAddr.sin_family = AF_INET; sLocalAddr.sin_len = sizeof(sLocalAddr); sLocalAddr.sin_port = htons(udp_data->srv_port); sLocalAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* binding the UDP socket to the UDP server address */ iStatus = bind(udp_data->srv_fd, (struct sockaddr *)&sLocalAddr, iAddrSize); if (iStatus < 0) { DEBUGPRINT("UDP ERROR: bind udp server socket fd error!\r\n"); goto Exit1; } DEBUGPRINT("UDP: bind successfully.\r\n"); /* Process client header */ recv_sz = recvfrom(udp_data->srv_fd, cBsdBuf, udp_data->buf_len, 0, (struct sockaddr *)&sLocalAddr, &iAddrSize); tot_sz += recv_sz; rpt_sz += recv_sz; etime = rpt_stime = stime = sys_current_time_get(); if (udp_data->dualmode == 0) { /* Run as udp server. The server is created by user. */ DEBUGPRINT("UDP: Check client header.\r\n"); sys_memcpy(&udp_hdr, cBsdBuf, sizeof(udp_hdr)); sys_memcpy(&header, cBsdBuf + sizeof(udp_hdr), sizeof(header)); #ifdef DEBUG_DUAL_MODE // buffer_dump("Clent header:", &header, sizeof(header)); client_header_dump(&header); #endif if (ntohl(header.flags) & DUAL_MODE_RUN_NOW) { /* Dual mode, do a bidirectional test simultaneously */ /* Create udp client data to send packets. */ int ret = client_data_init(); if (ret != 0) { goto Exit1; } DEBUGPRINT("UDP: dual mode, start client task.\r\n"); udp_cli_data->buf_len = ntohl(header.bufferlen); if (udp_cli_data->buf_len == 0) udp_cli_data->buf_len = 1460; if (header.mAmount != 0) { header.mAmount = ntohl(header.mAmount); if (((uint32_t)header.mAmount) > 0x7fffffff) { header.mAmount = (-header.mAmount) / 100; udp_cli_data->time_limit = header.mAmount * OS_TICK_RATE_HZ + 100; } else { udp_cli_data->size_limit = header.mAmount; } } udp_cli_data->srv_port = ntohl(header.mPort); udp_cli_data->bandwidth = (uint32_t)(ntohl(header.mWindowSize) >> 3); DEBUGPRINT("UDP: client bandwidth is %d.\r\n", udp_cli_data->bandwidth); snprintf(udp_cli_data->srv_ip, sizeof(udp_cli_data->srv_ip), "%s", inet_ntoa(sCliAddr.sin_addr)); #ifdef DEBUG_DUAL_MODE dump_udp_data(udp_data); #endif udp_cli_data->task_hdl = sys_task_create(NULL, (const uint8_t *)"udp_client", NULL, UDP_TEST_STACK_SIZE, 0, UDP_TEST_CLIENT_PRIO + TASK_PRIO_HIGHER(1), (task_func_t)udp_task_func, udp_cli_data); if (udp_cli_data->task_hdl == NULL) { DEBUGPRINT("UDP ERROR: create udp client task failed.\r\n"); goto Exit1; } } else { if (header.mAmount != 0) { header.mAmount = ntohl(header.mAmount); if (((uint32_t)header.mAmount) > 0x7fffffff) { header.mAmount = (-header.mAmount) / 100; udp_data->time_limit = header.mAmount * OS_TICK_RATE_HZ + 100; DEBUGPRINT("UDP: time limit is %d.\r\n", udp_data->time_limit); } else { udp_data->size_limit = header.mAmount; DEBUGPRINT("UDP: size limit is %d.\r\n", udp_data->size_limit); } } } } else { /* Run as udp client. This server is auto created since the client is dual mode. */ } /* Waits packets from the UDP client */ if (udp_data->size_limit > 0) { while (!udp_terminate && (tot_sz < udp_data->size_limit)) { recv_sz = recvfrom(udp_data->srv_fd, cBsdBuf, udp_data->buf_len, 0, (struct sockaddr *)&sLocalAddr, &iAddrSize); if (recv_sz < 0) { DEBUGPRINT("UDP ERROR: server recv data error. recv_sz is %d.\r\n", recv_sz); goto Exit1; } etime = sys_current_time_get(); tot_sz += recv_sz; rpt_sz += recv_sz; time = (etime - rpt_stime) * OS_MS_PER_TICK; if ((etime - rpt_stime) >= udp_data->rpt_intvl) { if (tcnt == 0) DEBUGPRINT("\t\tInterval\t\tTransfer\t\tBandwidth\r\n"); DEBUGPRINT("Recv\t%4d - %4d sec\t\t%4d KBytes\t\t%5d Kbps\r\n", tcnt, (tcnt + intvl_sec), (uint32_t)(rpt_sz >> 10), (uint32_t)((rpt_sz << 3) / time)); tcnt += intvl_sec; rpt_stime = etime; rpt_sz = 0; } } } else { while (!udp_terminate && ((etime - stime) <= udp_data->time_limit)) { recv_sz = recvfrom(udp_data->srv_fd, cBsdBuf, udp_data->buf_len, 0, (struct sockaddr *)&sLocalAddr, &iAddrSize); if (recv_sz < 0) { DEBUGPRINT("UDP ERROR: server recv data error. recv_sz is %d.\r\n", recv_sz); goto Exit1; } etime = sys_current_time_get(); tot_sz += recv_sz; rpt_sz += recv_sz; time = (etime - rpt_stime) * OS_MS_PER_TICK; if ((etime - rpt_stime) >= udp_data->rpt_intvl) { if (tcnt == 0) DEBUGPRINT("\t\tInterval\t\tTransfer\t\tBandwidth\r\n"); DEBUGPRINT("Recv\t%4d - %4d sec\t\t%4d KBytes\t\t%5d Kbps\r\n", tcnt, (tcnt + intvl_sec), (uint32_t)(rpt_sz >> 10), (uint32_t)((rpt_sz << 3) / time)); // DEBUGPRINT("etime=%d stime=%d limit=%d\r\n", etime, stime, udp_data->time_limit); tcnt += intvl_sec; rpt_stime = etime; rpt_sz = 0; } } } time = (etime - stime) * OS_MS_PER_TICK; DEBUGPRINT("Total\t%4d - %4d sec\t\t%4d KBytes\t\t%5d Kbps\r\n", 0, tcnt, (uint32_t)(tot_sz >> 10), (uint32_t)((tot_sz << 3) / time)); Exit1: /* close the server socket */ close(udp_data->srv_fd); Exit2: /* free buffer */ sys_mfree(cBsdBuf); return 0; } /*! \brief udp task function \param[in] param: pointer to the input argument \param[out] none \retval none */ static void udp_task_func(void *param) { struct udp_data_t *udp_data = (struct udp_data_t *)param; if (udp_data->is_server == 1) { DEBUGPRINT("UDP: start udp server!\r\n"); udp_server(udp_data); DEBUGPRINT("UDP server task: used stack = %d, free stack = %d\r\n", (UDP_TEST_STACK_SIZE - sys_stack_free_get(NULL)), sys_stack_free_get(NULL)); DEBUGPRINT("UDP: udp server stopped!\r\n"); } else { DEBUGPRINT("UDP: start udp client!\r\n"); udp_client(udp_data); DEBUGPRINT("UDP client task: used stack = %d, free stack = %d\r\n", (UDP_TEST_STACK_SIZE - sys_stack_free_get(NULL)), sys_stack_free_get(NULL)); DEBUGPRINT("UDP: udp client stopped!\r\n"); } udp_data->task_hdl = NULL; sys_task_delete(NULL); } /*! \brief command of tcp \param[in] argc: counter of input argument \param[out] argv: pointer to the input argument \retval none */ void cmd_udp(int argc, char **argv) { int arg_cnt = 1, is_server = 0; char *endptr = NULL; udp_terminate = 0; /* Parse main option */ if (arg_cnt == 1) { if (strcmp(argv[1], "-s") == 0) { DEBUGPRINT("\r\nIperf2: start iperf2 server!\r\n"); int ret = server_data_init(); if (ret == ERROR_ALREADY_RUNNING || ret == ERROR_NO_MEMORY) return; arg_cnt += 1; is_server = 1; } else if (strcmp(argv[1], "-c") == 0) { DEBUGPRINT("\r\nIperf2: start iperf2 client!\r\n"); int ret = client_data_init(); if (ret == ERROR_ALREADY_RUNNING || ret == ERROR_NO_MEMORY) return; if (argc >= 3) snprintf(udp_cli_data->srv_ip, sizeof(udp_cli_data->srv_ip), "%s", argv[2]); else goto Exit; arg_cnt += 2; } else if (strcmp(argv[1], "exit") == 0) { int cnt = 0; udp_terminate = 1; if (udp_srv_data) { while ((udp_srv_data->task_hdl != NULL) && (cnt++ < 10)) sys_ms_sleep(100); sys_mfree(udp_srv_data); udp_srv_data = NULL; } if (udp_cli_data) { cnt = 0; while ((udp_cli_data->task_hdl != NULL) && (cnt++ < 10)) sys_ms_sleep(100); sys_mfree(udp_cli_data); udp_cli_data = NULL; } return; } else { goto Exit; } } if (is_server) DEBUG_ASSERT(udp_srv_data != NULL); else DEBUG_ASSERT(udp_cli_data != NULL); /* Parse other options */ while (arg_cnt < argc) { /* Client/Server */ if (strcmp(argv[arg_cnt], "-i") == 0) { uint32_t intvl = 0; if (argc <= (arg_cnt + 1)) goto Exit; intvl = (uint32_t)atoi(argv[arg_cnt + 1]) * OS_TICK_RATE_HZ; if (intvl > 3600 * OS_TICK_RATE_HZ) { DEBUGPRINT("UDP WARNNING: Report interval is larger than 3600 seconds. Use 3600 seconds instead.\r\n"); intvl = 3600 * OS_TICK_RATE_HZ; } if (intvl > 0) { if (is_server) { udp_srv_data->rpt_intvl = intvl; } else { udp_cli_data->rpt_intvl = intvl; } } arg_cnt += 2; } else if (strcmp(argv[arg_cnt], "-l") == 0) { uint32_t len = 0; if (argc <= (arg_cnt + 1)) goto Exit; len = (uint32_t)atoi(argv[arg_cnt + 1]); if (len > 5000) { DEBUGPRINT("UDP WARNNING: To save memory, the buffer size is preferably less than 5K. Use 5K instead.\r\n"); len = 5000; } if (len > 0) { if (is_server) { udp_srv_data->buf_len = len; } else { udp_cli_data->buf_len = len; } } arg_cnt += 2; } else if (strcmp(argv[arg_cnt], "-p") == 0) { if (argc <= (arg_cnt + 1)) goto Exit; if (is_server) { udp_srv_data->srv_port = (uint16_t)atoi(argv[arg_cnt + 1]); } else { udp_cli_data->srv_port = (uint16_t)atoi(argv[arg_cnt + 1]); } arg_cnt += 2; /* Client Only */ } else if (strcmp(argv[arg_cnt], "-b") == 0) { if (argc <= (arg_cnt + 1)) goto Exit; if (is_server) { goto Exit; } else { udp_cli_data->bandwidth = (byte_atoi(argv[arg_cnt + 1]) >> 3); // unit: Bytes per second } arg_cnt += 2; } else if (strcmp(argv[arg_cnt], "-n") == 0) { if (argc <= (arg_cnt + 1)) goto Exit; if (is_server) { goto Exit; } else { udp_cli_data->size_limit = byte_atoi(argv[arg_cnt + 1]); } arg_cnt += 2; } else if (strcmp(argv[arg_cnt], "-t") == 0) { if (argc <= (arg_cnt + 1)) goto Exit; if (is_server) { goto Exit; } else { udp_cli_data->time_limit = (uint32_t)atoi(argv[arg_cnt + 1]) * OS_TICK_RATE_HZ + 100; } arg_cnt += 2; } else if (strcmp(argv[arg_cnt], "-d") == 0) { if (is_server) { goto Exit; } else { udp_cli_data->dualmode = 1; } arg_cnt += 1; } else if (strcmp(argv[arg_cnt], "-u") == 0){ arg_cnt += 1;/* ignore -u option */ } else if (strcmp(argv[arg_cnt], "-S") == 0){ if (argc <= (arg_cnt + 1)) goto Exit; if (is_server) { goto Exit; } else { udp_cli_data->tos = (uint8_t)strtoul(argv[arg_cnt + 1], &endptr, 0); if (*endptr != '\0') { DEBUGPRINT("iperf: invalid tos\r\n"); goto Exit; } } arg_cnt += 2; } else { goto Exit; } } /* Check report interval */ if ((udp_cli_data->size_limit == 0) && (udp_cli_data->rpt_intvl > udp_cli_data->time_limit)) { udp_cli_data->rpt_intvl = udp_cli_data->time_limit; } /* Create task */ if (is_server) { udp_srv_data->task_hdl = sys_task_create(NULL, (const uint8_t *)"udp_server", NULL, UDP_TEST_STACK_SIZE, 0, UDP_TEST_SERVER_PRIO, (task_func_t)udp_task_func, udp_srv_data); if (udp_srv_data->task_hdl == NULL) { DEBUGPRINT("UDP ERROR: create udp server task failed.\r\n"); return; } } else { udp_cli_data->task_hdl = sys_task_create(NULL, (const uint8_t *)"udp_client", NULL, UDP_TEST_STACK_SIZE, 0, UDP_TEST_CLIENT_PRIO, (task_func_t)udp_task_func, udp_cli_data); if (udp_cli_data->task_hdl == NULL) { DEBUGPRINT("UDP ERROR: create udp client task failed.\r\n"); return; } if (udp_cli_data->dualmode == 1) { int ret = server_data_init(); if (ret == ERROR_ALREADY_RUNNING || ret == ERROR_NO_MEMORY) return; udp_srv_data->srv_port = udp_cli_data->srv_port; udp_srv_data->dualmode = 1; udp_srv_data->time_limit = udp_cli_data->time_limit - 100; udp_srv_data->size_limit = udp_cli_data->size_limit; udp_srv_data->task_hdl = sys_task_create(NULL, (const uint8_t *)"udp_server", NULL, UDP_TEST_STACK_SIZE, 0, UDP_TEST_SERVER_PRIO + TASK_PRIO_LOWER(1), (task_func_t)udp_task_func, udp_srv_data); if (udp_srv_data->task_hdl == NULL) { DEBUGPRINT("UDP ERROR: create udp server task failed.\r\n"); return; } } } return; Exit: DEBUGPRINT("\rIperf2: iperf2 test command format error!\r\n"); DEBUGPRINT("\r\nUsage: \"iperf -s\" to start iperf2 server or \"iperf -c\" to start iperf2 client or \"iperf -h\" for help\r\n"); }