Merge pull request #13427 from miri64/lwip/enh/sock_async

lwip: provide sock_async support
This commit is contained in:
Gunar Schorcht 2020-03-06 14:37:54 +01:00 committed by GitHub
commit fc37d7bf81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 556 additions and 134 deletions

View File

@ -3,3 +3,7 @@
FEATURES_REQUIRED += arch_32bit
DEFAULT_MODULE += auto_init_lwip
ifneq (,$(filter lwip_sock_async,$(USEMODULE)))
USEMODULE += sock_async
endif

View File

@ -15,6 +15,7 @@ PSEUDOMODULES += lwip_stats
PSEUDOMODULES += lwip_tcp
PSEUDOMODULES += lwip_udp
PSEUDOMODULES += lwip_udplite
PSEUDOMODULES += lwip_sock_async
ifneq (,$(filter lwip_contrib,$(USEMODULE)))
DIRS += $(RIOTBASE)/pkg/lwip/contrib
@ -28,6 +29,9 @@ ifneq (,$(filter lwip_sock,$(USEMODULE)))
endif
DIRS += $(RIOTBASE)/pkg/lwip/contrib/sock
endif
ifneq (,$(filter lwip_sock_async,$(USEMODULE)))
CFLAGS += -DSOCK_HAS_ASYNC
endif
ifneq (,$(filter lwip_sock_ip,$(USEMODULE)))
DIRS += $(RIOTBASE)/pkg/lwip/contrib/sock/ip
endif

View File

