summaryrefslogtreecommitdiff
path: root/test/regression/bsd_test/netx_bsd_recvfromto_test.c
diff options
context:
space:
mode:
authorFrédéric Desbiens <[email protected]>2026-06-08 10:03:52 +0200
committerGitHub <[email protected]>2026-06-08 10:03:52 +0200
commit1a0e9e43a03e37ddecfb6b49e9b078d6e1803d05 (patch)
treec60ec41b4ff4fd2d7566c505cbdd423ceddd65f3 /test/regression/bsd_test/netx_bsd_recvfromto_test.c
parent8b6e03ac30ab688bec02c69d42f2304b7f72a202 (diff)
parent4d88828b06d164a5b7e82152395a92254abcd6e4 (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.c315
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 */