You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
680 lines
19 KiB
680 lines
19 KiB
|
|
#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 |
|
|
|
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 */
|
|
|