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