@ -28,7 +28,6 @@
#include "lwip/sys.h"
#include "lwip/sock_internal.h"
int sock_ip_create(sock_ip_t *sock, const sock_ip_ep_t *local,
const sock_ip_ep_t *remote, uint8_t proto, uint16_t flags)
{
@ -42,7 +41,10 @@ int sock_ip_create(sock_ip_t *sock, const sock_ip_ep_t *local,
if ((res = lwip_sock_create(&tmp, (struct _sock_tl_ep *)local,
(struct _sock_tl_ep *)remote, proto, flags,
NETCONN_RAW)) == 0) {
sock->conn = tmp;
sock->base.conn = tmp;
#if IS_ACTIVE(SOCK_HAS_ASYNC)
netconn_set_callback_arg(sock->base.conn, &sock->base);
#endif
}
return res;
}
@ -50,23 +52,23 @@ int sock_ip_create(sock_ip_t *sock, const sock_ip_ep_t *local,
void sock_ip_close(sock_ip_t *sock)
{
assert(sock != NULL);
if (sock->conn != NULL) {
netconn_delete(sock->conn);
sock->conn = NULL;
if (sock->base.conn != NULL) {
netconn_delete(sock->base.conn);
sock->base.conn = NULL;
}
}
int sock_ip_get_local(sock_ip_t *sock, sock_ip_ep_t *ep)
{
assert(sock != NULL);
return (lwip_sock_get_addr(sock->conn, (struct _sock_tl_ep *)ep,
return (lwip_sock_get_addr(sock->base.conn, (struct _sock_tl_ep *)ep,
1)) ? -EADDRNOTAVAIL : 0;
}
int sock_ip_get_remote(sock_ip_t *sock, sock_ip_ep_t *ep)
{
assert(sock != NULL);
return (lwip_sock_get_addr(sock->conn, (struct _sock_tl_ep *)ep,
return (lwip_sock_get_addr(sock->base.conn, (struct _sock_tl_ep *)ep,
0)) ? -ENOTCONN : 0;
}
@ -161,7 +163,7 @@ ssize_t sock_ip_recv(sock_ip_t *sock, void *data, size_t max_len,
int res;
assert((sock != NULL) && (data != NULL) && (max_len > 0));
if ((res = lwip_sock_recv(sock->conn, timeout, &buf)) < 0) {
if ((res = lwip_sock_recv(sock->base.conn, timeout, &buf)) < 0) {
return res;
}
res = _parse_iphdr(buf, data, max_len, remote);
@ -174,8 +176,22 @@ ssize_t sock_ip_send(sock_ip_t *sock, const void *data, size_t len,
{
assert((sock != NULL) || (remote != NULL));
assert((len == 0) || (data != NULL)); /* (len != 0) => (data != NULL) */
return lwip_sock_send(sock ? sock->conn : NULL, data, len, proto,
return lwip_sock_send(sock ? sock->base.conn : NULL, data, len, proto,
(struct _sock_tl_ep *)remote, NETCONN_RAW);
}
#ifdef SOCK_HAS_ASYNC
void sock_ip_set_cb(sock_ip_t *sock, sock_ip_cb_t cb)
{
sock->base.async_cb.ip = cb;
}
#ifdef SOCK_HAS_ASYNC_CTX
sock_async_ctx_t *sock_ip_get_async_ctx(sock_ip_t *sock)
{
return &sock->base.async_ctx;
}
#endif /* SOCK_HAS_ASYNC_CTX */
#endif /* SOCK_HAS_ASYNC */
/** @} */

View File

@ -23,9 +23,12 @@
#include "lwip/err.h"
#include "lwip/ip.h"
#include "lwip/tcp.h"
#include "lwip/netif.h"
#include "lwip/opt.h"
#include "sock_types.h"
#if !LWIP_IPV4 && !LWIP_IPV6
#error "lwip_sock needs IPv4 or IPv6 support"
#endif
@ -255,11 +258,78 @@ static int _sock_ep_to_netconn_pars(const struct _sock_tl_ep *local,
return res;
}
static void _netconn_cb(struct netconn *conn, enum netconn_evt evt,
u16_t len)
{
#if IS_ACTIVE(SOCK_HAS_ASYNC)
lwip_sock_base_t *sock = netconn_get_callback_arg(conn);
if (sock && conn->pcb.raw &&
/* lwIP's TCP implementation initializes callback_arg.socket with -1
* when not provided */
(conn->callback_arg.socket != -1)) {
sock_async_flags_t flags = 0;
(void)len;
switch (evt) {
case NETCONN_EVT_RCVPLUS:
if (LWIP_TCP && (conn->type & NETCONN_TCP)) {
#if LWIP_TCP /* additional guard needed due to dependent member access */
switch (conn->pcb.tcp->state) {
case CLOSED:
case CLOSE_WAIT:
case CLOSING:
flags |= SOCK_ASYNC_CONN_FIN;
break;
default:
break;
}
if (cib_avail(&conn->acceptmbox.mbox.cib)) {
flags |= SOCK_ASYNC_CONN_RECV;
}
if (cib_avail(&conn->recvmbox.mbox.cib)) {
flags |= SOCK_ASYNC_MSG_RECV;
}
#endif
}
else {
flags |= SOCK_ASYNC_MSG_RECV;
}
break;
case NETCONN_EVT_SENDPLUS:
flags |= SOCK_ASYNC_MSG_SENT;
break;
case NETCONN_EVT_ERROR:
if (LWIP_TCP && (conn->type & NETCONN_TCP)) {
/* try to report this */
flags |= SOCK_ASYNC_CONN_FIN;
}
break;
case NETCONN_EVT_RCVMINUS:
case NETCONN_EVT_SENDMINUS:
break;
default:
LWIP_ASSERT("unknown event", 0);
break;
}
if (flags && sock->async_cb.gen) {
sock->async_cb.gen(sock, flags);
}
}
#else
(void)conn;
(void)evt;
(void)len;
#endif
}
static int _create(int type, int proto, uint16_t flags, struct netconn **out)
{
if ((*out = netconn_new_with_proto_and_callback(type, proto, NULL)) == NULL) {
if ((*out = netconn_new_with_proto_and_callback(
type, proto,
IS_ACTIVE(SOCK_HAS_ASYNC) ? _netconn_cb : NULL)) == NULL) {
return -ENOMEM;
}
netconn_set_callback_arg(*out, NULL);
#if LWIP_IPV4 && LWIP_IPV6
if (type & NETCONN_TYPE_IPV6) {
netconn_set_ipv6only(*out, 1);

View File

@ -27,7 +27,8 @@ static inline void _tcp_sock_init(sock_tcp_t *sock, struct netconn *conn,
{
mutex_init(&sock->mutex);
mutex_lock(&sock->mutex);
sock->conn = conn;
sock->base.conn = conn;
netconn_set_callback_arg(sock->base.conn, &sock->base);
sock->queue = queue;
sock->last_buf = NULL;
sock->last_offset = 0;
@ -74,13 +75,14 @@ int sock_tcp_listen(sock_tcp_queue_t *queue, const sock_tcp_ep_t *local,
assert(tmp != NULL); /* just in case lwIP is trolling */
mutex_init(&queue->mutex);
mutex_lock(&queue->mutex);
queue->conn = tmp;
queue->base.conn = tmp;
netconn_set_callback_arg(queue->base.conn, &queue->base);
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)) {
switch (netconn_listen_with_backlog(queue->base.conn, queue->len)) {
case ERR_OK:
break;
case ERR_MEM:
@ -90,8 +92,8 @@ int sock_tcp_listen(sock_tcp_queue_t *queue, const sock_tcp_ep_t *local,
case ERR_VAL:
return -EINVAL;
default:
assert(false); /* should not happen since queue->conn is not closed
* and we have a TCP conn */
assert(false); /* should not happen since queue->base.conn is not
* closed and we have a TCP conn */
break;
}
return 0;
@ -101,10 +103,10 @@ 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->base.conn != NULL) {
netconn_close(sock->base.conn);
netconn_delete(sock->base.conn);
sock->base.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 */
@ -122,10 +124,10 @@ 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;
if (queue->base.conn != NULL) {
netconn_close(queue->base.conn);
netconn_delete(queue->base.conn);
queue->base.conn = NULL;
/* sever connections established through this queue */
for (unsigned i = 0; i < queue->len; i++) {
sock_tcp_disconnect(&queue->array[i]);
@ -143,7 +145,7 @@ 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,
if ((sock->base.conn == NULL) || lwip_sock_get_addr(sock->base.conn,
(struct _sock_tl_ep *)ep,
1)) {
res = -EADDRNOTAVAIL;
@ -157,7 +159,7 @@ 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,
if ((sock->base.conn == NULL) || lwip_sock_get_addr(sock->base.conn,
(struct _sock_tl_ep *)ep,
0)) {
res = -ENOTCONN;
@ -172,7 +174,7 @@ int sock_tcp_queue_get_local(sock_tcp_queue_t *queue, sock_tcp_ep_t *ep)
assert(queue != NULL);
mutex_lock(&queue->mutex);
if ((queue->conn == NULL) || lwip_sock_get_addr(queue->conn,
if ((queue->base.conn == NULL) || lwip_sock_get_addr(queue->base.conn,
(struct _sock_tl_ep *)ep,
1)) {
res = -EADDRNOTAVAIL;
@ -188,7 +190,7 @@ int sock_tcp_accept(sock_tcp_queue_t *queue, sock_tcp_t **sock,
int res = 0;
assert((queue != NULL) && (sock != NULL));
if (queue->conn == NULL) {
if (queue->base.conn == NULL) {
return -EINVAL;
}
if (timeout == 0) {
@ -202,19 +204,19 @@ int sock_tcp_accept(sock_tcp_queue_t *queue, sock_tcp_t **sock,
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);
netconn_set_recvtimeout(queue->base.conn, timeout / US_PER_MS);
}
else
#endif
if ((timeout == 0) && !cib_avail(&queue->conn->acceptmbox.mbox.cib)) {
if ((timeout == 0) && !cib_avail(&queue->base.conn->acceptmbox.mbox.cib)) {
mutex_unlock(&queue->mutex);
return -EAGAIN;
}
switch (netconn_accept(queue->conn, &tmp)) {
switch (netconn_accept(queue->base.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) {
if (s->base.conn == NULL) {
_tcp_sock_init(s, tmp, queue);
queue->used++;
assert(queue->used > 0);
@ -241,10 +243,17 @@ int sock_tcp_accept(sock_tcp_queue_t *queue, sock_tcp_t **sock,
}
}
else {
while (cib_avail(&queue->base.conn->acceptmbox.mbox.cib)) {
/* close connections potentially accepted by lwIP */
if (netconn_accept(queue->base.conn, &tmp) == ERR_OK) {
netconn_close(tmp);
netconn_delete(tmp);
}
}
res = -ENOMEM;
}
#if LWIP_SO_RCVTIMEO
netconn_set_recvtimeout(queue->conn, 0);
netconn_set_recvtimeout(queue->base.conn, 0);
#endif
mutex_unlock(&queue->mutex);
return res;
@ -259,7 +268,7 @@ ssize_t sock_tcp_read(sock_tcp_t *sock, void *data, size_t max_len,
bool done = false;
assert((sock != NULL) && (data != NULL) && (max_len > 0));
if (sock->conn == NULL) {
if (sock->base.conn == NULL) {
return -ENOTCONN;
}
if (timeout == 0) {
@ -272,11 +281,11 @@ ssize_t sock_tcp_read(sock_tcp_t *sock, void *data, size_t max_len,
}
#if LWIP_SO_RCVTIMEO
if ((timeout != 0) && (timeout != SOCK_NO_TIMEOUT)) {
netconn_set_recvtimeout(sock->conn, timeout / US_PER_MS);
netconn_set_recvtimeout(sock->base.conn, timeout / US_PER_MS);
}
else
#endif
if ((timeout == 0) && !cib_avail(&sock->conn->recvmbox.mbox.cib)) {
if ((timeout == 0) && !cib_avail(&sock->base.conn->recvmbox.mbox.cib)) {
mutex_unlock(&sock->mutex);
return -EAGAIN;
}
@ -287,7 +296,7 @@ ssize_t sock_tcp_read(sock_tcp_t *sock, void *data, size_t max_len,
}
else {
err_t err;
if ((err = netconn_recv_tcp_pbuf(sock->conn, &buf)) < 0) {
if ((err = netconn_recv_tcp_pbuf(sock->base.conn, &buf)) < 0) {
switch (err) {
case ERR_ABRT:
res = -ECONNABORTED;
@ -343,9 +352,9 @@ ssize_t sock_tcp_read(sock_tcp_t *sock, void *data, size_t max_len,
}
/* unset flags */
#if LWIP_SO_RCVTIMEO
netconn_set_recvtimeout(sock->conn, 0);
netconn_set_recvtimeout(sock->base.conn, 0);
#endif
netconn_set_nonblocking(sock->conn, false);
netconn_set_nonblocking(sock->base.conn, false);
mutex_unlock(&sock->mutex);
return res;
}
@ -358,11 +367,11 @@ ssize_t sock_tcp_write(sock_tcp_t *sock, const void *data, size_t len)
assert(sock != NULL);
assert((len == 0) || (data != NULL)); /* (len != 0) => (data != NULL) */
mutex_lock(&sock->mutex);
if (sock->conn == NULL) {
if (sock->base.conn == NULL) {
mutex_unlock(&sock->mutex);
return -ENOTCONN;
}
conn = sock->conn;
conn = sock->base.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 */
@ -370,4 +379,28 @@ ssize_t sock_tcp_write(sock_tcp_t *sock, const void *data, size_t len)
return res;
}
#ifdef SOCK_HAS_ASYNC
void sock_tcp_set_cb(sock_tcp_t *sock, sock_tcp_cb_t cb)
{
sock->base.async_cb.tcp = cb;
}
void sock_tcp_queue_set_cb(sock_tcp_queue_t *queue, sock_tcp_queue_cb_t cb)
{
queue->base.async_cb.tcp_queue = cb;
}
#ifdef SOCK_HAS_ASYNC_CTX
sock_async_ctx_t *sock_tcp_get_async_ctx(sock_tcp_t *sock)
{
return &sock->base.async_ctx;
}
sock_async_ctx_t *sock_tcp_queue_get_async_ctx(sock_tcp_queue_t *queue)
{
return &queue->base.async_ctx;
}
#endif /* SOCK_HAS_ASYNC_CTX */
#endif /* SOCK_HAS_ASYNC */
/** @} */

View File

@ -37,7 +37,10 @@ int sock_udp_create(sock_udp_t *sock, const sock_udp_ep_t *local,
if ((res = lwip_sock_create(&tmp, (struct _sock_tl_ep *)local,
(struct _sock_tl_ep *)remote, 0, flags,
NETCONN_UDP)) == 0) {
sock->conn = tmp;
sock->base.conn = tmp;
#if IS_ACTIVE(SOCK_HAS_ASYNC)
netconn_set_callback_arg(sock->base.conn, &sock->base);
#endif
}
return res;
}
@ -45,23 +48,23 @@ int sock_udp_create(sock_udp_t *sock, const sock_udp_ep_t *local,
void sock_udp_close(sock_udp_t *sock)
{
assert(sock != NULL);
if (sock->conn != NULL) {
netconn_delete(sock->conn);
sock->conn = NULL;
if (sock->base.conn != NULL) {
netconn_delete(sock->base.conn);
sock->base.conn = NULL;
}
}
int sock_udp_get_local(sock_udp_t *sock, sock_udp_ep_t *ep)
{
assert(sock != NULL);
return (lwip_sock_get_addr(sock->conn, (struct _sock_tl_ep *)ep,
return (lwip_sock_get_addr(sock->base.conn, (struct _sock_tl_ep *)ep,
1)) ? -EADDRNOTAVAIL : 0;
}
int sock_udp_get_remote(sock_udp_t *sock, sock_udp_ep_t *ep)
{
assert(sock != NULL);
return (lwip_sock_get_addr(sock->conn, (struct _sock_tl_ep *)ep,
return (lwip_sock_get_addr(sock->base.conn, (struct _sock_tl_ep *)ep,
0)) ? -ENOTCONN : 0;
}
@ -73,7 +76,7 @@ ssize_t sock_udp_recv(sock_udp_t *sock, void *data, size_t max_len,
int res;
assert((sock != NULL) && (data != NULL) && (max_len > 0));
if ((res = lwip_sock_recv(sock->conn, timeout, &buf)) < 0) {
if ((res = lwip_sock_recv(sock->base.conn, timeout, &buf)) < 0) {
return res;
}
res = buf->p->tot_len;
@ -85,7 +88,7 @@ ssize_t sock_udp_recv(sock_udp_t *sock, void *data, size_t max_len,
/* convert remote */
size_t addr_len;
#if LWIP_IPV6
if (sock->conn->type & NETCONN_TYPE_IPV6) {
if (sock->base.conn->type & NETCONN_TYPE_IPV6) {
addr_len = sizeof(ipv6_addr_t);
remote->family = AF_INET6;
}
@ -128,8 +131,22 @@ ssize_t sock_udp_send(sock_udp_t *sock, const void *data, size_t len,
if ((remote != NULL) && (remote->port == 0)) {
return -EINVAL;
}
return lwip_sock_send((sock) ? sock->conn : NULL, data, len, 0,
return lwip_sock_send((sock) ? sock->base.conn : NULL, data, len, 0,
(struct _sock_tl_ep *)remote, NETCONN_UDP);
}
#ifdef SOCK_HAS_ASYNC
void sock_udp_set_cb(sock_udp_t *sock, sock_udp_cb_t cb)
{
sock->base.async_cb.udp = cb;
}
#ifdef SOCK_HAS_ASYNC_CTX
sock_async_ctx_t *sock_udp_get_async_ctx(sock_udp_t *sock)
{
return &sock->base.async_ctx;
}
#endif /* SOCK_HAS_ASYNC_CTX */
#endif /* SOCK_HAS_ASYNC */
/** @} */

View File

@ -86,7 +86,6 @@ extern "C" {
#define LWIP_IPV6 (0)
#endif /* MODULE_LWIP_IPV6 */
#ifdef MODULE_LWIP_NETIF_PPP
#define PPP_SUPPORT (1)
#else /* MODULE_LWIP_NETIF_PPP */
@ -129,12 +128,20 @@ extern "C" {
#define LWIP_UDPLITE (0)
#endif /* MODULE_LWIP_UDPLITE */
#if defined(MODULE_LWIP_CONN) || defined(MODULE_LWIP_SOCK)
#if defined(MODULE_LWIP_SOCK)
#define LWIP_NETCONN (1)
#else
#define LWIP_NETCONN (0)
#endif
#ifndef TCP_LISTEN_BACKLOG
# if defined(MODULE_LWIP_SOCK_TCP)
# define TCP_LISTEN_BACKLOG (1)
# else
# define TCP_LISTEN_BACKLOG (0)
# endif
#endif /* TCP_LISTEN_BACKLOG */
#define LWIP_SOCKET (0)
#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS

View File

@ -20,11 +20,66 @@
#include "net/af.h"
#include "lwip/api.h"
#ifdef SOCK_HAS_ASYNC
#include "net/sock/async/types.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Forward declaration
* @internal
*/
typedef struct lwip_sock_base lwip_sock_base_t;
#ifdef SOCK_HAS_ASYNC
/**
* @brief Event callback for @ref lwip_sock_base_t
* @internal
*/
typedef void (*lwip_sock_cb_t)(lwip_sock_base_t *sock,
sock_async_flags_t flags);
#endif /* SOCK_HAS_ASYNC */
/**
* @brief Sock base type
* @warning For network stack internal purposes only. Do not access members
* externally.
* @internal
*/
struct lwip_sock_base {
struct netconn *conn; /**< lwIP network connection object */
#ifdef SOCK_HAS_ASYNC
/**
* @brief Asynchronous upper layer callback
*
* @note All have void return value and a (sock pointer, sock_async_flags_t)
* pair, so casting between these function pointers is okay.
*/
union {
lwip_sock_cb_t gen; /**< generic version */
#ifdef MODULE_SOCK_IP
sock_ip_cb_t ip; /**< IP version */
#endif
#ifdef MODULE_SOCK_TCP
sock_tcp_cb_t tcp; /**< TCP version */
/**
* @brief TCP queue version
*/
sock_tcp_queue_cb_t tcp_queue;
#endif
#ifdef MODULE_SOCK_UDP
sock_udp_cb_t udp; /**< UDP version */
#endif
} async_cb;
#ifdef SOCK_HAS_ASYNC_CTX
sock_async_ctx_t async_ctx; /**< asynchronous event context */
#endif /* SOCK_HAS_ASYNC_CTX */
#endif /* SOCK_HAS_ASYNC */
};
/**
* @brief Raw IP sock type
* @warning For network stack internal purposes only. Do not access members
@ -32,7 +87,7 @@ extern "C" {
* @internal
*/
struct sock_ip {
struct netconn *conn; /**< lwIP network connection object */
lwip_sock_base_t base; /**< parent class */
};
/**
@ -42,7 +97,7 @@ struct sock_ip {
* @internal
*/
struct sock_tcp {
struct netconn *conn; /**< lwIP network connection object */
lwip_sock_base_t base; /**< parent class */
struct sock_tcp_queue *queue; /**< Queue the sock might have been generated from */
mutex_t mutex; /**< Mutex to protect the sock */
struct pbuf *last_buf; /**< Last received data */
@ -55,7 +110,7 @@ struct sock_tcp {
* externally.
*/
struct sock_tcp_queue {
struct netconn *conn; /**< lwIP network connection object */
lwip_sock_base_t base; /**< parent class */
struct sock_tcp *array; /**< Allocation array for sock objects to generate */
mutex_t mutex; /**< Mutex to protect the queue */
unsigned short len; /**< Length of the struct sock_tcp_queue::array */
@ -69,7 +124,7 @@ struct sock_tcp_queue {
* @internal
*/
struct sock_udp {
struct netconn *conn; /**< lwIP network connection object */
lwip_sock_base_t base; /**< parent class */
};
#ifdef __cplusplus

View File

@ -0,0 +1,120 @@
From 59d78b78b683c9212949d4950355ea5f424c1da9 Mon Sep 17 00:00:00 2001
From: Simon Goldschmidt <goldsimon@gmx.de>
Date: Sat, 13 Jul 2019 20:46:36 +0200
Subject: [PATCH] netconn: add callback arg storage
This reuses the member 'int socket' by making it a union containing
both int and void pointer.
See bug #56593.
Signed-off-by: Simon Goldschmidt <goldsimon@gmx.de>
Suggested-by: Wilfred <wilfrednilsen@hotmail.com>
(cherry picked from commit 5465fdfd6988354e77dc0e7a6117303d4c87cbd0)
---
src/api/api_msg.c | 4 +---
src/api/sockets.c | 14 +++++++-------
src/include/lwip/api.h | 11 +++++++----
3 files changed, 15 insertions(+), 14 deletions(-)
diff --git a/src/api/api_msg.c b/src/api/api_msg.c
index 39531024..19218de3 100644
--- a/src/api/api_msg.c
+++ b/src/api/api_msg.c
@@ -756,10 +756,8 @@ netconn_alloc(enum netconn_type t, netconn_callback callback)
sys_mbox_set_invalid(&conn->acceptmbox);
#endif
conn->state = NETCONN_NONE;
-#if LWIP_SOCKET
/* initialize socket to -1 since 0 is a valid socket */
- conn->socket = -1;
-#endif /* LWIP_SOCKET */
+ conn->callback_arg.socket = -1;
conn->callback = callback;
#if LWIP_TCP
conn->current_msg = NULL;
diff --git a/src/api/sockets.c b/src/api/sockets.c
index cb7df914..ce12af1e 100644
--- a/src/api/sockets.c
+++ b/src/api/sockets.c
@@ -666,8 +666,8 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
* so nsock->rcvevent is >= 1 here!
*/
SYS_ARCH_PROTECT(lev);
- recvevent = (s16_t)(-1 - newconn->socket);
- newconn->socket = newsock;
+ recvevent = (s16_t)(-1 - newconn->callback_arg.socket);
+ newconn->callback_arg.socket = newsock;
SYS_ARCH_UNPROTECT(lev);
if (newconn->callback) {
@@ -1735,7 +1735,7 @@ lwip_socket(int domain, int type, int protocol)
set_errno(ENFILE);
return -1;
}
- conn->socket = i;
+ conn->callback_arg.socket = i;
done_socket(&sockets[i - LWIP_SOCKET_OFFSET]);
LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
set_errno(0);
@@ -2484,7 +2484,7 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
/* Get socket */
if (conn) {
- s = conn->socket;
+ s = conn->callback_arg.socket;
if (s < 0) {
/* Data comes in right away after an accept, even though
* the server task might not have created a new socket yet.
@@ -2492,16 +2492,16 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
* will use the data later. Note that only receive events
* can happen before the new socket is set up. */
SYS_ARCH_PROTECT(lev);
- if (conn->socket < 0) {
+ if (conn->callback_arg.socket < 0) {
if (evt == NETCONN_EVT_RCVPLUS) {
/* conn->socket is -1 on initialization
lwip_accept adjusts sock->recvevent if conn->socket < -1 */
- conn->socket--;
+ conn->callback_arg.socket--;
}
SYS_ARCH_UNPROTECT(lev);
return;
}
- s = conn->socket;
+ s = conn->callback_arg.socket;
SYS_ARCH_UNPROTECT(lev);
}
diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h
index c2afaf26..d6e8fa1f 100644
--- a/src/include/lwip/api.h
+++ b/src/include/lwip/api.h
@@ -246,10 +246,10 @@ struct netconn {
all threads when closing while threads are waiting. */
int mbox_threads_waiting;
#endif
- /** only used for socket layer */
-#if LWIP_SOCKET
- int socket;
-#endif /* LWIP_SOCKET */
+ union {
+ int socket;
+ void *ptr;
+ } callback_arg;
#if LWIP_SO_SNDTIMEO
/** timeout to wait for sending data (which means enqueueing data for sending
in internal buffers) in milliseconds */
@@ -373,6 +373,9 @@ err_t netconn_err(struct netconn *conn);
#define netconn_clear_flags(conn, clr_flags) do { (conn)->flags = (u8_t)((conn)->flags & (u8_t)(~(clr_flags) & 0xff)); } while(0)
#define netconn_is_flag_set(conn, flag) (((conn)->flags & (flag)) != 0)
+#define netconn_set_callback_arg(conn, arg) do { (conn)->callback_arg.ptr = (arg); } while(0)
+#define netconn_get_callback_arg(conn) ((conn)->callback_arg.ptr)
+
/** Set the blocking status of netconn calls (@todo: write/send is missing) */
#define netconn_set_nonblocking(conn, val) do { if(val) { \
netconn_set_flags(conn, NETCONN_FLAG_NON_BLOCKING); \
--
2.25.1

View File

@ -104,7 +104,7 @@ void sock_tcp_queue_event_init(sock_tcp_queue_t *queue,
event_queue_t *ev_queue,
sock_tcp_queue_cb_t handler)
{
sock_async_ctx_t *ctx = sock_tcp_queue_get_async_ctx(sock);
sock_async_ctx_t *ctx = sock_tcp_queue_get_async_ctx(queue);
_set_ctx(ctx, ev_queue);
ctx->event.cb.tcp_queue = handler;

View File

@ -20,6 +20,8 @@ endif
USEMODULE += lwip lwip_sock_ip lwip_netdev
USEMODULE += lwip_udp lwip_sock_udp
USEMODULE += lwip_tcp lwip_sock_tcp
USEMODULE += lwip_sock_async
USEMODULE += sock_async_event
USEMODULE += shell
USEMODULE += shell_commands
USEMODULE += ps

View File

@ -23,6 +23,7 @@
#include "common.h"
#include "od.h"
#include "net/af.h"
#include "net/sock/async/event.h"
#include "net/sock/ip.h"
#include "shell.h"
#include "thread.h"
@ -43,25 +44,14 @@ static sock_ip_t server_sock;
static char server_stack[THREAD_STACKSIZE_DEFAULT];
static msg_t server_msg_queue[SERVER_MSG_QUEUE_SIZE];
static void *_server_thread(void *args)
static void _ip_recv(sock_ip_t *sock, sock_async_flags_t flags)
{
sock_ip_ep_t server_addr = SOCK_IP_EP_ANY;
uint8_t protocol;
msg_init_queue(server_msg_queue, SERVER_MSG_QUEUE_SIZE);
/* parse protocol */
protocol = atoi(args);
if (sock_ip_create(&server_sock, &server_addr, NULL, protocol, 0) < 0) {
return NULL;
}
server_running = true;
printf("Success: started IP server on protocol %u\n", protocol);
while (1) {
int res;
if (flags & SOCK_ASYNC_MSG_RECV) {
sock_ip_ep_t src;
int res;
if ((res = sock_ip_recv(&server_sock, sock_inbuf, sizeof(sock_inbuf),
SOCK_NO_TIMEOUT, &src)) < 0) {
if ((res = sock_ip_recv(sock, sock_inbuf, sizeof(sock_inbuf),
0, &src)) < 0) {
puts("Error on receive");
}
else if (res == 0) {
@ -82,6 +72,25 @@ static void *_server_thread(void *args)
od_hex_dump(sock_inbuf, res, 0);
}
}
}
static void *_server_thread(void *args)
{
event_queue_t queue;
sock_ip_ep_t server_addr = SOCK_IP_EP_ANY;
uint8_t protocol;
msg_init_queue(server_msg_queue, SERVER_MSG_QUEUE_SIZE);
/* parse protocol */
protocol = atoi(args);
if (sock_ip_create(&server_sock, &server_addr, NULL, protocol, 0) < 0) {
return NULL;
}
server_running = true;
printf("Success: started IP server on protocol %u\n", protocol);
event_queue_init(&queue);
sock_ip_event_init(&server_sock, &queue, _ip_recv);
event_loop(&queue);
return NULL;
}

View File

@ -23,6 +23,7 @@
#include "common.h"
#include "od.h"
#include "net/af.h"
#include "net/sock/async/event.h"
#include "net/sock/tcp.h"
#include "shell.h"
#include "thread.h"
@ -43,6 +44,72 @@ static sock_tcp_t server_sock, client_sock;
static sock_tcp_queue_t server_queue;
static char server_stack[THREAD_STACKSIZE_DEFAULT];
static msg_t server_msg_queue[SERVER_MSG_QUEUE_SIZE];
static char _addr_str[IPV6_ADDR_MAX_STR_LEN];
static event_queue_t _ev_queue;
static void _tcp_recv(sock_tcp_t *sock, sock_async_flags_t flags)
{
sock_tcp_ep_t client;
if (sock_tcp_get_remote(sock, &client) < 0) {
/* socket was disconnected between event firing and this handler */
return;
}
#ifdef MODULE_LWIP_IPV6
ipv6_addr_to_str(_addr_str, (ipv6_addr_t *)&client.addr.ipv6,
sizeof(_addr_str));
#else
ipv4_addr_to_str(_addr_str, (ipv4_addr_t *)&client.addr.ipv4,
sizeof(_addr_str));
#endif
if (flags & SOCK_ASYNC_MSG_RECV) {
int res;
/* we don't use timeouts so all errors should be related to a lost
* connection */
while ((res = sock_tcp_read(sock, sock_inbuf, sizeof(sock_inbuf),
0)) >= 0) {
printf("Received TCP data from client [%s]:%u:\n", _addr_str,
client.port);
if (res > 0) {
od_hex_dump(sock_inbuf, res, 0);
}
else {
puts("(nul)");
}
}
}
if (flags & SOCK_ASYNC_CONN_FIN) {
printf("TCP connection to [%s]:%u reset\n", _addr_str, client.port);
sock_tcp_disconnect(sock);
}
}
static void _tcp_accept(sock_tcp_queue_t *queue, sock_async_flags_t flags)
{
if (flags & SOCK_ASYNC_CONN_RECV) {
sock_tcp_t *sock = NULL;
int res;
if ((res = sock_tcp_accept(queue, &sock, 0)) < 0) {
printf("Error on TCP accept [%d]\n", res);
}
else {
sock_tcp_ep_t client;
sock_tcp_event_init(sock, &_ev_queue, _tcp_recv);
sock_tcp_get_remote(sock, &client);
#ifdef MODULE_LWIP_IPV6
ipv6_addr_to_str(_addr_str, (ipv6_addr_t *)&client.addr.ipv6,
sizeof(_addr_str));
#else
ipv4_addr_to_str(_addr_str, (ipv4_addr_t *)&client.addr.ipv4,
sizeof(_addr_str));
#endif
printf("TCP client [%s]:%u connected\n", _addr_str, client.port);
}
}
}
static void *_server_thread(void *args)
{
@ -61,48 +128,9 @@ static void *_server_thread(void *args)
server_running = true;
printf("Success: started TCP server on port %" PRIu16 "\n",
server_addr.port);
while (1) {
char client_addr[IPV6_ADDR_MAX_STR_LEN];
sock_tcp_t *sock = NULL;
int res;
unsigned client_port;
if ((res = sock_tcp_accept(&server_queue, &sock, SOCK_NO_TIMEOUT)) < 0) {
puts("Error on TCP accept");
continue;
}
else {
sock_tcp_ep_t client;
sock_tcp_get_remote(sock, &client);
#ifdef MODULE_LWIP_IPV6
ipv6_addr_to_str(client_addr, (ipv6_addr_t *)&client.addr.ipv6,
sizeof(client_addr));
#else
ipv4_addr_to_str(client_addr, (ipv4_addr_t *)&client.addr.ipv4,
sizeof(client_addr));
#endif
client_port = client.port;
printf("TCP client [%s]:%u connected\n",
client_addr, client_port);
}
/* we don't use timeouts so all errors should be related to a lost
* connection */
while ((res = sock_tcp_read(sock, sock_inbuf, sizeof(sock_inbuf),
SOCK_NO_TIMEOUT)) >= 0) {
printf("Received TCP data from client [%s]:%u:\n",
client_addr, client_port);
if (res > 0) {
od_hex_dump(sock_inbuf, res, 0);
}
else {
puts("(nul)");
}
}
printf("TCP connection to [%s]:%u reset, starting to accept again\n",
client_addr, client_port);
sock_tcp_disconnect(sock);
}
event_queue_init(&_ev_queue);
sock_tcp_queue_event_init(&server_queue, &_ev_queue, _tcp_accept);
event_loop(&_ev_queue);
return NULL;
}
@ -112,7 +140,7 @@ static int tcp_connect(char *addr_str, char *port_str, char *local_port_str)
uint16_t local_port = 0;
if (client_running) {
puts("Cient already connected");
puts("Client already connected");
}
/* parse destination address */

View File

@ -14,6 +14,7 @@ import subprocess
import time
import types
import pexpect
import socket
DEFAULT_TIMEOUT = 5
@ -268,6 +269,53 @@ def test_tcpv6_send(board_group, application, env=None):
client.expect_exact(u"could not send")
def test_tcpv6_multiconnect(board_group, application, env=None):
if any(b.name != "native" for b in board_group.boards):
# run test only with native
print("SKIP_TEST INFO found non-native board")
return
env_client = os.environ.copy()
if env is not None:
env_client.update(env)
env_client.update(board_group.boards[0].to_env())
env_server = os.environ.copy()
if env is not None:
env_server.update(env)
env_server.update(board_group.boards[1].to_env())
with pexpect.spawnu("make", ["-C", application, "term"], env=env_client,
timeout=DEFAULT_TIMEOUT) as client, \
pexpect.spawnu("make", ["-C", application, "term"], env=env_server,
timeout=DEFAULT_TIMEOUT) as server:
port = random.randint(0x0000, 0xffff)
server_ip = get_ipv6_address(server)
client_ip = get_ipv6_address(client)
try:
connect_addr = socket.getaddrinfo(
"%s%%tapbr0" % server_ip, port)[0][4]
except socket.gaierror as e:
print("SKIP_TEST INFO", e)
return
server.sendline(u"tcp server start %d" % port)
# wait for neighbor discovery to be done
time.sleep(5)
client.sendline(u"tcp connect %s %d" % (server_ip, port))
server.expect(u"TCP client \\[%s\\]:[0-9]+ connected" % client_ip)
with socket.socket(socket.AF_INET6) as sock:
sock.connect(connect_addr)
server.expect(u"Error on TCP accept \\[-[0-9]+\\]")
client.sendline(u"tcp disconnect")
server.expect(u"TCP connection to \\[%s\\]:[0-9]+ reset" % client_ip)
client.sendline(u"tcp connect %s %d" % (server_ip, port))
server.expect(u"TCP client \\[%s\\]:[0-9]+ connected" % client_ip)
client.sendline(u"tcp disconnect")
server.expect(u"TCP connection to \\[%s\\]:[0-9]+ reset" % client_ip)
with socket.socket(socket.AF_INET6) as sock:
sock.connect(connect_addr)
server.expect(u"TCP client \\[[0-9a-f:]+\\]:[0-9]+ connected")
server.expect(u"TCP connection to \\[[0-9a-f:]+\\]:[0-9]+ reset")
def test_triple_send(board_group, application, env=None):
env_sender = os.environ.copy()
if env is not None:
@ -312,4 +360,4 @@ if __name__ == "__main__":
TestStrategy().execute([BoardGroup((Board("native", "tap0"),
Board("native", "tap1")))],
[test_ipv6_send, test_udpv6_send, test_tcpv6_send,
test_triple_send])
test_tcpv6_multiconnect, test_triple_send])

View File

@ -23,6 +23,7 @@
#include "common.h"
#include "od.h"
#include "net/af.h"
#include "net/sock/async/event.h"
#include "net/sock/udp.h"
#include "shell.h"
#include "thread.h"
@ -43,28 +44,14 @@ static sock_udp_t server_sock;
static char server_stack[THREAD_STACKSIZE_DEFAULT];
static msg_t server_msg_queue[SERVER_MSG_QUEUE_SIZE];
static void *_server_thread(void *args)
static void _udp_recv(sock_udp_t *sock, sock_async_flags_t flags)
{
sock_udp_ep_t server_addr = SOCK_IP_EP_ANY;
int res;
msg_init_queue(server_msg_queue, SERVER_MSG_QUEUE_SIZE);
/* parse port */
server_addr.port = atoi(args);
if ((res = sock_udp_create(&server_sock, &server_addr, NULL, 0)) < 0) {
printf("Unable to open UDP server on port %" PRIu16 " (error code %d)\n",
server_addr.port, -res);
return NULL;
}
server_running = true;
printf("Success: started UDP server on port %" PRIu16 "\n",
server_addr.port);
while (1) {
if (flags & SOCK_ASYNC_MSG_RECV) {
sock_udp_ep_t src;
int res;
if ((res = sock_udp_recv(&server_sock, sock_inbuf, sizeof(sock_inbuf),
SOCK_NO_TIMEOUT, &src)) < 0) {
if ((res = sock_udp_recv(sock, sock_inbuf, sizeof(sock_inbuf),
0, &src)) < 0) {
puts("Error on receive");
}
else if (res == 0) {
@ -85,6 +72,28 @@ static void *_server_thread(void *args)
od_hex_dump(sock_inbuf, res, 0);
}
}
}
static void *_server_thread(void *args)
{
event_queue_t queue;
sock_udp_ep_t server_addr = SOCK_IP_EP_ANY;
int res;
msg_init_queue(server_msg_queue, SERVER_MSG_QUEUE_SIZE);
/* parse port */
server_addr.port = atoi(args);
if ((res = sock_udp_create(&server_sock, &server_addr, NULL, 0)) < 0) {
printf("Unable to open UDP server on port %" PRIu16 " (error code %d)\n",
server_addr.port, -res);
return NULL;
}
server_running = true;
printf("Success: started UDP server on port %" PRIu16 "\n",
server_addr.port);
event_queue_init(&queue);
sock_udp_event_init(&server_sock, &queue, _udp_recv);
event_loop(&queue);
return NULL;
}