Init commit

This commit is contained in:
2021-04-27 17:22:34 +02:00
commit 4f6fe6959f
1140 changed files with 1174277 additions and 0 deletions

View File

@ -0,0 +1,31 @@
# This file is indended to be included in end-user CMakeLists.txt
# include(/path/to/Filelists.cmake)
# It assumes the variable LWIP_DIR is defined pointing to the
# root path of lwIP sources.
#
# This file is NOT designed (on purpose) to be used as cmake
# subdir via add_subdirectory()
# The intention is to provide greater flexibility to users to
# create their own targets using the *_SRCS variables.
set(LWIP_TESTDIR ${LWIP_DIR}/test/unit)
set(LWIP_TESTFILES
${LWIP_TESTDIR}/lwip_unittests.c
${LWIP_TESTDIR}/api/test_sockets.c
${LWIP_TESTDIR}/arch/sys_arch.c
${LWIP_TESTDIR}/core/test_def.c
${LWIP_TESTDIR}/core/test_mem.c
${LWIP_TESTDIR}/core/test_netif.c
${LWIP_TESTDIR}/core/test_pbuf.c
${LWIP_TESTDIR}/core/test_timers.c
${LWIP_TESTDIR}/dhcp/test_dhcp.c
${LWIP_TESTDIR}/etharp/test_etharp.c
${LWIP_TESTDIR}/ip4/test_ip4.c
${LWIP_TESTDIR}/ip6/test_ip6.c
${LWIP_TESTDIR}/mdns/test_mdns.c
${LWIP_TESTDIR}/mqtt/test_mqtt.c
${LWIP_TESTDIR}/tcp/tcp_helper.c
${LWIP_TESTDIR}/tcp/test_tcp_oos.c
${LWIP_TESTDIR}/tcp/test_tcp.c
${LWIP_TESTDIR}/udp/test_udp.c
)

View File

@ -0,0 +1,51 @@
#
# Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# 3. The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
# SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
# OF SUCH DAMAGE.
#
# This file is part of the lwIP TCP/IP stack.
#
# Author: Adam Dunkels <adam@sics.se>
#
TESTDIR=$(LWIPDIR)/../test/unit
TESTFILES=$(TESTDIR)/lwip_unittests.c \
$(TESTDIR)/api/test_sockets.c \
$(TESTDIR)/arch/sys_arch.c \
$(TESTDIR)/core/test_def.c \
$(TESTDIR)/core/test_mem.c \
$(TESTDIR)/core/test_netif.c \
$(TESTDIR)/core/test_pbuf.c \
$(TESTDIR)/core/test_timers.c \
$(TESTDIR)/dhcp/test_dhcp.c \
$(TESTDIR)/etharp/test_etharp.c \
$(TESTDIR)/ip4/test_ip4.c \
$(TESTDIR)/ip6/test_ip6.c \
$(TESTDIR)/mdns/test_mdns.c \
$(TESTDIR)/mqtt/test_mqtt.c \
$(TESTDIR)/tcp/tcp_helper.c \
$(TESTDIR)/tcp/test_tcp_oos.c \
$(TESTDIR)/tcp/test_tcp.c \
$(TESTDIR)/udp/test_udp.c

View File

@ -0,0 +1,852 @@
#include "test_sockets.h"
#include "lwip/mem.h"
#include "lwip/opt.h"
#include "lwip/sockets.h"
#include "lwip/priv/sockets_priv.h"
#include "lwip/stats.h"
#include "lwip/tcpip.h"
#include "lwip/priv/tcp_priv.h"
#include "lwip/api.h"
static int
test_sockets_get_used_count(void)
{
int used = 0;
int i;
for (i = 0; i < NUM_SOCKETS; i++) {
struct lwip_sock* s = lwip_socket_dbg_get_socket(i);
if (s != NULL) {
if (s->fd_used) {
used++;
}
}
}
return used;
}
/* Setups/teardown functions */
static void
sockets_setup(void)
{
/* expect full free heap */
lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
}
static void
sockets_teardown(void)
{
fail_unless(test_sockets_get_used_count() == 0);
/* poll until all memory is released... */
tcpip_thread_poll_one();
while (tcp_tw_pcbs) {
tcp_abort(tcp_tw_pcbs);
tcpip_thread_poll_one();
}
tcpip_thread_poll_one();
/* ensure full free heap */
lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
}
#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;
char buf[4];
/* 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);
/* write from server to client */
ret = write(s3, "test", 4);
fail_unless(ret == 4);
ret = lwip_shutdown(s3, SHUT_WR);
fail_unless(ret == 0);
while(tcpip_thread_poll_one());
ret = lwip_recv(s2, buf, 3, MSG_PEEK);
fail_unless(ret == 3);
ret = lwip_recv(s2, buf, 3, MSG_PEEK);
fail_unless(ret == 3);
ret = lwip_read(s2, buf, 4);
fail_unless(ret == 4);
ret = lwip_read(s2, buf, 1);
fail_unless(ret == 0);
ret = lwip_read(s2, buf, 1);
fail_unless(ret == -1);
ret = lwip_write(s2, "foo", 3);
fail_unless(ret == 3);
ret = lwip_close(s2);
fail_unless(ret == 0);
while(tcpip_thread_poll_one());
/* read one byte more than available to check handling FIN */
ret = lwip_read(s3, buf, 4);
fail_unless(ret == 3);
ret = lwip_read(s3, buf, 1);
fail_unless(ret == 0);
ret = lwip_read(s3, buf, 1);
fail_unless(ret == -1);
while(tcpip_thread_poll_one());
ret = lwip_close(s);
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_init_loopback_addr(int domain, struct sockaddr_storage *addr_st, socklen_t *sz)
{
memset(addr_st, 0, sizeof(*addr_st));
switch(domain) {
#if LWIP_IPV6
case AF_INET6: {
struct sockaddr_in6 *addr = (struct sockaddr_in6*)addr_st;
struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT;
addr->sin6_family = AF_INET6;
addr->sin6_port = 0; /* use ephemeral port */
addr->sin6_addr = lo6;
*sz = sizeof(*addr);
}
break;
#endif /* LWIP_IPV6 */
#if LWIP_IPV4
case AF_INET: {
struct sockaddr_in *addr = (struct sockaddr_in*)addr_st;
addr->sin_family = AF_INET;
addr->sin_port = 0; /* use ephemeral port */
addr->sin_addr.s_addr = PP_HTONL(INADDR_LOOPBACK);
*sz = sizeof(*addr);
}
break;
#endif /* LWIP_IPV4 */
default:
*sz = 0;
fail();
break;
}
}
static void test_sockets_msgapi_update_iovs(struct msghdr *msg, size_t bytes)
{
int i;
/* note: this modifies the underyling iov_base and iov_len for a partial
read for an individual vector. This updates the msg->msg_iov pointer
to skip fully consumed vecotrs */
/* process fully consumed vectors */
for (i = 0; i < msg->msg_iovlen; i++) {
if (msg->msg_iov[i].iov_len <= bytes) {
/* reduce bytes by amount of this vector */
bytes -= msg->msg_iov[i].iov_len;
} else {
break; /* iov not fully consumed */
}
}
/* slide down over fully consumed vectors */
msg->msg_iov = &msg->msg_iov[i];
msg->msg_iovlen -= i;
/* update new first vector with any remaining amount */
msg->msg_iov[0].iov_base = ((u8_t *)msg->msg_iov[0].iov_base + bytes);
msg->msg_iov[0].iov_len -= bytes;
}
static void test_sockets_msgapi_tcp(int domain)
{
#define BUF_SZ (TCP_SND_BUF/4)
#define TOTAL_DATA_SZ (BUF_SZ*8) /* ~(TCP_SND_BUF*2) that accounts for integer rounding */
#define NEED_TRAILER (BUF_SZ % 4 != 0)
int listnr, s1, s2, i, ret, opt;
int bytes_written, bytes_read;
struct sockaddr_storage addr_storage;
socklen_t addr_size;
struct iovec siovs[8];
struct msghdr smsg;
u8_t * snd_buf;
struct iovec riovs[5];
struct iovec riovs_tmp[5];
struct msghdr rmsg;
u8_t * rcv_buf;
int rcv_off;
int rcv_trailer = 0;
u8_t val;
test_sockets_init_loopback_addr(domain, &addr_storage, &addr_size);
listnr = test_sockets_alloc_socket_nonblocking(domain, SOCK_STREAM);
fail_unless(listnr >= 0);
s1 = test_sockets_alloc_socket_nonblocking(domain, SOCK_STREAM);
fail_unless(s1 >= 0);
/* setup a listener socket on loopback with ephemeral port */
ret = lwip_bind(listnr, (struct sockaddr*)&addr_storage, addr_size);
fail_unless(ret == 0);
ret = lwip_listen(listnr, 0);
fail_unless(ret == 0);
/* update address with ephemeral port */
ret = lwip_getsockname(listnr, (struct sockaddr*)&addr_storage, &addr_size);
fail_unless(ret == 0);
/* connect, won't complete until we accept it */
ret = lwip_connect(s1, (struct sockaddr*)&addr_storage, addr_size);
fail_unless(ret == -1);
fail_unless(errno == EINPROGRESS);
while (tcpip_thread_poll_one());
/* accept, creating the other side of the connection */
s2 = lwip_accept(listnr, NULL, NULL);
fail_unless(s2 >= 0);
/* double check s1 is connected */
ret = lwip_connect(s1, (struct sockaddr*)&addr_storage, addr_size);
fail_unless(ret == -1);
fail_unless(errno == EISCONN);
/* set s2 to non-blocking, not inherited from listener */
opt = lwip_fcntl(s2, F_GETFL, 0);
fail_unless(opt == 6);
opt = O_NONBLOCK;
ret = lwip_fcntl(s2, F_SETFL, opt);
fail_unless(ret == 0);
/* we are done with listener, close it */
ret = lwip_close(listnr);
fail_unless(ret == 0);
/* allocate a buffer for a stream of incrementing hex (0x00..0xFF) which we will use
to create an input vector set that is larger than the TCP's send buffer. This will
force execution of the partial IO vector send case */
snd_buf = (u8_t*)mem_malloc(BUF_SZ);
val = 0x00;
fail_unless(snd_buf != NULL);
for (i = 0; i < BUF_SZ; i++,val++) {
snd_buf[i] = val;
}
/* send the buffer 8 times in one message, equating to TOTAL_DATA_SZ */
for (i = 0; i < 8; i++) {
siovs[i].iov_base = snd_buf;
siovs[i].iov_len = BUF_SZ;
}
/* allocate a receive buffer, same size as snd_buf for easy verification */
rcv_buf = (u8_t*)mem_calloc(1, BUF_SZ);
fail_unless(rcv_buf != NULL);
/* split across iovs */
for (i = 0; i < 4; i++) {
riovs[i].iov_base = &rcv_buf[i*(BUF_SZ/4)];
riovs[i].iov_len = BUF_SZ/4;
}
/* handling trailing bytes if buffer doesn't evenly divide by 4 */
#if NEED_TRAILER
if ((BUF_SZ % 4) != 0) {
riovs[5].iov_base = &rcv_buf[4*(BUF_SZ/4)];
riovs[5].iov_len = BUF_SZ - (4*(BUF_SZ/4));
rcv_trailer = 1;
}
#endif /* NEED_TRAILER */
/* we use a copy of riovs since we'll be modifying base and len during
receiving. This gives us an easy way to reset the iovs for next recvmsg */
memcpy(riovs_tmp, riovs, sizeof(riovs));
memset(&smsg, 0, sizeof(smsg));
smsg.msg_iov = siovs;
smsg.msg_iovlen = 8;
memset(&rmsg, 0, sizeof(rmsg));
rmsg.msg_iov = riovs_tmp;
rmsg.msg_iovlen = (rcv_trailer ? 5 : 4);
bytes_written = 0;
bytes_read = 0;
rcv_off = 0;
while (bytes_written < TOTAL_DATA_SZ && (bytes_read < TOTAL_DATA_SZ)) {
/* send data */
if (bytes_written < TOTAL_DATA_SZ) {
ret = lwip_sendmsg(s1, &smsg, 0);
/* note: since we always receive after sending, there will be open
space in the send buffer */
fail_unless(ret > 0);
bytes_written += ret;
if (bytes_written < TOTAL_DATA_SZ) {
test_sockets_msgapi_update_iovs(&smsg, (size_t)ret);
}
}
while (tcpip_thread_poll_one());
/* receive and verify data */
do {
if (bytes_read < TOTAL_DATA_SZ) {
ret = lwip_recvmsg(s2, &rmsg, 0);
fail_unless(ret > 0 || (ret == -1 && errno == EWOULDBLOCK));
if (ret > 0) {
rcv_off += ret;
/* we have received a full buffer */
if (rcv_off == BUF_SZ) {
/* note: since iovs are just pointers, compare underlying buf */
fail_unless(!memcmp(snd_buf, rcv_buf, BUF_SZ));
bytes_read += BUF_SZ;
/* reset receive state for next buffer */
rcv_off = 0;
memset(rcv_buf, 0, BUF_SZ);
memcpy(riovs_tmp, riovs, sizeof(riovs));
rmsg.msg_iov = riovs_tmp;
rmsg.msg_iovlen = (rcv_trailer ? 5 : 4);
} else { /* partial read */
test_sockets_msgapi_update_iovs(&rmsg, (size_t)ret);
}
}
} else {
break;
}
} while(ret > 0);
}
ret = lwip_close(s1);
fail_unless(ret == 0);
ret = lwip_close(s2);
fail_unless(ret == 0);
mem_free(snd_buf);
mem_free(rcv_buf);
}
static void test_sockets_msgapi_udp_send_recv_loop(int s, struct msghdr *smsg, struct msghdr *rmsg)
{
int i, ret;
/* send/receive our datagram of IO vectors 10 times */
for (i = 0; i < 10; i++) {
ret = lwip_sendmsg(s, smsg, 0);
fail_unless(ret == 4);
while (tcpip_thread_poll_one());
/* receive the datagram split across 4 buffers */
ret = lwip_recvmsg(s, rmsg, 0);
fail_unless(ret == 4);
/* verify data */
fail_unless(*((u8_t*)rmsg->msg_iov[0].iov_base) == 0xDE);
fail_unless(*((u8_t*)rmsg->msg_iov[1].iov_base) == 0xAD);
fail_unless(*((u8_t*)rmsg->msg_iov[2].iov_base) == 0xBE);
fail_unless(*((u8_t*)rmsg->msg_iov[3].iov_base) == 0xEF);
/* clear rcv_buf to ensure no data is being skipped */
*((u8_t*)rmsg->msg_iov[0].iov_base) = 0x00;
*((u8_t*)rmsg->msg_iov[1].iov_base) = 0x00;
*((u8_t*)rmsg->msg_iov[2].iov_base) = 0x00;
*((u8_t*)rmsg->msg_iov[3].iov_base) = 0x00;
}
}
static void test_sockets_msgapi_udp(int domain)
{
int s, i, ret;
struct sockaddr_storage addr_storage;
socklen_t addr_size;
struct iovec riovs[4];
struct msghdr rmsg;
u8_t rcv_buf[4];
struct iovec siovs[4];
struct msghdr smsg;
u8_t snd_buf[4] = {0xDE, 0xAD, 0xBE, 0xEF};
/* initialize IO vectors with data */
for (i = 0; i < 4; i++) {
siovs[i].iov_base = &snd_buf[i];
siovs[i].iov_len = sizeof(u8_t);
riovs[i].iov_base = &rcv_buf[i];
riovs[i].iov_len = sizeof(u8_t);
}
test_sockets_init_loopback_addr(domain, &addr_storage, &addr_size);
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;
}
/* send and receive the datagram in 4 pieces */
memset(&smsg, 0, sizeof(smsg));
smsg.msg_iov = siovs;
smsg.msg_iovlen = 4;
memset(&rmsg, 0, sizeof(rmsg));
rmsg.msg_iov = riovs;
rmsg.msg_iovlen = 4;
/* perform a sendmsg with remote host (self) */
smsg.msg_name = &addr_storage;
smsg.msg_namelen = addr_size;
test_sockets_msgapi_udp_send_recv_loop(s, &smsg, &rmsg);
/* Connect to self, allowing us to not pass message name */
ret = lwip_connect(s, (struct sockaddr*)&addr_storage, addr_size);
fail_unless(ret == 0);
smsg.msg_name = NULL;
smsg.msg_namelen = 0;
test_sockets_msgapi_udp_send_recv_loop(s, &smsg, &rmsg);
ret = lwip_close(s);
fail_unless(ret == 0);
}
#if LWIP_IPV4
static void test_sockets_msgapi_cmsg(int domain)
{
int s, ret, enable;
struct sockaddr_storage addr_storage;
socklen_t addr_size;
struct iovec iov;
struct msghdr msg;
struct cmsghdr *cmsg;
struct in_pktinfo *pktinfo;
u8_t rcv_buf[4];
u8_t snd_buf[4] = {0xDE, 0xAD, 0xBE, 0xEF};
u8_t cmsg_buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
test_sockets_init_loopback_addr(domain, &addr_storage, &addr_size);
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);
enable = 1;
ret = lwip_setsockopt(s, IPPROTO_IP, IP_PKTINFO, &enable, sizeof(enable));
fail_unless(ret == 0);
/* Receive full message, including control message */
iov.iov_base = rcv_buf;
iov.iov_len = sizeof(rcv_buf);
msg.msg_control = cmsg_buf;
msg.msg_controllen = sizeof(cmsg_buf);
msg.msg_flags = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
memset(rcv_buf, 0, sizeof(rcv_buf));
ret = lwip_sendto(s, snd_buf, sizeof(snd_buf), 0, (struct sockaddr*)&addr_storage, addr_size);
fail_unless(ret == sizeof(snd_buf));
tcpip_thread_poll_one();
ret = lwip_recvmsg(s, &msg, 0);
fail_unless(ret == sizeof(rcv_buf));
fail_unless(!memcmp(rcv_buf, snd_buf, sizeof(rcv_buf)));
/* Verify message header */
cmsg = CMSG_FIRSTHDR(&msg);
fail_unless(cmsg != NULL);
fail_unless(cmsg->cmsg_len > 0);
fail_unless(cmsg->cmsg_level == IPPROTO_IP);
fail_unless(cmsg->cmsg_type == IP_PKTINFO);
/* Verify message data */
pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
/* We only have loopback interface enabled */
fail_unless(pktinfo->ipi_ifindex == 1);
fail_unless(pktinfo->ipi_addr.s_addr == PP_HTONL(INADDR_LOOPBACK));
/* Verify there are no additional messages */
cmsg = CMSG_NXTHDR(&msg, cmsg);
fail_unless(cmsg == NULL);
/* Send datagram again, testing truncation */
memset(rcv_buf, 0, sizeof(rcv_buf));
ret = lwip_sendto(s, snd_buf, sizeof(snd_buf), 0, (struct sockaddr*)&addr_storage, addr_size);
fail_unless(ret == sizeof(snd_buf));
tcpip_thread_poll_one();
msg.msg_controllen = 1;
msg.msg_flags = 0;
ret = lwip_recvmsg(s, &msg, 0);
fail_unless(ret == sizeof(rcv_buf));
fail_unless(!memcmp(rcv_buf, snd_buf, sizeof(rcv_buf)));
/* Ensure truncation was returned */
fail_unless(msg.msg_flags & MSG_CTRUNC);
/* Ensure no control messages were returned */
fail_unless(msg.msg_controllen == 0);
ret = lwip_close(s);
fail_unless(ret == 0);
}
#endif /* LWIP_IPV4 */
START_TEST(test_sockets_msgapis)
{
LWIP_UNUSED_ARG(_i);
#if LWIP_IPV4
test_sockets_msgapi_udp(AF_INET);
test_sockets_msgapi_tcp(AF_INET);
test_sockets_msgapi_cmsg(AF_INET);
#endif
#if LWIP_IPV6
test_sockets_msgapi_udp(AF_INET6);
test_sockets_msgapi_tcp(AF_INET6);
#endif
}
END_TEST
START_TEST(test_sockets_select)
{
#if LWIP_SOCKET_SELECT
int s;
int ret;
fd_set readset;
fd_set writeset;
fd_set errset;
struct timeval tv;
fail_unless(test_sockets_get_used_count() == 0);
s = lwip_socket(AF_INET, SOCK_STREAM, 0);
fail_unless(s >= 0);
fail_unless(test_sockets_get_used_count() == 0);
FD_ZERO(&readset);
FD_SET(s, &readset);
FD_ZERO(&writeset);
FD_SET(s, &writeset);
FD_ZERO(&errset);
FD_SET(s, &errset);
tv.tv_sec = tv.tv_usec = 0;
ret = lwip_select(s + 1, &readset, &writeset, &errset, &tv);
fail_unless(ret == 0);
fail_unless(test_sockets_get_used_count() == 0);
ret = lwip_close(s);
fail_unless(ret == 0);
#endif
LWIP_UNUSED_ARG(_i);
}
END_TEST
START_TEST(test_sockets_recv_after_rst)
{
int sl, sact;
int spass = -1;
int ret;
struct sockaddr_in sa_listen;
const u16_t port = 1234;
int arg;
const char txbuf[] = "something";
char rxbuf[16];
struct lwip_sock *sact_sock;
int err;
LWIP_UNUSED_ARG(_i);
fail_unless(test_sockets_get_used_count() == 0);
memset(&sa_listen, 0, sizeof(sa_listen));
sa_listen.sin_family = AF_INET;
sa_listen.sin_port = PP_HTONS(port);
sa_listen.sin_addr.s_addr = PP_HTONL(INADDR_LOOPBACK);
/* set up the listener */
sl = lwip_socket(AF_INET, SOCK_STREAM, 0);
fail_unless(sl >= 0);
fail_unless(test_sockets_get_used_count() == 0);
ret = lwip_bind(sl, (struct sockaddr *)&sa_listen, sizeof(sa_listen));
fail_unless(ret == 0);
ret = lwip_listen(sl, 0);
fail_unless(ret == 0);
/* set up the client */
sact = lwip_socket(AF_INET, SOCK_STREAM, 0);
fail_unless(sact >= 0);
fail_unless(test_sockets_get_used_count() == 0);
/* set the client to nonblocking to simplify this test */
arg = 1;
ret = lwip_ioctl(sact, FIONBIO, &arg);
fail_unless(ret == 0);
/* connect */
do {
ret = lwip_connect(sact, (struct sockaddr *)&sa_listen, sizeof(sa_listen));
err = errno;
fail_unless((ret == 0) || (ret == -1));
if (ret != 0) {
if (err == EISCONN) {
/* Although this is not valid, use EISCONN as an indicator for successful connection.
This marks us as "connect phase is done". On error, we would either have a different
errno code or "send" fails later... -> good enough for this test. */
ret = 0;
} else {
fail_unless(err == EINPROGRESS);
if (err != EINPROGRESS) {
goto cleanup;
}
/* we're in progress: little side check: test for EALREADY */
ret = lwip_connect(sact, (struct sockaddr *)&sa_listen, sizeof(sa_listen));
err = errno;
fail_unless(ret == -1);
fail_unless(err == EALREADY);
if ((ret != -1) || (err != EALREADY)) {
goto cleanup;
}
}
tcpip_thread_poll_one();
tcpip_thread_poll_one();
tcpip_thread_poll_one();
tcpip_thread_poll_one();
}
} while (ret != 0);
fail_unless(ret == 0);
/* accept the server connection part */
spass = lwip_accept(sl, NULL, NULL);
fail_unless(spass >= 0);
/* write data from client */
ret = lwip_send(sact, txbuf, sizeof(txbuf), 0);
fail_unless(ret == sizeof(txbuf));
tcpip_thread_poll_one();
tcpip_thread_poll_one();
/* issue RST (This is a HACK, don't try this in your own app!) */
sact_sock = lwip_socket_dbg_get_socket(sact);
fail_unless(sact_sock != NULL);
if (sact_sock != NULL) {
struct netconn *sact_conn = sact_sock->conn;
fail_unless(sact_conn != NULL);
if (sact_conn != NULL) {
struct tcp_pcb *pcb = sact_conn->pcb.tcp;
fail_unless(pcb != NULL);
if (pcb != NULL) {
tcp_rst(pcb, pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
pcb->local_port, pcb->remote_port);
}
}
}
tcpip_thread_poll_one();
tcpip_thread_poll_one();
/* expect to receive data first */
ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
fail_unless(ret > 0);
tcpip_thread_poll_one();
tcpip_thread_poll_one();
/* expect to receive RST indication */
ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
fail_unless(ret == -1);
err = errno;
fail_unless(err == ECONNRESET);
tcpip_thread_poll_one();
tcpip_thread_poll_one();
/* expect to receive ENOTCONN indication */
ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
fail_unless(ret == -1);
err = errno;
fail_unless(err == ENOTCONN);
tcpip_thread_poll_one();
tcpip_thread_poll_one();
/* expect to receive ENOTCONN indication */
ret = lwip_recv(spass, rxbuf, sizeof(rxbuf), 0);
fail_unless(ret == -1);
err = errno;
fail_unless(err == ENOTCONN);
tcpip_thread_poll_one();
tcpip_thread_poll_one();
cleanup:
ret = lwip_close(sl);
fail_unless(ret == 0);
ret = lwip_close(sact);
fail_unless(ret == 0);
if (spass >= 0) {
ret = lwip_close(spass);
fail_unless(ret == 0);
}
}
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_msgapis),
TESTFUNC(test_sockets_select),
TESTFUNC(test_sockets_recv_after_rst),
};
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 */

