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.
296 lines
6.7 KiB
296 lines
6.7 KiB
#include "test_sockets.h" |
|
|
|
#include "lwip/sockets.h" |
|
#include "lwip/stats.h" |
|
|
|
#include "lwip/tcpip.h" |
|
|
|
|
|
/* Setups/teardown functions */ |
|
|
|
static void |
|
sockets_setup(void) |
|
{ |
|
} |
|
|
|
static void |
|
sockets_teardown(void) |
|
{ |
|
} |
|
|
|
#ifndef NUM_SOCKETS |
|
#define NUM_SOCKETS MEMP_NUM_NETCONN |
|
#endif |
|
|
|
#if LWIP_SOCKET |
|
static int |
|
test_sockets_alloc_socket_nonblocking(int domain, int type) |
|
{ |
|
int s = lwip_socket(domain, type, 0); |
|
if (s >= 0) { |
|
int ret = lwip_fcntl(s, F_SETFL, O_NONBLOCK); |
|
fail_unless(ret == 0); |
|
} |
|
return s; |
|
} |
|
|
|
/* Verify basic sockets functionality |
|
*/ |
|
START_TEST(test_sockets_basics) |
|
{ |
|
int s, i, ret; |
|
int s2[NUM_SOCKETS]; |
|
LWIP_UNUSED_ARG(_i); |
|
|
|
s = lwip_socket(AF_INET, SOCK_STREAM, 0); |
|
fail_unless(s >= 0); |
|
lwip_close(s); |
|
|
|
for (i = 0; i < NUM_SOCKETS; i++) { |
|
s2[i] = lwip_socket(AF_INET, SOCK_STREAM, 0); |
|
fail_unless(s2[i] >= 0); |
|
} |
|
|
|
/* all sockets used, now it should fail */ |
|
s = lwip_socket(AF_INET, SOCK_STREAM, 0); |
|
fail_unless(s == -1); |
|
/* close one socket */ |
|
ret = lwip_close(s2[0]); |
|
fail_unless(ret == 0); |
|
/* now it should succeed */ |
|
s2[0] = lwip_socket(AF_INET, SOCK_STREAM, 0); |
|
fail_unless(s2[0] >= 0); |
|
|
|
/* close all sockets */ |
|
for (i = 0; i < NUM_SOCKETS; i++) { |
|
ret = lwip_close(s2[i]); |
|
fail_unless(ret == 0); |
|
} |
|
} |
|
END_TEST |
|
|
|
static void test_sockets_allfunctions_basic_domain(int domain) |
|
{ |
|
int s, s2, s3, ret; |
|
struct sockaddr_storage addr, addr2; |
|
socklen_t addrlen, addr2len; |
|
/* listen socket */ |
|
s = lwip_socket(domain, SOCK_STREAM, 0); |
|
fail_unless(s >= 0); |
|
|
|
ret = lwip_listen(s, 0); |
|
fail_unless(ret == 0); |
|
|
|
addrlen = sizeof(addr); |
|
ret = lwip_getsockname(s, (struct sockaddr*)&addr, &addrlen); |
|
fail_unless(ret == 0); |
|
|
|
s2 = test_sockets_alloc_socket_nonblocking(domain, SOCK_STREAM); |
|
fail_unless(s2 >= 0); |
|
/* nonblocking connect s2 to s (but use loopback address) */ |
|
if (domain == AF_INET) { |
|
#if LWIP_IPV4 |
|
struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; |
|
addr4->sin_addr.s_addr = PP_HTONL(INADDR_LOOPBACK); |
|
#endif |
|
} else { |
|
#if LWIP_IPV6 |
|
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; |
|
struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT; |
|
addr6->sin6_addr = lo6; |
|
#endif |
|
} |
|
ret = lwip_connect(s2, (struct sockaddr*)&addr, addrlen); |
|
fail_unless(ret == -1); |
|
fail_unless(errno == EINPROGRESS); |
|
ret = lwip_connect(s2, (struct sockaddr*)&addr, addrlen); |
|
fail_unless(ret == -1); |
|
fail_unless(errno == EALREADY); |
|
|
|
while(tcpip_thread_poll_one()); |
|
|
|
s3 = lwip_accept(s, (struct sockaddr*)&addr2, &addr2len); |
|
fail_unless(s3 >= 0); |
|
|
|
ret = lwip_connect(s2, (struct sockaddr*)&addr, addrlen); |
|
fail_unless(ret == -1); |
|
fail_unless(errno == EISCONN); |
|
|
|
ret = lwip_close(s); |
|
fail_unless(ret == 0); |
|
ret = lwip_close(s2); |
|
fail_unless(ret == 0); |
|
ret = lwip_close(s3); |
|
fail_unless(ret == 0); |
|
} |
|
|
|
/* Try to step through all sockets functions once... |
|
*/ |
|
START_TEST(test_sockets_allfunctions_basic) |
|
{ |
|
LWIP_UNUSED_ARG(_i); |
|
#if LWIP_IPV4 |
|
test_sockets_allfunctions_basic_domain(AF_INET); |
|
#endif |
|
#if LWIP_IPV6 |
|
test_sockets_allfunctions_basic_domain(AF_INET6); |
|
#endif |
|
} |
|
END_TEST |
|
|
|
static void test_sockets_sendmsg_udp_send_recv_loop(int s, struct msghdr *msg) |
|
{ |
|
int i, ret; |
|
u8_t buf[4]; |
|
|
|
/* send/receive our datagram of IO vectors 10 times */ |
|
for (i = 0; i < 10; i++) { |
|
ret = lwip_sendmsg(s, msg, 0); |
|
fail_unless(ret == 4); |
|
|
|
while (tcpip_thread_poll_one()); |
|
|
|
ret = lwip_recv(s, buf, sizeof(buf), 0); |
|
fail_unless(ret == 4); |
|
|
|
/* verify data */ |
|
fail_unless(buf[0] == 0xDE); |
|
fail_unless(buf[1] == 0xAD); |
|
fail_unless(buf[2] == 0xBE); |
|
fail_unless(buf[3] == 0xEF); |
|
} |
|
} |
|
|
|
static void test_sockets_sendmsg_udp(int domain) |
|
{ |
|
int s, i, ret; |
|
struct sockaddr_storage addr_storage; |
|
socklen_t addr_size; |
|
|
|
struct iovec iovs[4]; |
|
struct msghdr msg; |
|
u8_t bytes[4]; |
|
|
|
/* each datagram should be 0xDEADBEEF */ |
|
bytes[0] = 0xDE; |
|
bytes[1] = 0xAD; |
|
bytes[2] = 0xBE; |
|
bytes[3] = 0xEF; |
|
|
|
/* initialize IO vectors with data */ |
|
for (i = 0; i < 4; i++) { |
|
iovs[i].iov_base = &bytes[i]; |
|
iovs[i].iov_len = sizeof(char); |
|
} |
|
|
|
/* set up address to send to */ |
|
memset(&addr_storage, 0, sizeof(addr_storage)); |
|
switch(domain) { |
|
#if LWIP_IPV6 |
|
case AF_INET6: { |
|
struct sockaddr_in6 *addr = (struct sockaddr_in6*)&addr_storage; |
|
struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT; |
|
addr->sin6_family = AF_INET6; |
|
addr->sin6_port = 0; /* use ephemeral port */ |
|
addr->sin6_addr = lo6; |
|
addr_size = sizeof(*addr); |
|
} |
|
break; |
|
#endif /* LWIP_IPV6 */ |
|
#if LWIP_IPV4 |
|
case AF_INET: { |
|
struct sockaddr_in *addr = (struct sockaddr_in*)&addr_storage; |
|
addr->sin_family = AF_INET; |
|
addr->sin_port = 0; /* use ephemeral port */ |
|
addr->sin_addr.s_addr = PP_HTONL(INADDR_LOOPBACK); |
|
addr_size = sizeof(*addr); |
|
} |
|
break; |
|
#endif /* LWIP_IPV4 */ |
|
default: |
|
fail(); |
|
break; |
|
} |
|
|
|
s = test_sockets_alloc_socket_nonblocking(domain, SOCK_DGRAM); |
|
fail_unless(s >= 0); |
|
|
|
ret = lwip_bind(s, (struct sockaddr*)&addr_storage, addr_size); |
|
fail_unless(ret == 0); |
|
|
|
/* Update addr with epehermal port */ |
|
ret = lwip_getsockname(s, (struct sockaddr*)&addr_storage, &addr_size); |
|
fail_unless(ret == 0); |
|
switch(domain) { |
|
#if LWIP_IPV6 |
|
case AF_INET6: |
|
fail_unless(addr_size == sizeof(struct sockaddr_in6)); |
|
break; |
|
#endif /* LWIP_IPV6 */ |
|
#if LWIP_IPV4 |
|
case AF_INET: |
|
fail_unless(addr_size == sizeof(struct sockaddr_in)); |
|
break; |
|
#endif /* LWIP_IPV6 */ |
|
default: |
|
fail(); |
|
break; |
|
} |
|
|
|
msg.msg_iov = iovs; |
|
msg.msg_iovlen = 4; |
|
msg.msg_control = NULL; |
|
msg.msg_controllen = 0; |
|
msg.msg_flags = 0; |
|
|
|
/* perform a sendmsg with remote host (self) */ |
|
msg.msg_name = &addr_storage; |
|
msg.msg_namelen = addr_size; |
|
|
|
test_sockets_sendmsg_udp_send_recv_loop(s, &msg); |
|
|
|
/* Connect to self, allowing us to not pass message name */ |
|
ret = lwip_connect(s, (struct sockaddr*)&addr_storage, addr_size); |
|
fail_unless(ret == 0); |
|
|
|
msg.msg_name = NULL; |
|
msg.msg_namelen = 0; |
|
|
|
test_sockets_sendmsg_udp_send_recv_loop(s, &msg); |
|
|
|
ret = lwip_close(s); |
|
fail_unless(ret == 0); |
|
} |
|
|
|
START_TEST(test_sockets_sendmsg) |
|
{ |
|
LWIP_UNUSED_ARG(_i); |
|
#if LWIP_IPV4 |
|
test_sockets_sendmsg_udp(AF_INET); |
|
#endif |
|
#if LWIP_IPV6 |
|
test_sockets_sendmsg_udp(AF_INET6); |
|
#endif |
|
} |
|
END_TEST |
|
|
|
/** Create the suite including all tests for this module */ |
|
Suite * |
|
sockets_suite(void) |
|
{ |
|
testfunc tests[] = { |
|
TESTFUNC(test_sockets_basics), |
|
TESTFUNC(test_sockets_allfunctions_basic), |
|
TESTFUNC(test_sockets_sendmsg), |
|
}; |
|
return create_suite("SOCKETS", tests, sizeof(tests)/sizeof(testfunc), sockets_setup, sockets_teardown); |
|
} |
|
|
|
#else /* LWIP_SOCKET */ |
|
|
|
Suite * |
|
sockets_suite(void) |
|
{ |
|
return create_suite("SOCKETS", NULL, 0, NULL, NULL); |
|
} |
|
#endif /* LWIP_SOCKET */
|
|
|