1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-27 07:21:18 +01:00

Merge pull request #11930 from brummer-simon/gnrc_tcp-improve_tests

gnrc_tcp: test improvement
This commit is contained in:
Martine Lenders 2019-10-03 15:40:16 +02:00 committed by GitHub
commit e9e0001239
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 748 additions and 616 deletions

61
tests/gnrc_tcp/Makefile Normal file
View File

@ -0,0 +1,61 @@
include ../Makefile.tests_common
# Basic Configuration
BOARD ?= native
TAP ?= tap0
# Shorten default TCP timeouts to speedup testing
MSL_US ?= 1000000
TIMEOUT_US ?= 3000000
# Mark Boards with insufficient memory
BOARD_INSUFFICIENT_MEMORY := arduino-duemilanove arduino-leonardo \
arduino-mega2560 arduino-nano arduino-uno \
hifive1 hifive1b i-nucleo-lrwan1 mega-xplained \
msb-430 msb-430h nucleo-f030r8 nucleo-f031k6 \
nucleo-f042k6 nucleo-f070rb nucleo-f072rb \
nucleo-f303k8 nucleo-f334r8 nucleo-l031k6 \
nucleo-l053r8 saml10-xpro saml11-xpro \
stm32f0discovery stm32l0538-disco telosb \
waspmote-pro wsn430-v1_3b wsn430-v1_4 z1
# unsupported by ethos: chronos, hamilton, ruuvitag
BOARD_BLACKLIST := chronos hamilton ruuvitag thingy52
# This test depends on tap device setup (only allowed by root)
# Suppress test execution to avoid CI errors
TEST_ON_CI_BLACKLIST += all
CFLAGS += -DSHELL_NO_ECHO
CFLAGS += -DGNRC_TCP_MSL=$(MSL_US)
CFLAGS += -DGNRC_TCP_CONNECTION_TIMEOUT_DURATION=$(TIMEOUT_US)
ifeq (native,$(BOARD))
USEMODULE += netdev_tap
TERMFLAGS ?= $(TAP)
else
USEMODULE += stdio_ethos
ETHOS_BAUDRATE ?= 115200
CFLAGS += -DETHOS_BAUDRATE=$(ETHOS_BAUDRATE)
TERMDEPS += ethos
TERMPROG ?= sudo $(RIOTTOOLS)/ethos/ethos
TERMFLAGS ?= $(TAP) $(PORT) $(ETHOS_BAUDRATE)
endif
USEMODULE += auto_init_gnrc_netif
USEMODULE += gnrc_ipv6_default
USEMODULE += gnrc_tcp
USEMODULE += gnrc_pktbuf_cmd
USEMODULE += shell
USEMODULE += shell_commands
USEMODULE += od
# Export used tap device to environment
export TAPDEV = $(TAP)
.PHONY: ethos
ethos:
$(Q)env -u CC -u CFLAGS make -C $(RIOTTOOLS)/ethos
include $(RIOTBASE)/Makefile.include

34
tests/gnrc_tcp/README.md Normal file
View File

@ -0,0 +1,34 @@
Test description
==========
The entire GNRC TCP test consists of several test cases. Each test is ran via its own python script
in the tests directory.
1) 01-conn_lifecycle_as_client.py
This test covers TCP connection establishment and teardown with GNRC_TCP acting as tcp client.
2) 02-conn_lifecycle_as_server.py
This test covers TCP connection establishment and teardown with GNRC_TCP acting as tcp server.
3) 03-send_data.py
This test covers sending of a byte stream from GNRC_TCP to the host system.
The amount of data to send is large enough to force GNRC_TCP to split the given stream into
multiple packets.
4) 04-receive_data.py
This test covers receiving of a byte stream from the host system. The received data is
causing window opening and closing as well as data transmission over multiple packets.
Setup
==========
The test requires a tap-device setup. This can be achieved by running 'dist/tools/tapsetup/tapsetup'
or by executing the following commands:
sudo ip tuntap add tap0 mode tap user ${USER}
sudo ip link set tap0 up
Usage
==========
make BOARD=<BOARD_NAME> all flash
sudo make BOARD=<BOARD_NAME> test
'sudo' is only required if the board is not native, due to ethos usage.

308
tests/gnrc_tcp/main.c Normal file
View File

