From 5c3bb19923638b216f229e837657e3506d34df63 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Thu, 2 Mar 2017 20:38:11 +0100 Subject: [PATCH] added nonblocking accept/recv to netconn API (task #14396) (also added netconn_recv_udp_raw_netbuf_flags() and netconn_recv_tcp_pbuf_flags() to pass socket-like flags to nonblock for one call only) --- CHANGELOG | 3 ++ src/api/api_lib.c | 114 +++++++++++++++++++++++++++++++++-------- src/include/lwip/api.h | 2 + 3 files changed, 97 insertions(+), 22 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ae69d00f..566c33bf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,9 @@ HISTORY ++ New features: + 2017-03-02: Simon Goldschmidt + * netconn: added nonblocking accept/recv to netconn API (task #14396) + 2017-02-28: Simon Goldschmidt * Added LWIP_SINGLE_NETIF for small targets with only one netif diff --git a/src/api/api_lib.c b/src/api/api_lib.c index e929e532..5f4216bc 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -413,16 +413,25 @@ netconn_accept(struct netconn *conn, struct netconn **new_conn) API_MSG_VAR_ALLOC(msg); #endif /* TCP_LISTEN_BACKLOG */ -#if LWIP_SO_RCVTIMEO - if (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { + if (netconn_is_nonblocking(conn)) { + if (sys_arch_mbox_tryfetch(&conn->acceptmbox, &accept_ptr) == SYS_ARCH_TIMEOUT) { #if TCP_LISTEN_BACKLOG - API_MSG_VAR_FREE(msg); + API_MSG_VAR_FREE(msg); #endif /* TCP_LISTEN_BACKLOG */ - return ERR_TIMEOUT; - } + return ERR_WOULDBLOCK; + } + } else { +#if LWIP_SO_RCVTIMEO + if (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { +#if TCP_LISTEN_BACKLOG + API_MSG_VAR_FREE(msg); +#endif /* TCP_LISTEN_BACKLOG */ + return ERR_TIMEOUT; + } #else - sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0); + sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0); #endif /* LWIP_SO_RCVTIMEO*/ + } newconn = (struct netconn *)accept_ptr; /* Register event with callback */ API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); @@ -467,15 +476,21 @@ netconn_accept(struct netconn *conn, struct netconn **new_conn) /** * @ingroup netconn_common * Receive data: actual implementation that doesn't care whether pbuf or netbuf - * is received + * is received (this is internal, it's just here for describing common errors) * * @param conn the netconn from which to receive data * @param new_buf pointer where a new pbuf/netbuf is stored when received data + * @param apiflags flags that control function behaviour. For now only: + * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data * @return ERR_OK if data has been received, an error code otherwise (timeout, * memory error or another error) + * ERR_CONN if not connected + * ERR_CLSD if TCP connection has been closed + * ERR_WOULDBLOCK if the netconn is nonblocking but would block to wait for data + * ERR_TIMEOUT if the netconn has a receive timeout and no data was received */ static err_t -netconn_recv_data(struct netconn *conn, void **new_buf) +netconn_recv_data(struct netconn *conn, void **new_buf, u8_t apiflags) { void *buf = NULL; u16_t len; @@ -520,21 +535,35 @@ netconn_recv_data(struct netconn *conn, void **new_buf) } #endif /* LWIP_TCP */ -#if LWIP_SO_RCVTIMEO - if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { + if (netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK)) { + if (sys_arch_mbox_tryfetch(&conn->recvmbox, &buf) == SYS_ARCH_TIMEOUT) { #if LWIP_TCP #if (LWIP_UDP || LWIP_RAW) - if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) + if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) #endif /* (LWIP_UDP || LWIP_RAW) */ - { - API_MSG_VAR_FREE(msg); - } + { + API_MSG_VAR_FREE(msg); + } #endif /* LWIP_TCP */ - return ERR_TIMEOUT; - } + return ERR_WOULDBLOCK; + } + } else { +#if LWIP_SO_RCVTIMEO + if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { +#if LWIP_TCP +#if (LWIP_UDP || LWIP_RAW) + if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) +#endif /* (LWIP_UDP || LWIP_RAW) */ + { + API_MSG_VAR_FREE(msg); + } +#endif /* LWIP_TCP */ + return ERR_TIMEOUT; + } #else - sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0); + sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0); #endif /* LWIP_SO_RCVTIMEO*/ + } #if LWIP_TCP #if (LWIP_UDP || LWIP_RAW) @@ -600,7 +629,7 @@ netconn_recv_data(struct netconn *conn, void **new_buf) * @param conn the netconn from which to receive data * @param new_buf pointer where a new pbuf is stored when received data * @return ERR_OK if data has been received, an error code otherwise (timeout, - * memory error or another error) + * memory error or another error, @see netconn_recv_data) * ERR_ARG if conn is not a TCP netconn */ err_t @@ -609,7 +638,28 @@ netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf) LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) && NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); - return netconn_recv_data(conn, (void **)new_buf); + return netconn_recv_data(conn, (void **)new_buf, 0); +} + +/** + * @ingroup netconn_tcp + * Receive data (in form of a pbuf) from a TCP netconn + * + * @param conn the netconn from which to receive data + * @param new_buf pointer where a new pbuf is stored when received data + * @param apiflags flags that control function behaviour. For now only: + * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data + * @return ERR_OK if data has been received, an error code otherwise (timeout, + * memory error or another error, @see netconn_recv_data) + * ERR_ARG if conn is not a TCP netconn + */ +err_t +netconn_recv_tcp_pbuf_flags(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags) +{ + LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) && + NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); + + return netconn_recv_data(conn, (void **)new_buf, apiflags); } /** @@ -627,7 +677,27 @@ netconn_recv_udp_raw_netbuf(struct netconn *conn, struct netbuf **new_buf) LWIP_ERROR("netconn_recv_udp_raw_netbuf: invalid conn", (conn != NULL) && NETCONNTYPE_GROUP(netconn_type(conn)) != NETCONN_TCP, return ERR_ARG;); - return netconn_recv_data(conn, (void **)new_buf); + return netconn_recv_data(conn, (void **)new_buf, 0); +} + +/** + * Receive data (in form of a netbuf) from a UDP or RAW netconn + * + * @param conn the netconn from which to receive data + * @param new_buf pointer where a new netbuf is stored when received data + * @param apiflags flags that control function behaviour. For now only: + * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data + * @return ERR_OK if data has been received, an error code otherwise (timeout, + * memory error or another error) + * ERR_ARG if conn is not a UDP/RAW netconn + */ +err_t +netconn_recv_udp_raw_netbuf_flags(struct netconn *conn, struct netbuf **new_buf, u8_t apiflags) +{ + LWIP_ERROR("netconn_recv_udp_raw_netbuf: invalid conn", (conn != NULL) && + NETCONNTYPE_GROUP(netconn_type(conn)) != NETCONN_TCP, return ERR_ARG;); + + return netconn_recv_data(conn, (void **)new_buf, apiflags); } /** @@ -664,7 +734,7 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf) return ERR_MEM; } - err = netconn_recv_data(conn, (void **)&p); + err = netconn_recv_data(conn, (void **)&p, 0); if (err != ERR_OK) { memp_free(MEMP_NETBUF, buf); return err; @@ -685,7 +755,7 @@ netconn_recv(struct netconn *conn, struct netbuf **new_buf) #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ { #if (LWIP_UDP || LWIP_RAW) - return netconn_recv_data(conn, (void **)new_buf); + return netconn_recv_data(conn, (void **)new_buf, 0); #endif /* (LWIP_UDP || LWIP_RAW) */ } } diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h index 23aa774e..2510d403 100644 --- a/src/include/lwip/api.h +++ b/src/include/lwip/api.h @@ -311,7 +311,9 @@ err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog); err_t netconn_accept(struct netconn *conn, struct netconn **new_conn); err_t netconn_recv(struct netconn *conn, struct netbuf **new_buf); err_t netconn_recv_udp_raw_netbuf(struct netconn *conn, struct netbuf **new_buf); +err_t netconn_recv_udp_raw_netbuf_flags(struct netconn *conn, struct netbuf **new_buf, u8_t apiflags); err_t netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf); +err_t netconn_recv_tcp_pbuf_flags(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags); err_t netconn_sendto(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port); err_t netconn_send(struct netconn *conn, struct netbuf *buf);