Use the BSD license Fix errors detected by GCC compiler in WebServer/ConfigurationTable.c Add libraries: CpuLib, DxeServicesTableLib and MtrrLib Signed-off-by: lpleahy git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13115 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			783 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			783 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/**
 | 
						|
  @file
 | 
						|
  Web server application
 | 
						|
 | 
						|
  Copyright (c) 2011-2012, Intel Corporation
 | 
						|
  All rights reserved. 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 <WebServer.h>
 | 
						|
 | 
						|
DT_WEB_SERVER mWebServer;   ///<  Web server's control structure
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Add a port to the list of ports to be polled.
 | 
						|
 | 
						|
  @param [in] pWebServer    The web server control structure address.
 | 
						|
 | 
						|
  @param [in] SocketFD      The socket's file descriptor to add to the list.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS       The port was successfully added
 | 
						|
  @retval EFI_NO_RESOURCES  Insufficient memory to add the port
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
PortAdd (
 | 
						|
  IN DT_WEB_SERVER * pWebServer,
 | 
						|
  IN int SocketFD
 | 
						|
  )
 | 
						|
{
 | 
						|
  nfds_t Index;
 | 
						|
  size_t LengthInBytes;
 | 
						|
  nfds_t MaxEntries;
 | 
						|
  nfds_t MaxEntriesNew;
 | 
						|
  struct pollfd * pFdList;
 | 
						|
  struct pollfd * pFdListNew;
 | 
						|
  WSDT_PORT ** ppPortListNew;
 | 
						|
  WSDT_PORT * pPort;
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Use for/break instead of goto
 | 
						|
  //
 | 
						|
  for ( ; ; ) {
 | 
						|
    //
 | 
						|
    //  Assume success
 | 
						|
    //
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
 | 
						|
    //
 | 
						|
    //  Create a new list if necessary
 | 
						|
    //
 | 
						|
    pFdList = pWebServer->pFdList;
 | 
						|
    MaxEntries = pWebServer->MaxEntries;
 | 
						|
    if ( pWebServer->Entries >= MaxEntries ) {
 | 
						|
      MaxEntriesNew = 16 + MaxEntries;
 | 
						|
 | 
						|
      //
 | 
						|
      //  The current FD list is full
 | 
						|
      //  Allocate a new FD list
 | 
						|
      //
 | 
						|
      LengthInBytes = sizeof ( *pFdList ) * MaxEntriesNew;
 | 
						|
      Status = gBS->AllocatePool ( EfiRuntimeServicesData,
 | 
						|
                                   LengthInBytes,
 | 
						|
                                   (VOID **)&pFdListNew );
 | 
						|
      if ( EFI_ERROR ( Status )) {
 | 
						|
        DEBUG (( DEBUG_ERROR | DEBUG_POOL,
 | 
						|
                  "ERROR - Failed to allocate the FD list, Status: %r\r\n",
 | 
						|
                  Status ));
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      //  Allocate a new port list
 | 
						|
      //
 | 
						|
      LengthInBytes = sizeof ( *ppPortListNew ) * MaxEntriesNew;
 | 
						|
      Status = gBS->AllocatePool ( EfiRuntimeServicesData,
 | 
						|
                                   LengthInBytes,
 | 
						|
                                   (VOID **) &ppPortListNew );
 | 
						|
      if ( EFI_ERROR ( Status )) {
 | 
						|
        DEBUG (( DEBUG_ERROR | DEBUG_POOL,
 | 
						|
                  "ERROR - Failed to allocate the port list, Status: %r\r\n",
 | 
						|
                  Status ));
 | 
						|
 | 
						|
        //
 | 
						|
        //  Free the new FD list
 | 
						|
        //
 | 
						|
        gBS->FreePool ( pFdListNew );
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      //  Duplicate the FD list
 | 
						|
      //
 | 
						|
      Index = MaxEntries;
 | 
						|
      if ( NULL != pFdList ) {
 | 
						|
        CopyMem ( pFdListNew,
 | 
						|
                  pFdList,
 | 
						|
                  Index * sizeof ( *pFdList ));
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      //  Initialize the new entries in the FD list
 | 
						|
      //
 | 
						|
      for ( ; MaxEntriesNew > Index; Index++ ) {
 | 
						|
        pFdListNew[ Index ].fd = -1;
 | 
						|
        pFdListNew[ Index ].events = 0;
 | 
						|
        pFdListNew[ Index ].revents = 0;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      //  Free the old FD list
 | 
						|
      //
 | 
						|
      if ( NULL != pFdList ) {
 | 
						|
        gBS->FreePool ( pFdList );
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      //  Switch to the new FD list
 | 
						|
      //
 | 
						|
      pWebServer->pFdList = pFdListNew;
 | 
						|
      pFdList = pWebServer->pFdList;
 | 
						|
 | 
						|
      //
 | 
						|
      //  Duplicate the port list
 | 
						|
      //
 | 
						|
      Index = MaxEntries;
 | 
						|
      if ( NULL != pWebServer->ppPortList ) {
 | 
						|
        CopyMem ( ppPortListNew,
 | 
						|
                  pWebServer->ppPortList,
 | 
						|
                  Index * sizeof ( *ppPortListNew ));
 | 
						|
      }
 | 
						|
      
 | 
						|
      //
 | 
						|
      //  Initialize the new entries in the port list
 | 
						|
      //
 | 
						|
      for ( ; MaxEntriesNew > Index; Index++ ) {
 | 
						|
        ppPortListNew[ Index ] = NULL;
 | 
						|
      }
 | 
						|
      
 | 
						|
      //
 | 
						|
      //  Free the old port list
 | 
						|
      //
 | 
						|
      if ( NULL != pWebServer->ppPortList ) {
 | 
						|
        gBS->FreePool ( pWebServer->ppPortList );
 | 
						|
      }
 | 
						|
      
 | 
						|
      //
 | 
						|
      //  Switch to the new port list
 | 
						|
      //
 | 
						|
      pWebServer->ppPortList = ppPortListNew;
 | 
						|
      
 | 
						|
      //
 | 
						|
      //  Update the list size
 | 
						|
      //
 | 
						|
      pWebServer->MaxEntries = MaxEntriesNew;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Allocate a new port
 | 
						|
    //
 | 
						|
    LengthInBytes = sizeof ( *pPort );
 | 
						|
    Status = gBS->AllocatePool ( EfiRuntimeServicesData,
 | 
						|
                                 LengthInBytes,
 | 
						|
                                 (VOID **)&pPort );
 | 
						|
    if ( EFI_ERROR ( Status )) {
 | 
						|
      DEBUG (( DEBUG_ERROR | DEBUG_POOL,
 | 
						|
                "ERROR - Failed to allocate the port, Status: %r\r\n",
 | 
						|
                Status ));
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Initialize the port
 | 
						|
    //
 | 
						|
    pPort->RequestLength = 0;
 | 
						|
    pPort->TxBytes = 0;
 | 
						|
 | 
						|
    //
 | 
						|
    //  Add the socket to the FD list
 | 
						|
    //
 | 
						|
    pFdList[ pWebServer->Entries ].fd = SocketFD;
 | 
						|
    pFdList[ pWebServer->Entries ].events = POLLRDNORM
 | 
						|
                                             | POLLHUP;
 | 
						|
    pFdList[ pWebServer->Entries ].revents = 0;
 | 
						|
 | 
						|
    //
 | 
						|
    //  Add the port to the port list
 | 
						|
    //
 | 
						|
    pWebServer->ppPortList[ pWebServer->Entries ] = pPort;
 | 
						|
 | 
						|
    //
 | 
						|
    //  Account for the new entry
 | 
						|
    //
 | 
						|
    pWebServer->Entries += 1;
 | 
						|
    DEBUG (( DEBUG_PORT_WORK | DEBUG_INFO,
 | 
						|
              "WebServer handling %d ports\r\n",
 | 
						|
              pWebServer->Entries ));
 | 
						|
 | 
						|
    //
 | 
						|
    //  All done
 | 
						|
    //
 | 
						|
    break;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Remove a port from the list of ports to be polled.
 | 
						|
 | 
						|
  @param [in] pWebServer    The web server control structure address.
 | 
						|
 | 
						|
  @param [in] SocketFD      The socket's file descriptor to add to the list.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
PortRemove (
 | 
						|
  IN DT_WEB_SERVER * pWebServer,
 | 
						|
  IN int SocketFD
 | 
						|
  )
 | 
						|
{
 | 
						|
  nfds_t Entries;
 | 
						|
  nfds_t Index;
 | 
						|
  struct pollfd * pFdList;
 | 
						|
  WSDT_PORT ** ppPortList;
 | 
						|
 | 
						|
  DBG_ENTER ( );
 | 
						|
 | 
						|
  //
 | 
						|
  //  Attempt to remove the entry from the list
 | 
						|
  //
 | 
						|
  Entries = pWebServer->Entries;
 | 
						|
  pFdList = pWebServer->pFdList;
 | 
						|
  ppPortList = pWebServer->ppPortList;
 | 
						|
  for ( Index = 0; Entries > Index; Index++ ) {
 | 
						|
    //
 | 
						|
    //  Locate the specified socket file descriptor
 | 
						|
    //
 | 
						|
    if ( SocketFD == pFdList[ Index ].fd ) {
 | 
						|
      //
 | 
						|
      //  Determine if this is the listen port
 | 
						|
      //
 | 
						|
      if ( SocketFD == pWebServer->HttpListenPort ) {
 | 
						|
        pWebServer->HttpListenPort = -1;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      //  Close the socket
 | 
						|
      //
 | 
						|
      close ( SocketFD );
 | 
						|
 | 
						|
      //
 | 
						|
      //  Free the port structure
 | 
						|
      //
 | 
						|
      gBS->FreePool ( ppPortList[ Index ]);
 | 
						|
 | 
						|
      //
 | 
						|
      //  Remove this port from the list by copying
 | 
						|
      //  the rest of the list down one entry
 | 
						|
      //
 | 
						|
      Entries -= 1;
 | 
						|
      for ( ; Entries > Index; Index++ ) {
 | 
						|
        pFdList[ Index ] = pFdList[ Index + 1 ];
 | 
						|
        ppPortList[ Index ] = ppPortList[ Index + 1 ];
 | 
						|
      }
 | 
						|
      pFdList[ Index ].fd = -1;
 | 
						|
      pFdList[ Index ].events = 0;
 | 
						|
      pFdList[ Index ].revents = 0;
 | 
						|
      ppPortList[ Index ] = NULL;
 | 
						|
 | 
						|
      //
 | 
						|
      //  Update the number of entries in the list
 | 
						|
      //
 | 
						|
      pWebServer->Entries = Entries;
 | 
						|
      DEBUG (( DEBUG_PORT_WORK | DEBUG_INFO,
 | 
						|
                "WebServer handling %d ports\r\n",
 | 
						|
                pWebServer->Entries ));
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  DBG_EXIT ( );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Process the work for the sockets.
 | 
						|
 | 
						|
  @param [in] pWebServer    The web server control structure address.
 | 
						|
 | 
						|
  @param [in] SocketFD      The socket's file descriptor to add to the list.
 | 
						|
 | 
						|
  @param [in] events        everts is a bitmask of the work to be done
 | 
						|
 | 
						|
  @param [in] pPort         The address of a WSDT_PORT structure
 | 
						|
 | 
						|
  @retval EFI_SUCCESS       The operation was successful
 | 
						|
  @retval EFI_DEVICE_ERROR  Error, close the port
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
PortWork (
 | 
						|
  IN DT_WEB_SERVER * pWebServer,
 | 
						|
  IN int SocketFD,
 | 
						|
  IN INTN events,
 | 
						|
  IN WSDT_PORT * pPort
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN bDone;
 | 
						|
  size_t LengthInBytes;
 | 
						|
  int NewSocket;
 | 
						|
  EFI_STATUS OpStatus;
 | 
						|
  struct sockaddr_in6 RemoteAddress;
 | 
						|
  socklen_t RemoteAddressLength;
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  DEBUG (( DEBUG_PORT_WORK, "Entering PortWork\r\n" ));
 | 
						|
 | 
						|
  //
 | 
						|
  //  Assume success
 | 
						|
  //
 | 
						|
  OpStatus = EFI_SUCCESS;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Handle input events
 | 
						|
  //
 | 
						|
  if ( 0 != ( events & POLLRDNORM )) {
 | 
						|
    //
 | 
						|
    //  Determine if this is a connection attempt
 | 
						|
    //
 | 
						|
    if (( SocketFD == pWebServer->HttpListenPort )
 | 
						|
      || ( SocketFD == pWebServer->HttpListenPort6 )) {
 | 
						|
      //
 | 
						|
      //  Handle connection attempts
 | 
						|
      //  Accepts arrive as read events
 | 
						|
      //
 | 
						|
      RemoteAddressLength = sizeof ( RemoteAddress );
 | 
						|
      NewSocket = accept ( SocketFD,
 | 
						|
                           (struct sockaddr *)&RemoteAddress,
 | 
						|
                           &RemoteAddressLength );
 | 
						|
      if ( -1 != NewSocket ) {
 | 
						|
        if ( 0 != NewSocket ) {
 | 
						|
          //
 | 
						|
          //  Add this port to the list monitored by the web server
 | 
						|
          //
 | 
						|
          Status = PortAdd ( pWebServer, NewSocket );
 | 
						|
          if ( EFI_ERROR ( Status )) {
 | 
						|
            DEBUG (( DEBUG_ERROR,
 | 
						|
                      "ERROR - Failed to add the port 0x%08x, Status: %r\r\n",
 | 
						|
                      NewSocket,
 | 
						|
                      Status ));
 | 
						|
 | 
						|
            //
 | 
						|
            //  Done with the new socket
 | 
						|
            //
 | 
						|
            close ( NewSocket );
 | 
						|
          }
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          DEBUG (( DEBUG_ERROR,
 | 
						|
                    "ERROR - Socket not available!\r\n" ));
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        //  Leave the listen port open
 | 
						|
        //
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        //
 | 
						|
        //  Listen port error
 | 
						|
        //  Close the listen port by returning error status
 | 
						|
        //
 | 
						|
        OpStatus = EFI_DEVICE_ERROR;
 | 
						|
        DEBUG (( DEBUG_ERROR,
 | 
						|
                  "ERROR - Failed to accept new connection, errno: 0x%08x\r\n",
 | 
						|
                  errno ));
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      //
 | 
						|
      //  Handle the data received event
 | 
						|
      //
 | 
						|
      if ( 0 == pPort->RequestLength ) {
 | 
						|
        //
 | 
						|
        //  Receive the page request
 | 
						|
        //
 | 
						|
        pPort->RequestLength = recv ( SocketFD,
 | 
						|
                                      &pPort->Request[0],
 | 
						|
                                      DIM ( pPort->Request ),
 | 
						|
                                      0 );
 | 
						|
        if ( -1 == pPort->RequestLength ) {
 | 
						|
          //
 | 
						|
          //  Receive error detected
 | 
						|
          //  Close the port
 | 
						|
          //
 | 
						|
          OpStatus = EFI_DEVICE_ERROR;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          DEBUG (( DEBUG_REQUEST,
 | 
						|
                    "0x%08x: Socket - Received %d bytes of HTTP request\r\n",
 | 
						|
                    SocketFD,
 | 
						|
                    pPort->RequestLength ));
 | 
						|
 | 
						|
          //
 | 
						|
          //  Process the request
 | 
						|
          //
 | 
						|
          OpStatus = HttpRequest ( SocketFD, pPort, &bDone );
 | 
						|
          if ( bDone ) {
 | 
						|
            //
 | 
						|
            //  Notify the upper layer to close the socket
 | 
						|
            //
 | 
						|
            OpStatus = EFI_DEVICE_ERROR;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        //
 | 
						|
        //  Receive the file data
 | 
						|
        //
 | 
						|
        LengthInBytes = recv ( SocketFD,
 | 
						|
                               &pPort->RxBuffer[0],
 | 
						|
                               DIM ( pPort->RxBuffer ),
 | 
						|
                               0 );
 | 
						|
        if ( -1 == LengthInBytes ) {
 | 
						|
          //
 | 
						|
          //  Receive error detected
 | 
						|
          //  Close the port
 | 
						|
          //
 | 
						|
          OpStatus = EFI_DEVICE_ERROR;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          DEBUG (( DEBUG_REQUEST,
 | 
						|
                    "0x%08x: Socket - Received %d bytes of file data\r\n",
 | 
						|
                    SocketFD,
 | 
						|
                    LengthInBytes ));
 | 
						|
 | 
						|
          //
 | 
						|
          // TODO: Process the file data
 | 
						|
          //
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Handle the close event
 | 
						|
  //
 | 
						|
  if ( 0 != ( events & POLLHUP )) {
 | 
						|
    //
 | 
						|
    //  Close the port
 | 
						|
    //
 | 
						|
    OpStatus = EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the operation status
 | 
						|
  //
 | 
						|
  DEBUG (( DEBUG_PORT_WORK,
 | 
						|
            "Exiting PortWork, Status: %r\r\n",
 | 
						|
            OpStatus ));
 | 
						|
  return OpStatus;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Scan the list of sockets and process any pending work
 | 
						|
 | 
						|
  @param [in] pWebServer    The web server control structure address.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SocketPoll (
 | 
						|
  IN DT_WEB_SERVER * pWebServer
 | 
						|
  )
 | 
						|
{
 | 
						|
  int FDCount;
 | 
						|
  struct pollfd * pPoll;
 | 
						|
  WSDT_PORT ** ppPort;
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  DEBUG (( DEBUG_SOCKET_POLL, "Entering SocketPoll\r\n" ));
 | 
						|
 | 
						|
  //
 | 
						|
  //  Determine if any ports are active
 | 
						|
  //
 | 
						|
  FDCount = poll ( pWebServer->pFdList,
 | 
						|
                   pWebServer->Entries,
 | 
						|
                   CLIENT_POLL_DELAY );
 | 
						|
  if ( -1 == FDCount ) {
 | 
						|
    DEBUG (( DEBUG_ERROR | DEBUG_SOCKET_POLL,
 | 
						|
              "ERROR - errno: %d\r\n",
 | 
						|
              errno ));
 | 
						|
  }
 | 
						|
 | 
						|
  pPoll = pWebServer->pFdList;
 | 
						|
  ppPort = pWebServer->ppPortList;
 | 
						|
  while ( 0 < FDCount ) {
 | 
						|
    //
 | 
						|
    //  Walk the list of ports to determine what work needs to be done
 | 
						|
    //
 | 
						|
    if ( 0 != pPoll->revents ) {
 | 
						|
      //
 | 
						|
      //  Process this port
 | 
						|
      //
 | 
						|
      Status = PortWork ( pWebServer,
 | 
						|
                          pPoll->fd,
 | 
						|
                          pPoll->revents,
 | 
						|
                          *ppPort );
 | 
						|
      pPoll->revents = 0;
 | 
						|
 | 
						|
      //
 | 
						|
      //  Close the port if necessary
 | 
						|
      //
 | 
						|
      if ( EFI_ERROR ( Status )) {
 | 
						|
        PortRemove ( pWebServer, pPoll->fd );
 | 
						|
        pPoll -= 1;
 | 
						|
        ppPort -= 1;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      //  Account for this file descriptor
 | 
						|
      //
 | 
						|
      FDCount -= 1;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Set the next port
 | 
						|
    //
 | 
						|
    pPoll += 1;
 | 
						|
    ppPort += 1;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG (( DEBUG_SOCKET_POLL, "Exiting SocketPoll\r\n" ));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Create an HTTP port for the web server
 | 
						|
 | 
						|
  This routine polls the network layer to create an HTTP port for the
 | 
						|
  web server.  More than one attempt may be necessary since it may take
 | 
						|
  some time to get the IP address and initialize the upper layers of
 | 
						|
  the network stack.
 | 
						|
 | 
						|
  After the HTTP port is created, the socket layer will manage the
 | 
						|
  coming and going of the network connections until the last network
 | 
						|
  connection is broken.
 | 
						|
 | 
						|
  @param [in] pWebServer    The web server control structure address.
 | 
						|
  @param [in] AddressFamily Address family for the network connection
 | 
						|
  @param [in] Protocol      Protocol to use for the network connection
 | 
						|
  @param [in] HttpPort      Port number for the HTTP connection
 | 
						|
  @param [out] pPort        Address of the port
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
WebServerListen (
 | 
						|
  IN DT_WEB_SERVER * pWebServer,
 | 
						|
  IN sa_family_t AddressFamily,
 | 
						|
  IN int Protocol,
 | 
						|
  IN UINT16 HttpPort,
 | 
						|
  OUT int * pPort
 | 
						|
  )
 | 
						|
{
 | 
						|
  union {
 | 
						|
    struct sockaddr_in v4;
 | 
						|
    struct sockaddr_in6 v6;
 | 
						|
  } WebServerAddress;
 | 
						|
  int SocketStatus;
 | 
						|
  EFI_STATUS Status;
 | 
						|
 | 
						|
  DEBUG (( DEBUG_SERVER_LISTEN, "Entering WebServerListen\r\n" ));
 | 
						|
 | 
						|
  //
 | 
						|
  //  Attempt to create the socket for the web server
 | 
						|
  //
 | 
						|
  * pPort = socket ( AddressFamily, SOCK_STREAM, Protocol );
 | 
						|
  if ( -1 != *pPort ) {
 | 
						|
    //
 | 
						|
    //  Build the socket address
 | 
						|
    //
 | 
						|
    ZeroMem ( &WebServerAddress, sizeof ( WebServerAddress ));
 | 
						|
    if ( AF_INET == AddressFamily ) {
 | 
						|
      WebServerAddress.v4.sin_len = sizeof ( WebServerAddress.v4 );
 | 
						|
      WebServerAddress.v4.sin_family = AddressFamily;
 | 
						|
      WebServerAddress.v4.sin_port = htons ( HttpPort );
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      WebServerAddress.v6.sin6_len = sizeof ( WebServerAddress.v6 );
 | 
						|
      WebServerAddress.v6.sin6_family = AddressFamily;
 | 
						|
      WebServerAddress.v6.sin6_port = htons ( HttpPort );
 | 
						|
      WebServerAddress.v6.sin6_scope_id = __IPV6_ADDR_SCOPE_GLOBAL;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Bind the socket to the HTTP port
 | 
						|
    //
 | 
						|
    SocketStatus = bind ( *pPort,
 | 
						|
                          (struct sockaddr *) &WebServerAddress,
 | 
						|
                          WebServerAddress.v4.sin_len );
 | 
						|
    if ( -1 != SocketStatus ) {
 | 
						|
      //
 | 
						|
      //  Enable connections to the HTTP port
 | 
						|
      //
 | 
						|
      SocketStatus = listen ( *pPort, SOMAXCONN );
 | 
						|
      if ( -1 != SocketStatus ) {
 | 
						|
        //
 | 
						|
        //  Add the HTTP port to the list of ports to poll
 | 
						|
        //
 | 
						|
        Status = PortAdd ( pWebServer, *pPort );
 | 
						|
        if ( EFI_ERROR ( Status )) {
 | 
						|
          SocketStatus = -1;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          DEBUG (( DEBUG_PORT_WORK,
 | 
						|
                    "Listening on Tcp%d:%d\r\n",
 | 
						|
                    ( AF_INET == AddressFamily ) ? 4 : 6,
 | 
						|
                    HttpPort ));
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Release the socket if necessary
 | 
						|
    //
 | 
						|
    if ( -1 == SocketStatus ) {
 | 
						|
      close ( *pPort );
 | 
						|
      *pPort = -1;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG (( DEBUG_SERVER_LISTEN, "Exiting WebServerListen\r\n" ));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Entry point for the web server application.
 | 
						|
 | 
						|
  @param [in] Argc  The number of arguments
 | 
						|
  @param [in] Argv  The argument value array
 | 
						|
 | 
						|
  @retval  0        The application exited normally.
 | 
						|
  @retval  Other    An error occurred.
 | 
						|
**/
 | 
						|