@ -0,0 +1,308 @@
/*
* Copyright (C) 2018 Simon Brummer <simon.brummer@posteo.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#include <stdio.h>
#include <string.h>
#include "shell.h"
#include "msg.h"
#include "net/af.h"
#include "net/gnrc/tcp.h"
#define MAIN_QUEUE_SIZE (8)
#define BUFFER_SIZE (2049)
static msg_t main_msg_queue[MAIN_QUEUE_SIZE];
static gnrc_tcp_tcb_t tcb;
static char buffer[BUFFER_SIZE];
void dump_args(int argc, char **argv)
{
printf("%s: ", argv[0]);
printf("argc=%d", argc);
for (int i = 0; i < argc; ++i) {
printf(", argv[%d] = %s", i, argv[i]);
}
printf("\n");
}
int get_af_family(char *family)
{
if (memcmp(family, "AF_INET6", sizeof("AF_INET6")) == 0) {
return AF_INET6;
}
else if (memcmp(family, "AF_INET", sizeof("AF_INET")) == 0) {
return AF_INET;
}
return AF_UNSPEC;
}
/* API Export for test script */
int buffer_init_cmd(int argc, char **argv)
{
dump_args(argc, argv);
memset(buffer, '\0', sizeof(buffer));
return 0;
}
int buffer_get_max_size_cmd(int argc, char **argv)
{
dump_args(argc, argv);
printf("%s: returns %d\n", argv[0], BUFFER_SIZE - 1);
return 0;
}
int buffer_write_cmd(int argc, char **argv)
{
dump_args(argc, argv);
size_t offset = atol(argv[1]);
char *src = argv[2];
size_t src_len = strlen(src);
char *dst = buffer + offset;
memcpy(dst, src, src_len);
return 0;
}
int buffer_read_cmd(int argc, char **argv)
{
dump_args(argc, argv);
size_t offset = atol(argv[1]);
size_t size = atol(argv[2]);
/* Calculate Start and End of readout */
char *begin = buffer + offset;
char *end = begin + size;
/* Place temporary endmarker in buffer and print */
char tmp = *end;
*end = '\0';
printf("%s: <begin>%s<end>\n", argv[0], begin);
*end = tmp;
return 0;
}
int gnrc_tcp_tcb_init_cmd(int argc, char **argv)
{
dump_args(argc, argv);
gnrc_tcp_tcb_init(&tcb);
return 0;
}
int gnrc_tcp_open_active_cmd(int argc, char **argv)
{
dump_args(argc, argv);
int af_family = get_af_family(argv[1]);
char *target_addr = argv[2];
uint16_t target_port = atol(argv[3]);
uint16_t local_port = atol(argv[4]);
int err = gnrc_tcp_open_active(&tcb, af_family, target_addr, target_port,
local_port);
switch (err) {
case -EAFNOSUPPORT:
printf("%s: returns -EAFNOSUPPORT\n", argv[0]);
break;
case -EINVAL:
printf("%s: returns -EINVAL\n", argv[0]);
break;
case -EISCONN:
printf("%s: returns -EISCONN\n", argv[0]);
break;
case -ENOMEM:
printf("%s: returns -ENOMEM\n", argv[0]);
break;
case -EADDRINUSE:
printf("%s: returns -EADDRINUSE\n", argv[0]);
break;
case -ETIMEDOUT:
printf("%s: returns -ETIMEOUT\n", argv[0]);
break;
case -ECONNREFUSED:
printf("%s: returns -ECONNREFUSED\n", argv[0]);
break;
default:
printf("%s: returns %d\n", argv[0], err);
}
return err;
}
int gnrc_tcp_open_passive_cmd(int argc, char **argv)
{
dump_args(argc, argv);
int af_family = get_af_family(argv[1]);
char *local_addr = NULL;
uint16_t local_port = 0;
if (argc == 3) {
local_port = atol(argv[2]);
}
else if (argc == 4) {
local_addr = argv[2];
local_port = atol(argv[3]);
}
int err = gnrc_tcp_open_passive(&tcb, af_family, local_addr, local_port);
switch (err) {
case -EAFNOSUPPORT:
printf("%s: returns -EAFNOSUPPORT\n", argv[0]);
break;
case -EINVAL:
printf("%s: returns -EINVAL\n", argv[0]);
break;
case -EISCONN:
printf("%s: returns -EISCONN\n", argv[0]);
break;
case -ENOMEM:
printf("%s: returns -ENOMEM\n", argv[0]);
break;
default:
printf("%s: returns %d\n", argv[0], err);
}
return err;
}
int gnrc_tcp_send_cmd(int argc, char **argv)
{
dump_args(argc, argv);
int timeout = atol(argv[1]);
size_t to_send = strlen(buffer);
size_t sent = 0;
while (sent < to_send) {
int ret = gnrc_tcp_send(&tcb, buffer + sent, to_send - sent, timeout);
switch (ret) {
case -ENOTCONN:
printf("%s: returns -ENOTCONN\n", argv[0]);
return ret;
case -ECONNRESET:
printf("%s: returns -ECONNRESET\n", argv[0]);
return ret;
case -ECONNABORTED:
printf("%s: returns -ECONNABORTED\n", argv[0]);
return ret;
case -ETIMEDOUT:
printf("%s: returns -ETIMEDOUT\n", argv[0]);
return ret;
}
sent += ret;
}
printf("%s: sent %u\n", argv[0], (unsigned)sent);
return sent;
}
int gnrc_tcp_recv_cmd(int argc, char **argv)
{
dump_args(argc, argv);
int timeout = atol(argv[1]);
size_t to_receive = atol(argv[2]);
size_t rcvd = 0;
while (rcvd < to_receive) {
int ret = gnrc_tcp_recv(&tcb, buffer + rcvd, to_receive - rcvd,
timeout);
switch (ret) {
case -EAGAIN:
printf("%s: returns -EAGAIN\n", argv[0]);
continue;
case -ETIMEDOUT:
printf("%s: returns -ETIMEDOUT\n", argv[0]);
continue;
case -ENOTCONN:
printf("%s: returns -ENOTCONN\n", argv[0]);
return ret;
case -ECONNRESET:
printf("%s: returns -ECONNRESET\n", argv[0]);
return ret;
case -ECONNABORTED:
printf("%s: returns -ECONNABORTED\n", argv[0]);
return ret;
}
rcvd += ret;
}
printf("%s: received %u\n", argv[0], (unsigned)rcvd);
return 0;
}
int gnrc_tcp_close_cmd(int argc, char **argv)
{
dump_args(argc, argv);
gnrc_tcp_close(&tcb);
return 0;
}
int gnrc_tcp_abort_cmd(int argc, char **argv)
{
dump_args(argc, argv);
gnrc_tcp_abort(&tcb);
return 0;
}
/* Exporting GNRC TCP Api to for shell usage */
static const shell_command_t shell_commands[] = {
{ "gnrc_tcp_tcb_init", "gnrc_tcp: init tcb", gnrc_tcp_tcb_init_cmd },
{ "gnrc_tcp_open_active", "gnrc_tcp: open active connection",
gnrc_tcp_open_active_cmd },
{ "gnrc_tcp_open_passive", "gnrc_tcp: open passive connection",
gnrc_tcp_open_passive_cmd },
{ "gnrc_tcp_send", "gnrc_tcp: send data to connected peer",
gnrc_tcp_send_cmd },
{ "gnrc_tcp_recv", "gnrc_tcp: recv data from connected peer",
gnrc_tcp_recv_cmd },
{ "gnrc_tcp_close", "gnrc_tcp: close connection gracefully",
gnrc_tcp_close_cmd },
{ "gnrc_tcp_abort", "gnrc_tcp: close connection forcefully",
gnrc_tcp_abort_cmd },
{ "buffer_init", "init internal buffer", buffer_init_cmd },
{ "buffer_get_max_size", "get max size of internal buffer",
buffer_get_max_size_cmd },
{ "buffer_write", "write data into internal buffer", buffer_write_cmd },
{ "buffer_read", "read data from internal buffer", buffer_read_cmd },
{ NULL, NULL, NULL }
};
int main(void)
{
/* we need a message queue for the thread running the shell in order to
* receive potentially fast incoming networking packets */
msg_init_queue(main_msg_queue, MAIN_QUEUE_SIZE);
printf("RIOT GNRC_TCP test application\n");
/* start shell */
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
/* should be never reached */
return 0;
}

