]> git.proxmox.com Git - mirror_edk2.git/blobdiff - AppPkg/Applications/Sockets/DataSink/DataSink.c
Add Socket Library applications.
[mirror_edk2.git] / AppPkg / Applications / Sockets / DataSink / DataSink.c
diff --git a/AppPkg/Applications/Sockets/DataSink/DataSink.c b/AppPkg/Applications/Sockets/DataSink/DataSink.c
new file mode 100644 (file)
index 0000000..911cf36
--- /dev/null
@@ -0,0 +1,1029 @@
+/** @file\r
+  Data source for network testing.\r
+\r
+  Copyright (c) 2011, Intel Corporation\r
+  All rights reserved. This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <errno.h>\r
+#include <Uefi.h>\r
+\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+\r
+#include <netinet/in.h>\r
+\r
+#include <sys/EfiSysCall.h>\r
+#include <sys/poll.h>\r
+#include <sys/socket.h>\r
+\r
+\r
+#define MAX_CONNECTIONS       ( 1 + 16 )  ///<  Maximum number of client connections\r
+#define RANGE_SWITCH                2048  ///<  Switch display ranges\r
+#define DATA_RATE_UPDATE_SHIFT      2     ///<  2n seconds between updates\r
+#define AVERAGE_SHIFT_COUNT ( 6 - DATA_RATE_UPDATE_SHIFT )  ///<  2n samples in average\r
+\r
+#define TPL_DATASINK        TPL_CALLBACK  ///<  Synchronization TPL\r
+\r
+#define PACKET_SIZE                 1448  ///<  Size of data packets\r
+#define DATA_BUFFER_SIZE    (( 65536 / PACKET_SIZE ) * PACKET_SIZE )  ///<  Buffer size in bytes\r
+\r
+typedef struct _DT_PORT {\r
+  UINT64 BytesAverage;\r
+  UINT64 BytesPrevious;\r
+  UINT64 BytesTotal;\r
+  struct sockaddr_in RemoteAddress;\r
+  UINT64 Samples;\r
+} DT_PORT;\r
+\r
+volatile BOOLEAN bTick;\r
+BOOLEAN bTimerRunning;\r
+struct sockaddr_in LocalAddress;\r
+EFI_EVENT pTimer;\r
+int ListenSocket;\r
+UINT8 Buffer [ DATA_BUFFER_SIZE ];\r
+struct pollfd PollFd [ MAX_CONNECTIONS ];\r
+DT_PORT Port [ MAX_CONNECTIONS ];\r
+nfds_t MaxPort;\r
+\r
+\r
+//\r
+//  Forward routine declarations\r
+//\r
+EFI_STATUS TimerStart ( UINTN Milliseconds );\r
+\r
+\r
+/**\r
+  Check for control C entered at console\r
+\r
+  @retval  EFI_SUCCESS  Control C not entered\r
+  @retval  EFI_ABORTED  Control C entered\r
+**/\r
+EFI_STATUS\r
+ControlCCheck (\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  //  Assume no user intervention\r
+  //\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  //  Display user stop request\r
+  //\r
+  if ( EFI_ERROR ( Status )) {\r
+    DEBUG (( DEBUG_INFO,\r
+              "User stop request!\r\n" ));\r
+  }\r
+\r
+  //\r
+  //  Return the check status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Accept a socket connection\r
+\r
+  @retval  EFI_SUCCESS      The application is running normally\r
+  @retval  EFI_NOT_STARTED  Error with the listen socket\r
+  @retval  Other            The user stopped the application\r
+**/\r
+EFI_STATUS\r
+SocketAccept (\r
+  )\r
+{\r
+  INT32 SocketStatus;\r
+  EFI_STATUS Status;\r
+  INTN Index;\r
+\r
+  //\r
+  //  Assume failure\r
+  //\r
+  Status = EFI_DEVICE_ERROR;\r
+\r
+  //\r
+  //  Bind to the local address\r
+  //\r
+  SocketStatus = bind ( ListenSocket,\r
+                        (struct sockaddr *) &LocalAddress,\r
+                        LocalAddress.sin_len );\r
+  if ( 0 == SocketStatus ) {\r
+    //\r
+    //  Start listening on the local socket\r
+    //\r
+    SocketStatus = listen ( ListenSocket, 5 );\r
+    if ( 0 == SocketStatus ) {\r
+      //\r
+      //  Local socket in the listen state\r
+      //\r
+      Status = EFI_SUCCESS;\r
+\r
+      //\r
+      //  Allocate a port\r
+      //\r
+      Index = MaxPort++;\r
+      PollFd [ Index ].fd = ListenSocket;\r
+      PollFd [ Index ].events = POLLRDNORM | POLLHUP;\r
+      PollFd [ Index ].revents = 0;\r
+      Port [ Index ].BytesAverage = 0;\r
+      Port [ Index ].BytesPrevious = 0;\r
+      Port [ Index ].BytesTotal = 0;\r
+      Port [ Index ].Samples = 0;\r
+      Port [ Index ].RemoteAddress.sin_len = 0;\r
+      Port [ Index ].RemoteAddress.sin_family = 0;\r
+      Port [ Index ].RemoteAddress.sin_port = 0;\r
+      Port [ Index ].RemoteAddress.sin_addr.s_addr= 0;\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Close the socket\r
+\r
+  @retval  EFI_SUCCESS  The application is running normally\r
+  @retval  Other        The user stopped the application\r
+**/\r
+EFI_STATUS\r
+SocketClose (\r
+  )\r
+{\r
+  INT32 CloseStatus;\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  //  Determine if the socket is open\r
+  //\r
+  Status = EFI_DEVICE_ERROR;\r
+  if ( -1 != ListenSocket ) {\r
+    //\r
+    //  Attempt to close the socket\r
+    //\r
+    CloseStatus = close ( ListenSocket );\r
+    if ( 0 == CloseStatus ) {\r
+      DEBUG (( DEBUG_INFO,\r
+                "0x%08x: Socket closed\r\n",\r
+                ListenSocket ));\r
+      ListenSocket = -1;\r
+      Status = EFI_SUCCESS;\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR: Failed to close socket, errno: %d\r\n",\r
+                errno ));\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Create the socket\r
+\r
+  @retval  EFI_SUCCESS  The application is running normally\r
+  @retval  Other        The user stopped the application\r
+**/\r
+EFI_STATUS\r
+SocketNew (\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  //  Get the port number\r
+  //\r
+  ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));\r
+  LocalAddress.sin_len = sizeof ( LocalAddress );\r
+  LocalAddress.sin_family = AF_INET;\r
+  LocalAddress.sin_port = htons ( PcdGet16 ( DataSource_Port ));\r
+  \r
+  //\r
+  //  Loop creating the socket\r
+  //\r
+  DEBUG (( DEBUG_INFO,\r
+            "Creating the socket\r\n" ));\r
+\r
+  //\r
+  //  Check for user stop request\r
+  //\r
+  Status = ControlCCheck ( );\r
+  if ( !EFI_ERROR ( Status )) {\r
+    //\r
+    //  Attempt to create the socket\r
+    //\r
+    ListenSocket = socket ( AF_INET,\r
+                            SOCK_STREAM,\r
+                            IPPROTO_TCP );\r
+    if ( -1 != ListenSocket ) {\r
+      DEBUG (( DEBUG_INFO,\r
+                "0x%08x: Socket created\r\n",\r
+                ListenSocket ));\r
+    }\r
+    else\r
+    {\r
+      Status = EFI_NOT_STARTED;\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Poll the socket for more work\r
+\r
+  @retval  EFI_SUCCESS      The application is running normally\r
+  @retval  EFI_NOT_STARTED  Listen socket error\r
+  @retval  Other            The user stopped the application\r
+**/\r
+EFI_STATUS\r
+SocketPoll (\r
+  )\r
+{\r
+  BOOLEAN bRemoveSocket;\r
+  BOOLEAN bListenError;\r
+  size_t BytesReceived;\r
+  int CloseStatus;\r
+  nfds_t Entry;\r
+  INTN EntryPrevious;\r
+  int FdCount;\r
+  nfds_t Index;\r
+  socklen_t LengthInBytes;\r
+  struct sockaddr_in RemoteAddress;\r
+  int Socket;\r
+  EFI_STATUS Status;\r
+  EFI_TPL TplPrevious;\r
+\r
+  //\r
+  //  Check for control-C\r
+  //\r
+  bListenError = FALSE;\r
+  Status = ControlCCheck ( );\r
+  if ( !EFI_ERROR ( Status )) {\r
+    //\r
+    //  Poll the sockets\r
+    //\r
+    FdCount = poll ( &PollFd[0],\r
+                     MaxPort,\r
+                     0 );\r
+    if ( -1 == FdCount ) {\r
+      //\r
+      //  Poll error\r
+      //\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Poll error, errno: %d\r\n",\r
+                errno ));\r
+      Status = EFI_DEVICE_ERROR;\r
+    }\r
+    else {\r
+      //\r
+      //  Process the poll output\r
+      //\r
+      Index = 0;\r
+      while ( FdCount ) {\r
+        bRemoveSocket = FALSE;\r
+\r
+        //\r
+        //  Account for this descriptor\r
+        //\r
+        if ( 0 != PollFd [ Index ].revents ) {\r
+          FdCount -= 1;\r
+        }\r
+\r
+        //\r
+        //  Check for a broken connection\r
+        //\r
+        if ( 0 != ( PollFd [ Index ].revents & POLLHUP )) {\r
+          bRemoveSocket = TRUE;\r
+          if ( ListenSocket == PollFd [ Index ].fd ) {\r
+            bListenError = TRUE;\r
+            DEBUG (( DEBUG_ERROR,\r
+                      "ERROR - Network closed on listen socket, errno: %d\r\n",\r
+                      errno ));\r
+          }\r
+          else {\r
+            DEBUG (( DEBUG_ERROR,\r
+                      "ERROR - Network closed on socket %d.%d.%d.%d:%d, errno: %d\r\n",\r
+                      Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff,\r
+                      ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
+                      ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
+                      ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
+                      htons ( Port [ Index ].RemoteAddress.sin_port ),\r
+                      errno ));\r
+\r
+            //\r
+            //  Close the socket\r
+            //\r
+            CloseStatus = close ( PollFd [ Index ].fd );\r
+            if ( 0 == CloseStatus ) {\r
+              bRemoveSocket = TRUE;\r
+              DEBUG (( DEBUG_INFO,\r
+                        "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",\r
+                        PollFd [ Index ].fd,\r
+                        Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff,\r
+                        ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
+                        ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
+                        ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
+                        htons ( Port [ Index ].RemoteAddress.sin_port )));\r
+            }\r
+            else {\r
+              DEBUG (( DEBUG_ERROR,\r
+                        "ERROR - Failed to close socket 0x%08x for %d.%d.%d.%d:%d, errno: %d\r\n",\r
+                        PollFd [ Index ].fd,\r
+                        Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff,\r
+                        ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
+                        ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
+                        ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
+                        htons ( Port [ Index ].RemoteAddress.sin_port ),\r
+                        errno ));\r
+            }\r
+          }\r
+        }\r
+        \r
+        //\r
+        //  Check for a connection or read data\r
+        //\r
+        if ( 0 != ( PollFd [ Index ].revents & POLLRDNORM )) {\r
+          //\r
+          //  Check for a connection\r
+          //\r
+          if ( ListenSocket == PollFd [ Index ].fd ) {\r
+            //\r
+            //  Another client connection was received\r
+            //\r
+            LengthInBytes = sizeof ( RemoteAddress );\r
+            Socket = accept ( ListenSocket,\r
+                              (struct sockaddr *) &RemoteAddress,\r
+                              &LengthInBytes );\r
+            if ( -1 == Socket ) {\r
+              //\r
+              //  Listen socket error\r
+              //\r
+              bListenError = TRUE;\r
+              bRemoveSocket = TRUE;\r
+              DEBUG (( DEBUG_ERROR,\r
+                        "ERROR - Listen socket failure, errno: %d\r\n",\r
+                        errno ));\r
+            }\r
+            else {\r
+              //\r
+              //  Determine if there is room for this connection\r
+              //\r
+              if (( MAX_CONNECTIONS <= MaxPort )\r
+                || ((( MAX_CONNECTIONS - 1 ) == MaxPort ) && ( -1 == ListenSocket ))) {\r
+                //\r
+                //  Display the connection\r
+                //\r
+                Print ( L"Rejecting connection to remote system %d.%d.%d.%d:%d\r\n",\r
+                        RemoteAddress.sin_addr.s_addr & 0xff,\r
+                        ( RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
+                        ( RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
+                        ( RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
+                        htons ( RemoteAddress.sin_port ));\r
+\r
+                //\r
+                //  No room for this connection\r
+                //  Close the connection\r
+                //\r
+                CloseStatus = close ( Socket );\r
+                if ( 0 == CloseStatus ) {\r
+                  bRemoveSocket = TRUE;\r
+                  DEBUG (( DEBUG_INFO,\r
+                            "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",\r
+                            PollFd [ Index ].fd,\r
+                            RemoteAddress.sin_addr.s_addr & 0xff,\r
+                            ( RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
+                            ( RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
+                            ( RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
+                            htons ( RemoteAddress.sin_port )));\r
+                }\r
+                else {\r
+                  DEBUG (( DEBUG_ERROR,\r
+                            "ERROR - Failed to close socket 0x%08x, errno: %d\r\n",\r
+                            PollFd [ Index ].fd,\r
+                            errno ));\r
+                }\r
+\r
+                //\r
+                //  Keep the application running\r
+                //  No issue with the listen socket\r
+                //\r
+                Status = EFI_SUCCESS;\r
+              }\r
+              else\r
+              {\r
+                //\r
+                //  Display the connection\r
+                //\r
+                Print ( L"Connected to remote system %d.%d.%d.%d:%d\r\n",\r
+                        RemoteAddress.sin_addr.s_addr & 0xff,\r
+                        ( RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
+                        ( RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
+                        ( RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
+                        htons ( RemoteAddress.sin_port ));\r
+\r
+                //\r
+                //  Allocate the client connection\r
+                //\r
+                Index = MaxPort++;\r
+                Port [ Index ].BytesAverage = 0;\r
+                Port [ Index ].BytesPrevious = 0;\r
+                Port [ Index ].BytesTotal = 0;\r
+                Port [ Index ].Samples = 0;\r
+                Port [ Index ].RemoteAddress.sin_len = RemoteAddress.sin_len;\r
+                Port [ Index ].RemoteAddress.sin_family = RemoteAddress.sin_family;\r
+                Port [ Index ].RemoteAddress.sin_port = RemoteAddress.sin_port;\r
+                Port [ Index ].RemoteAddress.sin_addr = RemoteAddress.sin_addr;\r
+                PollFd [ Index ].fd = Socket;\r
+                PollFd [ Index ].events = POLLRDNORM | POLLHUP;\r
+                PollFd [ Index ].revents = 0;\r
+              }\r
+            }\r
+          }\r
+          else {\r
+            //\r
+            //  Data received\r
+            //\r
+            BytesReceived = read ( PollFd [ Index ].fd,\r
+                                   &Buffer,\r
+                                   sizeof ( Buffer ));\r
+            if ( 0 < BytesReceived ) {\r
+              //\r
+              //  Display the amount of data received\r
+              //\r
+              DEBUG (( DEBUG_INFO,\r
+                        "0x%08x: Socket received 0x%08x bytes from %d.%d.%d.%d:%d\r\n",\r
+                        PollFd [ Index ].fd,\r
+                        BytesReceived,\r
+                        Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff,\r
+                        ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
+                        ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
+                        ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
+                        htons ( Port [ Index ].RemoteAddress.sin_port )));\r
+\r
+              //\r
+              //  Synchronize with the TimerCallback routine\r
+              //\r
+              TplPrevious = gBS->RaiseTPL ( TPL_DATASINK );\r
+\r
+              //\r
+              //  Account for the data received\r
+              //\r
+              Port [ Index ].BytesTotal += BytesReceived;\r
+\r
+              //\r
+              //  Release the synchronization with the TimerCallback routine\r
+              //\r
+              gBS->RestoreTPL ( TplPrevious );\r
+            }\r
+            else if ( -1 == BytesReceived ) {\r
+              //\r
+              //  Close the socket\r
+              //\r
+              DEBUG (( DEBUG_INFO,\r
+                        "ERROR - Receive failure for %d.%d.%d.%d:%d, errno: %d\r\n",\r
+                        Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff,\r
+                        ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
+                        ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
+                        ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
+                        htons ( Port [ Index ].RemoteAddress.sin_port ),\r
+                        errno ));\r
+              CloseStatus = close ( PollFd [ Index ].fd );\r
+              if ( 0 == CloseStatus ) {\r
+                bRemoveSocket = TRUE;\r
+                DEBUG (( DEBUG_INFO,\r
+                          "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",\r
+                          PollFd [ Index ].fd,\r
+                          Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff,\r
+                          ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
+                          ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
+                          ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
+                          htons ( Port [ Index ].RemoteAddress.sin_port )));\r
+              }\r
+              else {\r
+                DEBUG (( DEBUG_ERROR,\r
+                          "ERROR - Failed to close socket 0x%08x for %d.%d.%d.%d:%d, errno: %d\r\n",\r
+                          PollFd [ Index ].fd,\r
+                          Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff,\r
+                          ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
+                          ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
+                          ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
+                          htons ( Port [ Index ].RemoteAddress.sin_port ),\r
+                          errno ));\r
+              }\r
+            }\r
+\r
+            //\r
+            //  Keep the application running\r
+            //  No issue with the listen socket\r
+            //\r
+            Status = EFI_SUCCESS;\r
+          }\r
+        }\r
+\r
+        //\r
+        //  Remove the socket if necessary\r
+        //\r
+        if ( bRemoveSocket ) {\r
+          DEBUG (( DEBUG_INFO,\r
+                    "0x%08x: Socket removed from polling\r\n",\r
+                    PollFd [ Index ].fd ));\r
+          MaxPort -= 1;\r
+          for ( Entry = Index + 1; MaxPort >= Entry; Entry++ ) {\r
+            EntryPrevious = Entry;\r
+            Port [ EntryPrevious ].BytesAverage = Port [ Entry ].BytesAverage;\r
+            Port [ EntryPrevious ].BytesPrevious = Port [ Entry ].BytesPrevious;\r
+            Port [ EntryPrevious ].BytesTotal = Port [ Entry ].BytesTotal;\r
+            Port [ EntryPrevious ].RemoteAddress.sin_len = Port [ Entry ].RemoteAddress.sin_len;\r
+            Port [ EntryPrevious ].RemoteAddress.sin_family = Port [ Entry ].RemoteAddress.sin_family;\r
+            Port [ EntryPrevious ].RemoteAddress.sin_port = Port [ Entry ].RemoteAddress.sin_port;\r
+            Port [ EntryPrevious ].RemoteAddress.sin_addr.s_addr = Port [ Entry ].RemoteAddress.sin_addr.s_addr;\r
+            Port [ EntryPrevious ].Samples = Port [ Entry ].Samples;\r
+            PollFd [ EntryPrevious ].events = PollFd [ Entry ].events;\r
+            PollFd [ EntryPrevious ].fd = PollFd [ Entry ].fd;\r
+            PollFd [ EntryPrevious ].revents = PollFd [ Entry ].revents;\r
+          }\r
+          PollFd [ MaxPort ].fd = -1;\r
+          Index -= 1;\r
+        }\r
+\r
+        //\r
+        //  Account for this socket\r
+        //\r
+        Index += 1;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Return the listen failure if necessary\r
+  //\r
+  if (( !EFI_ERROR ( Status )) && bListenError ) {\r
+    Status = EFI_NOT_STARTED;\r
+  }\r
+\r
+  //\r
+  //  Return the poll status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Handle the timer callback\r
+\r
+  @param [in] Event     Event that caused this callback\r
+  @param [in] pContext  Context for this routine\r
+**/\r
+VOID\r
+TimerCallback (\r
+  IN EFI_EVENT Event,\r
+  IN VOID * pContext\r
+  )\r
+{\r
+  UINT64 Average;\r
+  UINT64 BytesReceived;\r
+  UINT32 Delta;\r
+  UINT64 DeltaBytes;\r
+  nfds_t Index;\r
+\r
+  //\r
+  //  Notify the other code of the timer tick\r
+  //\r
+  bTick = TRUE;\r
+\r
+  //\r
+  //  Walk the list of ports\r
+  //\r
+  for ( Index = 0; MaxPort > Index; Index++ ) {\r
+    //\r
+    //  Determine if any data was received\r
+    //\r
+    BytesReceived = Port [ Index ].BytesTotal;\r
+    if (( ListenSocket != PollFd [ Index ].fd )\r
+      && ( 0 != BytesReceived )) {\r
+      //\r
+      //  Update the average bytes per second\r
+      //\r
+      DeltaBytes = Port [ Index ].BytesAverage >> AVERAGE_SHIFT_COUNT;\r
+      Port [ Index ].BytesAverage -= DeltaBytes;\r
+      DeltaBytes = BytesReceived - Port [ Index ].BytesPrevious;\r
+      Port [ Index ].BytesPrevious = BytesReceived;\r
+      Port [ Index ].BytesAverage += DeltaBytes;\r
+\r
+      //\r
+      //  Separate the samples\r
+      //\r
+      if (( 2 << AVERAGE_SHIFT_COUNT ) == Port [ Index ].Samples ) {\r
+        Print ( L"---------- Stable average ----------\r\n" );\r
+      }\r
+      Port [ Index ].Samples += 1;\r
+\r
+      //\r
+      //  Display the data rate\r
+      //\r
+      Delta = (UINT32)( DeltaBytes >> DATA_RATE_UPDATE_SHIFT );\r
+      Average = Port [ Index ].BytesAverage >> ( AVERAGE_SHIFT_COUNT + DATA_RATE_UPDATE_SHIFT );\r
+      if ( Average < RANGE_SWITCH ) {\r
+        Print ( L"%d Bytes/sec, Ave: %d Bytes/Sec\r\n",\r
+                Delta,\r
+                (UINT32) Average );\r
+      }\r
+      else {\r
+        Average >>= 10;\r
+        if ( Average < RANGE_SWITCH ) {\r
+          Print ( L"%d Bytes/sec, Ave: %d KiBytes/Sec\r\n",\r
+                  Delta,\r
+                  (UINT32) Average );\r
+        }\r
+        else {\r
+          Average >>= 10;\r
+          if ( Average < RANGE_SWITCH ) {\r
+            Print ( L"%d Bytes/sec, Ave: %d MiBytes/Sec\r\n",\r
+                    Delta,\r
+                    (UINT32) Average );\r
+          }\r
+          else {\r
+            Average >>= 10;\r
+            if ( Average < RANGE_SWITCH ) {\r
+              Print ( L"%d Bytes/sec, Ave: %d GiBytes/Sec\r\n",\r
+                      Delta,\r
+                      (UINT32) Average );\r
+            }\r
+            else {\r
+              Average >>= 10;\r
+              if ( Average < RANGE_SWITCH ) {\r
+                Print ( L"%d Bytes/sec, Ave: %d TiBytes/Sec\r\n",\r
+                        Delta,\r
+                        Average );\r
+              }\r
+              else {\r
+                Average >>= 10;\r
+                Print ( L"%d Bytes/sec, Ave: %d PiBytes/Sec\r\n",\r
+                        Delta,\r
+                        (UINT32) Average );\r
+              }\r
+            }\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Create the timer\r
+\r
+  @retval  EFI_SUCCESS  The timer was successfully created\r
+  @retval  Other        Timer initialization failed\r
+**/\r
+EFI_STATUS\r
+TimerCreate (\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  //  Create the timer\r
+  //\r
+  Status = gBS->CreateEvent ( EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                              TPL_DATASINK,\r
+                              TimerCallback,\r
+                              NULL,\r
+                              &pTimer );\r
+  if ( EFI_ERROR ( Status )) {\r
+    DEBUG (( DEBUG_ERROR,\r
+              "ERROR - Failed to allocate the timer event, Status: %r\r\n",\r
+              Status ));\r
+  }\r
+  else {\r
+    DEBUG (( DEBUG_INFO,\r
+              "0x%08x: Timer created\r\n",\r
+              pTimer ));\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Stop the timer\r
+\r
+  @retval  EFI_SUCCESS  The timer was stopped successfully\r
+  @retval  Other        The timer failed to stop\r
+**/\r
+EFI_STATUS\r
+TimerStop (\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  //  Assume success\r
+  //\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  //  Determine if the timer is running\r
+  //\r
+  if ( bTimerRunning ) {\r
+    //\r
+    //  Stop the timer\r
+    //\r
+    Status = gBS->SetTimer ( pTimer,\r
+                             TimerCancel,\r
+                             0 );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to stop the timer, Status: %r\r\n",\r
+                Status ));\r
+    }\r
+    else {\r
+      //\r
+      //  Timer timer is now stopped\r
+      //\r
+      bTimerRunning = FALSE;\r
+      DEBUG (( DEBUG_INFO,\r
+                "0x%08x: Timer stopped\r\n",\r
+                pTimer ));\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Start the timer\r
+\r
+  @param [in] Milliseconds  The number of milliseconds between timer callbacks\r
+\r
+  @retval  EFI_SUCCESS  The timer was successfully created\r
+  @retval  Other        Timer initialization failed\r
+**/\r
+EFI_STATUS\r
+TimerStart (\r
+  UINTN Milliseconds\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+  UINT64 TimeDelay;\r
+\r
+  //\r
+  //  Stop the timer if necessary\r
+  //\r
+  Status = EFI_SUCCESS;\r
+  if ( bTimerRunning ) {\r
+    Status = TimerStop ( );\r
+  }\r
+  if ( !EFI_ERROR ( Status )) {\r
+    //\r
+    //  Compute the new delay\r
+    //\r
+    TimeDelay = Milliseconds;\r
+    TimeDelay *= 1000 * 10;\r
+\r
+    //\r
+    //  Start the timer\r
+    //\r
+    Status = gBS->SetTimer ( pTimer,\r
+                             TimerPeriodic,\r
+                             TimeDelay );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to start the timer, Status: %r\r\n",\r
+                Status ));\r
+    }\r
+    else {\r
+      //\r
+      //  The timer is now running\r
+      //\r
+      bTimerRunning = TRUE;\r
+      DEBUG (( DEBUG_INFO,\r
+        "0x%08x: Timer running\r\n",\r
+        pTimer ));\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Destroy the timer\r
+\r
+  @retval  EFI_SUCCESS  The timer was destroyed successfully\r
+  @retval  Other        Failed to destroy the timer\r
+**/\r
+EFI_STATUS\r
+TimerDestroy (\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  //\r
+  //  Assume success\r
+  //\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  //  Determine if the timer is running\r
+  //\r
+  if ( bTimerRunning ) {\r
+    //\r
+    //  Stop the timer\r
+    //\r
+    Status = TimerStop ( );\r
+  }\r
+  if (( !EFI_ERROR ( Status )) && ( NULL != pTimer )) {\r
+    //\r
+    //  Done with this timer\r
+    //\r
+    Status = gBS->CloseEvent ( pTimer );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR,\r
+                "ERROR - Failed to free the timer event, Status: %r\r\n",\r
+                Status ));\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_INFO,\r
+                "0x%08x: Timer Destroyed\r\n",\r
+                pTimer ));\r
+      pTimer = NULL;\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Receive data from the DataSource program to test a network's bandwidth.\r
+\r
+  @param [in] Argc  The number of arguments\r
+  @param [in] Argv  The argument value array\r
+\r
+  @retval  0        The application exited normally.\r
+  @retval  Other    An error occurred.\r
+**/\r
+int\r
+main (\r
+  IN int Argc,\r
+  IN char **Argv\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  DEBUG (( DEBUG_INFO,\r
+            "DataSink starting\r\n" ));\r
+\r
+  //\r
+  //  Use for/break instead of goto\r
+  //\r
+  for ( ; ; )\r
+  {\r
+    //\r
+    //  Create the timer\r
+    //\r
+    bTick = TRUE;\r
+    Status = TimerCreate ( );\r
+    if ( EFI_ERROR ( Status )) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Start a timer to perform network polling and display updates\r
+    //\r
+    Status = TimerStart ( 1 * 1000 );\r
+    if ( EFI_ERROR ( Status )) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Loop forever waiting for abuse\r
+    //\r
+    do {\r
+      ListenSocket = -1;\r
+      do {\r
+        //\r
+        //  Complete any client operations\r
+        //\r
+        Status = SocketPoll ( );\r
+        if ( EFI_ERROR ( Status )) {\r
+          //\r
+          //  Control-C\r
+          //\r
+          break;\r
+        }\r
+      \r
+        //\r
+        //  Wait for a while\r
+        //\r
+      } while ( !bTick );\r
+      if ( EFI_ERROR ( Status )) {\r
+        //\r
+        //  Control-C\r
+        //\r
+        break;\r
+      }\r
+      \r
+      //\r
+      //  Wait for the network layer to initialize\r
+      //\r
+      Status = SocketNew ( );\r
+      if ( EFI_ERROR ( Status )) {\r
+        continue;\r
+      }\r
+\r
+      //\r
+      //  Wait for the remote network application to start\r
+      //\r
+      Status = SocketAccept ( );\r
+      if ( EFI_NOT_STARTED == Status ) {\r
+        Status = SocketClose ( );\r
+        continue;\r
+      }\r
+      else if ( EFI_SUCCESS != Status ) {\r
+        //\r
+        //  Control-C\r
+        //\r
+        break;\r
+      }\r
+\r
+      //\r
+      //  Send data until the connection breaks\r
+      //\r
+      do {\r
+        Status = SocketPoll ( );\r
+      } while ( !EFI_ERROR ( Status ));\r
+\r
+      //\r
+      //  Done with the socket\r
+      //\r
+      Status = SocketClose ( );\r
+    } while ( !EFI_ERROR ( Status ));\r
+\r
+    //\r
+    //  Close the socket if necessary\r
+    //\r
+    SocketClose ( );\r
+\r
+    //\r
+    //  All done\r
+    //\r
+    break;\r
+  }\r
+\r
+  //\r
+  //  Stop the timer if necessary\r
+  //\r
+  TimerStop ( );\r
+  TimerDestroy ( );\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  DEBUG (( DEBUG_INFO,\r
+            "DataSink exiting, Status: %r\r\n",\r
+            Status ));\r
+  return Status;\r
+}\r