View File

@ -0,0 +1,8 @@
#ifndef LWIP_HDR_TEST_SOCKETS_H
#define LWIP_HDR_TEST_SOCKETS_H
#include "../lwip_check.h"
Suite *sockets_suite(void);
#endif

View File

@ -0,0 +1,371 @@
/*
* Copyright (c) 2017 Simon Goldschmidt
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Simon Goldschmidt
*
*/
#include <lwip/opt.h>
#include <lwip/arch.h>
#if !NO_SYS
#include "sys_arch.h"
#endif
#include <lwip/stats.h>
#include <lwip/debug.h>
#include <lwip/sys.h>
#include <string.h>
u32_t lwip_sys_now;
u32_t
sys_jiffies(void)
{
return lwip_sys_now;
}
u32_t
sys_now(void)
{
return lwip_sys_now;
}
void
sys_init(void)
{
}
#if !NO_SYS
test_sys_arch_waiting_fn the_waiting_fn;
void
test_sys_arch_wait_callback(test_sys_arch_waiting_fn waiting_fn)
{
the_waiting_fn = waiting_fn;
}
err_t
sys_sem_new(sys_sem_t *sem, u8_t count)
{
LWIP_ASSERT("sem != NULL", sem != NULL);
*sem = count + 1;
return ERR_OK;
}
void
sys_sem_free(sys_sem_t *sem)
{
LWIP_ASSERT("sem != NULL", sem != NULL);
*sem = 0;
}
void
sys_sem_set_invalid(sys_sem_t *sem)
{
LWIP_ASSERT("sem != NULL", sem != NULL);
*sem = 0;
}
/* semaphores are 1-based because RAM is initialized as 0, which would be valid */
u32_t
sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
{
u32_t ret = 0;
LWIP_ASSERT("sem != NULL", sem != NULL);
LWIP_ASSERT("*sem > 0", *sem > 0);
if (*sem == 1) {
/* need to wait */
if(!timeout)
{
/* wait infinite */
LWIP_ASSERT("cannot wait without waiting callback", the_waiting_fn != NULL);
do {
int expectSomething = the_waiting_fn(sem, NULL);
LWIP_ASSERT("*sem > 0", *sem > 0);
LWIP_ASSERT("expecting a semaphore count but it's 0", !expectSomething || (*sem > 1));
ret++;
if (ret == SYS_ARCH_TIMEOUT) {
ret--;
}
} while(*sem == 1);
}
else
{
if (the_waiting_fn) {
int expectSomething = the_waiting_fn(sem, NULL);
LWIP_ASSERT("expecting a semaphore count but it's 0", !expectSomething || (*sem > 1));
}
LWIP_ASSERT("*sem > 0", *sem > 0);
if (*sem == 1) {
return SYS_ARCH_TIMEOUT;
}
ret = 1;
}
}
LWIP_ASSERT("*sem > 0", *sem > 0);
(*sem)--;
LWIP_ASSERT("*sem > 0", *sem > 0);
/* return the time we waited for the sem */
return ret;
}
void
sys_sem_signal(sys_sem_t *sem)
{
LWIP_ASSERT("sem != NULL", sem != NULL);
LWIP_ASSERT("*sem > 0", *sem > 0);
(*sem)++;
LWIP_ASSERT("*sem > 0", *sem > 0);
}
err_t
sys_mutex_new(sys_mutex_t *mutex)
{
LWIP_ASSERT("mutex != NULL", mutex != NULL);
*mutex = 1; /* 1 allocated */
return ERR_OK;
}
void
sys_mutex_free(sys_mutex_t *mutex)
{
/* parameter check */
LWIP_ASSERT("mutex != NULL", mutex != NULL);
LWIP_ASSERT("*mutex >= 1", *mutex >= 1);
*mutex = 0;
}
void
sys_mutex_set_invalid(sys_mutex_t *mutex)
{
LWIP_ASSERT("mutex != NULL", mutex != NULL);
*mutex = 0;
}
void
sys_mutex_lock(sys_mutex_t *mutex)
{
/* nothing to do, no multithreading supported */
LWIP_ASSERT("mutex != NULL", mutex != NULL);
/* check that the mutext is valid and unlocked (no nested locking) */
LWIP_ASSERT("*mutex >= 1", *mutex == 1);
/* we count up just to check the correct pairing of lock/unlock */
(*mutex)++;
LWIP_ASSERT("*mutex >= 1", *mutex >= 1);
}
void
sys_mutex_unlock(sys_mutex_t *mutex)
{
/* nothing to do, no multithreading supported */
LWIP_ASSERT("mutex != NULL", mutex != NULL);
LWIP_ASSERT("*mutex >= 1", *mutex >= 1);
/* we count down just to check the correct pairing of lock/unlock */
(*mutex)--;
LWIP_ASSERT("*mutex >= 1", *mutex >= 1);
}
sys_thread_t
sys_thread_new(const char *name, lwip_thread_fn function, void *arg, int stacksize, int prio)
{
LWIP_UNUSED_ARG(name);
LWIP_UNUSED_ARG(function);
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(stacksize);
LWIP_UNUSED_ARG(prio);
/* threads not supported */
return 0;
}
err_t
sys_mbox_new(sys_mbox_t *mbox, int size)
{
int mboxsize = size;
LWIP_ASSERT("mbox != NULL", mbox != NULL);
LWIP_ASSERT("size >= 0", size >= 0);
if (size == 0) {
mboxsize = 1024;
}
mbox->head = mbox->tail = 0;
mbox->sem = mbox; /* just point to something for sys_mbox_valid() */
mbox->q_mem = (void**)malloc(sizeof(void*)*mboxsize);
mbox->size = mboxsize;
mbox->used = 0;
memset(mbox->q_mem, 0, sizeof(void*)*mboxsize);
return ERR_OK;
}
void
sys_mbox_free(sys_mbox_t *mbox)
{
/* parameter check */
LWIP_ASSERT("mbox != NULL", mbox != NULL);
LWIP_ASSERT("mbox->sem != NULL", mbox->sem != NULL);
LWIP_ASSERT("mbox->sem == mbox", mbox->sem == mbox);
LWIP_ASSERT("mbox->q_mem != NULL", mbox->q_mem != NULL);
mbox->sem = NULL;
free(mbox->q_mem);
mbox->q_mem = NULL;
}
void
sys_mbox_set_invalid(sys_mbox_t *mbox)
{
LWIP_ASSERT("mbox != NULL", mbox != NULL);
LWIP_ASSERT("mbox->q_mem == NULL", mbox->q_mem == NULL);
mbox->sem = NULL;
mbox->q_mem = NULL;
}
void
sys_mbox_post(sys_mbox_t *q, void *msg)
{
LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL);
LWIP_ASSERT("q->sem == q", q->sem == q);
LWIP_ASSERT("q->q_mem != NULL", q->q_mem != NULL);
LWIP_ASSERT("q->used >= 0", q->used >= 0);
LWIP_ASSERT("q->size > 0", q->size > 0);
LWIP_ASSERT("mbox already full", q->used < q->size);
q->q_mem[q->head] = msg;
q->head++;
if (q->head >= (unsigned int)q->size) {
q->head = 0;
}
LWIP_ASSERT("mbox is full!", q->head != q->tail);
q->used++;
}
err_t
sys_mbox_trypost(sys_mbox_t *q, void *msg)
{
LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL);
LWIP_ASSERT("q->sem == q", q->sem == q);
LWIP_ASSERT("q->q_mem != NULL", q->q_mem != NULL);
LWIP_ASSERT("q->used >= 0", q->used >= 0);
LWIP_ASSERT("q->size > 0", q->size > 0);
LWIP_ASSERT("q->used <= q->size", q->used <= q->size);
if (q->used == q->size) {
return ERR_MEM;
}
sys_mbox_post(q, msg);
return ERR_OK;
}
err_t
sys_mbox_trypost_fromisr(sys_mbox_t *q, void *msg)
{
return sys_mbox_trypost(q, msg);
}
u32_t
sys_arch_mbox_fetch(sys_mbox_t *q, void **msg, u32_t timeout)
{
u32_t ret = 0;
u32_t ret2;
LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL);
LWIP_ASSERT("q->sem == q", q->sem == q);
LWIP_ASSERT("q->q_mem != NULL", q->q_mem != NULL);
LWIP_ASSERT("q->used >= 0", q->used >= 0);
LWIP_ASSERT("q->size > 0", q->size > 0);
if (q->used == 0) {
/* need to wait */
/* need to wait */
if(!timeout)
{
/* wait infinite */
LWIP_ASSERT("cannot wait without waiting callback", the_waiting_fn != NULL);
do {
int expectSomething = the_waiting_fn(NULL, q);
LWIP_ASSERT("q->used >= 0", q->used >= 0);
LWIP_ASSERT("expecting item available but it's 0", !expectSomething || (q->used > 0));
ret++;
if (ret == SYS_ARCH_TIMEOUT) {
ret--;
}
} while(q->used == 0);
}
else
{
if (the_waiting_fn) {
int expectSomething = the_waiting_fn(NULL, q);
LWIP_ASSERT("expecting item available count but it's 0", !expectSomething || (q->used > 0));
}
LWIP_ASSERT("q->used >= 0", q->used >= 0);
if (q->used == 0) {
if(msg) {
*msg = NULL;
}
return SYS_ARCH_TIMEOUT;
}
ret = 1;
}
}
LWIP_ASSERT("q->used > 0", q->used > 0);
ret2 = sys_arch_mbox_tryfetch(q, msg);
LWIP_ASSERT("got no message", ret2 == 0);
return ret;
}
u32_t
sys_arch_mbox_tryfetch(sys_mbox_t *q, void **msg)
{
LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL);
LWIP_ASSERT("q->sem == q", q->sem == q);
LWIP_ASSERT("q->q_mem != NULL", q->q_mem != NULL);
LWIP_ASSERT("q->used >= 0", q->used >= 0);
LWIP_ASSERT("q->size > 0", q->size > 0);
if (!q->used) {
return SYS_ARCH_TIMEOUT;
}
if(msg) {
*msg = q->q_mem[q->tail];
}
q->tail++;
if (q->tail >= (unsigned int)q->size) {
q->tail = 0;
}
q->used--;
LWIP_ASSERT("q->used >= 0", q->used >= 0);
return 0;
}
#if LWIP_NETCONN_SEM_PER_THREAD
#error LWIP_NETCONN_SEM_PER_THREAD==1 not supported
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
#endif /* !NO_SYS */

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2017 Simon Goldschmidt
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Simon Goldschmidt
*
*/
#ifndef LWIP_HDR_TEST_SYS_ARCH_H
#define LWIP_HDR_TEST_SYS_ARCH_H
typedef int sys_sem_t;
#define sys_sem_valid(sema) ((sema) != NULL)
typedef int sys_mutex_t;
#define sys_mutex_valid(mutex) (((mutex) != NULL)
struct lwip_mbox {
void* sem;
void** q_mem;
unsigned int head, tail;
int size;
int used;
};
typedef struct lwip_mbox sys_mbox_t;
#define SYS_MBOX_NULL NULL
#define sys_mbox_valid(mbox) ((mbox != NULL) && ((mbox)->sem != NULL) && ((mbox)->sem != (void*)-1))
#define sys_mbox_valid_val(mbox) (((mbox).sem != NULL) && ((mbox).sem != (void*)-1))
/* DWORD (thread id) is used for sys_thread_t but we won't include windows.h */
typedef u32_t sys_thread_t;
#define SYS_ARCH_DECL_PROTECT(lev)
#define SYS_ARCH_PROTECT(lev)
#define SYS_ARCH_UNPROTECT(lev)
/* to implement doing something while blocking on an mbox or semaphore:
* pass a function to test_sys_arch_wait_callback() that returns
* '0' if waiting again and
* '1' if now there should be something to do (used for asserting)
*/
typedef int (*test_sys_arch_waiting_fn)(sys_sem_t* wait_sem, sys_mbox_t* wait_mbox);
void test_sys_arch_wait_callback(test_sys_arch_waiting_fn waiting_fn);
/* current time */
extern u32_t lwip_sys_now;
#endif /* LWIP_HDR_TEST_SYS_ARCH_H */

View File

@ -0,0 +1,84 @@
#include "test_def.h"
#include "lwip/def.h"
#define MAGIC_UNTOUCHED_BYTE 0x7a
#define TEST_BUFSIZE 32
#define GUARD_SIZE 4
/* Setups/teardown functions */
static void
def_setup(void)
{
}
static void
def_teardown(void)
{
}
static void
def_check_range_untouched(const char *buf, size_t len)
{
size_t i;
for (i = 0; i < len; i++) {
fail_unless(buf[i] == (char)MAGIC_UNTOUCHED_BYTE);
}
}
static void test_def_itoa(int number, const char *expected)
{
char buf[TEST_BUFSIZE];
char *test_buf = &buf[GUARD_SIZE];
size_t exp_len = strlen(expected);
fail_unless(exp_len + 4 < (TEST_BUFSIZE - (2 * GUARD_SIZE)));
memset(buf, MAGIC_UNTOUCHED_BYTE, sizeof(buf));
lwip_itoa(test_buf, exp_len + 1, number);
def_check_range_untouched(buf, GUARD_SIZE);
fail_unless(test_buf[exp_len] == 0);
fail_unless(!memcmp(test_buf, expected, exp_len));
def_check_range_untouched(&test_buf[exp_len + 1], TEST_BUFSIZE - GUARD_SIZE - exp_len - 1);
/* check with too small buffer */
memset(buf, MAGIC_UNTOUCHED_BYTE, sizeof(buf));
lwip_itoa(test_buf, exp_len, number);
def_check_range_untouched(buf, GUARD_SIZE);
def_check_range_untouched(&test_buf[exp_len + 1], TEST_BUFSIZE - GUARD_SIZE - exp_len - 1);
/* check with too large buffer */
memset(buf, MAGIC_UNTOUCHED_BYTE, sizeof(buf));
lwip_itoa(test_buf, exp_len + 4, number);
def_check_range_untouched(buf, GUARD_SIZE);
fail_unless(test_buf[exp_len] == 0);
fail_unless(!memcmp(test_buf, expected, exp_len));
def_check_range_untouched(&test_buf[exp_len + 4], TEST_BUFSIZE - GUARD_SIZE - exp_len - 4);
}
START_TEST(test_def_lwip_itoa)
{
LWIP_UNUSED_ARG(_i);
test_def_itoa(0, "0");
test_def_itoa(1, "1");
test_def_itoa(-1, "-1");
test_def_itoa(15, "15");
test_def_itoa(-15, "-15");
test_def_itoa(156, "156");
test_def_itoa(1192, "1192");
test_def_itoa(-156, "-156");
}
END_TEST
/** Create the suite including all tests for this module */
Suite *
def_suite(void)
{
testfunc tests[] = {
TESTFUNC(test_def_lwip_itoa)
};
return create_suite("DEF", tests, sizeof(tests)/sizeof(testfunc), def_setup, def_teardown);
}

View File