View File

@ -0,0 +1,50 @@
#!/usr/bin/env python3
# Copyright (C) 2018 Simon Brummer <simon.brummer@posteo.de>
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
import os
import sys
import threading
from testrunner import run
from shared_func import TcpServer, generate_port_number, get_host_tap_device, \
get_host_ll_addr, get_riot_if_id, verify_pktbuf_empty, \
sudo_guard
def tcp_server(port, shutdown_event):
with TcpServer(port, shutdown_event):
pass
def testfunc(child):
port = generate_port_number()
shutdown_event = threading.Event()
server_handle = threading.Thread(target=tcp_server, args=(port, shutdown_event))
server_handle.start()
target_addr = get_host_ll_addr(get_host_tap_device()) + '%' + get_riot_if_id(child)
# Setup RIOT Node to connect to host systems TCP Server
child.sendline('gnrc_tcp_tcb_init')
child.sendline('gnrc_tcp_open_active AF_INET6 ' + target_addr + ' ' + str(port) + ' 0')
child.expect_exact('gnrc_tcp_open_active: returns 0')
# Close connection and verify that pktbuf is cleared
shutdown_event.set()
child.sendline('gnrc_tcp_close')
server_handle.join()
verify_pktbuf_empty(child)
print(os.path.basename(sys.argv[0]) + ': success')
if __name__ == '__main__':
sudo_guard()
sys.exit(run(testfunc, timeout=5, echo=False, traceback=True))

View File

@ -0,0 +1,57 @@
#!/usr/bin/env python3
# Copyright (C) 2018 Simon Brummer <simon.brummer@posteo.de>
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
import os
import sys
import socket
import threading
from testrunner import run
from shared_func import generate_port_number, get_host_tap_device, get_riot_ll_addr, \
verify_pktbuf_empty, sudo_guard
def tcp_client(addr, port, shutdown_event):
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
addr_info = socket.getaddrinfo(addr + '%' + get_host_tap_device(), port, type=socket.SOCK_STREAM)
sock.connect(addr_info[0][-1])
shutdown_event.wait()
sock.close()
def testfunc(child):
port = generate_port_number()
shutdown_event = threading.Event()
client_handle = threading.Thread(target=tcp_client, args=(get_riot_ll_addr(child), port, shutdown_event))
# Setup RIOT Node wait for incoming connections from host system
child.sendline('gnrc_tcp_tcb_init')
child.sendline('gnrc_tcp_open_passive AF_INET6 ' + str(port))
client_handle.start()
child.expect_exact('gnrc_tcp_open_passive: returns 0')
# Close connection and verify that pktbuf is cleared
shutdown_event.set()
child.sendline('gnrc_tcp_close')
client_handle.join()
verify_pktbuf_empty(child)
print(os.path.basename(sys.argv[0]) + ': success')
if __name__ == '__main__':
sudo_guard()
sys.exit(run(testfunc, timeout=5, echo=False, traceback=True))

View File

@ -0,0 +1,63 @@
#!/usr/bin/env python3
# Copyright (C) 2018 Simon Brummer <simon.brummer@posteo.de>
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
import os
import sys
import threading
from testrunner import run
from shared_func import TcpServer, generate_port_number, get_host_tap_device, \
get_host_ll_addr, get_riot_if_id, setup_internal_buffer, \
write_data_to_internal_buffer, verify_pktbuf_empty, \
sudo_guard
def tcp_server(port, shutdown_event, expected_data):
with TcpServer(port, shutdown_event) as tcp_srv:
assert tcp_srv.recv(len(expected_data)) == expected_data
def testfunc(child):
port = generate_port_number()
shutdown_event = threading.Event()
# Try to send 2000 byte from RIOT to the Host System.
data = '0123456789' * 200
data_len = len(data)
# Verify that RIOT Applications internal buffer can hold test data.
assert setup_internal_buffer(child) >= data_len
server_handle = threading.Thread(target=tcp_server, args=(port, shutdown_event, data))
server_handle.start()
target_addr = get_host_ll_addr(get_host_tap_device()) + '%' + get_riot_if_id(child)
# Setup RIOT Node to connect to host systems TCP Server
child.sendline('gnrc_tcp_tcb_init')
child.sendline('gnrc_tcp_open_active AF_INET6 ' + target_addr + ' ' + str(port) + ' 0')
child.expect_exact('gnrc_tcp_open_active: returns 0')
# Send data from RIOT Node to Linux
write_data_to_internal_buffer(child, data)
child.sendline('gnrc_tcp_send 0')
child.expect_exact('gnrc_tcp_send: sent ' + str(data_len))
# Close connection and verify that pktbuf is cleared
shutdown_event.set()
child.sendline('gnrc_tcp_close')
server_handle.join()
verify_pktbuf_empty(child)
print(os.path.basename(sys.argv[0]) + ': success')
if __name__ == '__main__':
sudo_guard()
sys.exit(run(testfunc, timeout=5, echo=False, traceback=True))

