1
2#include "socket_examples.h"
3
4#include "lwip/opt.h"
5
6#if LWIP_SOCKET && (LWIP_IPV4 || LWIP_IPV6)
7
8#include "lwip/sockets.h"
9#include "lwip/sys.h"
10
11#include <string.h>
12#include <stdio.h>
13
14#ifndef SOCK_TARGET_HOST4
15#define SOCK_TARGET_HOST4  "192.168.1.1"
16#endif
17
18#ifndef SOCK_TARGET_HOST6
19#define SOCK_TARGET_HOST6  "FE80::12:34FF:FE56:78AB"
20#endif
21
22#ifndef SOCK_TARGET_PORT
23#define SOCK_TARGET_PORT  80
24#endif
25
26#ifndef SOCK_TARGET_MAXHTTPPAGESIZE
27#define SOCK_TARGET_MAXHTTPPAGESIZE 1024
28#endif
29
30#ifndef SOCKET_EXAMPLES_RUN_PARALLEL
31#define SOCKET_EXAMPLES_RUN_PARALLEL 0
32#endif
33
34const u8_t cmpbuf[8] = {0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab};
35
36/* a helper struct to ensure memory before/after fd_set is not touched */
37typedef struct _xx
38{
39  u8_t buf1[8];
40  fd_set readset;
41  u8_t buf2[8];
42  fd_set writeset;
43  u8_t buf3[8];
44  fd_set errset;
45  u8_t buf4[8];
46} fdsets;
47
48#define INIT_FDSETS(sets) do { \
49  memset((sets)->buf1, 0xab, 8); \
50  memset((sets)->buf2, 0xab, 8); \
51  memset((sets)->buf3, 0xab, 8); \
52  memset((sets)->buf4, 0xab, 8); \
53}while(0)
54
55#define CHECK_FDSETS(sets) do { \
56  LWIP_ASSERT("buf1 fail", !memcmp((sets)->buf1, cmpbuf, 8)); \
57  LWIP_ASSERT("buf2 fail", !memcmp((sets)->buf2, cmpbuf, 8)); \
58  LWIP_ASSERT("buf3 fail", !memcmp((sets)->buf3, cmpbuf, 8)); \
59  LWIP_ASSERT("buf4 fail", !memcmp((sets)->buf4, cmpbuf, 8)); \
60}while(0)
61
62static ip_addr_t dstaddr;
63
64/** This is an example function that tests
65    blocking- and nonblocking connect. */
66static void
67sockex_nonblocking_connect(void *arg)
68{
69  int s;
70  int ret;
71  u32_t opt;
72#if LWIP_IPV6
73  struct sockaddr_in6 addr;
74#else /* LWIP_IPV6 */
75  struct sockaddr_in addr;
76#endif /* LWIP_IPV6 */
77  fdsets sets;
78  struct timeval tv;
79  u32_t ticks_a, ticks_b;
80  int err;
81  const ip_addr_t *ipaddr = (const ip_addr_t*)arg;
82  INIT_FDSETS(&sets);
83
84  /* set up address to connect to */
85  memset(&addr, 0, sizeof(addr));
86#if LWIP_IPV6
87  addr.sin6_len = sizeof(addr);
88  addr.sin6_family = AF_INET6;
89  addr.sin6_port = PP_HTONS(SOCK_TARGET_PORT);
90  inet6_addr_from_ip6addr(&addr.sin6_addr, ip_2_ip6(ipaddr));
91#else /* LWIP_IPV6 */
92  addr.sin_len = sizeof(addr);
93  addr.sin_family = AF_INET;
94  addr.sin_port = PP_HTONS(SOCK_TARGET_PORT);
95  inet_addr_from_ip4addr(&addr.sin_addr, ip_2_ip4(ipaddr));
96#endif /* LWIP_IPV6 */
97
98  /* first try blocking: */
99
100  /* create the socket */
101#if LWIP_IPV6
102  s = lwip_socket(AF_INET6, SOCK_STREAM, 0);
103#else /* LWIP_IPV6 */
104  s = lwip_socket(AF_INET, SOCK_STREAM, 0);
105#endif /* LWIP_IPV6 */
106  LWIP_ASSERT("s >= 0", s >= 0);
107
108  /* connect */
109  ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr));
110  /* should succeed */
111  LWIP_ASSERT("ret == 0", ret == 0);
112
113  /* write something */
114  ret = lwip_write(s, "test", 4);
115  LWIP_ASSERT("ret == 4", ret == 4);
116
117  /* close */
118  ret = lwip_close(s);
119  LWIP_ASSERT("ret == 0", ret == 0);
120
121  /* now try nonblocking and close before being connected */
122
123  /* create the socket */
124#if LWIP_IPV6
125  s = lwip_socket(AF_INET6, SOCK_STREAM, 0);
126#else /* LWIP_IPV6 */
127  s = lwip_socket(AF_INET, SOCK_STREAM, 0);
128#endif /* LWIP_IPV6 */
129  LWIP_ASSERT("s >= 0", s >= 0);
130  /* nonblocking */
131  opt = lwip_fcntl(s, F_GETFL, 0);
132  LWIP_ASSERT("ret != -1", ret != -1);
133  opt |= O_NONBLOCK;
134  ret = lwip_fcntl(s, F_SETFL, opt);
135  LWIP_ASSERT("ret != -1", ret != -1);
136  /* connect */
137  ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr));
138  /* should have an error: "inprogress" */
139  LWIP_ASSERT("ret == -1", ret == -1);
140  err = errno;
141  LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS);
142  /* close */
143  ret = lwip_close(s);
144  LWIP_ASSERT("ret == 0", ret == 0);
145  /* try to close again, should fail with EBADF */
146  ret = lwip_close(s);
147  LWIP_ASSERT("ret == -1", ret == -1);
148  err = errno;
149  LWIP_ASSERT("errno == EBADF", err == EBADF);
150  printf("closing socket in nonblocking connect succeeded\n");
151
152  /* now try nonblocking, connect should succeed:
153     this test only works if it is fast enough, i.e. no breakpoints, please! */
154
155  /* create the socket */
156#if LWIP_IPV6
157  s = lwip_socket(AF_INET6, SOCK_STREAM, 0);
158#else /* LWIP_IPV6 */
159  s = lwip_socket(AF_INET, SOCK_STREAM, 0);
160#endif /* LWIP_IPV6 */
161  LWIP_ASSERT("s >= 0", s >= 0);
162
163  /* nonblocking */
164  opt = 1;
165  ret = lwip_ioctl(s, FIONBIO, &opt);
166  LWIP_ASSERT("ret == 0", ret == 0);
167
168  /* connect */
169  ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr));
170  /* should have an error: "inprogress" */
171  LWIP_ASSERT("ret == -1", ret == -1);
172  err = errno;
173  LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS);
174
175  /* write should fail, too */
176  ret = lwip_write(s, "test", 4);
177  LWIP_ASSERT("ret == -1", ret == -1);
178  err = errno;
179  LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS);
180
181  CHECK_FDSETS(&sets);
182  FD_ZERO(&sets.readset);
183  CHECK_FDSETS(&sets);
184  FD_SET(s, &sets.readset);
185  CHECK_FDSETS(&sets);
186  FD_ZERO(&sets.writeset);
187  CHECK_FDSETS(&sets);
188  FD_SET(s, &sets.writeset);
189  CHECK_FDSETS(&sets);
190  FD_ZERO(&sets.errset);
191  CHECK_FDSETS(&sets);
192  FD_SET(s, &sets.errset);
193  CHECK_FDSETS(&sets);
194  tv.tv_sec = 0;
195  tv.tv_usec = 0;
196  /* select without waiting should fail */
197  ret = lwip_select(s + 1, &sets.readset, &sets.writeset, &sets.errset, &tv);
198  CHECK_FDSETS(&sets);
199  LWIP_ASSERT("ret == 0", ret == 0);
200  LWIP_ASSERT("!FD_ISSET(s, &writeset)", !FD_ISSET(s, &sets.writeset));
201  LWIP_ASSERT("!FD_ISSET(s, &readset)", !FD_ISSET(s, &sets.readset));
202  LWIP_ASSERT("!FD_ISSET(s, &errset)", !FD_ISSET(s, &sets.errset));
203
204  FD_ZERO(&sets.readset);
205  FD_SET(s, &sets.readset);
206  FD_ZERO(&sets.writeset);
207  FD_SET(s, &sets.writeset);
208  FD_ZERO(&sets.errset);
209  FD_SET(s, &sets.errset);
210  ticks_a = sys_now();
211  /* select with waiting should succeed */
212  ret = lwip_select(s + 1, &sets.readset, &sets.writeset, &sets.errset, NULL);
213  ticks_b = sys_now();
214  LWIP_ASSERT("ret == 1", ret == 1);
215  LWIP_ASSERT("FD_ISSET(s, &writeset)", FD_ISSET(s, &sets.writeset));
216  LWIP_ASSERT("!FD_ISSET(s, &readset)", !FD_ISSET(s, &sets.readset));
217  LWIP_ASSERT("!FD_ISSET(s, &errset)", !FD_ISSET(s, &sets.errset));
218
219  /* now write should succeed */
220  ret = lwip_write(s, "test", 4);
221  LWIP_ASSERT("ret == 4", ret == 4);
222
223  /* close */
224  ret = lwip_close(s);
225  LWIP_ASSERT("ret == 0", ret == 0);
226
227  printf("select() needed %d ticks to return writable\n", (int)(ticks_b - ticks_a));
228
229
230  /* now try nonblocking to invalid address:
231     this test only works if it is fast enough, i.e. no breakpoints, please! */
232
233  /* create the socket */
234#if LWIP_IPV6
235  s = lwip_socket(AF_INET6, SOCK_STREAM, 0);
236#else /* LWIP_IPV6 */
237  s = lwip_socket(AF_INET, SOCK_STREAM, 0);
238#endif /* LWIP_IPV6 */
239  LWIP_ASSERT("s >= 0", s >= 0);
240
241  /* nonblocking */
242  opt = 1;
243  ret = lwip_ioctl(s, FIONBIO, &opt);
244  LWIP_ASSERT("ret == 0", ret == 0);
245
246#if LWIP_IPV6
247  addr.sin6_addr.un.u8_addr[0]++; /* this should result in an invalid address */
248#else /* LWIP_IPV6 */
249  addr.sin_addr.s_addr++; /* this should result in an invalid address */
250#endif /* LWIP_IPV6 */
251
252  /* connect */
253  ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr));
254  /* should have an error: "inprogress" */
255  LWIP_ASSERT("ret == -1", ret == -1);
256  err = errno;
257  LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS);
258
259  /* write should fail, too */
260  ret = lwip_write(s, "test", 4);
261  LWIP_ASSERT("ret == -1", ret == -1);
262  err = errno;
263  LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS);
264  LWIP_UNUSED_ARG(err);
265
266  FD_ZERO(&sets.readset);
267  FD_SET(s, &sets.readset);
268  FD_ZERO(&sets.writeset);
269  FD_SET(s, &sets.writeset);
270  FD_ZERO(&sets.errset);
271  FD_SET(s, &sets.errset);
272  tv.tv_sec = 0;
273  tv.tv_usec = 0;
274  /* select without waiting should fail */
275  ret = lwip_select(s + 1, &sets.readset, &sets.writeset, &sets.errset, &tv);
276  LWIP_ASSERT("ret == 0", ret == 0);
277
278  FD_ZERO(&sets.readset);
279  FD_SET(s, &sets.readset);
280  FD_ZERO(&sets.writeset);
281  FD_SET(s, &sets.writeset);
282  FD_ZERO(&sets.errset);
283  FD_SET(s, &sets.errset);
284  ticks_a = sys_now();
285  /* select with waiting should eventually succeed and return errset! */
286  ret = lwip_select(s + 1, &sets.readset, &sets.writeset, &sets.errset, NULL);
287  ticks_b = sys_now();
288  LWIP_ASSERT("ret > 0", ret > 0);
289  LWIP_ASSERT("FD_ISSET(s, &errset)", FD_ISSET(s, &sets.errset));
290  /*LWIP_ASSERT("!FD_ISSET(s, &readset)", !FD_ISSET(s, &sets.readset));
291  LWIP_ASSERT("!FD_ISSET(s, &writeset)", !FD_ISSET(s, &sets.writeset));*/
292
293  /* close */
294  ret = lwip_close(s);
295  LWIP_ASSERT("ret == 0", ret == 0);
296  LWIP_UNUSED_ARG(ret);
297
298  printf("select() needed %d ticks to return error\n", (int)(ticks_b - ticks_a));
299  printf("all tests done, thread ending\n");
300}
301
302/** This is an example function that tests
303    the recv function (timeout etc.). */
304static void
305sockex_testrecv(void *arg)
306{
307  int s;
308  int ret;
309  int err;
310  int opt, opt2;
311  socklen_t opt2size;
312#if LWIP_IPV6
313  struct sockaddr_in6 addr;
314#else /* LWIP_IPV6 */
315  struct sockaddr_in addr;
316#endif /* LWIP_IPV6 */
317  size_t len;
318  char rxbuf[SOCK_TARGET_MAXHTTPPAGESIZE];
319  fd_set readset;
320  fd_set errset;
321  struct timeval tv;
322  const ip_addr_t *ipaddr = (const ip_addr_t*)arg;
323
324  /* set up address to connect to */
325  memset(&addr, 0, sizeof(addr));
326#if LWIP_IPV6
327  addr.sin6_len = sizeof(addr);
328  addr.sin6_family = AF_INET6;
329  addr.sin6_port = PP_HTONS(SOCK_TARGET_PORT);
330  inet6_addr_from_ip6addr(&addr.sin6_addr, ip_2_ip6(ipaddr));
331#else /* LWIP_IPV6 */
332  addr.sin_len = sizeof(addr);
333  addr.sin_family = AF_INET;
334  addr.sin_port = PP_HTONS(SOCK_TARGET_PORT);
335  inet_addr_from_ip4addr(&addr.sin_addr, ip_2_ip4(ipaddr));
336#endif /* LWIP_IPV6 */
337
338  /* first try blocking: */
339
340  /* create the socket */
341#if LWIP_IPV6
342  s = lwip_socket(AF_INET6, SOCK_STREAM, 0);
343#else /* LWIP_IPV6 */
344  s = lwip_socket(AF_INET, SOCK_STREAM, 0);
345#endif /* LWIP_IPV6 */
346  LWIP_ASSERT("s >= 0", s >= 0);
347
348  /* connect */
349  ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr));
350  /* should succeed */
351  LWIP_ASSERT("ret == 0", ret == 0);
352
353  /* set recv timeout (100 ms) */
354  opt = 100;
355  ret = lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &opt, sizeof(int));
356  LWIP_ASSERT("ret == 0", ret == 0);
357  opt2 = 0;
358  opt2size = sizeof(opt2);
359  ret = lwip_getsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &opt2, &opt2size);
360  LWIP_ASSERT("ret == 0", ret == 0);
361  LWIP_ASSERT("opt2size == sizeof(opt2)", opt2size == sizeof(opt2));
362  LWIP_ASSERT("opt == opt2", opt == opt2);
363
364  /* write the start of a GET request */
365#define SNDSTR1 "G"
366  len = strlen(SNDSTR1);
367  ret = lwip_write(s, SNDSTR1, len);
368  LWIP_ASSERT("ret == len", ret == (int)len);
369
370  /* should time out if the other side is a good HTTP server */
371  ret = lwip_read(s, rxbuf, 1);
372  LWIP_ASSERT("ret == -1", ret == -1);
373  err = errno;
374  LWIP_ASSERT("errno == EAGAIN", err == EAGAIN);
375  LWIP_UNUSED_ARG(err);
376
377  /* write the rest of a GET request */
378#define SNDSTR2 "ET / HTTP_1.1\r\n\r\n"
379  len = strlen(SNDSTR2);
380  ret = lwip_write(s, SNDSTR2, len);
381  LWIP_ASSERT("ret == len", ret == (int)len);
382
383  /* wait a while: should be enough for the server to send a response */
384  sys_msleep(1000);
385
386  /* should not time out but receive a response */
387  ret = lwip_read(s, rxbuf, SOCK_TARGET_MAXHTTPPAGESIZE);
388  LWIP_ASSERT("ret > 0", ret > 0);
389
390  /* now select should directly return because the socket is readable */
391  FD_ZERO(&readset);
392  FD_ZERO(&errset);
393  FD_SET(s, &readset);
394  FD_SET(s, &errset);
395  tv.tv_sec = 10;
396  tv.tv_usec = 0;
397  ret = lwip_select(s + 1, &readset, NULL, &errset, &tv);
398  LWIP_ASSERT("ret == 1", ret == 1);
399  LWIP_ASSERT("!FD_ISSET(s, &errset)", !FD_ISSET(s, &errset));
400  LWIP_ASSERT("FD_ISSET(s, &readset)", FD_ISSET(s, &readset));
401
402  /* should not time out but receive a response */
403  ret = lwip_read(s, rxbuf, SOCK_TARGET_MAXHTTPPAGESIZE);
404  /* might receive a second packet for HTTP/1.1 servers */
405  if (ret > 0) {
406    /* should return 0: closed */
407    ret = lwip_read(s, rxbuf, SOCK_TARGET_MAXHTTPPAGESIZE);
408    LWIP_ASSERT("ret == 0", ret == 0);
409  }
410
411  /* close */
412  ret = lwip_close(s);
413  LWIP_ASSERT("ret == 0", ret == 0);
414  LWIP_UNUSED_ARG(ret);
415
416  printf("sockex_testrecv finished successfully\n");
417}
418
419/** helper struct for the 2 functions below (multithreaded: thread-argument) */
420struct sockex_select_helper {
421  int socket;
422  int wait_read;
423  int expect_read;
424  int wait_write;
425  int expect_write;
426  int wait_err;
427  int expect_err;
428  int wait_ms;
429  sys_sem_t sem;
430};
431
432/** helper thread to wait for socket events using select */
433static void
434sockex_select_waiter(void *arg)
435{
436  struct sockex_select_helper *helper = (struct sockex_select_helper *)arg;
437  int ret;
438  fd_set readset;
439  fd_set writeset;
440  fd_set errset;
441  struct timeval tv;
442
443  LWIP_ASSERT("helper != NULL", helper != NULL);
444
445  FD_ZERO(&readset);
446  FD_ZERO(&writeset);
447  FD_ZERO(&errset);
448  if (helper->wait_read) {
449    FD_SET(helper->socket, &readset);
450  }
451  if (helper->wait_write) {
452    FD_SET(helper->socket, &writeset);
453  }
454  if (helper->wait_err) {
455    FD_SET(helper->socket, &errset);
456  }
457
458  tv.tv_sec = helper->wait_ms / 1000;
459  tv.tv_usec = (helper->wait_ms % 1000) * 1000;
460
461  ret = lwip_select(helper->socket, &readset, &writeset, &errset, &tv);
462  if (helper->expect_read || helper->expect_write || helper->expect_err) {
463    LWIP_ASSERT("ret > 0", ret > 0);
464  } else {
465    LWIP_ASSERT("ret == 0", ret == 0);
466  }
467  LWIP_UNUSED_ARG(ret);
468  if (helper->expect_read) {
469    LWIP_ASSERT("FD_ISSET(helper->socket, &readset)", FD_ISSET(helper->socket, &readset));
470  } else {
471    LWIP_ASSERT("!FD_ISSET(helper->socket, &readset)", !FD_ISSET(helper->socket, &readset));
472  }
473  if (helper->expect_write) {
474    LWIP_ASSERT("FD_ISSET(helper->socket, &writeset)", FD_ISSET(helper->socket, &writeset));
475  } else {
476    LWIP_ASSERT("!FD_ISSET(helper->socket, &writeset)", !FD_ISSET(helper->socket, &writeset));
477  }
478  if (helper->expect_err) {
479    LWIP_ASSERT("FD_ISSET(helper->socket, &errset)", FD_ISSET(helper->socket, &errset));
480  } else {
481    LWIP_ASSERT("!FD_ISSET(helper->socket, &errset)", !FD_ISSET(helper->socket, &errset));
482  }
483  sys_sem_signal(&helper->sem);
484}
485
486/** This is an example function that tests
487    more than one thread being active in select. */
488static void
489sockex_testtwoselects(void *arg)
490{
491  int s1;
492  int s2;
493  int ret;
494#if LWIP_IPV6
495  struct sockaddr_in6 addr;
496#else /* LWIP_IPV6 */
497  struct sockaddr_in addr;
498#endif /* LWIP_IPV6 */
499  size_t len;
500  err_t lwiperr;
501  struct sockex_select_helper h1, h2, h3, h4;
502  const ip_addr_t *ipaddr = (const ip_addr_t*)arg;
503
504  /* set up address to connect to */
505  memset(&addr, 0, sizeof(addr));
506#if LWIP_IPV6
507  addr.sin6_len = sizeof(addr);
508  addr.sin6_family = AF_INET6;
509  addr.sin6_port = PP_HTONS(SOCK_TARGET_PORT);
510  inet6_addr_from_ip6addr(&addr.sin6_addr, ip_2_ip6(ipaddr));
511#else /* LWIP_IPV6 */
512  addr.sin_len = sizeof(addr);
513  addr.sin_family = AF_INET;
514  addr.sin_port = PP_HTONS(SOCK_TARGET_PORT);
515  inet_addr_from_ip4addr(&addr.sin_addr, ip_2_ip4(ipaddr));
516#endif /* LWIP_IPV6 */
517
518  /* create the sockets */
519#if LWIP_IPV6
520  s1 = lwip_socket(AF_INET6, SOCK_STREAM, 0);
521  s2 = lwip_socket(AF_INET6, SOCK_STREAM, 0);
522#else /* LWIP_IPV6 */
523  s1 = lwip_socket(AF_INET, SOCK_STREAM, 0);
524  s2 = lwip_socket(AF_INET, SOCK_STREAM, 0);
525#endif /* LWIP_IPV6 */
526  LWIP_ASSERT("s1 >= 0", s1 >= 0);
527  LWIP_ASSERT("s2 >= 0", s2 >= 0);
528
529  /* connect, should succeed */
530  ret = lwip_connect(s1, (struct sockaddr*)&addr, sizeof(addr));
531  LWIP_ASSERT("ret == 0", ret == 0);
532  ret = lwip_connect(s2, (struct sockaddr*)&addr, sizeof(addr));
533  LWIP_ASSERT("ret == 0", ret == 0);
534
535  /* write the start of a GET request */
536#define SNDSTR1 "G"
537  len = strlen(SNDSTR1);
538  ret = lwip_write(s1, SNDSTR1, len);
539  LWIP_ASSERT("ret == len", ret == (int)len);
540  ret = lwip_write(s2, SNDSTR1, len);
541  LWIP_ASSERT("ret == len", ret == (int)len);
542  LWIP_UNUSED_ARG(ret);
543
544  h1.wait_read  = 1;
545  h1.wait_write = 1;
546  h1.wait_err   = 1;
547  h1.expect_read  = 0;
548  h1.expect_write = 0;
549  h1.expect_err   = 0;
550  lwiperr = sys_sem_new(&h1.sem, 0);
551  LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK);
552  h1.socket = s1;
553  h1.wait_ms = 500;
554
555  h2 = h1;
556  lwiperr = sys_sem_new(&h2.sem, 0);
557  LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK);
558  h2.socket = s2;
559  h2.wait_ms = 1000;
560
561  h3 = h1;
562  lwiperr = sys_sem_new(&h3.sem, 0);
563  LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK);
564  h3.socket = s2;
565  h3.wait_ms = 1500;
566
567  h4 = h1;
568  lwiperr = sys_sem_new(&h4.sem, 0);
569  LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK);
570  LWIP_UNUSED_ARG(lwiperr);
571  h4.socket = s2;
572  h4.wait_ms = 2000;
573
574  /* select: all sockets should time out if the other side is a good HTTP server */
575
576  sys_thread_new("sockex_select_waiter1", sockex_select_waiter, &h2, 0, 0);
577  sys_msleep(100);
578  sys_thread_new("sockex_select_waiter2", sockex_select_waiter, &h1, 0, 0);
579  sys_msleep(100);
580  sys_thread_new("sockex_select_waiter2", sockex_select_waiter, &h4, 0, 0);
581  sys_msleep(100);
582  sys_thread_new("sockex_select_waiter2", sockex_select_waiter, &h3, 0, 0);
583
584  sys_sem_wait(&h1.sem);
585  sys_sem_wait(&h2.sem);
586  sys_sem_wait(&h3.sem);
587  sys_sem_wait(&h4.sem);
588
589  /* close */
590  ret = lwip_close(s1);
591  LWIP_ASSERT("ret == 0", ret == 0);
592  ret = lwip_close(s2);
593  LWIP_ASSERT("ret == 0", ret == 0);
594
595  printf("sockex_testtwoselects finished successfully\n");
596}
597
598#if !SOCKET_EXAMPLES_RUN_PARALLEL
599static void
600socket_example_test(void* arg)
601{
602  sockex_nonblocking_connect(arg);
603  sockex_testrecv(arg);
604  sockex_testtwoselects(arg);
605}
606#endif
607
608void socket_examples_init(void)
609{
610
611#if LWIP_IPV6
612  IP_SET_TYPE_VAL(dstaddr, IPADDR_TYPE_V6);
613  ip6addr_aton(SOCK_TARGET_HOST6, ip_2_ip6(&dstaddr));
614#else /* LWIP_IPV6 */
615  IP_SET_TYPE_VAL(dstaddr, IPADDR_TYPE_V4);
616  ip4addr_aton(SOCK_TARGET_HOST4, ip_2_ip4(&dstaddr));
617#endif /* LWIP_IPV6 */
618
619#if SOCKET_EXAMPLES_RUN_PARALLEL
620  sys_thread_new("sockex_nonblocking_connect", sockex_nonblocking_connect, &dstaddr, 0, 0);
621  sys_thread_new("sockex_testrecv", sockex_testrecv, &dstaddr, 0, 0);
622  sys_thread_new("sockex_testtwoselects", sockex_testtwoselects, &dstaddr, 0, 0);
623#else
624  sys_thread_new("socket_example_test", socket_example_test, &dstaddr, 0, 0);
625#endif
626}
627
628#endif /* LWIP_SOCKET */
629