summaryrefslogtreecommitdiff
path: root/contrib/apps/socket_examples
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/apps/socket_examples')
-rw-r--r--contrib/apps/socket_examples/socket_examples.c680
-rw-r--r--contrib/apps/socket_examples/socket_examples.h6
2 files changed, 686 insertions, 0 deletions
diff --git a/contrib/apps/socket_examples/socket_examples.c b/contrib/apps/socket_examples/socket_examples.c
new file mode 100644
index 00000000000..a60156f0e3a
--- /dev/null
+++ b/contrib/apps/socket_examples/socket_examples.c
@@ -0,0 +1,680 @@
+
+#include "socket_examples.h"
+
+#include "lwip/opt.h"
+
+#if LWIP_SOCKET && (LWIP_IPV4 || LWIP_IPV6)
+
+#include "lwip/sockets.h"
+#include "lwip/sys.h"
+
+#include <string.h>
+#include <stdio.h>
+
+#ifndef SOCK_TARGET_HOST4
+#define SOCK_TARGET_HOST4 "192.168.0.1"
+#endif
+
+#ifndef SOCK_TARGET_HOST6
+#define SOCK_TARGET_HOST6 "FE80::12:34FF:FE56:78AB"
+#endif
+
+#ifndef SOCK_TARGET_PORT
+#define SOCK_TARGET_PORT 80
+#endif
+
+#ifndef SOCK_TARGET_MAXHTTPPAGESIZE
+#define SOCK_TARGET_MAXHTTPPAGESIZE 1024
+#endif
+
+#ifndef SOCKET_EXAMPLES_RUN_PARALLEL
+#define SOCKET_EXAMPLES_RUN_PARALLEL 0
+#endif
+
+static const u8_t cmpbuf[8] = {0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab};
+
+/* a helper struct to ensure memory before/after fd_set is not touched */
+typedef struct _xx
+{
+ u8_t buf1[8];
+ fd_set readset;
+ u8_t buf2[8];
+ fd_set writeset;
+ u8_t buf3[8];
+ fd_set errset;
+ u8_t buf4[8];
+} fdsets;
+
+#define INIT_FDSETS(sets) do { \
+ memset((sets)->buf1, 0xab, 8); \
+ memset((sets)->buf2, 0xab, 8); \
+ memset((sets)->buf3, 0xab, 8); \
+ memset((sets)->buf4, 0xab, 8); \
+}while(0)
+
+#define CHECK_FDSETS(sets) do { \
+ LWIP_ASSERT("buf1 fail", !memcmp((sets)->buf1, cmpbuf, 8)); \
+ LWIP_ASSERT("buf2 fail", !memcmp((sets)->buf2, cmpbuf, 8)); \
+ LWIP_ASSERT("buf3 fail", !memcmp((sets)->buf3, cmpbuf, 8)); \
+ LWIP_ASSERT("buf4 fail", !memcmp((sets)->buf4, cmpbuf, 8)); \
+}while(0)
+
+static ip_addr_t dstaddr;
+
+/** This is an example function that tests
+ blocking- and nonblocking connect. */
+static void
+sockex_nonblocking_connect(void *arg)
+{
+#if LWIP_SOCKET_SELECT
+ int s;
+ int ret;
+ int opt;
+#if LWIP_IPV6
+ struct sockaddr_in6 addr;
+#else /* LWIP_IPV6 */
+ struct sockaddr_in addr;
+#endif /* LWIP_IPV6 */
+ fdsets sets;
+ struct timeval tv;
+ u32_t ticks_a, ticks_b;
+ int err;
+ const ip_addr_t *ipaddr = (const ip_addr_t*)arg;
+ struct pollfd fds;
+ INIT_FDSETS(&sets);
+
+ /* set up address to connect to */
+ memset(&addr, 0, sizeof(addr));
+#if LWIP_IPV6
+ addr.sin6_len = sizeof(addr);
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = PP_HTONS(SOCK_TARGET_PORT);
+ inet6_addr_from_ip6addr(&addr.sin6_addr, ip_2_ip6(ipaddr));
+#else /* LWIP_IPV6 */
+ addr.sin_len = sizeof(addr);
+ addr.sin_family = AF_INET;
+ addr.sin_port = PP_HTONS(SOCK_TARGET_PORT);
+ inet_addr_from_ip4addr(&addr.sin_addr, ip_2_ip4(ipaddr));
+#endif /* LWIP_IPV6 */
+
+ /* first try blocking: */
+
+ /* create the socket */
+#if LWIP_IPV6
+ s = lwip_socket(AF_INET6, SOCK_STREAM, 0);
+#else /* LWIP_IPV6 */
+ s = lwip_socket(AF_INET, SOCK_STREAM, 0);
+#endif /* LWIP_IPV6 */
+ LWIP_ASSERT("s >= 0", s >= 0);
+
+ /* connect */
+ ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr));
+ /* should succeed */
+ LWIP_ASSERT("ret == 0", ret == 0);
+
+ /* write something */
+ ret = lwip_write(s, "test", 4);
+ LWIP_ASSERT("ret == 4", ret == 4);
+
+ /* close */
+ ret = lwip_close(s);
+ LWIP_ASSERT("ret == 0", ret == 0);
+
+ /* now try nonblocking and close before being connected */
+
+ /* create the socket */
+#if LWIP_IPV6
+ s = lwip_socket(AF_INET6, SOCK_STREAM, 0);
+#else /* LWIP_IPV6 */
+ s = lwip_socket(AF_INET, SOCK_STREAM, 0);
+#endif /* LWIP_IPV6 */
+ LWIP_ASSERT("s >= 0", s >= 0);
+ /* nonblocking */
+ opt = lwip_fcntl(s, F_GETFL, 0);
+ LWIP_ASSERT("ret != -1", ret != -1);
+ opt |= O_NONBLOCK;
+ ret = lwip_fcntl(s, F_SETFL, opt);
+ LWIP_ASSERT("ret != -1", ret != -1);
+ /* connect */
+ ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr));
+ /* should have an error: "inprogress" */
+ LWIP_ASSERT("ret == -1", ret == -1);
+ err = errno;
+ LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS);
+ /* close */
+ ret = lwip_close(s);
+ LWIP_ASSERT("ret == 0", ret == 0);
+ /* try to close again, should fail with EBADF */
+ ret = lwip_close(s);
+ LWIP_ASSERT("ret == -1", ret == -1);
+ err = errno;
+ LWIP_ASSERT("errno == EBADF", err == EBADF);
+ printf("closing socket in nonblocking connect succeeded\n");
+
+ /* now try nonblocking, connect should succeed:
+ this test only works if it is fast enough, i.e. no breakpoints, please! */
+
+ /* create the socket */
+#if LWIP_IPV6
+ s = lwip_socket(AF_INET6, SOCK_STREAM, 0);
+#else /* LWIP_IPV6 */
+ s = lwip_socket(AF_INET, SOCK_STREAM, 0);
+#endif /* LWIP_IPV6 */
+ LWIP_ASSERT("s >= 0", s >= 0);
+
+ /* nonblocking */
+ opt = 1;
+ ret = lwip_ioctl(s, FIONBIO, &opt);
+ LWIP_ASSERT("ret == 0", ret == 0);
+
+ /* connect */
+ ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr));
+ /* should have an error: "inprogress" */
+ LWIP_ASSERT("ret == -1", ret == -1);
+ err = errno;
+ LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS);
+
+ /* write should fail, too */
+ ret = lwip_write(s, "test", 4);
+ LWIP_ASSERT("ret == -1", ret == -1);
+ err = errno;
+ LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS);
+
+ CHECK_FDSETS(&sets);
+ FD_ZERO(&sets.readset);
+ CHECK_FDSETS(&sets);
+ FD_SET(s, &sets.readset);
+ CHECK_FDSETS(&sets);
+ FD_ZERO(&sets.writeset);
+ CHECK_FDSETS(&sets);
+ FD_SET(s, &sets.writeset);
+ CHECK_FDSETS(&sets);
+ FD_ZERO(&sets.errset);
+ CHECK_FDSETS(&sets);
+ FD_SET(s, &sets.errset);
+ CHECK_FDSETS(&sets);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ /* select without waiting should fail */
+ ret = lwip_select(s + 1, &sets.readset, &sets.writeset, &sets.errset, &tv);
+ CHECK_FDSETS(&sets);
+ LWIP_ASSERT("ret == 0", ret == 0);
+ LWIP_ASSERT("!FD_ISSET(s, &writeset)", !FD_ISSET(s, &sets.writeset));
+ LWIP_ASSERT("!FD_ISSET(s, &readset)", !FD_ISSET(s, &sets.readset));
+ LWIP_ASSERT("!FD_ISSET(s, &errset)", !FD_ISSET(s, &sets.errset));
+
+ fds.fd = s;
+ fds.events = POLLIN|POLLOUT;
+ fds.revents = 0;
+ ret = lwip_poll(&fds, 1, 0);
+ LWIP_ASSERT("ret == 0", ret == 0);
+ LWIP_ASSERT("fds.revents == 0", fds.revents == 0);
+
+ FD_ZERO(&sets.readset);
+ FD_SET(s, &sets.readset);
+ FD_ZERO(&sets.writeset);
+ FD_SET(s, &sets.writeset);
+ FD_ZERO(&sets.errset);
+ FD_SET(s, &sets.errset);
+ ticks_a = sys_now();
+ /* select with waiting should succeed */
+ ret = lwip_select(s + 1, &sets.readset, &sets.writeset, &sets.errset, NULL);
+ ticks_b = sys_now();
+ LWIP_ASSERT("ret == 1", ret == 1);
+ LWIP_ASSERT("FD_ISSET(s, &writeset)", FD_ISSET(s, &sets.writeset));
+ LWIP_ASSERT("!FD_ISSET(s, &readset)", !FD_ISSET(s, &sets.readset));
+ LWIP_ASSERT("!FD_ISSET(s, &errset)", !FD_ISSET(s, &sets.errset));
+
+ fds.fd = s;
+ fds.events = POLLIN|POLLOUT;
+ fds.revents = 0;
+ ret = lwip_poll(&fds, 1, 0);
+ LWIP_ASSERT("ret == 1", ret == 1);
+ LWIP_ASSERT("fds.revents & POLLOUT", fds.revents & POLLOUT);
+
+ /* now write should succeed */
+ ret = lwip_write(s, "test", 4);
+ LWIP_ASSERT("ret == 4", ret == 4);
+
+ /* close */
+ ret = lwip_close(s);
+ LWIP_ASSERT("ret == 0", ret == 0);
+
+ printf("select() needed %d ticks to return writable\n", (int)(ticks_b - ticks_a));
+
+
+ /* now try nonblocking to invalid address:
+ this test only works if it is fast enough, i.e. no breakpoints, please! */
+
+ /* create the socket */
+#if LWIP_IPV6
+ s = lwip_socket(AF_INET6, SOCK_STREAM, 0);
+#else /* LWIP_IPV6 */
+ s = lwip_socket(AF_INET, SOCK_STREAM, 0);
+#endif /* LWIP_IPV6 */
+ LWIP_ASSERT("s >= 0", s >= 0);
+
+ /* nonblocking */
+ opt = 1;
+ ret = lwip_ioctl(s, FIONBIO, &opt);
+ LWIP_ASSERT("ret == 0", ret == 0);
+
+#if LWIP_IPV6
+ addr.sin6_addr.un.u8_addr[0]++; /* this should result in an invalid address */
+#else /* LWIP_IPV6 */
+ addr.sin_addr.s_addr++; /* this should result in an invalid address */
+#endif /* LWIP_IPV6 */
+
+ /* connect */
+ ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr));
+ /* should have an error: "inprogress" */
+ LWIP_ASSERT("ret == -1", ret == -1);
+ err = errno;
+ LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS);
+
+ /* write should fail, too */
+ ret = lwip_write(s, "test", 4);
+ LWIP_ASSERT("ret == -1", ret == -1);
+ err = errno;
+ LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS);
+ LWIP_UNUSED_ARG(err);
+
+ FD_ZERO(&sets.readset);
+ FD_SET(s, &sets.readset);
+ FD_ZERO(&sets.writeset);
+ FD_SET(s, &sets.writeset);
+ FD_ZERO(&sets.errset);
+ FD_SET(s, &sets.errset);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ /* select without waiting should fail */
+ ret = lwip_select(s + 1, &sets.readset, &sets.writeset, &sets.errset, &tv);
+ LWIP_ASSERT("ret == 0", ret == 0);
+
+ FD_ZERO(&sets.readset);
+ FD_SET(s, &sets.readset);
+ FD_ZERO(&sets.writeset);
+ FD_SET(s, &sets.writeset);
+ FD_ZERO(&sets.errset);
+ FD_SET(s, &sets.errset);
+ ticks_a = sys_now();
+ /* select with waiting should eventually succeed and return errset! */
+ ret = lwip_select(s + 1, &sets.readset, &sets.writeset, &sets.errset, NULL);
+ ticks_b = sys_now();
+ LWIP_ASSERT("ret > 0", ret > 0);
+ LWIP_ASSERT("FD_ISSET(s, &errset)", FD_ISSET(s, &sets.errset));
+ /*LWIP_ASSERT("!FD_ISSET(s, &readset)", !FD_ISSET(s, &sets.readset));
+ LWIP_ASSERT("!FD_ISSET(s, &writeset)", !FD_ISSET(s, &sets.writeset));*/
+
+ /* close */
+ ret = lwip_close(s);
+ LWIP_ASSERT("ret == 0", ret == 0);
+ LWIP_UNUSED_ARG(ret);
+
+ printf("select() needed %d ticks to return error\n", (int)(ticks_b - ticks_a));
+ printf("sockex_nonblocking_connect finished successfully\n");
+#else
+ LWIP_UNUSED_ARG(arg);
+#endif
+}
+
+/** This is an example function that tests
+ the recv function (timeout etc.). */
+static void
+sockex_testrecv(void *arg)
+{
+ int s;
+ int ret;
+ int err;
+#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD
+ int opt, opt2;
+#else
+ struct timeval opt, opt2;
+#endif
+ socklen_t opt2size;
+#if LWIP_IPV6
+ struct sockaddr_in6 addr;
+#else /* LWIP_IPV6 */
+ struct sockaddr_in addr;
+#endif /* LWIP_IPV6 */
+ size_t len;
+ char rxbuf[SOCK_TARGET_MAXHTTPPAGESIZE];
+#if LWIP_SOCKET_SELECT
+ fd_set readset;
+ fd_set errset;
+ struct timeval tv;
+#endif
+ const ip_addr_t *ipaddr = (const ip_addr_t*)arg;
+
+ /* set up address to connect to */
+ memset(&addr, 0, sizeof(addr));
+#if LWIP_IPV6
+ addr.sin6_len = sizeof(addr);
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = PP_HTONS(SOCK_TARGET_PORT);
+ inet6_addr_from_ip6addr(&addr.sin6_addr, ip_2_ip6(ipaddr));
+#else /* LWIP_IPV6 */
+ addr.sin_len = sizeof(addr);
+ addr.sin_family = AF_INET;
+ addr.sin_port = PP_HTONS(SOCK_TARGET_PORT);
+ inet_addr_from_ip4addr(&addr.sin_addr, ip_2_ip4(ipaddr));
+#endif /* LWIP_IPV6 */
+
+ /* first try blocking: */
+
+ /* create the socket */
+#if LWIP_IPV6
+ s = lwip_socket(AF_INET6, SOCK_STREAM, 0);
+#else /* LWIP_IPV6 */
+ s = lwip_socket(AF_INET, SOCK_STREAM, 0);
+#endif /* LWIP_IPV6 */
+ LWIP_ASSERT("s >= 0", s >= 0);
+
+ /* connect */
+ ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr));
+ /* should succeed */
+ LWIP_ASSERT("ret == 0", ret == 0);
+
+ /* set recv timeout (100 ms) */
+#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD
+ opt = 100;
+#else
+ opt.tv_sec = 0;
+ opt.tv_usec = 100 * 1000;
+#endif
+ ret = lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &opt, sizeof(opt));
+ LWIP_ASSERT("ret == 0", ret == 0);
+#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD
+ opt2 = 0;
+#else
+ opt2.tv_sec = 0;
+ opt2.tv_usec = 0;
+#endif
+ opt2size = sizeof(opt2);
+ ret = lwip_getsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &opt2, &opt2size);
+ LWIP_ASSERT("ret == 0", ret == 0);
+ LWIP_ASSERT("opt2size == sizeof(opt2)", opt2size == sizeof(opt2));
+#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD
+ LWIP_ASSERT("opt == opt2", opt == opt2);
+#else
+ LWIP_ASSERT("opt == opt2", opt.tv_sec == opt2.tv_sec);
+ LWIP_ASSERT("opt == opt2", opt.tv_usec == opt2.tv_usec);
+#endif
+
+ /* write the start of a GET request */
+#define SNDSTR1 "G"
+ len = strlen(SNDSTR1);
+ ret = lwip_write(s, SNDSTR1, len);
+ LWIP_ASSERT("ret == len", ret == (int)len);
+
+ /* should time out if the other side is a good HTTP server */
+ ret = lwip_read(s, rxbuf, 1);
+ LWIP_ASSERT("ret == -1", ret == -1);
+ err = errno;
+ LWIP_ASSERT("errno == EAGAIN", err == EAGAIN);
+ LWIP_UNUSED_ARG(err);
+
+ /* write the rest of a GET request */
+#define SNDSTR2 "ET / HTTP_1.1\r\n\r\n"
+ len = strlen(SNDSTR2);
+ ret = lwip_write(s, SNDSTR2, len);
+ LWIP_ASSERT("ret == len", ret == (int)len);
+
+ /* wait a while: should be enough for the server to send a response */
+ sys_msleep(1000);
+
+ /* should not time out but receive a response */
+ ret = lwip_read(s, rxbuf, SOCK_TARGET_MAXHTTPPAGESIZE);
+ LWIP_ASSERT("ret > 0", ret > 0);
+
+#if LWIP_SOCKET_SELECT
+ /* now select should directly return because the socket is readable */
+ FD_ZERO(&readset);
+ FD_ZERO(&errset);
+ FD_SET(s, &readset);
+ FD_SET(s, &errset);
+ tv.tv_sec = 10;
+ tv.tv_usec = 0;
+ ret = lwip_select(s + 1, &readset, NULL, &errset, &tv);
+ LWIP_ASSERT("ret == 1", ret == 1);
+ LWIP_ASSERT("!FD_ISSET(s, &errset)", !FD_ISSET(s, &errset));
+ LWIP_ASSERT("FD_ISSET(s, &readset)", FD_ISSET(s, &readset));
+#endif
+
+ /* should not time out but receive a response */
+ ret = lwip_read(s, rxbuf, SOCK_TARGET_MAXHTTPPAGESIZE);
+ /* might receive a second packet for HTTP/1.1 servers */
+ if (ret > 0) {
+ /* should return 0: closed */
+ ret = lwip_read(s, rxbuf, SOCK_TARGET_MAXHTTPPAGESIZE);
+ LWIP_ASSERT("ret == 0", ret == 0);
+ }
+
+ /* close */
+ ret = lwip_close(s);
+ LWIP_ASSERT("ret == 0", ret == 0);
+ LWIP_UNUSED_ARG(ret);
+
+ printf("sockex_testrecv finished successfully\n");
+}
+
+#if LWIP_SOCKET_SELECT
+/** helper struct for the 2 functions below (multithreaded: thread-argument) */
+struct sockex_select_helper {
+ int socket;
+ int wait_read;
+ int expect_read;
+ int wait_write;
+ int expect_write;
+ int wait_err;
+ int expect_err;
+ int wait_ms;
+ sys_sem_t sem;
+};
+
+/** helper thread to wait for socket events using select */
+static void
+sockex_select_waiter(void *arg)
+{
+ struct sockex_select_helper *helper = (struct sockex_select_helper *)arg;
+ int ret;
+ fd_set readset;
+ fd_set writeset;
+ fd_set errset;
+ struct timeval tv;
+
+ LWIP_ASSERT("helper != NULL", helper != NULL);
+
+ FD_ZERO(&readset);
+ FD_ZERO(&writeset);
+ FD_ZERO(&errset);
+ if (helper->wait_read) {
+ FD_SET(helper->socket, &readset);
+ }
+ if (helper->wait_write) {
+ FD_SET(helper->socket, &writeset);
+ }
+ if (helper->wait_err) {
+ FD_SET(helper->socket, &errset);
+ }
+
+ tv.tv_sec = helper->wait_ms / 1000;
+ tv.tv_usec = (helper->wait_ms % 1000) * 1000;
+
+ ret = lwip_select(helper->socket, &readset, &writeset, &errset, &tv);
+ if (helper->expect_read || helper->expect_write || helper->expect_err) {
+ LWIP_ASSERT("ret > 0", ret > 0);
+ } else {
+ LWIP_ASSERT("ret == 0", ret == 0);
+ }
+ LWIP_UNUSED_ARG(ret);
+ if (helper->expect_read) {
+ LWIP_ASSERT("FD_ISSET(helper->socket, &readset)", FD_ISSET(helper->socket, &readset));
+ } else {
+ LWIP_ASSERT("!FD_ISSET(helper->socket, &readset)", !FD_ISSET(helper->socket, &readset));
+ }
+ if (helper->expect_write) {
+ LWIP_ASSERT("FD_ISSET(helper->socket, &writeset)", FD_ISSET(helper->socket, &writeset));
+ } else {
+ LWIP_ASSERT("!FD_ISSET(helper->socket, &writeset)", !FD_ISSET(helper->socket, &writeset));
+ }
+ if (helper->expect_err) {
+ LWIP_ASSERT("FD_ISSET(helper->socket, &errset)", FD_ISSET(helper->socket, &errset));
+ } else {
+ LWIP_ASSERT("!FD_ISSET(helper->socket, &errset)", !FD_ISSET(helper->socket, &errset));
+ }
+ sys_sem_signal(&helper->sem);
+}
+
+/** This is an example function that tests
+ more than one thread being active in select. */
+static void
+sockex_testtwoselects(void *arg)
+{
+ int s1;
+ int s2;
+ int ret;
+#if LWIP_IPV6
+ struct sockaddr_in6 addr;
+#else /* LWIP_IPV6 */
+ struct sockaddr_in addr;
+#endif /* LWIP_IPV6 */
+ size_t len;
+ err_t lwiperr;
+ struct sockex_select_helper h1, h2, h3, h4;
+ const ip_addr_t *ipaddr = (const ip_addr_t*)arg;
+
+ /* set up address to connect to */
+ memset(&addr, 0, sizeof(addr));
+#if LWIP_IPV6
+ addr.sin6_len = sizeof(addr);
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = PP_HTONS(SOCK_TARGET_PORT);
+ inet6_addr_from_ip6addr(&addr.sin6_addr, ip_2_ip6(ipaddr));
+#else /* LWIP_IPV6 */
+ addr.sin_len = sizeof(addr);
+ addr.sin_family = AF_INET;
+ addr.sin_port = PP_HTONS(SOCK_TARGET_PORT);
+ inet_addr_from_ip4addr(&addr.sin_addr, ip_2_ip4(ipaddr));
+#endif /* LWIP_IPV6 */
+
+ /* create the sockets */
+#if LWIP_IPV6
+ s1 = lwip_socket(AF_INET6, SOCK_STREAM, 0);
+ s2 = lwip_socket(AF_INET6, SOCK_STREAM, 0);
+#else /* LWIP_IPV6 */
+ s1 = lwip_socket(AF_INET, SOCK_STREAM, 0);
+ s2 = lwip_socket(AF_INET, SOCK_STREAM, 0);
+#endif /* LWIP_IPV6 */
+ LWIP_ASSERT("s1 >= 0", s1 >= 0);
+ LWIP_ASSERT("s2 >= 0", s2 >= 0);
+
+ /* connect, should succeed */
+ ret = lwip_connect(s1, (struct sockaddr*)&addr, sizeof(addr));
+ LWIP_ASSERT("ret == 0", ret == 0);
+ ret = lwip_connect(s2, (struct sockaddr*)&addr, sizeof(addr));
+ LWIP_ASSERT("ret == 0", ret == 0);
+
+ /* write the start of a GET request */
+#define SNDSTR1 "G"
+ len = strlen(SNDSTR1);
+ ret = lwip_write(s1, SNDSTR1, len);
+ LWIP_ASSERT("ret == len", ret == (int)len);
+ ret = lwip_write(s2, SNDSTR1, len);
+ LWIP_ASSERT("ret == len", ret == (int)len);
+ LWIP_UNUSED_ARG(ret);
+
+ h1.wait_read = 1;
+ h1.wait_write = 1;
+ h1.wait_err = 1;
+ h1.expect_read = 0;
+ h1.expect_write = 0;
+ h1.expect_err = 0;
+ lwiperr = sys_sem_new(&h1.sem, 0);
+ LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK);
+ h1.socket = s1;
+ h1.wait_ms = 500;
+
+ h2 = h1;
+ lwiperr = sys_sem_new(&h2.sem, 0);
+ LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK);
+ h2.socket = s2;
+ h2.wait_ms = 1000;
+
+ h3 = h1;
+ lwiperr = sys_sem_new(&h3.sem, 0);
+ LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK);
+ h3.socket = s2;
+ h3.wait_ms = 1500;
+
+ h4 = h1;
+ lwiperr = sys_sem_new(&h4.sem, 0);
+ LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK);
+ LWIP_UNUSED_ARG(lwiperr);
+ h4.socket = s2;
+ h4.wait_ms = 2000;
+
+ /* select: all sockets should time out if the other side is a good HTTP server */
+
+ sys_thread_new("sockex_select_waiter1", sockex_select_waiter, &h2, 0, 0);
+ sys_msleep(100);
+ sys_thread_new("sockex_select_waiter2", sockex_select_waiter, &h1, 0, 0);
+ sys_msleep(100);
+ sys_thread_new("sockex_select_waiter2", sockex_select_waiter, &h4, 0, 0);
+ sys_msleep(100);
+ sys_thread_new("sockex_select_waiter2", sockex_select_waiter, &h3, 0, 0);
+
+ sys_sem_wait(&h1.sem);
+ sys_sem_wait(&h2.sem);
+ sys_sem_wait(&h3.sem);
+ sys_sem_wait(&h4.sem);
+
+ /* close */
+ ret = lwip_close(s1);
+ LWIP_ASSERT("ret == 0", ret == 0);
+ ret = lwip_close(s2);
+ LWIP_ASSERT("ret == 0", ret == 0);
+
+ printf("sockex_testtwoselects finished successfully\n");
+}
+#else
+static void
+sockex_testtwoselects(void *arg)
+{
+ LWIP_UNUSED_ARG(arg);
+}
+#endif
+
+#if !SOCKET_EXAMPLES_RUN_PARALLEL
+static void
+socket_example_test(void* arg)
+{
+ sys_msleep(1000);
+ sockex_nonblocking_connect(arg);
+ sockex_testrecv(arg);
+ sockex_testtwoselects(arg);
+ printf("all tests done, thread ending\n");
+}
+#endif
+
+void socket_examples_init(void)
+{
+ int addr_ok;
+#if LWIP_IPV6
+ IP_SET_TYPE_VAL(dstaddr, IPADDR_TYPE_V6);
+ addr_ok = ip6addr_aton(SOCK_TARGET_HOST6, ip_2_ip6(&dstaddr));
+#else /* LWIP_IPV6 */
+ IP_SET_TYPE_VAL(dstaddr, IPADDR_TYPE_V4);
+ addr_ok = ip4addr_aton(SOCK_TARGET_HOST4, ip_2_ip4(&dstaddr));
+#endif /* LWIP_IPV6 */
+ LWIP_ASSERT("invalid address", addr_ok);
+#if SOCKET_EXAMPLES_RUN_PARALLEL
+ sys_thread_new("sockex_nonblocking_connect", sockex_nonblocking_connect, &dstaddr, 0, 0);
+ sys_thread_new("sockex_testrecv", sockex_testrecv, &dstaddr, 0, 0);
+ sys_thread_new("sockex_testtwoselects", sockex_testtwoselects, &dstaddr, 0, 0);
+#else
+ sys_thread_new("socket_example_test", socket_example_test, &dstaddr, 0, 0);
+#endif
+}
+
+#endif /* LWIP_SOCKET */
diff --git a/contrib/apps/socket_examples/socket_examples.h b/contrib/apps/socket_examples/socket_examples.h
new file mode 100644
index 00000000000..354d03add0f
--- /dev/null
+++ b/contrib/apps/socket_examples/socket_examples.h
@@ -0,0 +1,6 @@
+#ifndef LWIP_SOCKET_EXAMPLES_H
+#define LWIP_SOCKET_EXAMPLES_H
+
+void socket_examples_init(void);
+
+#endif /* LWIP_SOCKET_EXAMPLES_H */