Merged socket development branch:
[mirror_edk2.git] / AppPkg / Applications / Sockets / WebServer / WebServer.c
index 00bf4b6..00f8633 100644 (file)
@@ -124,9 +124,9 @@ PortAdd (
       //  Initialize the new entries in the FD list
       //
       for ( ; MaxEntriesNew > Index; Index++ ) {
-        pFdListNew [ Index ].fd = -1;
-        pFdListNew [ Index ].events = 0;
-        pFdListNew [ Index ].revents = 0;
+        pFdListNew[ Index ].fd = -1;
+        pFdListNew[ Index ].events = 0;
+        pFdListNew[ Index ].revents = 0;
       }
 
       //
@@ -156,7 +156,7 @@ PortAdd (
       //  Initialize the new entries in the port list
       //
       for ( ; MaxEntriesNew > Index; Index++ ) {
-        ppPortListNew [ Index ] = NULL;
+        ppPortListNew[ Index ] = NULL;
       }
       
       //
@@ -200,15 +200,15 @@ PortAdd (
     //
     //  Add the socket to the FD list
     //
-    pFdList [ pWebServer->Entries ].fd = SocketFD;
-    pFdList [ pWebServer->Entries ].events = POLLRDNORM
+    pFdList[ pWebServer->Entries ].fd = SocketFD;
+    pFdList[ pWebServer->Entries ].events = POLLRDNORM
                                              | POLLHUP;
-    pFdList [ pWebServer->Entries ].revents = 0;
+    pFdList[ pWebServer->Entries ].revents = 0;
 
     //
     //  Add the port to the port list
     //
-    pWebServer->ppPortList [ pWebServer->Entries ] = pPort;
+    pWebServer->ppPortList[ pWebServer->Entries ] = pPort;
 
     //
     //  Account for the new entry
@@ -263,7 +263,7 @@ PortRemove (
     //
     //  Locate the specified socket file descriptor
     //
-    if ( SocketFD == pFdList [ Index ].fd ) {
+    if ( SocketFD == pFdList[ Index ].fd ) {
       //
       //  Determine if this is the listen port
       //
@@ -279,7 +279,7 @@ PortRemove (
       //
       //  Free the port structure
       //
-      gBS->FreePool ( ppPortList [ Index ]);
+      gBS->FreePool ( ppPortList[ Index ]);
 
       //
       //  Remove this port from the list by copying
@@ -287,13 +287,13 @@ PortRemove (
       //
       Entries -= 1;
       for ( ; Entries > Index; Index++ ) {
-        pFdList [ Index ] = pFdList [ Index + 1 ];
-        ppPortList [ Index ] = ppPortList [ Index + 1 ];
+        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;
+      pFdList[ Index ].fd = -1;
+      pFdList[ Index ].events = 0;
+      pFdList[ Index ].revents = 0;
+      ppPortList[ Index ] = NULL;
 
       //
       //  Update the number of entries in the list
@@ -337,7 +337,7 @@ PortWork (
   size_t LengthInBytes;
   int NewSocket;
   EFI_STATUS OpStatus;
-  struct sockaddr RemoteAddress;
+  struct sockaddr_in6 RemoteAddress;
   socklen_t RemoteAddressLength;
   EFI_STATUS Status;
 
@@ -355,14 +355,15 @@ PortWork (
     //
     //  Determine if this is a connection attempt
     //
-    if ( SocketFD == pWebServer->HttpListenPort ) {
+    if (( SocketFD == pWebServer->HttpListenPort )
+      || ( SocketFD == pWebServer->HttpListenPort6 )) {
       //
       //  Handle connection attempts
       //  Accepts arrive as read events
       //
       RemoteAddressLength = sizeof ( RemoteAddress );
       NewSocket = accept ( SocketFD,
-                           &RemoteAddress,
+                           (struct sockaddr *)&RemoteAddress,
                            &RemoteAddressLength );
       if ( -1 != NewSocket ) {
         if ( 0 != NewSocket ) {
@@ -439,8 +440,7 @@ PortWork (
           }
         }
       }
-      else
-      {
+      else {
         //
         //  Receive the file data
         //
@@ -562,9 +562,9 @@ SocketPoll (
 
 
 /**
-  Create the HTTP port for the web server
+  Create an HTTP port for the web server
 
-  This routine polls the network layer to create the HTTP port for the
+  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.
@@ -573,196 +573,93 @@ SocketPoll (
   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] 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
-WebServerTimer (
-  IN DT_WEB_SERVER * pWebServer
+WebServerListen (
+  IN DT_WEB_SERVER * pWebServer,
+  IN sa_family_t AddressFamily,
+  IN int Protocol,
+  IN UINT16 HttpPort,
+  OUT int * pPort
   )
 {
-  UINT16 HttpPort;
-  struct sockaddr_in WebServerAddress;
+  union {
+    struct sockaddr_in v4;
+    struct sockaddr_in6 v6;
+  } WebServerAddress;
   int SocketStatus;
   EFI_STATUS Status;
 
-  DEBUG (( DEBUG_SERVER_TIMER, "Entering WebServerTimer\r\n" ));
+  DEBUG (( DEBUG_SERVER_LISTEN, "Entering WebServerListen\r\n" ));
 
   //
-  //  Open the HTTP port on the server
+  //  Attempt to create the socket for the web server
   //
-  do {
-    do {
-      //
-      //  Complete the client operations
-      //
-      SocketPoll ( pWebServer );
-
-      //
-      //  Wait for a while
-      //
-      Status = gBS->CheckEvent ( pWebServer->TimerEvent );
-    } while ( EFI_SUCCESS != Status );
-
+  * pPort = socket ( AddressFamily, SOCK_STREAM, Protocol );
+  if ( -1 != *pPort ) {
     //
-    //  Attempt to create the socket for the web server
+    //  Build the socket address
     //
-    pWebServer->HttpListenPort = socket ( AF_INET,
-                                          SOCK_STREAM,
-                                          IPPROTO_TCP );
-    if ( -1 != pWebServer->HttpListenPort )
-    {
-      //
-      //  Set the socket address
-      //
-      ZeroMem ( &WebServerAddress, sizeof ( WebServerAddress ));
-      HttpPort = PcdGet16 ( WebServer_HttpPort );
-      DEBUG (( DEBUG_HTTP_PORT,
-                "HTTP Port: %d\r\n",
-                HttpPort ));
-      WebServerAddress.sin_len = sizeof ( WebServerAddress );
-      WebServerAddress.sin_family = AF_INET;
-      WebServerAddress.sin_addr.s_addr = INADDR_ANY;
-      WebServerAddress.sin_port = htons ( HttpPort );
+    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 ) {
       //
-      //  Bind the socket to the HTTP port
+      //  Enable connections to the HTTP port
       //
-      SocketStatus = bind ( pWebServer->HttpListenPort,
-                            (struct sockaddr *) &WebServerAddress,
-                            WebServerAddress.sin_len );
+      SocketStatus = listen ( *pPort, SOMAXCONN );
       if ( -1 != SocketStatus ) {
         //
-        //  Enable connections to the HTTP port
+        //  Add the HTTP port to the list of ports to poll
         //
-        SocketStatus = listen ( pWebServer->HttpListenPort,
-                                SOMAXCONN );
-      }
-  
-      //
-      //  Release the socket if necessary
-      //
-      if ( -1 == SocketStatus ) {
-        close ( pWebServer->HttpListenPort );
-        pWebServer->HttpListenPort = -1;
+        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 ));
+        }
       }
     }
 
     //
-    //  Wait until the socket is open
+    //  Release the socket if necessary
     //
-  }while ( -1 == pWebServer->HttpListenPort );
-
-  DEBUG (( DEBUG_SERVER_TIMER, "Exiting WebServerTimer\r\n" ));
-}
-
-
-/**
-  Start the web server port creation timer
-
-  @param [in] pWebServer  The web server control structure address.
-
-  @retval EFI_SUCCESS         The timer was successfully started.
-  @retval EFI_ALREADY_STARTED The timer is already running.
-  @retval Other               The timer failed to start.
-
-**/
-EFI_STATUS
-WebServerTimerStart (
-  IN DT_WEB_SERVER * pWebServer
-  )
-{
-  EFI_STATUS Status;
-  UINT64 TriggerTime;
-
-  DBG_ENTER ( );
-
-  //
-  //  Assume the timer is already running
-  //
-  Status = EFI_ALREADY_STARTED;
-  if ( !pWebServer->bTimerRunning ) {
-    //
-    //  Compute the poll interval
-    //
-    TriggerTime = HTTP_PORT_POLL_DELAY * ( 1000 * 10 );
-    Status = gBS->SetTimer ( pWebServer->TimerEvent,
-                             TimerPeriodic,
-                             TriggerTime );
-    if ( !EFI_ERROR ( Status )) {
-      DEBUG (( DEBUG_HTTP_PORT, "HTTP port timer started\r\n" ));
-
-      //
-      //  Mark the timer running
-      //
-      pWebServer->bTimerRunning = TRUE;
-    }
-    else {
-      DEBUG (( DEBUG_ERROR | DEBUG_HTTP_PORT,
-                "ERROR - Failed to start HTTP port timer, Status: %r\r\n",
-                Status ));
+    if ( -1 == SocketStatus ) {
+      close ( *pPort );
+      *pPort = -1;
     }
   }
 
-  //
-  //  Return the operation status
-  //
-  DBG_EXIT_STATUS ( Status );
-  return Status;
+  DEBUG (( DEBUG_SERVER_LISTEN, "Exiting WebServerListen\r\n" ));
 }
 
 
-/**
-  Stop the web server port creation timer
-
-  @param [in] pWebServer  The web server control structure address.
-
-  @retval EFI_SUCCESS   The HTTP port timer is stopped
-  @retval Other         Failed to stop the HTTP port timer
-
-**/
-EFI_STATUS
-WebServerTimerStop (
-  IN DT_WEB_SERVER * pWebServer
-  )
-{
-  EFI_STATUS Status;
-
-  DBG_ENTER ( );
-
-  //
-  //  Assume the timer is stopped
-  //
-  Status = EFI_SUCCESS;
-  if ( pWebServer->bTimerRunning ) {
-    //
-    //  Stop the port creation polling
-    //
-    Status = gBS->SetTimer ( pWebServer->TimerEvent,
-                             TimerCancel,
-                             0 );
-    if ( !EFI_ERROR ( Status )) {
-      DEBUG (( DEBUG_HTTP_PORT, "HTTP port timer stopped\r\n" ));
-
-      //
-      //  Mark the timer stopped
-      //
-      pWebServer->bTimerRunning = FALSE;
-    }
-    else {
-      DEBUG (( DEBUG_ERROR | DEBUG_HTTP_PORT,
-                "ERROR - Failed to stop HTTP port timer, Status: %r\r\n",
-                Status ));
-    }
-  }
-
-  //
-  //  Return the operation status
-  //
-  DBG_EXIT_STATUS ( Status );
-  return Status;
-}
-
 /**
   Entry point for the web server application.
 
@@ -778,8 +675,19 @@ main (
   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
@@ -791,12 +699,18 @@ main (
                               NULL,
                               &pWebServer->TimerEvent );
   if ( !EFI_ERROR ( Status )) {
-    Status = WebServerTimerStart ( pWebServer );
+    TriggerTime = HTTP_PORT_POLL_DELAY * ( 1000 * 10 );
+    Status = gBS->SetTimer ( pWebServer->TimerEvent,
+                             TimerPeriodic,
+                             TriggerTime );
     if ( !EFI_ERROR ( Status )) {
       //
       //  Run the web server forever
       //
-      for ( ; ; ) {
+      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
@@ -804,45 +718,72 @@ main (
         //  the IP address and initialize the upper layers
         //  of the network stack.
         //
-        WebServerTimer ( pWebServer );
-
-        //
-        //  Add the HTTP port to the list of ports
-        //
-        Status = PortAdd ( pWebServer, pWebServer->HttpListenPort );
-        if ( !EFI_ERROR ( Status )) {
-          //
-          //  Poll the sockets for activity
-          //
+        if (( -1 == pWebServer->HttpListenPort )
+          || ( -1 == pWebServer->HttpListenPort6 )) {
           do {
-            SocketPoll ( pWebServer );
-          } while ( -1 != pWebServer->HttpListenPort );
+            //
+            //  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 );
+            }
 
-          //
-          //  The HTTP port failed the accept and was closed
-          //
+            //
+            //  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 );
         }
 
         //
-        //  Close the HTTP port if necessary
+        //  Poll the sockets for activity while both network
+        //  connections are connected
         //
-        if ( -1 != pWebServer->HttpListenPort ) {
-          close ( pWebServer->HttpListenPort );
-          pWebServer->HttpListenPort = -1;
-        }
-//
-// TODO: Remove the following test code
-//  Exit when the network connection is broken
-//
-break;
-      }
+        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 );
 
       //
-      //  Done with the timer event
+      //  Stop the timer
       //
-      WebServerTimerStop ( pWebServer );
-      Status = gBS->CloseEvent ( pWebServer->TimerEvent );
+      gBS->SetTimer ( pWebServer->TimerEvent,
+                      TimerCancel,
+                      0 );
     }
+
+    //
+    //  Done with the timer event
+    //
+    gBS->CloseEvent ( pWebServer->TimerEvent );
   }
 
   //