1 /*
2  * Copyright (c) 2019 Linaro Limited
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(net_test, CONFIG_NET_SOCKETS_LOG_LEVEL);
9 
10 #include <stdio.h>
11 #include <zephyr/ztest_assert.h>
12 
13 #include <zephyr/net/socket.h>
14 
15 #include "../../socket_helpers.h"
16 
17 #define BUF_AND_SIZE(buf) buf, sizeof(buf) - 1
18 #define STRLEN(buf) (sizeof(buf) - 1)
19 
20 #define TEST_STR_SMALL "test"
21 
22 #define MY_IPV6_ADDR "::1"
23 
24 #define ANY_PORT 0
25 #define SERVER_PORT 4242
26 #define CLIENT_PORT 9898
27 
28 /* Fudge factor added to expected timeouts, in milliseconds. */
29 #define FUZZ 60
30 
31 #define TIMEOUT_MS 60
32 
ZTEST_USER(net_socket_select,test_fd_set)33 ZTEST_USER(net_socket_select, test_fd_set)
34 {
35 	zsock_fd_set set;
36 
37 	/* Relies on specific value of CONFIG_ZVFS_OPEN_MAX in prj.conf */
38 	zassert_equal(sizeof(set.bitset), sizeof(uint32_t) * 2, "");
39 
40 	ZSOCK_FD_ZERO(&set);
41 	zassert_equal(set.bitset[0], 0, "");
42 	zassert_equal(set.bitset[1], 0, "");
43 	zassert_false(ZSOCK_FD_ISSET(0, &set), "");
44 
45 	ZSOCK_FD_SET(0, &set);
46 	zassert_true(ZSOCK_FD_ISSET(0, &set), "");
47 
48 	ZSOCK_FD_CLR(0, &set);
49 	zassert_false(ZSOCK_FD_ISSET(0, &set), "");
50 
51 	ZSOCK_FD_SET(0, &set);
52 	zassert_equal(set.bitset[0], 0x00000001, "");
53 	zassert_equal(set.bitset[1], 0, "");
54 
55 	ZSOCK_FD_SET(31, &set);
56 	zassert_equal(set.bitset[0], 0x80000001, "");
57 	zassert_equal(set.bitset[1], 0, "");
58 
59 	ZSOCK_FD_SET(33, &set);
60 	zassert_equal(set.bitset[0], 0x80000001, "");
61 	zassert_equal(set.bitset[1], 0x00000002, "");
62 
63 	ZSOCK_FD_ZERO(&set);
64 	zassert_equal(set.bitset[0], 0, "");
65 	zassert_equal(set.bitset[1], 0, "");
66 }
67 
ZTEST_USER(net_socket_select,test_select)68 ZTEST_USER(net_socket_select, test_select)
69 {
70 	int res;
71 	int c_sock;
72 	int s_sock;
73 	struct sockaddr_in6 c_addr;
74 	struct sockaddr_in6 s_addr;
75 	zsock_fd_set readfds;
76 	uint32_t tstamp;
77 	ssize_t len;
78 	char buf[10];
79 	struct timeval tval;
80 
81 	prepare_sock_udp_v6(MY_IPV6_ADDR, CLIENT_PORT, &c_sock, &c_addr);
82 	prepare_sock_udp_v6(MY_IPV6_ADDR, SERVER_PORT, &s_sock, &s_addr);
83 
84 	res = zsock_bind(s_sock, (struct sockaddr *)&s_addr, sizeof(s_addr));
85 	zassert_equal(res, 0, "bind failed");
86 
87 	res = zsock_connect(c_sock, (struct sockaddr *)&s_addr, sizeof(s_addr));
88 	zassert_equal(res, 0, "connect failed");
89 
90 	ZSOCK_FD_ZERO(&readfds);
91 	ZSOCK_FD_SET(c_sock, &readfds);
92 	ZSOCK_FD_SET(s_sock, &readfds);
93 
94 	/* Poll non-ready fd's with timeout of 0 */
95 	tval.tv_sec = tval.tv_usec = 0;
96 	tstamp = k_uptime_get_32();
97 	res = zsock_select(s_sock + 1, &readfds, NULL, NULL, &tval);
98 	tstamp = k_uptime_get_32() - tstamp;
99 	/* Even though we expect select to be non-blocking, scheduler may
100 	 * preempt the thread. That's why we add FUZZ to the expected
101 	 * delay time. Also applies to similar cases below.
102 	 */
103 	zassert_true(tstamp <= FUZZ, "");
104 	zassert_equal(res, 0, "");
105 
106 	zassert_false(ZSOCK_FD_ISSET(c_sock, &readfds), "");
107 	zassert_false(ZSOCK_FD_ISSET(s_sock, &readfds), "");
108 
109 	/* Poll non-ready fd's with timeout of 10ms */
110 	ZSOCK_FD_SET(c_sock, &readfds);
111 	ZSOCK_FD_SET(s_sock, &readfds);
112 	tval.tv_sec = 0;
113 	tval.tv_usec = TIMEOUT_MS * 1000;
114 	tstamp = k_uptime_get_32();
115 	res = zsock_select(s_sock + 1, &readfds, NULL, NULL, &tval);
116 	tstamp = k_uptime_get_32() - tstamp;
117 	zassert_true(tstamp >= TIMEOUT_MS && tstamp <= TIMEOUT_MS + FUZZ, "");
118 	zassert_equal(res, 0, "");
119 
120 
121 	/* Send pkt for s_sock and poll with timeout of 10ms */
122 	len = zsock_send(c_sock, BUF_AND_SIZE(TEST_STR_SMALL), 0);
123 	zassert_equal(len, STRLEN(TEST_STR_SMALL), "invalid send len");
124 
125 	ZSOCK_FD_SET(c_sock, &readfds);
126 	ZSOCK_FD_SET(s_sock, &readfds);
127 	tval.tv_sec = 0;
128 	tval.tv_usec = TIMEOUT_MS * 1000;
129 	tstamp = k_uptime_get_32();
130 	res = zsock_select(s_sock + 1, &readfds, NULL, NULL, &tval);
131 	tstamp = k_uptime_get_32() - tstamp;
132 	zassert_true(tstamp <= FUZZ, "");
133 	zassert_equal(res, 1, "");
134 
135 	zassert_false(ZSOCK_FD_ISSET(c_sock, &readfds), "");
136 	zassert_true(ZSOCK_FD_ISSET(s_sock, &readfds), "");
137 
138 
139 	/* Recv pkt from s_sock and ensure no poll events happen */
140 	len = zsock_recv(s_sock, BUF_AND_SIZE(buf), 0);
141 	zassert_equal(len, STRLEN(TEST_STR_SMALL), "invalid recv len");
142 
143 	ZSOCK_FD_SET(c_sock, &readfds);
144 	ZSOCK_FD_SET(s_sock, &readfds);
145 	tval.tv_sec = tval.tv_usec = 0;
146 	tstamp = k_uptime_get_32();
147 	res = zsock_select(s_sock + 1, &readfds, NULL, NULL, &tval);
148 	zassert_true(k_uptime_get_32() - tstamp <= FUZZ, "");
149 	zassert_equal(res, 0, "");
150 	zassert_false(ZSOCK_FD_ISSET(s_sock, &readfds), "");
151 
152 
153 	/* Close one socket and ensure POLLNVAL happens */
154 	res = zsock_close(c_sock);
155 	zassert_equal(res, 0, "close failed");
156 
157 	ZSOCK_FD_SET(c_sock, &readfds);
158 	ZSOCK_FD_SET(s_sock, &readfds);
159 	tval.tv_sec = tval.tv_usec = 0;
160 	tstamp = k_uptime_get_32();
161 	res = zsock_select(s_sock + 1, &readfds, NULL, NULL, &tval);
162 	zassert_true(k_uptime_get_32() - tstamp <= FUZZ, "");
163 	zassert_true(res < 0, "");
164 	zassert_equal(errno, EBADF, "");
165 
166 	res = zsock_close(s_sock);
167 	zassert_equal(res, 0, "close failed");
168 }
169 
setup(void)170 static void *setup(void)
171 {
172 	if (IS_ENABLED(CONFIG_NET_TC_THREAD_COOPERATIVE)) {
173 		k_thread_priority_set(k_current_get(),
174 				K_PRIO_COOP(CONFIG_NUM_COOP_PRIORITIES - 1));
175 	} else {
176 		k_thread_priority_set(k_current_get(), K_PRIO_PREEMPT(9));
177 	}
178 
179 	k_thread_system_pool_assign(k_current_get());
180 	return NULL;
181 }
182 
183 ZTEST_SUITE(net_socket_select, NULL, setup, NULL, NULL, NULL);
184