diff --git a/Makefile.dep b/Makefile.dep index c3301ba5a3..65e843ab63 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -105,6 +105,11 @@ ifneq (,$(filter gnrc_sock_%,$(USEMODULE))) USEMODULE += gnrc_sock endif +ifneq (,$(filter gnrc_sock_async,$(USEMODULE))) + USEMODULE += sock_async + USEMODULE += gnrc_netapi_callbacks +endif + ifneq (,$(filter gnrc_sock_ip,$(USEMODULE))) USEMODULE += sock_ip endif diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index b11af0f939..f8309ad820 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -38,6 +38,7 @@ PSEUDOMODULES += gnrc_sixlowpan_iphc_nhc PSEUDOMODULES += gnrc_sixlowpan_nd_border_router PSEUDOMODULES += gnrc_sixlowpan_router PSEUDOMODULES += gnrc_sixlowpan_router_default +PSEUDOMODULES += gnrc_sock_async PSEUDOMODULES += gnrc_sock_check_reuse PSEUDOMODULES += gnrc_txtsnd PSEUDOMODULES += i2c_scan diff --git a/sys/Makefile.include b/sys/Makefile.include index cde195f739..cb51be94cb 100644 --- a/sys/Makefile.include +++ b/sys/Makefile.include @@ -13,6 +13,10 @@ ifneq (,$(filter gnrc_sock,$(USEMODULE))) endif endif +ifneq (,$(filter gnrc_sock_async,$(USEMODULE))) + CFLAGS += -DSOCK_HAS_ASYNC +endif + ifneq (,$(filter posix_headers,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/sys/posix/include endif diff --git a/sys/net/gnrc/sock/gnrc_sock.c b/sys/net/gnrc/sock/gnrc_sock.c index 6f7bd9a2f2..62c7373433 100644 --- a/sys/net/gnrc/sock/gnrc_sock.c +++ b/sys/net/gnrc/sock/gnrc_sock.c @@ -15,6 +15,7 @@ #include +#include "log.h" #include "net/af.h" #include "net/ipv6/hdr.h" #include "net/gnrc/ipv6.h" @@ -44,10 +45,36 @@ static void _callback_put(void *arg) } #endif +#ifdef SOCK_HAS_ASYNC +static void _netapi_cb(uint16_t cmd, gnrc_pktsnip_t *pkt, void *ctx) +{ + if (cmd == GNRC_NETAPI_MSG_TYPE_RCV) { + msg_t msg = { .type = GNRC_NETAPI_MSG_TYPE_RCV, + .content = { .ptr = pkt } }; + gnrc_sock_reg_t *reg = ctx; + + if (mbox_try_put(®->mbox, &msg) < 1) { + LOG_WARNING("gnrc_sock: dropped message to %p (was full)\n", + (void *)®->mbox); + } + if (reg->async_cb.generic) { + reg->async_cb.generic(reg, SOCK_ASYNC_MSG_RECV); + } + } +} +#endif /* SOCK_HAS_ASYNC */ + void gnrc_sock_create(gnrc_sock_reg_t *reg, gnrc_nettype_t type, uint32_t demux_ctx) { mbox_init(®->mbox, reg->mbox_queue, SOCK_MBOX_SIZE); +#ifdef SOCK_HAS_ASYNC + reg->async_cb.generic = NULL; + reg->netreg_cb.cb = _netapi_cb; + reg->netreg_cb.ctx = reg; + gnrc_netreg_entry_init_cb(®->entry, demux_ctx, ®->netreg_cb); +#else /* SOCK_HAS_ASYNC */ gnrc_netreg_entry_init_mbox(®->entry, demux_ctx, ®->mbox); +#endif /* SOCK_HAS_ASYNC */ gnrc_netreg_register(type, ®->entry); } diff --git a/sys/net/gnrc/sock/include/sock_types.h b/sys/net/gnrc/sock/include/sock_types.h index 82e446d414..59d25aee2d 100644 --- a/sys/net/gnrc/sock/include/sock_types.h +++ b/sys/net/gnrc/sock/include/sock_types.h @@ -29,6 +29,9 @@ #include "net/af.h" #include "net/gnrc.h" #include "net/gnrc/netreg.h" +#ifdef SOCK_HAS_ASYNC +#include "net/sock/async.h" +#endif #include "net/sock/ip.h" #include "net/sock/udp.h" @@ -40,18 +43,54 @@ extern "C" { #define SOCK_MBOX_SIZE (8) /**< Size for gnrc_sock_reg_t::mbox_queue */ #endif +/** + * @brief Forward declaration + * @internal + */ +typedef struct gnrc_sock_reg gnrc_sock_reg_t; + +#ifdef SOCK_HAS_ASYNC +/** + * @brief Event callback for @ref gnrc_sock_reg_t + * @internal + */ +typedef void (*gnrc_sock_reg_cb_t)(gnrc_sock_reg_t *sock, + sock_async_flags_t flags); +#endif /* SOCK_HAS_ASYNC */ + /** * @brief sock @ref net_gnrc_netreg info * @internal */ -typedef struct gnrc_sock_reg { +struct gnrc_sock_reg { #ifdef MODULE_GNRC_SOCK_CHECK_REUSE struct gnrc_sock_reg *next; /**< list-like for internal storage */ #endif gnrc_netreg_entry_t entry; /**< @ref net_gnrc_netreg entry for mbox */ mbox_t mbox; /**< @ref core_mbox target for the sock */ msg_t mbox_queue[SOCK_MBOX_SIZE]; /**< queue for gnrc_sock_reg_t::mbox */ -} gnrc_sock_reg_t; +#ifdef SOCK_HAS_ASYNC + gnrc_netreg_entry_cbd_t netreg_cb; /**< netreg callback */ + /** + * @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 { + gnrc_sock_reg_cb_t generic; /**< generic version */ +#ifdef MODULE_SOCK_IP + sock_ip_cb_t ip; /**< IP version */ +#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 +#endif /* SOCK_HAS_ASYNC */ +}; /** * @brief Raw IP sock type diff --git a/sys/net/gnrc/sock/ip/gnrc_sock_ip.c b/sys/net/gnrc/sock/ip/gnrc_sock_ip.c index 548e0d710f..44719ff777 100644 --- a/sys/net/gnrc/sock/ip/gnrc_sock_ip.c +++ b/sys/net/gnrc/sock/ip/gnrc_sock_ip.c @@ -195,7 +195,26 @@ ssize_t sock_ip_send(sock_ip_t *sock, const void *data, size_t len, if (res <= 0) { return res; } +#ifdef SOCK_HAS_ASYNC + if ((sock != NULL) && (sock->reg.async_cb.ip)) { + sock->reg.async_cb.ip(sock, SOCK_ASYNC_MSG_SENT); + } +#endif /* SOCK_HAS_ASYNC */ return res; } +#ifdef SOCK_HAS_ASYNC +void sock_ip_set_cb(sock_ip_t *sock, sock_ip_cb_t cb) +{ + sock->reg.async_cb.ip = cb; +} + +#ifdef SOCK_HAS_ASYNC_CTX +sock_async_ctx_t *sock_ip_get_async_ctx(sock_ip_t *sock) +{ + return &sock->reg.async_ctx; +} +#endif /* SOCK_HAS_ASYNC_CTX */ +#endif /* SOCK_HAS_ASYNC */ + /** @} */ diff --git a/sys/net/gnrc/sock/udp/gnrc_sock_udp.c b/sys/net/gnrc/sock/udp/gnrc_sock_udp.c index 6268befe2c..72eba92c6a 100644 --- a/sys/net/gnrc/sock/udp/gnrc_sock_udp.c +++ b/sys/net/gnrc/sock/udp/gnrc_sock_udp.c @@ -317,7 +317,26 @@ ssize_t sock_udp_send(sock_udp_t *sock, const void *data, size_t len, if (res > 0) { res -= sizeof(udp_hdr_t); } +#ifdef SOCK_HAS_ASYNC + if ((sock != NULL) && (sock->reg.async_cb.udp)) { + sock->reg.async_cb.udp(sock, SOCK_ASYNC_MSG_SENT); + } +#endif /* SOCK_HAS_ASYNC */ return res; } +#ifdef SOCK_HAS_ASYNC +void sock_udp_set_cb(sock_udp_t *sock, sock_udp_cb_t cb) +{ + sock->reg.async_cb.udp = cb; +} + +#ifdef SOCK_HAS_ASYNC_CTX +sock_async_ctx_t *sock_udp_get_async_ctx(sock_udp_t *sock) +{ + return &sock->reg.async_ctx; +} +#endif /* SOCK_HAS_ASYNC_CTX */ +#endif /* SOCK_HAS_ASYNC */ + /** @} */