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