mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
pkg: provide sock_tcp support for lwip
This commit is contained in:
parent
e5e79c2834
commit
b915d15de1
@ -436,6 +436,10 @@ ifneq (,$(filter lwip_sock_ip,$(USEMODULE)))
|
||||
USEMODULE += lwip_raw
|
||||
endif
|
||||
|
||||
ifneq (,$(filter lwip_sock_tcp,$(USEMODULE)))
|
||||
USEMODULE += lwip_tcp
|
||||
endif
|
||||
|
||||
ifneq (,$(filter lwip_sock_udp,$(USEMODULE)))
|
||||
USEMODULE += lwip_udp
|
||||
endif
|
||||
|
@ -25,6 +25,9 @@ endif
|
||||
ifneq (,$(filter lwip_sock_ip,$(USEMODULE)))
|
||||
DIRS += $(RIOTBASE)/pkg/lwip/contrib/sock/ip
|
||||
endif
|
||||
ifneq (,$(filter lwip_sock_tcp,$(USEMODULE)))
|
||||
DIRS += $(RIOTBASE)/pkg/lwip/contrib/sock/tcp
|
||||
endif
|
||||
ifneq (,$(filter lwip_sock_udp,$(USEMODULE)))
|
||||
DIRS += $(RIOTBASE)/pkg/lwip/contrib/sock/udp
|
||||
endif
|
||||
|
@ -295,6 +295,11 @@ int lwip_sock_create(struct netconn **conn, const struct _sock_tl_ep *local,
|
||||
* local->port) demand binding */
|
||||
if (bind) {
|
||||
switch (netconn_bind(*conn, &local_addr, local_port)) {
|
||||
#if LWIP_TCP
|
||||
case ERR_BUF:
|
||||
res = -ENOMEM;
|
||||
break;
|
||||
#endif
|
||||
case ERR_USE:
|
||||
res = -EADDRINUSE;
|
||||
break;
|
||||
@ -311,6 +316,24 @@ int lwip_sock_create(struct netconn **conn, const struct _sock_tl_ep *local,
|
||||
}
|
||||
if (remote != NULL) {
|
||||
switch (netconn_connect(*conn, &remote_addr, remote_port)) {
|
||||
#if LWIP_TCP
|
||||
case ERR_BUF:
|
||||
res = -ENOMEM;
|
||||
break;
|
||||
case ERR_INPROGRESS:
|
||||
res = -EINPROGRESS;
|
||||
break;
|
||||
case ERR_ISCONN:
|
||||
res = -EISCONN;
|
||||
break;
|
||||
case ERR_IF:
|
||||
case ERR_RTE:
|
||||
res = -ENETUNREACH;
|
||||
break;
|
||||
case ERR_ABRT:
|
||||
res = -ETIMEDOUT;
|
||||
break;
|
||||
#endif
|
||||
case ERR_USE:
|
||||
res = -EADDRINUSE;
|
||||
break;
|
||||
@ -403,6 +426,7 @@ int lwip_sock_get_addr(struct netconn *conn, struct _sock_tl_ep *ep, u8_t local)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(MODULE_LWIP_SOCK_UDP) || defined(MODULE_LWIP_SOCK_IP)
|
||||
int lwip_sock_recv(struct netconn *conn, uint32_t timeout, struct netbuf **buf)
|
||||
{
|
||||
int res;
|
||||
@ -441,6 +465,7 @@ int lwip_sock_recv(struct netconn *conn, uint32_t timeout, struct netbuf **buf)
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
#endif /* defined(MODULE_LWIP_SOCK_UDP) || defined(MODULE_LWIP_SOCK_IP) */
|
||||
|
||||
ssize_t lwip_sock_send(struct netconn **conn, const void *data, size_t len,
|
||||
int proto, const struct _sock_tl_ep *remote, int type)
|
||||
@ -494,15 +519,20 @@ ssize_t lwip_sock_send(struct netconn **conn, const void *data, size_t len,
|
||||
netbuf_delete(buf);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
res = len; /* set for non-TCP calls */
|
||||
if (remote != NULL) {
|
||||
err = netconn_sendto(tmp, buf, &remote_addr, remote_port);
|
||||
}
|
||||
#if LWIP_TCP
|
||||
else if (tmp->type & NETCONN_TCP) {
|
||||
err = netconn_write_partly(tmp, data, len, 0, (size_t *)(&res));
|
||||
}
|
||||
#endif /* LWIP_TCP */
|
||||
else {
|
||||
err = netconn_send(tmp, buf);
|
||||
}
|
||||
switch (err) {
|
||||
case ERR_OK:
|
||||
res = len;
|
||||
if (conn != NULL) {
|
||||
*conn = tmp;
|
||||
}
|
||||
|
3
pkg/lwip/contrib/sock/tcp/Makefile
Normal file
3
pkg/lwip/contrib/sock/tcp/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE := lwip_sock_tcp
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
376
pkg/lwip/contrib/sock/tcp/lwip_sock_tcp.c
Normal file
376
pkg/lwip/contrib/sock/tcp/lwip_sock_tcp.c
Normal file
@ -0,0 +1,376 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Freie Universität Berlin
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @author Martine Lenders <m.lenders@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#include "mutex.h"
|
||||
|
||||
#include "net/sock/tcp.h"
|
||||
#include "timex.h"
|
||||
|
||||
#include "lwip/sock_internal.h"
|
||||
#include "lwip/api.h"
|
||||
#include "lwip/opt.h"
|
||||
|
||||
static inline void _tcp_sock_init(sock_tcp_t *sock, struct netconn *conn,
|
||||
sock_tcp_queue_t *queue)
|
||||
{
|
||||
mutex_init(&sock->mutex);
|
||||
mutex_lock(&sock->mutex);
|
||||
netconn_set_noautorecved(conn, 1);
|
||||
sock->conn = conn;
|
||||
sock->queue = queue;
|
||||
sock->last_buf = NULL;
|
||||
sock->last_offset = 0;
|
||||
mutex_unlock(&sock->mutex);
|
||||
}
|
||||
|
||||
int sock_tcp_connect(sock_tcp_t *sock, const sock_tcp_ep_t *remote,
|
||||
uint16_t local_port, uint16_t flags)
|
||||
{
|
||||
assert(sock != NULL);
|
||||
assert((remote != NULL) && (remote->port != 0));
|
||||
|
||||
int res;
|
||||
struct netconn *tmp = NULL;
|
||||
struct _sock_tl_ep local = { .family = remote->family,
|
||||
.netif = remote->netif,
|
||||
.port = local_port };
|
||||
|
||||
if ((res = lwip_sock_create(&tmp, &local, (struct _sock_tl_ep *)remote, 0,
|
||||
flags, NETCONN_TCP)) == 0) {
|
||||
_tcp_sock_init(sock, tmp, NULL);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int sock_tcp_listen(sock_tcp_queue_t *queue, const sock_tcp_ep_t *local,
|
||||
sock_tcp_t *queue_array, unsigned queue_len,
|
||||
uint16_t flags)
|
||||
{
|
||||
assert(queue != NULL);
|
||||
assert((local != NULL) && (local->port != 0));
|
||||
assert((queue_array != NULL) && (queue_len != 0));
|
||||
|
||||
int res;
|
||||
struct netconn *tmp = NULL;
|
||||
|
||||
if (queue_len > USHRT_MAX) {
|
||||
return -EFAULT;
|
||||
}
|
||||
if ((res = lwip_sock_create(&tmp, (struct _sock_tl_ep *)local, NULL, 0,
|
||||
flags, NETCONN_TCP)) < 0) {
|
||||
return res;
|
||||
}
|
||||
assert(tmp != NULL); /* just in case lwIP is trolling */
|
||||
mutex_init(&queue->mutex);
|
||||
mutex_lock(&queue->mutex);
|
||||
queue->conn = tmp;
|
||||
queue->array = queue_array;
|
||||
queue->len = queue_len;
|
||||
queue->used = 0;
|
||||
memset(queue->array, 0, sizeof(sock_tcp_t) * queue_len);
|
||||
mutex_unlock(&queue->mutex);
|
||||
switch (netconn_listen_with_backlog(queue->conn, queue->len)) {
|
||||
case ERR_OK:
|
||||
break;
|
||||
case ERR_MEM:
|
||||
return -ENOMEM;
|
||||
case ERR_USE:
|
||||
return -EADDRINUSE;
|
||||
case ERR_VAL:
|
||||
return -EINVAL;
|
||||
default:
|
||||
assert(false); /* should not happen since queue->conn is not closed
|
||||
* and we have a TCP conn */
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sock_tcp_disconnect(sock_tcp_t *sock)
|
||||
{
|
||||
assert(sock != NULL);
|
||||
mutex_lock(&sock->mutex);
|
||||
if (sock->conn != NULL) {
|
||||
netconn_close(sock->conn);
|
||||
netconn_delete(sock->conn);
|
||||
sock->conn = NULL;
|
||||
/* if sock came from a sock_tcp_queue_t: since sock is a pointer in it's
|
||||
* array it is also deleted from there, but we need to decrement the used
|
||||
* counter */
|
||||
if (sock->queue != NULL) {
|
||||
assert(sock->queue->used > 0);
|
||||
sock->queue->used--;
|
||||
sock->queue = NULL;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&sock->mutex);
|
||||
memset(&sock->mutex, 0, sizeof(mutex_t));
|
||||
}
|
||||
|
||||
void sock_tcp_stop_listen(sock_tcp_queue_t *queue)
|
||||
{
|
||||
assert(queue != NULL);
|
||||
mutex_lock(&queue->mutex);
|
||||
if (queue->conn != NULL) {
|
||||
netconn_close(queue->conn);
|
||||
netconn_delete(queue->conn);
|
||||
queue->conn = NULL;
|
||||
/* sever connections established through this queue */
|
||||
for (unsigned i = 0; i < queue->len; i++) {
|
||||
sock_tcp_disconnect(&queue->array[i]);
|
||||
}
|
||||
queue->array = NULL;
|
||||
queue->len = 0;
|
||||
queue->used = 0;
|
||||
}
|
||||
mutex_unlock(&queue->mutex);
|
||||
memset(&queue->mutex, 0, sizeof(mutex_t));
|
||||
}
|
||||
|
||||
int sock_tcp_get_local(sock_tcp_t *sock, sock_tcp_ep_t *ep)
|
||||
{
|
||||
int res = 0;
|
||||
assert(sock != NULL);
|
||||
mutex_lock(&sock->mutex);
|
||||
if ((sock->conn == NULL) || lwip_sock_get_addr(sock->conn,
|
||||
(struct _sock_tl_ep *)ep,
|
||||
1)) {
|
||||
res = -EADDRNOTAVAIL;
|
||||
}
|
||||
mutex_unlock(&sock->mutex);
|
||||
return res;
|
||||
}
|
||||
|
||||
int sock_tcp_get_remote(sock_tcp_t *sock, sock_tcp_ep_t *ep)
|
||||
{
|
||||
int res = 0;
|
||||
assert(sock != NULL);
|
||||
mutex_lock(&sock->mutex);
|
||||
if ((sock->conn == NULL) || lwip_sock_get_addr(sock->conn,
|
||||
(struct _sock_tl_ep *)ep,
|
||||
0)) {
|
||||
res = -ENOTCONN;
|
||||
}
|
||||
mutex_unlock(&sock->mutex);
|
||||
return res;
|
||||
}
|
||||
|
||||
int sock_tcp_queue_get_local(sock_tcp_queue_t *queue, sock_tcp_ep_t *ep)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
assert(queue != NULL);
|
||||
mutex_lock(&queue->mutex);
|
||||
if ((queue->conn == NULL) || lwip_sock_get_addr(queue->conn,
|
||||
(struct _sock_tl_ep *)ep,
|
||||
1)) {
|
||||
res = -EADDRNOTAVAIL;
|
||||
}
|
||||
mutex_unlock(&queue->mutex);
|
||||
return res;
|
||||
}
|
||||
|
||||
int sock_tcp_accept(sock_tcp_queue_t *queue, sock_tcp_t **sock,
|
||||
uint32_t timeout)
|
||||
{
|
||||
struct netconn *tmp = NULL;
|
||||
int res = 0;
|
||||
|
||||
assert((queue != NULL) && (sock != NULL));
|
||||
if (queue->conn == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (timeout == 0) {
|
||||
if (!mutex_trylock(&queue->mutex)) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
else if (timeout != 0) {
|
||||
mutex_lock(&queue->mutex);
|
||||
}
|
||||
if (queue->used < queue->len) {
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
if ((timeout != 0) && (timeout != SOCK_NO_TIMEOUT)) {
|
||||
netconn_set_recvtimeout(queue->conn, timeout / US_PER_MS);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if ((timeout == 0) && !cib_avail(&queue->conn->acceptmbox.mbox.cib)) {
|
||||
mutex_unlock(&queue->mutex);
|
||||
return -EAGAIN;
|
||||
}
|
||||
switch (netconn_accept(queue->conn, &tmp)) {
|
||||
case ERR_OK:
|
||||
for (unsigned short i = 0; i < queue->len; i++) {
|
||||
sock_tcp_t *s = &queue->array[i];
|
||||
if (s->conn == NULL) {
|
||||
_tcp_sock_init(s, tmp, queue);
|
||||
queue->used++;
|
||||
assert(queue->used > 0);
|
||||
*sock = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ERR_ABRT:
|
||||
res = -ECONNABORTED;
|
||||
break;
|
||||
case ERR_MEM:
|
||||
res = -ENOMEM;
|
||||
break;
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
case ERR_TIMEOUT:
|
||||
res = -ETIMEDOUT;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
assert(false);
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
res = -ENOMEM;
|
||||
}
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
netconn_set_recvtimeout(queue->conn, 0);
|
||||
#endif
|
||||
mutex_unlock(&queue->mutex);
|
||||
return res;
|
||||
}
|
||||
|
||||
ssize_t sock_tcp_read(sock_tcp_t *sock, void *data, size_t max_len,
|
||||
uint32_t timeout)
|
||||
{
|
||||
uint8_t *data_ptr = data;
|
||||
struct pbuf *buf;
|
||||
ssize_t offset = 0, res = 0;
|
||||
bool done = false;
|
||||
|
||||
assert((sock != NULL) && (data != NULL) && (max_len > 0));
|
||||
if (sock->conn == NULL) {
|
||||
return -ENOTCONN;
|
||||
}
|
||||
if (timeout == 0) {
|
||||
if (!mutex_trylock(&sock->mutex)) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mutex_lock(&sock->mutex);
|
||||
}
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
if ((timeout != 0) && (timeout != SOCK_NO_TIMEOUT)) {
|
||||
netconn_set_recvtimeout(sock->conn, timeout / US_PER_MS);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if ((timeout == 0) && !cib_avail(&sock->conn->recvmbox.mbox.cib)) {
|
||||
mutex_unlock(&sock->mutex);
|
||||
return -EAGAIN;
|
||||
}
|
||||
while (!done) {
|
||||
uint16_t copylen, buf_len;
|
||||
if (sock->last_buf != NULL) {
|
||||
buf = sock->last_buf;
|
||||
}
|
||||
else {
|
||||
err_t err;
|
||||
if ((err = netconn_recv_tcp_pbuf(sock->conn, &buf)) < 0) {
|
||||
switch (err) {
|
||||
case ERR_ABRT:
|
||||
res = -ECONNABORTED;
|
||||
break;
|
||||
case ERR_CONN:
|
||||
res = -EADDRNOTAVAIL;
|
||||
break;
|
||||
case ERR_RST:
|
||||
case ERR_CLSD:
|
||||
res = -ECONNRESET;
|
||||
break;
|
||||
case ERR_MEM:
|
||||
res = -ENOMEM;
|
||||
break;
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
case ERR_TIMEOUT:
|
||||
res = -ETIMEDOUT;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* no applicable error */
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
sock->last_buf = buf;
|
||||
}
|
||||
buf_len = buf->tot_len - sock->last_offset;
|
||||
copylen = (buf_len > max_len) ? (uint16_t)max_len : buf_len;
|
||||
pbuf_copy_partial(buf, data_ptr + offset, copylen, sock->last_offset);
|
||||
offset += copylen;
|
||||
max_len -= copylen; /* should be 0 at minimum due to copylen setting above */
|
||||
if (max_len == 0) {
|
||||
done = true;
|
||||
res = offset; /* in case offset == 0 */
|
||||
}
|
||||
/* post-process buf */
|
||||
if (buf_len > copylen) {
|
||||
/* there is still data in the buffer */
|
||||
sock->last_buf = buf;
|
||||
sock->last_offset = copylen;
|
||||
}
|
||||
else {
|
||||
sock->last_buf = NULL;
|
||||
sock->last_offset = 0;
|
||||
pbuf_free(buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (offset > 0) {
|
||||
/* inform lwIP how much we receive*/
|
||||
netconn_recved(sock->conn, (u32_t)offset);
|
||||
res = offset; /* we received data so return it */
|
||||
}
|
||||
/* unset flags */
|
||||
#if LWIP_SO_RCVTIMEO
|
||||
netconn_set_recvtimeout(sock->conn, 0);
|
||||
#endif
|
||||
netconn_set_nonblocking(sock->conn, false);
|
||||
mutex_unlock(&sock->mutex);
|
||||
return res;
|
||||
}
|
||||
|
||||
ssize_t sock_tcp_write(sock_tcp_t *sock, const void *data, size_t len)
|
||||
{
|
||||
struct netconn *conn;
|
||||
int res = 0;
|
||||
|
||||
assert(sock != NULL);
|
||||
assert((len == 0) || (data != NULL)); /* (len != 0) => (data != NULL) */
|
||||
mutex_lock(&sock->mutex);
|
||||
if (sock->conn == NULL) {
|
||||
mutex_unlock(&sock->mutex);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
conn = sock->conn;
|
||||
mutex_unlock(&sock->mutex); /* we won't change anything to sock here
|
||||
(lwip_sock_send neither, since it remote is
|
||||
NULL) so we can leave the mutex */
|
||||
res = lwip_sock_send(&conn, data, len, 0, NULL, NETCONN_TCP);
|
||||
return res;
|
||||
}
|
||||
|
||||
/** @} */
|
@ -34,6 +34,14 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Configures @ref sock_tcp_accept() timeout in milliseconds
|
||||
* (0 by default, which means no timeout)
|
||||
*/
|
||||
#ifndef LWIP_SOCK_TCP_ACCEPT_TIMEOUT
|
||||
#define LWIP_SOCK_TCP_ACCEPT_TIMEOUT (0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Internal helper functions for lwIP
|
||||
* @internal
|
||||
@ -44,7 +52,9 @@ int lwip_sock_create(struct netconn **conn, const struct _sock_tl_ep *local,
|
||||
uint16_t flags, int type);
|
||||
uint16_t lwip_sock_bind_addr_to_netif(const ip_addr_t *bind_addr);
|
||||
int lwip_sock_get_addr(struct netconn *conn, struct _sock_tl_ep *ep, u8_t local);
|
||||
#if defined(MODULE_LWIP_SOCK_UDP) || defined(MODULE_LWIP_SOCK_IP)
|
||||
int lwip_sock_recv(struct netconn *conn, uint32_t timeout, struct netbuf **buf);
|
||||
#endif
|
||||
ssize_t lwip_sock_send(struct netconn **conn, const void *data, size_t len,
|
||||
int proto, const struct _sock_tl_ep *remote, int type);
|
||||
/**
|
||||
|
@ -33,6 +33,29 @@ struct sock_ip {
|
||||
struct netconn *conn;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief TCP sock type
|
||||
* @internal
|
||||
*/
|
||||
struct sock_tcp {
|
||||
struct netconn *conn;
|
||||
struct sock_tcp_queue *queue;
|
||||
mutex_t mutex;
|
||||
struct pbuf *last_buf;
|
||||
ssize_t last_offset;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief TCP queue type
|
||||
*/
|
||||
struct sock_tcp_queue {
|
||||
struct netconn *conn;
|
||||
struct sock_tcp *array;
|
||||
mutex_t mutex;
|
||||
unsigned short len;
|
||||
unsigned short used;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief UDP sock type
|
||||
* @internal
|
||||
|
49
tests/lwip_sock_tcp/Makefile
Normal file
49
tests/lwip_sock_tcp/Makefile
Normal file
@ -0,0 +1,49 @@
|
||||
APPLICATION = lwip_sock_tcp
|
||||
|
||||
include ../Makefile.tests_common
|
||||
|
||||
# lwIP's memory management doesn't seem to work on non 32-bit platforms at the
|
||||
# moment.
|
||||
BOARD_BLACKLIST := arduino-uno arduino-duemilanove arduino-mega2560 chronos \
|
||||
msb-430 msb-430h telosb waspmote-pro wsn430-v1_3b \
|
||||
wsn430-v1_4 z1
|
||||
BOARD_INSUFFICIENT_MEMORY = nucleo-f030 nucleo32-f042 nucleo-f334 \
|
||||
stm32f0discovery weio
|
||||
|
||||
LWIP_IPV4 ?= 0
|
||||
|
||||
ifneq (0, $(LWIP_IPV4))
|
||||
USEMODULE += ipv4_addr
|
||||
USEMODULE += lwip_arp
|
||||
USEMODULE += lwip_ipv4
|
||||
CFLAGS += -DETHARP_SUPPORT_STATIC_ENTRIES=1
|
||||
LWIP_IPV6 ?= 0
|
||||
else
|
||||
LWIP_IPV6 ?= 1
|
||||
endif
|
||||
|
||||
ifneq (0, $(LWIP_IPV6))
|
||||
USEMODULE += ipv6_addr
|
||||
USEMODULE += lwip_ipv6_autoconfig
|
||||
endif
|
||||
|
||||
USEMODULE += inet_csum
|
||||
USEMODULE += lwip_ethernet lwip_netdev2
|
||||
USEMODULE += lwip_sock_tcp
|
||||
USEMODULE += netdev2_eth
|
||||
USEMODULE += netdev2_test
|
||||
USEMODULE += ps
|
||||
|
||||
DISABLE_MODULE += auto_init
|
||||
|
||||
CFLAGS += -DDEVELHELP
|
||||
CFLAGS += -DSO_REUSE
|
||||
CFLAGS += -DLWIP_SO_RCVTIMEO
|
||||
CFLAGS += -DLWIP_SOCK_TCP_ACCEPT_TIMEOUT=500
|
||||
CFLAGS += -DLWIP_NETIF_LOOPBACK=1
|
||||
CFLAGS += -DLWIP_HAVE_LOOPIF=1
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
||||
|
||||
test:
|
||||
./tests/01-run.py
|
33
tests/lwip_sock_tcp/README.md
Normal file
33
tests/lwip_sock_tcp/README.md
Normal file
@ -0,0 +1,33 @@
|
||||
Tests for lwIP's sock_tcp port
|
||||
==============================
|
||||
|
||||
This tests the `sock_tcp` port of lwIP. There is no network device needed since
|
||||
a [virtual device](http://doc.riot-os.org/group__sys__netdev2__test.html) is
|
||||
provided at the backend.
|
||||
|
||||
These tests test both IPv4 and IPv6 capabilities. They can be activated by
|
||||
the `LWIP_IPV4` and `LWIP_IPV6` environment variables to a non-zero value.
|
||||
IPv6 is activated by default:
|
||||
|
||||
```sh
|
||||
make all test
|
||||
# or
|
||||
LWIP_IPV6=1 make all test
|
||||
```
|
||||
|
||||
To just test IPv4 set the `LWIP_IPV4` to a non-zero value (IPv6 will be
|
||||
deactivated automatically):
|
||||
|
||||
```sh
|
||||
LWIP_IPV4=1 make all test
|
||||
```
|
||||
|
||||
To test both set the `LWIP_IPV4` and `LWIP_IPV6` to a non-zero value:
|
||||
|
||||
```sh
|
||||
LWIP_IPV4=1 LWIP_IPV6=1 make all test
|
||||
```
|
||||
|
||||
Since lwIP uses a lot of macro magic to activate/deactivate these capabilities
|
||||
it is advisable to **test all three configurations individually** (just IPv4,
|
||||
just IPv6, IPv4/IPv6 dual stack mode).
|
49
tests/lwip_sock_tcp/constants.h
Normal file
49
tests/lwip_sock_tcp/constants.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Freie Universität Berlin
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup
|
||||
* @ingroup
|
||||
* @brief
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief
|
||||
*
|
||||
* @author Martine Lenders <m.lenders@fu-berlin.de>
|
||||
*/
|
||||
#ifndef CONSTANTS_H_
|
||||
#define CONSTANTS_H_
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define _TEST_PORT_LOCAL (0x2c94)
|
||||
#define _TEST_PORT_REMOTE (0xa615)
|
||||
#define _TEST_NETIF (1)
|
||||
#define _TEST_TIMEOUT (1000000U)
|
||||
#define _TEST_ADDR4_LOCAL (0xc0a84f96U) /* 192.168.79.150 */
|
||||
#define _TEST_ADDR4_REMOTE (0x7f000001U) /* 127.0.0.1 */
|
||||
#define _TEST_ADDR4_WRONG (0x254c6b4cU)
|
||||
#define _TEST_ADDR4_MASK (0xffffff00U) /* 255.255.255.0 */
|
||||
#define _TEST_ADDR4_GW (0UL) /* so we can test unreachability */
|
||||
#define _TEST_ADDR6_LOCAL { 0x2f, 0xc4, 0x11, 0x5a, 0xe6, 0x91, 0x8d, 0x5d, \
|
||||
0x8c, 0xd1, 0x47, 0x07, 0xb7, 0x6f, 0x9b, 0x48 }
|
||||
#define _TEST_ADDR6_REMOTE { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }
|
||||
#define _TEST_ADDR6_WRONG { 0x2a, 0xce, 0x5d, 0x4e, 0xc8, 0xbf, 0x86, 0xf7, \
|
||||
0x85, 0x49, 0xb4, 0x19, 0xf2, 0x28, 0xde, 0x9b }
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CONSTANTS_H_ */
|
||||
/** @} */
|
1192
tests/lwip_sock_tcp/main.c
Normal file
1192
tests/lwip_sock_tcp/main.c
Normal file
File diff suppressed because it is too large
Load Diff
30
tests/lwip_sock_tcp/stack.c
Normal file
30
tests/lwip_sock_tcp/stack.c
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Freie Universität Berlin
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
|
||||
|
||||
#include "xtimer.h"
|
||||
|
||||
#include "lwip.h"
|
||||
#include "lwip/netif.h"
|
||||
|
||||
#include "stack.h"
|
||||
|
||||
void _net_init(void)
|
||||
{
|
||||
xtimer_init();
|
||||
lwip_bootstrap();
|
||||
}
|
||||
|
||||
/** @} */
|
37
tests/lwip_sock_tcp/stack.h
Normal file
37
tests/lwip_sock_tcp/stack.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Freie Universität Berlin
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup
|
||||
* @ingroup
|
||||
* @brief
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief
|
||||
*
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
#ifndef STACK_H_
|
||||
#define STACK_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initializes networking for tests
|
||||
*/
|
||||
void _net_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* STACK_H_ */
|
||||
/** @} */
|
141
tests/lwip_sock_tcp/tests/01-run.py
Executable file
141
tests/lwip_sock_tcp/tests/01-run.py
Executable file
@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (C) 2016 Freie Universität Berlin
|
||||
#
|
||||
# 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
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
sys.path.append(os.path.join(os.environ['RIOTBASE'], 'dist/tools/testrunner'))
|
||||
import testrunner
|
||||
|
||||
class InvalidTimeout(Exception):
|
||||
pass
|
||||
|
||||
def _reuse_tests(code):
|
||||
return code & 1
|
||||
|
||||
def _ipv6_tests(code):
|
||||
return code & (1 << 6)
|
||||
|
||||
def _ipv4_tests(code):
|
||||
return code & (1 << 4)
|
||||
|
||||
def testfunc(child):
|
||||
child.expect(u"code (0x[0-9a-f]{2})")
|
||||
code = int(child.match.group(1), base=16)
|
||||
if _ipv4_tests(code):
|
||||
if _reuse_tests(code):
|
||||
child.expect_exact("Calling test_tcp_connect4__EADDRINUSE()")
|
||||
child.expect_exact("Calling test_tcp_connect4__EAFNOSUPPORT()")
|
||||
child.expect_exact("Calling test_tcp_connect4__EINVAL_addr()")
|
||||
child.expect_exact("Calling test_tcp_connect4__EINVAL_netif()")
|
||||
child.expect_exact("Calling test_tcp_connect4__success_without_port()")
|
||||
child.expect_exact("Calling test_tcp_connect4__success_local_port()")
|
||||
if _reuse_tests(code):
|
||||
child.expect_exact("Calling test_tcp_listen4__EADDRINUSE()")
|
||||
child.expect_exact("Calling test_tcp_listen4__EAFNOSUPPORT()")
|
||||
child.expect_exact("Calling test_tcp_listen4__EINVAL()")
|
||||
child.expect_exact("Calling test_tcp_listen4__success_any_netif()")
|
||||
child.expect_exact("Calling test_tcp_listen4__success_spec_netif()")
|
||||
child.expect_exact("Calling test_tcp_accept4__EAGAIN()")
|
||||
child.expect_exact("Calling test_tcp_accept4__EINVAL()")
|
||||
child.expect_exact("Calling test_tcp_accept4__ETIMEDOUT()")
|
||||
start = datetime.now()
|
||||
child.expect_exact(" * Calling sock_tcp_accept()")
|
||||
child.expect(u" \\* \\(timed out with timeout (\\d+)\\)")
|
||||
exp_diff = int(child.match.group(1))
|
||||
stop = datetime.now()
|
||||
diff = (stop - start)
|
||||
diff = (diff.seconds * 1000000) + diff.microseconds
|
||||
# fail within 5% of expected
|
||||
if diff > (exp_diff + (exp_diff * 0.05)) or \
|
||||
diff < (exp_diff - (exp_diff * 0.05)):
|
||||
raise InvalidTimeout("Invalid timeout %d (expected %d)" % (diff, exp_diff));
|
||||
else:
|
||||
print("Timed out correctly: %d (expected %d)" % (diff, exp_diff))
|
||||
child.expect_exact("Calling test_tcp_accept4__success()")
|
||||
child.expect_exact("Calling test_tcp_read4__EAGAIN()")
|
||||
child.expect_exact("Calling test_tcp_read4__ECONNRESET()")
|
||||
child.expect_exact("Calling test_tcp_read4__ENOTCONN()")
|
||||
child.expect_exact("Calling test_tcp_read4__ETIMEDOUT()")
|
||||
start = datetime.now()
|
||||
child.expect_exact(" * Calling sock_tcp_read()")
|
||||
child.expect(u" \\* \\(timed out with timeout (\\d+)\\)")
|
||||
exp_diff = int(child.match.group(1))
|
||||
stop = datetime.now()
|
||||
diff = (stop - start)
|
||||
diff = (diff.seconds * 1000000) + diff.microseconds
|
||||
# fail within 5% of expected
|
||||
if diff > (exp_diff + (exp_diff * 0.05)) or \
|
||||
diff < (exp_diff - (exp_diff * 0.05)):
|
||||
raise InvalidTimeout("Invalid timeout %d (expected %d)" % (diff, exp_diff));
|
||||
else:
|
||||
print("Timed out correctly: %d (expected %d)" % (diff, exp_diff))
|
||||
child.expect_exact("Calling test_tcp_read4__success()")
|
||||
child.expect_exact("Calling test_tcp_read4__success_with_timeout()")
|
||||
child.expect_exact("Calling test_tcp_read4__success_non_blocking()")
|
||||
child.expect_exact("Calling test_tcp_write4__ENOTCONN()")
|
||||
child.expect_exact("Calling test_tcp_write4__success()")
|
||||
if _ipv6_tests(code):
|
||||
if _reuse_tests(code):
|
||||
child.expect_exact("Calling test_tcp_connect6__EADDRINUSE()")
|
||||
child.expect_exact("Calling test_tcp_connect6__EAFNOSUPPORT()")
|
||||
child.expect_exact("Calling test_tcp_connect6__EINVAL_addr()")
|
||||
child.expect_exact("Calling test_tcp_connect6__EINVAL_netif()")
|
||||
child.expect_exact("Calling test_tcp_connect6__success_without_port()")
|
||||
child.expect_exact("Calling test_tcp_connect6__success_local_port()")
|
||||
if _reuse_tests(code):
|
||||
child.expect_exact("Calling test_tcp_listen6__EADDRINUSE()")
|
||||
child.expect_exact("Calling test_tcp_listen6__EAFNOSUPPORT()")
|
||||
child.expect_exact("Calling test_tcp_listen6__EINVAL()")
|
||||
child.expect_exact("Calling test_tcp_listen6__success_any_netif()")
|
||||
child.expect_exact("Calling test_tcp_listen6__success_spec_netif()")
|
||||
child.expect_exact("Calling test_tcp_accept6__EAGAIN()")
|
||||
child.expect_exact("Calling test_tcp_accept6__EINVAL()")
|
||||
child.expect_exact("Calling test_tcp_accept6__ETIMEDOUT()")
|
||||
start = datetime.now()
|
||||
child.expect_exact(" * Calling sock_tcp_accept()")
|
||||
child.expect(u" \\* \\(timed out with timeout (\\d+)\\)")
|
||||
exp_diff = int(child.match.group(1))
|
||||
stop = datetime.now()
|
||||
diff = (stop - start)
|
||||
diff = (diff.seconds * 1000000) + diff.microseconds
|
||||
# fail within 5% of expected
|
||||
if diff > (exp_diff + (exp_diff * 0.05)) or \
|
||||
diff < (exp_diff - (exp_diff * 0.05)):
|
||||
raise InvalidTimeout("Invalid timeout %d (expected %d)" % (diff, exp_diff));
|
||||
else:
|
||||
print("Timed out correctly: %d (expected %d)" % (diff, exp_diff))
|
||||
child.expect_exact("Calling test_tcp_accept6__success()")
|
||||
child.expect_exact("Calling test_tcp_read6__EAGAIN()")
|
||||
child.expect_exact("Calling test_tcp_read6__ECONNRESET()")
|
||||
child.expect_exact("Calling test_tcp_read6__ENOTCONN()")
|
||||
child.expect_exact("Calling test_tcp_read6__ETIMEDOUT()")
|
||||
start = datetime.now()
|
||||
child.expect_exact(" * Calling sock_tcp_read()")
|
||||
child.expect(u" \\* \\(timed out with timeout (\\d+)\\)")
|
||||
exp_diff = int(child.match.group(1))
|
||||
stop = datetime.now()
|
||||
diff = (stop - start)
|
||||
diff = (diff.seconds * 1000000) + diff.microseconds
|
||||
# fail within 5% of expected
|
||||
if diff > (exp_diff + (exp_diff * 0.05)) or \
|
||||
diff < (exp_diff - (exp_diff * 0.05)):
|
||||
raise InvalidTimeout("Invalid timeout %d (expected %d)" % (diff, exp_diff));
|
||||
else:
|
||||
print("Timed out correctly: %d (expected %d)" % (diff, exp_diff))
|
||||
child.expect_exact("Calling test_tcp_read6__success()")
|
||||
child.expect_exact("Calling test_tcp_read6__success_with_timeout()")
|
||||
child.expect_exact("Calling test_tcp_read6__success_non_blocking()")
|
||||
child.expect_exact("Calling test_tcp_write6__ENOTCONN()")
|
||||
child.expect_exact("Calling test_tcp_write6__success()")
|
||||
child.expect_exact(u"ALL TESTS SUCCESSFUL")
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(testrunner.run(testfunc, timeout=60))
|
Loading…
Reference in New Issue
Block a user