Need the timer check to avoid the indefinite wait case
in HttpDxe driver
A.HTTP receive Header process in HttpTcpReceiveHeader();
B.HTTP receive Body process in HttpTcpReceiveBody();

Cc: Hegde Nagaraj P <nagaraj-p.he...@hpe.com>
Cc: El-Haj-Mahmoud Samer <samer.el-haj-mahm...@hpe.com>
Cc: Ye Ting <ting...@intel.com>
Cc: Fu Siyuan <siyuan...@intel.com>
Cc: Zhang Lubo <lubo.zh...@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiaxin Wu <jiaxin...@intel.com>
---
 NetworkPkg/HttpDxe/HttpImpl.c  | 60 ++++++++++++++++++++++++++++++++++++++++--
 NetworkPkg/HttpDxe/HttpProto.c | 59 ++++++++++++++++++++++++++++++++++-------
 NetworkPkg/HttpDxe/HttpProto.h | 15 +++++++----
 3 files changed, 117 insertions(+), 17 deletions(-)

diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c
index 63b683e..fe2acbc 100644
--- a/NetworkPkg/HttpDxe/HttpImpl.c
+++ b/NetworkPkg/HttpDxe/HttpImpl.c
@@ -174,10 +174,11 @@ EfiHttpConfigure (
         &HttpInstance->IPv4Node,
         HttpConfigData->AccessPoint.IPv4Node,
         sizeof (HttpInstance->IPv4Node)
         );
     }
+    
     //
     // Creat Tcp child
     //
     Status = HttpInitProtocol (HttpInstance, HttpInstance->LocalAddressIsIPv6);
     if (EFI_ERROR (Status)) {
@@ -894,11 +895,39 @@ HttpResponseWorker (
     }   
 
     HttpInstance->EndofHeader = &EndofHeader;
     HttpInstance->HttpHeaders = &HttpHeaders;
 
-    Status = HttpTcpReceiveHeader (HttpInstance, &SizeofHeaders, &BufferSize);
+
+    if (HttpInstance->TimeoutEvent == NULL) {
+      //
+      // Create TimeoutEvent for response
+      //
+      Status = gBS->CreateEvent (
+                      EVT_TIMER,
+                      TPL_CALLBACK,
+                      NULL,
+                      NULL,
+                      &HttpInstance->TimeoutEvent
+                      );
+      if (EFI_ERROR (Status)) {
+        goto Error;
+      }
+    }
+
+    //
+    // Start the timer, and wait Timeout seconds to receive the header packet.
+    //
+    Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, 
HTTP_RESPONSE_TIMEOUT * TICKS_PER_SECOND);
+    if (EFI_ERROR (Status)) {
+      goto Error;
+    }
+
+    Status = HttpTcpReceiveHeader (HttpInstance, &SizeofHeaders, &BufferSize, 
HttpInstance->TimeoutEvent);
+
+    gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
+
     if (EFI_ERROR (Status)) {
       goto Error;
     }
 
     ASSERT (HttpHeaders != NULL);
@@ -1095,14 +1124,41 @@ HttpResponseWorker (
     }    
   }
 
   ASSERT (HttpInstance->MsgParser != NULL);
 
+  if (HttpInstance->TimeoutEvent == NULL) {
+    //
+    // Create TimeoutEvent for response
+    //
+    Status = gBS->CreateEvent (
+                    EVT_TIMER,
+                    TPL_CALLBACK,
+                    NULL,
+                    NULL,
+                    &HttpInstance->TimeoutEvent
+                    );
+    if (EFI_ERROR (Status)) {
+      goto Error;
+    }
+  }
+
+  //
+  // Start the timer, and wait Timeout seconds to receive the body packet.
+  //
+  Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, 
HTTP_RESPONSE_TIMEOUT * TICKS_PER_SECOND);
+  if (EFI_ERROR (Status)) {
+    goto Error;
+  }
+
   //
   // We still need receive more data when there is no cache data and MsgParser 
is not NULL;
   //
-  Status = HttpTcpReceiveBody (Wrap, HttpMsg);
+  Status = HttpTcpReceiveBody (Wrap, HttpMsg, HttpInstance->TimeoutEvent);
+
+  gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
+
   if (EFI_ERROR (Status)) {
     goto Error;
   }
 
   return Status;
