]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lwip.git/commitdiff
Implemented limiting data on ooseq queue (task #9989) (define TCP_OOSEQ_MAX_BYTES...
authorSimon Goldschmidt <goldsimon@gmx.de>
Tue, 27 Sep 2011 20:42:46 +0000 (22:42 +0200)
committerSimon Goldschmidt <goldsimon@gmx.de>
Tue, 27 Sep 2011 20:42:46 +0000 (22:42 +0200)
CHANGELOG
src/core/tcp_in.c
src/include/lwip/opt.h
test/unit/tcp/test_tcp_oos.c

index 998fa7e078734d7b20d805ce192967c9c214a693..8138bbf7f1b42d67005be9d8cdbe0bf8a0b6deca 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -6,6 +6,10 @@ HISTORY
 
  ++ New features:
 
+  2011-09-27: Simon Goldschmidt
+  * opt.h, tcp.c, tcp_in.c: Implemented limiting data on ooseq queue (task #9989)
+    (define TCP_OOSEQ_MAX_BYTES / TCP_OOSEQ_MAX_PBUFS in lwipopts.h)
+
   2011-09-21: Simon Goldschmidt
   * opt.h, api.h, api_lib.c, api_msg.h/.c, sockets.c: Implemented timeout on
     send (TCP only, bug #33820)
index 704d310ceb2d02b0a913e79c30541f97d2fafaed..df7c33dd9792d1ef7b3803ecec0710c595c76923 100644 (file)
@@ -891,6 +891,10 @@ tcp_receive(struct tcp_pcb *pcb)
   u32_t right_wnd_edge;
   u16_t new_tot_len;
   int found_dupack = 0;
+#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS
+  u32_t ooseq_blen;
+  u16_t ooseq_qlen;
+#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */
 
   LWIP_ASSERT("tcp_receive: wrong state", pcb->state >= ESTABLISHED);
 
@@ -1275,8 +1279,7 @@ tcp_receive(struct tcp_pcb *pcb)
               pcb->ooseq = pcb->ooseq->next;
               tcp_seg_free(old_ooseq);
             }
-          }
-          else {
+          } else {
             next = pcb->ooseq;
             /* Remove all segments on ooseq that are covered by inseg already.
              * FIN is copied from ooseq to inseg if present. */
@@ -1516,8 +1519,32 @@ tcp_receive(struct tcp_pcb *pcb)
             prev = next;
           }
         }
+#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS
+        /* Check that the data on ooseq doesn't exceed one of the limits
+           and throw away everything above that limit. */
+        ooseq_blen = 0;
+        ooseq_qlen = 0;
+        prev = NULL;
+        for(next = pcb->ooseq; next != NULL; prev = next, next = next->next) {
+          struct pbuf *p = next->p;
+          ooseq_blen += p->tot_len;
+          ooseq_qlen += pbuf_clen(p);
+          if ((ooseq_blen > TCP_OOSEQ_MAX_BYTES) ||
+              (ooseq_qlen > TCP_OOSEQ_MAX_PBUFS)) {
+             /* too much ooseq data, dump this and everything after it */
+             tcp_segs_free(next);
+             if (prev == NULL) {
+               /* first ooseq segment is too much, dump the whole queue */
+               pcb->ooseq = NULL;
+             } else {
+               /* just dump 'next' and everything after it */
+               prev->next = NULL;
+             }
+             break;
+          }
+        }
+#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */
 #endif /* TCP_QUEUE_OOSEQ */
-
       }
     } else {
       /* The incoming segment is not withing the window. */
index aab3c8be108869d00d102a279fb1322d0b7b0494..2565022cc8b76e1bbb92131dd405aa0621527d5b 100644 (file)
 #define TCP_SNDQUEUELOWAT               ((TCP_SND_QUEUELEN)/2)
 #endif
 
+/**
+ * TCP_OOSEQ_MAX_BYTES: The maximum number of bytes queued on ooseq per pcb.
+ * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==0.
+ */
+#ifndef TCP_OOSEQ_MAX_BYTES
+#define TCP_OOSEQ_MAX_BYTES             0
+#endif
+
+/**
+ * TCP_OOSEQ_MAX_PBUFS: The maximum number of pbufs queued on ooseq per pcb.
+ * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==0.
+ */
+#ifndef TCP_OOSEQ_MAX_PBUFS
+#define TCP_OOSEQ_MAX_PBUFS             0
+#endif
+
 /**
  * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb.
  */
index c62dc1789175002d9e02b378231fc5c8e923144f..764de1c433dc7c9604ebeffe5ca4a76628b86944 100644 (file)
@@ -36,6 +36,18 @@ static int tcp_oos_count(struct tcp_pcb* pcb)
   return num;
 }
 