@ -0,0 +1,8 @@
#ifndef LWIP_HDR_TEST_DEF_H
#define LWIP_HDR_TEST_DEF_H
#include "../lwip_check.h"
Suite *def_suite(void);
#endif

View File

@ -0,0 +1,224 @@
#include "test_mem.h"
#include "lwip/mem.h"
#include "lwip/stats.h"
#if !LWIP_STATS || !MEM_STATS
#error "This tests needs MEM-statistics enabled"
#endif
#if LWIP_DNS
#error "This test needs DNS turned off (as it mallocs on init)"
#endif
/* Setups/teardown functions */
static void
mem_setup(void)
{
lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
}
static void
mem_teardown(void)
{
lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
}
/* Test functions */
/** Call mem_malloc, mem_free and mem_trim and check stats */
START_TEST(test_mem_one)
{
#define SIZE1 16
#define SIZE1_2 12
#define SIZE2 16
void *p1, *p2;
mem_size_t s1, s2;
LWIP_UNUSED_ARG(_i);
fail_unless(lwip_stats.mem.used == 0);
p1 = mem_malloc(SIZE1);
fail_unless(p1 != NULL);
fail_unless(lwip_stats.mem.used >= SIZE1);
s1 = lwip_stats.mem.used;
p2 = mem_malloc(SIZE2);
fail_unless(p2 != NULL);
fail_unless(lwip_stats.mem.used >= SIZE2 + s1);
s2 = lwip_stats.mem.used;
mem_trim(p1, SIZE1_2);
mem_free(p2);
fail_unless(lwip_stats.mem.used <= s2 - SIZE2);
mem_free(p1);
fail_unless(lwip_stats.mem.used == 0);
}
END_TEST
static void malloc_keep_x(int x, int num, int size, int freestep)
{
int i;
void* p[16];
LWIP_ASSERT("invalid size", size >= 0 && size < (mem_size_t)-1);
memset(p, 0, sizeof(p));
for(i = 0; i < num && i < 16; i++) {
p[i] = mem_malloc((mem_size_t)size);
fail_unless(p[i] != NULL);
}
for(i = 0; i < num && i < 16; i += freestep) {
if (i == x) {
continue;
}
mem_free(p[i]);
p[i] = NULL;
}
for(i = 0; i < num && i < 16; i++) {
if (i == x) {
continue;
}
if (p[i] != NULL) {
mem_free(p[i]);
p[i] = NULL;
}
}
fail_unless(p[x] != NULL);
mem_free(p[x]);
}
START_TEST(test_mem_random)
{
const int num = 16;
int x;
int size;
int freestep;
LWIP_UNUSED_ARG(_i);
fail_unless(lwip_stats.mem.used == 0);
for (x = 0; x < num; x++) {
for (size = 1; size < 32; size++) {
for (freestep = 1; freestep <= 3; freestep++) {
fail_unless(lwip_stats.mem.used == 0);
malloc_keep_x(x, num, size, freestep);
fail_unless(lwip_stats.mem.used == 0);
}
}
}
}
END_TEST
START_TEST(test_mem_invalid_free)
{
u8_t *ptr, *ptr_low, *ptr_high;
LWIP_UNUSED_ARG(_i);
fail_unless(lwip_stats.mem.used == 0);
fail_unless(lwip_stats.mem.illegal == 0);
ptr = (u8_t *)mem_malloc(1);
fail_unless(ptr != NULL);
fail_unless(lwip_stats.mem.used != 0);
ptr_low = ptr - 0x10;
mem_free(ptr_low);
fail_unless(lwip_stats.mem.illegal == 1);
lwip_stats.mem.illegal = 0;
ptr_high = ptr + (MEM_SIZE * 2);
mem_free(ptr_high);
fail_unless(lwip_stats.mem.illegal == 1);
lwip_stats.mem.illegal = 0;
mem_free(ptr);
fail_unless(lwip_stats.mem.illegal == 0);
fail_unless(lwip_stats.mem.used == 0);
}
END_TEST
START_TEST(test_mem_double_free)
{
u8_t *ptr1b, *ptr1, *ptr2, *ptr3;
LWIP_UNUSED_ARG(_i);
fail_unless(lwip_stats.mem.used == 0);
fail_unless(lwip_stats.mem.illegal == 0);
ptr1 = (u8_t *)mem_malloc(1);
fail_unless(ptr1 != NULL);
fail_unless(lwip_stats.mem.used != 0);
ptr2 = (u8_t *)mem_malloc(1);
fail_unless(ptr2 != NULL);
fail_unless(lwip_stats.mem.used != 0);
ptr3 = (u8_t *)mem_malloc(1);
fail_unless(ptr3 != NULL);
fail_unless(lwip_stats.mem.used != 0);
/* free the middle mem */
mem_free(ptr2);
fail_unless(lwip_stats.mem.illegal == 0);
/* double-free of middle mem: should fail */
mem_free(ptr2);
fail_unless(lwip_stats.mem.illegal == 1);
lwip_stats.mem.illegal = 0;
/* free upper memory and try again */
mem_free(ptr3);
fail_unless(lwip_stats.mem.illegal == 0);
mem_free(ptr2);
fail_unless(lwip_stats.mem.illegal == 1);
lwip_stats.mem.illegal = 0;
/* free lower memory and try again */
mem_free(ptr1);
fail_unless(lwip_stats.mem.illegal == 0);
fail_unless(lwip_stats.mem.used == 0);
mem_free(ptr2);
fail_unless(lwip_stats.mem.illegal == 1);
fail_unless(lwip_stats.mem.used == 0);
lwip_stats.mem.illegal = 0;
/* reallocate lowest memory, now overlapping already freed ptr2 */
#ifndef MIN_SIZE
#define MIN_SIZE 12
#endif
ptr1b = (u8_t *)mem_malloc(MIN_SIZE * 2);
fail_unless(ptr1b != NULL);
fail_unless(lwip_stats.mem.used != 0);
mem_free(ptr2);
fail_unless(lwip_stats.mem.illegal == 1);
lwip_stats.mem.illegal = 0;
memset(ptr1b, 1, MIN_SIZE * 2);
mem_free(ptr2);
fail_unless(lwip_stats.mem.illegal == 1);
lwip_stats.mem.illegal = 0;
mem_free(ptr1b);
fail_unless(lwip_stats.mem.illegal == 0);
fail_unless(lwip_stats.mem.used == 0);
}
END_TEST
/** Create the suite including all tests for this module */
Suite *
mem_suite(void)
{
testfunc tests[] = {
TESTFUNC(test_mem_one),
TESTFUNC(test_mem_random),
TESTFUNC(test_mem_invalid_free),
TESTFUNC(test_mem_double_free)
};
return create_suite("MEM", tests, sizeof(tests)/sizeof(testfunc), mem_setup, mem_teardown);
}

View File

@ -0,0 +1,8 @@
#ifndef LWIP_HDR_TEST_MEM_H
#define LWIP_HDR_TEST_MEM_H
#include "../lwip_check.h"
Suite *mem_suite(void);
#endif

View File

@ -0,0 +1,227 @@
#include "test_netif.h"
#include "lwip/netif.h"
#include "lwip/stats.h"
#include "lwip/etharp.h"
#include "netif/ethernet.h"
#if !LWIP_NETIF_EXT_STATUS_CALLBACK
#error "This tests needs LWIP_NETIF_EXT_STATUS_CALLBACK enabled"
#endif
struct netif net_test;
/* Setups/teardown functions */
static void
netif_setup(void)
{
lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
}
static void
netif_teardown(void)
{
lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
}
/* test helper functions */
static err_t
testif_tx_func(struct netif *netif, struct pbuf *p)
{
LWIP_UNUSED_ARG(netif);
LWIP_UNUSED_ARG(p);
return ERR_OK;
}
static err_t
testif_init(struct netif *netif)
{
netif->name[0] = 'c';
netif->name[1] = 'h';
netif->output = etharp_output;
netif->linkoutput = testif_tx_func;
netif->mtu = 1500;
netif->hwaddr_len = 6;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP | NETIF_FLAG_MLD6;
netif->hwaddr[0] = 0x02;
netif->hwaddr[1] = 0x03;
netif->hwaddr[2] = 0x04;
netif->hwaddr[3] = 0x05;
netif->hwaddr[4] = 0x06;
netif->hwaddr[5] = 0x07;
return ERR_OK;
}
#define MAX_NSC_REASON_IDX 10
static netif_nsc_reason_t expected_reasons;
static int callback_ctr;
static int dummy_active;
static void
test_netif_ext_callback_dummy(struct netif* netif, netif_nsc_reason_t reason, const netif_ext_callback_args_t* args)
{
LWIP_UNUSED_ARG(netif);
LWIP_UNUSED_ARG(reason);
LWIP_UNUSED_ARG(args);
fail_unless(dummy_active);
}
static void
test_netif_ext_callback(struct netif* netif, netif_nsc_reason_t reason, const netif_ext_callback_args_t* args)
{
LWIP_UNUSED_ARG(args); /* @todo */
callback_ctr++;
fail_unless(netif == &net_test);
fail_unless(expected_reasons == reason);
}
/* Test functions */
NETIF_DECLARE_EXT_CALLBACK(netif_callback_1)
NETIF_DECLARE_EXT_CALLBACK(netif_callback_2)
NETIF_DECLARE_EXT_CALLBACK(netif_callback_3)
START_TEST(test_netif_extcallbacks)
{
ip4_addr_t addr;
ip4_addr_t netmask;
ip4_addr_t gw;
LWIP_UNUSED_ARG(_i);
IP4_ADDR(&addr, 0, 0, 0, 0);
IP4_ADDR(&netmask, 0, 0, 0, 0);
IP4_ADDR(&gw, 0, 0, 0, 0);
netif_add_ext_callback(&netif_callback_3, test_netif_ext_callback_dummy);
netif_add_ext_callback(&netif_callback_2, test_netif_ext_callback);
netif_add_ext_callback(&netif_callback_1, test_netif_ext_callback_dummy);
dummy_active = 1;
/* positive tests: check that single events come as expected */
expected_reasons = LWIP_NSC_NETIF_ADDED;
callback_ctr = 0;
netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input);
fail_unless(callback_ctr == 1);
expected_reasons = LWIP_NSC_LINK_CHANGED;
callback_ctr = 0;
netif_set_link_up(&net_test);
fail_unless(callback_ctr == 1);
expected_reasons = LWIP_NSC_STATUS_CHANGED;
callback_ctr = 0;
netif_set_up(&net_test);
fail_unless(callback_ctr == 1);
IP4_ADDR(&addr, 1, 2, 3, 4);
expected_reasons = LWIP_NSC_IPV4_ADDRESS_CHANGED;
callback_ctr = 0;
netif_set_ipaddr(&net_test, &addr);
fail_unless(callback_ctr == 1);
IP4_ADDR(&netmask, 255, 255, 255, 0);
expected_reasons = LWIP_NSC_IPV4_NETMASK_CHANGED;
callback_ctr = 0;
netif_set_netmask(&net_test, &netmask);
fail_unless(callback_ctr == 1);
IP4_ADDR(&gw, 1, 2, 3, 254);
expected_reasons = LWIP_NSC_IPV4_GATEWAY_CHANGED;
callback_ctr = 0;
netif_set_gw(&net_test, &gw);
fail_unless(callback_ctr == 1);
IP4_ADDR(&addr, 0, 0, 0, 0);
expected_reasons = LWIP_NSC_IPV4_ADDRESS_CHANGED;
callback_ctr = 0;
netif_set_ipaddr(&net_test, &addr);
fail_unless(callback_ctr == 1);
IP4_ADDR(&netmask, 0, 0, 0, 0);
expected_reasons = LWIP_NSC_IPV4_NETMASK_CHANGED;
callback_ctr = 0;
netif_set_netmask(&net_test, &netmask);
fail_unless(callback_ctr == 1);
IP4_ADDR(&gw, 0, 0, 0, 0);
expected_reasons = LWIP_NSC_IPV4_GATEWAY_CHANGED;
callback_ctr = 0;
netif_set_gw(&net_test, &gw);
fail_unless(callback_ctr == 1);
/* check for multi-events (only one combined callback expected) */
IP4_ADDR(&addr, 1, 2, 3, 4);
IP4_ADDR(&netmask, 255, 255, 255, 0);
IP4_ADDR(&gw, 1, 2, 3, 254);
expected_reasons = (netif_nsc_reason_t)(LWIP_NSC_IPV4_ADDRESS_CHANGED | LWIP_NSC_IPV4_NETMASK_CHANGED |
LWIP_NSC_IPV4_GATEWAY_CHANGED | LWIP_NSC_IPV4_SETTINGS_CHANGED);
callback_ctr = 0;
netif_set_addr(&net_test, &addr, &netmask, &gw);
fail_unless(callback_ctr == 1);
/* check that for no-change, no callback is expected */
expected_reasons = LWIP_NSC_NONE;
callback_ctr = 0;
netif_set_ipaddr(&net_test, &addr);
fail_unless(callback_ctr == 0);
netif_set_netmask(&net_test, &netmask);
callback_ctr = 0;
fail_unless(callback_ctr == 0);
callback_ctr = 0;
netif_set_gw(&net_test, &gw);
fail_unless(callback_ctr == 0);
callback_ctr = 0;
netif_set_addr(&net_test, &addr, &netmask, &gw);
fail_unless(callback_ctr == 0);
/* check for single-events */
IP4_ADDR(&addr, 1, 2, 3, 5);
expected_reasons = (netif_nsc_reason_t)(LWIP_NSC_IPV4_ADDRESS_CHANGED | LWIP_NSC_IPV4_SETTINGS_CHANGED);
callback_ctr = 0;
netif_set_addr(&net_test, &addr, &netmask, &gw);
fail_unless(callback_ctr == 1);
expected_reasons = LWIP_NSC_STATUS_CHANGED;
callback_ctr = 0;
netif_set_down(&net_test);
fail_unless(callback_ctr == 1);
expected_reasons = LWIP_NSC_NETIF_REMOVED;
callback_ctr = 0;
netif_remove(&net_test);
fail_unless(callback_ctr == 1);
expected_reasons = LWIP_NSC_NONE;
netif_remove_ext_callback(&netif_callback_2);
netif_remove_ext_callback(&netif_callback_3);
netif_remove_ext_callback(&netif_callback_1);
dummy_active = 0;
}
END_TEST
/** Create the suite including all tests for this module */
Suite *
netif_suite(void)
{
testfunc tests[] = {
TESTFUNC(test_netif_extcallbacks)
};
return create_suite("NETIF", tests, sizeof(tests)/sizeof(testfunc), netif_setup, netif_teardown);
}

View File

@ -0,0 +1,8 @@
#ifndef LWIP_HDR_TEST_NETIF_H
#define LWIP_HDR_TEST_NETIF_H
#include "../lwip_check.h"
Suite *netif_suite(void);
#endif

View File

@ -0,0 +1,271 @@
#include "test_pbuf.h"
#include "lwip/pbuf.h"
#include "lwip/stats.h"
#if !LWIP_STATS || !MEM_STATS ||!MEMP_STATS
#error "This tests needs MEM- and MEMP-statistics enabled"
#endif
#if LWIP_DNS
#error "This test needs DNS turned off (as it mallocs on init)"
#endif
#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || !LWIP_WND_SCALE
#error "This test needs TCP OOSEQ queueing and window scaling enabled"
#endif
/* Setups/teardown functions */
static void
pbuf_setup(void)
{
lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
}
static void
pbuf_teardown(void)
{
lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
}
#define TESTBUFSIZE_1 65535
#define TESTBUFSIZE_2 65530
#define TESTBUFSIZE_3 50050
static u8_t testbuf_1[TESTBUFSIZE_1];
static u8_t testbuf_1a[TESTBUFSIZE_1];
static u8_t testbuf_2[TESTBUFSIZE_2];
static u8_t testbuf_2a[TESTBUFSIZE_2];
static u8_t testbuf_3[TESTBUFSIZE_3];
static u8_t testbuf_3a[TESTBUFSIZE_3];
/* Test functions */
START_TEST(test_pbuf_alloc_zero_pbufs)
{
struct pbuf *p;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, 0, PBUF_ROM);
fail_unless(p != NULL);
if (p != NULL) {
pbuf_free(p);
}
p = pbuf_alloc(PBUF_RAW, 0, PBUF_RAM);
fail_unless(p != NULL);
if (p != NULL) {
pbuf_free(p);
}
p = pbuf_alloc(PBUF_RAW, 0, PBUF_REF);
fail_unless(p != NULL);
if (p != NULL) {
pbuf_free(p);
}
p = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
fail_unless(p != NULL);
if (p != NULL) {
pbuf_free(p);
}
}
END_TEST
/** Call pbuf_copy on a pbuf with zero length */
START_TEST(test_pbuf_copy_zero_pbuf)
{
struct pbuf *p1, *p2, *p3;
err_t err;
LWIP_UNUSED_ARG(_i);
fail_unless(lwip_stats.mem.used == 0);
fail_unless(MEMP_STATS_GET(used, MEMP_PBUF_POOL) == 0);
p1 = pbuf_alloc(PBUF_RAW, 1024, PBUF_RAM);
fail_unless(p1 != NULL);
fail_unless(p1->ref == 1);
p2 = pbuf_alloc(PBUF_RAW, 2, PBUF_POOL);
fail_unless(p2 != NULL);
fail_unless(p2->ref == 1);
p2->len = p2->tot_len = 0;
pbuf_cat(p1, p2);
fail_unless(p1->ref == 1);
fail_unless(p2->ref == 1);
p3 = pbuf_alloc(PBUF_RAW, p1->tot_len, PBUF_POOL);
err = pbuf_copy(p3, p1);
fail_unless(err == ERR_VAL);
pbuf_free(p1);
pbuf_free(p3);
fail_unless(lwip_stats.mem.used == 0);
fail_unless(lwip_stats.mem.used == 0);
fail_unless(MEMP_STATS_GET(used, MEMP_PBUF_POOL) == 0);
}
END_TEST
START_TEST(test_pbuf_split_64k_on_small_pbufs)
{
struct pbuf *p, *rest=NULL;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, 1, PBUF_POOL);
pbuf_split_64k(p, &rest);
fail_unless(p->tot_len == 1);
pbuf_free(p);
}
END_TEST
START_TEST(test_pbuf_queueing_bigger_than_64k)
{
int i;
err_t err;
struct pbuf *p1, *p2, *p3, *rest2=NULL, *rest3=NULL;
LWIP_UNUSED_ARG(_i);
for(i = 0; i < TESTBUFSIZE_1; i++) {
testbuf_1[i] = (u8_t)rand();
}
for(i = 0; i < TESTBUFSIZE_2; i++) {
testbuf_2[i] = (u8_t)rand();
}
for(i = 0; i < TESTBUFSIZE_3; i++) {
testbuf_3[i] = (u8_t)rand();
}
p1 = pbuf_alloc(PBUF_RAW, TESTBUFSIZE_1, PBUF_POOL);
fail_unless(p1 != NULL);
p2 = pbuf_alloc(PBUF_RAW, TESTBUFSIZE_2, PBUF_POOL);
fail_unless(p2 != NULL);
p3 = pbuf_alloc(PBUF_RAW, TESTBUFSIZE_3, PBUF_POOL);
fail_unless(p3 != NULL);
err = pbuf_take(p1, testbuf_1, TESTBUFSIZE_1);
fail_unless(err == ERR_OK);
err = pbuf_take(p2, testbuf_2, TESTBUFSIZE_2);
fail_unless(err == ERR_OK);
err = pbuf_take(p3, testbuf_3, TESTBUFSIZE_3);
fail_unless(err == ERR_OK);
pbuf_cat(p1, p2);
pbuf_cat(p1, p3);
pbuf_split_64k(p1, &rest2);
fail_unless(p1->tot_len == TESTBUFSIZE_1);
fail_unless(rest2->tot_len == (u16_t)((TESTBUFSIZE_2+TESTBUFSIZE_3) & 0xFFFF));
pbuf_split_64k(rest2, &rest3);
fail_unless(rest2->tot_len == TESTBUFSIZE_2);
fail_unless(rest3->tot_len == TESTBUFSIZE_3);
pbuf_copy_partial(p1, testbuf_1a, TESTBUFSIZE_1, 0);
pbuf_copy_partial(rest2, testbuf_2a, TESTBUFSIZE_2, 0);
pbuf_copy_partial(rest3, testbuf_3a, TESTBUFSIZE_3, 0);
fail_if(memcmp(testbuf_1, testbuf_1a, TESTBUFSIZE_1));
fail_if(memcmp(testbuf_2, testbuf_2a, TESTBUFSIZE_2));
fail_if(memcmp(testbuf_3, testbuf_3a, TESTBUFSIZE_3));
pbuf_free(p1);
pbuf_free(rest2);
pbuf_free(rest3);
}
END_TEST
/* Test for bug that writing with pbuf_take_at() did nothing
* and returned ERR_OK when writing at beginning of a pbuf
* in the chain.
*/
START_TEST(test_pbuf_take_at_edge)
{
err_t res;
u8_t *out;
int i;
u8_t testdata[] = { 0x01, 0x08, 0x82, 0x02 };
struct pbuf *p = pbuf_alloc(PBUF_RAW, 1024, PBUF_POOL);
struct pbuf *q = p->next;
LWIP_UNUSED_ARG(_i);
/* alloc big enough to get a chain of pbufs */
fail_if(p->tot_len == p->len);
memset(p->payload, 0, p->len);
memset(q->payload, 0, q->len);
/* copy data to the beginning of first pbuf */
res = pbuf_take_at(p, &testdata, sizeof(testdata), 0);
fail_unless(res == ERR_OK);
out = (u8_t*)p->payload;
for (i = 0; i < (int)sizeof(testdata); i++) {
fail_unless(out[i] == testdata[i],
"Bad data at pos %d, was %02X, expected %02X", i, out[i], testdata[i]);
}
/* copy data to the just before end of first pbuf */
res = pbuf_take_at(p, &testdata, sizeof(testdata), p->len - 1);
fail_unless(res == ERR_OK);
out = (u8_t*)p->payload;
fail_unless(out[p->len - 1] == testdata[0],
"Bad data at pos %d, was %02X, expected %02X", p->len - 1, out[p->len - 1], testdata[0]);
out = (u8_t*)q->payload;
for (i = 1; i < (int)sizeof(testdata); i++) {
fail_unless(out[i-1] == testdata[i],
"Bad data at pos %d, was %02X, expected %02X", p->len - 1 + i, out[i-1], testdata[i]);
}
/* copy data to the beginning of second pbuf */
res = pbuf_take_at(p, &testdata, sizeof(testdata), p->len);
fail_unless(res == ERR_OK);
out = (u8_t*)p->payload;
for (i = 0; i < (int)sizeof(testdata); i++) {
fail_unless(out[i] == testdata[i],
"Bad data at pos %d, was %02X, expected %02X", p->len+i, out[i], testdata[i]);
}
pbuf_free(p);
}
END_TEST
/* Verify pbuf_put_at()/pbuf_get_at() when using
* offsets equal to beginning of new pbuf in chain
*/
START_TEST(test_pbuf_get_put_at_edge)
{
u8_t *out;
u8_t testdata = 0x01;
u8_t getdata;
struct pbuf *p = pbuf_alloc(PBUF_RAW, 1024, PBUF_POOL);
struct pbuf *q = p->next;
LWIP_UNUSED_ARG(_i);
/* alloc big enough to get a chain of pbufs */
fail_if(p->tot_len == p->len);
memset(p->payload, 0, p->len);
memset(q->payload, 0, q->len);
/* put byte at the beginning of second pbuf */
pbuf_put_at(p, p->len, testdata);
out = (u8_t*)q->payload;
fail_unless(*out == testdata,
"Bad data at pos %d, was %02X, expected %02X", p->len, *out, testdata);
getdata = pbuf_get_at(p, p->len);
fail_unless(*out == getdata,
"pbuf_get_at() returned bad data at pos %d, was %02X, expected %02X", p->len, getdata, *out);
pbuf_free(p);
}
END_TEST
/** Create the suite including all tests for this module */
Suite *
pbuf_suite(void)
{
testfunc tests[] = {
TESTFUNC(test_pbuf_alloc_zero_pbufs),
TESTFUNC(test_pbuf_copy_zero_pbuf),
TESTFUNC(test_pbuf_split_64k_on_small_pbufs),
TESTFUNC(test_pbuf_queueing_bigger_than_64k),
TESTFUNC(test_pbuf_take_at_edge),
TESTFUNC(test_pbuf_get_put_at_edge)
};
return create_suite("PBUF", tests, sizeof(tests)/sizeof(testfunc), pbuf_setup, pbuf_teardown);
}

