diff --git a/include/zephyr/net/zperf.h b/include/zephyr/net/zperf.h index 5dfe2f13d3c..e008db83b37 100644 --- a/include/zephyr/net/zperf.h +++ b/include/zephyr/net/zperf.h @@ -39,6 +39,10 @@ struct zperf_upload_params { } options; }; +struct zperf_download_params { + uint16_t port; +}; + struct zperf_results { uint32_t nb_packets_sent; uint32_t nb_packets_rcvd; @@ -117,6 +121,34 @@ int zperf_udp_upload_async(const struct zperf_upload_params *param, int zperf_tcp_upload_async(const struct zperf_upload_params *param, zperf_callback callback, void *user_data); +/** + * @brief Start UDP server. + * + * @note Only one UDP server instance can run at a time. + * + * @param param Download parameters. + * @param callback Session results callback. + * @param user_data A pointer to the user data to be provided with the callback. + * + * @return 0 if server was started, a negative error code otherwise. + */ +int zperf_udp_download(const struct zperf_download_params *param, + zperf_callback callback, void *user_data); + +/** + * @brief Start TCP server. + * + * @note Only one TCP server instance can run at a time. + * + * @param param Download parameters. + * @param callback Session results callback. + * @param user_data A pointer to the user data to be provided with the callback. + * + * @return 0 if server was started, a negative error code otherwise. + */ +int zperf_tcp_download(const struct zperf_download_params *param, + zperf_callback callback, void *user_data); + #ifdef __cplusplus } #endif diff --git a/subsys/net/lib/zperf/zperf_internal.h b/subsys/net/lib/zperf/zperf_internal.h index 49abefe1537..1f8223a42c6 100644 --- a/subsys/net/lib/zperf/zperf_internal.h +++ b/subsys/net/lib/zperf/zperf_internal.h @@ -81,18 +81,12 @@ static inline uint32_t time_delta(uint32_t ts, uint32_t t) return (t >= ts) ? (t - ts) : (ULONG_MAX - ts + t); } -int zperf_get_ipv6_addr(const struct shell *sh, char *host, - char *prefix_str, struct in6_addr *addr); +int zperf_get_ipv6_addr(char *host, char *prefix_str, struct in6_addr *addr); struct sockaddr_in6 *zperf_get_sin6(void); -int zperf_get_ipv4_addr(const struct shell *sh, char *host, - struct in_addr *addr); +int zperf_get_ipv4_addr(char *host, struct in_addr *addr); struct sockaddr_in *zperf_get_sin(void); -extern void zperf_udp_receiver_init(const struct shell *sh, int port); - -extern void zperf_tcp_receiver_init(const struct shell *sh, int port); - extern void connect_ap(char *ssid); const struct in_addr *zperf_get_default_if_in4_addr(void); diff --git a/subsys/net/lib/zperf/zperf_shell.c b/subsys/net/lib/zperf/zperf_shell.c index 3697c549ba8..6834deb3c2a 100644 --- a/subsys/net/lib/zperf/zperf_shell.c +++ b/subsys/net/lib/zperf/zperf_shell.c @@ -127,8 +127,7 @@ static int parse_ipv6_addr(const struct shell *sh, char *host, char *port, return 0; } -int zperf_get_ipv6_addr(const struct shell *sh, char *host, - char *prefix_str, struct in6_addr *addr) +int zperf_get_ipv6_addr(char *host, char *prefix_str, struct in6_addr *addr) { struct net_if_ipv6_prefix *prefix; struct net_if_addr *ifaddr; @@ -149,8 +148,7 @@ int zperf_get_ipv6_addr(const struct shell *sh, char *host, ifaddr = net_if_ipv6_addr_add(net_if_get_default(), addr, NET_ADDR_MANUAL, 0); if (!ifaddr) { - shell_fprintf(sh, SHELL_WARNING, - "Cannot set IPv6 address %s\n", host); + NET_ERR("Cannot set IPv6 address %s", host); return -EINVAL; } @@ -158,8 +156,7 @@ int zperf_get_ipv6_addr(const struct shell *sh, char *host, addr, prefix_len, NET_IPV6_ND_INFINITE_LIFETIME); if (!prefix) { - shell_fprintf(sh, SHELL_WARNING, - "Cannot set IPv6 prefix %s\n", prefix_str); + NET_ERR("Cannot set IPv6 prefix %s", prefix_str); return -EINVAL; } @@ -192,8 +189,7 @@ static int parse_ipv4_addr(const struct shell *sh, char *host, char *port, return 0; } -int zperf_get_ipv4_addr(const struct shell *sh, char *host, - struct in_addr *addr) +int zperf_get_ipv4_addr(char *host, struct in_addr *addr) { struct net_if_addr *ifaddr; int ret; @@ -210,8 +206,7 @@ int zperf_get_ipv4_addr(const struct shell *sh, char *host, ifaddr = net_if_ipv4_addr_add(net_if_get_default(), addr, NET_ADDR_MANUAL, 0); if (!ifaddr) { - shell_fprintf(sh, SHELL_WARNING, - "Cannot set IPv4 address %s\n", host); + NET_ERR("Cannot set IPv4 address %s", host); return -EINVAL; } @@ -250,7 +245,7 @@ static int cmd_setip(const struct shell *sh, size_t argc, char *argv[]) return -ENOEXEC; } - if (zperf_get_ipv6_addr(sh, argv[start + 1], argv[start + 2], + if (zperf_get_ipv6_addr(argv[start + 1], argv[start + 2], &ipv6) < 0) { shell_fprintf(sh, SHELL_WARNING, "Unable to set IP\n"); @@ -268,7 +263,7 @@ static int cmd_setip(const struct shell *sh, size_t argc, char *argv[]) return -ENOEXEC; } - if (zperf_get_ipv4_addr(sh, argv[start + 1], &ipv4) < 0) { + if (zperf_get_ipv4_addr(argv[start + 1], &ipv4) < 0) { shell_fprintf(sh, SHELL_WARNING, "Unable to set IP\n"); return -ENOEXEC; @@ -286,7 +281,7 @@ static int cmd_setip(const struct shell *sh, size_t argc, char *argv[]) return -ENOEXEC; } - if (zperf_get_ipv4_addr(sh, argv[start + 1], + if (zperf_get_ipv4_addr(argv[start + 1], &ipv4) < 0) { shell_fprintf(sh, SHELL_WARNING, "Unable to set IP\n"); @@ -302,7 +297,7 @@ static int cmd_setip(const struct shell *sh, size_t argc, char *argv[]) return -ENOEXEC; } - if (zperf_get_ipv6_addr(sh, argv[start + 1], + if (zperf_get_ipv6_addr(argv[start + 1], argv[start + 2], &ipv6) < 0) { shell_fprintf(sh, SHELL_WARNING, "Unable to set IP\n"); @@ -318,35 +313,90 @@ static int cmd_setip(const struct shell *sh, size_t argc, char *argv[]) return 0; } +static void udp_session_cb(enum zperf_status status, + struct zperf_results *result, + void *user_data) +{ + const struct shell *sh = user_data; + + switch (status) { + case ZPERF_SESSION_STARTED: + shell_fprintf(sh, SHELL_NORMAL, "New session started.\n"); + break; + + case ZPERF_SESSION_FINISHED: { + uint32_t rate_in_kbps; + + /* Compute baud rate */ + if (result->time_in_us != 0U) { + rate_in_kbps = (uint32_t) + (((uint64_t)result->total_len * 8ULL * + (uint64_t)USEC_PER_SEC) / + ((uint64_t)result->time_in_us * 1024ULL)); + } else { + rate_in_kbps = 0U; + } + + shell_fprintf(sh, SHELL_NORMAL, "End of session!\n"); + + shell_fprintf(sh, SHELL_NORMAL, " duration:\t\t"); + print_number(sh, result->time_in_us, TIME_US, TIME_US_UNIT); + shell_fprintf(sh, SHELL_NORMAL, "\n"); + + shell_fprintf(sh, SHELL_NORMAL, " received packets:\t%u\n", + result->nb_packets_rcvd); + shell_fprintf(sh, SHELL_NORMAL, " nb packets lost:\t%u\n", + result->nb_packets_lost); + shell_fprintf(sh, SHELL_NORMAL, " nb packets outorder:\t%u\n", + result->nb_packets_outorder); + + shell_fprintf(sh, SHELL_NORMAL, " jitter:\t\t\t"); + print_number(sh, result->jitter_in_us, TIME_US, TIME_US_UNIT); + shell_fprintf(sh, SHELL_NORMAL, "\n"); + + shell_fprintf(sh, SHELL_NORMAL, " rate:\t\t\t"); + print_number(sh, rate_in_kbps, KBPS, KBPS_UNIT); + shell_fprintf(sh, SHELL_NORMAL, "\n"); + + break; + } + + case ZPERF_SESSION_ERROR: + shell_fprintf(sh, SHELL_ERROR, "UDP session error.\n"); + break; + } +} + static int cmd_udp_download(const struct shell *sh, size_t argc, char *argv[]) { if (IS_ENABLED(CONFIG_NET_UDP)) { - static bool udp_stopped = true; - int port, start = 0; + struct zperf_download_params param = { 0 }; + int ret; do_init(sh); if (argc >= 2) { - port = strtoul(argv[start + 1], NULL, 10); + param.port = strtoul(argv[1], NULL, 10); } else { - port = DEF_PORT; + param.port = DEF_PORT; } - if (!udp_stopped) { + ret = zperf_udp_download(¶m, udp_session_cb, (void *)sh); + if (ret == -EALREADY) { shell_fprintf(sh, SHELL_WARNING, "UDP server already started!\n"); return -ENOEXEC; + } else if (ret < 0) { + shell_fprintf(sh, SHELL_ERROR, + "Failed to start UDP server!\n"); + return -ENOEXEC; } - zperf_udp_receiver_init(sh, port); - k_yield(); - udp_stopped = false; - shell_fprintf(sh, SHELL_NORMAL, - "UDP server started on port %u\n", port); + "UDP server started on port %u\n", param.port); return 0; } else { @@ -974,30 +1024,77 @@ void zperf_tcp_started(void) tcp_running = true; } +static void tcp_session_cb(enum zperf_status status, + struct zperf_results *result, + void *user_data) +{ + const struct shell *sh = user_data; + + switch (status) { + case ZPERF_SESSION_STARTED: + shell_fprintf(sh, SHELL_NORMAL, "New TCP session started.\n"); + break; + + case ZPERF_SESSION_FINISHED: { + uint32_t rate_in_kbps; + + /* Compute baud rate */ + if (result->time_in_us != 0U) { + rate_in_kbps = (uint32_t) + (((uint64_t)result->total_len * 8ULL * + (uint64_t)USEC_PER_SEC) / + ((uint64_t)result->time_in_us * 1024ULL)); + } else { + rate_in_kbps = 0U; + } + + shell_fprintf(sh, SHELL_NORMAL, "TCP session ended\n"); + + shell_fprintf(sh, SHELL_NORMAL, " Duration:\t\t"); + print_number(sh, result->time_in_us, TIME_US, TIME_US_UNIT); + shell_fprintf(sh, SHELL_NORMAL, "\n"); + + shell_fprintf(sh, SHELL_NORMAL, " rate:\t\t\t"); + print_number(sh, rate_in_kbps, KBPS, KBPS_UNIT); + shell_fprintf(sh, SHELL_NORMAL, "\n"); + + break; + } + + case ZPERF_SESSION_ERROR: + shell_fprintf(sh, SHELL_ERROR, "TCP session error.\n"); + break; + } +} + static int cmd_tcp_download(const struct shell *sh, size_t argc, char *argv[]) { if (IS_ENABLED(CONFIG_NET_TCP)) { - int port; + struct zperf_download_params param = { 0 }; + int ret; do_init(sh); if (argc >= 2) { - port = strtoul(argv[1], NULL, 10); + param.port = strtoul(argv[1], NULL, 10); } else { - port = DEF_PORT; + param.port = DEF_PORT; } - if (tcp_running) { + ret = zperf_tcp_download(¶m, tcp_session_cb, (void *)sh); + if (ret == -EALREADY) { shell_fprintf(sh, SHELL_WARNING, "TCP server already started!\n"); return -ENOEXEC; + } else if (ret < 0) { + shell_fprintf(sh, SHELL_ERROR, + "Failed to start TCP server!\n"); + return -ENOEXEC; } - zperf_tcp_receiver_init(sh, port); - shell_fprintf(sh, SHELL_NORMAL, - "TCP server started on port %u\n", port); + "TCP server started on port %u\n", param.port); return 0; } else { @@ -1020,7 +1117,7 @@ static void zperf_init(const struct shell *sh) shell_fprintf(sh, SHELL_NORMAL, "\n"); if (IS_ENABLED(CONFIG_NET_IPV6) && MY_IP6ADDR) { - if (zperf_get_ipv6_addr(sh, MY_IP6ADDR, MY_PREFIX_LEN_STR, + if (zperf_get_ipv6_addr(MY_IP6ADDR, MY_PREFIX_LEN_STR, &ipv6) < 0) { shell_fprintf(sh, SHELL_WARNING, "Unable to set IP\n"); @@ -1047,7 +1144,7 @@ static void zperf_init(const struct shell *sh) } if (IS_ENABLED(CONFIG_NET_IPV4) && MY_IP4ADDR) { - if (zperf_get_ipv4_addr(sh, MY_IP4ADDR, &ipv4) < 0) { + if (zperf_get_ipv4_addr(MY_IP4ADDR, &ipv4) < 0) { shell_fprintf(sh, SHELL_WARNING, "Unable to set IP\n"); } else { diff --git a/subsys/net/lib/zperf/zperf_tcp_receiver.c b/subsys/net/lib/zperf/zperf_tcp_receiver.c index da4c0b13af7..309f11646dd 100644 --- a/subsys/net/lib/zperf/zperf_tcp_receiver.c +++ b/subsys/net/lib/zperf/zperf_tcp_receiver.c @@ -16,7 +16,6 @@ LOG_MODULE_DECLARE(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL); #include #include "zperf_internal.h" -#include "shell_utils.h" #include "zperf_session.h" /* To get net_sprint_ipv{4|6}_addr() */ @@ -44,10 +43,14 @@ static bool init_done; #define TCP_RECEIVER_BUF_SIZE 1500 -K_THREAD_STACK_DEFINE(tcp_receiver_stack_area, TCP_RECEIVER_STACK_SIZE); -struct k_thread tcp_receiver_thread_data; +static K_THREAD_STACK_DEFINE(tcp_receiver_stack_area, TCP_RECEIVER_STACK_SIZE); +static struct k_thread tcp_receiver_thread_data; -static void tcp_received(const struct shell *sh, int sock, size_t datalen) +static zperf_callback tcp_session_cb; +static void *tcp_user_data; +static bool tcp_server_running; + +static void tcp_received(int sock, size_t datalen) { struct session *session; int64_t time; @@ -56,7 +59,7 @@ static void tcp_received(const struct shell *sh, int sock, size_t datalen) session = get_tcp_session(sock); if (!session) { - shell_fprintf(sh, SHELL_WARNING, "Cannot get a session!\n"); + NET_ERR("Cannot get a session!"); return; } @@ -64,47 +67,34 @@ static void tcp_received(const struct shell *sh, int sock, size_t datalen) case STATE_COMPLETED: break; case STATE_NULL: - shell_fprintf(sh, SHELL_NORMAL, - "New TCP session started\n"); zperf_reset_session_stats(session); session->start_time = k_uptime_ticks(); session->state = STATE_ONGOING; + + if (tcp_session_cb != NULL) { + tcp_session_cb(ZPERF_SESSION_STARTED, NULL, + tcp_user_data); + } + __fallthrough; case STATE_ONGOING: session->counter++; session->length += datalen; if (datalen == 0) { /* EOF */ - uint32_t rate_in_kbps; - uint32_t duration; - - duration = k_ticks_to_us_ceil32(time - - session->start_time); + struct zperf_results results = { 0 }; session->state = STATE_COMPLETED; - /* Compute baud rate */ - if (duration != 0U) { - rate_in_kbps = (uint32_t) - ((session->length * 8ULL * - (uint64_t)USEC_PER_SEC) / - ((uint64_t)duration * 1024ULL)); - } else { - rate_in_kbps = 0U; + results.total_len = session->length; + results.time_in_us = k_ticks_to_us_ceil32( + time - session->start_time); + + if (tcp_session_cb != NULL) { + tcp_session_cb(ZPERF_SESSION_FINISHED, &results, + tcp_user_data); } - shell_fprintf(sh, SHELL_NORMAL, - "TCP session ended\n"); - - shell_fprintf(sh, SHELL_NORMAL, - " Duration:\t\t"); - print_number(sh, duration, TIME_US, TIME_US_UNIT); - shell_fprintf(sh, SHELL_NORMAL, "\n"); - - shell_fprintf(sh, SHELL_NORMAL, " rate:\t\t\t"); - print_number(sh, rate_in_kbps, KBPS, KBPS_UNIT); - shell_fprintf(sh, SHELL_NORMAL, "\n"); - zperf_tcp_stopped(); session->state = STATE_NULL; @@ -115,16 +105,16 @@ static void tcp_received(const struct shell *sh, int sock, size_t datalen) case STATE_LAST_PACKET_RECEIVED: break; default: - shell_fprintf(sh, SHELL_WARNING, "Unsupported case\n"); + NET_ERR("Unsupported case"); } } void tcp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) { + ARG_UNUSED(ptr1); ARG_UNUSED(ptr3); static uint8_t buf[TCP_RECEIVER_BUF_SIZE]; - const struct shell *sh = ptr1; int port = POINTER_TO_INT(ptr2); struct zsock_pollfd fds[SOCK_ID_MAX] = { 0 }; int ret; @@ -141,18 +131,16 @@ void tcp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) fds[SOCK_ID_IPV4_LISTEN].fd = zsock_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (fds[SOCK_ID_IPV4_LISTEN].fd < 0) { - shell_fprintf(sh, SHELL_WARNING, - "Cannot create IPv4 network socket.\n"); + NET_ERR("Cannot create IPv4 network socket."); goto cleanup; } if (MY_IP4ADDR && strlen(MY_IP4ADDR)) { /* Use Setting IP */ - ret = zperf_get_ipv4_addr(sh, MY_IP4ADDR, + ret = zperf_get_ipv4_addr(MY_IP4ADDR, &in4_addr_my->sin_addr); if (ret < 0) { - shell_fprintf(sh, SHELL_WARNING, - "Unable to set IPv4\n"); + NET_WARN("Unable to set IPv4"); goto use_existing_ipv4; } } else { @@ -160,9 +148,8 @@ void tcp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) /* Use existing IP */ in4_addr = zperf_get_default_if_in4_addr(); if (!in4_addr) { - shell_fprintf(sh, SHELL_WARNING, - "Unable to get IPv4 by default\n"); - return; + NET_ERR("Unable to get IPv4 by default"); + goto cleanup; } memcpy(&in4_addr_my->sin_addr, in4_addr, sizeof(struct in_addr)); @@ -170,24 +157,21 @@ void tcp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) in4_addr_my->sin_port = htons(port); - shell_fprintf(sh, SHELL_NORMAL, "Binding to %s\n", - net_sprint_ipv4_addr(&in4_addr_my->sin_addr)); + NET_INFO("Binding to %s", + net_sprint_ipv4_addr(&in4_addr_my->sin_addr)); ret = zsock_bind(fds[SOCK_ID_IPV4_LISTEN].fd, (struct sockaddr *)in4_addr_my, sizeof(struct sockaddr_in)); if (ret < 0) { - shell_fprintf(sh, SHELL_WARNING, - "Cannot bind IPv4 UDP port %d (%d)\n", - ntohs(in4_addr_my->sin_port), - errno); + NET_ERR("Cannot bind IPv4 UDP port %d (%d)", + ntohs(in4_addr_my->sin_port), errno); goto cleanup; } ret = zsock_listen(fds[SOCK_ID_IPV4_LISTEN].fd, 1); if (ret < 0) { - shell_fprintf(sh, SHELL_WARNING, - "Cannot listen IPv4 TCP (%d)", errno); + NET_ERR("Cannot listen IPv4 TCP (%d)", errno); goto cleanup; } @@ -202,19 +186,17 @@ void tcp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) fds[SOCK_ID_IPV6_LISTEN].fd = zsock_socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); if (fds[SOCK_ID_IPV6_LISTEN].fd < 0) { - shell_fprintf(sh, SHELL_WARNING, - "Cannot create IPv6 network socket.\n"); + NET_ERR("Cannot create IPv6 network socket."); goto cleanup; } if (MY_IP6ADDR && strlen(MY_IP6ADDR)) { /* Use Setting IP */ - ret = zperf_get_ipv6_addr(sh, MY_IP6ADDR, + ret = zperf_get_ipv6_addr(MY_IP6ADDR, MY_PREFIX_LEN_STR, &in6_addr_my->sin6_addr); if (ret < 0) { - shell_fprintf(sh, SHELL_WARNING, - "Unable to set IPv6\n"); + NET_WARN("Unable to set IPv6"); goto use_existing_ipv6; } } else { @@ -222,9 +204,8 @@ void tcp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) /* Use existing IP */ in6_addr = zperf_get_default_if_in6_addr(); if (!in6_addr) { - shell_fprintf(sh, SHELL_WARNING, - "Unable to get IPv4 by default\n"); - return; + NET_ERR("Unable to get IPv4 by default"); + goto cleanup; } memcpy(&in6_addr_my->sin6_addr, in6_addr, sizeof(struct in6_addr)); @@ -232,32 +213,28 @@ void tcp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) in6_addr_my->sin6_port = htons(port); - shell_fprintf(sh, SHELL_NORMAL, "Binding to %s\n", - net_sprint_ipv6_addr(&in6_addr_my->sin6_addr)); + NET_INFO("Binding to %s", + net_sprint_ipv6_addr(&in6_addr_my->sin6_addr)); ret = zsock_bind(fds[SOCK_ID_IPV6_LISTEN].fd, (struct sockaddr *)in6_addr_my, sizeof(struct sockaddr_in6)); if (ret < 0) { - shell_fprintf(sh, SHELL_WARNING, - "Cannot bind IPv6 UDP port %d (%d)\n", - ntohs(in6_addr_my->sin6_port), - errno); + NET_ERR("Cannot bind IPv6 UDP port %d (%d)", + ntohs(in6_addr_my->sin6_port), errno); goto cleanup; } ret = zsock_listen(fds[SOCK_ID_IPV6_LISTEN].fd, 1); if (ret < 0) { - shell_fprintf(sh, SHELL_WARNING, - "Cannot listen IPv6 TCP (%d)", errno); + NET_ERR("Cannot listen IPv6 TCP (%d)", errno); goto cleanup; } fds[SOCK_ID_IPV6_LISTEN].events = ZSOCK_POLLIN; } - shell_fprintf(sh, SHELL_NORMAL, - "Listening on port %d\n", port); + NET_INFO("Listening on port %d", port); /* TODO Investigate started/stopped logic */ zperf_tcp_started(); @@ -266,9 +243,7 @@ void tcp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) while (true) { ret = zsock_poll(fds, ARRAY_SIZE(fds), -1); if (ret < 0) { - shell_fprintf(sh, SHELL_WARNING, - "TCP receiver poll error (%d)\n", - errno); + NET_ERR("TCP receiver poll error (%d)", errno); goto cleanup; } @@ -278,9 +253,7 @@ void tcp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) if ((fds[i].revents & ZSOCK_POLLERR) || (fds[i].revents & ZSOCK_POLLNVAL)) { - shell_fprintf( - sh, SHELL_WARNING, - "TCP receiver IPv%d socket error\n", + NET_ERR("TCP receiver IPv%d socket error", (i <= SOCK_ID_IPV4_DATA) ? 4 : 6); goto cleanup; } @@ -296,9 +269,7 @@ void tcp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) &addrlen); if (sock < 0) { - shell_fprintf( - sh, SHELL_WARNING, - "TCP receiver IPv%d accept error\n", + NET_ERR("TCP receiver IPv%d accept error", (i <= SOCK_ID_IPV4_DATA) ? 4 : 6); goto cleanup; } @@ -324,15 +295,13 @@ void tcp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) case SOCK_ID_IPV6_DATA: ret = zsock_recv(fds[i].fd, buf, sizeof(buf), 0); if (ret < 0) { - shell_fprintf( - sh, SHELL_WARNING, - "recv failed on IPv%d socket (%d)\n", + NET_ERR("recv failed on IPv%d socket (%d)", (i <= SOCK_ID_IPV4_DATA) ? 4 : 6, errno); goto cleanup; } - tcp_received(sh, fds[i].fd, ret); + tcp_received(fds[i].fd, ret); if (ret == 0) { zsock_close(fds[i].fd); @@ -345,6 +314,11 @@ void tcp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) } cleanup: + if (tcp_session_cb != NULL) { + tcp_session_cb(ZPERF_SESSION_ERROR, NULL, + tcp_user_data); + } + for (int i = 0; i < ARRAY_SIZE(fds); i++) { if (fds[i].fd >= 0) { zsock_close(fds[i].fd); @@ -352,7 +326,7 @@ cleanup: } } -void zperf_tcp_receiver_init(const struct shell *sh, int port) +void zperf_tcp_receiver_init(int port) { if (init_done) { zperf_tcp_started(); @@ -363,9 +337,29 @@ void zperf_tcp_receiver_init(const struct shell *sh, int port) tcp_receiver_stack_area, K_THREAD_STACK_SIZEOF(tcp_receiver_stack_area), tcp_receiver_thread, - (void *)sh, INT_TO_POINTER(port), NULL, + NULL, INT_TO_POINTER(port), NULL, TCP_RECEIVER_THREAD_PRIORITY, IS_ENABLED(CONFIG_USERSPACE) ? K_USER | K_INHERIT_PERMS : 0, K_NO_WAIT); } + +int zperf_tcp_download(const struct zperf_download_params *param, + zperf_callback callback, void *user_data) +{ + if (param == NULL || callback == NULL) { + return -EINVAL; + } + + if (tcp_server_running) { + return -EALREADY; + } + + tcp_session_cb = callback; + tcp_user_data = user_data; + tcp_server_running = true; + + zperf_tcp_receiver_init(param->port); + + return 0; +} diff --git a/subsys/net/lib/zperf/zperf_udp_receiver.c b/subsys/net/lib/zperf/zperf_udp_receiver.c index 705eb5bef4f..f5e7486772f 100644 --- a/subsys/net/lib/zperf/zperf_udp_receiver.c +++ b/subsys/net/lib/zperf/zperf_udp_receiver.c @@ -16,7 +16,6 @@ LOG_MODULE_DECLARE(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL); #include #include "zperf_internal.h" -#include "shell_utils.h" #include "zperf_session.h" /* To get net_sprint_ipv{4|6}_addr() */ @@ -40,8 +39,12 @@ static struct sockaddr_in *in4_addr_my; #define UDP_RECEIVER_BUF_SIZE 1500 -K_THREAD_STACK_DEFINE(udp_receiver_stack_area, UDP_RECEIVER_STACK_SIZE); -struct k_thread udp_receiver_thread_data; +static K_THREAD_STACK_DEFINE(udp_receiver_stack_area, UDP_RECEIVER_STACK_SIZE); +static struct k_thread udp_receiver_thread_data; + +static zperf_callback udp_session_cb; +static void *udp_user_data; +static bool udp_server_running; static inline void build_reply(struct zperf_udp_datagram *hdr, struct zperf_server_hdr *stat, @@ -71,8 +74,7 @@ static inline void build_reply(struct zperf_udp_datagram *hdr, #define BUF_SIZE sizeof(struct zperf_udp_datagram) + \ sizeof(struct zperf_server_hdr) -static int zperf_receiver_send_stat(const struct shell *sh, - int sock, const struct sockaddr *addr, +static int zperf_receiver_send_stat(int sock, const struct sockaddr *addr, struct zperf_udp_datagram *hdr, struct zperf_server_hdr *stat) { @@ -86,15 +88,13 @@ static int zperf_receiver_send_stat(const struct shell *sh, sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); if (ret < 0) { - shell_fprintf(sh, SHELL_WARNING, - " Cannot send data to peer (%d)", errno); + NET_ERR("Cannot send data to peer (%d)", errno); } return ret; } -static void udp_received(const struct shell *sh, int sock, - const struct sockaddr *addr, uint8_t *data, +static void udp_received(int sock, const struct sockaddr *addr, uint8_t *data, size_t datalen) { struct zperf_udp_datagram *hdr; @@ -104,8 +104,7 @@ static void udp_received(const struct shell *sh, int sock, int32_t id; if (datalen < sizeof(struct zperf_udp_datagram)) { - shell_fprintf(sh, SHELL_WARNING, - "Short iperf packet!\n"); + NET_WARN("Short iperf packet!"); return; } @@ -114,8 +113,7 @@ static void udp_received(const struct shell *sh, int sock, session = get_session(addr, SESSION_UDP); if (!session) { - shell_fprintf(sh, SHELL_WARNING, - "Cannot get a session!\n"); + NET_ERR("Cannot get a session!"); return; } @@ -128,44 +126,33 @@ static void udp_received(const struct shell *sh, int sock, /* Session is already completed: Resend the stat packet * and continue */ - if (zperf_receiver_send_stat(sh, sock, addr, hdr, + if (zperf_receiver_send_stat(sock, addr, hdr, &session->stat) < 0) { - shell_fprintf(sh, SHELL_WARNING, - "Failed to send the packet\n"); + NET_ERR("Failed to send the packet"); } } else { - /* Start a new session! */ - shell_fprintf(sh, SHELL_NORMAL, - "New session started.\n"); - zperf_reset_session_stats(session); session->state = STATE_ONGOING; session->start_time = time; + + /* Start a new session! */ + if (udp_session_cb != NULL) { + udp_session_cb(ZPERF_SESSION_STARTED, NULL, + udp_user_data); + } } break; case STATE_ONGOING: if (id < 0) { /* Negative id means session end. */ - uint32_t rate_in_kbps; + struct zperf_results results = { 0 }; uint32_t duration; - shell_fprintf(sh, SHELL_NORMAL, "End of session!\n"); - duration = k_ticks_to_us_ceil32(time - session->start_time); /* Update state machine */ session->state = STATE_COMPLETED; - /* Compute baud rate */ - if (duration != 0U) { - rate_in_kbps = (uint32_t) - ((session->length * 8ULL * - (uint64_t)USEC_PER_SEC) / - ((uint64_t)duration * 1024ULL)); - } else { - rate_in_kbps = 0U; - } - /* Fill statistics */ session->stat.flags = 0x80000000; session->stat.total_len1 = session->length >> 32; @@ -179,37 +166,23 @@ static void udp_received(const struct shell *sh, int sock, session->stat.jitter1 = 0; session->stat.jitter2 = session->jitter; - if (zperf_receiver_send_stat(sh, sock, addr, hdr, + if (zperf_receiver_send_stat(sock, addr, hdr, &session->stat) < 0) { - shell_fprintf(sh, SHELL_WARNING, - "Failed to send the packet\n"); + NET_ERR("Failed to send the packet"); } - shell_fprintf(sh, SHELL_NORMAL, - " duration:\t\t"); - print_number(sh, duration, TIME_US, TIME_US_UNIT); - shell_fprintf(sh, SHELL_NORMAL, "\n"); + results.nb_packets_rcvd = session->counter; + results.nb_packets_lost = session->error; + results.nb_packets_outorder = session->outorder; + results.total_len = session->length; + results.time_in_us = duration; + results.jitter_in_us = session->jitter; + results.packet_size = session->length / session->counter; - shell_fprintf(sh, SHELL_NORMAL, - " received packets:\t%u\n", - session->counter); - shell_fprintf(sh, SHELL_NORMAL, - " nb packets lost:\t%u\n", - session->error); - shell_fprintf(sh, SHELL_NORMAL, - " nb packets outorder:\t%u\n", - session->outorder); - - shell_fprintf(sh, SHELL_NORMAL, - " jitter:\t\t\t"); - print_number(sh, session->jitter, TIME_US, - TIME_US_UNIT); - shell_fprintf(sh, SHELL_NORMAL, "\n"); - - shell_fprintf(sh, SHELL_NORMAL, - " rate:\t\t\t"); - print_number(sh, rate_in_kbps, KBPS, KBPS_UNIT); - shell_fprintf(sh, SHELL_NORMAL, "\n"); + if (udp_session_cb != NULL) { + udp_session_cb(ZPERF_SESSION_FINISHED, &results, + udp_user_data); + } } else { /* Update counter */ session->counter++; @@ -254,10 +227,10 @@ static void udp_received(const struct shell *sh, int sock, void udp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) { + ARG_UNUSED(ptr1); ARG_UNUSED(ptr3); static uint8_t buf[UDP_RECEIVER_BUF_SIZE]; - const struct shell *sh = ptr1; int port = POINTER_TO_INT(ptr2); struct zsock_pollfd fds[SOCK_ID_MAX] = { 0 }; int ret; @@ -274,18 +247,16 @@ void udp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) fds[SOCK_ID_IPV4].fd = zsock_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fds[SOCK_ID_IPV4].fd < 0) { - shell_fprintf(sh, SHELL_WARNING, - "Cannot create IPv4 network socket.\n"); + NET_ERR("Cannot create IPv4 network socket."); goto cleanup; } if (MY_IP4ADDR && strlen(MY_IP4ADDR)) { /* Use setting IP */ - ret = zperf_get_ipv4_addr(sh, MY_IP4ADDR, + ret = zperf_get_ipv4_addr(MY_IP4ADDR, &in4_addr_my->sin_addr); if (ret < 0) { - shell_fprintf(sh, SHELL_WARNING, - "Unable to set IPv4\n"); + NET_WARN("Unable to set IPv4"); goto use_existing_ipv4; } } else { @@ -293,16 +264,15 @@ void udp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) /* Use existing IP */ in4_addr = zperf_get_default_if_in4_addr(); if (!in4_addr) { - shell_fprintf(sh, SHELL_WARNING, - "Unable to get IPv4 by default\n"); + NET_ERR("Unable to get IPv4 by default"); goto cleanup; } memcpy(&in4_addr_my->sin_addr, in4_addr, sizeof(struct in_addr)); } - shell_fprintf(sh, SHELL_NORMAL, "Binding to %s\n", - net_sprint_ipv4_addr(&in4_addr_my->sin_addr)); + NET_INFO("Binding to %s", + net_sprint_ipv4_addr(&in4_addr_my->sin_addr)); in4_addr_my->sin_port = htons(port); @@ -310,10 +280,9 @@ void udp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) (struct sockaddr *)in4_addr_my, sizeof(struct sockaddr_in)); if (ret < 0) { - shell_fprintf(sh, SHELL_WARNING, - "Cannot bind IPv4 UDP port %d (%d)\n", - ntohs(in4_addr_my->sin_port), - errno); + NET_ERR("Cannot bind IPv4 UDP port %d (%d)", + ntohs(in4_addr_my->sin_port), + errno); goto cleanup; } @@ -328,19 +297,17 @@ void udp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) fds[SOCK_ID_IPV6].fd = zsock_socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (fds[SOCK_ID_IPV6].fd < 0) { - shell_fprintf(sh, SHELL_WARNING, - "Cannot create IPv4 network socket.\n"); + NET_ERR("Cannot create IPv4 network socket."); goto cleanup; } if (MY_IP6ADDR && strlen(MY_IP6ADDR)) { /* Use setting IP */ - ret = zperf_get_ipv6_addr(sh, MY_IP6ADDR, + ret = zperf_get_ipv6_addr(MY_IP6ADDR, MY_PREFIX_LEN_STR, &in6_addr_my->sin6_addr); if (ret < 0) { - shell_fprintf(sh, SHELL_WARNING, - "Unable to set IPv6\n"); + NET_WARN("Unable to set IPv6"); goto use_existing_ipv6; } } else { @@ -348,16 +315,15 @@ void udp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) /* Use existing IP */ in6_addr = zperf_get_default_if_in6_addr(); if (!in6_addr) { - shell_fprintf(sh, SHELL_WARNING, - "Unable to get IPv4 by default\n"); + NET_ERR("Unable to get IPv4 by default"); goto cleanup; } memcpy(&in6_addr_my->sin6_addr, in6_addr, sizeof(struct in6_addr)); } - shell_fprintf(sh, SHELL_NORMAL, "Binding to %s\n", - net_sprint_ipv6_addr(&in6_addr_my->sin6_addr)); + NET_INFO("Binding to %s", + net_sprint_ipv6_addr(&in6_addr_my->sin6_addr)); in6_addr_my->sin6_port = htons(port); @@ -365,25 +331,21 @@ void udp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) (struct sockaddr *)in6_addr_my, sizeof(struct sockaddr_in6)); if (ret < 0) { - shell_fprintf(sh, SHELL_WARNING, - "Cannot bind IPv6 UDP port %d (%d)\n", - ntohs(in6_addr_my->sin6_port), - ret); + NET_ERR("Cannot bind IPv6 UDP port %d (%d)", + ntohs(in6_addr_my->sin6_port), + ret); goto cleanup; } fds[SOCK_ID_IPV6].events = ZSOCK_POLLIN; } - shell_fprintf(sh, SHELL_NORMAL, - "Listening on port %d\n", port); + NET_INFO("Listening on port %d", port); while (true) { ret = zsock_poll(fds, ARRAY_SIZE(fds), -1); if (ret < 0) { - shell_fprintf(sh, SHELL_WARNING, - "UDP receiver poll error (%d)\n", - errno); + NET_ERR("UDP receiver poll error (%d)", errno); goto cleanup; } @@ -393,9 +355,7 @@ void udp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) if ((fds[i].revents & ZSOCK_POLLERR) || (fds[i].revents & ZSOCK_POLLNVAL)) { - shell_fprintf( - sh, SHELL_WARNING, - "UDP receiver IPv%d socket error\n", + NET_ERR("UDP receiver IPv%d socket error", (i == SOCK_ID_IPV4) ? 4 : 6); goto cleanup; } @@ -407,18 +367,20 @@ void udp_receiver_thread(void *ptr1, void *ptr2, void *ptr3) ret = zsock_recvfrom(fds[i].fd, buf, sizeof(buf), 0, &addr, &addrlen); if (ret < 0) { - shell_fprintf( - sh, SHELL_WARNING, - "recv failed on IPv%d socket (%d)\n", + NET_ERR("recv failed on IPv%d socket (%d)", (i == SOCK_ID_IPV4) ? 4 : 6, errno); goto cleanup; } - udp_received(sh, fds[i].fd, &addr, buf, ret); + udp_received(fds[i].fd, &addr, buf, ret); } } cleanup: + if (udp_session_cb != NULL) { + udp_session_cb(ZPERF_SESSION_ERROR, NULL, udp_user_data); + } + for (int i = 0; i < ARRAY_SIZE(fds); i++) { if (fds[i].fd >= 0) { zsock_close(fds[i].fd); @@ -426,15 +388,35 @@ cleanup: } } -void zperf_udp_receiver_init(const struct shell *sh, int port) +static void zperf_udp_receiver_init(int port) { k_thread_create(&udp_receiver_thread_data, udp_receiver_stack_area, K_THREAD_STACK_SIZEOF(udp_receiver_stack_area), udp_receiver_thread, - (void *)sh, INT_TO_POINTER(port), NULL, + NULL, INT_TO_POINTER(port), NULL, UDP_RECEIVER_THREAD_PRIORITY, IS_ENABLED(CONFIG_USERSPACE) ? K_USER | K_INHERIT_PERMS : 0, K_NO_WAIT); } + +int zperf_udp_download(const struct zperf_download_params *param, + zperf_callback callback, void *user_data) +{ + if (param == NULL || callback == NULL) { + return -EINVAL; + } + + if (udp_server_running) { + return -EALREADY; + } + + udp_session_cb = callback; + udp_user_data = user_data; + udp_server_running = true; + + zperf_udp_receiver_init(param->port); + + return 0; +}