View File

@ -0,0 +1,65 @@
#!/usr/bin/env python3
# Copyright (C) 2018 Simon Brummer <simon.brummer@posteo.de>
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
import os
import sys
import threading
from testrunner import run
from shared_func import TcpServer, generate_port_number, get_host_tap_device, \
get_host_ll_addr, get_riot_if_id, setup_internal_buffer, \
read_data_from_internal_buffer, verify_pktbuf_empty, \
sudo_guard
def tcp_server(port, shutdown_event, data):
with TcpServer(port, shutdown_event) as tcp_srv:
tcp_srv.send(data)
def testfunc(child):
port = generate_port_number()
shutdown_event = threading.Event()
# Try to receive 2000 bytes sent from the Host System.
data = '0123456789' * 200
data_len = len(data)
# Verify that RIOT Applications internal buffer can hold test data.
assert setup_internal_buffer(child) >= data_len
server_handle = threading.Thread(target=tcp_server, args=(port, shutdown_event, data))
server_handle.start()
target_addr = get_host_ll_addr(get_host_tap_device()) + '%' + get_riot_if_id(child)
# Setup RIOT Node to connect to Hostsystems TCP Server
child.sendline('gnrc_tcp_tcb_init')
child.sendline('gnrc_tcp_open_active AF_INET6 ' + target_addr + " " + str(port) + ' 0')
child.expect_exact('gnrc_tcp_open_active: returns 0')
# Accept Data sent by the host system
child.sendline('gnrc_tcp_recv 1000000 ' + str(data_len))
child.expect_exact('gnrc_tcp_recv: received ' + str(data_len), timeout=20)
# Close connection and verify that pktbuf is cleared
shutdown_event.set()
child.sendline('gnrc_tcp_close')
server_handle.join()
verify_pktbuf_empty(child)
# Verify received Data
assert read_data_from_internal_buffer(child, data_len) == data
print(os.path.basename(sys.argv[0]) + ': success')
if __name__ == '__main__':
sudo_guard()
sys.exit(run(testfunc, timeout=5, echo=False, traceback=True))

View File

@ -0,0 +1,110 @@
#!/usr/bin/env python3
# Copyright (C) 2018 Simon Brummer <simon.brummer@posteo.de>
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
import sys
import os
import re
import socket
import random
class TcpServer:
def __init__(self, port, shutdown_event):
self._port = port
self._shutdown = shutdown_event
def __enter__(self):
self.sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.bind(('::', self._port))
self.sock.listen(1)
self.conn, self.addr = self.sock.accept()
return self
def __exit__(self, exc, exc_val, exc_trace):
self._shutdown.wait()
self.conn.close()
self.sock.close()
def send(self, data):
self.conn.send(data.encode('utf-8'))
def recv(self, number_of_bytes):
return self.conn.recv(number_of_bytes, socket.MSG_WAITALL).decode('utf-8')
def generate_port_number():
return random.randint(1024, 65535)
def get_host_tap_device():
# Check if given tap device is part of a network bridge
# if so use bridged interface instead of given tap device
tap = os.environ["TAPDEV"]
result = os.popen('bridge link show dev {}'.format(tap))
bridge = re.search('master (.*) state', result.read())
return bridge.group(1).strip() if bridge else tap
def get_host_ll_addr(interface):
result = os.popen('ip addr show dev ' + interface + ' scope link')
return re.search('inet6 (.*)/64', result.read()).group(1).strip()
def get_riot_ll_addr(child):
child.sendline('ifconfig')
child.expect('(fe80:[0-9a-f:]+)')
return child.match.group(1).strip()
def get_riot_if_id(child):
child.sendline('ifconfig')
child.expect(r'Iface\s+(\d+)')
return child.match.group(1).strip()
def setup_internal_buffer(child):
child.sendline('buffer_init')
child.sendline('buffer_get_max_size')
child.expect(r'returns (\d+)')
return int(child.match.group(1).strip())
def write_data_to_internal_buffer(child, data):
# This is a workaround to avoid the restrictions of the RIOT Shell Buffersize by
# filling an internal buffer piece by piece. The internal buffers current content is via tcp
# by calling gnrc_tcp_send.
CHUNK_SIZE = 100
for i in range(0, len(data), CHUNK_SIZE):
child.sendline('buffer_write ' + str(i) + ' ' + data[i: CHUNK_SIZE + i])
def read_data_from_internal_buffer(child, bytes_to_read):
child.sendline('buffer_read 0 ' + str(bytes_to_read))
child.expect('<begin>(.*)<end>')
return child.match.group(1)
def verify_pktbuf_empty(child):
child.sendline('pktbuf')
child.expect(r'first byte: (0x[0-9a-fA-F]+).*\(size: (\d+)\)')
pktbuf_addr = child.match.group(1)
pktbuf_size = child.match.group(2)
child.expect(r'~ unused: {} \(next: (\(nil\)|0), size: {}\) ~'.format(pktbuf_addr, pktbuf_size))
def sudo_guard():
sudo_required = os.environ.get("BOARD", "") != "native"
if sudo_required and os.geteuid() != 0:
print("\x1b[1;31mThis test requires root privileges.\n"
"It's constructing and sending Ethernet frames.\x1b[0m\n",
file=sys.stderr)
sys.exit(1)