View File

@ -0,0 +1,8 @@
#ifndef LWIP_HDR_TEST_PBUF_H
#define LWIP_HDR_TEST_PBUF_H
#include "../lwip_check.h"
Suite *pbuf_suite(void);
#endif

View File

@ -0,0 +1,233 @@
#include "test_timers.h"
#include "lwip/def.h"
#include "lwip/timeouts.h"
#include "arch/sys_arch.h"
/* Setups/teardown functions */
static struct sys_timeo* old_list_head;
static void
timers_setup(void)
{
struct sys_timeo** list_head = sys_timeouts_get_next_timeout();
old_list_head = *list_head;
*list_head = NULL;
}
static void
timers_teardown(void)
{
struct sys_timeo** list_head = sys_timeouts_get_next_timeout();
*list_head = old_list_head;
lwip_sys_now = 0;
}
static int fired[3];
static void
dummy_handler(void* arg)
{
int index = LWIP_PTR_NUMERIC_CAST(int, arg);
fired[index] = 1;
}
#define HANDLER_EXECUTION_TIME 5
static int cyclic_fired;
static void
dummy_cyclic_handler(void)
{
cyclic_fired = 1;
lwip_sys_now += HANDLER_EXECUTION_TIME;
}
struct lwip_cyclic_timer test_cyclic = {10, dummy_cyclic_handler};
static void
do_test_cyclic_timers(u32_t offset)
{
struct sys_timeo** list_head = sys_timeouts_get_next_timeout();
/* verify normal timer expiration */
lwip_sys_now = offset + 0;
sys_timeout(test_cyclic.interval_ms, lwip_cyclic_timer, &test_cyclic);
cyclic_fired = 0;
sys_check_timeouts();
fail_unless(cyclic_fired == 0);
lwip_sys_now = offset + test_cyclic.interval_ms;
sys_check_timeouts();
fail_unless(cyclic_fired == 1);
fail_unless((*list_head)->time == (u32_t)(lwip_sys_now + test_cyclic.interval_ms - HANDLER_EXECUTION_TIME));
sys_untimeout(lwip_cyclic_timer, &test_cyclic);
/* verify "overload" - next cyclic timer execution is already overdue twice */
lwip_sys_now = offset + 0;
sys_timeout(test_cyclic.interval_ms, lwip_cyclic_timer, &test_cyclic);
cyclic_fired = 0;
sys_check_timeouts();
fail_unless(cyclic_fired == 0);
lwip_sys_now = offset + 2*test_cyclic.interval_ms;
sys_check_timeouts();
fail_unless(cyclic_fired == 1);
fail_unless((*list_head)->time == (u32_t)(lwip_sys_now + test_cyclic.interval_ms));
}
START_TEST(test_cyclic_timers)
{
LWIP_UNUSED_ARG(_i);
/* check without u32_t wraparound */
do_test_cyclic_timers(0);
/* check with u32_t wraparound */
do_test_cyclic_timers(0xfffffff0);
}
END_TEST
/* reproduce bug #52748: the bug in timeouts.c */
START_TEST(test_bug52748)
{
LWIP_UNUSED_ARG(_i);
memset(&fired, 0, sizeof(fired));
lwip_sys_now = 50;
sys_timeout(20, dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 0));
sys_timeout( 5, dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 2));
lwip_sys_now = 55;
sys_check_timeouts();
fail_unless(fired[0] == 0);
fail_unless(fired[1] == 0);
fail_unless(fired[2] == 1);
lwip_sys_now = 60;
sys_timeout(10, dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 1));
sys_check_timeouts();
fail_unless(fired[0] == 0);
fail_unless(fired[1] == 0);
fail_unless(fired[2] == 1);
lwip_sys_now = 70;
sys_check_timeouts();
fail_unless(fired[0] == 1);
fail_unless(fired[1] == 1);
fail_unless(fired[2] == 1);
}
END_TEST
static void
do_test_timers(u32_t offset)
{
struct sys_timeo** list_head = sys_timeouts_get_next_timeout();
lwip_sys_now = offset + 0;
sys_timeout(10, dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 0));
fail_unless(sys_timeouts_sleeptime() == 10);
sys_timeout(20, dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 1));
fail_unless(sys_timeouts_sleeptime() == 10);
sys_timeout( 5, dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 2));
fail_unless(sys_timeouts_sleeptime() == 5);
/* linked list correctly sorted? */
fail_unless((*list_head)->time == (u32_t)(lwip_sys_now + 5));
fail_unless((*list_head)->next->time == (u32_t)(lwip_sys_now + 10));
fail_unless((*list_head)->next->next->time == (u32_t)(lwip_sys_now + 20));
/* check timers expire in correct order */
memset(&fired, 0, sizeof(fired));
lwip_sys_now += 4;
sys_check_timeouts();
fail_unless(fired[2] == 0);
lwip_sys_now += 1;
sys_check_timeouts();
fail_unless(fired[2] == 1);
lwip_sys_now += 4;
sys_check_timeouts();
fail_unless(fired[0] == 0);
lwip_sys_now += 1;
sys_check_timeouts();
fail_unless(fired[0] == 1);
lwip_sys_now += 9;
sys_check_timeouts();
fail_unless(fired[1] == 0);
lwip_sys_now += 1;
sys_check_timeouts();
fail_unless(fired[1] == 1);
sys_untimeout(dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 0));
sys_untimeout(dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 1));
sys_untimeout(dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 2));
}
START_TEST(test_timers)
{
LWIP_UNUSED_ARG(_i);
/* check without u32_t wraparound */
do_test_timers(0);
/* check with u32_t wraparound */
do_test_timers(0xfffffff0);
}
END_TEST
START_TEST(test_long_timer)
{
LWIP_UNUSED_ARG(_i);
memset(&fired, 0, sizeof(fired));
lwip_sys_now = 0;
sys_timeout(LWIP_UINT32_MAX / 4, dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 0));
fail_unless(sys_timeouts_sleeptime() == LWIP_UINT32_MAX / 4);
sys_check_timeouts();
fail_unless(fired[0] == 0);
lwip_sys_now += LWIP_UINT32_MAX / 8;
sys_check_timeouts();
fail_unless(fired[0] == 0);
lwip_sys_now += LWIP_UINT32_MAX / 8;
sys_check_timeouts();
fail_unless(fired[0] == 0);
lwip_sys_now += 1;
sys_check_timeouts();
fail_unless(fired[0] == 1);
sys_untimeout(dummy_handler, LWIP_PTR_NUMERIC_CAST(void*, 0));
}
END_TEST
/** Create the suite including all tests for this module */
Suite *
timers_suite(void)
{
testfunc tests[] = {
TESTFUNC(test_bug52748),
TESTFUNC(test_cyclic_timers),
TESTFUNC(test_timers),
TESTFUNC(test_long_timer),
};
return create_suite("TIMERS", tests, LWIP_ARRAYSIZE(tests), timers_setup, timers_teardown);
}

View File

@ -0,0 +1,8 @@
#ifndef LWIP_HDR_TEST_TIMERS_H
#define LWIP_HDR_TEST_TIMERS_H
#include "../lwip_check.h"
Suite *timers_suite(void);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
#ifndef LWIP_HDR_TEST_DHCP_H
#define LWIP_HDR_TEST_DHCP_H
#include "../lwip_check.h"
Suite* dhcp_suite(void);
#endif

View File

@ -0,0 +1,272 @@
#include "test_etharp.h"
#include "lwip/udp.h"
#include "lwip/etharp.h"
#include "netif/ethernet.h"
#include "lwip/stats.h"
#include "lwip/prot/iana.h"
#if !LWIP_STATS || !UDP_STATS || !MEMP_STATS || !ETHARP_STATS
#error "This tests needs UDP-, MEMP- and ETHARP-statistics enabled"
#endif
#if !ETHARP_SUPPORT_STATIC_ENTRIES
#error "This test needs ETHARP_SUPPORT_STATIC_ENTRIES enabled"
#endif
static struct netif test_netif;
static ip4_addr_t test_ipaddr, test_netmask, test_gw;
struct eth_addr test_ethaddr = {{1,1,1,1,1,1}};
struct eth_addr test_ethaddr2 = {{1,1,1,1,1,2}};
struct eth_addr test_ethaddr3 = {{1,1,1,1,1,3}};
struct eth_addr test_ethaddr4 = {{1,1,1,1,1,4}};
static int linkoutput_ctr;
/* Helper functions */
static void
etharp_remove_all(void)
{
int i;
/* call etharp_tmr often enough to have all entries cleaned */
for(i = 0; i < 0xff; i++) {
etharp_tmr();
}
}
static err_t
default_netif_linkoutput(struct netif *netif, struct pbuf *p)
{
fail_unless(netif == &test_netif);
fail_unless(p != NULL);
linkoutput_ctr++;
return ERR_OK;
}
static err_t
default_netif_init(struct netif *netif)
{
fail_unless(netif != NULL);
netif->linkoutput = default_netif_linkoutput;
netif->output = etharp_output;
netif->mtu = 1500;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
netif->hwaddr_len = ETHARP_HWADDR_LEN;
return ERR_OK;
}
static void
default_netif_add(void)
{
IP4_ADDR(&test_gw, 192,168,0,1);
IP4_ADDR(&test_ipaddr, 192,168,0,1);
IP4_ADDR(&test_netmask, 255,255,0,0);
fail_unless(netif_default == NULL);
netif_set_default(netif_add(&test_netif, &test_ipaddr, &test_netmask,
&test_gw, NULL, default_netif_init, NULL));
netif_set_up(&test_netif);
}
static void
default_netif_remove(void)
{
fail_unless(netif_default == &test_netif);
netif_remove(&test_netif);
}
static void
create_arp_response(ip4_addr_t *adr)
{
int k;
struct eth_hdr *ethhdr;
struct etharp_hdr *etharphdr;
struct pbuf *p = pbuf_alloc(PBUF_RAW, sizeof(struct eth_hdr) + sizeof(struct etharp_hdr), PBUF_RAM);
if(p == NULL) {
FAIL_RET();
}
ethhdr = (struct eth_hdr*)p->payload;
etharphdr = (struct etharp_hdr*)(ethhdr + 1);
ethhdr->dest = test_ethaddr;
ethhdr->src = test_ethaddr2;
ethhdr->type = htons(ETHTYPE_ARP);
etharphdr->hwtype = htons(LWIP_IANA_HWTYPE_ETHERNET);
etharphdr->proto = htons(ETHTYPE_IP);
etharphdr->hwlen = ETHARP_HWADDR_LEN;
etharphdr->protolen = sizeof(ip4_addr_t);
etharphdr->opcode = htons(ARP_REPLY);
SMEMCPY(&etharphdr->sipaddr, adr, sizeof(ip4_addr_t));
SMEMCPY(&etharphdr->dipaddr, &test_ipaddr, sizeof(ip4_addr_t));
k = 6;
while(k > 0) {
k--;
/* Write the ARP MAC-Addresses */
etharphdr->shwaddr.addr[k] = test_ethaddr2.addr[k];
etharphdr->dhwaddr.addr[k] = test_ethaddr.addr[k];
/* Write the Ethernet MAC-Addresses */
ethhdr->dest.addr[k] = test_ethaddr.addr[k];
ethhdr->src.addr[k] = test_ethaddr2.addr[k];
}
ethernet_input(p, &test_netif);
}
/* Setups/teardown functions */
static void
etharp_setup(void)
{
etharp_remove_all();
default_netif_add();
lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
}
static void
etharp_teardown(void)
{
etharp_remove_all();
default_netif_remove();
lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
}
/* Test functions */
START_TEST(test_etharp_table)
{
#if ETHARP_SUPPORT_STATIC_ENTRIES
err_t err;
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
ssize_t idx;
const ip4_addr_t *unused_ipaddr;
struct eth_addr *unused_ethaddr;
struct udp_pcb* pcb;
LWIP_UNUSED_ARG(_i);
if (netif_default != &test_netif) {
fail("This test needs a default netif");
}
linkoutput_ctr = 0;
pcb = udp_new();
fail_unless(pcb != NULL);
if (pcb != NULL) {
ip4_addr_t adrs[ARP_TABLE_SIZE + 2];
int i;
for(i = 0; i < ARP_TABLE_SIZE + 2; i++) {
IP4_ADDR(&adrs[i], 192,168,0,i+2);
}
/* fill ARP-table with dynamic entries */
for(i = 0; i < ARP_TABLE_SIZE; i++) {
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 10, PBUF_RAM);
fail_unless(p != NULL);
if (p != NULL) {
err_t err2;
ip_addr_t dst;
ip_addr_copy_from_ip4(dst, adrs[i]);
err2 = udp_sendto(pcb, p, &dst, 123);
fail_unless(err2 == ERR_OK);
/* etharp request sent? */
fail_unless(linkoutput_ctr == (2*i) + 1);
pbuf_free(p);
/* create an ARP response */
create_arp_response(&adrs[i]);
/* queued UDP packet sent? */
fail_unless(linkoutput_ctr == (2*i) + 2);
idx = etharp_find_addr(NULL, &adrs[i], &unused_ethaddr, &unused_ipaddr);
fail_unless(idx == i);
etharp_tmr();
}
}
linkoutput_ctr = 0;
#if ETHARP_SUPPORT_STATIC_ENTRIES
/* create one static entry */
err = etharp_add_static_entry(&adrs[ARP_TABLE_SIZE], &test_ethaddr3);
fail_unless(err == ERR_OK);
idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr);
fail_unless(idx == 0);
fail_unless(linkoutput_ctr == 0);
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
linkoutput_ctr = 0;
/* fill ARP-table with dynamic entries */
for(i = 0; i < ARP_TABLE_SIZE; i++) {
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 10, PBUF_RAM);
fail_unless(p != NULL);
if (p != NULL) {
err_t err2;
ip_addr_t dst;
ip_addr_copy_from_ip4(dst, adrs[i]);
err2 = udp_sendto(pcb, p, &dst, 123);
fail_unless(err2 == ERR_OK);
/* etharp request sent? */
fail_unless(linkoutput_ctr == (2*i) + 1);
pbuf_free(p);
/* create an ARP response */
create_arp_response(&adrs[i]);
/* queued UDP packet sent? */
fail_unless(linkoutput_ctr == (2*i) + 2);
idx = etharp_find_addr(NULL, &adrs[i], &unused_ethaddr, &unused_ipaddr);
if (i < ARP_TABLE_SIZE - 1) {
fail_unless(idx == i+1);
} else {
/* the last entry must not overwrite the static entry! */
fail_unless(idx == 1);
}
etharp_tmr();
}
}
#if ETHARP_SUPPORT_STATIC_ENTRIES
/* create a second static entry */
err = etharp_add_static_entry(&adrs[ARP_TABLE_SIZE+1], &test_ethaddr4);
fail_unless(err == ERR_OK);
idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr);
fail_unless(idx == 0);
idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE+1], &unused_ethaddr, &unused_ipaddr);
fail_unless(idx == 2);
/* and remove it again */
err = etharp_remove_static_entry(&adrs[ARP_TABLE_SIZE+1]);
fail_unless(err == ERR_OK);
idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr);
fail_unless(idx == 0);
idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE+1], &unused_ethaddr, &unused_ipaddr);
fail_unless(idx == -1);
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
/* check that static entries don't time out */
etharp_remove_all();
idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr);
fail_unless(idx == 0);
#if ETHARP_SUPPORT_STATIC_ENTRIES
/* remove the first static entry */
err = etharp_remove_static_entry(&adrs[ARP_TABLE_SIZE]);
fail_unless(err == ERR_OK);
idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr);
fail_unless(idx == -1);
idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE+1], &unused_ethaddr, &unused_ipaddr);
fail_unless(idx == -1);
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
udp_remove(pcb);
}
}
END_TEST
/** Create the suite including all tests for this module */
Suite *
etharp_suite(void)
{
testfunc tests[] = {
TESTFUNC(test_etharp_table)
};
return create_suite("ETHARP", tests, sizeof(tests)/sizeof(testfunc), etharp_setup, etharp_teardown);
}

