From 517d32ae3467596ca8173ff5f9300aa7d84d2b7f Mon Sep 17 00:00:00 2001
From: jiangheng <jiangheng14@huawei.com>
Date: Mon, 22 Jan 2024 17:30:30 +0800
Subject: [PATCH] fix receive fin packet process error

---
 src/lstack/core/lstack_lwip.c | 67 +++++++++++++++++++++++------------
 1 file changed, 45 insertions(+), 22 deletions(-)

diff --git a/src/lstack/core/lstack_lwip.c b/src/lstack/core/lstack_lwip.c
index fe30edf..a7201aa 100644
--- a/src/lstack/core/lstack_lwip.c
+++ b/src/lstack/core/lstack_lwip.c
@@ -38,6 +38,8 @@
 #include "lstack_cfg.h"
 #include "lstack_lwip.h"
 
+static const uint8_t fin_packet = 0;
+
 static void free_ring_pbuf(struct rte_ring *ring)
 {
     void *pbufs[SOCK_RECV_RING_SIZE];
@@ -509,13 +511,15 @@ static inline struct pbuf *pbuf_last(struct pbuf *pbuf)
 ssize_t do_lwip_read_from_lwip(struct lwip_sock *sock, int32_t flags, u8_t apiflags)
 {
     if (sock->conn->recvmbox == NULL) {
-        return 0;
+        sock->conn->pending_err = ERR_CONN;
+        GAZELLE_RETURN(ENOTCONN);
     }
 
     free_recv_ring_readover(sock->recv_ring);
 
     uint32_t free_count = gazelle_ring_free_count(sock->recv_ring);
     if (free_count == 0) {
+        sock->conn->pending_err = ERR_WOULDBLOCK;
         GAZELLE_RETURN(EAGAIN);
     }
 
@@ -534,12 +538,19 @@ ssize_t do_lwip_read_from_lwip(struct lwip_sock *sock, int32_t flags, u8_t apifl
             err = netconn_recv_tcp_pbuf_flags(sock->conn, &pbufs[i], apiflags);
         }
         if (err != ERR_OK) {
-            if (recv_len > 0) {
-                /* already received data, return that (this trusts in getting the same error from
-                   netconn layer again next time netconn_recv is called) */
+            /* fin has been read from recvmbox, put it to recv_ring */
+            if (!NETCONN_IS_UDP(sock) &&
+                (netconn_is_flag_set(sock->conn, NETCONN_FIN_RX_PENDING) || err == ERR_CLSD)) {
+                /* fin has been read, lwip don't need to process fin packet */
+                netconn_clear_flags(sock->conn, NETCONN_FIN_RX_PENDING);
+                pbufs[i] = NULL;
+                read_count++;
                 break;
             }
-            return (err == ERR_CLSD) ? 0 : -1;
+
+            /* store err to pending_err again, clear it after app read */
+            sock->conn->pending_err = err;
+            GAZELLE_RETURN(err_to_errno(err));
         }
 
         recv_len += pbufs[i]->tot_len;
@@ -551,25 +562,17 @@ ssize_t do_lwip_read_from_lwip(struct lwip_sock *sock, int32_t flags, u8_t apifl
     }
 
     uint32_t enqueue_num = gazelle_ring_sp_enqueue(sock->recv_ring, (void **)pbufs, read_count);
-    for (uint32_t i = enqueue_num; i < read_count; i++) {
-        if (NETCONN_IS_UDP(sock)) {
-            pbuf_free(pbufs[i]);
-        } else {
-            /* update receive window */
-            tcp_recved(sock->conn->pcb.tcp, pbufs[i]->tot_len);
-            pbuf_free(pbufs[i]);
-        }
-        sock->stack->stats.read_lwip_drop++;
+    if (enqueue_num != read_count) {
+        LSTACK_LOG(ERR, LSTACK, "Code shouldn't get here!\n");
     }
 
     for (uint32_t i = 0; get_protocol_stack_group()->latency_start && i < read_count; i++) {
-        calculate_lstack_latency(&sock->stack->latency, pbufs[i], GAZELLE_LATENCY_LWIP);
+        if (pbufs[i] != NULL) {
+            calculate_lstack_latency(&sock->stack->latency, pbufs[i], GAZELLE_LATENCY_LWIP);
+        }
     }
 
     sock->stack->stats.read_lwip_cnt += read_count;
-    if (recv_len == 0) {
-        GAZELLE_RETURN(EAGAIN);
-    }
     return recv_len;
 }
 
@@ -817,7 +820,8 @@ ssize_t do_lwip_read_from_stack(int32_t fd, void *buf, size_t len, int32_t flags
     bool latency_enable = get_protocol_stack_group()->latency_start;
 
     if (sock->errevent > 0 && !NETCONN_IS_DATAIN(sock)) {
-        return 0;
+        errno = err_to_errno(netconn_err(sock->conn));
+        return -1;
     }
 
     thread_bind_stack(sock);
@@ -839,7 +843,8 @@ ssize_t do_lwip_read_from_stack(int32_t fd, void *buf, size_t len, int32_t flags
                 while (gazelle_ring_read(sock->recv_ring, (void **)&pbuf, 1) != 1 && recvd == 0) {
                     /* if the connection is disconnected, recv return 0 */
                     if (sock->errevent > 0 && !NETCONN_IS_DATAIN(sock)) {
-                        return 0;
+                        errno = err_to_errno(netconn_err(sock->conn));
+                        return -1;
                     }
 
                     lstack_block_wait(sock->wakeup);
@@ -847,6 +852,23 @@ ssize_t do_lwip_read_from_stack(int32_t fd, void *buf, size_t len, int32_t flags
             }
         }
 
+        /* fin */
+        if (unlikely(pbuf == NULL)) {
+            if (recvd > 0) {
+                /* read data first, then read fin */
+                sock->recv_lastdata = (void *)&fin_packet;
+                gazelle_ring_read_over(sock->recv_ring);
+                break;
+            }
+            gazelle_ring_read_over(sock->recv_ring);
+            return 0;
+        }
+
+        /* pending fin */
+        if (unlikely(pbuf == (void *)&fin_packet)) {
+            return 0;
+        }
+
         copy_len = (recv_left > pbuf->tot_len) ? pbuf->tot_len : recv_left;
         if (copy_len > UINT16_MAX) {
             copy_len = UINT16_MAX;
@@ -946,10 +968,11 @@ void do_lwip_read_recvlist(struct protocol_stack *stack, uint32_t max_num)
         } else {
             len = lwip_recv(sock->conn->socket, NULL, 0, 0);
         }
-        if (len == 0) {
+        if (len < 0 && errno != EAGAIN) {
             sock->errevent = 1;
             add_sock_event(sock, EPOLLERR);
-        } else if (len > 0) {
+        /* = 0: fin */
+        } else if (len >= 0) {
             add_sock_event(sock, EPOLLIN);
         }
     }
-- 
2.33.0