View File

@ -1,47 +0,0 @@
include ../Makefile.tests_common
# If no BOARD is found in the environment, use this default:
BOARD ?= native
ifeq (native,$(BOARD))
PORT ?= tap1
endif
TCP_SERVER_ADDR ?= 2001:db8::affe:0001
TCP_SERVER_PORT ?= 80
TCP_CLIENT_ADDR ?= 2001:db8::affe:0002
TCP_TEST_CYCLES ?= 3
# Mark Boards with insufficient memory
BOARD_INSUFFICIENT_MEMORY := airfy-beacon arduino-duemilanove \
arduino-leonardo arduino-mega2560 \
arduino-nano arduino-uno calliope-mini chronos \
hifive1 hifive1b i-nucleo-lrwan1 mega-xplained microbit \
msb-430 msb-430h nrf51dk nrf51dongle nrf6310 \
nucleo-f031k6 nucleo-f042k6 nucleo-f303k8 \
nucleo-l031k6 nucleo-f030r8 nucleo-f070rb \
nucleo-f072rb nucleo-f302r8 nucleo-f334r8 \
nucleo-l053r8 saml10-xpro saml11-xpro sb-430 sb-430h \
stm32f0discovery stm32l0538-disco telosb \
waspmote-pro wsn430-v1_3b \
wsn430-v1_4 yunjia-nrf51822 z1
# Target Address, Target Port and number of Test Cycles
CFLAGS += -DSERVER_ADDR=\"$(TCP_SERVER_ADDR)\"
CFLAGS += -DSERVER_PORT=$(TCP_SERVER_PORT)
CFLAGS += -DCLIENT_ADDR=\"$(TCP_CLIENT_ADDR)\"
CFLAGS += -DCYCLES=$(TCP_TEST_CYCLES)
CFLAGS += -DGNRC_NETIF_IPV6_GROUPS_NUMOF=3
CFLAGS += -DGNRC_IPV6_NIB_CONF_ARSM=1
CFLAGS += -DGNRC_IPV6_NIB_CONF_QUEUE_PKT=1
# Modules to include
USEMODULE += gnrc_netdev_default
USEMODULE += auto_init_gnrc_netif
USEMODULE += gnrc_ipv6_default
USEMODULE += gnrc_tcp
# include this for IP address manipulation
USEMODULE += shell_commands
include $(RIOTBASE)/Makefile.include

View File

@ -1,32 +0,0 @@
Test description
==========
This test starts a client using GNRC TCP. The test is intended to
work with gnrc_tcp_server.
On startup the client tries to connect to a server waiting
for an incoming connection request. The target address and port number
can be user specified during the test build. After successful
connection establishment, the clients sends 2048 byte containing a test pattern (0xF0)
to the peer. After successful transmission, the client expects to receive 2048 byte
with a test pattern (0xA7) from the peer. After successful verification, the connection
termination sequence is initiated.
The test sequence above runs a configurable amount of times.
Usage (native)
==========
Build and run test:
make clean all term
Build and run test, user specified target address:
make clean all term TCP_TARGET_ADDR=<IPv6-Addr>
Build and run test, user specified target port:
make clean all term TCP_TARGET_PORT=<Port>
Build and run test, user specified amount of test cycles:
make clean all term TCP_TEST_CYLES=<Cycles>
Build and run test, fully specified:
make clean all term TCP_TARGET_ADDR=<IPv6-Addr> TCP_TARGET_PORT=<Port> TCP_TEST_CYLES=<Cycles>

View File

