1195972f6Sopenharmony_ci#include "test_sockets.h"
2195972f6Sopenharmony_ci
3195972f6Sopenharmony_ci#include "lwip/mem.h"
4195972f6Sopenharmony_ci#include "lwip/opt.h"
5195972f6Sopenharmony_ci#include "lwip/sockets.h"
6195972f6Sopenharmony_ci#include "lwip/priv/sockets_priv.h"
7195972f6Sopenharmony_ci#include "lwip/stats.h"
8195972f6Sopenharmony_ci
9195972f6Sopenharmony_ci#include "lwip/tcpip.h"
10195972f6Sopenharmony_ci#include "lwip/priv/tcp_priv.h"
11195972f6Sopenharmony_ci#include "lwip/api.h"
12195972f6Sopenharmony_ci
13195972f6Sopenharmony_ci
14195972f6Sopenharmony_cistatic int
15195972f6Sopenharmony_citest_sockets_get_used_count(void)
16195972f6Sopenharmony_ci{
17195972f6Sopenharmony_ci  int used = 0;
18195972f6Sopenharmony_ci  int i;
19195972f6Sopenharmony_ci
20195972f6Sopenharmony_ci  for (i = 0; i < NUM_SOCKETS; i++) {
21195972f6Sopenharmony_ci    struct lwip_sock* s = lwip_socket_dbg_get_socket(i);
22195972f6Sopenharmony_ci    if (s != NULL) {
23195972f6Sopenharmony_ci      if (s->fd_used) {
24195972f6Sopenharmony_ci        used++;
25195972f6Sopenharmony_ci      }
26195972f6Sopenharmony_ci    }
27195972f6Sopenharmony_ci  }
28195972f6Sopenharmony_ci  return used;
29195972f6Sopenharmony_ci}
30195972f6Sopenharmony_ci
31195972f6Sopenharmony_ci
32195972f6Sopenharmony_ci/* Setups/teardown functions */
33195972f6Sopenharmony_ci
34195972f6Sopenharmony_cistatic void
35195972f6Sopenharmony_cisockets_setup(void)
36195972f6Sopenharmony_ci{
37195972f6Sopenharmony_ci  /* expect full free heap */
38195972f6Sopenharmony_ci  lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
39195972f6Sopenharmony_ci}
40195972f6Sopenharmony_ci
41195972f6Sopenharmony_cistatic void
42195972f6Sopenharmony_cisockets_teardown(void)
43195972f6Sopenharmony_ci{
44195972f6Sopenharmony_ci  fail_unless(test_sockets_get_used_count() == 0);
45195972f6Sopenharmony_ci  /* poll until all memory is released... */
46195972f6Sopenharmony_ci  tcpip_thread_poll_one();
47195972f6Sopenharmony_ci  while (tcp_tw_pcbs) {
48195972f6Sopenharmony_ci    tcp_abort(tcp_tw_pcbs);
49195972f6Sopenharmony_ci    tcpip_thread_poll_one();
50195972f6Sopenharmony_ci  }
51195972f6Sopenharmony_ci  tcpip_thread_poll_one();
52195972f6Sopenharmony_ci  /* ensure full free heap */
53195972f6Sopenharmony_ci  lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
54195972f6Sopenharmony_ci}
55195972f6Sopenharmony_ci
56195972f6Sopenharmony_ci#ifndef NUM_SOCKETS
57195972f6Sopenharmony_ci#define NUM_SOCKETS MEMP_NUM_NETCONN
58195972f6Sopenharmony_ci#endif
59195972f6Sopenharmony_ci
60195972f6Sopenharmony_ci#if LWIP_SOCKET
61195972f6Sopenharmony_cistatic int
62195972f6Sopenharmony_citest_sockets_alloc_socket_nonblocking(int domain, int type)
63195972f6Sopenharmony_ci{
64195972f6Sopenharmony_ci  int s = lwip_socket(domain, type, 0);
65195972f6Sopenharmony_ci  if (s >= 0) {
66195972f6Sopenharmony_ci    int ret = lwip_fcntl(s, F_SETFL, O_NONBLOCK);
67195972f6Sopenharmony_ci    fail_unless(ret == 0);
68195972f6Sopenharmony_ci  }
69195972f6Sopenharmony_ci  return s;
70195972f6Sopenharmony_ci}
71195972f6Sopenharmony_ci
72195972f6Sopenharmony_ci/* Verify basic sockets functionality
73195972f6Sopenharmony_ci */
74195972f6Sopenharmony_ciSTART_TEST(test_sockets_basics)
75195972f6Sopenharmony_ci{
76195972f6Sopenharmony_ci  int s, i, ret;
77195972f6Sopenharmony_ci  int s2[NUM_SOCKETS];
78195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(_i);
79195972f6Sopenharmony_ci
80195972f6Sopenharmony_ci  s = lwip_socket(AF_INET, SOCK_STREAM, 0);
81195972f6Sopenharmony_ci  fail_unless(s >= 0);
82195972f6Sopenharmony_ci  lwip_close(s);
83195972f6Sopenharmony_ci
84195972f6Sopenharmony_ci  for (i = 0; i < NUM_SOCKETS; i++) {
85195972f6Sopenharmony_ci    s2[i] = lwip_socket(AF_INET, SOCK_STREAM, 0);
86195972f6Sopenharmony_ci    fail_unless(s2[i] >= 0);
87195972f6Sopenharmony_ci  }
88195972f6Sopenharmony_ci
89195972f6Sopenharmony_ci  /* all sockets used, now it should fail */
90195972f6Sopenharmony_ci  s = lwip_socket(AF_INET, SOCK_STREAM, 0);
91195972f6Sopenharmony_ci  fail_unless(s == -1);
92195972f6Sopenharmony_ci  /* close one socket */
93195972f6Sopenharmony_ci  ret = lwip_close(s2[0]);
94195972f6Sopenharmony_ci  fail_unless(ret == 0);
95195972f6Sopenharmony_ci  /* now it should succeed */
96195972f6Sopenharmony_ci  s2[0] = lwip_socket(AF_INET, SOCK_STREAM, 0);
97195972f6Sopenharmony_ci  fail_unless(s2[0] >= 0);
98195972f6Sopenharmony_ci
99195972f6Sopenharmony_ci  /* close all sockets */
100195972f6Sopenharmony_ci  for (i = 0; i < NUM_SOCKETS; i++) {
101195972f6Sopenharmony_ci    ret = lwip_close(s2[i]);
102195972f6Sopenharmony_ci    fail_unless(ret == 0);
103195972f6Sopenharmony_ci  }
104195972f6Sopenharmony_ci}
105195972f6Sopenharmony_ciEND_TEST
106195972f6Sopenharmony_ci
107195972f6Sopenharmony_cistatic void test_sockets_allfunctions_basic_domain(int domain)
108195972f6Sopenharmony_ci{
109195972f6Sopenharmony_ci  int s, s2, s3, ret;
110195972f6Sopenharmony_ci  struct sockaddr_storage addr, addr2;
111195972f6Sopenharmony_ci  socklen_t addrlen, addr2len;
112195972f6Sopenharmony_ci  char buf[4];
113195972f6Sopenharmony_ci  /* listen socket */
114195972f6Sopenharmony_ci  s = lwip_socket(domain, SOCK_STREAM, 0);
115195972f6Sopenharmony_ci  fail_unless(s >= 0);
116195972f6Sopenharmony_ci
117195972f6Sopenharmony_ci  ret = lwip_listen(s, 0);
118195972f6Sopenharmony_ci  fail_unless(ret == 0);
119195972f6Sopenharmony_ci
120195972f6Sopenharmony_ci  addrlen = sizeof(addr);
121195972f6Sopenharmony_ci  ret = lwip_getsockname(s, (struct sockaddr*)&addr, &addrlen);
122195972f6Sopenharmony_ci  fail_unless(ret == 0);
123195972f6Sopenharmony_ci
124195972f6Sopenharmony_ci  s2 = test_sockets_alloc_socket_nonblocking(domain, SOCK_STREAM);
125195972f6Sopenharmony_ci  fail_unless(s2 >= 0);
126195972f6Sopenharmony_ci  /* nonblocking connect s2 to s (but use loopback address) */
127195972f6Sopenharmony_ci  if (domain == AF_INET) {
128195972f6Sopenharmony_ci#if LWIP_IPV4
129195972f6Sopenharmony_ci    struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;
130195972f6Sopenharmony_ci    addr4->sin_addr.s_addr = PP_HTONL(INADDR_LOOPBACK);
131195972f6Sopenharmony_ci#endif
132195972f6Sopenharmony_ci  } else {
133195972f6Sopenharmony_ci#if LWIP_IPV6
134195972f6Sopenharmony_ci    struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
135195972f6Sopenharmony_ci    struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT;
136195972f6Sopenharmony_ci    addr6->sin6_addr = lo6;
137195972f6Sopenharmony_ci#endif
138195972f6Sopenharmony_ci  }
139195972f6Sopenharmony_ci  ret = lwip_connect(s2, (struct sockaddr*)&addr, addrlen);
140195972f6Sopenharmony_ci  fail_unless(ret == -1);
141195972f6Sopenharmony_ci  fail_unless(errno == EINPROGRESS);
142195972f6Sopenharmony_ci  ret = lwip_connect(s2, (struct sockaddr*)&addr, addrlen);
143195972f6Sopenharmony_ci  fail_unless(ret == -1);
144195972f6Sopenharmony_ci  fail_unless(errno == EALREADY);
145195972f6Sopenharmony_ci
146195972f6Sopenharmony_ci  while(tcpip_thread_poll_one());
147195972f6Sopenharmony_ci
148195972f6Sopenharmony_ci  s3 = lwip_accept(s, (struct sockaddr*)&addr2, &addr2len);
149195972f6Sopenharmony_ci  fail_unless(s3 >= 0);
150195972f6Sopenharmony_ci
151195972f6Sopenharmony_ci  ret = lwip_connect(s2, (struct sockaddr*)&addr, addrlen);
152195972f6Sopenharmony_ci  fail_unless(ret == -1);
153195972f6Sopenharmony_ci  fail_unless(errno == EISCONN);
154195972f6Sopenharmony_ci
155195972f6Sopenharmony_ci  /* write from server to client */
156195972f6Sopenharmony_ci  ret = write(s3, "test", 4);
157195972f6Sopenharmony_ci  fail_unless(ret == 4);
158195972f6Sopenharmony_ci
159195972f6Sopenharmony_ci  ret = lwip_shutdown(s3, SHUT_WR);
160195972f6Sopenharmony_ci  fail_unless(ret == 0);
161195972f6Sopenharmony_ci
162195972f6Sopenharmony_ci  while(tcpip_thread_poll_one());
163195972f6Sopenharmony_ci
164195972f6Sopenharmony_ci  ret = lwip_recv(s2, buf, 3, MSG_PEEK);
165195972f6Sopenharmony_ci  fail_unless(ret == 3);
166195972f6Sopenharmony_ci
167195972f6Sopenharmony_ci  ret = lwip_recv(s2, buf, 3, MSG_PEEK);
168195972f6Sopenharmony_ci  fail_unless(ret == 3);
169195972f6Sopenharmony_ci
170195972f6Sopenharmony_ci  ret = lwip_read(s2, buf, 4);
171195972f6Sopenharmony_ci  fail_unless(ret == 4);
172195972f6Sopenharmony_ci
173195972f6Sopenharmony_ci  ret = lwip_read(s2, buf, 1);
174195972f6Sopenharmony_ci  fail_unless(ret == 0);
175195972f6Sopenharmony_ci
176195972f6Sopenharmony_ci  ret = lwip_read(s2, buf, 1);
177195972f6Sopenharmony_ci  fail_unless(ret == -1);
178195972f6Sopenharmony_ci
179195972f6Sopenharmony_ci  ret = lwip_write(s2, "foo", 3);
180195972f6Sopenharmony_ci  fail_unless(ret == 3);
181195972f6Sopenharmony_ci
182195972f6Sopenharmony_ci  ret = lwip_close(s2);
183195972f6Sopenharmony_ci  fail_unless(ret == 0);
184195972f6Sopenharmony_ci
185195972f6Sopenharmony_ci  while(tcpip_thread_poll_one());
186195972f6Sopenharmony_ci
187195972f6Sopenharmony_ci  /* read one byte more than available to check handling FIN */
188195972f6Sopenharmony_ci  ret = lwip_read(s3, buf, 4);
189195972f6Sopenharmony_ci  fail_unless(ret == 3);
190195972f6Sopenharmony_ci
191195972f6Sopenharmony_ci  ret = lwip_read(s3, buf, 1);
192195972f6Sopenharmony_ci  fail_unless(ret == 0);
193195972f6Sopenharmony_ci
194195972f6Sopenharmony_ci  ret = lwip_read(s3, buf, 1);
195195972f6Sopenharmony_ci  fail_unless(ret == -1);
196195972f6Sopenharmony_ci
197195972f6Sopenharmony_ci  while(tcpip_thread_poll_one());
198195972f6Sopenharmony_ci
199195972f6Sopenharmony_ci  ret = lwip_close(s);
200195972f6Sopenharmony_ci  fail_unless(ret == 0);
201195972f6Sopenharmony_ci  ret = lwip_close(s3);
202195972f6Sopenharmony_ci  fail_unless(ret == 0);
203195972f6Sopenharmony_ci}
204195972f6Sopenharmony_ci
205195972f6Sopenharmony_ci/* Try to step through all sockets functions once...
206195972f6Sopenharmony_ci */
207195972f6Sopenharmony_ciSTART_TEST(test_sockets_allfunctions_basic)
208195972f6Sopenharmony_ci{
209195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(_i);
210195972f6Sopenharmony_ci#if LWIP_IPV4
211195972f6Sopenharmony_ci  test_sockets_allfunctions_basic_domain(AF_INET);
212195972f6Sopenharmony_ci#endif
213195972f6Sopenharmony_ci#if LWIP_IPV6
214195972f6Sopenharmony_ci  test_sockets_allfunctions_basic_domain(AF_INET6);
215195972f6Sopenharmony_ci#endif
216195972f6Sopenharmony_ci}
217195972f6Sopenharmony_ciEND_TEST
218195972f6Sopenharmony_ci
219195972f6Sopenharmony_cistatic void test_sockets_init_loopback_addr(int domain, struct sockaddr_storage *addr_st, socklen_t *sz)
220195972f6Sopenharmony_ci{
221195972f6Sopenharmony_ci  memset(addr_st, 0, sizeof(*addr_st));
222195972f6Sopenharmony_ci  switch(domain) {
223195972f6Sopenharmony_ci#if LWIP_IPV6
224195972f6Sopenharmony_ci    case AF_INET6: {
225195972f6Sopenharmony_ci      struct sockaddr_in6 *addr = (struct sockaddr_in6*)addr_st;
226195972f6Sopenharmony_ci      struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT;
227195972f6Sopenharmony_ci      addr->sin6_family = AF_INET6;
228195972f6Sopenharmony_ci      addr->sin6_port = 0; /* use ephemeral port */
229195972f6Sopenharmony_ci      addr->sin6_addr = lo6;
230195972f6Sopenharmony_ci      *sz = sizeof(*addr);
231195972f6Sopenharmony_ci   }
232195972f6Sopenharmony_ci      break;
233195972f6Sopenharmony_ci#endif /* LWIP_IPV6 */
234195972f6Sopenharmony_ci#if LWIP_IPV4
235195972f6Sopenharmony_ci    case AF_INET: {
236195972f6Sopenharmony_ci      struct sockaddr_in *addr = (struct sockaddr_in*)addr_st;
237195972f6Sopenharmony_ci      addr->sin_family = AF_INET;
238195972f6Sopenharmony_ci      addr->sin_port = 0; /* use ephemeral port */
239195972f6Sopenharmony_ci      addr->sin_addr.s_addr = PP_HTONL(INADDR_LOOPBACK);
240195972f6Sopenharmony_ci      *sz = sizeof(*addr);
241195972f6Sopenharmony_ci    }
242195972f6Sopenharmony_ci      break;
243195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */
244195972f6Sopenharmony_ci    default:
245195972f6Sopenharmony_ci      *sz = 0;
246195972f6Sopenharmony_ci      fail();
247195972f6Sopenharmony_ci      break;
248195972f6Sopenharmony_ci  }
249195972f6Sopenharmony_ci}
250195972f6Sopenharmony_ci
251195972f6Sopenharmony_cistatic void test_sockets_msgapi_update_iovs(struct msghdr *msg, size_t bytes)
252195972f6Sopenharmony_ci{
253195972f6Sopenharmony_ci  int i;
254195972f6Sopenharmony_ci
255195972f6Sopenharmony_ci  /* note: this modifies the underyling iov_base and iov_len for a partial
256195972f6Sopenharmony_ci     read for an individual vector. This updates the msg->msg_iov pointer
257195972f6Sopenharmony_ci     to skip fully consumed vecotrs */
258195972f6Sopenharmony_ci
259195972f6Sopenharmony_ci  /* process fully consumed vectors */
260195972f6Sopenharmony_ci  for (i = 0; i < msg->msg_iovlen; i++) {
261195972f6Sopenharmony_ci    if (msg->msg_iov[i].iov_len <= bytes) {
262195972f6Sopenharmony_ci      /* reduce bytes by amount of this vector */
263195972f6Sopenharmony_ci      bytes -= msg->msg_iov[i].iov_len;
264195972f6Sopenharmony_ci    } else {
265195972f6Sopenharmony_ci      break; /* iov not fully consumed */
266195972f6Sopenharmony_ci    }
267195972f6Sopenharmony_ci  }
268195972f6Sopenharmony_ci
269195972f6Sopenharmony_ci  /* slide down over fully consumed vectors */
270195972f6Sopenharmony_ci  msg->msg_iov = &msg->msg_iov[i];
271195972f6Sopenharmony_ci  msg->msg_iovlen -= i;
272195972f6Sopenharmony_ci
273195972f6Sopenharmony_ci  /* update new first vector with any remaining amount */
274195972f6Sopenharmony_ci  msg->msg_iov[0].iov_base = ((u8_t *)msg->msg_iov[0].iov_base + bytes);
275195972f6Sopenharmony_ci  msg->msg_iov[0].iov_len -= bytes;
276195972f6Sopenharmony_ci}
277195972f6Sopenharmony_ci
278195972f6Sopenharmony_cistatic void test_sockets_msgapi_tcp(int domain)
279195972f6Sopenharmony_ci{
280195972f6Sopenharmony_ci  #define BUF_SZ          (TCP_SND_BUF/4)
281195972f6Sopenharmony_ci  #define TOTAL_DATA_SZ   (BUF_SZ*8) /* ~(TCP_SND_BUF*2) that accounts for integer rounding */
282195972f6Sopenharmony_ci  #define NEED_TRAILER    (BUF_SZ % 4 != 0)
283195972f6Sopenharmony_ci  int listnr, s1, s2, i, ret, opt;
284195972f6Sopenharmony_ci  int bytes_written, bytes_read;
285195972f6Sopenharmony_ci  struct sockaddr_storage addr_storage;
286195972f6Sopenharmony_ci  socklen_t addr_size;
287195972f6Sopenharmony_ci  struct iovec siovs[8];
288195972f6Sopenharmony_ci  struct msghdr smsg;
289195972f6Sopenharmony_ci  u8_t * snd_buf;
290195972f6Sopenharmony_ci  struct iovec riovs[5];
291195972f6Sopenharmony_ci  struct iovec riovs_tmp[5];
292195972f6Sopenharmony_ci  struct msghdr rmsg;
293195972f6Sopenharmony_ci  u8_t * rcv_buf;
294195972f6Sopenharmony_ci  int    rcv_off;
295195972f6Sopenharmony_ci  int    rcv_trailer = 0;
296195972f6Sopenharmony_ci  u8_t val;
297195972f6Sopenharmony_ci
298195972f6Sopenharmony_ci  test_sockets_init_loopback_addr(domain, &addr_storage, &addr_size);
299195972f6Sopenharmony_ci
300195972f6Sopenharmony_ci  listnr = test_sockets_alloc_socket_nonblocking(domain, SOCK_STREAM);
301195972f6Sopenharmony_ci  fail_unless(listnr >= 0);
302195972f6Sopenharmony_ci  s1 = test_sockets_alloc_socket_nonblocking(domain, SOCK_STREAM);
303195972f6Sopenharmony_ci  fail_unless(s1 >= 0);
304195972f6Sopenharmony_ci
305195972f6Sopenharmony_ci  /* setup a listener socket on loopback with ephemeral port */
306195972f6Sopenharmony_ci  ret = lwip_bind(listnr, (struct sockaddr*)&addr_storage, addr_size);
307195972f6Sopenharmony_ci  fail_unless(ret == 0);
308195972f6Sopenharmony_ci  ret = lwip_listen(listnr, 0);
309195972f6Sopenharmony_ci  fail_unless(ret == 0);
310195972f6Sopenharmony_ci
311195972f6Sopenharmony_ci  /* update address with ephemeral port */
312195972f6Sopenharmony_ci  ret = lwip_getsockname(listnr, (struct sockaddr*)&addr_storage, &addr_size);
313195972f6Sopenharmony_ci  fail_unless(ret == 0);
314195972f6Sopenharmony_ci
315195972f6Sopenharmony_ci  /* connect, won't complete until we accept it */
316195972f6Sopenharmony_ci  ret = lwip_connect(s1, (struct sockaddr*)&addr_storage, addr_size);
317195972f6Sopenharmony_ci  fail_unless(ret == -1);
318195972f6Sopenharmony_ci  fail_unless(errno == EINPROGRESS);
319195972f6Sopenharmony_ci
320195972f6Sopenharmony_ci  while (tcpip_thread_poll_one());
321195972f6Sopenharmony_ci
322195972f6Sopenharmony_ci  /* accept, creating the other side of the connection */
323195972f6Sopenharmony_ci  s2 = lwip_accept(listnr, NULL, NULL);
324195972f6Sopenharmony_ci  fail_unless(s2 >= 0);
325195972f6Sopenharmony_ci
326195972f6Sopenharmony_ci  /* double check s1 is connected */
327195972f6Sopenharmony_ci  ret = lwip_connect(s1, (struct sockaddr*)&addr_storage, addr_size);
328195972f6Sopenharmony_ci  fail_unless(ret == -1);
329195972f6Sopenharmony_ci  fail_unless(errno == EISCONN);
330195972f6Sopenharmony_ci
331195972f6Sopenharmony_ci  /* set s2 to non-blocking, not inherited from listener */
332195972f6Sopenharmony_ci  opt = lwip_fcntl(s2, F_GETFL, 0);
333195972f6Sopenharmony_ci  fail_unless(opt == 6);
334195972f6Sopenharmony_ci  opt = O_NONBLOCK;
335195972f6Sopenharmony_ci  ret = lwip_fcntl(s2, F_SETFL, opt);
336195972f6Sopenharmony_ci  fail_unless(ret == 0);
337195972f6Sopenharmony_ci
338195972f6Sopenharmony_ci  /* we are done with listener, close it */
339195972f6Sopenharmony_ci  ret = lwip_close(listnr);
340195972f6Sopenharmony_ci  fail_unless(ret == 0);
341195972f6Sopenharmony_ci
342195972f6Sopenharmony_ci  /* allocate a buffer for a stream of incrementing hex (0x00..0xFF) which we will use
343195972f6Sopenharmony_ci     to create an input vector set that is larger than the TCP's send buffer. This will
344195972f6Sopenharmony_ci     force execution of the partial IO vector send case */
345195972f6Sopenharmony_ci  snd_buf = (u8_t*)mem_malloc(BUF_SZ);
346195972f6Sopenharmony_ci  val = 0x00;
347195972f6Sopenharmony_ci  fail_unless(snd_buf != NULL);
348195972f6Sopenharmony_ci  for (i = 0; i < BUF_SZ; i++,val++) {
349195972f6Sopenharmony_ci    snd_buf[i] = val;
350195972f6Sopenharmony_ci  }
351195972f6Sopenharmony_ci
352195972f6Sopenharmony_ci  /* send the buffer 8 times in one message, equating to TOTAL_DATA_SZ */
353195972f6Sopenharmony_ci  for (i = 0; i < 8; i++) {
354195972f6Sopenharmony_ci    siovs[i].iov_base = snd_buf;
355195972f6Sopenharmony_ci    siovs[i].iov_len = BUF_SZ;
356195972f6Sopenharmony_ci  }
357195972f6Sopenharmony_ci
358195972f6Sopenharmony_ci  /* allocate a receive buffer, same size as snd_buf for easy verification */
359195972f6Sopenharmony_ci  rcv_buf = (u8_t*)mem_calloc(1, BUF_SZ);
360195972f6Sopenharmony_ci  fail_unless(rcv_buf != NULL);
361195972f6Sopenharmony_ci  /* split across iovs */
362195972f6Sopenharmony_ci  for (i = 0; i < 4; i++) {
363195972f6Sopenharmony_ci    riovs[i].iov_base = &rcv_buf[i*(BUF_SZ/4)];
364195972f6Sopenharmony_ci    riovs[i].iov_len = BUF_SZ/4;
365195972f6Sopenharmony_ci  }
366195972f6Sopenharmony_ci  /* handling trailing bytes if buffer doesn't evenly divide by 4 */
367195972f6Sopenharmony_ci#if NEED_TRAILER
368195972f6Sopenharmony_ci  if ((BUF_SZ % 4) != 0) {
369195972f6Sopenharmony_ci    riovs[5].iov_base = &rcv_buf[4*(BUF_SZ/4)];
370195972f6Sopenharmony_ci    riovs[5].iov_len = BUF_SZ - (4*(BUF_SZ/4));
371195972f6Sopenharmony_ci    rcv_trailer = 1;
372195972f6Sopenharmony_ci  }
373195972f6Sopenharmony_ci#endif /* NEED_TRAILER */
374195972f6Sopenharmony_ci
375195972f6Sopenharmony_ci  /* we use a copy of riovs since we'll be modifying base and len during
376195972f6Sopenharmony_ci     receiving. This gives us an easy way to reset the iovs for next recvmsg */
377195972f6Sopenharmony_ci  memcpy(riovs_tmp, riovs, sizeof(riovs));
378195972f6Sopenharmony_ci
379195972f6Sopenharmony_ci  memset(&smsg, 0, sizeof(smsg));
380195972f6Sopenharmony_ci  smsg.msg_iov = siovs;
381195972f6Sopenharmony_ci  smsg.msg_iovlen = 8;
382195972f6Sopenharmony_ci
383195972f6Sopenharmony_ci  memset(&rmsg, 0, sizeof(rmsg));
384195972f6Sopenharmony_ci  rmsg.msg_iov = riovs_tmp;
385195972f6Sopenharmony_ci  rmsg.msg_iovlen = (rcv_trailer ? 5 : 4);
386195972f6Sopenharmony_ci
387195972f6Sopenharmony_ci  bytes_written = 0;
388195972f6Sopenharmony_ci  bytes_read = 0;
389195972f6Sopenharmony_ci  rcv_off = 0;
390195972f6Sopenharmony_ci
391195972f6Sopenharmony_ci  while (bytes_written < TOTAL_DATA_SZ && (bytes_read < TOTAL_DATA_SZ)) {
392195972f6Sopenharmony_ci    /* send data */
393195972f6Sopenharmony_ci    if (bytes_written < TOTAL_DATA_SZ) {
394195972f6Sopenharmony_ci      ret = lwip_sendmsg(s1, &smsg, 0);
395195972f6Sopenharmony_ci      /* note: since we always receive after sending, there will be open
396195972f6Sopenharmony_ci         space in the send buffer */
397195972f6Sopenharmony_ci      fail_unless(ret > 0);
398195972f6Sopenharmony_ci
399195972f6Sopenharmony_ci      bytes_written += ret;
400195972f6Sopenharmony_ci      if (bytes_written < TOTAL_DATA_SZ) {
401195972f6Sopenharmony_ci        test_sockets_msgapi_update_iovs(&smsg, (size_t)ret);
402195972f6Sopenharmony_ci      }
403195972f6Sopenharmony_ci    }
404195972f6Sopenharmony_ci
405195972f6Sopenharmony_ci    while (tcpip_thread_poll_one());
406195972f6Sopenharmony_ci
407195972f6Sopenharmony_ci    /* receive and verify data */
408195972f6Sopenharmony_ci    do {
409195972f6Sopenharmony_ci      if (bytes_read < TOTAL_DATA_SZ) {
410195972f6Sopenharmony_ci        ret = lwip_recvmsg(s2, &rmsg, 0);
411195972f6Sopenharmony_ci        fail_unless(ret > 0 || (ret == -1 && errno == EWOULDBLOCK));
412195972f6Sopenharmony_ci
413195972f6Sopenharmony_ci        if (ret > 0) {
414195972f6Sopenharmony_ci          rcv_off += ret;
415195972f6Sopenharmony_ci          /* we have received a full buffer */
416195972f6Sopenharmony_ci          if (rcv_off == BUF_SZ) {
417195972f6Sopenharmony_ci            /* note: since iovs are just pointers, compare underlying buf */
418195972f6Sopenharmony_ci            fail_unless(!memcmp(snd_buf, rcv_buf, BUF_SZ));
419195972f6Sopenharmony_ci            bytes_read += BUF_SZ;
420195972f6Sopenharmony_ci            /* reset receive state for next buffer */
421195972f6Sopenharmony_ci            rcv_off = 0;
422195972f6Sopenharmony_ci            memset(rcv_buf, 0, BUF_SZ);
423195972f6Sopenharmony_ci            memcpy(riovs_tmp, riovs, sizeof(riovs));
424195972f6Sopenharmony_ci            rmsg.msg_iov = riovs_tmp;
425195972f6Sopenharmony_ci            rmsg.msg_iovlen = (rcv_trailer ? 5 : 4);
426195972f6Sopenharmony_ci          } else { /* partial read */
427195972f6Sopenharmony_ci            test_sockets_msgapi_update_iovs(&rmsg, (size_t)ret);
428195972f6Sopenharmony_ci          }
429195972f6Sopenharmony_ci        }
430195972f6Sopenharmony_ci      } else {
431195972f6Sopenharmony_ci        break;
432195972f6Sopenharmony_ci      }
433195972f6Sopenharmony_ci    } while(ret > 0);
434195972f6Sopenharmony_ci  }
435195972f6Sopenharmony_ci
436195972f6Sopenharmony_ci  ret = lwip_close(s1);
437195972f6Sopenharmony_ci  fail_unless(ret == 0);
438195972f6Sopenharmony_ci  ret = lwip_close(s2);
439195972f6Sopenharmony_ci  fail_unless(ret == 0);
440195972f6Sopenharmony_ci  mem_free(snd_buf);
441195972f6Sopenharmony_ci  mem_free(rcv_buf);
442195972f6Sopenharmony_ci}
443195972f6Sopenharmony_ci
444195972f6Sopenharmony_cistatic void test_sockets_msgapi_udp_send_recv_loop(int s, struct msghdr *smsg, struct msghdr *rmsg)
445195972f6Sopenharmony_ci{
446195972f6Sopenharmony_ci  int i, ret;
447195972f6Sopenharmony_ci
448195972f6Sopenharmony_ci  /* send/receive our datagram of IO vectors 10 times */
449195972f6Sopenharmony_ci  for (i = 0; i < 10; i++) {
450195972f6Sopenharmony_ci    ret = lwip_sendmsg(s, smsg, 0);
451195972f6Sopenharmony_ci    fail_unless(ret == 4);
452195972f6Sopenharmony_ci
453195972f6Sopenharmony_ci    while (tcpip_thread_poll_one());
454195972f6Sopenharmony_ci
455195972f6Sopenharmony_ci    /* receive the datagram split across 4 buffers */
456195972f6Sopenharmony_ci    ret = lwip_recvmsg(s, rmsg, 0);
457195972f6Sopenharmony_ci    fail_unless(ret == 4);
458195972f6Sopenharmony_ci
459195972f6Sopenharmony_ci    /* verify data */
460195972f6Sopenharmony_ci    fail_unless(*((u8_t*)rmsg->msg_iov[0].iov_base) == 0xDE);
461195972f6Sopenharmony_ci    fail_unless(*((u8_t*)rmsg->msg_iov[1].iov_base) == 0xAD);
462195972f6Sopenharmony_ci    fail_unless(*((u8_t*)rmsg->msg_iov[2].iov_base) == 0xBE);
463195972f6Sopenharmony_ci    fail_unless(*((u8_t*)rmsg->msg_iov[3].iov_base) == 0xEF);
464195972f6Sopenharmony_ci
465195972f6Sopenharmony_ci    /* clear rcv_buf to ensure no data is being skipped */
466195972f6Sopenharmony_ci    *((u8_t*)rmsg->msg_iov[0].iov_base) = 0x00;
467195972f6Sopenharmony_ci    *((u8_t*)rmsg->msg_iov[1].iov_base) = 0x00;
468195972f6Sopenharmony_ci    *((u8_t*)rmsg->msg_iov[2].iov_base) = 0x00;
469195972f6Sopenharmony_ci    *((u8_t*)rmsg->msg_iov[3].iov_base) = 0x00;
470195972f6Sopenharmony_ci  }
471195972f6Sopenharmony_ci}
472195972f6Sopenharmony_ci
473195972f6Sopenharmony_cistatic void test_sockets_msgapi_udp(int domain)
474195972f6Sopenharmony_ci{
475195972f6Sopenharmony_ci  int s, i, ret;
476195972f6Sopenharmony_ci  struct sockaddr_storage addr_storage;
477195972f6Sopenharmony_ci  socklen_t addr_size;
478195972f6Sopenharmony_ci  struct iovec riovs[4];
479195972f6Sopenharmony_ci  struct msghdr rmsg;
480195972f6Sopenharmony_ci  u8_t rcv_buf[4];
481195972f6Sopenharmony_ci  struct iovec siovs[4];
482195972f6Sopenharmony_ci  struct msghdr smsg;
483195972f6Sopenharmony_ci  u8_t snd_buf[4] = {0xDE, 0xAD, 0xBE, 0xEF};
484195972f6Sopenharmony_ci
485195972f6Sopenharmony_ci  /* initialize IO vectors with data */
486195972f6Sopenharmony_ci  for (i = 0; i < 4; i++) {
487195972f6Sopenharmony_ci    siovs[i].iov_base = &snd_buf[i];
488195972f6Sopenharmony_ci    siovs[i].iov_len = sizeof(u8_t);
489195972f6Sopenharmony_ci    riovs[i].iov_base = &rcv_buf[i];
490195972f6Sopenharmony_ci    riovs[i].iov_len = sizeof(u8_t);
491195972f6Sopenharmony_ci  }
492195972f6Sopenharmony_ci
493195972f6Sopenharmony_ci  test_sockets_init_loopback_addr(domain, &addr_storage, &addr_size);
494195972f6Sopenharmony_ci
495195972f6Sopenharmony_ci  s = test_sockets_alloc_socket_nonblocking(domain, SOCK_DGRAM);
496195972f6Sopenharmony_ci  fail_unless(s >= 0);
497195972f6Sopenharmony_ci
498195972f6Sopenharmony_ci  ret = lwip_bind(s, (struct sockaddr*)&addr_storage, addr_size);
499195972f6Sopenharmony_ci  fail_unless(ret == 0);
500195972f6Sopenharmony_ci
501195972f6Sopenharmony_ci  /* Update addr with epehermal port */
502195972f6Sopenharmony_ci  ret = lwip_getsockname(s, (struct sockaddr*)&addr_storage, &addr_size);
503195972f6Sopenharmony_ci  fail_unless(ret == 0);
504195972f6Sopenharmony_ci  switch(domain) {
505195972f6Sopenharmony_ci#if LWIP_IPV6
506195972f6Sopenharmony_ci    case AF_INET6:
507195972f6Sopenharmony_ci      fail_unless(addr_size == sizeof(struct sockaddr_in6));
508195972f6Sopenharmony_ci      break;
509195972f6Sopenharmony_ci#endif /* LWIP_IPV6 */
510195972f6Sopenharmony_ci#if LWIP_IPV4
511195972f6Sopenharmony_ci    case AF_INET:
512195972f6Sopenharmony_ci        fail_unless(addr_size == sizeof(struct sockaddr_in));
513195972f6Sopenharmony_ci        break;
514195972f6Sopenharmony_ci#endif /* LWIP_IPV6 */
515195972f6Sopenharmony_ci    default:
516195972f6Sopenharmony_ci      fail();
517195972f6Sopenharmony_ci      break;
518195972f6Sopenharmony_ci  }
519195972f6Sopenharmony_ci
520195972f6Sopenharmony_ci  /* send and receive the datagram in 4 pieces */
521195972f6Sopenharmony_ci  memset(&smsg, 0, sizeof(smsg));
522195972f6Sopenharmony_ci  smsg.msg_iov = siovs;
523195972f6Sopenharmony_ci  smsg.msg_iovlen = 4;
524195972f6Sopenharmony_ci  memset(&rmsg, 0, sizeof(rmsg));
525195972f6Sopenharmony_ci  rmsg.msg_iov = riovs;
526195972f6Sopenharmony_ci  rmsg.msg_iovlen = 4;
527195972f6Sopenharmony_ci
528195972f6Sopenharmony_ci  /* perform a sendmsg with remote host (self) */
529195972f6Sopenharmony_ci  smsg.msg_name = &addr_storage;
530195972f6Sopenharmony_ci  smsg.msg_namelen = addr_size;
531195972f6Sopenharmony_ci
532195972f6Sopenharmony_ci  test_sockets_msgapi_udp_send_recv_loop(s, &smsg, &rmsg);
533195972f6Sopenharmony_ci
534195972f6Sopenharmony_ci  /* Connect to self, allowing us to not pass message name */
535195972f6Sopenharmony_ci  ret = lwip_connect(s, (struct sockaddr*)&addr_storage, addr_size);
536195972f6Sopenharmony_ci  fail_unless(ret == 0);
537195972f6Sopenharmony_ci
538195972f6Sopenharmony_ci  smsg.msg_name = NULL;
539195972f6Sopenharmony_ci  smsg.msg_namelen = 0;
540195972f6Sopenharmony_ci
541195972f6Sopenharmony_ci  test_sockets_msgapi_udp_send_recv_loop(s, &smsg, &rmsg);
542195972f6Sopenharmony_ci
543195972f6Sopenharmony_ci  ret = lwip_close(s);
544195972f6Sopenharmony_ci  fail_unless(ret == 0);
545195972f6Sopenharmony_ci}
546195972f6Sopenharmony_ci
547195972f6Sopenharmony_ci#if LWIP_IPV4
548195972f6Sopenharmony_cistatic void test_sockets_msgapi_cmsg(int domain)
549195972f6Sopenharmony_ci{
550195972f6Sopenharmony_ci  int s, ret, enable;
551195972f6Sopenharmony_ci  struct sockaddr_storage addr_storage;
552195972f6Sopenharmony_ci  socklen_t addr_size;
553195972f6Sopenharmony_ci  struct iovec iov;
554195972f6Sopenharmony_ci  struct msghdr msg;
555195972f6Sopenharmony_ci  struct cmsghdr *cmsg;
556195972f6Sopenharmony_ci  struct in_pktinfo *pktinfo;
557195972f6Sopenharmony_ci  u8_t rcv_buf[4];
558195972f6Sopenharmony_ci  u8_t snd_buf[4] = {0xDE, 0xAD, 0xBE, 0xEF};
559195972f6Sopenharmony_ci  u8_t cmsg_buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
560195972f6Sopenharmony_ci
561195972f6Sopenharmony_ci  test_sockets_init_loopback_addr(domain, &addr_storage, &addr_size);
562195972f6Sopenharmony_ci
563195972f6Sopenharmony_ci  s = test_sockets_alloc_socket_nonblocking(domain, SOCK_DGRAM);
564195972f6Sopenharmony_ci  fail_unless(s >= 0);
565195972f6Sopenharmony_ci
566195972f6Sopenharmony_ci  ret = lwip_bind(s, (struct sockaddr*)&addr_storage, addr_size);
567195972f6Sopenharmony_ci  fail_unless(ret == 0);
568195972f6Sopenharmony_ci
569195972f6Sopenharmony_ci  /* Update addr with epehermal port */
570195972f6Sopenharmony_ci  ret = lwip_getsockname(s, (struct sockaddr*)&addr_storage, &addr_size);
571195972f6Sopenharmony_ci  fail_unless(ret == 0);
572195972f6Sopenharmony_ci
573195972f6Sopenharmony_ci  enable = 1;
574195972f6Sopenharmony_ci  ret = lwip_setsockopt(s, IPPROTO_IP, IP_PKTINFO, &enable, sizeof(enable));
575195972f6Sopenharmony_ci  fail_unless(ret == 0);
576195972f6Sopenharmony_ci
577195972f6Sopenharmony_ci  /* Receive full message, including control message */
578195972f6Sopenharmony_ci  iov.iov_base = rcv_buf;
579195972f6Sopenharmony_ci  iov.iov_len = sizeof(rcv_buf);
580195972f6Sopenharmony_ci  msg.msg_control = cmsg_buf;
581195972f6Sopenharmony_ci  msg.msg_controllen = sizeof(cmsg_buf);
582195972f6Sopenharmony_ci  msg.msg_flags = 0;
583195972f6Sopenharmony_ci  msg.msg_iov = &iov;
584195972f6Sopenharmony_ci  msg.msg_iovlen = 1;
585195972f6Sopenharmony_ci  msg.msg_name = NULL;
586195972f6Sopenharmony_ci  msg.msg_namelen = 0;
587195972f6Sopenharmony_ci
588195972f6Sopenharmony_ci  memset(rcv_buf, 0, sizeof(rcv_buf));
589195972f6Sopenharmony_ci  ret = lwip_sendto(s, snd_buf, sizeof(snd_buf), 0, (struct sockaddr*)&addr_storage, addr_size);
590195972f6Sopenharmony_ci  fail_unless(ret == sizeof(snd_buf));
591195972f6Sopenharmony_ci
592195972f6Sopenharmony_ci  tcpip_thread_poll_one();
593195972f6Sopenharmony_ci
594195972f6Sopenharmony_ci  ret = lwip_recvmsg(s, &msg, 0);
595195972f6Sopenharmony_ci  fail_unless(ret == sizeof(rcv_buf));
596195972f6Sopenharmony_ci  fail_unless(!memcmp(rcv_buf, snd_buf, sizeof(rcv_buf)));
597195972f6Sopenharmony_ci
598195972f6Sopenharmony_ci  /* Verify message header */
599195972f6Sopenharmony_ci  cmsg = CMSG_FIRSTHDR(&msg);
600195972f6Sopenharmony_ci  fail_unless(cmsg != NULL);
601195972f6Sopenharmony_ci  fail_unless(cmsg->cmsg_len > 0);
602195972f6Sopenharmony_ci  fail_unless(cmsg->cmsg_level == IPPROTO_IP);
603195972f6Sopenharmony_ci  fail_unless(cmsg->cmsg_type == IP_PKTINFO);
604195972f6Sopenharmony_ci
605195972f6Sopenharmony_ci  /* Verify message data */
606195972f6Sopenharmony_ci  pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
607195972f6Sopenharmony_ci  /* We only have loopback interface enabled */
608195972f6Sopenharmony_ci  fail_unless(pktinfo->ipi_ifindex == 1);
609195972f6Sopenharmony_ci  fail_unless(pktinfo->ipi_addr.s_addr == PP_HTONL(INADDR_LOOPBACK));
610195972f6Sopenharmony_ci
611195972f6Sopenharmony_ci  /* Verify there are no additional messages */
612195972f6Sopenharmony_ci  cmsg = CMSG_NXTHDR(&msg, cmsg);
613195972f6Sopenharmony_ci  fail_unless(cmsg == NULL);
614195972f6Sopenharmony_ci
615195972f6Sopenharmony_ci  /* Send datagram again, testing truncation */
616195972f6Sopenharmony_ci  memset(rcv_buf, 0, sizeof(rcv_buf));
617195972f6Sopenharmony_ci  ret = lwip_sendto(s, snd_buf, sizeof(snd_buf), 0, (struct sockaddr*)&addr_storage, addr_size);
618195972f6Sopenharmony_ci  fail_unless(ret == sizeof(snd_buf));
619195972f6Sopenharmony_ci
620195972f6Sopenharmony_ci  tcpip_thread_poll_one();
621195972f6Sopenharmony_ci
622195972f6Sopenharmony_ci  msg.msg_controllen = 1;
623195972f6Sopenharmony_ci  msg.msg_flags = 0;
624195972f6Sopenharmony_ci  ret = lwip_recvmsg(s, &msg, 0);
625195972f6Sopenharmony_ci  fail_unless(ret == sizeof(rcv_buf));
626195972f6Sopenharmony_ci  fail_unless(!memcmp(rcv_buf, snd_buf, sizeof(rcv_buf)));
627195972f6Sopenharmony_ci  /* Ensure truncation was returned */
628195972f6Sopenharmony_ci  fail_unless(msg.msg_flags & MSG_CTRUNC);
629195972f6Sopenharmony_ci  /* Ensure no control messages were returned */
630195972f6Sopenharmony_ci  fail_unless(msg.msg_controllen == 0);
631195972f6Sopenharmony_ci
632195972f6Sopenharmony_ci  ret = lwip_close(s);
633195972f6Sopenharmony_ci  fail_unless(ret == 0);
634195972f6Sopenharmony_ci}
635195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */
636195972f6Sopenharmony_ci
637195972f6Sopenharmony_ciSTART_TEST(test_sockets_msgapis)
638195972f6Sopenharmony_ci{
639195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(_i);
640195972f6Sopenharmony_ci#if LWIP_IPV4
641195972f6Sopenharmony_ci  test_sockets_msgapi_udp(AF_INET);
642195972f6Sopenharmony_ci  test_sockets_msgapi_tcp(AF_INET);
643195972f6Sopenharmony_ci  test_sockets_msgapi_cmsg(AF_INET);
644195972f6Sopenharmony_ci#endif
645195972f6Sopenharmony_ci#if LWIP_IPV6
646195972f6Sopenharmony_ci  test_sockets_msgapi_udp(AF_INET6);
647195972f6Sopenharmony_ci  test_sockets_msgapi_tcp(AF_INET6);
648195972f6Sopenharmony_ci#endif
649195972f6Sopenharmony_ci}
650195972f6Sopenharmony_ciEND_TEST
651195972f6Sopenharmony_ci
652195972f6Sopenharmony_ciSTART_TEST(test_sockets_select)
653195972f6Sopenharmony_ci{
654195972f6Sopenharmony_ci#if LWIP_SOCKET_SELECT
655195972f6Sopenharmony_ci  int s;
656195972f6Sopenharmony_ci  int ret;
657195972f6Sopenharmony_ci  fd_set readset;
658195972f6Sopenharmony_ci  fd_set writeset;
659195972f6Sopenharmony_ci  fd_set errset;
660195972f6Sopenharmony_ci  struct timeval tv;
661195972f6Sopenharmony_ci
662195972f6Sopenharmony_ci  fail_unless(test_sockets_get_used_count() == 0);
663195972f6Sopenharmony_ci
664195972f6Sopenharmony_ci  s = lwip_socket(AF_INET, SOCK_STREAM, 0);
665195972f6Sopenharmony_ci  fail_unless(s >= 0);
666195972f6Sopenharmony_ci  fail_unless(test_sockets_get_used_count() == 0);
667195972f6Sopenharmony_ci
668195972f6Sopenharmony_ci  FD_ZERO(&readset);
669195972f6Sopenharmony_ci  FD_SET(s, &readset);
670195972f6Sopenharmony_ci  FD_ZERO(&writeset);
671195972f6Sopenharmony_ci  FD_SET(s, &writeset);
672195972f6Sopenharmony_ci  FD_ZERO(&errset);
673195972f6Sopenharmony_ci  FD_SET(s, &errset);
674195972f6Sopenharmony_ci
675195972f6Sopenharmony_ci  tv.tv_sec = tv.tv_usec = 0;
676195972f6Sopenharmony_ci  ret = lwip_select(s + 1, &readset, &writeset, &errset, &tv);
677195972f6Sopenharmony_ci  fail_unless(ret == 0);
678195972f6Sopenharmony_ci  fail_unless(test_sockets_get_used_count() == 0);
679195972f6Sopenharmony_ci
680195972f6Sopenharmony_ci  ret = lwip_close(s);
681195972f6Sopenharmony_ci  fail_unless(ret == 0);
682195972f6Sopenharmony_ci
683195972f6Sopenharmony_ci#endif
684195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(_i);
685195972f6Sopenharmony_ci}
686195972f6Sopenharmony_ciEND_TEST
687195972f6Sopenharmony_ci
688195972f6Sopenharmony_ciSTART_TEST(test_sockets_recv_after_rst)
689195972f6Sopenharmony_ci{
690195972f6Sopenharmony_ci  int sl, sact;
691195972f6Sopenharmony_ci  int spass = -1;
692195972f6Sopenharmony_ci  int ret;
693195972f6Sopenharmony_ci  struct sockaddr_in sa_listen;
694195972f6Sopenharmony_ci  const u16_t port = 1234;
695195972f6Sopenharmony_ci  int arg;
696195972f6Sopenharmony_ci  const char txbuf[] = "something";
697195972f6Sopenharmony_ci  char rxbuf[16];
698195972f6Sopenharmony_ci  struct lwip_sock *sact_sock;
699195972f6Sopenharmony_ci  int err;
700195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(_i);
701195972f6Sopenharmony_ci
702195972f6Sopenharmony_ci  fail_unless(test_sockets_get_used_count() == 0);
703195972f6Sopenharmony_ci
704195972f6Sopenharmony_ci  memset(&sa_listen, 0, sizeof(sa_listen));
705195972f6Sopenharmony_ci  sa_listen.sin_family = AF_INET;
706195972f6Sopenharmony_ci  sa_listen.sin_port = PP_HTONS(port);
707195972f6Sopenharmony_ci  sa_listen.sin_addr.s_addr = PP_HTONL(INADDR_LOOPBACK);
708195972f6Sopenharmony_ci
709195972f6Sopenharmony_ci  /* set up the listener */
710195972f6Sopenharmony_ci  sl = lwip_socket(AF_INET, SOCK_STREAM, 0);
711195972f6Sopenharmony_ci  fail_unless(sl >= 0);
712195972f6Sopenharmony_ci  fail_unless(test_sockets_get_used_count() == 0);
713195972f6Sopenharmony_ci
714195972f6Sopenharmony_ci  ret = lwip_bind(sl, (struct sockaddr *)&sa_listen, sizeof(sa_listen));
715195972f6Sopenharmony_ci  fail_unless(ret == 0);
716195972f6Sopenharmony_ci  ret = lwip_listen(sl, 0);
717195972f6Sopenharmony_ci  fail_unless(ret == 0);
718195972f6Sopenharmony_ci
719195972f6Sopenharmony_ci  /* set up the client */
720195972f6Sopenharmony_ci  sact = lwip_socket(AF_INET, SOCK_STREAM, 0);
721195972f6Sopenharmony_ci  fail_unless(sact >= 0);
722195972f6Sopenharmony_ci  fail_unless(test_sockets_get_used_count() == 0);
723195972f6Sopenharmony_ci  /* set the client to nonblocking to simplify this test */
724195972f6Sopenharmony_ci  arg = 1;
725195972f6Sopenharmony_ci  ret = lwip_ioctl(sact, FIONBIO, &arg);
726195972f6Sopenharmony_ci  fail_unless(ret == 0);
727195972f6Sopenharmony_ci  /* connect */
728195972f6Sopenharmony_ci  do {
729195972f6Sopenharmony_ci    ret = lwip_connect(sact, (struct sockaddr *)&sa_listen, sizeof(sa_listen));
730195972f6Sopenharmony_ci    err = errno;
731195972f6Sopenharmony_ci    fail_unless((ret == 0) || (ret == -1));
732195972f6Sopenharmony_ci    if (ret != 0) {
733195972f6Sopenharmony_ci      if (err == EISCONN) {
734195972f6Sopenharmony_ci        /* Although this is not valid, use EISCONN as an indicator for successful connection.
735195972f6Sopenharmony_ci           This marks us as "connect phase is done". On error, we would either have a different
736195972f6Sopenharmony_ci           errno code or "send" fails later... -> good enough for this test. */
737195972f6Sopenharmony_ci        ret = 0;
738195972f6Sopenharmony_ci      } else {
739195972f6Sopenharmony_ci        fail_unless(err == EINPROGRESS);
740195972f6Sopenharmony_ci        if (err != EINPROGRESS) {
741195972f6Sopenharmony_ci          goto cleanup;
742195972f6Sopenharmony_ci        }
743195972f6Sopenharmony_ci        /* we're in progress: little side check: test for EALREADY */
744195972f6Sopenharmony_ci        ret = lwip_connect(sact, (struct sockaddr *)&sa_listen, sizeof(sa_listen));
745195972f6Sopenharmony_ci        err = errno;
746195972f6Sopenharmony_ci        fail_unless(ret == -1);
747195972f6Sopenharmony_ci        fail_unless(err == EALREADY);
748195972f6Sopenharmony_ci        if ((ret != -1) || (err != EALREADY)) {
749195972f6Sopenharmony_ci          goto cleanup;
750195972f6Sopenharmony_ci        }
751195972f6Sopenharmony_ci      }
752195972f6Sopenharmony_ci      tcpip_thread_poll_one();
753195972f6Sopenharmony_ci      tcpip_thread_poll_one();
754195972f6Sopenharmony_ci      tcpip_thread_poll_one();
755195972f6Sopenharmony_ci      tcpip_thread_poll_one();
756195972f6Sopenharmony_ci    }
757195972f6Sopenharmony_ci  } while (ret != 0);
758195972f6Sopenharmony_ci  fail_unless(ret == 0);
759195972f6Sopenharmony_ci
760195972f6Sopenharmony_ci  /* accept the server connection part */
761195972f6Sopenharmony_ci  spass = lwip_accept(sl, NULL, NULL);
762195972f6Sopenharmony_ci  fail_unless(spass >= 0);
763195972f6Sopenharmony_ci
764195972f6Sopenharmony_ci  /* write data from client */
765195972f6Sopenharmony_ci  ret = lwip_send(sact, txbuf, sizeof(txbuf), 0);
766195972f6Sopenharmony_ci  fail_unless(ret == sizeof(txbuf));
767195972f6Sopenharmony_ci
768195972f6Sopenharmony_ci  tcpip_thread_poll_one();
769195972f6Sopenharmony_ci  tcpip_thread_poll_one();
770195972f6Sopenharmony_ci
771195972f6Sopenharmony_ci  /* issue RST (This is a HACK, don't try this in your own app!) */
772195972f6Sopenharmony_ci  sact_sock = lwip_socket_dbg_get_socket(sact);
773195972f6Sopenharmony_ci  fail_unless(sact_sock != NULL);
774195972f6Sopenharmony_ci  if (sact_sock != NULL) {
775195972f6Sopenharmony_ci    struct netconn *sact_conn = sact_sock->conn;
776195972f6Sopenharmony_ci    fail_unless(sact_conn != NULL);
777195972f6Sopenharmony_ci    if (sact_conn != NULL) {
778195972f6Sopenharmony_ci      struct tcp_pcb *pcb = sact_conn->pcb.tcp;
779195972f6Sopenharmony_ci      fail_unless(pcb != NULL);
780195972f6Sopenharmony_ci      if (pcb != NULL) {
781195972f6Sopenharmony_ci        tcp_rst(pcb, pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
782195972f6Sopenharmony_ci                     pcb->local_port, pcb->remote_port);
783195972f6Sopenharmony_ci      }
784195972f6Sopenharmony_ci    }
785195972f6Sopenharmony_ci  }
786195972f6Sopenharmony_ci  tcpip_thread_poll_one();
787195972f6Sopenharmony_ci  tcpip_thread_poll_one();
788195972f6Sopenharmony_ci
789195972f6Sopenharmony_ci  /* expect to receive data first */
790195972f6Sopenharmony_ci  ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
791195972f6Sopenharmony_ci  fail_unless(ret > 0);
792195972f6Sopenharmony_ci  tcpip_thread_poll_one();
793195972f6Sopenharmony_ci  tcpip_thread_poll_one();
794195972f6Sopenharmony_ci
795195972f6Sopenharmony_ci  /* expect to receive RST indication */
796195972f6Sopenharmony_ci  ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
797195972f6Sopenharmony_ci  fail_unless(ret == -1);
798195972f6Sopenharmony_ci  err = errno;
799195972f6Sopenharmony_ci  fail_unless(err == ECONNRESET);
800195972f6Sopenharmony_ci  tcpip_thread_poll_one();
801195972f6Sopenharmony_ci  tcpip_thread_poll_one();
802195972f6Sopenharmony_ci
803195972f6Sopenharmony_ci  /* expect to receive ENOTCONN indication */
804195972f6Sopenharmony_ci  ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
805195972f6Sopenharmony_ci  fail_unless(ret == -1);
806195972f6Sopenharmony_ci  err = errno;
807195972f6Sopenharmony_ci  fail_unless(err == ENOTCONN);
808195972f6Sopenharmony_ci  tcpip_thread_poll_one();
809195972f6Sopenharmony_ci  tcpip_thread_poll_one();
810195972f6Sopenharmony_ci
811195972f6Sopenharmony_ci  /* expect to receive ENOTCONN indication */
812195972f6Sopenharmony_ci  ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
813195972f6Sopenharmony_ci  fail_unless(ret == -1);
814195972f6Sopenharmony_ci  err = errno;
815195972f6Sopenharmony_ci  fail_unless(err == ENOTCONN);
816195972f6Sopenharmony_ci  tcpip_thread_poll_one();
817195972f6Sopenharmony_ci  tcpip_thread_poll_one();
818195972f6Sopenharmony_ci
819195972f6Sopenharmony_cicleanup:
820195972f6Sopenharmony_ci  ret = lwip_close(sl);
821195972f6Sopenharmony_ci  fail_unless(ret == 0);
822195972f6Sopenharmony_ci  ret = lwip_close(sact);
823195972f6Sopenharmony_ci  fail_unless(ret == 0);
824195972f6Sopenharmony_ci  if (spass >= 0) {
825195972f6Sopenharmony_ci    ret = lwip_close(spass);
826195972f6Sopenharmony_ci    fail_unless(ret == 0);
827195972f6Sopenharmony_ci  }
828195972f6Sopenharmony_ci}
829195972f6Sopenharmony_ciEND_TEST
830195972f6Sopenharmony_ci
831195972f6Sopenharmony_ci/** Create the suite including all tests for this module */
832195972f6Sopenharmony_ciSuite *
833195972f6Sopenharmony_cisockets_suite(void)
834195972f6Sopenharmony_ci{
835195972f6Sopenharmony_ci  testfunc tests[] = {
836195972f6Sopenharmony_ci    TESTFUNC(test_sockets_basics),
837195972f6Sopenharmony_ci    TESTFUNC(test_sockets_allfunctions_basic),
838195972f6Sopenharmony_ci    TESTFUNC(test_sockets_msgapis),
839195972f6Sopenharmony_ci    TESTFUNC(test_sockets_select),
840195972f6Sopenharmony_ci    TESTFUNC(test_sockets_recv_after_rst),
841195972f6Sopenharmony_ci  };
842195972f6Sopenharmony_ci  return create_suite("SOCKETS", tests, sizeof(tests)/sizeof(testfunc), sockets_setup, sockets_teardown);
843195972f6Sopenharmony_ci}
844195972f6Sopenharmony_ci
845195972f6Sopenharmony_ci#else /* LWIP_SOCKET */
846195972f6Sopenharmony_ci
847195972f6Sopenharmony_ciSuite *
848195972f6Sopenharmony_cisockets_suite(void)
849195972f6Sopenharmony_ci{
850195972f6Sopenharmony_ci  return create_suite("SOCKETS", NULL, 0, NULL, NULL);
851195972f6Sopenharmony_ci}
852195972f6Sopenharmony_ci#endif /* LWIP_SOCKET */
853