/** @file
Data source for network testing.
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 <errno.h>
#include <Uefi.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <netinet/in.h>
#include <sys/EfiSysCall.h>
#include <sys/poll.h>
#include <sys/socket.h>
#define DATA_SAMPLE_SHIFT 5 ///< Shift for number of samples
#define MAX_CONNECTIONS ( 1 + 16 ) ///< Maximum number of client connections
#define RANGE_SWITCH ( 1024 * 1024 ) ///< Switch display ranges
#define DATA_RATE_UPDATE_SHIFT 2 ///< 2n seconds between updates
#define AVERAGE_SHIFT_COUNT ( 6 - DATA_RATE_UPDATE_SHIFT ) ///< 2n samples in average
#define DATA_SAMPLES ( 1 << DATA_SAMPLE_SHIFT ) ///< Number of samples
#define TPL_DATASINK TPL_CALLBACK ///< Synchronization TPL
#define PACKET_SIZE 1448 ///< Size of data packets
#define DATA_BUFFER_SIZE (( 65536 / PACKET_SIZE ) * PACKET_SIZE ) ///< Buffer size in bytes
typedef struct _DT_PORT {
UINT64 BytesTotal;
struct sockaddr_in6 IpAddress;
UINT32 In;
UINT32 Samples;
UINT64 BytesReceived[ DATA_SAMPLES ];
} DT_PORT;
volatile BOOLEAN bTick;
BOOLEAN bTimerRunning;
struct sockaddr_in6 LocalAddress;
EFI_EVENT pTimer;
int ListenSocket;
UINT8 Buffer[ DATA_BUFFER_SIZE ];
struct pollfd PollFd[ MAX_CONNECTIONS ];
DT_PORT Port[ MAX_CONNECTIONS ];
nfds_t MaxPort;
//
// Forward routine declarations
//
EFI_STATUS TimerStart ( UINTN Milliseconds );
/**
Check for control C entered at console
@retval EFI_SUCCESS Control C not entered
@retval EFI_ABORTED Control C entered
**/
EFI_STATUS
ControlCCheck (
)
{
EFI_STATUS Status;
//
// Assume no user intervention
//
Status = EFI_SUCCESS;
//
// Display user stop request
//
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_INFO,
"User stop request!\r\n" ));
}
//
// Return the check status
//
return Status;
}
/**
Accept a socket connection
@retval EFI_SUCCESS The application is running normally
@retval EFI_NOT_STARTED Error with the listen socket
@retval Other The user stopped the application
**/
EFI_STATUS
SocketAccept (
)
{
INT32 SocketStatus;
EFI_STATUS Status;
INTN Index;
//
// Assume failure
//
Status = EFI_DEVICE_ERROR;
//
// Bind to the local address
//
SocketStatus = bind ( ListenSocket,
(struct sockaddr *) &LocalAddress,
LocalAddress.sin6_len );
if ( 0 == SocketStatus ) {
//
// Start listening on the local socket
//
SocketStatus = listen ( ListenSocket, 5 );
if ( 0 == SocketStatus ) {
//
// Local socket in the listen state
//
Status = EFI_SUCCESS;
//
// Allocate a port
//
Index = MaxPort++;
PollFd[ Index ].fd = ListenSocket;
PollFd[ Index ].events = POLLRDNORM | POLLHUP;
PollFd[ Index ].revents = 0;
ZeroMem ( &Port[ Index ], sizeof ( Port[ Index ]));
}
}
//
// Return the operation status
//
return Status;
}
/**
Close the socket
@retval EFI_SUCCESS The application is running normally
@retval Other The user stopped the application
**/
EFI_STATUS
SocketClose (
)
{
INT32 CloseStatus;
EFI_STATUS Status;
//
// Determine if the socket is open
//
Status = EFI_DEVICE_ERROR;
if ( -1 != ListenSocket ) {
//
// Attempt to close the socket
//
CloseStatus = close ( ListenSocket );
if ( 0 == CloseStatus ) {
DEBUG (( DEBUG_INFO,
"0x%08x: Socket closed\r\n",
ListenSocket ));
ListenSocket = -1;
Status = EFI_SUCCESS;
}
else {
DEBUG (( DEBUG_ERROR,
"ERROR: Failed to close socket, errno: %d\r\n",
errno ));
}
}
//
// Return the operation status
//
return Status;
}
/**
Create the socket
@param [in] Family Network family, AF_INET or AF_INET6
@retval EFI_SUCCESS The application is running normally
@retval Other The user stopped the application
**/
EFI_STATUS
SocketNew (
sa_family_t Family
)
{
EFI_STATUS Status;
//
// Get the port number
//
ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));
LocalAddress.sin6_len = sizeof ( LocalAddress );
LocalAddress.sin6_family = Family;
LocalAddress.sin6_port = htons ( PcdGet16 ( DataSource_Port ));
//
// Loop creating the socket
//
DEBUG (( DEBUG_INFO,
"Creating the socket\r\n" ));
//
// Check for user stop request
//
Status = ControlCCheck ( );
if ( !EFI_ERROR ( Status )) {
//
// Attempt to create the socket
//
ListenSocket = socket ( LocalAddress.sin6_family,
SOCK_STREAM,
IPPROTO_TCP );
if ( -1 != ListenSocket ) {
DEBUG (( DEBUG_INFO,
"0x%08x: Socket created\r\n",
ListenSocket ));
}
else {
Status = EFI_NOT_STARTED;
}
}
//
// Return the operation status
//
return Status;
}
/**
Poll the socket for more work
@retval EFI_SUCCESS The application is running normally
@retval EFI_NOT_STARTED Listen socket error
@retval Other The user stopped the application
**/
EFI_STATUS
SocketPoll (
)
{
BOOLEAN bRemoveSocket;
BOOLEAN bListenError;
size_t BytesReceived;
int CloseStatus;
nfds_t Entry;
INTN EntryPrevious;
int FdCount;
nfds_t Index;
socklen_t LengthInBytes;
struct sockaddr_in * pPortIpAddress4;
struct sockaddr_in6 * pPortIpAddress6;
struct sockaddr_in * pRemoteAddress4;
struct sockaddr_in6 * pRemoteAddress6;
struct sockaddr_in6 RemoteAddress;
int Socket;
EFI_STATUS Status;
EFI_TPL TplPrevious;
//
// Check for control-C
//
pRemoteAddress4 = (struct sockaddr_in *)&RemoteAddress;
pRemoteAddress6 = (struct sockaddr_in6 *)&RemoteAddress;
bListenError = FALSE;
Status = ControlCCheck ( );
if ( !EFI_ERROR ( Status )) {
//
// Poll the sockets
//
FdCount = poll ( &PollFd[0],
MaxPort,
0 );
if ( -1 == FdCount ) {
//
// Poll error
//
DEBUG (( DEBUG_ERROR,
"ERROR - Poll error, errno: %d\r\n",
errno ));
Status = EFI_DEVICE_ERROR;
}
else {
//
// Process the poll output
//
Index = 0;
while ( FdCount ) {
bRemoveSocket = FALSE;
//
// Account for this descriptor
//
pPortIpAddress4 = (struct sockaddr_in *)&Port[ Index ].IpAddress;
pPortIpAddress6 = (struct sockaddr_in6 *)&Port[ Index ].IpAddress;
if ( 0 != PollFd[ Index ].revents ) {
FdCount -= 1;
}
//
// Check for a broken connection
//
if ( 0 != ( PollFd[ Index ].revents & POLLHUP )) {
bRemoveSocket = TRUE;
if ( ListenSocket == PollFd[ Index ].fd ) {
bListenError = TRUE;
DEBUG (( DEBUG_ERROR,
"ERROR - Network closed on listen socket, errno: %d\r\n",
errno ));
}
else {
if ( AF_INET == pPortIpAddress4->sin_family ) {
DEBUG (( DEBUG_ERROR,
"ERROR - Network closed on socket %d.%d.%d.%d:%d, errno: %d\r\n",
pPortIpAddress4->sin_addr.s_addr & 0xff,
( pPortIpAddress4->sin_addr.s_addr >> 8 ) & 0xff,
( pPortIpAddress4->sin_addr.s_addr >> 16 ) & 0xff,
( pPortIpAddress4->sin_addr.s_addr >> 24 ) & 0xff,
ntohs ( pPortIpAddress4->sin_port ),
errno ));
}
else {
DEBUG (( DEBUG_ERROR,
"ERROR - Network closed on socket [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d, errno: %d\r\n",
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
ntohs ( pPortIpAddress6->sin6_port ),
errno ));
}
//
// Close the socket
//
CloseStatus = close ( PollFd[ Index ].fd );
if ( 0 == CloseStatus ) {
bRemoveSocket = TRUE;
if ( AF_INET == pPortIpAddress4->sin_family ) {
DEBUG (( DEBUG_INFO,
"0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",
PollFd[ Index ].fd,
pPortIpAddress4->sin_addr.s_addr & 0xff,
( pPortIpAddress4->sin_addr.s_addr >> 8 ) & 0xff,
( pPortIpAddress4->sin_addr.s_addr >> 16 ) & 0xff,
( pPortIpAddress4->sin_addr.s_addr >> 24 ) & 0xff,
ntohs ( pPortIpAddress4->sin_port )));
}
else {
DEBUG (( DEBUG_INFO,
"0x%08x: Socket closed for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
PollFd[ Index ].fd,
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
ntohs ( pPortIpAddress6->sin6_port )));
}
}
else {
if ( AF_INET == pPortIpAddress4->sin_family ) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to close socket 0x%08x for %d.%d.%d.%d:%d, errno: %d\r\n",
PollFd[ Index ].fd,
pPortIpAddress4->sin_addr.s_addr & 0xff,
( pPortIpAddress4->sin_addr.s_addr >> 8 ) & 0xff,
( pPortIpAddress4->sin_addr.s_addr >> 16 ) & 0xff,
( pPortIpAddress4->sin_addr.s_addr >> 24 ) & 0xff,
ntohs ( pPortIpAddress4->sin_port ),
errno ));
}
else {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to close socket 0x%08x for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d, errno: %d\r\n",
PollFd[ Index ].fd,
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
ntohs ( pPortIpAddress6->sin6_port ),
errno ));
}
}
}
}
//
// Check for a connection or read data
//
if ( 0 != ( PollFd[ Index ].revents & POLLRDNORM )) {
//
// Check for a connection
//
if ( ListenSocket == PollFd[ Index ].fd ) {
//
// Another client connection was received
//
LengthInBytes = sizeof ( RemoteAddress );
Socket = accept ( ListenSocket,
(struct sockaddr *) &RemoteAddress,
&LengthInBytes );
if ( -1 == Socket ) {
//
// Listen socket error
//
bListenError = TRUE;
bRemoveSocket = TRUE;
DEBUG (( DEBUG_ERROR,
"ERROR - Listen socket failure, errno: %d\r\n",
errno ));
}
else {
//
// Determine if there is room for this connection
//
if (( MAX_CONNECTIONS <= MaxPort )
|| ((( MAX_CONNECTIONS - 1 ) == MaxPort ) && ( -1 == ListenSocket ))) {
//
// Display the connection
//
if ( AF_INET == pRemoteAddress4->sin_family ) {
Print ( L"Rejecting connection to remote system %d.%d.%d.%d:%d\r\n",
pRemoteAddress4->sin_addr.s_addr & 0xff,
( pRemoteAddress4->sin_addr.s_addr >> 8 ) & 0xff,
( pRemoteAddress4->sin_addr.s_addr >> 16 ) & 0xff,
( pRemoteAddress4->sin_addr.s_addr >> 24 ) & 0xff,
ntohs ( pRemoteAddress4->sin_port ));
}
else {
Print ( L"Rejecting connection to remote system [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
ntohs ( pRemoteAddress6->sin6_port ));
}
//
// No room for this connection
// Close the connection
//
CloseStatus = close ( Socket );
if ( 0 == CloseStatus ) {
bRemoveSocket = TRUE;
if ( AF_INET == pRemoteAddress4->sin_family ) {
DEBUG (( DEBUG_INFO,
"0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",
PollFd[ Index ].fd,
pRemoteAddress4->sin_addr.s_addr & 0xff,
( pRemoteAddress4->sin_addr.s_addr >> 8 ) & 0xff,
( pRemoteAddress4->sin_addr.s_addr >> 16 ) & 0xff,
( pRemoteAddress4->sin_addr.s_addr >> 24 ) & 0xff,
ntohs ( pRemoteAddress4->sin_port )));
}
else {
DEBUG (( DEBUG_INFO,
"0x%08x: Socket closed for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
PollFd[ Index ].fd,
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
ntohs ( pRemoteAddress6->sin6_port )));
}
}
else {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to close socket 0x%08x, errno: %d\r\n",
PollFd[ Index ].fd,
errno ));
}
//
// Keep the application running
// No issue with the listen socket
//
Status = EFI_SUCCESS;
}
else {
//
// Display the connection
//
if ( AF_INET == pRemoteAddress4->sin_family ) {
Print ( L"Connected to remote system %d.%d.%d.%d:%d\r\n",
pRemoteAddress4->sin_addr.s_addr & 0xff,
( pRemoteAddress4->sin_addr.s_addr >> 8 ) & 0xff,
( pRemoteAddress4->sin_addr.s_addr >> 16 ) & 0xff,
( pRemoteAddress4->sin_addr.s_addr >> 24 ) & 0xff,
ntohs ( pRemoteAddress4->sin_port ));
}
else {
Print ( L"Connected to remote system [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
ntohs ( pRemoteAddress6->sin6_port ));
}
//
// Allocate the client connection
//
Index = MaxPort++;
ZeroMem ( &Port[ Index ], sizeof ( Port[ Index ]));
CopyMem ( pPortIpAddress6, pRemoteAddress6, sizeof ( *pRemoteAddress6 ));
PollFd[ Index ].fd = Socket;
PollFd[ Index ].events = POLLRDNORM | POLLHUP;
PollFd[ Index ].revents = 0;
}
}
}
else {
//
// Data received
//
BytesReceived = read ( PollFd[ Index ].fd,
&Buffer,
sizeof ( Buffer ));
if ( 0 < BytesReceived ) {
//
// Display the amount of data received
//
if ( AF_INET == pPortIpAddress4->sin_family ) {
DEBUG (( DEBUG_INFO,
"0x%08x: Socket received 0x%08x bytes from %d.%d.%d.%d:%d\r\n",
PollFd[ Index ].fd,
BytesReceived,
pPortIpAddress4->sin_addr.s_addr & 0xff,
( pPortIpAddress4->sin_addr.s_addr >> 8 ) & 0xff,
( pPortIpAddress4->sin_addr.s_addr >> 16 ) & 0xff,
( pPortIpAddress4->sin_addr.s_addr >> 24 ) & 0xff,
ntohs ( pPortIpAddress4->sin_port )));
}
else {
DEBUG (( DEBUG_INFO,
"0x%08x: Socket received 0x%08x bytes from [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
PollFd[ Index ].fd,
BytesReceived,
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
ntohs ( pPortIpAddress6->sin6_port )));
}
//
// Synchronize with the TimerCallback routine
//
TplPrevious = gBS->RaiseTPL ( TPL_DATASINK );
//
// Account for the data received
//
Port[ Index ].BytesTotal += BytesReceived;
//
// Release the synchronization with the TimerCallback routine
//
gBS->RestoreTPL ( TplPrevious );
}
else if ( -1 == BytesReceived ) {
//
// Close the socket
//
if ( AF_INET == pPortIpAddress4->sin_family ) {
DEBUG (( DEBUG_INFO,
"ERROR - Receive failure for %d.%d.%d.%d:%d, errno: %d\r\n",
pPortIpAddress4->sin_addr.s_addr & 0xff,
( pPortIpAddress4->sin_addr.s_addr >> 8 ) & 0xff,
( pPortIpAddress4->sin_addr.s_addr >> 16 ) & 0xff,
( pPortIpAddress4->sin_addr.s_addr >> 24 ) & 0xff,
ntohs ( pPortIpAddress4->sin_port ),
errno ));
}
else {
DEBUG (( DEBUG_INFO,
"ERROR - Receive failure for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d, errno: %d\r\n",
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
ntohs ( pPortIpAddress6->sin6_port ),
errno ));
}
CloseStatus = close ( PollFd[ Index ].fd );
if ( 0 == CloseStatus ) {
bRemoveSocket = TRUE;
if ( AF_INET == pPortIpAddress4->sin_family ) {
DEBUG (( DEBUG_INFO,
"0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",
PollFd[ Index ].fd,
pPortIpAddress4->sin_addr.s_addr & 0xff,
( pPortIpAddress4->sin_addr.s_addr >> 8 ) & 0xff,
( pPortIpAddress4->sin_addr.s_addr >> 16 ) & 0xff,
( pPortIpAddress4->sin_addr.s_addr >> 24 ) & 0xff,
ntohs ( pPortIpAddress4->sin_port )));
}
else {
DEBUG (( DEBUG_INFO,
"0x%08x: Socket closed for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
PollFd[ Index ].fd,
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
ntohs ( pPortIpAddress6->sin6_port )));
}
}
else {
if ( AF_INET == pPortIpAddress4->sin_family ) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to close socket 0x%08x for %d.%d.%d.%d:%d, errno: %d\r\n",
PollFd[ Index ].fd,
pPortIpAddress4->sin_addr.s_addr & 0xff,
( pPortIpAddress4->sin_addr.s_addr >> 8 ) & 0xff,
( pPortIpAddress4->sin_addr.s_addr >> 16 ) & 0xff,
( pPortIpAddress4->sin_addr.s_addr >> 24 ) & 0xff,
ntohs ( pPortIpAddress4->sin_port ),
errno ));
}
else {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to close socket 0x%08x for [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d, errno: %d\r\n",
PollFd[ Index ].fd,
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ],
pPortIpAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ],
ntohs ( pPortIpAddress6->sin6_port ),
errno ));
}
}
}
//
// Keep the application running
// No issue with the listen socket
//
Status = EFI_SUCCESS;
}
}
//
// Remove the socket if necessary
//
if ( bRemoveSocket ) {
DEBUG (( DEBUG_INFO,
"0x%08x: Socket removed from polling\r\n",
PollFd[ Index ].fd ));
MaxPort -= 1;
for ( Entry = Index + 1; MaxPort >= Entry; Entry++ ) {
EntryPrevious = Entry;
CopyMem ( &Port[ EntryPrevious ],
&Port[ Entry ],
sizeof ( Port[ Entry ]));
PollFd[ EntryPrevious ].events = PollFd[ Entry ].events;
PollFd[ EntryPrevious ].fd = PollFd[ Entry ].fd;
PollFd[ EntryPrevious ].revents = PollFd[ Entry ].revents;
}
PollFd[ MaxPort ].fd = -1;
Index -= 1;
}
//
// Account for this socket
//
Index += 1;
}
}
}
//
// Return the listen failure if necessary
//
if (( !EFI_ERROR ( Status )) && bListenError ) {
Status = EFI_NOT_STARTED;
}
//
// Return the poll status
//
return Status;
}
/**
Handle the timer callback
@param [in] Event Event that caused this callback
@param [in] pContext Context for this routine
**/
VOID
EFIAPI
TimerCallback (
IN EFI_EVENT Event,
IN VOID * pContext
)
{
UINT32 Average;
UINT64 BitsPerSecond;
UINT64 BytesReceived;
UINT32 Count;
nfds_t Index;
UINT64 TotalBytes;
//
// Notify the other code of the timer tick
//
bTick = TRUE;
//
// Walk the list of ports
//
for ( Index = 0; MaxPort > Index; Index++ ) {
//
// Determine if any data was received
//
BytesReceived = Port[ Index ].BytesTotal;
if (( ListenSocket != PollFd[ Index ].fd )
&& ( 0 != BytesReceived )) {
//
// Update the received data samples
//
Port[ Index ].BytesTotal = 0;
Port[ Index ].BytesReceived [ Port[ Index ].In ] = BytesReceived;
Port[ Index ].In += 1;
if ( DATA_SAMPLES <= Port[ Index ].In ) {
Port[ Index ].In = 0;
}
//
// Separate the samples
//
if ( DATA_SAMPLES == Port[ Index ].Samples ) {
Print ( L"---------- Stable average ----------\r\n" );
}
Port[ Index ].Samples += 1;
//
// Compute the data rate
//
TotalBytes = 0;
for ( Count = 0; DATA_SAMPLES > Count; Count++ )
{
TotalBytes += Port[ Index ].BytesReceived[ Count ];
}
Average = (UINT32)RShiftU64 ( TotalBytes, DATA_SAMPLE_SHIFT );
BitsPerSecond = Average * 8;
//
// Display the data rate
//
if (( RANGE_SWITCH >> 10 ) > Average ) {
Print ( L"Ave: %d Bytes/Sec, %Ld Bits/sec\r\n",
Average,
BitsPerSecond );
}
else {
BitsPerSecond /= 1000;
if ( RANGE_SWITCH > Average ) {
Print ( L"Ave: %d.%03d KiBytes/Sec, %Ld KBits/sec\r\n",
Average >> 10,
(( Average & 0x3ff ) * 1000 ) >> 10,
BitsPerSecond );
}
else {
BitsPerSecond /= 1000;
Average >>= 10;
if ( RANGE_SWITCH > Average ) {
Print ( L"Ave: %d.%03d MiBytes/Sec, %Ld MBits/sec\r\n",
Average >> 10,
(( Average & 0x3ff ) * 1000 ) >> 10,
BitsPerSecond );
}
else {
BitsPerSecond /= 1000;
Average >>= 10;
if ( RANGE_SWITCH > Average ) {
Print ( L"Ave: %d.%03d GiBytes/Sec, %Ld GBits/sec\r\n",
Average >> 10,
(( Average & 0x3ff ) * 1000 ) >> 10,
BitsPerSecond );
}
else {
BitsPerSecond /= 1000;
Average >>= 10;
if ( RANGE_SWITCH > Average ) {
Print ( L"Ave: %d.%03d TiBytes/Sec, %Ld TBits/sec\r\n",
Average >> 10,
(( Average & 0x3ff ) * 1000 ) >> 10,
BitsPerSecond );
}
else {
BitsPerSecond /= 1000;
Average >>= 10;
Print ( L"Ave: %d.%03d PiBytes/Sec, %Ld PBits/sec\r\n",
Average >> 10,
(( Average & 0x3ff ) * 1000 ) >> 10,
BitsPerSecond );
}
}
}
}
}
}
}
}
/**
Create the timer
@retval EFI_SUCCESS The timer was successfully created
@retval Other Timer initialization failed
**/
EFI_STATUS
TimerCreate (
)
{
EFI_STATUS Status;
//
// Create the timer
//
Status = gBS->CreateEvent ( EVT_TIMER | EVT_NOTIFY_SIGNAL,
TPL_DATASINK,
TimerCallback,
NULL,
&pTimer );
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to allocate the timer event, Status: %r\r\n",
Status ));
}
else {
DEBUG (( DEBUG_INFO,
"0x%08x: Timer created\r\n",
pTimer ));
}
//
// Return the operation status
//
return Status;
}
/**
Stop the timer
@retval EFI_SUCCESS The timer was stopped successfully
@retval Other The timer failed to stop
**/
EFI_STATUS
TimerStop (
)
{
EFI_STATUS Status;
//
// Assume success
//
Status = EFI_SUCCESS;
//
// Determine if the timer is running
//
if ( bTimerRunning ) {
//
// Stop the timer
//
Status = gBS->SetTimer ( pTimer,
TimerCancel,
0 );
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to stop the timer, Status: %r\r\n",
Status ));
}
else {
//
// Timer timer is now stopped
//
bTimerRunning = FALSE;
DEBUG (( DEBUG_INFO,
"0x%08x: Timer stopped\r\n",
pTimer ));
}
}
//
// Return the operation status
//
return Status;
}
/**
Start the timer
@param [in] Milliseconds The number of milliseconds between timer callbacks
@retval EFI_SUCCESS The timer was successfully created
@retval Other Timer initialization failed
**/
EFI_STATUS
TimerStart (
UINTN Milliseconds
)
{
EFI_STATUS Status;
UINT64 TimeDelay;
//
// Stop the timer if necessary
//
Status = EFI_SUCCESS;
if ( bTimerRunning ) {
Status = TimerStop ( );
}
if ( !EFI_ERROR ( Status )) {
//
// Compute the new delay
//
TimeDelay = Milliseconds;
TimeDelay *= 1000 * 10;
//
// Start the timer
//
Status = gBS->SetTimer ( pTimer,
TimerPeriodic,
TimeDelay );
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to start the timer, Status: %r\r\n",
Status ));
}
else {
//
// The timer is now running
//
bTimerRunning = TRUE;
DEBUG (( DEBUG_INFO,
"0x%08x: Timer running\r\n",
pTimer ));
}
}
//
// Return the operation status
//
return Status;
}
/**
Destroy the timer
@retval EFI_SUCCESS The timer was destroyed successfully
@retval Other Failed to destroy the timer
**/
EFI_STATUS
TimerDestroy (
)
{
EFI_STATUS Status;
//
// Assume success
//
Status = EFI_SUCCESS;
//
// Determine if the timer is running
//
if ( bTimerRunning ) {
//
// Stop the timer
//
Status = TimerStop ( );
}
if (( !EFI_ERROR ( Status )) && ( NULL != pTimer )) {
//
// Done with this timer
//
Status = gBS->CloseEvent ( pTimer );
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to free the timer event, Status: %r\r\n",
Status ));
}
else {
DEBUG (( DEBUG_INFO,
"0x%08x: Timer Destroyed\r\n",
pTimer ));
pTimer = NULL;
}
}
//
// Return the operation status
//
return Status;
}
/**
Receive data from the DataSource program to test a network's bandwidth.
@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
)
{
sa_family_t Family;
EFI_STATUS Status;
DEBUG (( DEBUG_INFO,
"DataSink starting\r\n" ));
//
// Determine the family to use
//
Family = ( 1 < Argc ) ? AF_INET6 : AF_INET;
//
// Use for/break instead of goto
//
for ( ; ; ) {
//
// Create the timer
//
bTick = TRUE;
Status = TimerCreate ( );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Start a timer to perform network polling and display updates
//
Status = TimerStart ( 1 * 1000 );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Loop forever waiting for abuse
//
do {
ListenSocket = -1;
do {
//
// Complete any client operations
//
Status = SocketPoll ( );
if ( EFI_ERROR ( Status )) {
//
// Control-C
//
break;
}
//
// Wait for a while
//
} while ( !bTick );
if ( EFI_ERROR ( Status )) {
//
// Control-C
//
break;
}
//
// Wait for the network layer to initialize
//
Status = SocketNew ( Family );
if ( EFI_ERROR ( Status )) {
continue;
}
//
// Wait for the remote network application to start
//
Status = SocketAccept ( );
if ( EFI_NOT_STARTED == Status ) {
Status = SocketClose ( );
continue;
}
else if ( EFI_SUCCESS != Status ) {
//
// Control-C
//
break;
}
//
// Receive data until the connection breaks
//
do {
Status = SocketPoll ( );
} while ( !EFI_ERROR ( Status ));
//
// Done with the socket
//
Status = SocketClose ( );
} while ( !EFI_ERROR ( Status ));
//
// Close the socket if necessary
//
SocketClose ( );
//
// All done
//
break;
}
//
// Stop the timer if necessary
//
TimerStop ( );
TimerDestroy ( );
//
// Return the operation status
//
DEBUG (( DEBUG_INFO,
"DataSink exiting, Status: %r\r\n",
Status ));
return Status;
}