mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
688 lines
24 KiB
Python
Executable File
688 lines
24 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# Copyright (C) 2021 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 random
|
|
import pexpect
|
|
import base64
|
|
|
|
from scapy.all import Ether, IPv6, TCP, raw, sendp
|
|
|
|
from helpers import Runner, RiotTcpServer, RiotTcpClient, HostTcpServer, HostTcpClient, \
|
|
generate_port_number, sudo_guard
|
|
|
|
# Custom NO_TIMEOUT constant. Note: the value must match
|
|
# with CUSTOM_GNRC_TCP_NO_TIMEOUT from the makefile
|
|
_GNRC_TCP_NO_TIMEOUT = 1
|
|
|
|
|
|
@Runner(timeout=5)
|
|
def test_connection_lifecycle_as_client(child):
|
|
""" Open/close a single connection as tcp client """
|
|
# Setup Host as server
|
|
with HostTcpServer(generate_port_number()) as host_srv:
|
|
# Setup Riot as client
|
|
with RiotTcpClient(child, host_srv):
|
|
# Accept and close connection
|
|
host_srv.accept()
|
|
host_srv.close()
|
|
|
|
|
|
@Runner(timeout=10)
|
|
def test_connection_lifecycle_as_server(child):
|
|
""" Open/close a single connection as tcp server """
|
|
# Setup RIOT as server
|
|
with RiotTcpServer(child, generate_port_number()) as riot_srv:
|
|
# Setup Host as client
|
|
with HostTcpClient(riot_srv):
|
|
# Accept and close connection
|
|
riot_srv.accept(timeout_ms=1000)
|
|
riot_srv.close()
|
|
|
|
|
|
@Runner(timeout=5)
|
|
def test_send_data_from_riot_to_host(child):
|
|
""" Send Data from RIOT Node to Host system """
|
|
# Setup Host as server
|
|
with HostTcpServer(generate_port_number()) as host_srv:
|
|
# Setup Riot as client
|
|
with RiotTcpClient(child, host_srv) as riot_cli:
|
|
# Accept and close connection
|
|
host_srv.accept()
|
|
|
|
# Send Data from RIOT to Host system and verify reception
|
|
data = '0123456789' * 200
|
|
riot_cli.send(timeout_ms=0, payload_to_send=data)
|
|
host_srv.receive(data)
|
|
|
|
# Teardown connection
|
|
host_srv.close()
|
|
|
|
|
|
@Runner(timeout=5)
|
|
def test_send_data_from_host_to_riot(child):
|
|
""" Send Data from Host system to RIOT node """
|
|
# Setup RIOT as server
|
|
with RiotTcpServer(child, generate_port_number()) as riot_srv:
|
|
# Setup Host as client
|
|
with HostTcpClient(riot_srv) as host_cli:
|
|
# Accept and close connection
|
|
riot_srv.accept(timeout_ms=1000)
|
|
|
|
# Send Data from Host system to RIOT
|
|
data = '0123456789' * 200
|
|
host_cli.send(data)
|
|
riot_srv.receive(timeout_ms=1000, sent_payload=data)
|
|
|
|
riot_srv.close()
|
|
|
|
|
|
@Runner(timeout=5)
|
|
def test_gnrc_tcp_garbage_packets_short_payload(child):
|
|
""" Receive unusually short payload with timeout. Verifies fix for
|
|
https://github.com/RIOT-OS/RIOT/issues/11999
|
|
"""
|
|
# Setup RIOT as server
|
|
with RiotTcpServer(child, generate_port_number()) as riot_srv:
|
|
# Setup Host as client
|
|
with HostTcpClient(riot_srv) as host_cli:
|
|
# Accept new connection
|
|
riot_srv.accept(timeout_ms=2000)
|
|
|
|
# Receive 1 byte with timeout, this should block
|
|
child.sendline('gnrc_tcp_recv 1000000 1')
|
|
child.expect_exact('gnrc_tcp_recv: argc=3, '
|
|
'argv[0] = gnrc_tcp_recv, '
|
|
'argv[1] = 1000000, argv[2] = 1')
|
|
|
|
# Send 1 byte from host to RIOT
|
|
assert 1 == host_cli.sock.send(b"f")
|
|
|
|
# Receive 1 byte
|
|
child.expect_exact('gnrc_tcp_recv: received 1', timeout=20)
|
|
|
|
# Close connection
|
|
riot_srv.close()
|
|
|
|
|
|
@Runner(timeout=5)
|
|
def test_gnrc_tcp_garbage_packets_short_header(child):
|
|
""" This test verifies fix malformed tcp header. See
|
|
https://github.com/RIOT-OS/RIOT/issues/12086
|
|
"""
|
|
# Setup RIOT as server
|
|
with RiotTcpServer(child, generate_port_number()) as riot_srv:
|
|
|
|
# Construct HostTcpClient to lookup node properties
|
|
host_cli = HostTcpClient(riot_srv)
|
|
|
|
# Try to accept incoming connection from host system.
|
|
child.sendline('gnrc_tcp_accept 2000')
|
|
|
|
# Build malformed short header with SYN Flag
|
|
tcp_hdr = TCP(
|
|
dport=int(riot_srv.listen_port), flags="S", sport=2342, seq=1, dataofs=6
|
|
)
|
|
tcp_hdr = raw(tcp_hdr)[:-2]
|
|
sendp(
|
|
Ether(dst=riot_srv.mac) / IPv6(src=host_cli.address, dst=riot_srv.address) /
|
|
tcp_hdr, iface=host_cli.interface, verbose=0
|
|
)
|
|
|
|
# Establish normal tcp connection from host system to check if RIOT node
|
|
# was able to recover from malformed packet
|
|
with host_cli:
|
|
child.expect_exact('gnrc_tcp_accept: returns 0')
|
|
|
|
riot_srv.close()
|
|
|
|
|
|
@Runner(timeout=5)
|
|
def test_gnrc_tcp_garbage_packets_ack_instead_of_sym(child):
|
|
""" This test verifies that sending and ACK instead of a SYN.
|
|
doesn't break GNRC_TCP.
|
|
"""
|
|
# Setup RIOT as server
|
|
with RiotTcpServer(child, generate_port_number()) as riot_srv:
|
|
# Construct HostTcpClient to lookup node properties
|
|
host_cli = HostTcpClient(riot_srv)
|
|
|
|
# Try to accept incoming connection from host system.
|
|
# Use timeout of 15s discarding 1000 packages can take a while on smaller platforms
|
|
child.sendline('gnrc_tcp_accept 15000')
|
|
|
|
# Check if debug output is enabled. Send fewer packets on if it is disabled
|
|
# To ensure that the amount of generated output doesn't break the test
|
|
debug = child.expect(
|
|
[pexpect.TIMEOUT, r'GNRC_TCP: Enter "\S+", File: .+\(\d+\)\s'], timeout=1
|
|
)
|
|
|
|
if debug:
|
|
count = 10
|
|
else:
|
|
count = 1000
|
|
|
|
# see https://github.com/RIOT-OS/RIOT/pull/12001
|
|
provided_data = base64.b64decode("rwsQf2pekYLaU+exUBBwgPDKAAA=")
|
|
tcp_hdr = TCP(provided_data)
|
|
assert provided_data == raw(tcp_hdr)
|
|
|
|
# set destination port to application specific port
|
|
tcp_hdr.dport = int(riot_srv.listen_port)
|
|
sendp(
|
|
Ether(dst=riot_srv.mac) / IPv6(src=host_cli.address, dst=riot_srv.address) /
|
|
tcp_hdr, iface=host_cli.interface, verbose=0, count=count
|
|
)
|
|
|
|
# check if server actually still works
|
|
with host_cli:
|
|
child.expect_exact('gnrc_tcp_accept: returns 0')
|
|
|
|
riot_srv.close()
|
|
|
|
|
|
@Runner(timeout=5)
|
|
def test_gnrc_tcp_garbage_packets_option_parsing(child):
|
|
""" This test verifies that malformed option don't break TCP
|
|
doesn't break GNRC_TCP. See: https://github.com/RIOT-OS/RIOT/issues/12086
|
|
"""
|
|
# Setup RIOT as server
|
|
with RiotTcpServer(child, generate_port_number()) as riot_srv:
|
|
# Construct HostTcpClient to lookup node properties
|
|
host_cli = HostTcpClient(riot_srv)
|
|
|
|
# Try to accept incoming connection from host system.
|
|
child.sendline('gnrc_tcp_accept 2000')
|
|
|
|
tcp_hdr = TCP(
|
|
dport=int(riot_srv.listen_port), flags="S", sport=2342, seq=1, dataofs=6
|
|
)
|
|
|
|
sendp(
|
|
Ether(dst=riot_srv.mac) / IPv6(src=host_cli.address, dst=riot_srv.address) /
|
|
tcp_hdr / b"\x50\x00\x00\x00", iface=host_cli.interface, verbose=0
|
|
)
|
|
|
|
# check if server actually still works
|
|
with host_cli:
|
|
child.expect_exact('gnrc_tcp_accept: returns 0')
|
|
|
|
riot_srv.close()
|
|
|
|
|
|
@Runner(timeout=5)
|
|
def test_gnrc_tcp_recv_behavior_on_closed_connection(child):
|
|
""" This test ensures that a gnrc_tcp_recv doesn't block if a connection
|
|
was closed already.
|
|
"""
|
|
# Setup Host as server
|
|
with HostTcpServer(generate_port_number()) as host_srv:
|
|
# Setup Riot as client
|
|
with RiotTcpClient(child, host_srv) as riot_cli:
|
|
# Accept connection
|
|
host_srv.accept()
|
|
|
|
# Transmit data to RIOT client and close connection from host side
|
|
data = 'test_data_'
|
|
host_srv.send(payload_to_send=data)
|
|
host_srv.close()
|
|
|
|
# Read half amount of data with huge timeout.
|
|
# Expectency: direct with verified test data. Timeout doesn't matter
|
|
half_data_len = int(len(data) / 2)
|
|
huge_timeout_ms = 1000000000
|
|
no_timeout_ms = 0
|
|
riot_cli.receive(timeout_ms=huge_timeout_ms, sent_payload=data[:half_data_len])
|
|
|
|
# Read half amount of data without timeout.
|
|
# Expectency: direct return with verified test data
|
|
riot_cli.receive(timeout_ms=no_timeout_ms, sent_payload=data[half_data_len:])
|
|
|
|
# All received data is read, try to read 1 byte with timeout.
|
|
# Expectency: fast return despite timeout since the connection is already closed
|
|
child.sendline('gnrc_tcp_recv {} 1'.format(huge_timeout_ms))
|
|
child.expect_exact('gnrc_tcp_recv: returns 0')
|
|
|
|
# All received data is read, try to read 1 byte without timeout.
|
|
# Expectency: fast return since the connection is already closed
|
|
child.sendline('gnrc_tcp_recv {} 1'.format(no_timeout_ms))
|
|
child.expect_exact('gnrc_tcp_recv: returns 0')
|
|
|
|
|
|
@Runner(timeout=5)
|
|
def test_gnrc_tcp_recv_behavior_on_zero_length_buffer_size(child):
|
|
""" This test verifies that gnrc_tcp_recv accepts zero as buffer size
|
|
and returns 0.
|
|
"""
|
|
with HostTcpServer(generate_port_number()) as host_srv:
|
|
riot_cli = RiotTcpClient(child, host_srv)
|
|
|
|
# Call gnrc_tcp_recv with on data and no timeout on unconnected TCB
|
|
# This must return -ENOTCONN
|
|
child.sendline('gnrc_tcp_recv 0 0')
|
|
child.expect_exact('gnrc_tcp_recv: returns -ENOTCONN')
|
|
|
|
with riot_cli:
|
|
host_srv.accept()
|
|
|
|
# Call gnrc_tcp_recv with on data and no timeout
|
|
# This must return 0 not -EAGAIN
|
|
child.sendline('gnrc_tcp_recv 0 0')
|
|
child.expect_exact('gnrc_tcp_recv: returns 0')
|
|
|
|
host_srv.close()
|
|
|
|
|
|
@Runner(timeout=5)
|
|
def test_gnrc_tcp_send_behavior_on_zero_length_buffer_size(child):
|
|
""" This test verifies that gnrc_tcp_send accepts zero length payload
|
|
and returns 0.
|
|
"""
|
|
with HostTcpServer(generate_port_number()) as host_srv:
|
|
riot_cli = RiotTcpClient(child, host_srv)
|
|
|
|
# Call gnrc_tcp_send with on data and no timeout on unconnected TCB
|
|
# This must return -ENOTCONN
|
|
child.sendline('gnrc_tcp_send 0 0')
|
|
child.expect_exact('gnrc_tcp_send: returns -ENOTCONN')
|
|
|
|
with riot_cli:
|
|
host_srv.accept()
|
|
|
|
# Call gnrc_tcp_send with on data and no timeout
|
|
# This must return 0 not -EAGAIN
|
|
child.sendline('gnrc_tcp_send 0 0')
|
|
child.expect_exact('gnrc_tcp_send: returns 0')
|
|
|
|
host_srv.close()
|
|
|
|
|
|
@Runner(timeout=1)
|
|
def test_gnrc_tcp_ep_from_str(child):
|
|
""" Verify Endpoint construction from string """
|
|
# Build funspec
|
|
valid = '[::]'
|
|
child.sendline('gnrc_tcp_ep_from_str {}'.format(valid))
|
|
child.expect_exact('gnrc_tcp_ep_from_str: returns 0')
|
|
child.expect_exact('Family: AF_INET6')
|
|
child.expect_exact('Addr: ::')
|
|
child.expect_exact('Port: 0')
|
|
child.expect_exact('Netif: 0')
|
|
|
|
# Build unspec with port
|
|
valid = '[::]:8080'
|
|
child.sendline('gnrc_tcp_ep_from_str {}'.format(valid))
|
|
child.expect_exact('gnrc_tcp_ep_from_str: returns 0')
|
|
child.expect_exact('Family: AF_INET6')
|
|
child.expect_exact('Addr: ::')
|
|
child.expect_exact('Port: 8080')
|
|
child.expect_exact('Netif: 0')
|
|
|
|
# Build unspec with interface and port
|
|
valid = '[::%5]:8080'
|
|
child.sendline('gnrc_tcp_ep_from_str {}'.format(valid))
|
|
child.expect_exact('gnrc_tcp_ep_from_str: returns 0')
|
|
child.expect_exact('Family: AF_INET6')
|
|
child.expect_exact('Addr: ::')
|
|
child.expect_exact('Port: 8080')
|
|
child.expect_exact('Netif: 5')
|
|
|
|
# Build addr, interface and port
|
|
valid = '[fe80::68bf:dbff:fe05:c35e%5]:8080'
|
|
child.sendline('gnrc_tcp_ep_from_str {}'.format(valid))
|
|
child.expect_exact('gnrc_tcp_ep_from_str: returns 0')
|
|
child.expect_exact('Family: AF_INET6')
|
|
child.expect_exact('Addr: fe80::68bf:dbff:fe05:c35e')
|
|
child.expect_exact('Port: 8080')
|
|
child.expect_exact('Netif: 5')
|
|
|
|
|
|
@Runner(timeout=0.5)
|
|
def test_gnrc_tcp_ep_from_str_returns_EINVAL(child):
|
|
""" Verify faulty endpoint construction from string return -EINVAL"""
|
|
# Error: No brackets
|
|
invalid = '::'
|
|
child.sendline('gnrc_tcp_ep_from_str {}'.format(invalid))
|
|
child.expect_exact('gnrc_tcp_ep_from_str: returns -EINVAL')
|
|
|
|
# Error: Too much brackets
|
|
invalid = '[:]:]'
|
|
child.sendline('gnrc_tcp_ep_from_str {}'.format(invalid))
|
|
child.expect_exact('gnrc_tcp_ep_from_str: returns -EINVAL')
|
|
|
|
# Error: Swapped bracket order
|
|
invalid = ']::['
|
|
child.sendline('gnrc_tcp_ep_from_str {}'.format(invalid))
|
|
child.expect_exact('gnrc_tcp_ep_from_str: returns -EINVAL')
|
|
|
|
# Error: Empty brackets
|
|
invalid = '[]'
|
|
child.sendline('gnrc_tcp_ep_from_str {}'.format(invalid))
|
|
child.expect_exact('gnrc_tcp_ep_from_str: returns -EINVAL')
|
|
|
|
# Error First char before brackets
|
|
invalid = 'a[]'
|
|
child.sendline('gnrc_tcp_ep_from_str {}'.format(invalid))
|
|
child.expect_exact('gnrc_tcp_ep_from_str: returns -EINVAL')
|
|
|
|
# Error token but no port
|
|
invalid = '[::]:'
|
|
child.sendline('gnrc_tcp_ep_from_str {}'.format(invalid))
|
|
child.expect_exact('gnrc_tcp_ep_from_str: returns -EINVAL')
|
|
|
|
# Error invalid char in port
|
|
invalid = '[::]:103f2'
|
|
child.sendline('gnrc_tcp_ep_from_str {}'.format(invalid))
|
|
child.expect_exact('gnrc_tcp_ep_from_str: returns -EINVAL')
|
|
|
|
# Error port out of range
|
|
invalid = '[::]:65536'
|
|
child.sendline('gnrc_tcp_ep_from_str {}'.format(invalid))
|
|
child.expect_exact('gnrc_tcp_ep_from_str: returns -EINVAL')
|
|
|
|
# Error interface after bracket
|
|
invalid = '[::]%5'
|
|
child.sendline('gnrc_tcp_ep_from_str {}'.format(invalid))
|
|
child.expect_exact('gnrc_tcp_ep_from_str: returns -EINVAL')
|
|
|
|
# Error interface token bur no interface
|
|
invalid = '[::%]'
|
|
child.sendline('gnrc_tcp_ep_from_str {}'.format(invalid))
|
|
child.expect_exact('gnrc_tcp_ep_from_str: returns -EINVAL')
|
|
|
|
# Error: invalid interface
|
|
invalid = '[::%5a]'
|
|
child.sendline('gnrc_tcp_ep_from_str {}'.format(invalid))
|
|
child.expect_exact('gnrc_tcp_ep_from_str: returns -EINVAL')
|
|
|
|
# Error: address to short
|
|
invalid = '[:%5]'
|
|
child.sendline('gnrc_tcp_ep_from_str {}'.format(invalid))
|
|
child.expect_exact('gnrc_tcp_ep_from_str: returns -EINVAL')
|
|
|
|
|
|
@Runner(timeout=0.5)
|
|
def test_gnrc_tcp_accept_returns_EAGAIN(child):
|
|
""" gnrc_tcp_accept must return with -EAGAIN
|
|
if no connection is ready and timeout is 0
|
|
"""
|
|
riot_srv = RiotTcpServer(child, generate_port_number())
|
|
riot_srv.listen()
|
|
|
|
child.sendline('gnrc_tcp_accept 0')
|
|
child.expect_exact('gnrc_tcp_accept: returns -EAGAIN')
|
|
|
|
|
|
@Runner(timeout=1.5)
|
|
def test_gnrc_tcp_accept_returns_ETIMEDOUT(child):
|
|
""" gnrc_tcp_accept must return with -ETIMEDOUT
|
|
if no connection is ready and timeout is not 0
|
|
"""
|
|
riot_srv = RiotTcpServer(child, generate_port_number())
|
|
riot_srv.listen()
|
|
|
|
child.sendline('gnrc_tcp_accept 1000')
|
|
child.expect_exact('gnrc_tcp_accept: returns -ETIMEDOUT')
|
|
|
|
|
|
@Runner(timeout=1)
|
|
def test_gnrc_tcp_accept_returns_ENOMEM(child):
|
|
""" gnrc_tcp_accept must return with -ENOMEM
|
|
if all TCBs already handle a connection
|
|
"""
|
|
with RiotTcpServer(child, generate_port_number()) as riot_srv:
|
|
# Establish connection to ensure that all TCBs are in use
|
|
with HostTcpClient(riot_srv):
|
|
riot_srv.accept(timeout_ms=0)
|
|
|
|
# Out of memory accept should return immediately despite a huge timeout.
|
|
child.sendline('gnrc_tcp_accept 100000000')
|
|
child.expect_exact('gnrc_tcp_accept: returns -ENOMEM')
|
|
|
|
|
|
@Runner(timeout=0.5)
|
|
def test_gnrc_tcp_accept_returns_EINVAL(child):
|
|
""" gnrc_tcp_accept must return with -EINVAL
|
|
if listen was not called before.
|
|
"""
|
|
child.sendline('gnrc_tcp_accept 0')
|
|
child.expect_exact('gnrc_tcp_accept: returns -EINVAL')
|
|
|
|
|
|
@Runner(timeout=5)
|
|
def test_gnrc_tcp_get_local_returns_0(child):
|
|
""" This test verifies that get_local returns 0 in a connected state
|
|
and the used endpoint contains the expected connection parameters
|
|
"""
|
|
local_port = 30423
|
|
|
|
# Setup Host as server
|
|
with HostTcpServer(generate_port_number()) as host_srv:
|
|
# Setup Riot as client
|
|
with RiotTcpClient(child, host_srv, local_port) as riot_cli:
|
|
|
|
# Accept connection
|
|
host_srv.accept()
|
|
|
|
# Get and verify local endpoint
|
|
riot_cli.get_local()
|
|
child.expect_exact('Endpoint: addr.ipv6={} netif={} port={}'.format(
|
|
riot_cli.address, riot_cli.interface, riot_cli.port)
|
|
)
|
|
|
|
# Close connection
|
|
host_srv.close()
|
|
|
|
|
|
@Runner(timeout=1)
|
|
def test_gnrc_tcp_get_local_returns_EADDRNOTAVAIL(child):
|
|
""" This Test verifies that get_local returns -EADDRNOTAVAIL
|
|
then not connected
|
|
"""
|
|
child.sendline('gnrc_tcp_get_local')
|
|
child.expect_exact('gnrc_tcp_get_local: returns -EADDRNOTAVAIL')
|
|
|
|
|
|
@Runner(timeout=5)
|
|
def test_gnrc_tcp_get_remote_returns_0(child):
|
|
""" This test verifies that get_remote returns 0 in a connected state
|
|
and the used endpoint contains the expected connection parameters
|
|
"""
|
|
# Setup Host as server
|
|
with HostTcpServer(generate_port_number()) as host_srv:
|
|
# Setup Riot as client
|
|
with RiotTcpClient(child, host_srv) as riot_cli:
|
|
|
|
# Accept connection
|
|
host_srv.accept()
|
|
|
|
# Get and verify local endpoint
|
|
riot_cli.get_remote()
|
|
child.expect_exact('Endpoint: addr.ipv6={} netif=0 port={}'.format(
|
|
host_srv.address, host_srv.listen_port)
|
|
)
|
|
|
|
# Close connection
|
|
host_srv.close()
|
|
|
|
|
|
@Runner(timeout=1)
|
|
def test_gnrc_tcp_get_remote_returns_ENOTCONN(child):
|
|
""" This test verifies that get_remote returns -ENOTCONN
|
|
then not connected
|
|
"""
|
|
child.sendline('gnrc_tcp_get_remote')
|
|
child.expect_exact('gnrc_tcp_get_remote: returns -ENOTCONN')
|
|
|
|
|
|
@Runner(timeout=1)
|
|
def test_gnrc_tcp_queue_get_local_returns_0(child):
|
|
""" This test verifies that queue_get_local returns 0 then put after listen.
|
|
And the endpoint content is as are as expected.
|
|
"""
|
|
# Enter listen with accept all address
|
|
listen_addr = '::'
|
|
listen_port = generate_port_number()
|
|
riot_srv = RiotTcpServer(child, listen_port)
|
|
riot_srv.listen()
|
|
riot_srv.queue_get_local()
|
|
child.expect_exact('Endpoint: addr.ipv6=:: netif=0 port={}'.format(
|
|
listen_port)
|
|
)
|
|
riot_srv.stop_listen()
|
|
|
|
# Enter listen with specified address
|
|
listen_addr = 'fe80::4c49:c7ff:fecd:34a3'
|
|
listen_port = generate_port_number()
|
|
riot_srv = RiotTcpServer(child, listen_port, listen_addr)
|
|
riot_srv.listen()
|
|
riot_srv.queue_get_local()
|
|
child.expect_exact('Endpoint: addr.ipv6={} netif=0 port={}'.format(
|
|
listen_addr, listen_port)
|
|
)
|
|
riot_srv.stop_listen()
|
|
|
|
|
|
@Runner(timeout=1)
|
|
def test_gnrc_tcp_queue_get_local_returns_EADDRNOTAVAIL(child):
|
|
""" This Test verifies that queue_get_local returns -EADDRNOTAVAIL
|
|
then not listening
|
|
"""
|
|
child.sendline('gnrc_tcp_queue_get_local')
|
|
child.expect_exact('gnrc_tcp_queue_get_local: returns -EADDRNOTAVAIL')
|
|
|
|
|
|
@Runner(timeout=5)
|
|
def test_gnrc_tcp_accept_respects_GNRC_TCP_NO_TIMEOUT(child):
|
|
""" gnrc_tcp_accept timeout mechanism must be disabled if GNRC_TCP_NO_TIMEOUT
|
|
is set as timeout value.
|
|
"""
|
|
|
|
pexpect_timeout_sec = _GNRC_TCP_NO_TIMEOUT + 1
|
|
|
|
riot_srv = RiotTcpServer(child, generate_port_number())
|
|
riot_srv.listen()
|
|
|
|
child.sendline('gnrc_tcp_accept {}'.format(_GNRC_TCP_NO_TIMEOUT))
|
|
|
|
# The test is successful if gnrc_tcp_accept does not return before pexpects timeout.
|
|
# Afterwards the connection must be still able to accept a connection.
|
|
returned = True
|
|
try:
|
|
child.expect_exact('gnrc_tcp_accept: returns', timeout=pexpect_timeout_sec)
|
|
except pexpect.TIMEOUT:
|
|
returned = False
|
|
finally:
|
|
if returned:
|
|
raise RuntimeError('gnrc_tcp_accept returned')
|
|
|
|
# Ensure that gnrc_tcp_accept returns after the test host connects
|
|
with HostTcpClient(riot_srv):
|
|
child.expect_exact('gnrc_tcp_accept: returns 0')
|
|
riot_srv.close()
|
|
|
|
|
|
@Runner(timeout=5)
|
|
def test_gnrc_tcp_recv_respects_GNRC_TCP_NO_TIMEOUT(child):
|
|
""" gnrc_tcp_recv timeout mechanism must be disabled if GNRC_TCP_NO_TIMEOUT
|
|
is set as timeout value.
|
|
"""
|
|
|
|
pexpect_timeout_sec = _GNRC_TCP_NO_TIMEOUT + 1
|
|
payload = "12345"
|
|
|
|
# Setup Host as server
|
|
with HostTcpServer(generate_port_number()) as host_srv:
|
|
# Setup Riot as client
|
|
with RiotTcpClient(child, host_srv):
|
|
|
|
# Accept connection
|
|
host_srv.accept()
|
|
|
|
# Wait for incoming data blocking.
|
|
# This gnrc_tcp_recv must not return until some Data was sent.
|
|
child.sendline('gnrc_tcp_recv {} {}'.format(_GNRC_TCP_NO_TIMEOUT, len(payload)))
|
|
returned = True
|
|
try:
|
|
child.expect_exact('gnrc_tcp_recv: re', timeout=pexpect_timeout_sec)
|
|
except pexpect.TIMEOUT:
|
|
returned = False
|
|
finally:
|
|
if returned:
|
|
raise RuntimeError('gnrc_tcp_recv returned')
|
|
|
|
# Send data to unblock gnrc_tcp_recv and teardown the connection
|
|
host_srv.send(payload)
|
|
child.expect_exact('gnrc_tcp_recv: received {}'.format(len(payload)))
|
|
host_srv.close()
|
|
|
|
|
|
@Runner(timeout=10)
|
|
def test_connection_listen_accept_cycle(child, iterations=10):
|
|
""" This test verifies gnrc_tcp in a typical server role by
|
|
accepting a connection, exchange data, teardown connection, handle the next one
|
|
"""
|
|
# Setup RIOT Node as server
|
|
with RiotTcpServer(child, generate_port_number()) as riot_srv:
|
|
# Establish multiple connections iterativly
|
|
for i in range(iterations):
|
|
print('\n Running listen/accept iteration {}'.format(i), end='')
|
|
|
|
with HostTcpClient(riot_srv) as host_cli:
|
|
# Accept connection from host system
|
|
riot_srv.accept(timeout_ms=0)
|
|
|
|
# Send data from host to RIOT
|
|
data = '0123456789'
|
|
host_cli.send(payload_to_send=data)
|
|
riot_srv.receive(timeout_ms=500, sent_payload=data)
|
|
|
|
# Send data from RIOT to host
|
|
riot_srv.send(timeout_ms=500, payload_to_send=data)
|
|
host_cli.receive(sent_payload=data)
|
|
|
|
# Randomize connection teardown: The connections
|
|
# can be either closed or aborted from either
|
|
# side. Regardless the type of the connection teardown
|
|
# riot_srv must be able to accept the next connection
|
|
# Note: python sockets don't offer abort...
|
|
dice_throw = random.randint(0, 3)
|
|
if dice_throw == 0:
|
|
riot_srv.close()
|
|
host_cli.close()
|
|
|
|
elif dice_throw == 1:
|
|
riot_srv.abort()
|
|
host_cli.close()
|
|
|
|
elif dice_throw == 2:
|
|
host_cli.close()
|
|
riot_srv.close()
|
|
|
|
elif dice_throw == 3:
|
|
host_cli.close()
|
|
riot_srv.abort()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sudo_guard(uses_scapy=True)
|
|
|
|
# Read and run all test functions.
|
|
script = sys.modules[__name__]
|
|
tests = [getattr(script, t) for t in script.__dict__
|
|
if type(getattr(script, t)).__name__ == 'function'
|
|
and t.startswith('test_')]
|
|
|
|
for test in tests:
|
|
res = test()
|
|
if (res != 0):
|
|
sys.exit(res)
|
|
|
|
print('\n' + os.path.basename(sys.argv[0]) + ': success\n')
|