From 98fc82fa7128fabc9f592447cc1d60269b76ffa8 Mon Sep 17 00:00:00 2001 From: sg Date: Sat, 31 Dec 2016 15:36:31 +0100 Subject: [PATCH] added function tcp_listen_with_backlog_and_err() to get the error reason when listening fails (bug #49861) --- CHANGELOG | 6 +++++- src/api/api_msg.c | 15 ++++++++------ src/core/tcp.c | 44 ++++++++++++++++++++++++++++++++++++------ src/include/lwip/tcp.h | 1 + 4 files changed, 53 insertions(+), 13 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4371f02e..051f7ae4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,8 +6,12 @@ HISTORY ++ New features: + 2016-12-31: Simon Goldschmidt + * tcp.h/.c: added function tcp_listen_with_backlog_and_err() to get the error + reason when listening fails (bug #49861) + 2016-12-14: Jan Breuer: - opt.h, ndc.h/.c: add support for RDNSS option (as per RFC 6106) + * opt.h, ndc.h/.c: add support for RDNSS option (as per RFC 6106) 2016-12-14: David van Moolenbroek * opt.h, nd6.c: Added LWIP_HOOK_ND6_GET_GW() diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 10092285..4927ee50 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -1307,6 +1307,13 @@ lwip_netconn_do_listen(void *m) /* connection is not closed, cannot listen */ msg->err = ERR_VAL; } else { + err_t err; + u8_t backlog; +#if TCP_LISTEN_BACKLOG + backlog = msg->msg.lb.backlog; +#else /* TCP_LISTEN_BACKLOG */ + backlog = TCP_DEFAULT_LISTEN_BACKLOG; +#endif /* TCP_LISTEN_BACKLOG */ #if LWIP_IPV4 && LWIP_IPV6 /* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY, * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen @@ -1319,15 +1326,11 @@ lwip_netconn_do_listen(void *m) } #endif /* LWIP_IPV4 && LWIP_IPV6 */ -#if TCP_LISTEN_BACKLOG - lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog); -#else /* TCP_LISTEN_BACKLOG */ - lpcb = tcp_listen(msg->conn->pcb.tcp); -#endif /* TCP_LISTEN_BACKLOG */ + lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err); if (lpcb == NULL) { /* in this case, the old pcb is still allocated */ - msg->err = ERR_MEM; + msg->err = err; } else { /* delete the recvmbox and allocate the acceptmbox */ if (sys_mbox_valid(&msg->conn->recvmbox)) { diff --git a/src/core/tcp.c b/src/core/tcp.c index f72597bb..63e44457 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -636,19 +636,44 @@ tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err) * * @note The original tcp_pcb is freed. This function therefore has to be * called like this: - * tpcb = tcp_listen(tpcb); + * tpcb = tcp_listen_with_backlog(tpcb, backlog); */ struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) { - struct tcp_pcb_listen *lpcb; + return tcp_listen_with_backlog_and_err(pcb, backlog, NULL); +} + +/** + * @ingroup tcp_raw + * Set the state of the connection to be LISTEN, which means that it + * is able to accept incoming connections. The protocol control block + * is reallocated in order to consume less memory. Setting the + * connection to LISTEN is an irreversible process. + * + * @param pcb the original tcp_pcb + * @param backlog the incoming connections queue limit + * @param err when NULL is returned, this contains the error reason + * @return tcp_pcb used for listening, consumes less memory. + * + * @note The original tcp_pcb is freed. This function therefore has to be + * called like this: + * tpcb = tcp_listen_with_backlog_and_err(tpcb, backlog, &err); + */ +struct tcp_pcb * +tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err) +{ + struct tcp_pcb_listen *lpcb = NULL; + err_t res; LWIP_UNUSED_ARG(backlog); - LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, return NULL); + LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, res = ERR_CLSD; goto done); /* already listening? */ if (pcb->state == LISTEN) { - return pcb; + lpcb = (struct tcp_pcb_listen*)pcb; + res = ERR_ALREADY; + goto done; } #if SO_REUSE if (ip_get_option(pcb, SOF_REUSEADDR)) { @@ -659,14 +684,16 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) if ((lpcb->local_port == pcb->local_port) && ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) { /* this address/port is already used */ - return NULL; + res = ERR_USE; + goto done; } } } #endif /* SO_REUSE */ lpcb = (struct tcp_pcb_listen *)memp_malloc(MEMP_TCP_PCB_LISTEN); if (lpcb == NULL) { - return NULL; + res = ERR_MEM; + goto done; } lpcb->callback_arg = pcb->callback_arg; lpcb->local_port = pcb->local_port; @@ -691,6 +718,11 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) tcp_backlog_set(lpcb, backlog); #endif /* TCP_LISTEN_BACKLOG */ TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb); + res = ERR_OK; +done: + if (err != NULL) { + *err = res; + } return (struct tcp_pcb *)lpcb; } diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h index 35584b45..3fd44678 100644 --- a/src/include/lwip/tcp.h +++ b/src/include/lwip/tcp.h @@ -387,6 +387,7 @@ err_t tcp_bind (struct tcp_pcb *pcb, const ip_addr_t *ipaddr, err_t tcp_connect (struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, tcp_connected_fn connected); +struct tcp_pcb * tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err); struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog); /** @ingroup tcp_raw */ #define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG)