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 #include <zephyr/sys/fdtable.h>
15
16 #include "../../socket_helpers.h"
17
18 #define BUF_AND_SIZE(buf) buf, sizeof(buf) - 1
19 #define STRLEN(buf) (sizeof(buf) - 1)
20
21 #define TEST_STR_SMALL "test"
22
23 #define MY_IPV6_ADDR "::1"
24
25 #define ANY_PORT 0
26 #define SERVER_PORT 4242
27 #define CLIENT_PORT 9898
28
29 /* On QEMU, poll() which waits takes +10ms from the requested time. */
30 #define FUZZ 10
31
32 #define TCP_TEARDOWN_TIMEOUT K_SECONDS(3)
33
ZTEST(net_socket_poll,test_poll)34 ZTEST(net_socket_poll, test_poll)
35 {
36 int res;
37 int c_sock;
38 int s_sock;
39 int c_sock_tcp;
40 int s_sock_tcp;
41 struct sockaddr_in6 c_addr;
42 struct sockaddr_in6 s_addr;
43 struct zsock_pollfd pollfds[2];
44 struct zsock_pollfd pollout[1];
45 uint32_t tstamp;
46 ssize_t len;
47 char buf[10];
48
49 prepare_sock_udp_v6(MY_IPV6_ADDR, CLIENT_PORT, &c_sock, &c_addr);
50 prepare_sock_udp_v6(MY_IPV6_ADDR, SERVER_PORT, &s_sock, &s_addr);
51 prepare_sock_tcp_v6(MY_IPV6_ADDR, CLIENT_PORT, &c_sock_tcp, &c_addr);
52 prepare_sock_tcp_v6(MY_IPV6_ADDR, SERVER_PORT, &s_sock_tcp, &s_addr);
53
54 res = zsock_bind(s_sock, (struct sockaddr *)&s_addr, sizeof(s_addr));
55 zassert_equal(res, 0, "bind failed");
56
57 res = zsock_connect(c_sock, (struct sockaddr *)&s_addr, sizeof(s_addr));
58 zassert_equal(res, 0, "connect failed");
59
60 memset(pollfds, 0, sizeof(pollfds));
61 pollfds[0].fd = c_sock;
62 pollfds[0].events = ZSOCK_POLLIN;
63 pollfds[1].fd = s_sock;
64 pollfds[1].events = ZSOCK_POLLIN;
65
66 /* Poll non-ready fd's with timeout of 0 */
67 tstamp = k_uptime_get_32();
68 res = zsock_poll(pollfds, ARRAY_SIZE(pollfds), 0);
69 zassert_true(k_uptime_get_32() - tstamp <= FUZZ, "");
70 zassert_equal(res, 0, "");
71
72 zassert_equal(pollfds[0].fd, c_sock, "");
73 zassert_equal(pollfds[0].events, ZSOCK_POLLIN, "");
74 zassert_equal(pollfds[0].revents, 0, "");
75 zassert_equal(pollfds[1].fd, s_sock, "");
76 zassert_equal(pollfds[1].events, ZSOCK_POLLIN, "");
77 zassert_equal(pollfds[1].revents, 0, "");
78
79
80 /* Poll non-ready fd's with timeout of 30 */
81 tstamp = k_uptime_get_32();
82 res = zsock_poll(pollfds, ARRAY_SIZE(pollfds), 30);
83 tstamp = k_uptime_get_32() - tstamp;
84 zassert_true(tstamp >= 30U && tstamp <= 30 + FUZZ * 2, "tstamp %d",
85 tstamp);
86 zassert_equal(res, 0, "");
87
88 /* Send pkt for s_sock and poll with timeout of 10 */
89 len = zsock_send(c_sock, BUF_AND_SIZE(TEST_STR_SMALL), 0);
90 zassert_equal(len, STRLEN(TEST_STR_SMALL), "invalid send len");
91
92 tstamp = k_uptime_get_32();
93 res = zsock_poll(pollfds, ARRAY_SIZE(pollfds), 30);
94 tstamp = k_uptime_get_32() - tstamp;
95 zassert_true(tstamp <= FUZZ, "");
96 zassert_equal(res, 1, "");
97
98 zassert_equal(pollfds[0].fd, c_sock, "");
99 zassert_equal(pollfds[0].events, ZSOCK_POLLIN, "");
100 zassert_equal(pollfds[0].revents, 0, "");
101 zassert_equal(pollfds[1].fd, s_sock, "");
102 zassert_equal(pollfds[1].events, ZSOCK_POLLIN, "");
103 zassert_equal(pollfds[1].revents, ZSOCK_POLLIN, "");
104
105
106 /* Recv pkt from s_sock and ensure no poll events happen */
107 len = zsock_recv(s_sock, BUF_AND_SIZE(buf), 0);
108 zassert_equal(len, STRLEN(TEST_STR_SMALL), "invalid recv len");
109
110 tstamp = k_uptime_get_32();
111 res = zsock_poll(pollfds, ARRAY_SIZE(pollfds), 0);
112 zassert_true(k_uptime_get_32() - tstamp <= FUZZ, "");
113 zassert_equal(res, 0, "");
114 zassert_equal(pollfds[1].revents, 0, "");
115
116 /* Make sure that POLLOUT does not wait if not really needed */
117 memset(pollout, 0, sizeof(pollout));
118 pollout[0].fd = c_sock;
119 pollout[0].events = ZSOCK_POLLOUT;
120
121 res = zsock_connect(c_sock, (const struct sockaddr *)&s_addr,
122 sizeof(s_addr));
123 zassert_equal(res, 0, "");
124
125 tstamp = k_uptime_get_32();
126 res = zsock_poll(pollout, ARRAY_SIZE(pollout), 200);
127 zassert_true(k_uptime_get_32() - tstamp < 100, "");
128 zassert_equal(res, 1, "");
129 zassert_equal(pollout[0].revents, ZSOCK_POLLOUT, "");
130
131 /* First test that TCP POLLOUT will not wait if there is enough
132 * room in TCP window
133 */
134 memset(pollout, 0, sizeof(pollout));
135 pollout[0].fd = c_sock_tcp;
136 pollout[0].events = ZSOCK_POLLOUT;
137
138 res = zsock_bind(s_sock_tcp, (struct sockaddr *)&s_addr, sizeof(s_addr));
139 zassert_equal(res, 0, "");
140 res = zsock_listen(s_sock_tcp, 0);
141 zassert_equal(res, 0, "");
142
143 res = zsock_connect(c_sock_tcp, (const struct sockaddr *)&s_addr,
144 sizeof(s_addr));
145 zassert_equal(res, 0, "");
146
147 tstamp = k_uptime_get_32();
148 res = zsock_poll(pollout, ARRAY_SIZE(pollout), 200);
149 zassert_true(k_uptime_get_32() - tstamp < 100, "");
150 zassert_equal(res, 1, "");
151 zassert_equal(pollout[0].revents, ZSOCK_POLLOUT, "");
152
153 res = zsock_close(c_sock_tcp);
154 zassert_equal(res, 0, "close failed");
155
156 res = zsock_close(s_sock_tcp);
157 zassert_equal(res, 0, "close failed");
158
159 /* Close one socket and ensure POLLNVAL happens */
160 res = zsock_close(c_sock);
161 zassert_equal(res, 0, "close failed");
162
163 tstamp = k_uptime_get_32();
164 res = zsock_poll(pollfds, ARRAY_SIZE(pollfds), 0);
165 zassert_true(k_uptime_get_32() - tstamp <= FUZZ, "");
166 zassert_equal(res, 1, "");
167 zassert_equal(pollfds[0].revents, ZSOCK_POLLNVAL, "");
168 zassert_equal(pollfds[1].revents, 0, "");
169
170 res = zsock_close(s_sock);
171 zassert_equal(res, 0, "close failed");
172
173 k_sleep(TCP_TEARDOWN_TIMEOUT);
174 }
175
176 #define TEST_SNDBUF_SIZE CONFIG_NET_TCP_MAX_RECV_WINDOW_SIZE
177
ZTEST(net_socket_poll,test_pollout_tcp)178 ZTEST(net_socket_poll, test_pollout_tcp)
179 {
180 int res;
181 int c_sock;
182 int s_sock;
183 int new_sock;
184 struct sockaddr_in6 c_addr;
185 struct sockaddr_in6 s_addr;
186 struct zsock_pollfd pollout[1];
187 char buf[TEST_SNDBUF_SIZE] = { };
188
189 prepare_sock_tcp_v6(MY_IPV6_ADDR, CLIENT_PORT, &c_sock, &c_addr);
190 prepare_sock_tcp_v6(MY_IPV6_ADDR, SERVER_PORT, &s_sock, &s_addr);
191
192 res = zsock_bind(s_sock, (struct sockaddr *)&s_addr, sizeof(s_addr));
193 zassert_equal(res, 0, "");
194 res = zsock_listen(s_sock, 0);
195 zassert_equal(res, 0, "");
196 res = zsock_connect(c_sock, (const struct sockaddr *)&s_addr,
197 sizeof(s_addr));
198 zassert_equal(res, 0, "");
199 new_sock = zsock_accept(s_sock, NULL, NULL);
200 zassert_true(new_sock >= 0, "");
201
202 k_msleep(10);
203
204 /* POLLOUT should be reported after connecting */
205 memset(pollout, 0, sizeof(pollout));
206 pollout[0].fd = c_sock;
207 pollout[0].events = ZSOCK_POLLOUT;
208
209 res = zsock_poll(pollout, ARRAY_SIZE(pollout), 10);
210 zassert_equal(res, 1, "");
211 zassert_equal(pollout[0].revents, ZSOCK_POLLOUT, "");
212
213 /* POLLOUT should not be reported after filling the window */
214 res = zsock_send(c_sock, buf, sizeof(buf), 0);
215 zassert_equal(res, sizeof(buf), "");
216
217 memset(pollout, 0, sizeof(pollout));
218 pollout[0].fd = c_sock;
219 pollout[0].events = ZSOCK_POLLOUT;
220
221 res = zsock_poll(pollout, ARRAY_SIZE(pollout), 10);
222 zassert_equal(res, 0, "%d", pollout[0].revents);
223 zassert_equal(pollout[0].revents, 0, "");
224
225 /* POLLOUT should be reported again after consuming the data server
226 * side.
227 */
228 res = zsock_recv(new_sock, buf, sizeof(buf), 0);
229 zassert_equal(res, sizeof(buf), "");
230
231 memset(pollout, 0, sizeof(pollout));
232 pollout[0].fd = c_sock;
233 pollout[0].events = ZSOCK_POLLOUT;
234
235 /* Wait longer this time to give TCP stack a chance to send ZWP. */
236 res = zsock_poll(pollout, ARRAY_SIZE(pollout), 500);
237 zassert_equal(res, 1, "");
238 zassert_equal(pollout[0].revents, ZSOCK_POLLOUT, "");
239
240 k_msleep(10);
241
242 /* Finalize the test */
243 res = zsock_close(c_sock);
244 zassert_equal(res, 0, "close failed");
245 res = zsock_close(s_sock);
246 zassert_equal(res, 0, "close failed");
247 res = zsock_close(new_sock);
248 zassert_equal(res, 0, "close failed");
249 }
250
251 ZTEST_SUITE(net_socket_poll, NULL, NULL, NULL, NULL, NULL);
252