diff options
| author | Frédéric Desbiens <[email protected]> | 2026-06-08 10:03:52 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-06-08 10:03:52 +0200 |
| commit | 1a0e9e43a03e37ddecfb6b49e9b078d6e1803d05 (patch) | |
| tree | c60ec41b4ff4fd2d7566c505cbdd423ceddd65f3 /test/regression/bsd_test/netx_bsd_recvfromto_test.c | |
| parent | 8b6e03ac30ab688bec02c69d42f2304b7f72a202 (diff) | |
| parent | 4d88828b06d164a5b7e82152395a92254abcd6e4 (diff) | |
Merge pull request #391 from eclipse-threadx/devv6.5.1.202602_reldev
Merging changes for the v.6.5.1.202602 release
Diffstat (limited to 'test/regression/bsd_test/netx_bsd_recvfromto_test.c')
| -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 */ |