View File

@ -0,0 +1,8 @@
#ifndef LWIP_HDR_TEST_ETHARP_H
#define LWIP_HDR_TEST_ETHARP_H
#include "../lwip_check.h"
Suite* etharp_suite(void);
#endif

View File

@ -0,0 +1,160 @@
#include "test_ip4.h"
#include "lwip/ip4.h"
#include "lwip/inet_chksum.h"
#include "lwip/stats.h"
#include "lwip/prot/ip.h"
#include "lwip/prot/ip4.h"
#include "lwip/tcpip.h"
#if !LWIP_IPV4 || !IP_REASSEMBLY || !MIB2_STATS || !IPFRAG_STATS
#error "This tests needs LWIP_IPV4, IP_REASSEMBLY; MIB2- and IPFRAG-statistics enabled"
#endif
/* Helper functions */
static void
create_ip4_input_fragment(u16_t ip_id, u16_t start, u16_t len, int last)
{
struct pbuf *p;
struct netif *input_netif = netif_list; /* just use any netif */
fail_unless((start & 7) == 0);
fail_unless(((len & 7) == 0) || last);
fail_unless(input_netif != NULL);
p = pbuf_alloc(PBUF_RAW, len + sizeof(struct ip_hdr), PBUF_RAM);
fail_unless(p != NULL);
if (p != NULL) {
err_t err;
struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
IPH_VHL_SET(iphdr, 4, sizeof(struct ip_hdr) / 4);
IPH_TOS_SET(iphdr, 0);
IPH_LEN_SET(iphdr, lwip_htons(p->tot_len));
IPH_ID_SET(iphdr, lwip_htons(ip_id));
if (last) {
IPH_OFFSET_SET(iphdr, lwip_htons(start / 8));
} else {
IPH_OFFSET_SET(iphdr, lwip_htons((start / 8) | IP_MF));
}
IPH_TTL_SET(iphdr, 5);
IPH_PROTO_SET(iphdr, IP_PROTO_UDP);
IPH_CHKSUM_SET(iphdr, 0);
ip4_addr_copy(iphdr->src, *netif_ip4_addr(input_netif));
iphdr->src.addr = lwip_htonl(lwip_htonl(iphdr->src.addr) + 1);
ip4_addr_copy(iphdr->dest, *netif_ip4_addr(input_netif));
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, sizeof(struct ip_hdr)));
err = ip4_input(p, input_netif);
if (err != ERR_OK) {
pbuf_free(p);
}
fail_unless(err == ERR_OK);
}
}
/* Setups/teardown functions */
static void
ip4_setup(void)
{
lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
}
static void
ip4_teardown(void)
{
if (netif_list->loop_first != NULL) {
pbuf_free(netif_list->loop_first);
netif_list->loop_first = NULL;
}
netif_list->loop_last = NULL;
/* poll until all memory is released... */
tcpip_thread_poll_one();
lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
}
/* Test functions */
START_TEST(test_ip4_reass)
{
const u16_t ip_id = 128;
LWIP_UNUSED_ARG(_i);
memset(&lwip_stats.mib2, 0, sizeof(lwip_stats.mib2));
create_ip4_input_fragment(ip_id, 8*200, 200, 1);
fail_unless(lwip_stats.ip_frag.recv == 1);
fail_unless(lwip_stats.ip_frag.err == 0);
fail_unless(lwip_stats.ip_frag.memerr == 0);
fail_unless(lwip_stats.ip_frag.drop == 0);
fail_unless(lwip_stats.mib2.ipreasmoks == 0);
create_ip4_input_fragment(ip_id, 0*200, 200, 0);
fail_unless(lwip_stats.ip_frag.recv == 2);
fail_unless(lwip_stats.ip_frag.err == 0);
fail_unless(lwip_stats.ip_frag.memerr == 0);
fail_unless(lwip_stats.ip_frag.drop == 0);
fail_unless(lwip_stats.mib2.ipreasmoks == 0);
create_ip4_input_fragment(ip_id, 1*200, 200, 0);
fail_unless(lwip_stats.ip_frag.recv == 3);
fail_unless(lwip_stats.ip_frag.err == 0);
fail_unless(lwip_stats.ip_frag.memerr == 0);
fail_unless(lwip_stats.ip_frag.drop == 0);
fail_unless(lwip_stats.mib2.ipreasmoks == 0);
create_ip4_input_fragment(ip_id, 2*200, 200, 0);
fail_unless(lwip_stats.ip_frag.recv == 4);
fail_unless(lwip_stats.ip_frag.err == 0);
fail_unless(lwip_stats.ip_frag.memerr == 0);
fail_unless(lwip_stats.ip_frag.drop == 0);
fail_unless(lwip_stats.mib2.ipreasmoks == 0);
create_ip4_input_fragment(ip_id, 3*200, 200, 0);
fail_unless(lwip_stats.ip_frag.recv == 5);
fail_unless(lwip_stats.ip_frag.err == 0);
fail_unless(lwip_stats.ip_frag.memerr == 0);
fail_unless(lwip_stats.ip_frag.drop == 0);
fail_unless(lwip_stats.mib2.ipreasmoks == 0);
create_ip4_input_fragment(ip_id, 4*200, 200, 0);
fail_unless(lwip_stats.ip_frag.recv == 6);
fail_unless(lwip_stats.ip_frag.err == 0);
fail_unless(lwip_stats.ip_frag.memerr == 0);
fail_unless(lwip_stats.ip_frag.drop == 0);
fail_unless(lwip_stats.mib2.ipreasmoks == 0);
create_ip4_input_fragment(ip_id, 7*200, 200, 0);
fail_unless(lwip_stats.ip_frag.recv == 7);
fail_unless(lwip_stats.ip_frag.err == 0);
fail_unless(lwip_stats.ip_frag.memerr == 0);
fail_unless(lwip_stats.ip_frag.drop == 0);
fail_unless(lwip_stats.mib2.ipreasmoks == 0);
create_ip4_input_fragment(ip_id, 6*200, 200, 0);
fail_unless(lwip_stats.ip_frag.recv == 8);
fail_unless(lwip_stats.ip_frag.err == 0);
fail_unless(lwip_stats.ip_frag.memerr == 0);
fail_unless(lwip_stats.ip_frag.drop == 0);
fail_unless(lwip_stats.mib2.ipreasmoks == 0);
create_ip4_input_fragment(ip_id, 5*200, 200, 0);
fail_unless(lwip_stats.ip_frag.recv == 9);
fail_unless(lwip_stats.ip_frag.err == 0);
fail_unless(lwip_stats.ip_frag.memerr == 0);
fail_unless(lwip_stats.ip_frag.drop == 0);
fail_unless(lwip_stats.mib2.ipreasmoks == 1);
}
END_TEST
/** Create the suite including all tests for this module */
Suite *
ip4_suite(void)
{
testfunc tests[] = {
TESTFUNC(test_ip4_reass),
};
return create_suite("IPv4", tests, sizeof(tests)/sizeof(testfunc), ip4_setup, ip4_teardown);
}

View File

@ -0,0 +1,8 @@
#ifndef LWIP_HDR_TEST_IP4_H
#define LWIP_HDR_TEST_IP4_H
#include "../lwip_check.h"
Suite* ip4_suite(void);
#endif

View File

@ -0,0 +1,321 @@
#include "test_ip6.h"
#include "lwip/ethip6.h"
#include "lwip/ip6.h"
#include "lwip/inet_chksum.h"
#include "lwip/nd6.h"
#include "lwip/stats.h"
#include "lwip/prot/ethernet.h"
#include "lwip/prot/ip.h"
#include "lwip/prot/ip6.h"
#include "lwip/tcpip.h"
#if LWIP_IPV6 /* allow to build the unit tests without IPv6 support */
static struct netif test_netif6;
static int linkoutput_ctr;
static err_t
default_netif_linkoutput(struct netif *netif, struct pbuf *p)
{
fail_unless(netif == &test_netif6);
fail_unless(p != NULL);
linkoutput_ctr++;
return ERR_OK;
}
static err_t
default_netif_init(struct netif *netif)
{
fail_unless(netif != NULL);
netif->linkoutput = default_netif_linkoutput;
netif->output_ip6 = ethip6_output;
netif->mtu = 1500;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHERNET | NETIF_FLAG_MLD6;
netif->hwaddr_len = ETH_HWADDR_LEN;
return ERR_OK;
}
static void
default_netif_add(void)
{
struct netif *n;
fail_unless(netif_default == NULL);
n = netif_add_noaddr(&test_netif6, NULL, default_netif_init, NULL);
fail_unless(n == &test_netif6);
netif_set_default(&test_netif6);
}
static void
default_netif_remove(void)
{
fail_unless(netif_default == &test_netif6);
netif_remove(&test_netif6);
}
static void
ip6_test_handle_timers(int count)
{
int i;
for (i = 0; i < count; i++) {
nd6_tmr();
}
}
/* Setups/teardown functions */
static void
ip6_setup(void)
{
default_netif_add();
lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
}
static void
ip6_teardown(void)
{
if (netif_list->loop_first != NULL) {
pbuf_free(netif_list->loop_first);
netif_list->loop_first = NULL;
}
netif_list->loop_last = NULL;
/* poll until all memory is released... */
tcpip_thread_poll_one();
default_netif_remove();
lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
}
/* Test functions */
static void
test_ip6_ll_addr_iter(int expected_ctr1, int expected_ctr2)
{
fail_unless(linkoutput_ctr == 0);
/* test that nothing is sent with link uo but netif down */
netif_set_link_up(&test_netif6);
ip6_test_handle_timers(500);
fail_unless(linkoutput_ctr == 0);
netif_set_link_down(&test_netif6);
fail_unless(linkoutput_ctr == 0);
/* test that nothing is sent with link down but netif up */
netif_set_up(&test_netif6);
ip6_test_handle_timers(500);
fail_unless(linkoutput_ctr == 0);
netif_set_down(&test_netif6);
fail_unless(linkoutput_ctr == 0);
/* test what is sent with link up + netif up */
netif_set_link_up(&test_netif6);
netif_set_up(&test_netif6);
ip6_test_handle_timers(500);
fail_unless(linkoutput_ctr == expected_ctr1);
netif_set_down(&test_netif6);
netif_set_link_down(&test_netif6);
fail_unless(linkoutput_ctr == expected_ctr1);
linkoutput_ctr = 0;
netif_set_up(&test_netif6);
netif_set_link_up(&test_netif6);
ip6_test_handle_timers(500);
fail_unless(linkoutput_ctr == expected_ctr2);
netif_set_link_down(&test_netif6);
netif_set_down(&test_netif6);
fail_unless(linkoutput_ctr == expected_ctr2);
linkoutput_ctr = 0;
}
START_TEST(test_ip6_ll_addr)
{
LWIP_UNUSED_ARG(_i);
/* test without link-local address */
test_ip6_ll_addr_iter(0, 0);
/* test with link-local address */
netif_create_ip6_linklocal_address(&test_netif6, 1);
test_ip6_ll_addr_iter(3 + LWIP_IPV6_DUP_DETECT_ATTEMPTS + LWIP_IPV6_MLD, 3);
}
END_TEST
START_TEST(test_ip6_aton_ipv4mapped)
{
int ret;
ip_addr_t addr;
ip6_addr_t addr6;
const ip_addr_t addr_expected = IPADDR6_INIT_HOST(0, 0, 0xFFFF, 0xD4CC65D2);
const char *full_ipv6_addr = "0:0:0:0:0:FFFF:D4CC:65D2";
const char *shortened_ipv6_addr = "::FFFF:D4CC:65D2";
const char *full_ipv4_mapped_addr = "0:0:0:0:0:FFFF:212.204.101.210";
const char *shortened_ipv4_mapped_addr = "::FFFF:212.204.101.210";
const char *bogus_ipv4_mapped_addr = "::FFFF:212.204.101.2101";
LWIP_UNUSED_ARG(_i);
/* check IPv6 representation */
memset(&addr6, 0, sizeof(addr6));
ret = ip6addr_aton(full_ipv6_addr, &addr6);
fail_unless(ret == 1);
fail_unless(memcmp(&addr6, &addr_expected, 16) == 0);
memset(&addr, 0, sizeof(addr));
ret = ipaddr_aton(full_ipv6_addr, &addr);
fail_unless(ret == 1);
fail_unless(memcmp(&addr, &addr_expected, 16) == 0);
/* check shortened IPv6 representation */
memset(&addr6, 0, sizeof(addr6));
ret = ip6addr_aton(shortened_ipv6_addr, &addr6);
fail_unless(ret == 1);
fail_unless(memcmp(&addr6, &addr_expected, 16) == 0);
memset(&addr, 0, sizeof(addr));
ret = ipaddr_aton(shortened_ipv6_addr, &addr);
fail_unless(ret == 1);
fail_unless(memcmp(&addr, &addr_expected, 16) == 0);
/* checked shortened mixed representation */
memset(&addr6, 0, sizeof(addr6));
ret = ip6addr_aton(shortened_ipv4_mapped_addr, &addr6);
fail_unless(ret == 1);
fail_unless(memcmp(&addr6, &addr_expected, 16) == 0);
memset(&addr, 0, sizeof(addr));
ret = ipaddr_aton(shortened_ipv4_mapped_addr, &addr);
fail_unless(ret == 1);
fail_unless(memcmp(&addr, &addr_expected, 16) == 0);
/* checked mixed representation */
memset(&addr6, 0, sizeof(addr6));
ret = ip6addr_aton(full_ipv4_mapped_addr, &addr6);
fail_unless(ret == 1);
fail_unless(memcmp(&addr6, &addr_expected, 16) == 0);
memset(&addr, 0, sizeof(addr));
ret = ipaddr_aton(full_ipv4_mapped_addr, &addr);
fail_unless(ret == 1);
fail_unless(memcmp(&addr, &addr_expected, 16) == 0);
/* checked bogus mixed representation */
memset(&addr6, 0, sizeof(addr6));
ret = ip6addr_aton(bogus_ipv4_mapped_addr, &addr6);
fail_unless(ret == 0);
memset(&addr, 0, sizeof(addr));
ret = ipaddr_aton(bogus_ipv4_mapped_addr, &addr);
fail_unless(ret == 0);
}
END_TEST
START_TEST(test_ip6_ntoa_ipv4mapped)
{
const ip_addr_t addr = IPADDR6_INIT_HOST(0, 0, 0xFFFF, 0xD4CC65D2);
char buf[128];
char *str;
LWIP_UNUSED_ARG(_i);
str = ip6addr_ntoa_r(ip_2_ip6(&addr), buf, sizeof(buf));
fail_unless(str == buf);
fail_unless(!strcmp(str, "::FFFF:212.204.101.210"));
}
END_TEST
struct test_addr_and_str {
ip_addr_t addr;
const char *str;
};
START_TEST(test_ip6_ntoa)
{
struct test_addr_and_str tests[] = {
{IPADDR6_INIT_HOST(0xfe800000, 0x00000000, 0xb2a1a2ff, 0xfea3a4a5), "FE80::B2A1:A2FF:FEA3:A4A5"}, /* test shortened zeros */
{IPADDR6_INIT_HOST(0xfe800000, 0xff000000, 0xb2a1a2ff, 0xfea3a4a5), "FE80:0:FF00:0:B2A1:A2FF:FEA3:A4A5"}, /* don't omit single zero blocks */
{IPADDR6_INIT_HOST(0xfe800000, 0xff000000, 0xb2000000, 0x0000a4a5), "FE80:0:FF00:0:B200::A4A5"}, /* omit longest zero block */
};
char buf[128];
char *str;
size_t i;
LWIP_UNUSED_ARG(_i);
for (i = 0; i < LWIP_ARRAYSIZE(tests); i++) {
str = ip6addr_ntoa_r(ip_2_ip6(&tests[i].addr), buf, sizeof(buf));
fail_unless(str == buf);
fail_unless(!strcmp(str, tests[i].str));
}
}
END_TEST
START_TEST(test_ip6_lladdr)
{
u8_t zeros[128];
const u8_t test_mac_addr[6] = {0xb0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5};
const u32_t expected_ip6_addr_1[4] = {PP_HTONL(0xfe800000), 0, PP_HTONL(0xb2a1a2ff), PP_HTONL(0xfea3a4a5)};
const u32_t expected_ip6_addr_2[4] = {PP_HTONL(0xfe800000), 0, PP_HTONL(0x0000b0a1), PP_HTONL(0xa2a3a4a5)};
LWIP_UNUSED_ARG(_i);
memset(zeros, 0, sizeof(zeros));
fail_unless(test_netif6.hwaddr_len == 6);
fail_unless(!memcmp(test_netif6.hwaddr, zeros, 6));
fail_unless(test_netif6.ip6_addr_state[0] == 0);
fail_unless(!memcmp(netif_ip6_addr(&test_netif6, 0), zeros, sizeof(ip6_addr_t)));
/* set specific mac addr */
memcpy(test_netif6.hwaddr, test_mac_addr, 6);
/* create link-local addr based on mac (EUI-48) */
netif_create_ip6_linklocal_address(&test_netif6, 1);
fail_unless(IP_IS_V6(&test_netif6.ip6_addr[0]));
fail_unless(!memcmp(&netif_ip6_addr(&test_netif6, 0)->addr, expected_ip6_addr_1, 16));
#if LWIP_IPV6_SCOPES
fail_unless(netif_ip6_addr(&test_netif6, 0)->zone == (test_netif6.num + 1));
#endif
/* reset address */
memset(&test_netif6.ip6_addr[0], 0, sizeof(ip6_addr_t));
test_netif6.ip6_addr_state[0] = 0;
/* create link-local addr based interface ID */
netif_create_ip6_linklocal_address(&test_netif6, 0);
fail_unless(IP_IS_V6(&test_netif6.ip6_addr[0]));
fail_unless(!memcmp(&netif_ip6_addr(&test_netif6, 0)->addr, expected_ip6_addr_2, 16));
#if LWIP_IPV6_SCOPES
fail_unless(netif_ip6_addr(&test_netif6, 0)->zone == (test_netif6.num + 1));
#endif
/* reset address */
memset(&test_netif6.ip6_addr[0], 0, sizeof(ip6_addr_t));
test_netif6.ip6_addr_state[0] = 0;
/* reset mac address */
memset(&test_netif6.hwaddr, 0, sizeof(test_netif6.hwaddr));
}
END_TEST
/** Create the suite including all tests for this module */
Suite *
ip6_suite(void)
{
testfunc tests[] = {
TESTFUNC(test_ip6_ll_addr),
TESTFUNC(test_ip6_aton_ipv4mapped),
TESTFUNC(test_ip6_ntoa_ipv4mapped),
TESTFUNC(test_ip6_ntoa),
TESTFUNC(test_ip6_lladdr)
};
return create_suite("IPv6", tests, sizeof(tests)/sizeof(testfunc), ip6_setup, ip6_teardown);
}
#else /* LWIP_IPV6 */
/* allow to build the unit tests without IPv6 support */
START_TEST(test_ip6_dummy)
{
LWIP_UNUSED_ARG(_i);
}
END_TEST
Suite *
ip6_suite(void)
{
testfunc tests[] = {
TESTFUNC(test_ip6_dummy),
};
return create_suite("IPv6", tests, sizeof(tests)/sizeof(testfunc), NULL, NULL);
}
#endif /* LWIP_IPV6 */

View File

@ -0,0 +1,8 @@
#ifndef LWIP_HDR_TEST_IP6_H
#define LWIP_HDR_TEST_IP6_H
#include "../lwip_check.h"
Suite* ip6_suite(void);
#endif

View File

