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).

This commit is contained in:
fbernon 2008-01-14 21:07:08 +00:00
parent 52e6922e5a
commit 7518acf634
6 changed files with 65 additions and 11 deletions

View File

@ -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".

View File

@ -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)

View File

@ -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;
}

View File

@ -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"));
}

View File

@ -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);

View File

@ -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) \