From 7518acf63424d9345cca5316892d0a511caf3137 Mon Sep 17 00:00:00 2001 From: fbernon Date: Mon, 14 Jan 2008 21:07:08 +0000 Subject: [PATCH] rawapi.txt, api_msg.c, tcp.c, tcp_in.c, tcp.h: changes for task #7675 "Enable to refuse data on a TCP_EVENT_RECV call". Important, behavior changes for the tcp_recv callback (see rawapi.txt). --- CHANGELOG | 5 +++++ doc/rawapi.txt | 5 ++++- src/api/api_msg.c | 7 ++++--- src/core/tcp.c | 29 +++++++++++++++++++++++------ src/core/tcp_in.c | 27 ++++++++++++++++++++++++++- src/include/lwip/tcp.h | 3 +++ 6 files changed, 65 insertions(+), 11 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4b0ea05c..ca190ea8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,6 +19,11 @@ HISTORY ++ New features: + 2008-01-14 Frédéric Bernon + * rawapi.txt, api_msg.c, tcp.c, tcp_in.c, tcp.h: changes for task #7675 "Enable + to refuse data on a TCP_EVENT_RECV call". Important, behavior changes for the + tcp_recv callback (see rawapi.txt). + 2008-01-14 Frédéric Bernon, Marc Chaland * ip.c: Integrate patch #6369" ip_input : checking before realloc". diff --git a/doc/rawapi.txt b/doc/rawapi.txt index 93c0e862..8213445e 100644 --- a/doc/rawapi.txt +++ b/doc/rawapi.txt @@ -188,7 +188,10 @@ window. Sets the callback function that will be called when new data arrives. The callback function will be passed a NULL pbuf to - indicate that the remote host has closed the connection. + indicate that the remote host has closed the connection. If + there are no errors and the callback function is to return + ERR_OK, then it must free the pbuf. Otherwise, it must not + free the pbuf so that lwIP core code can store it. - void tcp_recved(struct tcp_pcb *pcb, u16_t len) diff --git a/src/api/api_msg.c b/src/api/api_msg.c index ccb4c0dd..3464d071 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -165,7 +165,7 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, #if LWIP_TCP /** * Receive callback function for TCP netconns. - * Posts the packet to conn->recvmbox or deletes it on memory error. + * Posts the packet to conn->recvmbox, but doesn't delete it on errors. * * @see tcp.h (struct tcp_pcb.recv) for parameters and return value */ @@ -182,7 +182,6 @@ recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb); if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) { - pbuf_free(p); return ERR_VAL; } @@ -195,7 +194,9 @@ recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) } /* Register event with callback */ API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); - sys_mbox_post(conn->recvmbox, p); + if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) { + return ERR_MEM; + } return ERR_OK; } diff --git a/src/core/tcp.c b/src/core/tcp.c index 24ea5e70..531b26d5 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -770,7 +770,8 @@ tcp_slowtmr(void) } /** - * Is called every TCP_FAST_INTERVAL (250 ms) and sends delayed ACKs. + * Is called every TCP_FAST_INTERVAL (250 ms) and process data previously + * "refused" by upper layer (application) and sends delayed ACKs. * * Automatically called from tcp_tmr(). */ @@ -779,8 +780,19 @@ tcp_fasttmr(void) { struct tcp_pcb *pcb; - /* send delayed ACKs */ for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + /* If there is data which was previously "refused" by upper layer */ + if (pcb->refused_data != NULL) { + /* Notify again application with data previously received. */ + err_t err; + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_fasttmr: notify kept packet\n")); + TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err); + if (err == ERR_OK) { + pcb->refused_data = NULL; + } + } + + /* send delayed ACKs */ if (pcb->flags & TF_ACK_DELAY) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n")); tcp_ack_now(pcb); @@ -1135,15 +1147,20 @@ tcp_pcb_purge(struct tcp_pcb *pcb) pcb->state != LISTEN) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n")); - - if (pcb->unsent != NULL) { + + if (pcb->refused_data != NULL) { + LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n")); + pbuf_free(pcb->refused_data); + pcb->refused_data = NULL; + } + if (pcb->unsent != NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n")); } - if (pcb->unacked != NULL) { + if (pcb->unacked != NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n")); } #if TCP_QUEUE_OOSEQ /* LW */ - if (pcb->ooseq != NULL) { + if (pcb->ooseq != NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n")); } diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 4b7b919c..f3943123 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -272,6 +272,23 @@ tcp_input(struct pbuf *p, struct netif *inp) recv_data = NULL; recv_flags = 0; + /* If there is data which was previously "refused" by upper layer */ + if (pcb->refused_data != NULL) { + /* Notify again application with data previously received. */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n")); + TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err); + if (err == ERR_OK) { + pcb->refused_data = NULL; + } else { + /* drop incoming packets, because pcb is "full" */ + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n")); + TCP_STATS_INC(tcp.drop); + snmp_inc_tcpinerrs(); + pbuf_free(p); + return; + } + } + tcp_input_pcb = pcb; err = tcp_process(pcb); tcp_input_pcb = NULL; @@ -304,15 +321,23 @@ tcp_input(struct pbuf *p, struct netif *inp) if(flags & TCP_PSH) { recv_data->flags |= PBUF_FLAG_PUSH; } + /* Notify application that data has been received. */ TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err); + + /* If the upper layer can't receive this data, store it */ + if (err != ERR_OK) { + pcb->refused_data = recv_data; + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n")); + } } - + /* If a FIN segment was received, we call the callback function with a NULL buffer to indicate EOF. */ if (recv_flags & TF_GOT_FIN) { TCP_EVENT_RECV(pcb, NULL, ERR_OK, err); } + /* If there were no errors, we try to send something out. */ if (err == ERR_OK) { tcp_output(pcb); diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h index aa949e43..3fb04464 100644 --- a/src/include/lwip/tcp.h +++ b/src/include/lwip/tcp.h @@ -339,6 +339,8 @@ struct tcp_pcb { struct tcp_seg *ooseq; /* Received out of sequence segments. */ #endif /* TCP_QUEUE_OOSEQ */ + struct pbuf *refused_data; /* Data previously received but not yet taken by upper layer */ + #if LWIP_CALLBACK_API /* Function to be called when more send buffer space is available. * @param arg user-supplied argument (tcp_pcb.callback_arg) @@ -471,6 +473,7 @@ err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb, #define TCP_EVENT_RECV(pcb,p,err,ret) \ if((pcb)->recv != NULL) \ { ret = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err)); } else { \ + ret = ERR_OK; \ if (p) pbuf_free(p); } #define TCP_EVENT_CONNECTED(pcb,err,ret) \ if((pcb)->connected != NULL) \