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:
commit
e9e0001239
61
tests/gnrc_tcp/Makefile
Normal file
61
tests/gnrc_tcp/Makefile
Normal 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
34
tests/gnrc_tcp/README.md
Normal 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
308
tests/gnrc_tcp/main.c
Normal 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;
|
||||
}
|
||||
50
tests/gnrc_tcp/tests/01-conn_lifecycle_as_client.py
Executable file
50
tests/gnrc_tcp/tests/01-conn_lifecycle_as_client.py
Executable 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))
|
||||
57
tests/gnrc_tcp/tests/02-conn_lifecycle_as_server.py
Executable file
57
tests/gnrc_tcp/tests/02-conn_lifecycle_as_server.py
Executable 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))
|
||||
63
tests/gnrc_tcp/tests/03-send_data.py
Executable file
63
tests/gnrc_tcp/tests/03-send_data.py
Executable 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))
|
||||
65
tests/gnrc_tcp/tests/04-receive_data.py
Executable file
65
tests/gnrc_tcp/tests/04-receive_data.py
Executable 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))
|
||||
110
tests/gnrc_tcp/tests/shared_func.py
Normal file
110
tests/gnrc_tcp/tests/shared_func.py
Normal 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)
|
||||
@ -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
|
||||
@ -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>
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
@ -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>
|
||||
@ -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;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user