1 | #include "test_sockets.h"
|
---|
2 |
|
---|
3 | #include "lwip/mem.h"
|
---|
4 | #include "lwip/opt.h"
|
---|
5 | #include "lwip/sockets.h"
|
---|
6 | #include "lwip/priv/sockets_priv.h"
|
---|
7 | #include "lwip/stats.h"
|
---|
8 |
|
---|
9 | #include "lwip/tcpip.h"
|
---|
10 | #include "lwip/priv/tcp_priv.h"
|
---|
11 | #include "lwip/api.h"
|
---|
12 |
|
---|
13 |
|
---|
14 | static int
|
---|
15 | test_sockets_get_used_count(void)
|
---|
16 | {
|
---|
17 | int used = 0;
|
---|
18 | int i;
|
---|
19 |
|
---|
20 | for (i = 0; i < NUM_SOCKETS; i++) {
|
---|
21 | struct lwip_sock* s = lwip_socket_dbg_get_socket(i);
|
---|
22 | if (s != NULL) {
|
---|
23 | if (s->fd_used) {
|
---|
24 | used++;
|
---|
25 | }
|
---|
26 | }
|
---|
27 | }
|
---|
28 | return used;
|
---|
29 | }
|
---|
30 |
|
---|
31 |
|
---|
32 | /* Setups/teardown functions */
|
---|
33 |
|
---|
34 | static void
|
---|
35 | sockets_setup(void)
|
---|
36 | {
|
---|
37 | /* expect full free heap */
|
---|
38 | lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
|
---|
39 | }
|
---|
40 |
|
---|
41 | static void
|
---|
42 | sockets_teardown(void)
|
---|
43 | {
|
---|
44 | fail_unless(test_sockets_get_used_count() == 0);
|
---|
45 | /* poll until all memory is released... */
|
---|
46 | tcpip_thread_poll_one();
|
---|
47 | while (tcp_tw_pcbs) {
|
---|
48 | tcp_abort(tcp_tw_pcbs);
|
---|
49 | tcpip_thread_poll_one();
|
---|
50 | }
|
---|
51 | tcpip_thread_poll_one();
|
---|
52 | /* ensure full free heap */
|
---|
53 | lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
|
---|
54 | }
|
---|
55 |
|
---|
56 | #ifndef NUM_SOCKETS
|
---|
57 | #define NUM_SOCKETS MEMP_NUM_NETCONN
|
---|
58 | #endif
|
---|
59 |
|
---|
60 | #if LWIP_SOCKET
|
---|
61 | static int
|
---|
62 | test_sockets_alloc_socket_nonblocking(int domain, int type)
|
---|
63 | {
|
---|
64 | int s = lwip_socket(domain, type, 0);
|
---|
65 | if (s >= 0) {
|
---|
66 | int ret = lwip_fcntl(s, F_SETFL, O_NONBLOCK);
|
---|
67 | fail_unless(ret == 0);
|
---|
68 | }
|
---|
69 | return s;
|
---|
70 | }
|
---|
71 |
|
---|
72 | /* Verify basic sockets functionality
|
---|
73 | */
|
---|
74 | START_TEST(test_sockets_basics)
|
---|
75 | {
|
---|
76 | int s, i, ret;
|
---|
77 | int s2[NUM_SOCKETS];
|
---|
78 | LWIP_UNUSED_ARG(_i);
|
---|
79 |
|
---|
80 | s = lwip_socket(AF_INET, SOCK_STREAM, 0);
|
---|
81 | fail_unless(s >= 0);
|
---|
82 | lwip_close(s);
|
---|
83 |
|
---|
84 | for (i = 0; i < NUM_SOCKETS; i++) {
|
---|
85 | s2[i] = lwip_socket(AF_INET, SOCK_STREAM, 0);
|
---|
86 | fail_unless(s2[i] >= 0);
|
---|
87 | }
|
---|
88 |
|
---|
89 | /* all sockets used, now it should fail */
|
---|
90 | s = lwip_socket(AF_INET, SOCK_STREAM, 0);
|
---|
91 | fail_unless(s == -1);
|
---|
92 | /* close one socket */
|
---|
93 | ret = lwip_close(s2[0]);
|
---|
94 | fail_unless(ret == 0);
|
---|
95 | /* now it should succeed */
|
---|
96 | s2[0] = lwip_socket(AF_INET, SOCK_STREAM, 0);
|
---|
97 | fail_unless(s2[0] >= 0);
|
---|
98 |
|
---|
99 | /* close all sockets */
|
---|
100 | for (i = 0; i < NUM_SOCKETS; i++) {
|
---|
101 | ret = lwip_close(s2[i]);
|
---|
102 | fail_unless(ret == 0);
|
---|
103 | }
|
---|
104 | }
|
---|
105 | END_TEST
|
---|
106 |
|
---|
107 | static void test_sockets_allfunctions_basic_domain(int domain)
|
---|
108 | {
|
---|
109 | int s, s2, s3, ret;
|
---|
110 | struct sockaddr_storage addr, addr2;
|
---|
111 | socklen_t addrlen, addr2len;
|
---|
112 | char buf[4];
|
---|
113 | /* listen socket */
|
---|
114 | s = lwip_socket(domain, SOCK_STREAM, 0);
|
---|
115 | fail_unless(s >= 0);
|
---|
116 |
|
---|
117 | ret = lwip_listen(s, 0);
|
---|
118 | fail_unless(ret == 0);
|
---|
119 |
|
---|
120 | addrlen = sizeof(addr);
|
---|
121 | ret = lwip_getsockname(s, (struct sockaddr*)&addr, &addrlen);
|
---|
122 | fail_unless(ret == 0);
|
---|
123 |
|
---|
124 | s2 = test_sockets_alloc_socket_nonblocking(domain, SOCK_STREAM);
|
---|
125 | fail_unless(s2 >= 0);
|
---|
126 | /* nonblocking connect s2 to s (but use loopback address) */
|
---|
127 | if (domain == AF_INET) {
|
---|
128 | #if LWIP_IPV4
|
---|
129 | struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;
|
---|
130 | addr4->sin_addr.s_addr = PP_HTONL(INADDR_LOOPBACK);
|
---|
131 | #endif
|
---|
132 | } else {
|
---|
133 | #if LWIP_IPV6
|
---|
134 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
|
---|
135 | struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT;
|
---|
136 | addr6->sin6_addr = lo6;
|
---|
137 | #endif
|
---|
138 | }
|
---|
139 | ret = lwip_connect(s2, (struct sockaddr*)&addr, addrlen);
|
---|
140 | fail_unless(ret == -1);
|
---|
141 | fail_unless(errno == EINPROGRESS);
|
---|
142 | ret = lwip_connect(s2, (struct sockaddr*)&addr, addrlen);
|
---|
143 | fail_unless(ret == -1);
|
---|
144 | fail_unless(errno == EALREADY);
|
---|
145 |
|
---|
146 | while(tcpip_thread_poll_one());
|
---|
147 |
|
---|
148 | s3 = lwip_accept(s, (struct sockaddr*)&addr2, &addr2len);
|
---|
149 | fail_unless(s3 >= 0);
|
---|
150 |
|
---|
151 | ret = lwip_connect(s2, (struct sockaddr*)&addr, addrlen);
|
---|
152 | fail_unless(ret == -1);
|
---|
153 | fail_unless(errno == EISCONN);
|
---|
154 |
|
---|
155 | /* write from server to client */
|
---|
156 | ret = write(s3, "test", 4);
|
---|
157 | fail_unless(ret == 4);
|
---|
158 |
|
---|
159 | ret = lwip_shutdown(s3, SHUT_WR);
|
---|
160 | fail_unless(ret == 0);
|
---|
161 |
|
---|
162 | while(tcpip_thread_poll_one());
|
---|
163 |
|
---|
164 | ret = lwip_recv(s2, buf, 3, MSG_PEEK);
|
---|
165 | fail_unless(ret == 3);
|
---|
166 |
|
---|
167 | ret = lwip_recv(s2, buf, 3, MSG_PEEK);
|
---|
168 | fail_unless(ret == 3);
|
---|
169 |
|
---|
170 | ret = lwip_read(s2, buf, 4);
|
---|
171 | fail_unless(ret == 4);
|
---|
172 |
|
---|
173 | ret = lwip_read(s2, buf, 1);
|
---|
174 | fail_unless(ret == 0);
|
---|
175 |
|
---|
176 | ret = lwip_read(s2, buf, 1);
|
---|
177 | fail_unless(ret == -1);
|
---|
178 |
|
---|
179 | ret = lwip_write(s2, "foo", 3);
|
---|
180 | fail_unless(ret == 3);
|
---|
181 |
|
---|
182 | ret = lwip_close(s2);
|
---|
183 | fail_unless(ret == 0);
|
---|
184 |
|
---|
185 | while(tcpip_thread_poll_one());
|
---|
186 |
|
---|
187 | /* read one byte more than available to check handling FIN */
|
---|
188 | ret = lwip_read(s3, buf, 4);
|
---|
189 | fail_unless(ret == 3);
|
---|
190 |
|
---|
191 | ret = lwip_read(s3, buf, 1);
|
---|
192 | fail_unless(ret == 0);
|
---|
193 |
|
---|
194 | ret = lwip_read(s3, buf, 1);
|
---|
195 | fail_unless(ret == -1);
|
---|
196 |
|
---|
197 | while(tcpip_thread_poll_one());
|
---|
198 |
|
---|
199 | ret = lwip_close(s);
|
---|
200 | fail_unless(ret == 0);
|
---|
201 | ret = lwip_close(s3);
|
---|
202 | fail_unless(ret == 0);
|
---|
203 | }
|
---|
204 |
|
---|
205 | /* Try to step through all sockets functions once...
|
---|
206 | */
|
---|
207 | START_TEST(test_sockets_allfunctions_basic)
|
---|
208 | {
|
---|
209 | LWIP_UNUSED_ARG(_i);
|
---|
210 | #if LWIP_IPV4
|
---|
211 | test_sockets_allfunctions_basic_domain(AF_INET);
|
---|
212 | #endif
|
---|
213 | #if LWIP_IPV6
|
---|
214 | test_sockets_allfunctions_basic_domain(AF_INET6);
|
---|
215 | #endif
|
---|
216 | }
|
---|
217 | END_TEST
|
---|
218 |
|
---|
219 | static void test_sockets_init_loopback_addr(int domain, struct sockaddr_storage *addr_st, socklen_t *sz)
|
---|
220 | {
|
---|
221 | memset(addr_st, 0, sizeof(*addr_st));
|
---|
222 | switch(domain) {
|
---|
223 | #if LWIP_IPV6
|
---|
224 | case AF_INET6: {
|
---|
225 | struct sockaddr_in6 *addr = (struct sockaddr_in6*)addr_st;
|
---|
226 | struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT;
|
---|
227 | addr->sin6_family = AF_INET6;
|
---|
228 | addr->sin6_port = 0; /* use ephemeral port */
|
---|
229 | addr->sin6_addr = lo6;
|
---|
230 | *sz = sizeof(*addr);
|
---|
231 | }
|
---|
232 | break;
|
---|
233 | #endif /* LWIP_IPV6 */
|
---|
234 | #if LWIP_IPV4
|
---|
235 | case AF_INET: {
|
---|
236 | struct sockaddr_in *addr = (struct sockaddr_in*)addr_st;
|
---|
237 | addr->sin_family = AF_INET;
|
---|
238 | addr->sin_port = 0; /* use ephemeral port */
|
---|
239 | addr->sin_addr.s_addr = PP_HTONL(INADDR_LOOPBACK);
|
---|
240 | *sz = sizeof(*addr);
|
---|
241 | }
|
---|
242 | break;
|
---|
243 | #endif /* LWIP_IPV4 */
|
---|
244 | default:
|
---|
245 | *sz = 0;
|
---|
246 | fail();
|
---|
247 | break;
|
---|
248 | }
|
---|
249 | }
|
---|
250 |
|
---|
251 | static void test_sockets_msgapi_update_iovs(struct msghdr *msg, size_t bytes)
|
---|
252 | {
|
---|
253 | int i;
|
---|
254 |
|
---|
255 | /* note: this modifies the underyling iov_base and iov_len for a partial
|
---|
256 | read for an individual vector. This updates the msg->msg_iov pointer
|
---|
257 | to skip fully consumed vecotrs */
|
---|
258 |
|
---|
259 | /* process fully consumed vectors */
|
---|
260 | for (i = 0; i < msg->msg_iovlen; i++) {
|
---|
261 | if (msg->msg_iov[i].iov_len <= bytes) {
|
---|
262 | /* reduce bytes by amount of this vector */
|
---|
263 | bytes -= msg->msg_iov[i].iov_len;
|
---|
264 | } else {
|
---|
265 | break; /* iov not fully consumed */
|
---|
266 | }
|
---|
267 | }
|
---|
268 |
|
---|
269 | /* slide down over fully consumed vectors */
|
---|
270 | msg->msg_iov = &msg->msg_iov[i];
|
---|
271 | msg->msg_iovlen -= i;
|
---|
272 |
|
---|
273 | /* update new first vector with any remaining amount */
|
---|
274 | msg->msg_iov[0].iov_base = ((u8_t *)msg->msg_iov[0].iov_base + bytes);
|
---|
275 | msg->msg_iov[0].iov_len -= bytes;
|
---|
276 | }
|
---|
277 |
|
---|
278 | static void test_sockets_msgapi_tcp(int domain)
|
---|
279 | {
|
---|
280 | #define BUF_SZ (TCP_SND_BUF/4)
|
---|
281 | #define TOTAL_DATA_SZ (BUF_SZ*8) /* ~(TCP_SND_BUF*2) that accounts for integer rounding */
|
---|
282 | #define NEED_TRAILER (BUF_SZ % 4 != 0)
|
---|
283 | int listnr, s1, s2, i, ret, opt;
|
---|
284 | int bytes_written, bytes_read;
|
---|
285 | struct sockaddr_storage addr_storage;
|
---|
286 | socklen_t addr_size;
|
---|
287 | struct iovec siovs[8];
|
---|
288 | struct msghdr smsg;
|
---|
289 | u8_t * snd_buf;
|
---|
290 | struct iovec riovs[5];
|
---|
291 | struct iovec riovs_tmp[5];
|
---|
292 | struct msghdr rmsg;
|
---|
293 | u8_t * rcv_buf;
|
---|
294 | int rcv_off;
|
---|
295 | int rcv_trailer = 0;
|
---|
296 | u8_t val;
|
---|
297 |
|
---|
298 | test_sockets_init_loopback_addr(domain, &addr_storage, &addr_size);
|
---|
299 |
|
---|
300 | listnr = test_sockets_alloc_socket_nonblocking(domain, SOCK_STREAM);
|
---|
301 | fail_unless(listnr >= 0);
|
---|
302 | s1 = test_sockets_alloc_socket_nonblocking(domain, SOCK_STREAM);
|
---|
303 | fail_unless(s1 >= 0);
|
---|
304 |
|
---|
305 | /* setup a listener socket on loopback with ephemeral port */
|
---|
306 | ret = lwip_bind(listnr, (struct sockaddr*)&addr_storage, addr_size);
|
---|
307 | fail_unless(ret == 0);
|
---|
308 | ret = lwip_listen(listnr, 0);
|
---|
309 | fail_unless(ret == 0);
|
---|
310 |
|
---|
311 | /* update address with ephemeral port */
|
---|
312 | ret = lwip_getsockname(listnr, (struct sockaddr*)&addr_storage, &addr_size);
|
---|
313 | fail_unless(ret == 0);
|
---|
314 |
|
---|
315 | /* connect, won't complete until we accept it */
|
---|
316 | ret = lwip_connect(s1, (struct sockaddr*)&addr_storage, addr_size);
|
---|
317 | fail_unless(ret == -1);
|
---|
318 | fail_unless(errno == EINPROGRESS);
|
---|
319 |
|
---|
320 | while (tcpip_thread_poll_one());
|
---|
321 |
|
---|
322 | /* accept, creating the other side of the connection */
|
---|
323 | s2 = lwip_accept(listnr, NULL, NULL);
|
---|
324 | fail_unless(s2 >= 0);
|
---|
325 |
|
---|
326 | /* double check s1 is connected */
|
---|
327 | ret = lwip_connect(s1, (struct sockaddr*)&addr_storage, addr_size);
|
---|
328 | fail_unless(ret == -1);
|
---|
329 | fail_unless(errno == EISCONN);
|
---|
330 |
|
---|
331 | /* set s2 to non-blocking, not inherited from listener */
|
---|
332 | opt = lwip_fcntl(s2, F_GETFL, 0);
|
---|
333 | fail_unless(opt == 6);
|
---|
334 | opt = O_NONBLOCK;
|
---|
335 | ret = lwip_fcntl(s2, F_SETFL, opt);
|
---|
336 | fail_unless(ret == 0);
|
---|
337 |
|
---|
338 | /* we are done with listener, close it */
|
---|
339 | ret = lwip_close(listnr);
|
---|
340 | fail_unless(ret == 0);
|
---|
341 |
|
---|
342 | /* allocate a buffer for a stream of incrementing hex (0x00..0xFF) which we will use
|
---|
343 | to create an input vector set that is larger than the TCP's send buffer. This will
|
---|
344 | force execution of the partial IO vector send case */
|
---|
345 | snd_buf = (u8_t*)mem_malloc(BUF_SZ);
|
---|
346 | val = 0x00;
|
---|
347 | fail_unless(snd_buf != NULL);
|
---|
348 | for (i = 0; i < BUF_SZ; i++,val++) {
|
---|
349 | snd_buf[i] = val;
|
---|
350 | }
|
---|
351 |
|
---|
352 | /* send the buffer 8 times in one message, equating to TOTAL_DATA_SZ */
|
---|
353 | for (i = 0; i < 8; i++) {
|
---|
354 | siovs[i].iov_base = snd_buf;
|
---|
355 | siovs[i].iov_len = BUF_SZ;
|
---|
356 | }
|
---|
357 |
|
---|
358 | /* allocate a receive buffer, same size as snd_buf for easy verification */
|
---|
359 | rcv_buf = (u8_t*)mem_calloc(1, BUF_SZ);
|
---|
360 | fail_unless(rcv_buf != NULL);
|
---|
361 | /* split across iovs */
|
---|
362 | for (i = 0; i < 4; i++) {
|
---|
363 | riovs[i].iov_base = &rcv_buf[i*(BUF_SZ/4)];
|
---|
364 | riovs[i].iov_len = BUF_SZ/4;
|
---|
365 | }
|
---|
366 | /* handling trailing bytes if buffer doesn't evenly divide by 4 */
|
---|
367 | #if NEED_TRAILER
|
---|
368 | if ((BUF_SZ % 4) != 0) {
|
---|
369 | riovs[5].iov_base = &rcv_buf[4*(BUF_SZ/4)];
|
---|
370 | riovs[5].iov_len = BUF_SZ - (4*(BUF_SZ/4));
|
---|
371 | rcv_trailer = 1;
|
---|
372 | }
|
---|
373 | #endif /* NEED_TRAILER */
|
---|
374 |
|
---|
375 | /* we use a copy of riovs since we'll be modifying base and len during
|
---|
376 | receiving. This gives us an easy way to reset the iovs for next recvmsg */
|
---|
377 | memcpy(riovs_tmp, riovs, sizeof(riovs));
|
---|
378 |
|
---|
379 | memset(&smsg, 0, sizeof(smsg));
|
---|
380 | smsg.msg_iov = siovs;
|
---|
381 | smsg.msg_iovlen = 8;
|
---|
382 |
|
---|
383 | memset(&rmsg, 0, sizeof(rmsg));
|
---|
384 | rmsg.msg_iov = riovs_tmp;
|
---|
385 | rmsg.msg_iovlen = (rcv_trailer ? 5 : 4);
|
---|
386 |
|
---|
387 | bytes_written = 0;
|
---|
388 | bytes_read = 0;
|
---|
389 | rcv_off = 0;
|
---|
390 |
|
---|
391 | while (bytes_written < TOTAL_DATA_SZ && (bytes_read < TOTAL_DATA_SZ)) {
|
---|
392 | /* send data */
|
---|
393 | if (bytes_written < TOTAL_DATA_SZ) {
|
---|
394 | ret = lwip_sendmsg(s1, &smsg, 0);
|
---|
395 | /* note: since we always receive after sending, there will be open
|
---|
396 | space in the send buffer */
|
---|
397 | fail_unless(ret > 0);
|
---|
398 |
|
---|
399 | bytes_written += ret;
|
---|
400 | if (bytes_written < TOTAL_DATA_SZ) {
|
---|
401 | test_sockets_msgapi_update_iovs(&smsg, (size_t)ret);
|
---|
402 | }
|
---|
403 | }
|
---|
404 |
|
---|
405 | while (tcpip_thread_poll_one());
|
---|
406 |
|
---|
407 | /* receive and verify data */
|
---|
408 | do {
|
---|
409 | if (bytes_read < TOTAL_DATA_SZ) {
|
---|
410 | ret = lwip_recvmsg(s2, &rmsg, 0);
|
---|
411 | fail_unless(ret > 0 || (ret == -1 && errno == EWOULDBLOCK));
|
---|
412 |
|
---|
413 | if (ret > 0) {
|
---|
414 | rcv_off += ret;
|
---|
415 | /* we have received a full buffer */
|
---|
416 | if (rcv_off == BUF_SZ) {
|
---|
417 | /* note: since iovs are just pointers, compare underlying buf */
|
---|
418 | fail_unless(!memcmp(snd_buf, rcv_buf, BUF_SZ));
|
---|
419 | bytes_read += BUF_SZ;
|
---|
420 | /* reset receive state for next buffer */
|
---|
421 | rcv_off = 0;
|
---|
422 | memset(rcv_buf, 0, BUF_SZ);
|
---|
423 | memcpy(riovs_tmp, riovs, sizeof(riovs));
|
---|
424 | rmsg.msg_iov = riovs_tmp;
|
---|
425 | rmsg.msg_iovlen = (rcv_trailer ? 5 : 4);
|
---|
426 | } else { /* partial read */
|
---|
427 | test_sockets_msgapi_update_iovs(&rmsg, (size_t)ret);
|
---|
428 | }
|
---|
429 | }
|
---|
430 | } else {
|
---|
431 | break;
|
---|
432 | }
|
---|
433 | } while(ret > 0);
|
---|
434 | }
|
---|
435 |
|
---|
436 | ret = lwip_close(s1);
|
---|
437 | fail_unless(ret == 0);
|
---|
438 | ret = lwip_close(s2);
|
---|
439 | fail_unless(ret == 0);
|
---|
440 | mem_free(snd_buf);
|
---|
441 | mem_free(rcv_buf);
|
---|
442 | }
|
---|
443 |
|
---|
444 | static void test_sockets_msgapi_udp_send_recv_loop(int s, struct msghdr *smsg, struct msghdr *rmsg)
|
---|
445 | {
|
---|
446 | int i, ret;
|
---|
447 |
|
---|
448 | /* send/receive our datagram of IO vectors 10 times */
|
---|
449 | for (i = 0; i < 10; i++) {
|
---|
450 | ret = lwip_sendmsg(s, smsg, 0);
|
---|
451 | fail_unless(ret == 4);
|
---|
452 |
|
---|
453 | while (tcpip_thread_poll_one());
|
---|
454 |
|
---|
455 | /* receive the datagram split across 4 buffers */
|
---|
456 | ret = lwip_recvmsg(s, rmsg, 0);
|
---|
457 | fail_unless(ret == 4);
|
---|
458 |
|
---|
459 | /* verify data */
|
---|
460 | fail_unless(*((u8_t*)rmsg->msg_iov[0].iov_base) == 0xDE);
|
---|
461 | fail_unless(*((u8_t*)rmsg->msg_iov[1].iov_base) == 0xAD);
|
---|
462 | fail_unless(*((u8_t*)rmsg->msg_iov[2].iov_base) == 0xBE);
|
---|
463 | fail_unless(*((u8_t*)rmsg->msg_iov[3].iov_base) == 0xEF);
|
---|
464 |
|
---|
465 | /* clear rcv_buf to ensure no data is being skipped */
|
---|
466 | *((u8_t*)rmsg->msg_iov[0].iov_base) = 0x00;
|
---|
467 | *((u8_t*)rmsg->msg_iov[1].iov_base) = 0x00;
|
---|
468 | *((u8_t*)rmsg->msg_iov[2].iov_base) = 0x00;
|
---|
469 | *((u8_t*)rmsg->msg_iov[3].iov_base) = 0x00;
|
---|
470 | }
|
---|
471 | }
|
---|
472 |
|
---|
473 | static void test_sockets_msgapi_udp(int domain)
|
---|
474 | {
|
---|
475 | int s, i, ret;
|
---|
476 | struct sockaddr_storage addr_storage;
|
---|
477 | socklen_t addr_size;
|
---|
478 | struct iovec riovs[4];
|
---|
479 | struct msghdr rmsg;
|
---|
480 | u8_t rcv_buf[4];
|
---|
481 | struct iovec siovs[4];
|
---|
482 | struct msghdr smsg;
|
---|
483 | u8_t snd_buf[4] = {0xDE, 0xAD, 0xBE, 0xEF};
|
---|
484 |
|
---|
485 | /* initialize IO vectors with data */
|
---|
486 | for (i = 0; i < 4; i++) {
|
---|
487 | siovs[i].iov_base = &snd_buf[i];
|
---|
488 | siovs[i].iov_len = sizeof(u8_t);
|
---|
489 | riovs[i].iov_base = &rcv_buf[i];
|
---|
490 | riovs[i].iov_len = sizeof(u8_t);
|
---|
491 | }
|
---|
492 |
|
---|
493 | test_sockets_init_loopback_addr(domain, &addr_storage, &addr_size);
|
---|
494 |
|
---|
495 | s = test_sockets_alloc_socket_nonblocking(domain, SOCK_DGRAM);
|
---|
496 | fail_unless(s >= 0);
|
---|
497 |
|
---|
498 | ret = lwip_bind(s, (struct sockaddr*)&addr_storage, addr_size);
|
---|
499 | fail_unless(ret == 0);
|
---|
500 |
|
---|
501 | /* Update addr with epehermal port */
|
---|
502 | ret = lwip_getsockname(s, (struct sockaddr*)&addr_storage, &addr_size);
|
---|
503 | fail_unless(ret == 0);
|
---|
504 | switch(domain) {
|
---|
505 | #if LWIP_IPV6
|
---|
506 | case AF_INET6:
|
---|
507 | fail_unless(addr_size == sizeof(struct sockaddr_in6));
|
---|
508 | break;
|
---|
509 | #endif /* LWIP_IPV6 */
|
---|
510 | #if LWIP_IPV4
|
---|
511 | case AF_INET:
|
---|
512 | fail_unless(addr_size == sizeof(struct sockaddr_in));
|
---|
513 | break;
|
---|
514 | #endif /* LWIP_IPV6 */
|
---|
515 | default:
|
---|
516 | fail();
|
---|
517 | break;
|
---|
518 | }
|
---|
519 |
|
---|
520 | /* send and receive the datagram in 4 pieces */
|
---|
521 | memset(&smsg, 0, sizeof(smsg));
|
---|
522 | smsg.msg_iov = siovs;
|
---|
523 | smsg.msg_iovlen = 4;
|
---|
524 | memset(&rmsg, 0, sizeof(rmsg));
|
---|
525 | rmsg.msg_iov = riovs;
|
---|
526 | rmsg.msg_iovlen = 4;
|
---|
527 |
|
---|
528 | /* perform a sendmsg with remote host (self) */
|
---|
529 | smsg.msg_name = &addr_storage;
|
---|
530 | smsg.msg_namelen = addr_size;
|
---|
531 |
|
---|
532 | test_sockets_msgapi_udp_send_recv_loop(s, &smsg, &rmsg);
|
---|
533 |
|
---|
534 | /* Connect to self, allowing us to not pass message name */
|
---|
535 | ret = lwip_connect(s, (struct sockaddr*)&addr_storage, addr_size);
|
---|
536 | fail_unless(ret == 0);
|
---|
537 |
|
---|
538 | smsg.msg_name = NULL;
|
---|
539 | smsg.msg_namelen = 0;
|
---|
540 |
|
---|
541 | test_sockets_msgapi_udp_send_recv_loop(s, &smsg, &rmsg);
|
---|
542 |
|
---|
543 | ret = lwip_close(s);
|
---|
544 | fail_unless(ret == 0);
|
---|
545 | }
|
---|
546 |
|
---|
547 | #if LWIP_IPV4
|
---|
548 | static void test_sockets_msgapi_cmsg(int domain)
|
---|
549 | {
|
---|
550 | int s, ret, enable;
|
---|
551 | struct sockaddr_storage addr_storage;
|
---|
552 | socklen_t addr_size;
|
---|
553 | struct iovec iov;
|
---|
554 | struct msghdr msg;
|
---|
555 | struct cmsghdr *cmsg;
|
---|
556 | struct in_pktinfo *pktinfo;
|
---|
557 | u8_t rcv_buf[4];
|
---|
558 | u8_t snd_buf[4] = {0xDE, 0xAD, 0xBE, 0xEF};
|
---|
559 | u8_t cmsg_buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
|
---|
560 |
|
---|
561 | test_sockets_init_loopback_addr(domain, &addr_storage, &addr_size);
|
---|
562 |
|
---|
563 | s = test_sockets_alloc_socket_nonblocking(domain, SOCK_DGRAM);
|
---|
564 | fail_unless(s >= 0);
|
---|
565 |
|
---|
566 | ret = lwip_bind(s, (struct sockaddr*)&addr_storage, addr_size);
|
---|
567 | fail_unless(ret == 0);
|
---|
568 |
|
---|
569 | /* Update addr with epehermal port */
|
---|
570 | ret = lwip_getsockname(s, (struct sockaddr*)&addr_storage, &addr_size);
|
---|
571 | fail_unless(ret == 0);
|
---|
572 |
|
---|
573 | enable = 1;
|
---|
574 | ret = lwip_setsockopt(s, IPPROTO_IP, IP_PKTINFO, &enable, sizeof(enable));
|
---|
575 | fail_unless(ret == 0);
|
---|
576 |
|
---|
577 | /* Receive full message, including control message */
|
---|
578 | iov.iov_base = rcv_buf;
|
---|
579 | iov.iov_len = sizeof(rcv_buf);
|
---|
580 | msg.msg_control = cmsg_buf;
|
---|
581 | msg.msg_controllen = sizeof(cmsg_buf);
|
---|
582 | msg.msg_flags = 0;
|
---|
583 | msg.msg_iov = &iov;
|
---|
584 | msg.msg_iovlen = 1;
|
---|
585 | msg.msg_name = NULL;
|
---|
586 | msg.msg_namelen = 0;
|
---|
587 |
|
---|
588 | memset(rcv_buf, 0, sizeof(rcv_buf));
|
---|
589 | ret = lwip_sendto(s, snd_buf, sizeof(snd_buf), 0, (struct sockaddr*)&addr_storage, addr_size);
|
---|
590 | fail_unless(ret == sizeof(snd_buf));
|
---|
591 |
|
---|
592 | tcpip_thread_poll_one();
|
---|
593 |
|
---|
594 | ret = lwip_recvmsg(s, &msg, 0);
|
---|
595 | fail_unless(ret == sizeof(rcv_buf));
|
---|
596 | fail_unless(!memcmp(rcv_buf, snd_buf, sizeof(rcv_buf)));
|
---|
597 |
|
---|
598 | /* Verify message header */
|
---|
599 | cmsg = CMSG_FIRSTHDR(&msg);
|
---|
600 | fail_unless(cmsg != NULL);
|
---|
601 | fail_unless(cmsg->cmsg_len > 0);
|
---|
602 | fail_unless(cmsg->cmsg_level == IPPROTO_IP);
|
---|
603 | fail_unless(cmsg->cmsg_type == IP_PKTINFO);
|
---|
604 |
|
---|
605 | /* Verify message data */
|
---|
606 | pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
|
---|
607 | /* We only have loopback interface enabled */
|
---|
608 | fail_unless(pktinfo->ipi_ifindex == 1);
|
---|
609 | fail_unless(pktinfo->ipi_addr.s_addr == PP_HTONL(INADDR_LOOPBACK));
|
---|
610 |
|
---|
611 | /* Verify there are no additional messages */
|
---|
612 | cmsg = CMSG_NXTHDR(&msg, cmsg);
|
---|
613 | fail_unless(cmsg == NULL);
|
---|
614 |
|
---|
615 | /* Send datagram again, testing truncation */
|
---|
616 | memset(rcv_buf, 0, sizeof(rcv_buf));
|
---|
617 | ret = lwip_sendto(s, snd_buf, sizeof(snd_buf), 0, (struct sockaddr*)&addr_storage, addr_size);
|
---|
618 | fail_unless(ret == sizeof(snd_buf));
|
---|
619 |
|
---|
620 | tcpip_thread_poll_one();
|
---|
621 |
|
---|
622 | msg.msg_controllen = 1;
|
---|
623 | msg.msg_flags = 0;
|
---|
624 | ret = lwip_recvmsg(s, &msg, 0);
|
---|
625 | fail_unless(ret == sizeof(rcv_buf));
|
---|
626 | fail_unless(!memcmp(rcv_buf, snd_buf, sizeof(rcv_buf)));
|
---|
627 | /* Ensure truncation was returned */
|
---|
628 | fail_unless(msg.msg_flags & MSG_CTRUNC);
|
---|
629 | /* Ensure no control messages were returned */
|
---|
630 | fail_unless(msg.msg_controllen == 0);
|
---|
631 |
|
---|
632 | ret = lwip_close(s);
|
---|
633 | fail_unless(ret == 0);
|
---|
634 | }
|
---|
635 | #endif /* LWIP_IPV4 */
|
---|
636 |
|
---|
637 | START_TEST(test_sockets_msgapis)
|
---|
638 | {
|
---|
639 | LWIP_UNUSED_ARG(_i);
|
---|
640 | #if LWIP_IPV4
|
---|
641 | test_sockets_msgapi_udp(AF_INET);
|
---|
642 | test_sockets_msgapi_tcp(AF_INET);
|
---|
643 | test_sockets_msgapi_cmsg(AF_INET);
|
---|
644 | #endif
|
---|
645 | #if LWIP_IPV6
|
---|
646 | test_sockets_msgapi_udp(AF_INET6);
|
---|
647 | test_sockets_msgapi_tcp(AF_INET6);
|
---|
648 | #endif
|
---|
649 | }
|
---|
650 | END_TEST
|
---|
651 |
|
---|
652 | START_TEST(test_sockets_select)
|
---|
653 | {
|
---|
654 | #if LWIP_SOCKET_SELECT
|
---|
655 | int s;
|
---|
656 | int ret;
|
---|
657 | fd_set readset;
|
---|
658 | fd_set writeset;
|
---|
659 | fd_set errset;
|
---|
660 | struct timeval tv;
|
---|
661 |
|
---|
662 | fail_unless(test_sockets_get_used_count() == 0);
|
---|
663 |
|
---|
664 | s = lwip_socket(AF_INET, SOCK_STREAM, 0);
|
---|
665 | fail_unless(s >= 0);
|
---|
666 | fail_unless(test_sockets_get_used_count() == 0);
|
---|
667 |
|
---|
668 | FD_ZERO(&readset);
|
---|
669 | FD_SET(s, &readset);
|
---|
670 | FD_ZERO(&writeset);
|
---|
671 | FD_SET(s, &writeset);
|
---|
672 | FD_ZERO(&errset);
|
---|
673 | FD_SET(s, &errset);
|
---|
674 |
|
---|
675 | tv.tv_sec = tv.tv_usec = 0;
|
---|
676 | ret = lwip_select(s + 1, &readset, &writeset, &errset, &tv);
|
---|
677 | fail_unless(ret == 0);
|
---|
678 | fail_unless(test_sockets_get_used_count() == 0);
|
---|
679 |
|
---|
680 | ret = lwip_close(s);
|
---|
681 | fail_unless(ret == 0);
|
---|
682 |
|
---|
683 | #endif
|
---|
684 | LWIP_UNUSED_ARG(_i);
|
---|
685 | }
|
---|
686 | END_TEST
|
---|
687 |
|
---|
688 | START_TEST(test_sockets_recv_after_rst)
|
---|
689 | {
|
---|
690 | int sl, sact;
|
---|
691 | int spass = -1;
|
---|
692 | int ret;
|
---|
693 | struct sockaddr_in sa_listen;
|
---|
694 | const u16_t port = 1234;
|
---|
695 | int arg;
|
---|
696 | const char txbuf[] = "something";
|
---|
697 | char rxbuf[16];
|
---|
698 | struct lwip_sock *sact_sock;
|
---|
699 | int err;
|
---|
700 | LWIP_UNUSED_ARG(_i);
|
---|
701 |
|
---|
702 | fail_unless(test_sockets_get_used_count() == 0);
|
---|
703 |
|
---|
704 | memset(&sa_listen, 0, sizeof(sa_listen));
|
---|
705 | sa_listen.sin_family = AF_INET;
|
---|
706 | sa_listen.sin_port = PP_HTONS(port);
|
---|
707 | sa_listen.sin_addr.s_addr = PP_HTONL(INADDR_LOOPBACK);
|
---|
708 |
|
---|
709 | /* set up the listener */
|
---|
710 | sl = lwip_socket(AF_INET, SOCK_STREAM, 0);
|
---|
711 | fail_unless(sl >= 0);
|
---|
712 | fail_unless(test_sockets_get_used_count() == 0);
|
---|
713 |
|
---|
714 | ret = lwip_bind(sl, (struct sockaddr *)&sa_listen, sizeof(sa_listen));
|
---|
715 | fail_unless(ret == 0);
|
---|
716 | ret = lwip_listen(sl, 0);
|
---|
717 | fail_unless(ret == 0);
|
---|
718 |
|
---|
719 | /* set up the client */
|
---|
720 | sact = lwip_socket(AF_INET, SOCK_STREAM, 0);
|
---|
721 | fail_unless(sact >= 0);
|
---|
722 | fail_unless(test_sockets_get_used_count() == 0);
|
---|
723 | /* set the client to nonblocking to simplify this test */
|
---|
724 | arg = 1;
|
---|
725 | ret = lwip_ioctl(sact, FIONBIO, &arg);
|
---|
726 | fail_unless(ret == 0);
|
---|
727 | /* connect */
|
---|
728 | do {
|
---|
729 | ret = lwip_connect(sact, (struct sockaddr *)&sa_listen, sizeof(sa_listen));
|
---|
730 | err = errno;
|
---|
731 | fail_unless((ret == 0) || (ret == -1));
|
---|
732 | if (ret != 0) {
|
---|
733 | if (err == EISCONN) {
|
---|
734 | /* Although this is not valid, use EISCONN as an indicator for successful connection.
|
---|
735 | This marks us as "connect phase is done". On error, we would either have a different
|
---|
736 | errno code or "send" fails later... -> good enough for this test. */
|
---|
737 | ret = 0;
|
---|
738 | } else {
|
---|
739 | fail_unless(err == EINPROGRESS);
|
---|
740 | if (err != EINPROGRESS) {
|
---|
741 | goto cleanup;
|
---|
742 | }
|
---|
743 | /* we're in progress: little side check: test for EALREADY */
|
---|
744 | ret = lwip_connect(sact, (struct sockaddr *)&sa_listen, sizeof(sa_listen));
|
---|
745 | err = errno;
|
---|
746 | fail_unless(ret == -1);
|
---|
747 | fail_unless(err == EALREADY);
|
---|
748 | if ((ret != -1) || (err != EALREADY)) {
|
---|
749 | goto cleanup;
|
---|
750 | }
|
---|
751 | }
|
---|
752 | tcpip_thread_poll_one();
|
---|
753 | tcpip_thread_poll_one();
|
---|
754 | tcpip_thread_poll_one();
|
---|
755 | tcpip_thread_poll_one();
|
---|
756 | }
|
---|
757 | } while (ret != 0);
|
---|
758 | fail_unless(ret == 0);
|
---|
759 |
|
---|
760 | /* accept the server connection part */
|
---|
761 | spass = lwip_accept(sl, NULL, NULL);
|
---|
762 | fail_unless(spass >= 0);
|
---|
763 |
|
---|
764 | /* write data from client */
|
---|
765 | ret = lwip_send(sact, txbuf, sizeof(txbuf), 0);
|
---|
766 | fail_unless(ret == sizeof(txbuf));
|
---|
767 |
|
---|
768 | tcpip_thread_poll_one();
|
---|
769 | tcpip_thread_poll_one();
|
---|
770 |
|
---|
771 | /* issue RST (This is a HACK, don't try this in your own app!) */
|
---|
772 | sact_sock = lwip_socket_dbg_get_socket(sact);
|
---|
773 | fail_unless(sact_sock != NULL);
|
---|
774 | if (sact_sock != NULL) {
|
---|
775 | struct netconn *sact_conn = sact_sock->conn;
|
---|
776 | fail_unless(sact_conn != NULL);
|
---|
777 | if (sact_conn != NULL) {
|
---|
778 | struct tcp_pcb *pcb = sact_conn->pcb.tcp;
|
---|
779 | fail_unless(pcb != NULL);
|
---|
780 | if (pcb != NULL) {
|
---|
781 | tcp_rst(pcb, pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
|
---|
782 | pcb->local_port, pcb->remote_port);
|
---|
783 | }
|
---|
784 | }
|
---|
785 | }
|
---|
786 | tcpip_thread_poll_one();
|
---|
787 | tcpip_thread_poll_one();
|
---|
788 |
|
---|
789 | /* expect to receive data first */
|
---|
790 | ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
|
---|
791 | fail_unless(ret > 0);
|
---|
792 | tcpip_thread_poll_one();
|
---|
793 | tcpip_thread_poll_one();
|
---|
794 |
|
---|
795 | /* expect to receive RST indication */
|
---|
796 | ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
|
---|
797 | fail_unless(ret == -1);
|
---|
798 | err = errno;
|
---|
799 | fail_unless(err == ECONNRESET);
|
---|
800 | tcpip_thread_poll_one();
|
---|
801 | tcpip_thread_poll_one();
|
---|
802 |
|
---|
803 | /* expect to receive ENOTCONN indication */
|
---|
804 | ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
|
---|
805 | fail_unless(ret == -1);
|
---|
806 | err = errno;
|
---|
807 | fail_unless(err == ENOTCONN);
|
---|
808 | tcpip_thread_poll_one();
|
---|
809 | tcpip_thread_poll_one();
|
---|
810 |
|
---|
811 | /* expect to receive ENOTCONN indication */
|
---|
812 | ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
|
---|
813 | fail_unless(ret == -1);
|
---|
814 | err = errno;
|
---|
815 | fail_unless(err == ENOTCONN);
|
---|
816 | tcpip_thread_poll_one();
|
---|
817 | tcpip_thread_poll_one();
|
---|
818 |
|
---|
819 | cleanup:
|
---|
820 | ret = lwip_close(sl);
|
---|
821 | fail_unless(ret == 0);
|
---|
822 | ret = lwip_close(sact);
|
---|
823 | fail_unless(ret == 0);
|
---|
824 | if (spass >= 0) {
|
---|
825 | ret = lwip_close(spass);
|
---|
826 | fail_unless(ret == 0);
|
---|
827 | }
|
---|
828 | }
|
---|
829 | END_TEST
|
---|
830 |
|
---|
831 | /** Create the suite including all tests for this module */
|
---|
832 | Suite *
|
---|
833 | sockets_suite(void)
|
---|
834 | {
|
---|
835 | testfunc tests[] = {
|
---|
836 | TESTFUNC(test_sockets_basics),
|
---|
837 | TESTFUNC(test_sockets_allfunctions_basic),
|
---|
838 | TESTFUNC(test_sockets_msgapis),
|
---|
839 | TESTFUNC(test_sockets_select),
|
---|
840 | TESTFUNC(test_sockets_recv_after_rst),
|
---|
841 | };
|
---|
842 | return create_suite("SOCKETS", tests, sizeof(tests)/sizeof(testfunc), sockets_setup, sockets_teardown);
|
---|
843 | }
|
---|
844 |
|
---|
845 | #else /* LWIP_SOCKET */
|
---|
846 |
|
---|
847 | Suite *
|
---|
848 | sockets_suite(void)
|
---|
849 | {
|
---|
850 | return create_suite("SOCKETS", NULL, 0, NULL, NULL);
|
---|
851 | }
|
---|
852 | #endif /* LWIP_SOCKET */
|
---|