+/** Get the numbers of pbufs on the ooseq list */
+static int tcp_oos_pbuf_count(struct tcp_pcb* pcb)
+{
+  int num = 0;
+  struct tcp_seg* seg = pcb->ooseq;
+  while(seg != NULL) {
+    num += pbuf_clen(seg->p);
+    seg = seg->next;
+  }
+  return num;
+}
+
 /** Get the seqno of a segment (by index) on the ooseq list
  *
  * @param pcb the pcb to check for ooseq segments
@@ -440,6 +452,7 @@ static char data_full_wnd[TCP_WND];
  * to simulate overruning the rxwin with ooseq queueing enabled */
 START_TEST(test_tcp_recv_ooseq_overrun_rxwin)
 {
+#if !TCP_OOSEQ_MAX_BYTES && !TCP_OOSEQ_MAX_PBUFS
   int i, k;
   struct test_tcp_counters counters;
   struct tcp_pcb* pcb;
@@ -449,7 +462,6 @@ START_TEST(test_tcp_recv_ooseq_overrun_rxwin)
   struct netif netif;
   int datalen = 0;
   int datalen2;
-  LWIP_UNUSED_ARG(_i);
 
   for(i = 0; i < sizeof(data_full_wnd); i++) {
     data_full_wnd[i] = (char)i;
@@ -523,6 +535,166 @@ START_TEST(test_tcp_recv_ooseq_overrun_rxwin)
   EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
   tcp_abort(pcb);
   EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
+#endif /* !TCP_OOSEQ_MAX_BYTES && !TCP_OOSEQ_MAX_PBUFS */
+  LWIP_UNUSED_ARG(_i);
+}
+END_TEST
+
+START_TEST(test_tcp_recv_ooseq_max_bytes)
+{
+#if TCP_OOSEQ_MAX_BYTES && (TCP_OOSEQ_MAX_BYTES < (TCP_WND + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN))
+  int i, k;
+  struct test_tcp_counters counters;
+  struct tcp_pcb* pcb;
+  struct pbuf *p_ovr;
+  ip_addr_t remote_ip, local_ip;
+  u16_t remote_port = 0x100, local_port = 0x101;
+  struct netif netif;
+  int datalen = 0;
+  int datalen2;
+
+  for(i = 0; i < sizeof(data_full_wnd); i++) {
+    data_full_wnd[i] = (char)i;
+  }
+
+  /* initialize local vars */
+  memset(&netif, 0, sizeof(netif));
+  IP4_ADDR(&local_ip, 192, 168, 1, 1);
+  IP4_ADDR(&remote_ip, 192, 168, 1, 2);
+  /* initialize counter struct */
+  memset(&counters, 0, sizeof(counters));
+  counters.expected_data_len = TCP_WND;
+  counters.expected_data = data_full_wnd;
+
+  /* create and initialize the pcb */
+  pcb = test_tcp_new_counters_pcb(&counters);
+  EXPECT_RET(pcb != NULL);
+  tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);
+  pcb->rcv_nxt = 0x8000;
+
+  /* don't 'recv' the first segment (1 byte) so that all other segments will be ooseq */
+
+  /* create segments and 'recv' them */
+  for(k = 1, i = 1; k < TCP_OOSEQ_MAX_BYTES; k += TCP_MSS, i++) {
+    int count;
+    struct pbuf *p = tcp_create_rx_segment(pcb, &data_full_wnd[k],
+                                           TCP_MSS, k, 0, TCP_ACK);
+    EXPECT_RET(p != NULL);
+    EXPECT_RET(p->next == NULL);
+    /* pass the segment to tcp_input */
+    test_tcp_input(p, &netif);
+    /* check if counters are as expected */
+    EXPECT(counters.close_calls == 0);
+    EXPECT(counters.recv_calls == 0);
+    EXPECT(counters.recved_bytes == 0);
+    EXPECT(counters.err_calls == 0);
+    /* check ooseq queue */
+    count = tcp_oos_pbuf_count(pcb);
+    EXPECT_OOSEQ(count == i);
+    datalen = tcp_oos_tcplen(pcb);
+    EXPECT_OOSEQ(datalen == (i * TCP_MSS));
+  }
+
+  /* pass in one more segment, overrunning the limit */
+  p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[k+1], 1, k+1, 0, TCP_ACK);
+  EXPECT_RET(p_ovr != NULL);
+  /* pass the segment to tcp_input */
+  test_tcp_input(p_ovr, &netif);
+  /* check if counters are as expected */
+  EXPECT(counters.close_calls == 0);
+  EXPECT(counters.recv_calls == 0);
+  EXPECT(counters.recved_bytes == 0);
+  EXPECT(counters.err_calls == 0);
+  /* check ooseq queue (ensure the new segment was not accepted) */
+  EXPECT_OOSEQ(tcp_oos_count(pcb) == (i-1));
+  datalen2 = tcp_oos_tcplen(pcb);
+  EXPECT_OOSEQ(datalen2 == ((i-1) * TCP_MSS));
+
+  /* make sure the pcb is freed */
+  EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
+  tcp_abort(pcb);
+  EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
+#endif /* TCP_OOSEQ_MAX_BYTES && (TCP_OOSEQ_MAX_BYTES < (TCP_WND + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) */
+  LWIP_UNUSED_ARG(_i);
+}
+END_TEST
+
+START_TEST(test_tcp_recv_ooseq_max_pbufs)
+{
+#if TCP_OOSEQ_MAX_PBUFS && (TCP_OOSEQ_MAX_PBUFS < ((TCP_WND / TCP_MSS) + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN))
+  int i;
+  struct test_tcp_counters counters;
+  struct tcp_pcb* pcb;
+  struct pbuf *p_ovr;
+  ip_addr_t remote_ip, local_ip;
+  u16_t remote_port = 0x100, local_port = 0x101;
+  struct netif netif;
+  int datalen = 0;
+  int datalen2;
+
+  for(i = 0; i < sizeof(data_full_wnd); i++) {
+    data_full_wnd[i] = (char)i;
+  }
+
+  /* initialize local vars */
+  memset(&netif, 0, sizeof(netif));
+  IP4_ADDR(&local_ip, 192, 168, 1, 1);
+  IP4_ADDR(&remote_ip, 192, 168, 1, 2);
+  /* initialize counter struct */
+  memset(&counters, 0, sizeof(counters));
+  counters.expected_data_len = TCP_WND;
+  counters.expected_data = data_full_wnd;
+
+  /* create and initialize the pcb */
+  pcb = test_tcp_new_counters_pcb(&counters);
+  EXPECT_RET(pcb != NULL);
+  tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port);
+  pcb->rcv_nxt = 0x8000;
+
+  /* don't 'recv' the first segment (1 byte) so that all other segments will be ooseq */
+
+  /* create segments and 'recv' them */
+  for(i = 1; i <= TCP_OOSEQ_MAX_PBUFS; i++) {
+    int count;
+    struct pbuf *p = tcp_create_rx_segment(pcb, &data_full_wnd[i],
+                                           1, i, 0, TCP_ACK);
+    EXPECT_RET(p != NULL);
+    EXPECT_RET(p->next == NULL);
+    /* pass the segment to tcp_input */
+    test_tcp_input(p, &netif);
+    /* check if counters are as expected */
+    EXPECT(counters.close_calls == 0);
+    EXPECT(counters.recv_calls == 0);
+    EXPECT(counters.recved_bytes == 0);
+    EXPECT(counters.err_calls == 0);
+    /* check ooseq queue */
+    count = tcp_oos_pbuf_count(pcb);
+    EXPECT_OOSEQ(count == i);
+    datalen = tcp_oos_tcplen(pcb);
+    EXPECT_OOSEQ(datalen == i);
+  }
+
+  /* pass in one more segment, overrunning the limit */
+  p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[i+1], 1, i+1, 0, TCP_ACK);
+  EXPECT_RET(p_ovr != NULL);
+  /* pass the segment to tcp_input */
+  test_tcp_input(p_ovr, &netif);
+  /* check if counters are as expected */
+  EXPECT(counters.close_calls == 0);
+  EXPECT(counters.recv_calls == 0);
+  EXPECT(counters.recved_bytes == 0);
+  EXPECT(counters.err_calls == 0);
+  /* check ooseq queue (ensure the new segment was not accepted) */
+  EXPECT_OOSEQ(tcp_oos_count(pcb) == (i-1));
+  datalen2 = tcp_oos_tcplen(pcb);
+  EXPECT_OOSEQ(datalen2 == (i-1));
+
+  /* make sure the pcb is freed */
+  EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1);
+  tcp_abort(pcb);
+  EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
+#endif /* TCP_OOSEQ_MAX_PBUFS && (TCP_OOSEQ_MAX_BYTES < (TCP_WND + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) */
+  LWIP_UNUSED_ARG(_i);
 }
 END_TEST
 
@@ -662,7 +834,7 @@ static void test_tcp_recv_ooseq_double_FINs(int delay_packet)
         exp_oos_tcplen++;
       }
     } else {
-      /* inseq: no change */      
+      /* inseq: no change */
     }
   }
   /* check if counters are as expected */
@@ -749,6 +921,8 @@ tcp_oos_suite(void)
     test_tcp_recv_ooseq_FIN_OOSEQ,
     test_tcp_recv_ooseq_FIN_INSEQ,
     test_tcp_recv_ooseq_overrun_rxwin,
+    test_tcp_recv_ooseq_max_bytes,
+    test_tcp_recv_ooseq_max_pbufs,
     test_tcp_recv_ooseq_double_FIN_0,
     test_tcp_recv_ooseq_double_FIN_1,
     test_tcp_recv_ooseq_double_FIN_2,