@ -1,238 +0,0 @@
/*
* Copyright (C) 2015-2017 Simon Brummer
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#include <stdio.h>
#include <errno.h>
#include "thread.h"
#include "net/af.h"
#include "net/gnrc/ipv6.h"
#include "net/gnrc/netif.h"
#include "net/gnrc/tcp.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/* Number of possible parallel connections */
#ifndef CONNS
#define CONNS (1)
#endif
/* Amount of data to transmit */
#ifndef NBYTE
#define NBYTE (2048)
#endif
/* Test pattern used by client application */
#ifndef TEST_PATERN_CLI
#define TEST_PATERN_CLI (0xF0)
#endif
/* Test pattern used by server application */
#ifndef TEST_PATERN_SRV
#define TEST_PATERN_SRV (0xA7)
#endif
uint8_t bufs[CONNS][NBYTE];
uint8_t stacks[CONNS][THREAD_STACKSIZE_DEFAULT + THREAD_EXTRA_STACKSIZE_PRINTF];
void *cli_thread(void *arg);
int main(void)
{
gnrc_netif_t *netif;
ipv6_addr_t addr;
if (!(netif = gnrc_netif_iter(NULL))) {
printf("No valid network interface found\n");
return -1;
}
if (ipv6_addr_from_str(&addr, CLIENT_ADDR) == NULL) {
printf("Can't convert given string to IPv6 Address\n");
return -1;
}
if (gnrc_netif_ipv6_addr_add(netif, &addr, 64, GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_VALID) < 0) {
printf("Can't assign given IPv6 Address\n");
return -1;
}
printf("\nStarting Client Threads. SERVER_ADDR=%s, SERVER_PORT=%d, ", SERVER_ADDR, SERVER_PORT);
printf("CONNS=%d, NBYTE=%d, CYCLES=%d\n\n", CONNS, NBYTE, CYCLES);
/* Start connection handling threads */
for (int i = 0; i < CONNS; i += 1) {
thread_create((char *) stacks[i], sizeof(stacks[i]), THREAD_PRIORITY_MAIN, 0, cli_thread,
(void *) i, NULL);
}
return 0;
}
void *cli_thread(void *arg)
{
/* Test program variables */
int tid = (int) arg;
uint32_t cycles = 0;
uint32_t cycles_ok = 0;
uint32_t failed_payload_verifications = 0;
/* Transmission control block */
gnrc_tcp_tcb_t tcb;
printf("Client running: TID=%d\n", tid);
while (cycles < CYCLES) {
/* Copy peer address information. NOTE: This test uses link-local addresses
* -> The Device identifier is removed from target_addr in each iteration! */
char target_addr[] = SERVER_ADDR;
uint16_t target_port = SERVER_PORT;
/* Initialize TCB */
gnrc_tcp_tcb_init(&tcb);
/* Connect to peer */
int ret = gnrc_tcp_open_active(&tcb, AF_INET6, target_addr, target_port, 0);
switch (ret) {
case 0:
DEBUG("TID=%d : gnrc_tcp_open_active() : 0 : ok\n", tid);
break;
case -EISCONN:
printf("TID=%d : gnrc_tcp_open_active() : -EISCONN\n", tid);
return 0;
case -EINVAL:
printf("TID=%d : gnrc_tcp_open_active() : -EINVAL\n", tid);
return 0;
case -EAFNOSUPPORT:
printf("TID=%d : gnrc_tcp_open_active() : -EAFNOSUPPORT\n", tid);
return 0;
case -EADDRINUSE:
printf("TID=%d : gnrc_tcp_open_active() : -EADDRINUSE\n", tid);
return 0;
case -ECONNREFUSED:
printf("TID=%d : gnrc_tcp_open_active() : -ECONNREFUSED : retry after 10sec\n",
tid);
xtimer_sleep(10);
continue;
case -ENOMEM:
printf("TID=%d : gnrc_tcp_open_active() : -ENOMEM\n", tid);
return 0;
case -ETIMEDOUT:
printf("TID=%d : gnrc_tcp_open_active() : -ETIMEDOUT : retry after 10sec\n", tid);
xtimer_sleep(10);
continue;
default:
printf("TID=%d : gnrc_tcp_open_active() : %d\n", tid, ret);
return 0;
}
/* Fill buffer with a test pattern */
for (size_t i = 0; i < sizeof(bufs[tid]); ++i){
bufs[tid][i] = TEST_PATERN_CLI;
}
/* Send data, stop if errors were found */
for (size_t sent = 0; sent < sizeof(bufs[tid]) && ret >= 0; sent += ret) {
ret = gnrc_tcp_send(&tcb, bufs[tid] + sent, sizeof(bufs[tid]) - sent, 0);
switch (ret) {
case -ENOTCONN:
printf("TID=%d : gnrc_tcp_send() : -ENOTCONN\n", tid);
break;
case -ECONNABORTED:
printf("TID=%d : gnrc_tcp_send() : -ECONNABORTED\n", tid);
break;
case -ETIMEDOUT:
printf("TID=%d : gnrc_tcp_send() : -ETIMEDOUT\n", tid);
break;
case -ECONNRESET:
printf("TID=%d : gnrc_tcp_send() : -ECONNRESET\n", tid);
break;
default:
if (ret >= 0) {
DEBUG("TID=%d : gnrc_tcp_send() : %d Bytes sent\n", tid, ret);
}
else {
printf("TID=%d : gnrc_tcp_send() : %d\n", tid, ret);
return 0;
}
}
}
/* Receive data, stop if errors were found */
for (size_t rcvd = 0; rcvd < sizeof(bufs[tid]) && ret >= 0; rcvd += ret) {
ret = gnrc_tcp_recv(&tcb, (void *) (bufs[tid] + rcvd), sizeof(bufs[tid]) - rcvd,
GNRC_TCP_CONNECTION_TIMEOUT_DURATION);
switch (ret) {
case -ENOTCONN:
printf("TID=%d : gnrc_tcp_rcvd() : -ENOTCONN\n", tid);
break;
case -EAGAIN:
printf("TID=%d : gnrc_tcp_rcvd() : -EAGAIN : retry after 10sec\n", tid);
ret = 0;
xtimer_sleep(10);
break;
case -ECONNABORTED:
printf("TID=%d : gnrc_tcp_rcvd() : -ECONNABORTED\n", tid);
break;
case -ECONNRESET:
printf("TID=%d : gnrc_tcp_rcvd() : -ECONNRESET\n", tid);
break;
case -ETIMEDOUT:
printf("TID=%d : gnrc_tcp_rcvd() : -ETIMEDOUT\n", tid);
break;
default:
if (ret >= 0) {
DEBUG("TID=%d : gnrc_tcp_rcvd() : %d Bytes read.\n", tid, ret);
}
else {
printf("TID=%d : gnrc_tcp_rcvd() : %d\n", tid, ret);
return 0;
}
}
}
/* If there was no error: Check received pattern */
for (size_t i = 0; i < sizeof(bufs[tid]); ++i) {
if (bufs[tid][i] != TEST_PATERN_SRV) {
printf("TID=%d : Payload verfication failed\n", tid);
failed_payload_verifications += 1;
break;
}
}
/* Close connection */
gnrc_tcp_close(&tcb);
/* Gather data */
cycles += 1;
if (ret >= 0) {
cycles_ok += 1;
}
printf("TID=%d : %"PRIi32" test cycles completed. %"PRIi32" ok, %"PRIi32" faulty",
tid, cycles, cycles_ok, cycles - cycles_ok);
printf(", %"PRIi32" failed payload verifications\n", failed_payload_verifications);
}
printf("client thread terminating: TID=%d\n", tid);
return 0;
}