int
 | 
						|
main (
 | 
						|
  IN int Argc,
 | 
						|
  IN char **Argv
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT16 HttpPort;
 | 
						|
  UINTN Index;
 | 
						|
  DT_WEB_SERVER * pWebServer;
 | 
						|
  EFI_STATUS Status;
 | 
						|
  UINT64 TriggerTime;
 | 
						|
 | 
						|
  //
 | 
						|
  //  Get the HTTP port
 | 
						|
  //
 | 
						|
  HttpPort = PcdGet16 ( WebServer_HttpPort );
 | 
						|
  DEBUG (( DEBUG_HTTP_PORT,
 | 
						|
            "HTTP Port: %d\r\n",
 | 
						|
            HttpPort ));
 | 
						|
 | 
						|
  //
 | 
						|
  //  Create a timer event to start HTTP port
 | 
						|
  //
 | 
						|
  pWebServer = &mWebServer;
 | 
						|
  Status = gBS->CreateEvent ( EVT_TIMER,
 | 
						|
                              TPL_WEB_SERVER,
 | 
						|
                              NULL,
 | 
						|
                              NULL,
 | 
						|
                              &pWebServer->TimerEvent );
 | 
						|
  if ( !EFI_ERROR ( Status )) {
 | 
						|
    TriggerTime = HTTP_PORT_POLL_DELAY * ( 1000 * 10 );
 | 
						|
    Status = gBS->SetTimer ( pWebServer->TimerEvent,
 | 
						|
                             TimerPeriodic,
 | 
						|
                             TriggerTime );
 | 
						|
    if ( !EFI_ERROR ( Status )) {
 | 
						|
      //
 | 
						|
      //  Run the web server forever
 | 
						|
      //
 | 
						|
      pWebServer->HttpListenPort = -1;
 | 
						|
      pWebServer->HttpListenPort6 = -1;
 | 
						|
      pWebServer->bRunning = TRUE;
 | 
						|
      do {
 | 
						|
        //
 | 
						|
        //  Poll the network layer to create the HTTP port
 | 
						|
        //  for the web server.  More than one attempt may
 | 
						|
        //  be necessary since it may take some time to get
 | 
						|
        //  the IP address and initialize the upper layers
 | 
						|
        //  of the network stack.
 | 
						|
        //
 | 
						|
        if (( -1 == pWebServer->HttpListenPort )
 | 
						|
          || ( -1 == pWebServer->HttpListenPort6 )) {
 | 
						|
          do {
 | 
						|
            //
 | 
						|
            //  Wait a while before polling for a connection
 | 
						|
            //
 | 
						|
            if ( EFI_SUCCESS != gBS->CheckEvent ( pWebServer->TimerEvent )) {
 | 
						|
              if ( 0 != pWebServer->Entries ) {
 | 
						|
                  break;
 | 
						|
              }
 | 
						|
              gBS->WaitForEvent ( 1, &pWebServer->TimerEvent, &Index );
 | 
						|
            }
 | 
						|
 | 
						|
            //
 | 
						|
            //  Poll for a network connection
 | 
						|
            //
 | 
						|
            if ( -1 == pWebServer->HttpListenPort ) {
 | 
						|
              WebServerListen ( pWebServer,
 | 
						|
                                AF_INET,
 | 
						|
                                IPPROTO_TCP,
 | 
						|
                                HttpPort,
 | 
						|
                                &pWebServer->HttpListenPort );
 | 
						|
            }
 | 
						|
            if ( -1 == pWebServer->HttpListenPort6 ) {
 | 
						|
              WebServerListen ( pWebServer,
 | 
						|
                                AF_INET6,
 | 
						|
                                IPPROTO_TCP,
 | 
						|
                                HttpPort,
 | 
						|
                                &pWebServer->HttpListenPort6 );
 | 
						|
            }
 | 
						|
 | 
						|
            //
 | 
						|
            //  Continue polling while both network connections are
 | 
						|
            //  not present
 | 
						|
            //
 | 
						|
          } while ( 0 == pWebServer->Entries );
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        //  Poll the sockets for activity while both network
 | 
						|
        //  connections are connected
 | 
						|
        //
 | 
						|
        do {
 | 
						|
          SocketPoll ( pWebServer );
 | 
						|
        } while ( pWebServer->bRunning
 | 
						|
                && ( -1 != pWebServer->HttpListenPort )
 | 
						|
                && ( -1 != pWebServer->HttpListenPort6 ));
 | 
						|
 | 
						|
        //
 | 
						|
        //  Continue polling the network connections until both
 | 
						|
        //  TCP4 and TCP6 are connected
 | 
						|
        //
 | 
						|
      } while ( pWebServer->bRunning );
 | 
						|
 | 
						|
      //
 | 
						|
      //  Stop the timer
 | 
						|
      //
 | 
						|
      gBS->SetTimer ( pWebServer->TimerEvent,
 | 
						|
                      TimerCancel,
 | 
						|
                      0 );
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    //  Done with the timer event
 | 
						|
    //
 | 
						|
    gBS->CloseEvent ( pWebServer->TimerEvent );
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  //  Return the final status
 | 
						|
  //
 | 
						|
  DBG_EXIT_STATUS ( Status );
 | 
						|
  return Status;
 | 
						|
}
 |