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.

This commit is contained in:
goldsimon 2007-12-21 16:47:56 +00:00
parent 48e62e25e9
commit 1ed34774c8
11 changed files with 93 additions and 11 deletions

View File

@ -19,6 +19,12 @@ HISTORY
++ New features: ++ 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 2007-12-13 Frédéric Bernon
* api_msg.c, err.h, err.c, sockets.c, dns.c, dns.h: replace "enum dns_result" * 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". by err_t type. Add a new err_t code "ERR_INPROGRESS".

View File

@ -261,16 +261,23 @@ netconn_disconnect(struct netconn *conn)
* Set a TCP netconn into listen mode * Set a TCP netconn into listen mode
* *
* @param conn the tcp netconn to set to 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 * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns
* don't return any error (yet?)) * don't return any error (yet?))
*/ */
err_t err_t
netconn_listen(struct netconn *conn) netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
{ {
struct api_msg msg; 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;); 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.function = do_listen;
msg.msg.conn = conn; msg.msg.conn = conn;
TCPIP_APIMSG(&msg); 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;); LWIP_ERROR("netconn_accept: invalid acceptmbox", (conn->acceptmbox != SYS_MBOX_NULL), return NULL;);
#if LWIP_SO_RCVTIMEO #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; newconn = NULL;
} } else
#else #else
sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, 0); sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, 0);
#endif /* LWIP_SO_RCVTIMEO*/ #endif /* LWIP_SO_RCVTIMEO*/
{
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
/* Register event with callback */ #if LWIP_LISTEN_BACKLOG
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); 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; return newconn;
} }

View File

@ -735,6 +735,9 @@ do_listen(struct api_msg_msg *msg)
if (msg->conn->err == ERR_OK) { if (msg->conn->err == ERR_OK) {
msg->conn->state = NETCONN_LISTEN; msg->conn->state = NETCONN_LISTEN;
msg->conn->pcb.tcp = lpcb; 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_arg(msg->conn->pcb.tcp, msg->conn);
tcp_accept(msg->conn->pcb.tcp, accept_function); 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 (!ERR_IS_FATAL(msg->conn->err)) {
if (msg->conn->pcb.tcp != NULL) { if (msg->conn->pcb.tcp != NULL) {
if (msg->conn->type == NETCONN_TCP) { 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);
}
} }
} }
} }

View File

@ -430,15 +430,15 @@ lwip_listen(int s, int backlog)
struct lwip_socket *sock; struct lwip_socket *sock;
err_t err; 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_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); sock = get_socket(s);
if (!sock) if (!sock)
return -1; return -1;
err = netconn_listen(sock->conn); err = netconn_listen_with_backlog(sock->conn, backlog);
if (err != ERR_OK) { if (err != ERR_OK) {
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));

View File

@ -152,6 +152,10 @@
#if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS) #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" #error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h"
#endif #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. /* Compile-time checks for deprecated options.
*/ */

View File

@ -368,6 +368,10 @@ tcp_listen(struct tcp_pcb *pcb)
#if LWIP_CALLBACK_API #if LWIP_CALLBACK_API
lpcb->accept = tcp_accept_null; lpcb->accept = tcp_accept_null;
#endif /* LWIP_CALLBACK_API */ #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); TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb);
return (struct tcp_pcb *)lpcb; return (struct tcp_pcb *)lpcb;
} }

View File

@ -381,6 +381,11 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
tcphdr->dest, tcphdr->src); tcphdr->dest, tcphdr->src);
} else if (flags & TCP_SYN) { } else if (flags & TCP_SYN) {
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); 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); npcb = tcp_alloc(pcb->prio);
/* If a new PCB could not be created (probably due to lack of memory), /* 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 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); TCP_STATS_INC(tcp.memerr);
return ERR_MEM; return ERR_MEM;
} }
#if LWIP_LISTEN_BACKLOG
pcb->accepts_pending++;
#endif /* LWIP_LISTEN_BACKLOG */
/* Set up the new PCB. */ /* Set up the new PCB. */
ip_addr_set(&(npcb->local_ip), &(iphdr->dest)); ip_addr_set(&(npcb->local_ip), &(iphdr->dest));
npcb->local_port = pcb->local_port; npcb->local_port = pcb->local_port;

View File

@ -179,7 +179,8 @@ err_t netconn_connect (struct netconn *conn,
struct ip_addr *addr, struct ip_addr *addr,
u16_t port); u16_t port);
err_t netconn_disconnect (struct netconn *conn); 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 netconn * netconn_accept (struct netconn *conn);
struct netbuf * netconn_recv (struct netconn *conn); struct netbuf * netconn_recv (struct netconn *conn);
err_t netconn_sendto (struct netconn *conn, err_t netconn_sendto (struct netconn *conn,

View File

@ -93,6 +93,11 @@ struct api_msg_msg {
enum netconn_igmp join_or_leave; enum netconn_igmp join_or_leave;
} jl; } jl;
#endif /* LWIP_IGMP */ #endif /* LWIP_IGMP */
#if LWIP_LISTEN_BACKLOG
struct {
u8_t backlog;
} lb;
#endif /* LWIP_LISTEN_BACKLOG */
} msg; } msg;
}; };

View File

@ -728,6 +728,23 @@
#define LWIP_CALLBACK_API 0 #define LWIP_CALLBACK_API 0
#endif #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 ---------- ---------- Pbuf options ----------

View File

@ -79,6 +79,11 @@ void tcp_err (struct tcp_pcb *pcb,
#define tcp_mss(pcb) ((pcb)->mss) #define tcp_mss(pcb) ((pcb)->mss)
#define tcp_sndbuf(pcb) ((pcb)->snd_buf) #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); void tcp_recved (struct tcp_pcb *pcb, u16_t len);
err_t tcp_bind (struct tcp_pcb *pcb, struct ip_addr *ipaddr, err_t tcp_bind (struct tcp_pcb *pcb, struct ip_addr *ipaddr,
u16_t port); u16_t port);
@ -412,6 +417,10 @@ struct tcp_pcb_listen {
*/ */
err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err); err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err);
#endif /* LWIP_CALLBACK_API */ #endif /* LWIP_CALLBACK_API */
#if LWIP_LISTEN_BACKLOG
u8_t backlog;
u8_t accepts_pending;
#endif /* LWIP_LISTEN_BACKLOG */
}; };
#if LWIP_EVENT_API #if LWIP_EVENT_API