@ -0,0 +1,42 @@
#ifndef LWIP_HDR_LWIP_CHECK_H
#define LWIP_HDR_LWIP_CHECK_H
/* Common header file for lwIP unit tests using the check framework */
#include <config.h>
#include <check.h>
#include <stdlib.h>
#define FAIL_RET() do { fail(); return; } while(0)
#define EXPECT(x) fail_unless(x)
#define EXPECT_RET(x) do { fail_unless(x); if(!(x)) { return; }} while(0)
#define EXPECT_RETX(x, y) do { fail_unless(x); if(!(x)) { return y; }} while(0)
#define EXPECT_RETNULL(x) EXPECT_RETX(x, NULL)
typedef struct {
TFun func;
const char *name;
} testfunc;
#define TESTFUNC(x) {(x), "" # x "" }
/* Modified function from check.h, supplying function name */
#define tcase_add_named_test(tc,tf) \
_tcase_add_test((tc),(tf).func,(tf).name,0, 0, 0, 1)
/** typedef for a function returning a test suite */
typedef Suite* (suite_getter_fn)(void);
/** Create a test suite */
Suite* create_suite(const char* name, testfunc *tests, size_t num_tests, SFun setup, SFun teardown);
#ifdef LWIP_UNITTESTS_LIB
int lwip_unittests_run(void)
#endif
/* helper functions */
#define SKIP_POOL(x) (1 << x)
#define SKIP_HEAP (1 << MEMP_MAX)
void lwip_check_ensure_no_alloc(unsigned int skip);
#endif /* LWIP_HDR_LWIP_CHECK_H */

View File

@ -0,0 +1,107 @@
#include "lwip_check.h"
#include "ip4/test_ip4.h"
#include "ip6/test_ip6.h"
#include "udp/test_udp.h"
#include "tcp/test_tcp.h"
#include "tcp/test_tcp_oos.h"
#include "core/test_def.h"
#include "core/test_mem.h"
#include "core/test_netif.h"
#include "core/test_pbuf.h"
#include "core/test_timers.h"
#include "etharp/test_etharp.h"
#include "dhcp/test_dhcp.h"
#include "mdns/test_mdns.h"
#include "mqtt/test_mqtt.h"
#include "api/test_sockets.h"
#include "lwip/init.h"
#if !NO_SYS
#include "lwip/tcpip.h"
#endif
Suite* create_suite(const char* name, testfunc *tests, size_t num_tests, SFun setup, SFun teardown)
{
size_t i;
Suite *s = suite_create(name);
for(i = 0; i < num_tests; i++) {
TCase *tc_core = tcase_create(name);
if ((setup != NULL) || (teardown != NULL)) {
tcase_add_checked_fixture(tc_core, setup, teardown);
}
tcase_add_named_test(tc_core, tests[i]);
suite_add_tcase(s, tc_core);
}
return s;
}
void lwip_check_ensure_no_alloc(unsigned int skip)
{
int i;
unsigned int mask;
if (!(skip & SKIP_HEAP)) {
fail_unless(lwip_stats.mem.used == 0);
}
for (i = 0, mask = 1; i < MEMP_MAX; i++, mask <<= 1) {
if (!(skip & mask)) {
fail_unless(lwip_stats.memp[i]->used == 0);
}
}
}
#ifdef LWIP_UNITTESTS_LIB
int lwip_unittests_run(void)
#else
int main(void)
#endif
{
int number_failed;
SRunner *sr;
size_t i;
suite_getter_fn* suites[] = {
ip4_suite,
ip6_suite,
udp_suite,
tcp_suite,
tcp_oos_suite,
def_suite,
mem_suite,
netif_suite,
pbuf_suite,
timers_suite,
etharp_suite,
dhcp_suite,
mdns_suite,
mqtt_suite,
sockets_suite
};
size_t num = sizeof(suites)/sizeof(void*);
LWIP_ASSERT("No suites defined", num > 0);
#if NO_SYS
lwip_init();
#else
tcpip_init(NULL, NULL);
#endif
sr = srunner_create((suites[0])());
srunner_set_xml(sr, "lwip_unittests.xml");
for(i = 1; i < num; i++) {
srunner_add_suite(sr, ((suite_getter_fn*)suites[i])());
}
#ifdef LWIP_UNITTESTS_NOFORK
srunner_set_fork_status(sr, CK_NOFORK);
#endif
#ifdef LWIP_UNITTESTS_FORK
srunner_set_fork_status(sr, CK_FORK);
#endif
srunner_run_all(sr, CK_NORMAL);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

85
lwip/test/unit/lwipopts.h Normal file
View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Simon Goldschmidt
*
*/
#ifndef LWIP_HDR_LWIPOPTS_H
#define LWIP_HDR_LWIPOPTS_H
#define LWIP_TESTMODE 1
#define LWIP_IPV6 1
#define LWIP_CHECKSUM_ON_COPY 1
#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK 1
#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK_FAIL(printfmsg) LWIP_ASSERT("TCP_CHECKSUM_ON_COPY_SANITY_CHECK_FAIL", 0)
/* We link to special sys_arch.c (for basic non-waiting API layers unit tests) */
#define NO_SYS 0
#define SYS_LIGHTWEIGHT_PROT 0
#define LWIP_NETCONN !NO_SYS
#define LWIP_SOCKET !NO_SYS
#define LWIP_NETCONN_FULLDUPLEX LWIP_SOCKET
#define LWIP_NETBUF_RECVINFO 1
#define LWIP_HAVE_LOOPIF 1
#define TCPIP_THREAD_TEST
/* Enable DHCP to test it, disable UDP checksum to easier inject packets */
#define LWIP_DHCP 1
/* Minimal changes to opt.h required for tcp unit tests: */
#define MEM_SIZE 16000
#define TCP_SND_QUEUELEN 40
#define MEMP_NUM_TCP_SEG TCP_SND_QUEUELEN
#define TCP_SND_BUF (12 * TCP_MSS)
#define TCP_WND (10 * TCP_MSS)
#define LWIP_WND_SCALE 1
#define TCP_RCV_SCALE 0
#define PBUF_POOL_SIZE 400 /* pbuf tests need ~200KByte */
/* Enable IGMP and MDNS for MDNS tests */
#define LWIP_IGMP 1
#define LWIP_MDNS_RESPONDER 1
#define LWIP_NUM_NETIF_CLIENT_DATA (LWIP_MDNS_RESPONDER)
/* Minimal changes to opt.h required for etharp unit tests: */
#define ETHARP_SUPPORT_STATIC_ENTRIES 1
#define MEMP_NUM_SYS_TIMEOUT (LWIP_NUM_SYS_TIMEOUT_INTERNAL + 8)
/* MIB2 stats are required to check IPv4 reassembly results */
#define MIB2_STATS 1
/* netif tests want to test this, so enable: */
#define LWIP_NETIF_EXT_STATUS_CALLBACK 1
/* Check lwip_stats.mem.illegal instead of asserting */
#define LWIP_MEM_ILLEGAL_FREE(msg) /* to nothing */
#endif /* LWIP_HDR_LWIPOPTS_H */

View File

@ -0,0 +1,915 @@
/*
* Copyright (c) 2015 Verisure Innovation AB
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Erik Ekman <erik@kryo.se>
*
*/
#include "test_mdns.h"
#include "lwip/pbuf.h"
#include "lwip/apps/mdns.h"
#include "lwip/apps/mdns_priv.h"
START_TEST(readname_basic)
{
static const u8_t data[] = { 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x00 };
struct pbuf *p;
struct mdns_domain domain;
u16_t offset;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM);
fail_if(p == NULL);
p->payload = (void *)(size_t)data;
offset = mdns_readname(p, 0, &domain);
pbuf_free(p);
fail_unless(offset == sizeof(data));
fail_unless(domain.length == sizeof(data));
fail_if(memcmp(&domain.name, data, sizeof(data)));
}
END_TEST
START_TEST(readname_anydata)
{
static const u8_t data[] = { 0x05, 0x00, 0xFF, 0x08, 0xc0, 0x0f, 0x04, 0x7f, 0x80, 0x82, 0x88, 0x00 };
struct pbuf *p;
struct mdns_domain domain;
u16_t offset;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM);
fail_if(p == NULL);
p->payload = (void *)(size_t)data;
offset = mdns_readname(p, 0, &domain);
pbuf_free(p);
fail_unless(offset == sizeof(data));
fail_unless(domain.length == sizeof(data));
fail_if(memcmp(&domain.name, data, sizeof(data)));
}
END_TEST
START_TEST(readname_short_buf)
{
static const u8_t data[] = { 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a' };
struct pbuf *p;
struct mdns_domain domain;
u16_t offset;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM);
fail_if(p == NULL);
p->payload = (void *)(size_t)data;
offset = mdns_readname(p, 0, &domain);
pbuf_free(p);
fail_unless(offset == MDNS_READNAME_ERROR);
}
END_TEST
START_TEST(readname_long_label)
{
static const u8_t data[] = {
0x05, 'm', 'u', 'l', 't', 'i',
0x52, 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 0x00
};
struct pbuf *p;
struct mdns_domain domain;
u16_t offset;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM);
fail_if(p == NULL);
p->payload = (void *)(size_t)data;
offset = mdns_readname(p, 0, &domain);
pbuf_free(p);
fail_unless(offset == MDNS_READNAME_ERROR);
}
END_TEST
START_TEST(readname_overflow)
{
static const u8_t data[] = {
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x00
};
struct pbuf *p;
struct mdns_domain domain;
u16_t offset;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM);
fail_if(p == NULL);
p->payload = (void *)(size_t)data;
offset = mdns_readname(p, 0, &domain);
pbuf_free(p);
fail_unless(offset == MDNS_READNAME_ERROR);
}
END_TEST
START_TEST(readname_jump_earlier)
{
static const u8_t data[] = {
/* Some padding needed, not supported to jump to bytes containing dns header */
/* 0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 10 */ 0x0f, 0x0e, 0x05, 'l', 'o', 'c', 'a', 'l', 0x00, 0xab,
/* 20 */ 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc0, 0x0c
};
static const u8_t fullname[] = {
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00
};
struct pbuf *p;
struct mdns_domain domain;
u16_t offset;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM);
fail_if(p == NULL);
p->payload = (void *)(size_t)data;
offset = mdns_readname(p, 20, &domain);
pbuf_free(p);
fail_unless(offset == sizeof(data));
fail_unless(domain.length == sizeof(fullname));
fail_if(memcmp(&domain.name, fullname, sizeof(fullname)));
}
END_TEST
START_TEST(readname_jump_earlier_jump)
{
static const u8_t data[] = {
/* Some padding needed, not supported to jump to bytes containing dns header */
/* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x03, 0x0b, 0x0a, 0xf2,
/* 0x10 */ 0x04, 'c', 'a', 's', 't', 0x00, 0xc0, 0x10,
/* 0x18 */ 0x05, 'm', 'u', 'l', 't', 'i', 0xc0, 0x16
};
static const u8_t fullname[] = {
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x00
};
struct pbuf *p;
struct mdns_domain domain;
u16_t offset;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM);
fail_if(p == NULL);
p->payload = (void *)(size_t)data;
offset = mdns_readname(p, 0x18, &domain);
pbuf_free(p);
fail_unless(offset == sizeof(data));
fail_unless(domain.length == sizeof(fullname));
fail_if(memcmp(&domain.name, fullname, sizeof(fullname)));
}
END_TEST
START_TEST(readname_jump_maxdepth)
{
static const u8_t data[] = {
/* Some padding needed, not supported to jump to bytes containing dns header */
/* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x03, 0x0b, 0x0a, 0xf2,
/* 0x10 */ 0x04, 'n', 'a', 'm', 'e', 0xc0, 0x27, 0x03,
/* 0x18 */ 0x03, 'd', 'n', 's', 0xc0, 0x10, 0xc0, 0x10,
/* 0x20 */ 0x04, 'd', 'e', 'e', 'p', 0xc0, 0x18, 0x00,
/* 0x28 */ 0x04, 'c', 'a', 's', 't', 0xc0, 0x20, 0xb0,
/* 0x30 */ 0x05, 'm', 'u', 'l', 't', 'i', 0xc0, 0x28
};
static const u8_t fullname[] = {
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't',
0x04, 'd', 'e', 'e', 'p', 0x03, 'd', 'n', 's',
0x04, 'n', 'a', 'm', 'e', 0x00
};
struct pbuf *p;
struct mdns_domain domain;
u16_t offset;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM);
fail_if(p == NULL);
p->payload = (void *)(size_t)data;
offset = mdns_readname(p, 0x30, &domain);
pbuf_free(p);
fail_unless(offset == sizeof(data));
fail_unless(domain.length == sizeof(fullname));
fail_if(memcmp(&domain.name, fullname, sizeof(fullname)));
}
END_TEST
START_TEST(readname_jump_later)
{
static const u8_t data[] = {
/* 0x00 */ 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc0, 0x10, 0x00, 0x01, 0x40,
/* 0x10 */ 0x05, 'l', 'o', 'c', 'a', 'l', 0x00, 0xab
};
static const u8_t fullname[] = {
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00
};
struct pbuf *p;
struct mdns_domain domain;
u16_t offset;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM);
fail_if(p == NULL);
p->payload = (void *)(size_t)data;
offset = mdns_readname(p, 0, &domain);
pbuf_free(p);
fail_unless(offset == 13);
fail_unless(domain.length == sizeof(fullname));
fail_if(memcmp(&domain.name, fullname, sizeof(fullname)));
}
END_TEST
START_TEST(readname_half_jump)
{
static const u8_t data[] = {
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc0
};
struct pbuf *p;
struct mdns_domain domain;
u16_t offset;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM);
fail_if(p == NULL);
p->payload = (void *)(size_t)data;
offset = mdns_readname(p, 0, &domain);
pbuf_free(p);
fail_unless(offset == MDNS_READNAME_ERROR);
}
END_TEST
START_TEST(readname_jump_toolong)
{
static const u8_t data[] = {
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc2, 0x10, 0x00, 0x01, 0x40
};
struct pbuf *p;
struct mdns_domain domain;
u16_t offset;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM);
fail_if(p == NULL);
p->payload = (void *)(size_t)data;
offset = mdns_readname(p, 0, &domain);
pbuf_free(p);
fail_unless(offset == MDNS_READNAME_ERROR);
}
END_TEST
START_TEST(readname_jump_loop_label)
{
static const u8_t data[] = {
/* 0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 10 */ 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc0, 0x10
};
struct pbuf *p;
struct mdns_domain domain;
u16_t offset;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM);
fail_if(p == NULL);
p->payload = (void *)(size_t)data;
offset = mdns_readname(p, 10, &domain);
pbuf_free(p);
fail_unless(offset == MDNS_READNAME_ERROR);
}
END_TEST
START_TEST(readname_jump_loop_jump)
{
static const u8_t data[] = {
/* 0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 10 */ 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0xc0, 0x15
};
struct pbuf *p;
struct mdns_domain domain;
u16_t offset;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM);
fail_if(p == NULL);
p->payload = (void *)(size_t)data;
offset = mdns_readname(p, 10, &domain);
pbuf_free(p);
fail_unless(offset == MDNS_READNAME_ERROR);
}
END_TEST
START_TEST(add_label_basic)
{
static const u8_t data[] = { 0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x00 };
struct mdns_domain domain;
err_t res;
LWIP_UNUSED_ARG(_i);
memset(&domain, 0, sizeof(domain));
res = mdns_domain_add_label(&domain, "multi", 5);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain, "cast", 4);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain, NULL, 0);
fail_unless(res == ERR_OK);
fail_unless(domain.length == sizeof(data));
fail_if(memcmp(&domain.name, data, sizeof(data)));
}
END_TEST
START_TEST(add_label_long_label)
{
static const char *toolong = "abcdefghijklmnopqrstuvwxyz0123456789-abcdefghijklmnopqrstuvwxyz0123456789-abcdefghijklmnopqrstuvwxyz0123456789-";
struct mdns_domain domain;
err_t res;
LWIP_UNUSED_ARG(_i);
memset(&domain, 0, sizeof(domain));
res = mdns_domain_add_label(&domain, "multi", 5);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain, toolong, (u8_t)strlen(toolong));
fail_unless(res == ERR_VAL);
}
END_TEST
START_TEST(add_label_full)
{
static const char *label = "0123456789abcdef0123456789abcdef";
struct mdns_domain domain;
err_t res;
LWIP_UNUSED_ARG(_i);
memset(&domain, 0, sizeof(domain));
res = mdns_domain_add_label(&domain, label, (u8_t)strlen(label));
fail_unless(res == ERR_OK);
fail_unless(domain.length == 33);
res = mdns_domain_add_label(&domain, label, (u8_t)strlen(label));
fail_unless(res == ERR_OK);
fail_unless(domain.length == 66);
res = mdns_domain_add_label(&domain, label, (u8_t)strlen(label));
fail_unless(res == ERR_OK);
fail_unless(domain.length == 99);
res = mdns_domain_add_label(&domain, label, (u8_t)strlen(label));
fail_unless(res == ERR_OK);
fail_unless(domain.length == 132);
res = mdns_domain_add_label(&domain, label, (u8_t)strlen(label));
fail_unless(res == ERR_OK);
fail_unless(domain.length == 165);
res = mdns_domain_add_label(&domain, label, (u8_t)strlen(label));
fail_unless(res == ERR_OK);
fail_unless(domain.length == 198);
res = mdns_domain_add_label(&domain, label, (u8_t)strlen(label));
fail_unless(res == ERR_OK);
fail_unless(domain.length == 231);
res = mdns_domain_add_label(&domain, label, (u8_t)strlen(label));
fail_unless(res == ERR_VAL);
fail_unless(domain.length == 231);
res = mdns_domain_add_label(&domain, label, 25);
fail_unless(res == ERR_VAL);
fail_unless(domain.length == 231);
res = mdns_domain_add_label(&domain, label, 24);
fail_unless(res == ERR_VAL);
fail_unless(domain.length == 231);
res = mdns_domain_add_label(&domain, label, 23);
fail_unless(res == ERR_OK);
fail_unless(domain.length == 255);
res = mdns_domain_add_label(&domain, NULL, 0);
fail_unless(res == ERR_OK);
fail_unless(domain.length == 256);
res = mdns_domain_add_label(&domain, NULL, 0);
fail_unless(res == ERR_VAL);
fail_unless(domain.length == 256);
}
END_TEST
START_TEST(domain_eq_basic)
{
static const u8_t data[] = {
0x05, 'm', 'u', 'l', 't', 'i', 0x04, 'c', 'a', 's', 't', 0x00
};
struct mdns_domain domain1, domain2;
err_t res;
LWIP_UNUSED_ARG(_i);
memset(&domain1, 0, sizeof(domain1));
res = mdns_domain_add_label(&domain1, "multi", 5);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain1, "cast", 4);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain1, NULL, 0);
fail_unless(res == ERR_OK);
fail_unless(domain1.length == sizeof(data));
memset(&domain2, 0, sizeof(domain2));
res = mdns_domain_add_label(&domain2, "multi", 5);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain2, "cast", 4);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain2, NULL, 0);
fail_unless(res == ERR_OK);
fail_unless(mdns_domain_eq(&domain1, &domain2));
}
END_TEST
START_TEST(domain_eq_diff)
{
struct mdns_domain domain1, domain2;
err_t res;
LWIP_UNUSED_ARG(_i);
memset(&domain1, 0, sizeof(domain1));
res = mdns_domain_add_label(&domain1, "multi", 5);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain1, "base", 4);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain1, NULL, 0);
fail_unless(res == ERR_OK);
memset(&domain2, 0, sizeof(domain2));
res = mdns_domain_add_label(&domain2, "multi", 5);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain2, "cast", 4);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain2, NULL, 0);
fail_unless(res == ERR_OK);
fail_if(mdns_domain_eq(&domain1, &domain2));
}
END_TEST
START_TEST(domain_eq_case)
{
struct mdns_domain domain1, domain2;
err_t res;
LWIP_UNUSED_ARG(_i);
memset(&domain1, 0, sizeof(domain1));
res = mdns_domain_add_label(&domain1, "multi", 5);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain1, "cast", 4);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain1, NULL, 0);
fail_unless(res == ERR_OK);
memset(&domain2, 0, sizeof(domain2));
res = mdns_domain_add_label(&domain2, "MulTI", 5);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain2, "casT", 4);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain2, NULL, 0);
fail_unless(res == ERR_OK);
fail_unless(mdns_domain_eq(&domain1, &domain2));
}
END_TEST
START_TEST(domain_eq_anydata)
{
static const u8_t data1[] = { 0x05, 0xcc, 0xdc, 0x00, 0xa0 };
static const u8_t data2[] = { 0x7f, 0x8c, 0x01, 0xff, 0xcf };
struct mdns_domain domain1, domain2;
err_t res;
LWIP_UNUSED_ARG(_i);
memset(&domain1, 0, sizeof(domain1));
res = mdns_domain_add_label(&domain1, (const char*)data1, sizeof(data1));
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain1, "cast", 4);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain1, (const char*)data2, sizeof(data2));
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain1, NULL, 0);
fail_unless(res == ERR_OK);
memset(&domain2, 0, sizeof(domain2));
res = mdns_domain_add_label(&domain2, (const char*)data1, sizeof(data1));
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain2, "casT", 4);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain2, (const char*)data2, sizeof(data2));
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain2, NULL, 0);
fail_unless(res == ERR_OK);
fail_unless(mdns_domain_eq(&domain1, &domain2));
}
END_TEST
START_TEST(domain_eq_length)
{
struct mdns_domain domain1, domain2;
err_t res;
LWIP_UNUSED_ARG(_i);
memset(&domain1, 0, sizeof(domain1));
memset(domain1.name, 0xAA, sizeof(MDNS_DOMAIN_MAXLEN));
res = mdns_domain_add_label(&domain1, "multi", 5);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain1, "cast", 4);
fail_unless(res == ERR_OK);
memset(&domain2, 0, sizeof(domain2));
memset(domain2.name, 0xBB, sizeof(MDNS_DOMAIN_MAXLEN));
res = mdns_domain_add_label(&domain2, "multi", 5);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain2, "cast", 4);
fail_unless(res == ERR_OK);
fail_unless(mdns_domain_eq(&domain1, &domain2));
}
END_TEST
START_TEST(compress_full_match)
{
static const u8_t data[] = {
0x00, 0x00,
0x06, 'f', 'o', 'o', 'b', 'a', 'r', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00
};
struct pbuf *p;
struct mdns_domain domain;
u16_t offset;
u16_t length;
err_t res;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM);
fail_if(p == NULL);
p->payload = (void *)(size_t)data;
memset(&domain, 0, sizeof(domain));
res = mdns_domain_add_label(&domain, "foobar", 6);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain, "local", 5);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain, NULL, 0);
fail_unless(res == ERR_OK);
offset = 2;
length = mdns_compress_domain(p, &offset, &domain);
/* Write 0 bytes, then a jump to addr 2 */
fail_unless(length == 0);
fail_unless(offset == 2);
pbuf_free(p);
}
END_TEST
START_TEST(compress_full_match_subset)
{
static const u8_t data[] = {
0x00, 0x00,
0x02, 'g', 'o', 0x06, 'f', 'o', 'o', 'b', 'a', 'r', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00
};
struct pbuf *p;
struct mdns_domain domain;
u16_t offset;
u16_t length;
err_t res;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM);
fail_if(p == NULL);
p->payload = (void *)(size_t)data;
memset(&domain, 0, sizeof(domain));
res = mdns_domain_add_label(&domain, "foobar", 6);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain, "local", 5);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain, NULL, 0);
fail_unless(res == ERR_OK);
offset = 2;
length = mdns_compress_domain(p, &offset, &domain);
/* Write 0 bytes, then a jump to addr 5 */
fail_unless(length == 0);
fail_unless(offset == 5);
pbuf_free(p);
}
END_TEST
START_TEST(compress_full_match_jump)
{
static const u8_t data[] = {
/* 0x00 */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
/* 0x10 */ 0x04, 'l', 'w', 'i', 'p', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00, 0xc0, 0x00, 0x02, 0x00,
/* 0x20 */ 0x06, 'f', 'o', 'o', 'b', 'a', 'r', 0xc0, 0x15
};
struct pbuf *p;
struct mdns_domain domain;
u16_t offset;
u16_t length;
err_t res;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM);
fail_if(p == NULL);
p->payload = (void *)(size_t)data;
memset(&domain, 0, sizeof(domain));
res = mdns_domain_add_label(&domain, "foobar", 6);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain, "local", 5);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain, NULL, 0);
fail_unless(res == ERR_OK);
offset = 0x20;
length = mdns_compress_domain(p, &offset, &domain);
/* Write 0 bytes, then a jump to addr 0x20 */
fail_unless(length == 0);
fail_unless(offset == 0x20);
pbuf_free(p);
}
END_TEST
START_TEST(compress_no_match)
{
static const u8_t data[] = {
0x00, 0x00,
0x04, 'l', 'w', 'i', 'p', 0x05, 'w', 'i', 'k', 'i', 'a', 0x03, 'c', 'o', 'm', 0x00
};
struct pbuf *p;
struct mdns_domain domain;
u16_t offset;
u16_t length;
err_t res;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM);
fail_if(p == NULL);
p->payload = (void *)(size_t)data;
memset(&domain, 0, sizeof(domain));
res = mdns_domain_add_label(&domain, "foobar", 6);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain, "local", 5);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain, NULL, 0);
fail_unless(res == ERR_OK);
offset = 2;
length = mdns_compress_domain(p, &offset, &domain);
/* Write all bytes, no jump */
fail_unless(length == domain.length);
pbuf_free(p);
}
END_TEST
START_TEST(compress_2nd_label)
{
static const u8_t data[] = {
0x00, 0x00,
0x06, 'f', 'o', 'o', 'b', 'a', 'r', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00
};
struct pbuf *p;
struct mdns_domain domain;
u16_t offset;
u16_t length;
err_t res;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM);
fail_if(p == NULL);
p->payload = (void *)(size_t)data;
memset(&domain, 0, sizeof(domain));
res = mdns_domain_add_label(&domain, "lwip", 4);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain, "local", 5);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain, NULL, 0);
fail_unless(res == ERR_OK);
offset = 2;
length = mdns_compress_domain(p, &offset, &domain);
/* Write 5 bytes, then a jump to addr 9 */
fail_unless(length == 5);
fail_unless(offset == 9);
pbuf_free(p);
}
END_TEST
START_TEST(compress_2nd_label_short)
{
static const u8_t data[] = {
0x00, 0x00,
0x04, 'l', 'w', 'i', 'p', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00
};
struct pbuf *p;
struct mdns_domain domain;
u16_t offset;
u16_t length;
err_t res;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM);
fail_if(p == NULL);
p->payload = (void *)(size_t)data;
memset(&domain, 0, sizeof(domain));
res = mdns_domain_add_label(&domain, "foobar", 6);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain, "local", 5);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain, NULL, 0);
fail_unless(res == ERR_OK);
offset = 2;
length = mdns_compress_domain(p, &offset, &domain);
/* Write 5 bytes, then a jump to addr 7 */
fail_unless(length == 7);
fail_unless(offset == 7);
pbuf_free(p);
}
END_TEST
START_TEST(compress_jump_to_jump)
{
static const u8_t data[] = {
/* 0x00 */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
/* 0x10 */ 0x04, 'l', 'w', 'i', 'p', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00, 0xc0, 0x00, 0x02, 0x00,
/* 0x20 */ 0x07, 'b', 'a', 'n', 'a', 'n', 'a', 's', 0xc0, 0x15
};
struct pbuf *p;
struct mdns_domain domain;
u16_t offset;
u16_t length;
err_t res;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM);
fail_if(p == NULL);
p->payload = (void *)(size_t)data;
memset(&domain, 0, sizeof(domain));
res = mdns_domain_add_label(&domain, "foobar", 6);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain, "local", 5);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain, NULL, 0);
fail_unless(res == ERR_OK);
offset = 0x20;
length = mdns_compress_domain(p, &offset, &domain);
/* Dont compress if jump would be to a jump */
fail_unless(length == domain.length);
offset = 0x10;
length = mdns_compress_domain(p, &offset, &domain);
/* Write 7 bytes, then a jump to addr 0x15 */
fail_unless(length == 7);
fail_unless(offset == 0x15);
pbuf_free(p);
}
END_TEST
START_TEST(compress_long_match)
{
static const u8_t data[] = {
0x00, 0x00,
0x06, 'f', 'o', 'o', 'b', 'a', 'r', 0x05, 'l', 'o', 'c', 'a', 'l', 0x03, 'c', 'o', 'm', 0x00
};
struct pbuf *p;
struct mdns_domain domain;
u16_t offset;
u16_t length;
err_t res;
LWIP_UNUSED_ARG(_i);
p = pbuf_alloc(PBUF_RAW, sizeof(data), PBUF_ROM);
fail_if(p == NULL);
p->payload = (void *)(size_t)data;
memset(&domain, 0, sizeof(domain));
res = mdns_domain_add_label(&domain, "foobar", 6);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain, "local", 5);
fail_unless(res == ERR_OK);
res = mdns_domain_add_label(&domain, NULL, 0);
fail_unless(res == ERR_OK);
offset = 2;
length = mdns_compress_domain(p, &offset, &domain);
fail_unless(length == domain.length);
pbuf_free(p);
}
END_TEST
Suite* mdns_suite(void)
{
testfunc tests[] = {
TESTFUNC(readname_basic),
TESTFUNC(readname_anydata),
TESTFUNC(readname_short_buf),
TESTFUNC(readname_long_label),
TESTFUNC(readname_overflow),
TESTFUNC(readname_jump_earlier),
TESTFUNC(readname_jump_earlier_jump),
TESTFUNC(readname_jump_maxdepth),
TESTFUNC(readname_jump_later),
TESTFUNC(readname_half_jump),
TESTFUNC(readname_jump_toolong),
TESTFUNC(readname_jump_loop_label),
TESTFUNC(readname_jump_loop_jump),
TESTFUNC(add_label_basic),
TESTFUNC(add_label_long_label),
TESTFUNC(add_label_full),
TESTFUNC(domain_eq_basic),
TESTFUNC(domain_eq_diff),
TESTFUNC(domain_eq_case),
TESTFUNC(domain_eq_anydata),
TESTFUNC(domain_eq_length),
TESTFUNC(compress_full_match),
TESTFUNC(compress_full_match_subset),
TESTFUNC(compress_full_match_jump),
TESTFUNC(compress_no_match),
TESTFUNC(compress_2nd_label),
TESTFUNC(compress_2nd_label_short),
TESTFUNC(compress_jump_to_jump),
TESTFUNC(compress_long_match),
};
return create_suite("MDNS", tests, sizeof(tests)/sizeof(testfunc), NULL, NULL);
}

