]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lwip.git/commitdiff
rawapi.txt, api_msg.c, tcp.c, tcp_in.c, tcp.h: changes for task #7675 "Enable to...
authorfbernon <fbernon>
Mon, 14 Jan 2008 21:07:08 +0000 (21:07 +0000)
committerfbernon <fbernon>
Mon, 14 Jan 2008 21:07:08 +0000 (21:07 +0000)
CHANGELOG
doc/rawapi.txt
src/api/api_msg.c
src/core/tcp.c
src/core/tcp_in.c
src/include/lwip/tcp.h

index 4b0ea05c240daf9981f67abe71aef7a6856622be..ca190ea846d043cdea0198dcf5a00a864265e1a0 100644 (file)
--- 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".
   
index 93c0e862ce6a86b1504e6c5d3e0107696dc3722a..8213445e8acfe84916381cf699ff10b2884a76c9 100644 (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)
 
index ccb4c0dd64cbe8b09d4f949e93caa7369aeafd23..3464d071d359b3cdf1bca2a079782b47974c8451 100644 (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;
 }
index 24ea5e70f4596081f766557acef1878ab30e5bfa..531b26d531c9dbe53905de06bdd54a4d3ad0233a 100644 (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"));
     }
 
index 4b7b919cd3f6b74c82d1cdd3fc9c9e2fb67933ca..f3943123a250d899378d80b8c417267f57f52833 100644 (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);
index aa949e4349b3a8c7c4c19284a15bb93f071989e5..3fb044645b4c31ba3e5d0a98c747618bd038df48 100644 (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) \