diff options
| author | mzgrebnak <[email protected]> | 2026-05-29 16:34:38 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-05-29 10:34:38 -0400 |
| commit | 09ce97f8f9019724407917c197c2a0c0e859bf2d (patch) | |
| tree | 3f0683ac14105149cf0759ea1fa133ed9675cd34 /test/regression | |
| parent | 53070b69eed6af6840b0a890fe749e73e3f280f2 (diff) | |
Added BSD recvfromto support (#376)
* recvfromto support
* nx_bsd_inet_aton, disabling other format than four numbers separated by dots. Otherwise used in nx_bsd_inet_pton
It accepts unallowed format of IP address.
* bsd: address PR review feedback
- Fix build failure: add missing nx_bsd_recvfromto() prototype to
nxd_bsd.h near the other receive prototypes. The nx_bsd_recvfromto
macro maps to recvfromto, but without a prior declaration the
compiler emits -Werror=missing-declarations.
- Revert inet_aton() change: restore the 1-part, 2-part and 3-part
abbreviated IPv4 address formats (a.b.c and a.b). The PR removed
them, breaking existing tests that rely on these forms.
- Add IPv6 destination address support in recvfromto(): when the
receiving BSD socket is AF_INET6, extract the destination IPv6
address from the IPv6 packet header and populate a sockaddr_in6
in toAddr, mirroring the existing IPv4 path.
- Add regression test netx_bsd_recvfromto_test covering:
* recvfromto() populates fromAddr (sender) and toAddr (destination)
with correct address/port values for IPv4 UDP
* recvfromto() with NULL toAddr/toAddrLen works like recvfrom()
* inet_aton() still accepts abbreviated a.b and a.b.c forms
Register test in regression/CMakeLists.txt.
---------
Co-authored-by: Frédéric Desbiens <[email protected]>
Co-authored-by: Copilot <[email protected]>
Diffstat (limited to 'test/regression')
| -rw-r--r-- | test/regression/bsd_test/netx_bsd_recvfromto_test.c | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/test/regression/bsd_test/netx_bsd_recvfromto_test.c b/test/regression/bsd_test/netx_bsd_recvfromto_test.c new file mode 100644 index 00000000..223e5c04 --- /dev/null +++ b/test/regression/bsd_test/netx_bsd_recvfromto_test.c @@ -0,0 +1,315 @@ +/*************************************************************************** + * Copyright (C) 2026 Eclipse ThreadX contributors + * + * This program and the accompanying materials are made available under the + * terms of the MIT License which is available at + * https://opensource.org/licenses/MIT. + * + * AI Disclosure: This file was largely AI-generated by Copilot (Sonnet 4.6). + * The AI-generated portions may be considered public domain (CC0-1.0) + * and not subject to the project's licence. The human contributor has + * reviewed and verified that the code is correct. + * + * SPDX-License-Identifier: MIT and CC0-1.0 + **************************************************************************/ + +/* This test covers the recvfromto() API from PR #376: + * + * 1. recvfromto() populates fromAddr with the sender's address/port and + * toAddr with the destination (local) address/port of the UDP packet. + * + * 2. recvfromto() with NULL toAddr/toAddrLen works like recvfrom(). + * + * 3. inet_aton() still accepts abbreviated IPv4 forms such as a.b.c + * and a.b (regression for the inet_aton revert). + */ + +#include "tx_api.h" +#include "nx_api.h" +#if defined(NX_BSD_ENABLE) && !defined(NX_DISABLE_IPV4) && defined(__PRODUCT_NETXDUO__) +#include "nxd_bsd.h" + +#define DEMO_STACK_SIZE 4096 +#define BSD_THREAD_PRIORITY 2 +#define TEST_PORT 4444 + +static TX_THREAD ntest_0; +static TX_THREAD ntest_1; + +static NX_PACKET_POOL pool_0; +static NX_IP ip_0; /* BSD receiver: 1.2.3.4 */ +static NX_IP ip_1; /* NX sender: 1.2.3.5 */ +static TX_SEMAPHORE sema_rx_ready; +static TX_SEMAPHORE sema_done; + +static ULONG error_counter; + +static ULONG packet_pool_area[(512 + sizeof(NX_PACKET)) * 32 / 4]; +static ULONG bsd_thread_area[DEMO_STACK_SIZE / sizeof(ULONG)]; + +static void ntest_0_entry(ULONG thread_input); +static void ntest_1_entry(ULONG thread_input); +extern void test_control_return(UINT status); +extern void _nx_ram_network_driver_256(struct NX_IP_DRIVER_STRUCT *driver_req); + +#ifdef CTEST +VOID test_application_define(void *first_unused_memory) +#else +void netx_bsd_recvfromto_test_application_define(void *first_unused_memory) +#endif +{ +CHAR *pointer = (CHAR *)first_unused_memory; +UINT status; + + error_counter = 0; + + tx_thread_create(&ntest_0, "thread 0", ntest_0_entry, 0, + pointer, DEMO_STACK_SIZE, 3, 3, + TX_NO_TIME_SLICE, TX_AUTO_START); + pointer += DEMO_STACK_SIZE; + + tx_thread_create(&ntest_1, "thread 1", ntest_1_entry, 0, + pointer, DEMO_STACK_SIZE, 3, 3, + TX_NO_TIME_SLICE, TX_AUTO_START); + pointer += DEMO_STACK_SIZE; + + nx_system_initialize(); + + status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", 512, + packet_pool_area, sizeof(packet_pool_area)); + if (status) + error_counter++; + + status = nx_ip_create(&ip_0, "NetX IP Instance 0", + IP_ADDRESS(1, 2, 3, 4), 0xFFFFFF00UL, + &pool_0, _nx_ram_network_driver_256, + pointer, 2048, 1); + pointer += 2048; + if (status) + error_counter++; + + status = nx_ip_create(&ip_1, "NetX IP Instance 1", + IP_ADDRESS(1, 2, 3, 5), 0xFFFFFF00UL, + &pool_0, _nx_ram_network_driver_256, + pointer, 2048, 1); + pointer += 2048; + if (status) + error_counter++; + + status = nx_arp_enable(&ip_0, (void *)pointer, 1024); + pointer += 1024; + if (status) + error_counter++; + + status = nx_arp_enable(&ip_1, (void *)pointer, 1024); + pointer += 1024; + if (status) + error_counter++; + + status = nx_udp_enable(&ip_0); + status += nx_udp_enable(&ip_1); + if (status) + error_counter++; + + status = bsd_initialize(&ip_0, &pool_0, (CHAR *)&bsd_thread_area[0], + sizeof(bsd_thread_area), BSD_THREAD_PRIORITY); + if (status) + error_counter++; + + status = tx_semaphore_create(&sema_rx_ready, "RX READY", 0); + if (status) + error_counter++; + + status = tx_semaphore_create(&sema_done, "DONE", 0); + if (status) + error_counter++; +} + +/* Thread 0: BSD receiver */ +static void ntest_0_entry(ULONG thread_input) +{ +INT sock; +struct nx_bsd_sockaddr_in local_addr; +struct nx_bsd_sockaddr_in from_addr; +struct nx_bsd_sockaddr_in to_addr; +INT from_len; +INT to_len; +CHAR buf[64]; +INT ret; +UINT actual_status; + + /* Wait for IP stack initialisation. */ + nx_ip_status_check(&ip_0, NX_IP_INITIALIZE_DONE, &actual_status, + NX_IP_PERIODIC_RATE); + + /* --- Test 1: recvfromto() populates fromAddr and toAddr --- */ + sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) + { + error_counter++; + test_control_return(1); + return; + } + + memset(&local_addr, 0, sizeof(local_addr)); + local_addr.sin_family = AF_INET; + local_addr.sin_port = htons(TEST_PORT); + local_addr.sin_addr.s_addr = htonl(IP_ADDRESS(1, 2, 3, 4)); + + if (bind(sock, (struct nx_bsd_sockaddr *)&local_addr, sizeof(local_addr)) < 0) + { + error_counter++; + soc_close(sock); + test_control_return(1); + return; + } + + /* Signal sender that receiver is ready. */ + tx_semaphore_put(&sema_rx_ready); + + memset(&from_addr, 0, sizeof(from_addr)); + memset(&to_addr, 0, sizeof(to_addr)); + from_len = sizeof(from_addr); + to_len = sizeof(to_addr); + + ret = recvfromto(sock, buf, sizeof(buf), 0, + (struct nx_bsd_sockaddr *)&from_addr, &from_len, + (struct nx_bsd_sockaddr *)&to_addr, &to_len); + if (ret <= 0) + { + error_counter++; + } + else + { + /* Validate fromAddr: must be 1.2.3.5 : any port */ + if (from_addr.sin_family != AF_INET) + error_counter++; + if (ntohl(from_addr.sin_addr.s_addr) != IP_ADDRESS(1, 2, 3, 5)) + error_counter++; + + /* Validate toAddr: must be 1.2.3.4 : TEST_PORT */ + if (to_addr.sin_family != AF_INET) + error_counter++; + if (ntohl(to_addr.sin_addr.s_addr) != IP_ADDRESS(1, 2, 3, 4)) + error_counter++; + if (ntohs(to_addr.sin_port) != TEST_PORT) + error_counter++; + + /* toAddrLen must be trimmed to sizeof(sockaddr_in). */ + if (to_len != (INT)sizeof(struct nx_bsd_sockaddr_in)) + error_counter++; + } + + soc_close(sock); + + /* --- Test 2: recvfromto() with NULL toAddr works like recvfrom() --- */ + sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) + { + error_counter++; + test_control_return(1); + return; + } + + memset(&local_addr, 0, sizeof(local_addr)); + local_addr.sin_family = AF_INET; + local_addr.sin_port = htons(TEST_PORT); + local_addr.sin_addr.s_addr = htonl(IP_ADDRESS(1, 2, 3, 4)); + + if (bind(sock, (struct nx_bsd_sockaddr *)&local_addr, sizeof(local_addr)) < 0) + { + error_counter++; + soc_close(sock); + test_control_return(1); + return; + } + + tx_semaphore_put(&sema_rx_ready); + + memset(&from_addr, 0, sizeof(from_addr)); + from_len = sizeof(from_addr); + + ret = recvfromto(sock, buf, sizeof(buf), 0, + (struct nx_bsd_sockaddr *)&from_addr, &from_len, + NX_NULL, NX_NULL); + if (ret <= 0) + error_counter++; + + soc_close(sock); + + /* --- Test 3: inet_aton() still accepts abbreviated IPv4 forms --- */ + { + struct in_addr in_val; + INT rc; + + /* a.b format: 11.657930 == 11.0x0a0a0a == 11.10.10.10 */ + rc = inet_aton("11.657930", &in_val); + if (rc == 0) + error_counter++; + + /* a.b.c format: 11.10.2570 == 11.10.0x0a0a == 11.10.10.10 */ + rc = inet_aton("11.10.2570", &in_val); + if (rc == 0) + error_counter++; + + /* standard dotted-decimal must still work */ + rc = inet_aton("11.10.10.10", &in_val); + if (rc == 0) + error_counter++; + } + + tx_semaphore_put(&sema_done); +} + +/* Thread 1: NX UDP sender */ +static void ntest_1_entry(ULONG thread_input) +{ +NX_UDP_SOCKET udp_socket; +NX_PACKET *packet_ptr; +NXD_ADDRESS dest_addr; +UINT actual_status; + + nx_ip_status_check(&ip_1, NX_IP_INITIALIZE_DONE, &actual_status, + NX_IP_PERIODIC_RATE); + + nx_udp_socket_create(&ip_1, &udp_socket, "UDP sender", + NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 8); + nx_udp_socket_bind(&udp_socket, NX_ANY_PORT, NX_WAIT_FOREVER); + + memset(&dest_addr, 0, sizeof(dest_addr)); + dest_addr.nxd_ip_version = NX_IP_VERSION_V4; + dest_addr.nxd_ip_address.v4 = IP_ADDRESS(1, 2, 3, 4); + + /* Send for Test 1 */ + tx_semaphore_get(&sema_rx_ready, NX_IP_PERIODIC_RATE); + + nx_packet_allocate(&pool_0, &packet_ptr, NX_UDP_PACKET, NX_WAIT_FOREVER); + nx_packet_data_append(packet_ptr, "hello", 5, &pool_0, NX_WAIT_FOREVER); + nxd_udp_socket_send(&udp_socket, packet_ptr, &dest_addr, TEST_PORT); + + /* Send for Test 2 */ + tx_semaphore_get(&sema_rx_ready, NX_IP_PERIODIC_RATE); + + nx_packet_allocate(&pool_0, &packet_ptr, NX_UDP_PACKET, NX_WAIT_FOREVER); + nx_packet_data_append(packet_ptr, "world", 5, &pool_0, NX_WAIT_FOREVER); + nxd_udp_socket_send(&udp_socket, packet_ptr, &dest_addr, TEST_PORT); + + nx_udp_socket_unbind(&udp_socket); + nx_udp_socket_delete(&udp_socket); + + /* Wait for receiver to finish then report result. */ + tx_semaphore_get(&sema_done, 5 * NX_IP_PERIODIC_RATE); + test_control_return(error_counter ? 1 : 0); +} + +#else /* !(NX_BSD_ENABLE && !NX_DISABLE_IPV4) */ +#ifdef CTEST +VOID test_application_define(void *first_unused_memory) +#else +void netx_bsd_recvfromto_test_application_define(void *first_unused_memory) +#endif +{ + NX_PARAMETER_NOT_USED(first_unused_memory); + test_control_return(3); /* skip */ +} +#endif /* NX_BSD_ENABLE && !NX_DISABLE_IPV4 */ |
