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
14static int
15test_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
34static void
35sockets_setup(void)
36{
37  /* expect full free heap */
38  lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
39}
40
41static void
42sockets_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
61static int
62test_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 */
74START_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}
105END_TEST
106
107static 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 */
207START_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}
217END_TEST
218
219static 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
251static 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
278static 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
444static 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
473static 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
548static 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
637START_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}
650END_TEST
651
652START_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}
686END_TEST
687
688START_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
819cleanup:
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}
829END_TEST
830
831/** Create the suite including all tests for this module */
832Suite *
833sockets_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
847Suite *
848sockets_suite(void)
849{
850  return create_suite("SOCKETS", NULL, 0, NULL, NULL);
851}
852#endif /* LWIP_SOCKET */
853