View File

@ -1,46 +0,0 @@
include ../Makefile.tests_common
# If no BOARD is found in the environment, use this default:
BOARD ?= native
ifeq (native,$(BOARD))
PORT ?= tap0
endif
TCP_SERVER_ADDR ?= 2001:db8::affe:0001
TCP_SERVER_PORT ?= 80
TCP_TEST_CYCLES ?= 3
# Mark Boards with insufficient memory
BOARD_INSUFFICIENT_MEMORY := airfy-beacon arduino-duemilanove \
arduino-leonardo arduino-mega2560 \
arduino-nano arduino-uno calliope-mini chronos \
hifive1 hifive1b i-nucleo-lrwan1 mega-xplained microbit \
msb-430 msb-430h \
nrf51dk nrf51dongle nrf6310 nucleo-f031k6 \
nucleo-f042k6 nucleo-f303k8 nucleo-l031k6 \
nucleo-f030r8 nucleo-f070rb nucleo-f072rb \
nucleo-f302r8 nucleo-f334r8 nucleo-l053r8 \
saml10-xpro saml11-xpro sb-430 sb-430h \
stm32f0discovery stm32l0538-disco telosb \
waspmote-pro wsn430-v1_3b \
wsn430-v1_4 yunjia-nrf51822 z1
# Local Address, Local Port and number of Test Cycles
CFLAGS += -DSERVER_ADDR=\"$(TCP_SERVER_ADDR)\"
CFLAGS += -DSERVER_PORT=$(TCP_SERVER_PORT)
CFLAGS += -DCYCLES=$(TCP_TEST_CYCLES)
CFLAGS += -DGNRC_NETIF_IPV6_GROUPS_NUMOF=3
CFLAGS += -DGNRC_IPV6_NIB_CONF_ARSM=1
CFLAGS += -DGNRC_IPV6_NIB_CONF_QUEUE_PKT=1
# Modules to include
USEMODULE += gnrc_netdev_default
USEMODULE += auto_init_gnrc_netif
USEMODULE += gnrc_ipv6_default
USEMODULE += gnrc_tcp
# include this for IP address manipulation
USEMODULE += shell_commands
include $(RIOTBASE)/Makefile.include

View File

@ -1,33 +0,0 @@
Test description
==========
This test starts a server using GNRC TCP. The test is intended to
work with gnrc_tcp_client.
On startup the server assigns a given IP-Address to its network
interface and opens a given port number waiting for a client
to connect to this port. As soon as a client connects the server
expects to receive 2048 byte containing a sequence of a test pattern (0xF0).
After successful verification, the server sends 2048 byte with a test
pattern (0xA7) to the peer. After successful transmission the connection
termination sequence is initiated.
The test sequence above runs a configurable amount of times.
Usage (native)
==========
Build and run test:
make clean all term
Build and run test, user specified local address:
make clean all term TCP_LOCAL_ADDR=<IPv6-Addr>
Build and run test, user specified local port:
make clean all term TCP_LOCAL_PORT=<Port>
Build and run test, user specified amount of test cycles:
make clean all term TCP_TEST_CYLES=<Cycles>
Build and run test, fully specified:
make clean all term TCP_LOCAL_ADDR=<IPv6-Addr> TCP_LOCAL_PORT=<Port> TCP_TEST_CYLES=<Cycles>

View File

