| /** @file | |
| Miscellaneous routines for HttpDxe driver. | |
| Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR> | |
| (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "HttpDriver.h" | |
| /** | |
| The common notify function used in HTTP driver. | |
| @param[in] Event The event signaled. | |
| @param[in] Context The context. | |
| **/ | |
| VOID | |
| EFIAPI | |
| HttpCommonNotify ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| if ((Event == NULL) || (Context == NULL)) { | |
| return ; | |
| } | |
| *((BOOLEAN *) Context) = TRUE; | |
| } | |
| /** | |
| The notify function associated with Tx4Token for Tcp4->Transmit() or Tx6Token for Tcp6->Transmit(). | |
| @param[in] Context The context. | |
| **/ | |
| VOID | |
| EFIAPI | |
| HttpTcpTransmitNotifyDpc ( | |
| IN VOID *Context | |
| ) | |
| { | |
| HTTP_TOKEN_WRAP *Wrap; | |
| HTTP_PROTOCOL *HttpInstance; | |
| if (Context == NULL) { | |
| return ; | |
| } | |
| Wrap = (HTTP_TOKEN_WRAP *) Context; | |
| HttpInstance = Wrap->HttpInstance; | |
| if (!HttpInstance->LocalAddressIsIPv6) { | |
| Wrap->HttpToken->Status = Wrap->TcpWrap.Tx4Token.CompletionToken.Status; | |
| gBS->SignalEvent (Wrap->HttpToken->Event); | |
| // | |
| // Free resources. | |
| // | |
| if (Wrap->TcpWrap.Tx4Token.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) { | |
| FreePool (Wrap->TcpWrap.Tx4Token.Packet.TxData->FragmentTable[0].FragmentBuffer); | |
| } | |
| if (Wrap->TcpWrap.Tx4Token.CompletionToken.Event != NULL) { | |
| gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event); | |
| } | |
| } else { | |
| Wrap->HttpToken->Status = Wrap->TcpWrap.Tx6Token.CompletionToken.Status; | |
| gBS->SignalEvent (Wrap->HttpToken->Event); | |
| // | |
| // Free resources. | |
| // | |
| if (Wrap->TcpWrap.Tx6Token.Packet.TxData->FragmentTable[0].FragmentBuffer != NULL) { | |
| FreePool (Wrap->TcpWrap.Tx6Token.Packet.TxData->FragmentTable[0].FragmentBuffer); | |
| } | |
| if (Wrap->TcpWrap.Tx6Token.CompletionToken.Event != NULL) { | |
| gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event); | |
| } | |
| } | |
| Wrap->TcpWrap.IsTxDone = TRUE; | |
| // | |
| // Check pending TxTokens and sent out. | |
| // | |
| NetMapIterate (&Wrap->HttpInstance->TxTokens, HttpTcpTransmit, NULL); | |
| } | |
| /** | |
| Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK. | |
| @param Event The receive event delivered to TCP for transmit. | |
| @param Context Context for the callback. | |
| **/ | |
| VOID | |
| EFIAPI | |
| HttpTcpTransmitNotify ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| // | |
| // Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK | |
| // | |
| QueueDpc (TPL_CALLBACK, HttpTcpTransmitNotifyDpc, Context); | |
| } | |
| /** | |
| The notify function associated with Rx4Token for Tcp4->Receive () or Rx6Token for Tcp6->Receive(). | |
| @param[in] Context The context. | |
| **/ | |
| VOID | |
| EFIAPI | |
| HttpTcpReceiveNotifyDpc ( | |
| IN VOID *Context | |
| ) | |
| { | |
| HTTP_TOKEN_WRAP *Wrap; | |
| NET_MAP_ITEM *Item; | |
| UINTN Length; | |
| EFI_STATUS Status; | |
| HTTP_PROTOCOL *HttpInstance; | |
| BOOLEAN UsingIpv6; | |
| if (Context == NULL) { | |
| return ; | |
| } | |
| Wrap = (HTTP_TOKEN_WRAP *) Context; | |
| HttpInstance = Wrap->HttpInstance; | |
| UsingIpv6 = HttpInstance->LocalAddressIsIPv6; | |
| if (UsingIpv6) { | |
| gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event); | |
| Wrap->TcpWrap.Rx6Token.CompletionToken.Event = NULL; | |
| if (EFI_ERROR (Wrap->TcpWrap.Rx6Token.CompletionToken.Status)) { | |
| DEBUG ((EFI_D_ERROR, "HttpTcpReceiveNotifyDpc: %r!\n", Wrap->TcpWrap.Rx6Token.CompletionToken.Status)); | |
| Wrap->HttpToken->Status = Wrap->TcpWrap.Rx6Token.CompletionToken.Status; | |
| gBS->SignalEvent (Wrap->HttpToken->Event); | |
| Item = NetMapFindKey (&HttpInstance->RxTokens, Wrap->HttpToken); | |
| if (Item != NULL) { | |
| NetMapRemoveItem (&HttpInstance->RxTokens, Item, NULL); | |
| } | |
| FreePool (Wrap); | |
| Wrap = NULL; | |
| return ; | |
| } | |
| } else { | |
| gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event); | |
| Wrap->TcpWrap.Rx4Token.CompletionToken.Event = NULL; | |
| if (EFI_ERROR (Wrap->TcpWrap.Rx4Token.CompletionToken.Status)) { | |
| DEBUG ((EFI_D_ERROR, "HttpTcpReceiveNotifyDpc: %r!\n", Wrap->TcpWrap.Rx4Token.CompletionToken.Status)); | |
| Wrap->HttpToken->Status = Wrap->TcpWrap.Rx4Token.CompletionToken.Status; | |
| gBS->SignalEvent (Wrap->HttpToken->Event); | |
| Item = NetMapFindKey (&HttpInstance->RxTokens, Wrap->HttpToken); | |
| if (Item != NULL) { | |
| NetMapRemoveItem (&HttpInstance->RxTokens, Item, NULL); | |
| } | |
| FreePool (Wrap); | |
| Wrap = NULL; | |
| return ; | |
| } | |
| } | |
| // | |
| // Check whether we receive a complete HTTP message. | |
| // | |
| ASSERT (HttpInstance->MsgParser != NULL); | |
| if (UsingIpv6) { | |
| Length = (UINTN) Wrap->TcpWrap.Rx6Data.FragmentTable[0].FragmentLength; | |
| } else { | |
| Length = (UINTN) Wrap->TcpWrap.Rx4Data.FragmentTable[0].FragmentLength; | |
| } | |
| Status = HttpParseMessageBody ( | |
| HttpInstance->MsgParser, | |
| Length, | |
| Wrap->HttpToken->Message->Body | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return ; | |
| } | |
| if (HttpIsMessageComplete (HttpInstance->MsgParser)) { | |
| // | |
| // Free the MsgParse since we already have a full HTTP message. | |
| // | |
| HttpFreeMsgParser (HttpInstance->MsgParser); | |
| HttpInstance->MsgParser = NULL; | |
| } | |
| Wrap->HttpToken->Message->BodyLength = Length; | |
| ASSERT (HttpInstance->CacheBody == NULL); | |
| // | |
| // We receive part of header of next HTTP msg. | |
| // | |
| if (HttpInstance->NextMsg != NULL) { | |
| Wrap->HttpToken->Message->BodyLength = HttpInstance->NextMsg - | |
| (CHAR8 *) Wrap->HttpToken->Message->Body; | |
| HttpInstance->CacheLen = Length - Wrap->HttpToken->Message->BodyLength; | |
| if (HttpInstance->CacheLen != 0) { | |
| HttpInstance->CacheBody = AllocateZeroPool (HttpInstance->CacheLen); | |
| if (HttpInstance->CacheBody == NULL) { | |
| return ; | |
| } | |
| CopyMem (HttpInstance->CacheBody, HttpInstance->NextMsg, HttpInstance->CacheLen); | |
| HttpInstance->NextMsg = HttpInstance->CacheBody; | |
| HttpInstance->CacheOffset = 0; | |
| } | |
| } | |
| Item = NetMapFindKey (&Wrap->HttpInstance->RxTokens, Wrap->HttpToken); | |
| if (Item != NULL) { | |
| NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL); | |
| } | |
| Wrap->TcpWrap.IsRxDone = TRUE; | |
| if (UsingIpv6) { | |
| Wrap->HttpToken->Status = Wrap->TcpWrap.Rx6Token.CompletionToken.Status; | |
| } else { | |
| Wrap->HttpToken->Status = Wrap->TcpWrap.Rx4Token.CompletionToken.Status; | |
| } | |
| gBS->SignalEvent (Wrap->HttpToken->Event); | |
| // | |
| // Check pending RxTokens and receive the HTTP message. | |
| // | |
| NetMapIterate (&Wrap->HttpInstance->RxTokens, HttpTcpReceive, NULL); | |
| FreePool (Wrap); | |
| Wrap = NULL; | |
| } | |
| /** | |
| Request HttpTcpReceiveNotifyDpc as a DPC at TPL_CALLBACK. | |
| @param Event The receive event delivered to TCP for receive. | |
| @param Context Context for the callback. | |
| **/ | |
| VOID | |
| EFIAPI | |
| HttpTcpReceiveNotify ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| // | |
| // Request HttpTcpTransmitNotifyDpc as a DPC at TPL_CALLBACK | |
| // | |
| QueueDpc (TPL_CALLBACK, HttpTcpReceiveNotifyDpc, Context); | |
| } | |
| /** | |
| Create events for the TCP connection token and TCP close token. | |
| @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure. | |
| @retval EFI_SUCCESS The events are created successfully. | |
| @retval others Other error as indicated. | |
| **/ | |
| EFI_STATUS | |
| HttpCreateTcpConnCloseEvent ( | |
| IN HTTP_PROTOCOL *HttpInstance | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| if (!HttpInstance->LocalAddressIsIPv6) { | |
| // | |
| // Create events for variuos asynchronous operations. | |
| // | |
| Status = gBS->CreateEvent ( | |
| EVT_NOTIFY_SIGNAL, | |
| TPL_NOTIFY, | |
| HttpCommonNotify, | |
| &HttpInstance->IsTcp4ConnDone, | |
| &HttpInstance->Tcp4ConnToken.CompletionToken.Event | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto ERROR; | |
| } | |
| // | |
| // Initialize Tcp4CloseToken | |
| // | |
| Status = gBS->CreateEvent ( | |
| EVT_NOTIFY_SIGNAL, | |
| TPL_NOTIFY, | |
| HttpCommonNotify, | |
| &HttpInstance->IsTcp4CloseDone, | |
| &HttpInstance->Tcp4CloseToken.CompletionToken.Event | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto ERROR; | |
| } | |
| } else { | |
| // | |
| // Create events for variuos asynchronous operations. | |
| // | |
| Status = gBS->CreateEvent ( | |
| EVT_NOTIFY_SIGNAL, | |
| TPL_NOTIFY, | |
| HttpCommonNotify, | |
| &HttpInstance->IsTcp6ConnDone, | |
| &HttpInstance->Tcp6ConnToken.CompletionToken.Event | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto ERROR; | |
| } | |
| // | |
| // Initialize Tcp6CloseToken | |
| // | |
| Status = gBS->CreateEvent ( | |
| EVT_NOTIFY_SIGNAL, | |
| TPL_NOTIFY, | |
| HttpCommonNotify, | |
| &HttpInstance->IsTcp6CloseDone, | |
| &HttpInstance->Tcp6CloseToken.CompletionToken.Event | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto ERROR; | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| ERROR: | |
| // | |
| // Error handling | |
| // | |
| HttpCloseTcpConnCloseEvent (HttpInstance); | |
| return Status; | |
| } | |
| /** | |
| Close events in the TCP connection token and TCP close token. | |
| @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure. | |
| **/ | |
| VOID | |
| HttpCloseTcpConnCloseEvent ( | |
| IN HTTP_PROTOCOL *HttpInstance | |
| ) | |
| { | |
| ASSERT (HttpInstance != NULL); | |
| if (HttpInstance->LocalAddressIsIPv6) { | |
| if (NULL != HttpInstance->Tcp6ConnToken.CompletionToken.Event) { | |
| gBS->CloseEvent (HttpInstance->Tcp6ConnToken.CompletionToken.Event); | |
| HttpInstance->Tcp6ConnToken.CompletionToken.Event = NULL; | |
| } | |
| if (NULL != HttpInstance->Tcp6CloseToken.CompletionToken.Event) { | |
| gBS->CloseEvent(HttpInstance->Tcp6CloseToken.CompletionToken.Event); | |
| HttpInstance->Tcp6CloseToken.CompletionToken.Event = NULL; | |
| } | |
| } else { | |
| if (NULL != HttpInstance->Tcp4ConnToken.CompletionToken.Event) { | |
| gBS->CloseEvent (HttpInstance->Tcp4ConnToken.CompletionToken.Event); | |
| HttpInstance->Tcp4ConnToken.CompletionToken.Event = NULL; | |
| } | |
| if (NULL != HttpInstance->Tcp4CloseToken.CompletionToken.Event) { | |
| gBS->CloseEvent(HttpInstance->Tcp4CloseToken.CompletionToken.Event); | |
| HttpInstance->Tcp4CloseToken.CompletionToken.Event = NULL; | |
| } | |
| } | |
| } | |
| /** | |
| Create event for the TCP transmit token. | |
| @param[in] Wrap Point to HTTP token's wrap data. | |
| @retval EFI_SUCCESS The events is created successfully. | |
| @retval others Other error as indicated. | |
| **/ | |
| EFI_STATUS | |
| HttpCreateTcpTxEvent ( | |
| IN HTTP_TOKEN_WRAP *Wrap | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| HTTP_PROTOCOL *HttpInstance; | |
| HTTP_TCP_TOKEN_WRAP *TcpWrap; | |
| HttpInstance = Wrap->HttpInstance; | |
| TcpWrap = &Wrap->TcpWrap; | |
| if (!HttpInstance->LocalAddressIsIPv6) { | |
| Status = gBS->CreateEvent ( | |
| EVT_NOTIFY_SIGNAL, | |
| TPL_NOTIFY, | |
| HttpTcpTransmitNotify, | |
| Wrap, | |
| &TcpWrap->Tx4Token.CompletionToken.Event | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| TcpWrap->Tx4Data.Push = TRUE; | |
| TcpWrap->Tx4Data.Urgent = FALSE; | |
| TcpWrap->Tx4Data.FragmentCount = 1; | |
| TcpWrap->Tx4Token.Packet.TxData = &Wrap->TcpWrap.Tx4Data; | |
| TcpWrap->Tx4Token.CompletionToken.Status = EFI_NOT_READY; | |
| } else { | |
| Status = gBS->CreateEvent ( | |
| EVT_NOTIFY_SIGNAL, | |
| TPL_NOTIFY, | |
| HttpTcpTransmitNotify, | |
| Wrap, | |
| &TcpWrap->Tx6Token.CompletionToken.Event | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| TcpWrap->Tx6Data.Push = TRUE; | |
| TcpWrap->Tx6Data.Urgent = FALSE; | |
| TcpWrap->Tx6Data.FragmentCount = 1; | |
| TcpWrap->Tx6Token.Packet.TxData = &Wrap->TcpWrap.Tx6Data; | |
| TcpWrap->Tx6Token.CompletionToken.Status =EFI_NOT_READY; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Create event for the TCP receive token which is used to receive HTTP header. | |
| @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure. | |
| @retval EFI_SUCCESS The events is created successfully. | |
| @retval others Other error as indicated. | |
| **/ | |
| EFI_STATUS | |
| HttpCreateTcpRxEventForHeader ( | |
| IN HTTP_PROTOCOL *HttpInstance | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| if (!HttpInstance->LocalAddressIsIPv6) { | |
| Status = gBS->CreateEvent ( | |
| EVT_NOTIFY_SIGNAL, | |
| TPL_NOTIFY, | |
| HttpCommonNotify, | |
| &HttpInstance->IsRxDone, | |
| &HttpInstance->Rx4Token.CompletionToken.Event | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| HttpInstance->Rx4Data.FragmentCount = 1; | |
| HttpInstance->Rx4Token.Packet.RxData = &HttpInstance->Rx4Data; | |
| HttpInstance->Rx4Token.CompletionToken.Status = EFI_NOT_READY; | |
| } else { | |
| Status = gBS->CreateEvent ( | |
| EVT_NOTIFY_SIGNAL, | |
| TPL_NOTIFY, | |
| HttpCommonNotify, | |
| &HttpInstance->IsRxDone, | |
| &HttpInstance->Rx6Token.CompletionToken.Event | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| HttpInstance->Rx6Data.FragmentCount =1; | |
| HttpInstance->Rx6Token.Packet.RxData = &HttpInstance->Rx6Data; | |
| HttpInstance->Rx6Token.CompletionToken.Status = EFI_NOT_READY; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Create event for the TCP receive token which is used to receive HTTP body. | |
| @param[in] Wrap Point to HTTP token's wrap data. | |
| @retval EFI_SUCCESS The events is created successfully. | |
| @retval others Other error as indicated. | |
| **/ | |
| EFI_STATUS | |
| HttpCreateTcpRxEvent ( | |
| IN HTTP_TOKEN_WRAP *Wrap | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| HTTP_PROTOCOL *HttpInstance; | |
| HTTP_TCP_TOKEN_WRAP *TcpWrap; | |
| HttpInstance = Wrap->HttpInstance; | |
| TcpWrap = &Wrap->TcpWrap; | |
| if (!HttpInstance->LocalAddressIsIPv6) { | |
| Status = gBS->CreateEvent ( | |
| EVT_NOTIFY_SIGNAL, | |
| TPL_NOTIFY, | |
| HttpTcpReceiveNotify, | |
| Wrap, | |
| &TcpWrap->Rx4Token.CompletionToken.Event | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| TcpWrap->Rx4Data.FragmentCount = 1; | |
| TcpWrap->Rx4Token.Packet.RxData = &Wrap->TcpWrap.Rx4Data; | |
| TcpWrap->Rx4Token.CompletionToken.Status = EFI_NOT_READY; | |
| } else { | |
| Status = gBS->CreateEvent ( | |
| EVT_NOTIFY_SIGNAL, | |
| TPL_NOTIFY, | |
| HttpTcpReceiveNotify, | |
| Wrap, | |
| &TcpWrap->Rx6Token.CompletionToken.Event | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| TcpWrap->Rx6Data.FragmentCount = 1; | |
| TcpWrap->Rx6Token.Packet.RxData = &Wrap->TcpWrap.Rx6Data; | |
| TcpWrap->Rx6Token.CompletionToken.Status = EFI_NOT_READY; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Close Events for Tcp Receive Tokens for HTTP body and HTTP header. | |
| @param[in] Wrap Pointer to HTTP token's wrap data. | |
| **/ | |
| VOID | |
| HttpCloseTcpRxEvent ( | |
| IN HTTP_TOKEN_WRAP *Wrap | |
| ) | |
| { | |
| HTTP_PROTOCOL *HttpInstance; | |
| ASSERT (Wrap != NULL); | |
| HttpInstance = Wrap->HttpInstance; | |
| if (HttpInstance->LocalAddressIsIPv6) { | |
| if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) { | |
| gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event); | |
| } | |
| if (HttpInstance->Rx6Token.CompletionToken.Event != NULL) { | |
| gBS->CloseEvent (HttpInstance->Rx6Token.CompletionToken.Event); | |
| HttpInstance->Rx6Token.CompletionToken.Event = NULL; | |
| } | |
| } else { | |
| if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) { | |
| gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event); | |
| } | |
| if (HttpInstance->Rx4Token.CompletionToken.Event != NULL) { | |
| gBS->CloseEvent (HttpInstance->Rx4Token.CompletionToken.Event); | |
| HttpInstance->Rx4Token.CompletionToken.Event = NULL; | |
| } | |
| } | |
| } | |
| /** | |
| Intiialize the HTTP_PROTOCOL structure to the unconfigured state. | |
| @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure. | |
| @param[in] IpVersion Indicate us TCP4 protocol or TCP6 protocol. | |
| @retval EFI_SUCCESS HTTP_PROTOCOL structure is initialized successfully. | |
| @retval Others Other error as indicated. | |
| **/ | |
| EFI_STATUS | |
| HttpInitProtocol ( | |
| IN OUT HTTP_PROTOCOL *HttpInstance, | |
| IN BOOLEAN IpVersion | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| VOID *Interface; | |
| BOOLEAN UsingIpv6; | |
| ASSERT (HttpInstance != NULL); | |
| UsingIpv6 = IpVersion; | |
| if (!UsingIpv6) { | |
| // | |
| // Create TCP4 child. | |
| // | |
| Status = NetLibCreateServiceChild ( | |
| HttpInstance->Service->ControllerHandle, | |
| HttpInstance->Service->ImageHandle, | |
| &gEfiTcp4ServiceBindingProtocolGuid, | |
| &HttpInstance->Tcp4ChildHandle | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto ON_ERROR; | |
| } | |
| Status = gBS->OpenProtocol ( | |
| HttpInstance->Tcp4ChildHandle, | |
| &gEfiTcp4ProtocolGuid, | |
| (VOID **) &Interface, | |
| HttpInstance->Service->ImageHandle, | |
| HttpInstance->Service->ControllerHandle, | |
| EFI_OPEN_PROTOCOL_BY_DRIVER | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto ON_ERROR; | |
| } | |
| Status = gBS->OpenProtocol ( | |
| HttpInstance->Tcp4ChildHandle, | |
| &gEfiTcp4ProtocolGuid, | |
| (VOID **) &HttpInstance->Tcp4, | |
| HttpInstance->Service->ImageHandle, | |
| HttpInstance->Handle, | |
| EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER | |
| ); | |
| if (EFI_ERROR(Status)) { | |
| goto ON_ERROR; | |
| } | |
| Status = gBS->OpenProtocol ( | |
| HttpInstance->Service->Tcp4ChildHandle, | |
| &gEfiTcp4ProtocolGuid, | |
| (VOID **) &Interface, | |
| HttpInstance->Service->ImageHandle, | |
| HttpInstance->Handle, | |
| EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER | |
| ); | |
| if (EFI_ERROR(Status)) { | |
| goto ON_ERROR; | |
| } | |
| } else { | |
| // | |
| // Create TCP6 Child. | |
| // | |
| Status = NetLibCreateServiceChild ( | |
| HttpInstance->Service->ControllerHandle, | |
| HttpInstance->Service->ImageHandle, | |
| &gEfiTcp6ServiceBindingProtocolGuid, | |
| &HttpInstance->Tcp6ChildHandle | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto ON_ERROR; | |
| } | |
| Status = gBS->OpenProtocol ( | |
| HttpInstance->Tcp6ChildHandle, | |
| &gEfiTcp6ProtocolGuid, | |
| (VOID **) &Interface, | |
| HttpInstance->Service->ImageHandle, | |
| HttpInstance->Service->ControllerHandle, | |
| EFI_OPEN_PROTOCOL_BY_DRIVER | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto ON_ERROR; | |
| } | |
| Status = gBS->OpenProtocol ( | |
| HttpInstance->Tcp6ChildHandle, | |
| &gEfiTcp6ProtocolGuid, | |
| (VOID **) &HttpInstance->Tcp6, | |
| HttpInstance->Service->ImageHandle, | |
| HttpInstance->Handle, | |
| EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER | |
| ); | |
| if (EFI_ERROR(Status)) { | |
| goto ON_ERROR; | |
| } | |
| Status = gBS->OpenProtocol ( | |
| HttpInstance->Service->Tcp6ChildHandle, | |
| &gEfiTcp6ProtocolGuid, | |
| (VOID **) &Interface, | |
| HttpInstance->Service->ImageHandle, | |
| HttpInstance->Handle, | |
| EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER | |
| ); | |
| if (EFI_ERROR(Status)) { | |
| goto ON_ERROR; | |
| } | |
| } | |
| HttpInstance->Url = AllocateZeroPool (HTTP_URL_BUFFER_LEN); | |
| if (HttpInstance->Url == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto ON_ERROR; | |
| } | |
| return EFI_SUCCESS; | |
| ON_ERROR: | |
| if (HttpInstance->Tcp4ChildHandle != NULL) { | |
| gBS->CloseProtocol ( | |
| HttpInstance->Tcp4ChildHandle, | |
| &gEfiTcp4ProtocolGuid, | |
| HttpInstance->Service->ImageHandle, | |
| HttpInstance->Service->ControllerHandle | |
| ); | |
| gBS->CloseProtocol ( | |
| HttpInstance->Tcp4ChildHandle, | |
| &gEfiTcp4ProtocolGuid, | |
| HttpInstance->Service->ImageHandle, | |
| HttpInstance->Handle | |
| ); | |
| NetLibDestroyServiceChild ( | |
| HttpInstance->Service->ControllerHandle, | |
| HttpInstance->Service->ImageHandle, | |
| &gEfiTcp4ServiceBindingProtocolGuid, | |
| HttpInstance->Tcp4ChildHandle | |
| ); | |
| } | |
| if (HttpInstance->Service->Tcp4ChildHandle != NULL) { | |
| gBS->CloseProtocol ( | |
| HttpInstance->Service->Tcp4ChildHandle, | |
| &gEfiTcp4ProtocolGuid, | |
| HttpInstance->Service->ImageHandle, | |
| HttpInstance->Handle | |
| ); | |
| } | |
| if (HttpInstance->Tcp6ChildHandle != NULL) { | |
| gBS->CloseProtocol ( | |
| HttpInstance->Tcp6ChildHandle, | |
| &gEfiTcp6ProtocolGuid, | |
| HttpInstance->Service->ImageHandle, | |
| HttpInstance->Service->ControllerHandle | |
| ); | |
| gBS->CloseProtocol ( | |
| HttpInstance->Tcp6ChildHandle, | |
| &gEfiTcp6ProtocolGuid, | |
| HttpInstance->Service->ImageHandle, | |
| HttpInstance->Handle | |
| ); | |
| NetLibDestroyServiceChild ( | |
| HttpInstance->Service->ControllerHandle, | |
| HttpInstance->Service->ImageHandle, | |
| &gEfiTcp6ServiceBindingProtocolGuid, | |
| HttpInstance->Tcp6ChildHandle | |
| ); | |
| } | |
| if (HttpInstance->Service->Tcp6ChildHandle != NULL) { | |
| gBS->CloseProtocol ( | |
| HttpInstance->Service->Tcp6ChildHandle, | |
| &gEfiTcp6ProtocolGuid, | |
| HttpInstance->Service->ImageHandle, | |
| HttpInstance->Handle | |
| ); | |
| } | |
| return EFI_UNSUPPORTED; | |
| } | |
| /** | |
| Clean up the HTTP child, release all the resources used by it. | |
| @param[in] HttpInstance The HTTP child to clean up. | |
| **/ | |
| VOID | |
| HttpCleanProtocol ( | |
| IN HTTP_PROTOCOL *HttpInstance | |
| ) | |
| { | |
| 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; | |
| } | |
| if (HttpInstance->RemoteHost != NULL) { | |
| FreePool (HttpInstance->RemoteHost); | |
| HttpInstance->RemoteHost = NULL; | |
| } | |
| if (HttpInstance->MsgParser != NULL) { | |
| HttpFreeMsgParser (HttpInstance->MsgParser); | |
| HttpInstance->MsgParser = NULL; | |
| } | |
| if (HttpInstance->Url != NULL) { | |
| FreePool (HttpInstance->Url); | |
| HttpInstance->Url = NULL; | |
| } | |
| NetMapClean (&HttpInstance->TxTokens); | |
| NetMapClean (&HttpInstance->RxTokens); | |
| if (HttpInstance->Tcp4ChildHandle != NULL) { | |
| gBS->CloseProtocol ( | |
| HttpInstance->Tcp4ChildHandle, | |
| &gEfiTcp4ProtocolGuid, | |
| HttpInstance->Service->ImageHandle, | |
| HttpInstance->Service->ControllerHandle | |
| ); | |
| gBS->CloseProtocol ( | |
| HttpInstance->Tcp4ChildHandle, | |
| &gEfiTcp4ProtocolGuid, | |
| HttpInstance->Service->ImageHandle, | |
| HttpInstance->Handle | |
| ); | |
| NetLibDestroyServiceChild ( | |
| HttpInstance->Service->ControllerHandle, | |
| HttpInstance->Service->ImageHandle, | |
| &gEfiTcp4ServiceBindingProtocolGuid, | |
| HttpInstance->Tcp4ChildHandle | |
| ); | |
| } | |
| if (HttpInstance->Service->Tcp4ChildHandle != NULL) { | |
| gBS->CloseProtocol ( | |
| HttpInstance->Service->Tcp4ChildHandle, | |
| &gEfiTcp4ProtocolGuid, | |
| HttpInstance->Service->ImageHandle, | |
| HttpInstance->Handle | |
| ); | |
| } | |
| if (HttpInstance->Tcp6ChildHandle != NULL) { | |
| gBS->CloseProtocol ( | |
| HttpInstance->Tcp6ChildHandle, | |
| &gEfiTcp6ProtocolGuid, | |
| HttpInstance->Service->ImageHandle, | |
| HttpInstance->Service->ControllerHandle | |
| ); | |
| gBS->CloseProtocol ( | |
| HttpInstance->Tcp6ChildHandle, | |
| &gEfiTcp6ProtocolGuid, | |
| HttpInstance->Service->ImageHandle, | |
| HttpInstance->Handle | |
| ); | |
| NetLibDestroyServiceChild ( | |
| HttpInstance->Service->ControllerHandle, | |
| HttpInstance->Service->ImageHandle, | |
| &gEfiTcp6ServiceBindingProtocolGuid, | |
| HttpInstance->Tcp6ChildHandle | |
| ); | |
| } | |
| if (HttpInstance->Service->Tcp6ChildHandle != NULL) { | |
| gBS->CloseProtocol ( | |
| HttpInstance->Service->Tcp6ChildHandle, | |
| &gEfiTcp6ProtocolGuid, | |
| HttpInstance->Service->ImageHandle, | |
| HttpInstance->Handle | |
| ); | |
| } | |
| TlsCloseTxRxEvent (HttpInstance); | |
| } | |
| /** | |
| Establish TCP connection with HTTP server. | |
| @param[in] HttpInstance The HTTP instance private data. | |
| @retval EFI_SUCCESS The TCP connection is established. | |
| @retval Others Other error as indicated. | |
| **/ | |
| EFI_STATUS | |
| HttpCreateConnection ( | |
| IN HTTP_PROTOCOL *HttpInstance | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| // | |
| // Connect to Http server | |
| // | |
| if (!HttpInstance->LocalAddressIsIPv6) { | |
| HttpInstance->IsTcp4ConnDone = FALSE; | |
| HttpInstance->Tcp4ConnToken.CompletionToken.Status = EFI_NOT_READY; | |
| Status = HttpInstance->Tcp4->Connect (HttpInstance->Tcp4, &HttpInstance->Tcp4ConnToken); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp4->Connect() = %r\n", Status)); | |
| return Status; | |
| } | |
| while (!HttpInstance->IsTcp4ConnDone) { | |
| HttpInstance->Tcp4->Poll (HttpInstance->Tcp4); | |
| } | |
| Status = HttpInstance->Tcp4ConnToken.CompletionToken.Status; | |
| } else { | |
| HttpInstance->IsTcp6ConnDone = FALSE; | |
| HttpInstance->Tcp6ConnToken.CompletionToken.Status = EFI_NOT_READY; | |
| Status = HttpInstance->Tcp6->Connect (HttpInstance->Tcp6, &HttpInstance->Tcp6ConnToken); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((EFI_D_ERROR, "HttpCreateConnection: Tcp6->Connect() = %r\n", Status)); | |
| return Status; | |
| } | |
| while(!HttpInstance->IsTcp6ConnDone) { | |
| HttpInstance->Tcp6->Poll (HttpInstance->Tcp6); | |
| } | |
| Status = HttpInstance->Tcp6ConnToken.CompletionToken.Status; | |
| } | |
| if (!EFI_ERROR (Status)) { | |
| HttpInstance->State = HTTP_STATE_TCP_CONNECTED; | |
| } | |
| return Status; | |
| } | |
| /** | |
| Close existing TCP connection. | |
| @param[in] HttpInstance The HTTP instance private data. | |
| @retval EFI_SUCCESS The TCP connection is closed. | |
| @retval Others Other error as indicated. | |
| **/ | |
| EFI_STATUS | |
| HttpCloseConnection ( | |
| IN HTTP_PROTOCOL *HttpInstance | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| if (HttpInstance->State == HTTP_STATE_TCP_CONNECTED) { | |
| if (HttpInstance->LocalAddressIsIPv6) { | |
| HttpInstance->Tcp6CloseToken.AbortOnClose = TRUE; | |
| HttpInstance->IsTcp6CloseDone = FALSE; | |
| Status = HttpInstance->Tcp6->Close (HttpInstance->Tcp6, &HttpInstance->Tcp6CloseToken); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| while (!HttpInstance->IsTcp6CloseDone) { | |
| HttpInstance->Tcp6->Poll (HttpInstance->Tcp6); | |
| } | |
| } else { | |
| HttpInstance->Tcp4CloseToken.AbortOnClose = TRUE; | |
| HttpInstance->IsTcp4CloseDone = FALSE; | |
| Status = HttpInstance->Tcp4->Close (HttpInstance->Tcp4, &HttpInstance->Tcp4CloseToken); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| while (!HttpInstance->IsTcp4CloseDone) { | |
| HttpInstance->Tcp4->Poll (HttpInstance->Tcp4); | |
| } | |
| } | |
| } | |
| HttpInstance->State = HTTP_STATE_TCP_CLOSED; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Configure TCP4 protocol child. | |
| @param[in] HttpInstance The HTTP instance private data. | |
| @param[in] Wrap The HTTP token's wrap data. | |
| @retval EFI_SUCCESS The TCP4 protocol child is configured. | |
| @retval Others Other error as indicated. | |
| **/ | |
| EFI_STATUS | |
| HttpConfigureTcp4 ( | |
| IN HTTP_PROTOCOL *HttpInstance, | |
| IN HTTP_TOKEN_WRAP *Wrap | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_TCP4_CONFIG_DATA *Tcp4CfgData; | |
| EFI_TCP4_ACCESS_POINT *Tcp4AP; | |
| EFI_TCP4_OPTION *Tcp4Option; | |
| ASSERT (HttpInstance != NULL); | |
| Tcp4CfgData = &HttpInstance->Tcp4CfgData; | |
| ZeroMem (Tcp4CfgData, sizeof (EFI_TCP4_CONFIG_DATA)); | |
| Tcp4CfgData->TypeOfService = HTTP_TOS_DEAULT; | |
| Tcp4CfgData->TimeToLive = HTTP_TTL_DEAULT; | |
| Tcp4CfgData->ControlOption = &HttpInstance->Tcp4Option; | |
| Tcp4AP = &Tcp4CfgData->AccessPoint; | |
| Tcp4AP->UseDefaultAddress = HttpInstance->IPv4Node.UseDefaultAddress; | |
| if (!Tcp4AP->UseDefaultAddress) { | |
| IP4_COPY_ADDRESS (&Tcp4AP->StationAddress, &HttpInstance->IPv4Node.LocalAddress); | |
| IP4_COPY_ADDRESS (&Tcp4AP->SubnetMask, &HttpInstance->IPv4Node.LocalSubnet); | |
| } | |
| Tcp4AP->StationPort = HttpInstance->IPv4Node.LocalPort; | |
| Tcp4AP->RemotePort = HttpInstance->RemotePort; | |
| Tcp4AP->ActiveFlag = TRUE; | |
| IP4_COPY_ADDRESS (&Tcp4AP->RemoteAddress, &HttpInstance->RemoteAddr); | |
| Tcp4Option = Tcp4CfgData->ControlOption; | |
| Tcp4Option->ReceiveBufferSize = HTTP_BUFFER_SIZE_DEAULT; | |
| Tcp4Option->SendBufferSize = HTTP_BUFFER_SIZE_DEAULT; | |
| Tcp4Option->MaxSynBackLog = HTTP_MAX_SYN_BACK_LOG; | |
| Tcp4Option->ConnectionTimeout = HTTP_CONNECTION_TIMEOUT; | |
| Tcp4Option->DataRetries = HTTP_DATA_RETRIES; | |
| Tcp4Option->FinTimeout = HTTP_FIN_TIMEOUT; | |
| Tcp4Option->KeepAliveProbes = HTTP_KEEP_ALIVE_PROBES; | |
| Tcp4Option->KeepAliveTime = HTTP_KEEP_ALIVE_TIME; | |
| Tcp4Option->KeepAliveInterval = HTTP_KEEP_ALIVE_INTERVAL; | |
| Tcp4Option->EnableNagle = TRUE; | |
| Tcp4CfgData->ControlOption = Tcp4Option; | |
| Status = HttpInstance->Tcp4->Configure (HttpInstance->Tcp4, Tcp4CfgData); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((EFI_D_ERROR, "HttpConfigureTcp4 - %r\n", Status)); | |
| return Status; | |
| } | |
| Status = HttpCreateTcpConnCloseEvent (HttpInstance); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| Status = HttpCreateTcpTxEvent (Wrap); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| HttpInstance->State = HTTP_STATE_TCP_CONFIGED; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Configure TCP6 protocol child. | |
| @param[in] HttpInstance The HTTP instance private data. | |
| @param[in] Wrap The HTTP token's wrap data. | |
| @retval EFI_SUCCESS The TCP6 protocol child is configured. | |
| @retval Others Other error as indicated. | |
| **/ | |
| EFI_STATUS | |
| HttpConfigureTcp6 ( | |
| IN HTTP_PROTOCOL *HttpInstance, | |
| IN HTTP_TOKEN_WRAP *Wrap | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_TCP6_CONFIG_DATA *Tcp6CfgData; | |
| EFI_TCP6_ACCESS_POINT *Tcp6Ap; | |
| EFI_TCP6_OPTION *Tcp6Option; | |
| ASSERT (HttpInstance != NULL); | |
| Tcp6CfgData = &HttpInstance->Tcp6CfgData; | |
| ZeroMem (Tcp6CfgData, sizeof (EFI_TCP6_CONFIG_DATA)); | |
| Tcp6CfgData->TrafficClass = 0; | |
| Tcp6CfgData->HopLimit = 255; | |
| Tcp6CfgData->ControlOption = &HttpInstance->Tcp6Option; | |
| Tcp6Ap = &Tcp6CfgData->AccessPoint; | |
| Tcp6Ap->ActiveFlag = TRUE; | |
| Tcp6Ap->StationPort = HttpInstance->Ipv6Node.LocalPort; | |
| Tcp6Ap->RemotePort = HttpInstance->RemotePort; | |
| IP6_COPY_ADDRESS (&Tcp6Ap->StationAddress, &HttpInstance->Ipv6Node.LocalAddress); | |
| IP6_COPY_ADDRESS (&Tcp6Ap->RemoteAddress , &HttpInstance->RemoteIpv6Addr); | |
| Tcp6Option = Tcp6CfgData->ControlOption; | |
| Tcp6Option->ReceiveBufferSize = HTTP_BUFFER_SIZE_DEAULT; | |
| Tcp6Option->SendBufferSize = HTTP_BUFFER_SIZE_DEAULT; | |
| Tcp6Option->MaxSynBackLog = HTTP_MAX_SYN_BACK_LOG; | |
| Tcp6Option->ConnectionTimeout = HTTP_CONNECTION_TIMEOUT; | |
| Tcp6Option->DataRetries = HTTP_DATA_RETRIES; | |
| Tcp6Option->FinTimeout = HTTP_FIN_TIMEOUT; | |
| Tcp6Option->KeepAliveProbes = HTTP_KEEP_ALIVE_PROBES; | |
| Tcp6Option->KeepAliveTime = HTTP_KEEP_ALIVE_TIME; | |
| Tcp6Option->KeepAliveInterval = HTTP_KEEP_ALIVE_INTERVAL; | |
| Tcp6Option->EnableNagle = TRUE; | |
| Status = HttpInstance->Tcp6->Configure (HttpInstance->Tcp6, Tcp6CfgData); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((EFI_D_ERROR, "HttpConfigureTcp6 - %r\n", Status)); | |
| return Status; | |
| } | |
| Status = HttpCreateTcpConnCloseEvent (HttpInstance); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| Status = HttpCreateTcpTxEvent (Wrap); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| HttpInstance->State = HTTP_STATE_TCP_CONFIGED; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Check existing TCP connection, if in error state, recover TCP4 connection. Then, | |
| connect one TLS session if required. | |
| @param[in] HttpInstance The HTTP instance private data. | |
| @retval EFI_SUCCESS The TCP connection is established. | |
| @retval EFI_NOT_READY TCP4 protocol child is not created or configured. | |
| @retval Others Other error as indicated. | |
| **/ | |
| EFI_STATUS | |
| HttpConnectTcp4 ( | |
| IN HTTP_PROTOCOL *HttpInstance | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_TCP4_CONNECTION_STATE Tcp4State; | |
| if (HttpInstance->State < HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp4 == NULL) { | |
| return EFI_NOT_READY; | |
| } | |
| Status = HttpInstance->Tcp4->GetModeData( | |
| HttpInstance->Tcp4, | |
| &Tcp4State, | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL | |
| ); | |
| if (EFI_ERROR(Status)){ | |
| DEBUG ((EFI_D_ERROR, "Tcp4 GetModeData fail - %x\n", Status)); | |
| return Status; | |
| } | |
| if (Tcp4State == Tcp4StateEstablished) { | |
| return EFI_SUCCESS; | |
| } else if (Tcp4State > Tcp4StateEstablished ) { | |
| HttpCloseConnection(HttpInstance); | |
| } | |
| Status = HttpCreateConnection (HttpInstance); | |
| if (EFI_ERROR(Status)){ | |
| DEBUG ((EFI_D_ERROR, "Tcp4 Connection fail - %x\n", Status)); | |
| return Status; | |
| } | |
| // | |
| // Tls session connection. | |
| // | |
| if (HttpInstance->UseHttps) { | |
| if (HttpInstance->TimeoutEvent == NULL) { | |
| // | |
| // Create TimeoutEvent for TLS connection. | |
| // | |
| Status = gBS->CreateEvent ( | |
| EVT_TIMER, | |
| TPL_CALLBACK, | |
| NULL, | |
| NULL, | |
| &HttpInstance->TimeoutEvent | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| TlsCloseTxRxEvent (HttpInstance); | |
| return Status; | |
| } | |
| } | |
| // | |
| // Start the timer, and wait Timeout seconds for connection. | |
| // | |
| Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND); | |
| if (EFI_ERROR (Status)) { | |
| TlsCloseTxRxEvent (HttpInstance); | |
| return Status; | |
| } | |
| Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent); | |
| gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0); | |
| if (EFI_ERROR (Status)) { | |
| TlsCloseTxRxEvent (HttpInstance); | |
| return Status; | |
| } | |
| } | |
| return Status; | |
| } | |
| /** | |
| Check existing TCP connection, if in error state, recover TCP6 connection. Then, | |
| connect one TLS session if required. | |
| @param[in] HttpInstance The HTTP instance private data. | |
| @retval EFI_SUCCESS The TCP connection is established. | |
| @retval EFI_NOT_READY TCP6 protocol child is not created or configured. | |
| @retval Others Other error as indicated. | |
| **/ | |
| EFI_STATUS | |
| HttpConnectTcp6 ( | |
| IN HTTP_PROTOCOL *HttpInstance | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_TCP6_CONNECTION_STATE Tcp6State; | |
| if (HttpInstance->State < HTTP_STATE_TCP_CONFIGED || HttpInstance->Tcp6 == NULL) { | |
| return EFI_NOT_READY; | |
| } | |
| Status = HttpInstance->Tcp6->GetModeData ( | |
| HttpInstance->Tcp6, | |
| &Tcp6State, | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL | |
| ); | |
| if (EFI_ERROR(Status)){ | |
| DEBUG ((EFI_D_ERROR, "Tcp6 GetModeData fail - %x\n", Status)); | |
| return Status; | |
| } | |
| if (Tcp6State == Tcp6StateEstablished) { | |
| return EFI_SUCCESS; | |
| } else if (Tcp6State > Tcp6StateEstablished ) { | |
| HttpCloseConnection(HttpInstance); | |
| } | |
| Status = HttpCreateConnection (HttpInstance); | |
| if (EFI_ERROR(Status)){ | |
| DEBUG ((EFI_D_ERROR, "Tcp6 Connection fail - %x\n", Status)); | |
| return Status; | |
| } | |
| // | |
| // Tls session connection. | |
| // | |
| if (HttpInstance->UseHttps) { | |
| if (HttpInstance->TimeoutEvent == NULL) { | |
| // | |
| // Create TimeoutEvent for TLS connection. | |
| // | |
| Status = gBS->CreateEvent ( | |
| EVT_TIMER, | |
| TPL_CALLBACK, | |
| NULL, | |
| NULL, | |
| &HttpInstance->TimeoutEvent | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| TlsCloseTxRxEvent (HttpInstance); | |
| return Status; | |
| } | |
| } | |
| // | |
| // Start the timer, and wait Timeout seconds for connection. | |
| // | |
| Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND); | |
| if (EFI_ERROR (Status)) { | |
| TlsCloseTxRxEvent (HttpInstance); | |
| return Status; | |
| } | |
| Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent); | |
| gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0); | |
| if (EFI_ERROR (Status)) { | |
| TlsCloseTxRxEvent (HttpInstance); | |
| return Status; | |
| } | |
| } | |
| return Status; | |
| } | |
| /** | |
| Initialize Http session. | |
| @param[in] HttpInstance The HTTP instance private data. | |
| @param[in] Wrap The HTTP token's wrap data. | |
| @param[in] Configure The Flag indicates whether need to initialize session. | |
| @param[in] TlsConfigure The Flag indicates whether it's the new Tls session. | |
| @retval EFI_SUCCESS The initialization of session is done. | |
| @retval Others Other error as indicated. | |
| **/ | |
| EFI_STATUS | |
| HttpInitSession ( | |
| IN HTTP_PROTOCOL *HttpInstance, | |
| IN HTTP_TOKEN_WRAP *Wrap, | |
| IN BOOLEAN Configure, | |
| IN BOOLEAN TlsConfigure | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| ASSERT (HttpInstance != NULL); | |
| // | |
| // Configure Tls session. | |
| // | |
| if (TlsConfigure) { | |
| Status = TlsConfigureSession (HttpInstance); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| } | |
| if (!HttpInstance->LocalAddressIsIPv6) { | |
| // | |
| // Configure TCP instance. | |
| // | |
| if (Configure) { | |
| Status = HttpConfigureTcp4 (HttpInstance, Wrap); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| } | |
| // | |
| // Connect TCP. | |
| // | |
| Status = HttpConnectTcp4 (HttpInstance); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| } else { | |
| // | |
| // Configure TCP instance. | |
| // | |
| if (Configure) { | |
| Status = HttpConfigureTcp6 (HttpInstance, Wrap); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| } | |
| // | |
| // Connect TCP. | |
| // | |
| Status = HttpConnectTcp6 (HttpInstance); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Send the HTTP or HTTPS message through TCP4 or TCP6. | |
| @param[in] HttpInstance The HTTP instance private data. | |
| @param[in] Wrap The HTTP token's wrap data. | |
| @param[in] TxString Buffer containing the HTTP message string. | |
| @param[in] TxStringLen Length of the HTTP message string in bytes. | |
| @retval EFI_SUCCESS The HTTP message is queued into TCP transmit queue. | |
| @retval Others Other error as indicated. | |
| **/ | |
| EFI_STATUS | |
| HttpTransmitTcp ( | |
| IN HTTP_PROTOCOL *HttpInstance, | |
| IN HTTP_TOKEN_WRAP *Wrap, | |
| IN UINT8 *TxString, | |
| IN UINTN TxStringLen | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_TCP4_IO_TOKEN *Tx4Token; | |
| EFI_TCP4_PROTOCOL *Tcp4; | |
| EFI_TCP6_IO_TOKEN *Tx6Token; | |
| EFI_TCP6_PROTOCOL *Tcp6; | |
| UINT8 *Buffer; | |
| UINTN BufferSize; | |
| NET_FRAGMENT TempFragment; | |
| Status = EFI_SUCCESS; | |
| Buffer = NULL; | |
| // | |
| // Need to encrypt data. | |
| // | |
| if (HttpInstance->UseHttps) { | |
| // | |
| // Build BufferOut data | |
| // | |
| BufferSize = sizeof (TLS_RECORD_HEADER) + TxStringLen; | |
| Buffer = AllocateZeroPool (BufferSize); | |
| if (Buffer == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| return Status; | |
| } | |
| ((TLS_RECORD_HEADER *) Buffer)->ContentType = TLS_CONTENT_TYPE_APPLICATION_DATA; | |
| ((TLS_RECORD_HEADER *) Buffer)->Version.Major = HttpInstance->TlsConfigData.Version.Major; | |
| ((TLS_RECORD_HEADER *) Buffer)->Version.Minor = HttpInstance->TlsConfigData.Version.Minor; | |
| ((TLS_RECORD_HEADER *) Buffer)->Length = (UINT16) (TxStringLen); | |
| CopyMem (Buffer + sizeof (TLS_RECORD_HEADER), TxString, TxStringLen); | |
| // | |
| // Encrypt Packet. | |
| // | |
| Status = TlsProcessMessage ( | |
| HttpInstance, | |
| Buffer, | |
| BufferSize, | |
| EfiTlsEncrypt, | |
| &TempFragment | |
| ); | |
| FreePool (Buffer); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| } | |
| if (!HttpInstance->LocalAddressIsIPv6) { | |
| Tcp4 = HttpInstance->Tcp4; | |
| Tx4Token = &Wrap->TcpWrap.Tx4Token; | |
| if (HttpInstance->UseHttps) { | |
| Tx4Token->Packet.TxData->DataLength = TempFragment.Len; | |
| Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = TempFragment.Len; | |
| Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TempFragment.Bulk; | |
| } else { | |
| Tx4Token->Packet.TxData->DataLength = (UINT32) TxStringLen; | |
| Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen; | |
| Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString; | |
| } | |
| Tx4Token->CompletionToken.Status = EFI_NOT_READY; | |
| Wrap->TcpWrap.IsTxDone = FALSE; | |
| Status = Tcp4->Transmit (Tcp4, Tx4Token); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status)); | |
| return Status; | |
| } | |
| } else { | |
| Tcp6 = HttpInstance->Tcp6; | |
| Tx6Token = &Wrap->TcpWrap.Tx6Token; | |
| if (HttpInstance->UseHttps) { | |
| Tx6Token->Packet.TxData->DataLength = TempFragment.Len; | |
| Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = TempFragment.Len; | |
| Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TempFragment.Bulk; | |
| } else { | |
| Tx6Token->Packet.TxData->DataLength = (UINT32) TxStringLen; | |
| Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen; | |
| Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString; | |
| } | |
| Tx6Token->CompletionToken.Status = EFI_NOT_READY; | |
| Wrap->TcpWrap.IsTxDone = FALSE; | |
| Status = Tcp6->Transmit (Tcp6, Tx6Token); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status)); | |
| return Status; | |
| } | |
| } | |
| return Status; | |
| } | |
| /** | |
| Check whether the user's token or event has already | |
| been enqueue on HTTP Tx or Rx Token list. | |
| @param[in] Map The container of either user's transmit or receive | |
| token. | |
| @param[in] Item Current item to check against. | |
| @param[in] Context The Token to check againist. | |
| @retval EFI_ACCESS_DENIED The token or event has already been enqueued in IP | |
| @retval EFI_SUCCESS The current item isn't the same token/event as the | |
| context. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| HttpTokenExist ( | |
| IN NET_MAP *Map, | |
| IN NET_MAP_ITEM *Item, | |
| IN VOID *Context | |
| ) | |
| { | |
| EFI_HTTP_TOKEN *Token; | |
| EFI_HTTP_TOKEN *TokenInItem; | |
| Token = (EFI_HTTP_TOKEN *) Context; | |
| TokenInItem = (EFI_HTTP_TOKEN *) Item->Key; | |
| if (Token == TokenInItem || Token->Event == TokenInItem->Event) { | |
| return EFI_ACCESS_DENIED; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Check whether the HTTP message associated with Tx4Token or Tx6Token is already sent out. | |
| @param[in] Map The container of Tx4Token or Tx6Token. | |
| @param[in] Item Current item to check against. | |
| @param[in] Context The Token to check againist. | |
| @retval EFI_NOT_READY The HTTP message is still queued in the list. | |
| @retval EFI_SUCCESS The HTTP message has been sent out. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| HttpTcpNotReady ( | |
| IN NET_MAP *Map, | |
| IN NET_MAP_ITEM *Item, | |
| IN VOID *Context | |
| ) | |
| { | |
| HTTP_TOKEN_WRAP *ValueInItem; | |
| ValueInItem = (HTTP_TOKEN_WRAP *) Item->Value; | |
| if (!ValueInItem->TcpWrap.IsTxDone) { | |
| return EFI_NOT_READY; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Transmit the HTTP or HTTPS mssage by processing the associated HTTP token. | |
| @param[in] Map The container of Tx4Token or Tx6Token. | |
| @param[in] Item Current item to check against. | |
| @param[in] Context The Token to check againist. | |
| @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. | |
| @retval EFI_SUCCESS The HTTP message is queued into TCP transmit | |
| queue. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| HttpTcpTransmit ( | |
| IN NET_MAP *Map, | |
| IN NET_MAP_ITEM *Item, | |
| IN VOID *Context | |
| ) | |
| { | |
| HTTP_TOKEN_WRAP *ValueInItem; | |
| EFI_STATUS Status; | |
| CHAR8 *RequestMsg; | |
| CHAR8 *Url; | |
| UINTN UrlSize; | |
| UINTN RequestMsgSize; | |
| ValueInItem = (HTTP_TOKEN_WRAP *) Item->Value; | |
| if (ValueInItem->TcpWrap.IsTxDone) { | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Parse the URI of the remote host. | |
| // | |
| UrlSize = StrLen (ValueInItem->HttpToken->Message->Data.Request->Url) + 1; | |
| Url = AllocatePool (UrlSize); | |
| if (Url == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| UnicodeStrToAsciiStrS (ValueInItem->HttpToken->Message->Data.Request->Url, Url, UrlSize); | |
| // | |
| // Create request message. | |
| // | |
| Status = HttpGenRequestMessage ( | |
| ValueInItem->HttpToken->Message, | |
| Url, | |
| &RequestMsg, | |
| &RequestMsgSize | |
| ); | |
| FreePool (Url); | |
| if (EFI_ERROR (Status)){ | |
| return Status; | |
| } | |
| // | |
| // Transmit the request message. | |
| // | |
| Status = HttpTransmitTcp ( | |
| ValueInItem->HttpInstance, | |
| ValueInItem, | |
| (UINT8*) RequestMsg, | |
| RequestMsgSize | |
| ); | |
| FreePool (RequestMsg); | |
| return Status; | |
| } | |
| /** | |
| Receive the HTTP response by processing the associated HTTP token. | |
| @param[in] Map The container of Rx4Token or Rx6Token. | |
| @param[in] Item Current item to check against. | |
| @param[in] Context The Token to check againist. | |
| @retval EFI_SUCCESS The HTTP response is queued into TCP receive | |
| queue. | |
| @retval Others Other error as indicated. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| HttpTcpReceive ( | |
| IN NET_MAP *Map, | |
| IN NET_MAP_ITEM *Item, | |
| IN VOID *Context | |
| ) | |
| { | |
| // | |
| // Process the queued HTTP response. | |
| // | |
| return HttpResponseWorker ((HTTP_TOKEN_WRAP *) Item->Value); | |
| } | |
| /** | |
| 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 EFI_EVENT Timeout | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_TCP4_IO_TOKEN *Rx4Token; | |
| EFI_TCP4_PROTOCOL *Tcp4; | |
| EFI_TCP6_IO_TOKEN *Rx6Token; | |
| EFI_TCP6_PROTOCOL *Tcp6; | |
| CHAR8 **EndofHeader; | |
| CHAR8 **HttpHeaders; | |
| CHAR8 *Buffer; | |
| NET_FRAGMENT Fragment; | |
| ASSERT (HttpInstance != NULL); | |
| EndofHeader = HttpInstance->EndofHeader; | |
| HttpHeaders = HttpInstance->HttpHeaders; | |
| Tcp4 = HttpInstance->Tcp4; | |
| Tcp6 = HttpInstance->Tcp6; | |
| Buffer = NULL; | |
| Rx4Token = NULL; | |
| Rx6Token = NULL; | |
| Fragment.Len = 0; | |
| Fragment.Bulk = NULL; | |
| if (HttpInstance->LocalAddressIsIPv6) { | |
| ASSERT (Tcp6 != NULL); | |
| } else { | |
| ASSERT (Tcp4 != NULL); | |
| } | |
| if (!HttpInstance->UseHttps) { | |
| Status = HttpCreateTcpRxEventForHeader (HttpInstance); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| } | |
| if (!HttpInstance->LocalAddressIsIPv6) { | |
| if (!HttpInstance->UseHttps) { | |
| Rx4Token = &HttpInstance->Rx4Token; | |
| Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN); | |
| if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| return Status; | |
| } | |
| } | |
| // | |
| // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL. | |
| // | |
| while (*EndofHeader == NULL) { | |
| if (!HttpInstance->UseHttps) { | |
| HttpInstance->IsRxDone = FALSE; | |
| Rx4Token->Packet.RxData->DataLength = DEF_BUF_LEN; | |
| Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN; | |
| Status = Tcp4->Receive (Tcp4, Rx4Token); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status)); | |
| return Status; | |
| } | |
| while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) { | |
| Tcp4->Poll (Tcp4); | |
| } | |
| if (!HttpInstance->IsRxDone) { | |
| // | |
| // Cancle the Token before close its Event. | |
| // | |
| Tcp4->Cancel (HttpInstance->Tcp4, &Rx4Token->CompletionToken); | |
| gBS->CloseEvent (Rx4Token->CompletionToken.Event); | |
| Rx4Token->CompletionToken.Status = EFI_TIMEOUT; | |
| } | |
| Status = Rx4Token->CompletionToken.Status; | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| Fragment.Len = Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength; | |
| Fragment.Bulk = (UINT8 *) Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer; | |
| } else { | |
| if (Fragment.Bulk != NULL) { | |
| FreePool (Fragment.Bulk); | |
| Fragment.Bulk = NULL; | |
| } | |
| Status = HttpsReceive (HttpInstance, &Fragment, Timeout); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status)); | |
| return Status; | |
| } | |
| } | |
| // | |
| // Append the response string. | |
| // | |
| *BufferSize = *SizeofHeaders + Fragment.Len; | |
| Buffer = AllocateZeroPool (*BufferSize); | |
| if (Buffer == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| return Status; | |
| } | |
| if (*HttpHeaders != NULL) { | |
| CopyMem (Buffer, *HttpHeaders, *SizeofHeaders); | |
| FreePool (*HttpHeaders); | |
| } | |
| CopyMem ( | |
| Buffer + *SizeofHeaders, | |
| Fragment.Bulk, | |
| Fragment.Len | |
| ); | |
| *HttpHeaders = Buffer; | |
| *SizeofHeaders = *BufferSize; | |
| // | |
| // Check whether we received end of HTTP headers. | |
| // | |
| *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR); | |
| }; | |
| // | |
| // Free the buffer. | |
| // | |
| if (Rx4Token != NULL && Rx4Token->Packet.RxData != NULL && Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { | |
| FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer); | |
| Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; | |
| Fragment.Bulk = NULL; | |
| } | |
| if (Fragment.Bulk != NULL) { | |
| FreePool (Fragment.Bulk); | |
| Fragment.Bulk = NULL; | |
| } | |
| } else { | |
| if (!HttpInstance->UseHttps) { | |
| Rx6Token = &HttpInstance->Rx6Token; | |
| Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN); | |
| if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| return Status; | |
| } | |
| } | |
| // | |
| // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL. | |
| // | |
| while (*EndofHeader == NULL) { | |
| if (!HttpInstance->UseHttps) { | |
| HttpInstance->IsRxDone = FALSE; | |
| Rx6Token->Packet.RxData->DataLength = DEF_BUF_LEN; | |
| Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN; | |
| Status = Tcp6->Receive (Tcp6, Rx6Token); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status)); | |
| return Status; | |
| } | |
| while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) { | |
| Tcp6->Poll (Tcp6); | |
| } | |
| if (!HttpInstance->IsRxDone) { | |
| // | |
| // Cancle the Token before close its Event. | |
| // | |
| Tcp6->Cancel (HttpInstance->Tcp6, &Rx6Token->CompletionToken); | |
| gBS->CloseEvent (Rx6Token->CompletionToken.Event); | |
| Rx6Token->CompletionToken.Status = EFI_TIMEOUT; | |
| } | |
| Status = Rx6Token->CompletionToken.Status; | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| Fragment.Len = Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength; | |
| Fragment.Bulk = (UINT8 *) Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer; | |
| } else { | |
| if (Fragment.Bulk != NULL) { | |
| FreePool (Fragment.Bulk); | |
| Fragment.Bulk = NULL; | |
| } | |
| Status = HttpsReceive (HttpInstance, &Fragment, Timeout); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status)); | |
| return Status; | |
| } | |
| } | |
| // | |
| // Append the response string. | |
| // | |
| *BufferSize = *SizeofHeaders + Fragment.Len; | |
| Buffer = AllocateZeroPool (*BufferSize); | |
| if (Buffer == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| return Status; | |
| } | |
| if (*HttpHeaders != NULL) { | |
| CopyMem (Buffer, *HttpHeaders, *SizeofHeaders); | |
| FreePool (*HttpHeaders); | |
| } | |
| CopyMem ( | |
| Buffer + *SizeofHeaders, | |
| Fragment.Bulk, | |
| Fragment.Len | |
| ); | |
| *HttpHeaders = Buffer; | |
| *SizeofHeaders = *BufferSize; | |
| // | |
| // Check whether we received end of HTTP headers. | |
| // | |
| *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR); | |
| }; | |
| // | |
| // Free the buffer. | |
| // | |
| if (Rx6Token != NULL && Rx6Token->Packet.RxData != NULL && Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { | |
| FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer); | |
| Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; | |
| Fragment.Bulk = NULL; | |
| } | |
| if (Fragment.Bulk != NULL) { | |
| FreePool (Fragment.Bulk); | |
| Fragment.Bulk = NULL; | |
| } | |
| } | |
| // | |
| // Skip the CRLF after the HTTP headers. | |
| // | |
| *EndofHeader = *EndofHeader + AsciiStrLen (HTTP_END_OF_HDR_STR); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| 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. | |
| @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 | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| HTTP_PROTOCOL *HttpInstance; | |
| EFI_TCP6_PROTOCOL *Tcp6; | |
| EFI_TCP6_IO_TOKEN *Rx6Token; | |
| EFI_TCP4_PROTOCOL *Tcp4; | |
| EFI_TCP4_IO_TOKEN *Rx4Token; | |
| HttpInstance = Wrap->HttpInstance; | |
| Tcp4 = HttpInstance->Tcp4; | |
| Tcp6 = HttpInstance->Tcp6; | |
| Rx4Token = NULL; | |
| Rx6Token = NULL; | |
| if (HttpInstance->LocalAddressIsIPv6) { | |
| ASSERT (Tcp6 != NULL); | |
| } else { | |
| ASSERT (Tcp4 != NULL); | |
| } | |
| if (HttpInstance->LocalAddressIsIPv6) { | |
| Rx6Token = &Wrap->TcpWrap.Rx6Token; | |
| Rx6Token ->Packet.RxData->DataLength = (UINT32) HttpMsg->BodyLength; | |
| Rx6Token ->Packet.RxData->FragmentTable[0].FragmentLength = (UINT32) HttpMsg->BodyLength; | |
| Rx6Token ->Packet.RxData->FragmentTable[0].FragmentBuffer = (VOID *) HttpMsg->Body; | |
| Rx6Token->CompletionToken.Status = EFI_NOT_READY; | |
| Status = Tcp6->Receive (Tcp6, Rx6Token); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status)); | |
| return Status; | |
| } | |
| } 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; | |
| Rx4Token->CompletionToken.Status = EFI_NOT_READY; | |
| Status = Tcp4->Receive (Tcp4, Rx4Token); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status)); | |
| return Status; | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Clean up Tcp Tokens while the Tcp transmission error occurs. | |
| @param[in] Wrap Pointer to HTTP token's wrap data. | |
| **/ | |
| VOID | |
| HttpTcpTokenCleanup ( | |
| IN HTTP_TOKEN_WRAP *Wrap | |
| ) | |
| { | |
| HTTP_PROTOCOL *HttpInstance; | |
| EFI_TCP4_IO_TOKEN *Rx4Token; | |
| EFI_TCP6_IO_TOKEN *Rx6Token; | |
| ASSERT (Wrap != NULL); | |
| HttpInstance = Wrap->HttpInstance; | |
| Rx4Token = NULL; | |
| Rx6Token = NULL; | |
| if (HttpInstance->LocalAddressIsIPv6) { | |
| Rx6Token = &Wrap->TcpWrap.Rx6Token; | |
| if (Rx6Token->CompletionToken.Event != NULL) { | |
| gBS->CloseEvent (Rx6Token->CompletionToken.Event); | |
| Rx6Token->CompletionToken.Event = NULL; | |
| } | |
| FreePool (Wrap); | |
| Rx6Token = &HttpInstance->Rx6Token; | |
| if (Rx6Token->CompletionToken.Event != NULL) { | |
| gBS->CloseEvent (Rx6Token->CompletionToken.Event); | |
| Rx6Token->CompletionToken.Event = NULL; | |
| } | |
| if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { | |
| FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer); | |
| Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; | |
| } | |
| } else { | |
| Rx4Token = &Wrap->TcpWrap.Rx4Token; | |
| if (Rx4Token->CompletionToken.Event != NULL) { | |
| gBS->CloseEvent (Rx4Token->CompletionToken.Event); | |
| Rx4Token->CompletionToken.Event = NULL; | |
| } | |
| FreePool (Wrap); | |
| Rx4Token = &HttpInstance->Rx4Token; | |
| if (Rx4Token->CompletionToken.Event != NULL) { | |
| gBS->CloseEvent (Rx4Token->CompletionToken.Event); | |
| Rx4Token->CompletionToken.Event = NULL; | |
| } | |
| if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { | |
| FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer); | |
| Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL; | |
| } | |
| } | |
| } |