View File

@ -0,0 +1,8 @@
#ifndef LWIP_HDR_TEST_MDNS_H__
#define LWIP_HDR_TEST_MDNS_H__
#include "../lwip_check.h"
Suite* mdns_suite(void);
#endif

View File

@ -0,0 +1,115 @@
#include "test_mqtt.h"
#include "lwip/pbuf.h"
#include "lwip/apps/mqtt.h"
#include "lwip/apps/mqtt_priv.h"
#include "lwip/netif.h"
const ip_addr_t test_mqtt_local_ip = IPADDR4_INIT_BYTES(192, 168, 1, 1);
const ip_addr_t test_mqtt_remote_ip = IPADDR4_INIT_BYTES(192, 168, 1, 2);
const ip_addr_t test_mqtt_netmask = IPADDR4_INIT_BYTES(255, 255, 255, 0);
static err_t test_mqtt_netif_output(struct netif *netif, struct pbuf *p,
const ip4_addr_t *ipaddr)
{
LWIP_UNUSED_ARG(netif);
LWIP_UNUSED_ARG(ipaddr);
LWIP_UNUSED_ARG(p);
return ERR_OK;
}
static void
test_mqtt_init_netif(struct netif *netif, const ip_addr_t *ip_addr, const ip_addr_t *netmask)
{
struct netif *n;
memset(netif, 0, sizeof(struct netif));
netif->output = test_mqtt_netif_output;
netif->flags |= NETIF_FLAG_UP | NETIF_FLAG_LINK_UP;
ip_addr_copy_from_ip4(netif->netmask, *ip_2_ip4(netmask));
ip_addr_copy_from_ip4(netif->ip_addr, *ip_2_ip4(ip_addr));
for (n = netif_list; n != NULL; n = n->next) {
if (n == netif) {
return;
}
}
netif->next = NULL;
netif_list = netif;
}
/* Setups/teardown functions */
static struct netif *old_netif_list;
static struct netif *old_netif_default;
static void
mqtt_setup(void)
{
old_netif_list = netif_list;
old_netif_default = netif_default;
netif_list = NULL;
netif_default = NULL;
lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
}
static void
mqtt_teardown(void)
{
netif_list = NULL;
netif_default = NULL;
/* restore netif_list for next tests (e.g. loopif) */
netif_list = old_netif_list;
netif_default = old_netif_default;
lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
}
static void test_mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status)
{
LWIP_UNUSED_ARG(client);
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(status);
}
START_TEST(basic_connect)
{
mqtt_client_t* client;
struct netif netif;
err_t err;
struct mqtt_connect_client_info_t client_info = {
"dumm",
NULL, NULL,
10,
NULL, NULL, 0, 0
};
struct pbuf *p;
unsigned char rxbuf[] = {0x20, 0x02, 0x00, 0x00};
LWIP_UNUSED_ARG(_i);
test_mqtt_init_netif(&netif, &test_mqtt_local_ip, &test_mqtt_netmask);
client = mqtt_client_new();
fail_unless(client != NULL);
err = mqtt_client_connect(client, &test_mqtt_remote_ip, 1234, test_mqtt_connection_cb, NULL, &client_info);
fail_unless(err == ERR_OK);
client->conn->connected(client->conn->callback_arg, client->conn, ERR_OK);
p = pbuf_alloc(PBUF_RAW, sizeof(rxbuf), PBUF_REF);
fail_unless(p != NULL);
p->payload = rxbuf;
/* since we hack the rx path, we have to hack the rx window, too: */
client->conn->rcv_wnd -= p->tot_len;
if (client->conn->recv(client->conn->callback_arg, client->conn, p, ERR_OK) != ERR_OK) {
pbuf_free(p);
}
mqtt_disconnect(client);
/* fixme: mqtt_client_fre() is missing... */
mem_free(client);
}
END_TEST
Suite* mqtt_suite(void)
{
testfunc tests[] = {
TESTFUNC(basic_connect),
};
return create_suite("MQTT", tests, sizeof(tests)/sizeof(testfunc), mqtt_setup, mqtt_teardown);
}

View File

@ -0,0 +1,8 @@
#ifndef LWIP_HDR_TEST_MQTT_H__
#define LWIP_HDR_TEST_MQTT_H__
#include "../lwip_check.h"
Suite* mqtt_suite(void);
#endif

View File

@ -0,0 +1,319 @@
#include "tcp_helper.h"
#include "lwip/priv/tcp_priv.h"
#include "lwip/stats.h"
#include "lwip/pbuf.h"
#include "lwip/inet_chksum.h"
#include "lwip/ip_addr.h"
#if !LWIP_STATS || !TCP_STATS || !MEMP_STATS
#error "This tests needs TCP- and MEMP-statistics enabled"
#endif
const ip_addr_t test_local_ip = IPADDR4_INIT_BYTES(192, 168, 1, 1);
const ip_addr_t test_remote_ip = IPADDR4_INIT_BYTES(192, 168, 1, 2);
const ip_addr_t test_netmask = IPADDR4_INIT_BYTES(255, 255, 255, 0);
/** Remove all pcbs on the given list. */
static void
tcp_remove(struct tcp_pcb* pcb_list)
{
struct tcp_pcb *pcb = pcb_list;
struct tcp_pcb *pcb2;
while(pcb != NULL) {
pcb2 = pcb;
pcb = pcb->next;
tcp_abort(pcb2);
}
}
/** Remove all pcbs on listen-, active- and time-wait-list (bound- isn't exported). */
void
tcp_remove_all(void)
{
tcp_remove(tcp_listen_pcbs.pcbs);
tcp_remove(tcp_bound_pcbs);
tcp_remove(tcp_active_pcbs);
tcp_remove(tcp_tw_pcbs);
fail_unless(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0);
fail_unless(MEMP_STATS_GET(used, MEMP_TCP_PCB_LISTEN) == 0);
fail_unless(MEMP_STATS_GET(used, MEMP_TCP_SEG) == 0);
fail_unless(MEMP_STATS_GET(used, MEMP_PBUF_POOL) == 0);
}
/** Create a TCP segment usable for passing to tcp_input */
static struct pbuf*
tcp_create_segment_wnd(ip_addr_t* src_ip, ip_addr_t* dst_ip,
u16_t src_port, u16_t dst_port, void* data, size_t data_len,
u32_t seqno, u32_t ackno, u8_t headerflags, u16_t wnd)
{
struct pbuf *p, *q;
struct ip_hdr* iphdr;
struct tcp_hdr* tcphdr;
u16_t pbuf_len = (u16_t)(sizeof(struct ip_hdr) + sizeof(struct tcp_hdr) + data_len);
LWIP_ASSERT("data_len too big", data_len <= 0xFFFF);
p = pbuf_alloc(PBUF_RAW, pbuf_len, PBUF_POOL);
EXPECT_RETNULL(p != NULL);
/* first pbuf must be big enough to hold the headers */
EXPECT_RETNULL(p->len >= (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr)));
if (data_len > 0) {
/* first pbuf must be big enough to hold at least 1 data byte, too */
EXPECT_RETNULL(p->len > (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr)));
}
for(q = p; q != NULL; q = q->next) {
memset(q->payload, 0, q->len);
}
iphdr = (struct ip_hdr*)p->payload;
/* fill IP header */
iphdr->dest.addr = ip_2_ip4(dst_ip)->addr;
iphdr->src.addr = ip_2_ip4(src_ip)->addr;
IPH_VHL_SET(iphdr, 4, IP_HLEN / 4);
IPH_TOS_SET(iphdr, 0);
IPH_LEN_SET(iphdr, htons(p->tot_len));
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
/* let p point to TCP header */
pbuf_header(p, -(s16_t)sizeof(struct ip_hdr));
tcphdr = (struct tcp_hdr*)p->payload;
tcphdr->src = htons(src_port);
tcphdr->dest = htons(dst_port);
tcphdr->seqno = htonl(seqno);
tcphdr->ackno = htonl(ackno);
TCPH_HDRLEN_SET(tcphdr, sizeof(struct tcp_hdr)/4);
TCPH_FLAGS_SET(tcphdr, headerflags);
tcphdr->wnd = htons(wnd);
if (data_len > 0) {
/* let p point to TCP data */
pbuf_header(p, -(s16_t)sizeof(struct tcp_hdr));
/* copy data */
pbuf_take(p, data, (u16_t)data_len);
/* let p point to TCP header again */
pbuf_header(p, sizeof(struct tcp_hdr));
}
/* calculate checksum */
tcphdr->chksum = ip_chksum_pseudo(p,
IP_PROTO_TCP, p->tot_len, src_ip, dst_ip);
pbuf_header(p, sizeof(struct ip_hdr));
return p;
}
/** Create a TCP segment usable for passing to tcp_input */
struct pbuf*
tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip,
u16_t src_port, u16_t dst_port, void* data, size_t data_len,
u32_t seqno, u32_t ackno, u8_t headerflags)
{
return tcp_create_segment_wnd(src_ip, dst_ip, src_port, dst_port, data,
data_len, seqno, ackno, headerflags, TCP_WND);
}
/** Create a TCP segment usable for passing to tcp_input
* - IP-addresses, ports, seqno and ackno are taken from pcb
* - seqno and ackno can be altered with an offset
*/
struct pbuf*
tcp_create_rx_segment(struct tcp_pcb* pcb, void* data, size_t data_len, u32_t seqno_offset,
u32_t ackno_offset, u8_t headerflags)
{
return tcp_create_segment(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, pcb->local_port,
data, data_len, pcb->rcv_nxt + seqno_offset, pcb->lastack + ackno_offset, headerflags);
}
/** Create a TCP segment usable for passing to tcp_input
* - IP-addresses, ports, seqno and ackno are taken from pcb
* - seqno and ackno can be altered with an offset
* - TCP window can be adjusted
*/
struct pbuf* tcp_create_rx_segment_wnd(struct tcp_pcb* pcb, void* data, size_t data_len,
u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags, u16_t wnd)
{
return tcp_create_segment_wnd(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, pcb->local_port,
data, data_len, pcb->rcv_nxt + seqno_offset, pcb->lastack + ackno_offset, headerflags, wnd);
}
/** Safely bring a tcp_pcb into the requested state */
void
tcp_set_state(struct tcp_pcb* pcb, enum tcp_state state, const ip_addr_t* local_ip,
const ip_addr_t* remote_ip, u16_t local_port, u16_t remote_port)
{
u32_t iss;
/* @todo: are these all states? */
/* @todo: remove from previous list */
pcb->state = state;
iss = tcp_next_iss(pcb);
pcb->snd_wl2 = iss;
pcb->snd_nxt = iss;
pcb->lastack = iss;
pcb->snd_lbb = iss;
if (state == ESTABLISHED) {
TCP_REG(&tcp_active_pcbs, pcb);
ip_addr_copy(pcb->local_ip, *local_ip);
pcb->local_port = local_port;
ip_addr_copy(pcb->remote_ip, *remote_ip);
pcb->remote_port = remote_port;
} else if(state == LISTEN) {
TCP_REG(&tcp_listen_pcbs.pcbs, pcb);
ip_addr_copy(pcb->local_ip, *local_ip);
pcb->local_port = local_port;
} else if(state == TIME_WAIT) {
TCP_REG(&tcp_tw_pcbs, pcb);
ip_addr_copy(pcb->local_ip, *local_ip);
pcb->local_port = local_port;
ip_addr_copy(pcb->remote_ip, *remote_ip);
pcb->remote_port = remote_port;
} else {
fail();
}
}
void
test_tcp_counters_err(void* arg, err_t err)
{
struct test_tcp_counters* counters = (struct test_tcp_counters*)arg;
EXPECT_RET(arg != NULL);
counters->err_calls++;
counters->last_err = err;
}
static void
test_tcp_counters_check_rxdata(struct test_tcp_counters* counters, struct pbuf* p)
{
struct pbuf* q;
u32_t i, received;
if(counters->expected_data == NULL) {
/* no data to compare */
return;
}
EXPECT_RET(counters->recved_bytes + p->tot_len <= counters->expected_data_len);
received = counters->recved_bytes;
for(q = p; q != NULL; q = q->next) {
char *data = (char*)q->payload;
for(i = 0; i < q->len; i++) {
EXPECT_RET(data[i] == counters->expected_data[received]);
received++;
}
}
EXPECT(received == counters->recved_bytes + p->tot_len);
}
err_t
test_tcp_counters_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err)
{
struct test_tcp_counters* counters = (struct test_tcp_counters*)arg;
EXPECT_RETX(arg != NULL, ERR_OK);
EXPECT_RETX(pcb != NULL, ERR_OK);
EXPECT_RETX(err == ERR_OK, ERR_OK);
if (p != NULL) {
if (counters->close_calls == 0) {
counters->recv_calls++;
test_tcp_counters_check_rxdata(counters, p);
counters->recved_bytes += p->tot_len;
} else {
counters->recv_calls_after_close++;
counters->recved_bytes_after_close += p->tot_len;
}
pbuf_free(p);
} else {
counters->close_calls++;
}
EXPECT(counters->recv_calls_after_close == 0 && counters->recved_bytes_after_close == 0);
return ERR_OK;
}
/** Allocate a pcb and set up the test_tcp_counters_* callbacks */
struct tcp_pcb*
test_tcp_new_counters_pcb(struct test_tcp_counters* counters)
{
struct tcp_pcb* pcb = tcp_new();
if (pcb != NULL) {
/* set up args and callbacks */
tcp_arg(pcb, counters);
tcp_recv(pcb, test_tcp_counters_recv);
tcp_err(pcb, test_tcp_counters_err);
pcb->snd_wnd = TCP_WND;
pcb->snd_wnd_max = TCP_WND;
}
return pcb;
}
/** Calls tcp_input() after adjusting current_iphdr_dest */
void test_tcp_input(struct pbuf *p, struct netif *inp)
{
struct ip_hdr *iphdr = (struct ip_hdr*)p->payload;
/* these lines are a hack, don't use them as an example :-) */
ip_addr_copy_from_ip4(*ip_current_dest_addr(), iphdr->dest);
ip_addr_copy_from_ip4(*ip_current_src_addr(), iphdr->src);
ip_current_netif() = inp;
ip_data.current_ip4_header = iphdr;
/* since adding IPv6, p->payload must point to tcp header, not ip header */
pbuf_header(p, -(s16_t)sizeof(struct ip_hdr));
tcp_input(p, inp);
ip_addr_set_zero(ip_current_dest_addr());
ip_addr_set_zero(ip_current_src_addr());
ip_current_netif() = NULL;
ip_data.current_ip4_header = NULL;
}
static err_t test_tcp_netif_output(struct netif *netif, struct pbuf *p,
const ip4_addr_t *ipaddr)
{
struct test_tcp_txcounters *txcounters = (struct test_tcp_txcounters*)netif->state;
LWIP_UNUSED_ARG(ipaddr);
if (txcounters != NULL)
{
txcounters->num_tx_calls++;
txcounters->num_tx_bytes += p->tot_len;
if (txcounters->copy_tx_packets) {
struct pbuf *p_copy = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
err_t err;
EXPECT(p_copy != NULL);
err = pbuf_copy(p_copy, p);
EXPECT(err == ERR_OK);
if (txcounters->tx_packets == NULL) {
txcounters->tx_packets = p_copy;
} else {
pbuf_cat(txcounters->tx_packets, p_copy);
}
}
}
return ERR_OK;
}
void test_tcp_init_netif(struct netif *netif, struct test_tcp_txcounters *txcounters,
const ip_addr_t *ip_addr, const ip_addr_t *netmask)
{
struct netif *n;
memset(netif, 0, sizeof(struct netif));
if (txcounters != NULL) {
memset(txcounters, 0, sizeof(struct test_tcp_txcounters));
netif->state = txcounters;
}
netif->output = test_tcp_netif_output;
netif->flags |= NETIF_FLAG_UP | NETIF_FLAG_LINK_UP;
ip_addr_copy_from_ip4(netif->netmask, *ip_2_ip4(netmask));
ip_addr_copy_from_ip4(netif->ip_addr, *ip_2_ip4(ip_addr));
for (n = netif_list; n != NULL; n = n->next) {
if (n == netif) {
return;
}
}
netif->next = NULL;
netif_list = netif;
}

