From 1ed34774c8d89bf6cee7dbd41ca4fe616558689c Mon Sep 17 00:00:00 2001 From: goldsimon Date: Fri, 21 Dec 2007 16:47:56 +0000 Subject: [PATCH] tcp.h, opt.h, api.h, api_msg.h, tcp.c, tcp_in.c, api_lib.c, api_msg.c, sockets.c, init.c: task #7252: Implement TCP listen backlog: Warning: raw API applications have to call 'tcp_accepted(pcb)' in their accept callback to keep accepting new connections. --- CHANGELOG | 6 ++++++ src/api/api_lib.c | 28 +++++++++++++++++++++++----- src/api/api_msg.c | 12 +++++++++++- src/api/sockets.c | 8 ++++---- src/core/init.c | 4 ++++ src/core/tcp.c | 4 ++++ src/core/tcp_in.c | 8 ++++++++ src/include/lwip/api.h | 3 ++- src/include/lwip/api_msg.h | 5 +++++ src/include/lwip/opt.h | 17 +++++++++++++++++ src/include/lwip/tcp.h | 9 +++++++++ 11 files changed, 93 insertions(+), 11 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f89222ac..15f7dd21 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,6 +19,12 @@ HISTORY ++ New features: + 2007-12-21 Frédéric Bernon, Simon Goldschmidt, Jonathan Larmour + * tcp.h, opt.h, api.h, api_msg.h, tcp.c, tcp_in.c, api_lib.c, api_msg.c, + sockets.c, init.c: task #7252: Implement TCP listen backlog: Warning: raw API + applications have to call 'tcp_accepted(pcb)' in their accept callback to + keep accepting new connections. + 2007-12-13 Frédéric Bernon * api_msg.c, err.h, err.c, sockets.c, dns.c, dns.h: replace "enum dns_result" by err_t type. Add a new err_t code "ERR_INPROGRESS". diff --git a/src/api/api_lib.c b/src/api/api_lib.c index bc6acd4f..e109ceca 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -261,16 +261,23 @@ netconn_disconnect(struct netconn *conn) * Set a TCP netconn into listen mode * * @param conn the tcp netconn to set to listen mode + * @param backlog the listen backlog (0 = max), only used if LWIP_LISTEN_BACKLOG==1 * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns * don't return any error (yet?)) */ err_t -netconn_listen(struct netconn *conn) +netconn_listen_with_backlog(struct netconn *conn, u8_t backlog) { struct api_msg msg; + /* This does no harm. If LWIP_LISTEN_BACKLOG is off, backlog is unused. */ + LWIP_UNUSED_ARG(backlog); + LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;); +#if LWIP_LISTEN_BACKLOG + msg.msg.msg.lb.backlog = backlog; +#endif /* LWIP_LISTEN_BACKLOG */ msg.function = do_listen; msg.msg.conn = conn; TCPIP_APIMSG(&msg); @@ -292,15 +299,26 @@ netconn_accept(struct netconn *conn) LWIP_ERROR("netconn_accept: invalid acceptmbox", (conn->acceptmbox != SYS_MBOX_NULL), return NULL;); #if LWIP_SO_RCVTIMEO - if (sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, conn->recv_timeout)==SYS_ARCH_TIMEOUT) { + if (sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { newconn = NULL; - } + } else #else sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, 0); #endif /* LWIP_SO_RCVTIMEO*/ + { + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); +#if LWIP_LISTEN_BACKLOG + if (newconn != NULL) { + /* Let the stack know that we have accepted the connection. */ + struct api_msg msg; + msg.function = do_recv; + msg.msg.conn = conn; + TCPIP_APIMSG(&msg); + } +#endif /* LWIP_LISTEN_BACKLOG */ + } return newconn; } diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 373c9989..e44da527 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -735,6 +735,9 @@ do_listen(struct api_msg_msg *msg) if (msg->conn->err == ERR_OK) { msg->conn->state = NETCONN_LISTEN; msg->conn->pcb.tcp = lpcb; +#if LWIP_LISTEN_BACKLOG + tcp_backlog(lpcb, msg->msg.lb.backlog); +#endif /* LWIP_LISTEN_BACKLOG */ tcp_arg(msg->conn->pcb.tcp, msg->conn); tcp_accept(msg->conn->pcb.tcp, accept_function); } @@ -800,7 +803,14 @@ do_recv(struct api_msg_msg *msg) if (!ERR_IS_FATAL(msg->conn->err)) { if (msg->conn->pcb.tcp != NULL) { if (msg->conn->type == NETCONN_TCP) { - tcp_recved(msg->conn->pcb.tcp, msg->msg.r.len); +#if LWIP_LISTEN_BACKLOG + if (msg->conn->pcb.tcp->state == LISTEN) { + tcp_accepted(msg->conn->pcb.tcp); + } else +#endif /* LWIP_LISTEN_BACKLOG */ + { + tcp_recved(msg->conn->pcb.tcp, msg->msg.r.len); + } } } } diff --git a/src/api/sockets.c b/src/api/sockets.c index cea473c6..47f7074f 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -430,15 +430,15 @@ lwip_listen(int s, int backlog) struct lwip_socket *sock; err_t err; - /* This does no harm. If debugging is off, backlog is unused. */ - LWIP_UNUSED_ARG(backlog); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); + LWIP_ASSERT("backlog must be between 0 and 255", backlog > 0); + LWIP_ASSERT("backlog must be between 0 and 255", backlog <= 0xff); + sock = get_socket(s); if (!sock) return -1; - err = netconn_listen(sock->conn); + err = netconn_listen_with_backlog(sock->conn, backlog); if (err != ERR_OK) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); diff --git a/src/core/init.c b/src/core/init.c index b8b8aad3..d15ef89d 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -152,6 +152,10 @@ #if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS) #error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h" #endif +#if (LWIP_DEFAULT_LISTEN_BACKLOG < 0) || (LWIP_DEFAULT_LISTEN_BACKLOG > 255) + #error "LWIP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t" +#endif + /* Compile-time checks for deprecated options. */ diff --git a/src/core/tcp.c b/src/core/tcp.c index 2f47cdc0..a0de5a32 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -368,6 +368,10 @@ tcp_listen(struct tcp_pcb *pcb) #if LWIP_CALLBACK_API lpcb->accept = tcp_accept_null; #endif /* LWIP_CALLBACK_API */ +#if LWIP_LISTEN_BACKLOG + lpcb->accepts_pending = 0; + lpcb->backlog = LWIP_DEFAULT_LISTEN_BACKLOG; +#endif /* LWIP_LISTEN_BACKLOG */ TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb); return (struct tcp_pcb *)lpcb; } diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 54e913ba..489624c9 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -381,6 +381,11 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) tcphdr->dest, tcphdr->src); } else if (flags & TCP_SYN) { LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); +#if LWIP_LISTEN_BACKLOG + if (pcb->accepts_pending >= pcb->backlog) { + return ERR_ABRT; + } +#endif /* LWIP_LISTEN_BACKLOG */ npcb = tcp_alloc(pcb->prio); /* If a new PCB could not be created (probably due to lack of memory), we don't do anything, but rely on the sender will retransmit the @@ -390,6 +395,9 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) TCP_STATS_INC(tcp.memerr); return ERR_MEM; } +#if LWIP_LISTEN_BACKLOG + pcb->accepts_pending++; +#endif /* LWIP_LISTEN_BACKLOG */ /* Set up the new PCB. */ ip_addr_set(&(npcb->local_ip), &(iphdr->dest)); npcb->local_port = pcb->local_port; diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h index 74731dfc..225339b8 100644 --- a/src/include/lwip/api.h +++ b/src/include/lwip/api.h @@ -179,7 +179,8 @@ err_t netconn_connect (struct netconn *conn, struct ip_addr *addr, u16_t port); err_t netconn_disconnect (struct netconn *conn); -err_t netconn_listen (struct netconn *conn); +err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog); +#define netconn_listen(conn) netconn_listen_with_backlog(conn, LWIP_DEFAULT_LISTEN_BACKLOG); struct netconn * netconn_accept (struct netconn *conn); struct netbuf * netconn_recv (struct netconn *conn); err_t netconn_sendto (struct netconn *conn, diff --git a/src/include/lwip/api_msg.h b/src/include/lwip/api_msg.h index 446a8264..252c219a 100644 --- a/src/include/lwip/api_msg.h +++ b/src/include/lwip/api_msg.h @@ -93,6 +93,11 @@ struct api_msg_msg { enum netconn_igmp join_or_leave; } jl; #endif /* LWIP_IGMP */ +#if LWIP_LISTEN_BACKLOG + struct { + u8_t backlog; + } lb; +#endif /* LWIP_LISTEN_BACKLOG */ } msg; }; diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 539358ba..19a9c342 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -728,6 +728,23 @@ #define LWIP_CALLBACK_API 0 #endif +/** + * LWIP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. + */ +#ifndef LWIP_LISTEN_BACKLOG +#define LWIP_LISTEN_BACKLOG 1 +#endif + +/** + * The maximum allowed backlog for TCP listen netconns. + * This backlog is used unless another is explicitly specified. + * 0xff is the maximum (u8_t). + */ +#ifndef LWIP_DEFAULT_LISTEN_BACKLOG +#define LWIP_DEFAULT_LISTEN_BACKLOG 0xff +#endif + + /* ---------------------------------- ---------- Pbuf options ---------- diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h index ebe7ed3d..50f1459e 100644 --- a/src/include/lwip/tcp.h +++ b/src/include/lwip/tcp.h @@ -79,6 +79,11 @@ void tcp_err (struct tcp_pcb *pcb, #define tcp_mss(pcb) ((pcb)->mss) #define tcp_sndbuf(pcb) ((pcb)->snd_buf) +#if LWIP_LISTEN_BACKLOG +#define tcp_accepted(pcb) (((struct tcp_pcb_listen *)(pcb))->accepts_pending--) +#define tcp_backlog(pcb, bklog) (((struct tcp_pcb_listen *)(pcb))->backlog = bklog) +#endif /* LWIP_LISTEN_BACKLOG */ + void tcp_recved (struct tcp_pcb *pcb, u16_t len); err_t tcp_bind (struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port); @@ -412,6 +417,10 @@ struct tcp_pcb_listen { */ err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err); #endif /* LWIP_CALLBACK_API */ +#if LWIP_LISTEN_BACKLOG + u8_t backlog; + u8_t accepts_pending; +#endif /* LWIP_LISTEN_BACKLOG */ }; #if LWIP_EVENT_API