--- /dev/null
+/** @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