View File

@ -0,0 +1,58 @@
#ifndef LWIP_HDR_TCP_HELPER_H
#define LWIP_HDR_TCP_HELPER_H
#include "../lwip_check.h"
#include "lwip/arch.h"
#include "lwip/tcp.h"
#include "lwip/netif.h"
/* counters used for test_tcp_counters_* callback functions */
struct test_tcp_counters {
u32_t recv_calls;
u32_t recved_bytes;
u32_t recv_calls_after_close;
u32_t recved_bytes_after_close;
u32_t close_calls;
u32_t err_calls;
err_t last_err;
char* expected_data;
u32_t expected_data_len;
};
struct test_tcp_txcounters {
u32_t num_tx_calls;
u32_t num_tx_bytes;
u8_t copy_tx_packets;
struct pbuf *tx_packets;
};
extern const ip_addr_t test_local_ip;
extern const ip_addr_t test_remote_ip;
extern const ip_addr_t test_netmask;
#define TEST_REMOTE_PORT 0x100
#define TEST_LOCAL_PORT 0x101
/* Helper functions */
void tcp_remove_all(void);
struct pbuf* tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip,
u16_t src_port, u16_t dst_port, void* data, size_t data_len,
u32_t seqno, u32_t ackno, u8_t headerflags);
struct pbuf* tcp_create_rx_segment(struct tcp_pcb* pcb, void* data, size_t data_len,
u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags);
struct pbuf* tcp_create_rx_segment_wnd(struct tcp_pcb* pcb, void* data, size_t data_len,
u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags, u16_t wnd);
void tcp_set_state(struct tcp_pcb* pcb, enum tcp_state state, const ip_addr_t* local_ip,
const ip_addr_t* remote_ip, u16_t local_port, u16_t remote_port);
void test_tcp_counters_err(void* arg, err_t err);
err_t test_tcp_counters_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err);
struct tcp_pcb* test_tcp_new_counters_pcb(struct test_tcp_counters* counters);
void test_tcp_input(struct pbuf *p, struct netif *inp);
void test_tcp_init_netif(struct netif *netif, struct test_tcp_txcounters *txcounters,
const ip_addr_t *ip_addr, const ip_addr_t *netmask);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
#ifndef LWIP_HDR_TEST_TCP_H
#define LWIP_HDR_TEST_TCP_H
#include "../lwip_check.h"
Suite *tcp_suite(void);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
#ifndef LWIP_HDR_TEST_TCP_OOS_H
#define LWIP_HDR_TEST_TCP_OOS_H
#include "../lwip_check.h"
Suite *tcp_oos_suite(void);
#endif

View File

@ -0,0 +1,347 @@
#include "test_udp.h"
#include "lwip/udp.h"
#include "lwip/stats.h"
#include "lwip/inet_chksum.h"
#if !LWIP_STATS || !UDP_STATS || !MEMP_STATS
#error "This tests needs UDP- and MEMP-statistics enabled"
#endif
struct test_udp_rxdata {
u32_t rx_cnt;
u32_t rx_bytes;
struct udp_pcb *pcb;
};
static struct netif test_netif1, test_netif2;
static ip4_addr_t test_gw1, test_ipaddr1, test_netmask1;
static ip4_addr_t test_gw2, test_ipaddr2, test_netmask2;
static int output_ctr, linkoutput_ctr;
/* Helper functions */
static void
udp_remove_all(void)
{
struct udp_pcb *pcb = udp_pcbs;
struct udp_pcb *pcb2;
while(pcb != NULL) {
pcb2 = pcb;
pcb = pcb->next;
udp_remove(pcb2);
}
fail_unless(MEMP_STATS_GET(used, MEMP_UDP_PCB) == 0);
}
static err_t
default_netif_output(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr)
{
fail_unless((netif == &test_netif1) || (netif == &test_netif2));
fail_unless(p != NULL);
fail_unless(ipaddr != NULL);
output_ctr++;
return ERR_OK;
}
static err_t
default_netif_linkoutput(struct netif *netif, struct pbuf *p)
{
fail_unless((netif == &test_netif1) || (netif == &test_netif2));
fail_unless(p != NULL);
linkoutput_ctr++;
return ERR_OK;
}
static err_t
default_netif_init(struct netif *netif)
{
fail_unless(netif != NULL);
netif->output = default_netif_output;
netif->linkoutput = default_netif_linkoutput;
netif->mtu = 1500;
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
netif->hwaddr_len = 6;
return ERR_OK;
}
static void
default_netif_add(void)
{
struct netif *n;
#if LWIP_HAVE_LOOPIF
fail_unless(netif_list != NULL); /* the loopif */
fail_unless(netif_list->next == NULL);
#else
fail_unless(netif_list == NULL);
#endif
fail_unless(netif_default == NULL);
IP4_ADDR(&test_ipaddr1, 192,168,0,1);
IP4_ADDR(&test_netmask1, 255,255,255,0);
IP4_ADDR(&test_gw1, 192,168,0,254);
n = netif_add(&test_netif1, &test_ipaddr1, &test_netmask1,
&test_gw1, NULL, default_netif_init, NULL);
fail_unless(n == &test_netif1);
IP4_ADDR(&test_ipaddr2, 192,168,1,1);
IP4_ADDR(&test_netmask2, 255,255,255,0);
IP4_ADDR(&test_gw2, 192,168,1,254);
n = netif_add(&test_netif2, &test_ipaddr2, &test_netmask2,
&test_gw2, NULL, default_netif_init, NULL);
fail_unless(n == &test_netif2);
netif_set_default(&test_netif1);
netif_set_up(&test_netif1);
netif_set_up(&test_netif2);
}
static void
default_netif_remove(void)
{
fail_unless(netif_default == &test_netif1);
netif_remove(&test_netif1);
netif_remove(&test_netif2);
fail_unless(netif_default == NULL);
#if LWIP_HAVE_LOOPIF
fail_unless(netif_list != NULL); /* the loopif */
fail_unless(netif_list->next == NULL);
#else
fail_unless(netif_list == NULL);
#endif
}
/* Setups/teardown functions */
static void
udp_setup(void)
{
udp_remove_all();
default_netif_add();
lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
}
static void
udp_teardown(void)
{
udp_remove_all();
default_netif_remove();
lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
}
/* Test functions */
START_TEST(test_udp_new_remove)
{
struct udp_pcb* pcb;
LWIP_UNUSED_ARG(_i);
fail_unless(MEMP_STATS_GET(used, MEMP_UDP_PCB) == 0);
pcb = udp_new();
fail_unless(pcb != NULL);
if (pcb != NULL) {
fail_unless(MEMP_STATS_GET(used, MEMP_UDP_PCB) == 1);
udp_remove(pcb);
fail_unless(MEMP_STATS_GET(used, MEMP_UDP_PCB) == 0);
}
}
END_TEST
static void test_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p,
const ip_addr_t *addr, u16_t port)
{
struct test_udp_rxdata *ctr = (struct test_udp_rxdata *)arg;
LWIP_UNUSED_ARG(addr);
LWIP_UNUSED_ARG(port);
fail_unless(arg != NULL);
fail_unless(ctr->pcb == pcb);
ctr->rx_cnt++;
ctr->rx_bytes += p->tot_len;
if (p != NULL) {
pbuf_free(p);
}
}
static struct pbuf *
test_udp_create_test_packet(u16_t length, u16_t port, u32_t dst_addr)
{
err_t err;
u8_t ret;
struct udp_hdr *uh;
struct ip_hdr *ih;
struct pbuf *p;
const u8_t test_data[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
p = pbuf_alloc(PBUF_TRANSPORT, length, PBUF_POOL);
fail_unless(p != NULL);
if (p == NULL) {
return NULL;
}
fail_unless(p->next == NULL);
err = pbuf_take(p, test_data, length);
fail_unless(err == ERR_OK);
/* add UDP header */
ret = pbuf_add_header(p, sizeof(struct udp_hdr));
fail_unless(!ret);
uh = (struct udp_hdr *)p->payload;
uh->chksum = 0;
uh->dest = uh->src = lwip_htons(port);
uh->len = lwip_htons(p->tot_len);
/* add IPv4 header */
ret = pbuf_add_header(p, sizeof(struct ip_hdr));
fail_unless(!ret);
ih = (struct ip_hdr *)p->payload;
memset(ih, 0, sizeof(*ih));
ih->dest.addr = dst_addr;
ih->_len = lwip_htons(p->tot_len);
ih->_ttl = 32;
ih->_proto = IP_PROTO_UDP;
IPH_VHL_SET(ih, 4, sizeof(struct ip_hdr) / 4);
IPH_CHKSUM_SET(ih, inet_chksum(ih, sizeof(struct ip_hdr)));
return p;
}
/* bind 2 pcbs to specific netif IP and test which one gets broadcasts */
START_TEST(test_udp_broadcast_rx_with_2_netifs)
{
err_t err;
struct udp_pcb *pcb1, *pcb2;
const u16_t port = 12345;
struct test_udp_rxdata ctr1, ctr2;
struct pbuf *p;
#if SO_REUSE
struct udp_pcb *pcb_any;
struct test_udp_rxdata ctr_any;
#endif
LWIP_UNUSED_ARG(_i);
pcb1 = udp_new();
fail_unless(pcb1 != NULL);
pcb2 = udp_new();
fail_unless(pcb2 != NULL);
#if SO_REUSE
pcb_any = udp_new();
fail_unless(pcb_any != NULL);
ip_set_option(pcb1, SOF_REUSEADDR);
ip_set_option(pcb2, SOF_REUSEADDR);
ip_set_option(pcb_any, SOF_REUSEADDR);
err = udp_bind(pcb_any, NULL, port);
fail_unless(err == ERR_OK);
memset(&ctr_any, 0, sizeof(ctr_any));
ctr_any.pcb = pcb_any;
udp_recv(pcb_any, test_recv, &ctr_any);
#endif
err = udp_bind(pcb1, &test_netif1.ip_addr, port);
fail_unless(err == ERR_OK);
err = udp_bind(pcb2, &test_netif2.ip_addr, port);
fail_unless(err == ERR_OK);
memset(&ctr1, 0, sizeof(ctr1));
ctr1.pcb = pcb1;
memset(&ctr2, 0, sizeof(ctr2));
ctr2.pcb = pcb2;
udp_recv(pcb1, test_recv, &ctr1);
udp_recv(pcb2, test_recv, &ctr2);
/* unicast to netif1 */
p = test_udp_create_test_packet(16, port, test_ipaddr1.addr);
EXPECT_RET(p != NULL);
err = ip4_input(p, &test_netif1);
fail_unless(err == ERR_OK);
fail_unless(ctr1.rx_cnt == 1);
fail_unless(ctr1.rx_bytes == 16);
fail_unless(ctr2.rx_cnt == 0);
#if SO_REUSE
fail_unless(ctr_any.rx_cnt == 0);
#endif
ctr1.rx_cnt = ctr1.rx_bytes = 0;
/* unicast to netif2 */
p = test_udp_create_test_packet(16, port, test_ipaddr2.addr);
EXPECT_RET(p != NULL);
err = ip4_input(p, &test_netif2);
fail_unless(err == ERR_OK);
fail_unless(ctr2.rx_cnt == 1);
fail_unless(ctr2.rx_bytes == 16);
fail_unless(ctr1.rx_cnt == 0);
#if SO_REUSE
fail_unless(ctr_any.rx_cnt == 0);
#endif
ctr2.rx_cnt = ctr2.rx_bytes = 0;
/* broadcast to netif1-broadcast, input to netif2 */
p = test_udp_create_test_packet(16, port, test_ipaddr1.addr | ~test_netmask1.addr);
EXPECT_RET(p != NULL);
err = ip4_input(p, &test_netif2);
fail_unless(err == ERR_OK);
fail_unless(ctr1.rx_cnt == 1);
fail_unless(ctr1.rx_bytes == 16);
fail_unless(ctr2.rx_cnt == 0);
#if SO_REUSE
fail_unless(ctr_any.rx_cnt == 0);
#endif
ctr1.rx_cnt = ctr1.rx_bytes = 0;
/* broadcast to netif2-broadcast, input to netif1 */
p = test_udp_create_test_packet(16, port, test_ipaddr2.addr | ~test_netmask2.addr);
EXPECT_RET(p != NULL);
err = ip4_input(p, &test_netif1);
fail_unless(err == ERR_OK);
fail_unless(ctr2.rx_cnt == 1);
fail_unless(ctr2.rx_bytes == 16);
fail_unless(ctr1.rx_cnt == 0);
#if SO_REUSE
fail_unless(ctr_any.rx_cnt == 0);
#endif
ctr2.rx_cnt = ctr2.rx_bytes = 0;
/* broadcast to global-broadcast, input to netif1 */
p = test_udp_create_test_packet(16, port, 0xffffffff);
EXPECT_RET(p != NULL);
err = ip4_input(p, &test_netif1);
fail_unless(err == ERR_OK);
fail_unless(ctr1.rx_cnt == 1);
fail_unless(ctr1.rx_bytes == 16);
fail_unless(ctr2.rx_cnt == 0);
#if SO_REUSE
fail_unless(ctr_any.rx_cnt == 0);
#endif
ctr1.rx_cnt = ctr1.rx_bytes = 0;
/* broadcast to global-broadcast, input to netif2 */
p = test_udp_create_test_packet(16, port, 0xffffffff);
EXPECT_RET(p != NULL);
err = ip4_input(p, &test_netif2);
fail_unless(err == ERR_OK);
fail_unless(ctr2.rx_cnt == 1);
fail_unless(ctr2.rx_bytes == 16);
fail_unless(ctr1.rx_cnt == 0);
#if SO_REUSE
fail_unless(ctr_any.rx_cnt == 0);
#endif
ctr2.rx_cnt = ctr2.rx_bytes = 0;
}
END_TEST
/** Create the suite including all tests for this module */
Suite *
udp_suite(void)
{
testfunc tests[] = {
TESTFUNC(test_udp_new_remove),
TESTFUNC(test_udp_broadcast_rx_with_2_netifs)
};
return create_suite("UDP", tests, sizeof(tests)/sizeof(testfunc), udp_setup, udp_teardown);
}

View File

@ -0,0 +1,8 @@
#ifndef LWIP_HDR_TEST_UDP_H
#define LWIP_HDR_TEST_UDP_H
#include "../lwip_check.h"
Suite* udp_suite(void);
#endif