diff --git a/NetworkPkg/HttpDxe/HttpProto.c b/NetworkPkg/HttpDxe/HttpProto.c
index 156f138..eb2af7f 100644
--- a/NetworkPkg/HttpDxe/HttpProto.c
+++ b/NetworkPkg/HttpDxe/HttpProto.c
@@ -813,10 +813,15 @@ HttpCleanProtocol (
 {
   HttpCloseConnection (HttpInstance);
   
   HttpCloseTcpConnCloseEvent (HttpInstance);
 
+  if (HttpInstance->TimeoutEvent != NULL) {
+    gBS->CloseEvent (HttpInstance->TimeoutEvent);
+    HttpInstance->TimeoutEvent = NULL;
+  }
+
   if (HttpInstance->CacheBody != NULL) {
     FreePool (HttpInstance->CacheBody);
     HttpInstance->CacheBody = NULL;
     HttpInstance->NextMsg   = NULL;
   }
@@ -1537,20 +1542,22 @@ HttpTcpReceive (
   Receive the HTTP header by processing the associated HTTP token.
 
   @param[in]       HttpInstance     The HTTP instance private data.
   @param[in, out]  SizeofHeaders    The HTTP header length.
   @param[in, out]  BufferSize       The size of buffer to cacahe the header 
message.
+  @param[in]       Timeout          The time to wait for receiving the header 
packet.
   
   @retval EFI_SUCCESS               The HTTP header is received.               
           
   @retval Others                    Other errors as indicated.
 
 **/
 EFI_STATUS
 HttpTcpReceiveHeader (
   IN  HTTP_PROTOCOL         *HttpInstance,
   IN  OUT UINTN             *SizeofHeaders,
-  IN  OUT UINTN             *BufferSize
+  IN  OUT UINTN             *BufferSize,
+  IN  EFI_EVENT             Timeout
   )
 {
   EFI_STATUS                    Status;
   EFI_TCP4_IO_TOKEN             *Rx4Token;
   EFI_TCP4_PROTOCOL             *Tcp4;
@@ -1595,13 +1602,18 @@ HttpTcpReceiveHeader (
       if (EFI_ERROR (Status)) {
         DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
         return Status;
       }
       
-      while (!HttpInstance->IsRxDone) {
-       Tcp4->Poll (Tcp4);
-      }    
+      while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR 
(gBS->CheckEvent (Timeout)))) {
+        Tcp4->Poll (Tcp4);
+      }
+
+      if (!HttpInstance->IsRxDone) {
+        gBS->CloseEvent (Rx4Token->CompletionToken.Event);
+        Rx4Token->CompletionToken.Status = EFI_TIMEOUT;
+      }
   
       Status = Rx4Token->CompletionToken.Status;
       if (EFI_ERROR (Status)) {
         return Status;
       }
@@ -1656,13 +1668,18 @@ HttpTcpReceiveHeader (
       if (EFI_ERROR (Status)) {
         DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
         return Status;
       }
       
-      while (!HttpInstance->IsRxDone) {
-       Tcp6->Poll (Tcp6);
-      }    
+      while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR 
(gBS->CheckEvent (Timeout)))) {
+        Tcp6->Poll (Tcp6);
+      }
+
+      if (!HttpInstance->IsRxDone) {
+        gBS->CloseEvent (Rx6Token->CompletionToken.Event);
+        Rx6Token->CompletionToken.Status = EFI_TIMEOUT;
+      }
   
       Status = Rx6Token->CompletionToken.Status;
       if (EFI_ERROR (Status)) {
         return Status;
       }
@@ -1711,19 +1728,21 @@ HttpTcpReceiveHeader (
 /**
   Receive the HTTP body by processing the associated HTTP token.
 
   @param[in]  Wrap               The HTTP token's wrap data.
   @param[in]  HttpMsg            The HTTP message data.
+  @param[in]  Timeout            The time to wait for receiving the body 
packet.
 
   @retval EFI_SUCCESS            The HTTP body is received.                    
      
   @retval Others                 Other error as indicated.
 
 **/
 EFI_STATUS
 HttpTcpReceiveBody (
   IN  HTTP_TOKEN_WRAP       *Wrap,
-  IN  EFI_HTTP_MESSAGE      *HttpMsg
+  IN  EFI_HTTP_MESSAGE      *HttpMsg,
+  IN  EFI_EVENT             Timeout
   )
 {
   EFI_STATUS                Status;
   HTTP_PROTOCOL             *HttpInstance;
   EFI_TCP6_PROTOCOL         *Tcp6;
@@ -1734,11 +1753,10 @@ HttpTcpReceiveBody (
   HttpInstance   = Wrap->HttpInstance;
   Tcp4 = HttpInstance->Tcp4;
   Tcp6 = HttpInstance->Tcp6;
   Rx4Token       = NULL;
   Rx6Token       = NULL;
-
   
   if (HttpInstance->LocalAddressIsIPv6) {
     ASSERT (Tcp6 != NULL);
   } else {
     ASSERT (Tcp4 != NULL);
@@ -1754,11 +1772,21 @@ HttpTcpReceiveBody (
     Status = Tcp6->Receive (Tcp6, Rx6Token);
     if (EFI_ERROR (Status)) {
       DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
       return Status;
     }
-      
+
+    while (!Wrap->TcpWrap.IsRxDone && ((Timeout == NULL) || EFI_ERROR 
(gBS->CheckEvent (Timeout)))) {
+      Tcp6->Poll (Tcp6);
+    }
+
+    if (!Wrap->TcpWrap.IsRxDone) {
+      gBS->CloseEvent (Rx6Token->CompletionToken.Event);
+      Rx6Token->CompletionToken.Status = EFI_TIMEOUT;
+      Wrap->HttpToken->Status = Rx6Token->CompletionToken.Status;
+      gBS->SignalEvent (Wrap->HttpToken->Event);
+    }
   } else {
     Rx4Token = &Wrap->TcpWrap.Rx4Token;
     Rx4Token->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength;
     Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) 
HttpMsg->BodyLength;
     Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) 
HttpMsg->Body;
@@ -1767,10 +1795,21 @@ HttpTcpReceiveBody (
     Status = Tcp4->Receive (Tcp4, Rx4Token);
     if (EFI_ERROR (Status)) {
       DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
       return Status;
     }
+
+    while (!Wrap->TcpWrap.IsRxDone && ((Timeout == NULL) || EFI_ERROR 
(gBS->CheckEvent (Timeout)))) {
+      Tcp4->Poll (Tcp4);
+    }
+
+    if (!Wrap->TcpWrap.IsRxDone) {
+      gBS->CloseEvent (Rx4Token->CompletionToken.Event);
+      Rx4Token->CompletionToken.Status = EFI_TIMEOUT;
+      Wrap->HttpToken->Status = Rx4Token->CompletionToken.Status;
+      gBS->SignalEvent (Wrap->HttpToken->Event);
+    }
   }
 
   return EFI_SUCCESS;
 
 }
diff --git a/NetworkPkg/HttpDxe/HttpProto.h b/NetworkPkg/HttpDxe/HttpProto.h
index 7b4b343..8b47fe0 100644
--- a/NetworkPkg/HttpDxe/HttpProto.h
+++ b/NetworkPkg/HttpDxe/HttpProto.h
@@ -45,10 +45,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER 
EXPRESS OR IMPLIED.
 #define HTTP_TOS_DEAULT              8
 #define HTTP_TTL_DEAULT              255
 #define HTTP_BUFFER_SIZE_DEAULT      65535
 #define HTTP_MAX_SYN_BACK_LOG        5
 #define HTTP_CONNECTION_TIMEOUT      60
+#define HTTP_RESPONSE_TIMEOUT        5
 #define HTTP_DATA_RETRIES            12
 #define HTTP_FIN_TIMEOUT             2
 #define HTTP_KEEP_ALIVE_PROBES       6
 #define HTTP_KEEP_ALIVE_TIME         7200
 #define HTTP_KEEP_ALIVE_INTERVAL     30
@@ -91,10 +92,12 @@ typedef struct _HTTP_PROTOCOL {
   BOOLEAN                       InDestroy;
   INTN                          State;
 
   UINTN                         StatusCode;
 
+  EFI_EVENT                     TimeoutEvent;
+
   EFI_HANDLE                    Tcp4ChildHandle;
   EFI_TCP4_PROTOCOL             *Tcp4;
   EFI_TCP4_CONFIG_DATA          Tcp4CfgData;
   EFI_TCP4_OPTION               Tcp4Option;
 
@@ -114,13 +117,11 @@ typedef struct _HTTP_PROTOCOL {
   EFI_TCP6_CONNECTION_TOKEN     Tcp6ConnToken;
   BOOLEAN                       IsTcp6ConnDone;
   EFI_TCP6_CLOSE_TOKEN          Tcp6CloseToken;
   BOOLEAN                       IsTcp6CloseDone;
   EFI_IPv6_ADDRESS              RemoteIpv6Addr;
-
-
-  
+ 
   //
   // Rx4Token or Rx6Token used for receiving HTTP header.
   //
   EFI_TCP4_IO_TOKEN             Rx4Token;
   EFI_TCP4_RECEIVE_DATA         Rx4Data;
@@ -502,36 +503,40 @@ HttpTcpReceive (
   Receive the HTTP header by processing the associated HTTP token.
 
   @param[in]       HttpInstance    The HTTP instance private data.
   @param[in, out]  SizeofHeaders   The HTTP header length.
   @param[in, out]  BufferSize      The size of buffer to cacahe the header 
message.
+  @param[in]       Timeout         The time to wait for receiving the header 
packet.
 
   @retval EFI_SUCCESS              The HTTP header is received.                
          
   @retval Others                   Other errors as indicated.
 
 **/
 EFI_STATUS
 HttpTcpReceiveHeader (
   IN  HTTP_PROTOCOL         *HttpInstance,
   IN  OUT UINTN             *SizeofHeaders,
-  IN  OUT UINTN             *BufferSize
+  IN  OUT UINTN             *BufferSize,
+  IN  EFI_EVENT             Timeout
   );
 
 /**
   Receive the HTTP body by processing the associated HTTP token.
 
   @param[in]  Wrap               The HTTP token's wrap data.
   @param[in]  HttpMsg            The HTTP message data.
+  @param[in]  Timeout            The time to wait for receiving the body 
packet.
 
   @retval EFI_SUCCESS            The HTTP body is received.                    
      
   @retval Others                 Other error as indicated.
 
 **/
 EFI_STATUS
 HttpTcpReceiveBody (
   IN  HTTP_TOKEN_WRAP       *Wrap,
-  IN  EFI_HTTP_MESSAGE      *HttpMsg
+  IN  EFI_HTTP_MESSAGE      *HttpMsg,
+  IN  EFI_EVENT             Timeout
   );
 
 /**
   Clean up Tcp Tokens while the Tcp transmission error occurs.
 
-- 
1.9.5.msysgit.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to