lwip/test/unit/api/test_sockets.c

298 lines
6.7 KiB
C

#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;
//addr6->sin6_family = AF_INET6; /* TODO: fixme! */
#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 */