@ -1,220 +0,0 @@
/*
* Copyright (C) 2015-2017 Simon Brummer
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#include <stdio.h>
#include <errno.h>
#include "thread.h"
#include "net/af.h"
#include "net/gnrc/ipv6.h"
#include "net/gnrc/netif.h"
#include "net/gnrc/tcp.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/* Number of possible parallel connections */
#ifndef CONNS
#define CONNS (1)
#endif
/* Amount of data to transmit */
#ifndef NBYTE
#define NBYTE (2048)
#endif
/* Test pattern used by client application */
#ifndef TEST_PATERN_CLI
#define TEST_PATERN_CLI (0xF0)
#endif
/* Test pattern used by server application */
#ifndef TEST_PATERN_SRV
#define TEST_PATERN_SRV (0xA7)
#endif
uint8_t bufs[CONNS][NBYTE];
uint8_t stacks[CONNS][THREAD_STACKSIZE_DEFAULT + THREAD_EXTRA_STACKSIZE_PRINTF];
/* Server thread */
void *srv_thread(void *arg);
int main(void)
{
/* Set pre-configured IP address */
gnrc_netif_t *netif;
ipv6_addr_t addr;
if (!(netif = gnrc_netif_iter(NULL))) {
printf("No valid network interface found\n");
return -1;
}
if (ipv6_addr_from_str(&addr, SERVER_ADDR) == NULL) {
printf("Can't convert given string to IPv6 Address\n");
return -1;
}
if (gnrc_netif_ipv6_addr_add(netif, &addr, 64, GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_VALID) < 0) {
printf("Can't assign given IPv6 Address\n");
return -1;
}
/* Test configuration */
printf("\nStarting server: SERVER_ADDR=%s, SERVER_PORT=%d, ", SERVER_ADDR, SERVER_PORT);
printf("CONNS=%d, NBYTE=%d, CYCLES=%d\n\n", CONNS, NBYTE, CYCLES);
/* Start Threads to handle connections */
for (int i = 0; i < CONNS; i += 1) {
thread_create((char *) stacks[i], sizeof(stacks[i]), THREAD_PRIORITY_MAIN, 0, srv_thread,
(void *) i, NULL);
}
return 0;
}
void *srv_thread(void *arg)
{
int tid = (int) arg;
uint32_t cycles = 0;
uint32_t cycles_ok = 0;
uint32_t failed_payload_verifications = 0;
/* Transmission control block */
gnrc_tcp_tcb_t tcb;
/* Connection handling code */
printf("Server running: TID=%d\n", tid);
while (cycles < CYCLES) {
/* Initialize TCB struct */
gnrc_tcp_tcb_init(&tcb);
/* Connect to peer */
int ret = gnrc_tcp_open_passive(&tcb, AF_INET6, NULL, SERVER_PORT);
switch (ret) {
case 0:
DEBUG("TID=%d : gnrc_tcp_open_passive() : 0 : ok\n", tid);
break;
case -EISCONN:
printf("TID=%d : gnrc_tcp_open_passive() : -EISCONN\n", tid);
return 0;
case -EINVAL:
printf("TID=%d : gnrc_tcp_open_passive() : -EINVAL\n", tid);
return 0;
case -EAFNOSUPPORT:
printf("TID=%d : gnrc_tcp_open_passive() : -EAFNOSUPPORT\n", tid);
return 0;
case -ENOMEM:
printf("TID=%d : gnrc_tcp_open_passive() : -ENOMEM\n", tid);
return 0;
default:
printf("TID=%d : gnrc_tcp_open_passive() : %d\n", tid, ret);
return 0;
}
/* Receive data, stop if errors were found */
for (size_t rcvd = 0; rcvd < sizeof(bufs[tid]) && ret >= 0; rcvd += ret) {
ret = gnrc_tcp_recv(&tcb, (void *) (bufs[tid] + rcvd), sizeof(bufs[tid]) - rcvd,
GNRC_TCP_CONNECTION_TIMEOUT_DURATION);
switch (ret) {
case -ENOTCONN:
printf("TID=%d : gnrc_tcp_rcvd() : -ENOTCONN\n", tid);
break;
case -EAGAIN:
printf("TID=%d : gnrc_tcp_rcvd() : -EAGAIN : retry after 10sec\n", tid);
ret = 0;
xtimer_sleep(10);
break;
case -ECONNABORTED:
printf("TID=%d : gnrc_tcp_rcvd() : -ECONNABORTED\n", tid);
break;
case -ECONNRESET:
printf("TID=%d : gnrc_tcp_rcvd() : -ECONNRESET\n", tid);
break;
case -ETIMEDOUT:
printf("TID=%d : gnrc_tcp_rcvd() : -ETIMEDOUT\n", tid);
break;
default:
if (ret >= 0) {
DEBUG("TID=%d : gnrc_tcp_rcvd() : %d Bytes read\n", tid, ret);
}
else {
printf("TID=%d : gnrc_tcp_rcvd() : %d\n", tid, ret);
return 0;
}
}
}
/* Check received pattern */
for (size_t i = 0; i < sizeof(bufs[tid]); ++i) {
if (bufs[tid][i] != TEST_PATERN_CLI) {
printf("TID=%d : Payload verfication failed\n", tid);
failed_payload_verifications += 1;
break;
}
}
/* Fill buffer with a test pattern */
for (size_t i = 0; i < sizeof(bufs[tid]); ++i) {
bufs[tid][i] = TEST_PATERN_SRV;
}
/* Send data, stop if errors were found */
for (size_t sent = 0; sent < sizeof(bufs[tid]) && ret >= 0; sent += ret) {
ret = gnrc_tcp_send(&tcb, bufs[tid] + sent, sizeof(bufs[tid]) - sent, 0);
switch (ret) {
case -ENOTCONN:
printf("TID=%d : gnrc_tcp_send() : -ENOTCONN\n", tid);
break;
case -ECONNABORTED:
printf("TID=%d : gnrc_tcp_send() : -ECONNABORTED\n", tid);
break;
case -ETIMEDOUT:
printf("TID=%d : gnrc_tcp_send() : -ETIMEDOUT\n", tid);
break;
case -ECONNRESET:
printf("TID=%d : gnrc_tcp_send() : -ECONNRESET\n", tid);
break;
default:
if (ret >= 0) {
DEBUG("TID=%d : gnrc_tcp_send() : %d Bytes sent.\n", tid, ret);
}
else {
printf("TID=%d : gnrc_tcp_send() : %d\n", tid, ret);
return 0;
}
}
}
/* Close connection */
gnrc_tcp_close(&tcb);
/* Gather data */
cycles += 1;
if (ret >= 0) {
cycles_ok += 1;
}
printf("TID=%d : %"PRIi32" test cycles completed. %"PRIi32" ok, %"PRIi32" faulty",
tid, cycles, cycles_ok, cycles - cycles_ok);
printf(", %"PRIi32" failed payload verifications\n", failed_payload_verifications);
}
printf("server thread terminating: TID=%d\n", tid);
return 0;
}