From b347a22aecbfac9aac47831fee9a30aa810d6d0b Mon Sep 17 00:00:00 2001 From: Jiaxin Wu Date: Tue, 26 Apr 2016 16:46:33 +0800 Subject: [PATCH] NetworkPkg: Avoid the indefinite wait case in HttpDxe 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 Cc: El-Haj-Mahmoud Samer Cc: Ye Ting Cc: Fu Siyuan Cc: Zhang Lubo Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiaxin Wu Reviewed-by: Hegde Nagaraj P Reviewed-by: Fu Siyuan --- 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 553b79cca0..7a236f40e0 100644 --- a/NetworkPkg/HttpDxe/HttpImpl.c +++ b/NetworkPkg/HttpDxe/HttpImpl.c @@ -176,6 +176,7 @@ EfiHttpConfigure ( sizeof (HttpInstance->IPv4Node) ); } + // // Creat Tcp child // @@ -897,7 +898,35 @@ 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; } @@ -1098,10 +1127,37 @@ 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; } diff --git a/NetworkPkg/HttpDxe/HttpProto.c b/NetworkPkg/HttpDxe/HttpProto.c index 9b3c774ae2..06f3bb6860 100644 --- a/NetworkPkg/HttpDxe/HttpProto.c +++ b/NetworkPkg/HttpDxe/HttpProto.c @@ -815,6 +815,11 @@ HttpCleanProtocol ( HttpCloseTcpConnCloseEvent (HttpInstance); + if (HttpInstance->TimeoutEvent != NULL) { + gBS->CloseEvent (HttpInstance->TimeoutEvent); + HttpInstance->TimeoutEvent = NULL; + } + if (HttpInstance->CacheBody != NULL) { FreePool (HttpInstance->CacheBody); HttpInstance->CacheBody = NULL; @@ -1541,6 +1546,7 @@ HttpTcpReceive ( @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. @@ -1550,7 +1556,8 @@ 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; @@ -1599,9 +1606,14 @@ HttpTcpReceiveHeader ( 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)) { @@ -1660,9 +1672,14 @@ HttpTcpReceiveHeader ( 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)) { @@ -1715,6 +1732,7 @@ HttpTcpReceiveHeader ( @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. @@ -1723,7 +1741,8 @@ HttpTcpReceiveHeader ( 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; @@ -1738,7 +1757,6 @@ HttpTcpReceiveBody ( Tcp6 = HttpInstance->Tcp6; Rx4Token = NULL; Rx6Token = NULL; - if (HttpInstance->LocalAddressIsIPv6) { ASSERT (Tcp6 != NULL); @@ -1758,7 +1776,17 @@ HttpTcpReceiveBody ( 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; @@ -1771,6 +1799,17 @@ HttpTcpReceiveBody ( 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 7b4b343b2a..8b47fe00f6 100644 --- a/NetworkPkg/HttpDxe/HttpProto.h +++ b/NetworkPkg/HttpDxe/HttpProto.h @@ -47,6 +47,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #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 @@ -93,6 +94,8 @@ typedef struct _HTTP_PROTOCOL { UINTN StatusCode; + EFI_EVENT TimeoutEvent; + EFI_HANDLE Tcp4ChildHandle; EFI_TCP4_PROTOCOL *Tcp4; EFI_TCP4_CONFIG_DATA Tcp4CfgData; @@ -116,9 +119,7 @@ typedef struct _HTTP_PROTOCOL { EFI_TCP6_CLOSE_TOKEN Tcp6CloseToken; BOOLEAN IsTcp6CloseDone; EFI_IPv6_ADDRESS RemoteIpv6Addr; - - - + // // Rx4Token or Rx6Token used for receiving HTTP header. // @@ -504,6 +505,7 @@ HttpTcpReceive ( @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. @@ -513,7 +515,8 @@ EFI_STATUS HttpTcpReceiveHeader ( IN HTTP_PROTOCOL *HttpInstance, IN OUT UINTN *SizeofHeaders, - IN OUT UINTN *BufferSize + IN OUT UINTN *BufferSize, + IN EFI_EVENT Timeout ); /** @@ -521,6 +524,7 @@ HttpTcpReceiveHeader ( @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. @@ -529,7 +533,8 @@ HttpTcpReceiveHeader ( EFI_STATUS HttpTcpReceiveBody ( IN HTTP_TOKEN_WRAP *Wrap, - IN EFI_HTTP_MESSAGE *HttpMsg + IN EFI_HTTP_MESSAGE *HttpMsg, + IN EFI_EVENT Timeout ); /** -- 2.39.2