audk/AppPkg/Applications/Sockets/DataSource/DataSource.c

1750 lines
45 KiB
C

/** @file
Data source for network testing.
Copyright (c) 2011-2012, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#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 <Protocol/ServiceBinding.h>
#include <Protocol/Tcp4.h>
#include <sys/EfiSysCall.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#define DATA_SAMPLE_SHIFT 5 ///< Shift for number of samples
#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_DATASOURCE 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
//
// Socket Data
//
int Socket = -1;
//
// TCP V4 Data
//
BOOLEAN bTcp4; ///< TRUE if TCP4 is being used
BOOLEAN bTcp4Connected; ///< TRUE if connected to remote system
BOOLEAN bTcp4Connecting; ///< TRUE while connection in progress
UINTN Tcp4Index; ///< Index into handle array
EFI_HANDLE Tcp4Controller; ///< Network controller handle
EFI_HANDLE Tcp4Handle; ///< TCP4 port handle
EFI_TCP4_PROTOCOL * pTcp4Protocol; ///< TCP4 protocol pointer
EFI_SERVICE_BINDING_PROTOCOL * pTcp4Service; ///< TCP4 Service binding
EFI_TCP4_CONFIG_DATA Tcp4ConfigData;///< TCP4 configuration data
EFI_TCP4_OPTION Tcp4Option; ///< TCP4 port options
EFI_TCP4_CLOSE_TOKEN Tcp4CloseToken;///< Close control
EFI_TCP4_CONNECTION_TOKEN Tcp4ConnectToken; ///< Connection control
EFI_TCP4_LISTEN_TOKEN Tcp4ListenToken; ///< Listen control
EFI_TCP4_IO_TOKEN Tcp4TxToken; ///< Normal data token
//
// Timer Data
//
volatile BOOLEAN bTick;
BOOLEAN bTimerRunning;
EFI_EVENT pTimer;
//
// Remote IP Address Data
//
struct sockaddr_in6 RemoteHostAddress;
CHAR8 * pRemoteHost;
//
// Traffic Data
//
UINT64 TotalBytesSent;
UINT32 In;
UINT32 Samples;
UINT64 BytesSent[ DATA_SAMPLES ];
UINT8 Buffer[ DATA_BUFFER_SIZE ];
//
// 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;
}
/**
Get a digit
@param [in] pDigit The address of the next digit
@param [out] pValue The address to receive the value
@return Returns the address of the separator
**/
CHAR8 *
GetDigit (
CHAR8 * pDigit,
UINT32 * pValue
)
{
UINT32 Value;
//
// Walk the digits
//
Value = 0;
while (( '0' <= *pDigit ) && ( '9' >= *pDigit )) {
//
// Make room for the new least significant digit
//
Value *= 10;
//
// Convert the digit from ASCII to binary
//
Value += *pDigit - '0';
//
// Set the next digit
//
pDigit += 1;
}
//
// Return the value
//
*pValue = Value;
//
// Return the next separator
//
return pDigit;
}
/**
Get the IP address
@retval EFI_SUCCESS The IP address is valid
@retval Other Failure to convert the IP address
**/
EFI_STATUS
IpAddress (
)
{
struct sockaddr_in * pRemoteAddress4;
struct sockaddr_in6 * pRemoteAddress6;
UINT32 RemoteAddress;
EFI_STATUS Status;
UINT32 Value1;
UINT32 Value2;
UINT32 Value3;
UINT32 Value4;
UINT32 Value5;
UINT32 Value6;
UINT32 Value7;
UINT32 Value8;
//
// Assume failure
//
Status = EFI_INVALID_PARAMETER;
//
// Get the port number
//
ZeroMem ( &RemoteHostAddress, sizeof ( RemoteHostAddress ));
RemoteHostAddress.sin6_port = htons ( PcdGet16 ( DataSource_Port ));
pRemoteAddress4 = (struct sockaddr_in *)&RemoteHostAddress;
pRemoteAddress6 = &RemoteHostAddress;
//
// Convert the IP address from a string to a numeric value
//
if (( 4 == sscanf ( pRemoteHost,
"%d.%d.%d.%d",
&Value1,
&Value2,
&Value3,
&Value4 ))
&& ( 255 >= Value1 )
&& ( 255 >= Value2 )
&& ( 255 >= Value3 )
&& ( 255 >= Value4 )) {
//
// Build the IPv4 address
//
pRemoteAddress4->sin_len = sizeof ( *pRemoteAddress4 );
pRemoteAddress4->sin_family = AF_INET;
RemoteAddress = Value1
| ( Value2 << 8 )
| ( Value3 << 16 )
| ( Value4 << 24 );
pRemoteAddress4->sin_addr.s_addr = RemoteAddress;
Status = EFI_SUCCESS;
//
// Display the IP address
//
DEBUG (( DEBUG_INFO,
"%d.%d.%d.%d: Remote host IP address\r\n",
Value1,
Value2,
Value3,
Value4 ));
}
else if (( 8 == sscanf ( pRemoteHost,
"%x:%x:%x:%x:%x:%x:%x:%x",
&Value1,
&Value2,
&Value3,
&Value4,
&Value5,
&Value6,
&Value7,
&Value8 ))
&& ( 0xffff >= Value1 )
&& ( 0xffff >= Value2 )
&& ( 0xffff >= Value3 )
&& ( 0xffff >= Value4 )
&& ( 0xffff >= Value5 )
&& ( 0xffff >= Value6 )
&& ( 0xffff >= Value7 )
&& ( 0xffff >= Value8 )) {
//
// Build the IPv6 address
//
pRemoteAddress6->sin6_len = sizeof ( *pRemoteAddress6 );
pRemoteAddress6->sin6_family = AF_INET6;
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 0 ] = (UINT8)( Value1 >> 8 );
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 1 ] = (UINT8)Value1;
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 2 ] = (UINT8)( Value2 >> 8 );
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 3 ] = (UINT8)Value2;
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 4 ] = (UINT8)( Value3 >> 8 );
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 5 ] = (UINT8)Value3;
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 6 ] = (UINT8)( Value4 >> 8 );
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 7 ] = (UINT8)Value4;
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 8 ] = (UINT8)( Value5 >> 8 );
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 9 ] = (UINT8)Value5;
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 10 ] = (UINT8)( Value6 >> 8 );
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 11 ] = (UINT8)Value6;
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 12 ] = (UINT8)( Value7 >> 8 );
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 13 ] = (UINT8)Value7;
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 14 ] = (UINT8)( Value8 >> 8 );
pRemoteAddress6->sin6_addr.__u6_addr.__u6_addr8[ 15 ] = (UINT8)Value8;
Status = EFI_SUCCESS;
//
// Display the IP address
//
DEBUG (( DEBUG_INFO,
"[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]: Remote host IP address\r\n",
Value1,
Value2,
Value3,
Value4,
Value5,
Value6,
Value7,
Value8 ));
}
else {
Print ( L"ERROR - Invalid IP address!\r\n" );
}
//
// 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 (
)
{
int CloseStatus;
EFI_STATUS Status;
//
// Determine if the socket is open
//
Status = EFI_DEVICE_ERROR;
if ( -1 != Socket ) {
//
// Attempt to close the socket
//
CloseStatus = close ( Socket );
if ( 0 == CloseStatus ) {
DEBUG (( DEBUG_INFO,
"0x%08x: Socket closed\r\n",
Socket ));
Socket = -1;
Status = EFI_SUCCESS;
}
else {
DEBUG (( DEBUG_ERROR,
"ERROR: Failed to close socket, errno: %d\r\n",
errno ));
}
}
//
// Return the operation status
//
return Status;
}
/**
Connect the socket
@retval EFI_SUCCESS The application is running normally
@retval Other The user stopped the application
**/
EFI_STATUS
SocketConnect (
)
{
int ConnectStatus;
struct sockaddr_in * pRemoteAddress4;
struct sockaddr_in6 * pRemoteAddress6;
EFI_STATUS Status;
//
// Display the connecting message
//
pRemoteAddress4 = (struct sockaddr_in *)&RemoteHostAddress;
pRemoteAddress6 = &RemoteHostAddress;
if ( AF_INET == pRemoteAddress6->sin6_family ) {
Print ( L"Connecting 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"Connecting to remote system [%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 ));
}
//
// Connect to the remote system
//
Status = EFI_SUCCESS;
do {
//
// Check for user stop request
//
while ( !bTick ) {
Status = ControlCCheck ( );
if ( EFI_ERROR ( Status )) {
break;
}
}
bTick = FALSE;
if ( EFI_ERROR ( Status )) {
break;
}
//
// Connect to the remote system
//
ConnectStatus = connect ( Socket,
(struct sockaddr *)pRemoteAddress6,
pRemoteAddress6->sin6_len );
if ( -1 != ConnectStatus ) {
if ( AF_INET == pRemoteAddress6->sin6_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]:%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 ));
}
Print ( L"ConnectStatus: %d, Status: %r\r\n", ConnectStatus, Status );
}
else {
//
// Close the socket and try again
//
if ( EAGAIN != errno ) {
Status = EFI_NOT_STARTED;
break;
}
}
} while ( -1 == ConnectStatus );
//
// Return the operation status
//
Print ( L"SocketConnect returning Status: %r\r\n", 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;
//
// Loop creating the socket
//
DEBUG (( DEBUG_INFO,
"Creating the socket\r\n" ));
do {
//
// Check for user stop request
//
Status = ControlCCheck ( );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Attempt to create the socket
//
Socket = socket ( Family,
SOCK_STREAM,
IPPROTO_TCP );
if ( -1 != Socket ) {
DEBUG (( DEBUG_INFO,
"0x%08x: Socket created\r\n",
Socket ));
break;
}
} while ( -1 == Socket );
//
// Return the operation status
//
return Status;
}
/**
Send data over the socket
@retval EFI_SUCCESS The application is running normally
@retval Other The user stopped the application
**/
EFI_STATUS
SocketSend (
)
{
size_t BytesSent;
EFI_STATUS Status;
EFI_TPL TplPrevious;
//
// Restart the timer
//
TimerStart ( 1 * 1000 );
//
// Loop until the connection breaks or the user stops
//
do {
//
// Check for user stop request
//
Status = ControlCCheck ( );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Send some bytes
//
BytesSent = write ( Socket, &Buffer[0], sizeof ( Buffer ));
if ( -1 == BytesSent ) {
DEBUG (( DEBUG_INFO,
"ERROR: send failed, errno: %d\r\n",
errno ));
Print ( L"ERROR: send failed, errno: %d\r\n", errno );
//
// Try again
//
Status = EFI_SUCCESS;
//
// Exit now
//
Status = EFI_NOT_STARTED;
break;
}
//
// Synchronize with the TimerCallback routine
//
TplPrevious = gBS->RaiseTPL ( TPL_DATASOURCE );
//
// Account for the data sent
//
TotalBytesSent += BytesSent;
//
// Release the TimerCallback routine synchronization
//
gBS->RestoreTPL ( TplPrevious );
} while ( !EFI_ERROR ( Status ));
//
// Return the operation status
//
return Status;
}
/**
Open the network connection and send the data.
@retval EFI_SUCCESS Continue looping
@retval other Stopped by user's Control-C input
**/
EFI_STATUS
SocketOpen (
)
{
EFI_STATUS Status;
//
// Use do/while and break instead of goto
//
do {
//
// Wait for the network layer to initialize
//
Status = SocketNew ( RemoteHostAddress.sin6_family );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Wait for the remote network application to start
//
Status = SocketConnect ( );
Print ( L"Status: %r\r\n", Status );
if ( EFI_NOT_STARTED == Status ) {
Status = SocketClose ( );
continue;
}
else if ( EFI_SUCCESS != Status ) {
//
// Control-C
//
break;
}
//
// Send data until the connection breaks
//
Status = SocketSend ( );
if ( EFI_ERROR ( Status )) {
break;
}
} while ( FALSE );
//
// Return the operation status
//
Print ( L"Returning Status: %r\r\n", Status );
return Status;
}
/**
Close the TCP connection
@retval EFI_SUCCESS The application is running normally
@retval Other The user stopped the application
**/
EFI_STATUS
Tcp4Close (
)
{
UINTN Index;
UINT8 * pIpAddress;
EFI_STATUS Status;
//
// Close the port
//
if ( bTcp4Connected ) {
Tcp4CloseToken.AbortOnClose = TRUE;
Status = pTcp4Protocol->Close ( pTcp4Protocol,
&Tcp4CloseToken );
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to start the TCP port close, Status: %r\r\n",
Status ));
}
else {
Status = gBS->WaitForEvent ( 1,
&Tcp4CloseToken.CompletionToken.Event,
&Index );
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to wait for close event, Status: %r\r\n",
Status ));
}
else {
Status = Tcp4CloseToken.CompletionToken.Status;
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to close the TCP port, Status: %r\r\n",
Status ));
}
else {
DEBUG (( DEBUG_INFO,
"0x%08x: TCP port closed\r\n",
pTcp4Protocol ));
bTcp4Connected = FALSE;
//
// Display the port closed message
//
pIpAddress = (UINT8 *)&((struct sockaddr_in *)&RemoteHostAddress)->sin_addr.s_addr;
Print ( L"Closed connection to %d.%d.%d.%d:%d\r\n",
pIpAddress[0],
pIpAddress[1],
pIpAddress[2],
pIpAddress[3],
ntohs ( ((struct sockaddr_in *)&RemoteHostAddress)->sin_port ));
}
}
}
}
//
// Release the events
//
if ( NULL != Tcp4TxToken.CompletionToken.Event ) {
Status = gBS->CloseEvent ( Tcp4TxToken.CompletionToken.Event );
if ( !EFI_ERROR ( Status )) {
DEBUG (( DEBUG_INFO,
"0x%08x: TX event closed\r\n",
Tcp4TxToken.CompletionToken.Event ));
Tcp4TxToken.CompletionToken.Event = NULL;
}
else {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to close the Tcp4TxToken event, Status: %r\r\n",
Status ));
}
}
if ( NULL != Tcp4ListenToken.CompletionToken.Event ) {
Status = gBS->CloseEvent ( Tcp4ListenToken.CompletionToken.Event );
if ( !EFI_ERROR ( Status )) {
DEBUG (( DEBUG_INFO,
"0x%08x: Listen event closed\r\n",
Tcp4ListenToken.CompletionToken.Event ));
Tcp4ListenToken.CompletionToken.Event = NULL;
}
else {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to close the Tcp4ListenToken event, Status: %r\r\n",
Status ));
}
}
if ( NULL != Tcp4ConnectToken.CompletionToken.Event ) {
Status = gBS->CloseEvent ( Tcp4ConnectToken.CompletionToken.Event );
if ( !EFI_ERROR ( Status )) {
DEBUG (( DEBUG_INFO,
"0x%08x: Connect event closed\r\n",
Tcp4ConnectToken.CompletionToken.Event ));
Tcp4ConnectToken.CompletionToken.Event = NULL;
}
else {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to close the Tcp4ConnectToken event, Status: %r\r\n",
Status ));
}
}
if ( NULL != Tcp4CloseToken.CompletionToken.Event ) {
Status = gBS->CloseEvent ( Tcp4CloseToken.CompletionToken.Event );
if ( !EFI_ERROR ( Status )) {
DEBUG (( DEBUG_INFO,
"0x%08x: Close event closed\r\n",
Tcp4CloseToken.CompletionToken.Event ));
Tcp4CloseToken.CompletionToken.Event = NULL;
}
else {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to close the Tcp4CloseToken event, Status: %r\r\n",
Status ));
}
}
//
// Close the TCP protocol
//
if ( NULL != pTcp4Protocol ) {
Status = gBS->CloseProtocol ( Tcp4Handle,
&gEfiTcp4ProtocolGuid,
gImageHandle,
NULL );
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to close the TCP protocol, Status: %r\r\n",
Status ));
}
else {
DEBUG (( DEBUG_INFO,
"0x%08x: TCP4 protocol closed\r\n",
pTcp4Protocol ));
pTcp4Protocol = NULL;
}
}
//
// Done with the TCP service
//
if ( NULL != Tcp4Handle ) {
Status = pTcp4Service->DestroyChild ( pTcp4Service,
Tcp4Handle );
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to release TCP service handle, Status: %r\r\n",
Status ));
}
else {
DEBUG (( DEBUG_INFO,
"Ox%08x: TCP service closed\r\n",
Tcp4Handle ));
Tcp4Handle = NULL;
}
}
//
// Close the service protocol
//
if ( NULL != pTcp4Service ) {
Status = gBS->CloseProtocol ( Tcp4Controller,
&gEfiTcp4ServiceBindingProtocolGuid,
gImageHandle,
NULL );
if ( !EFI_ERROR ( Status )) {
DEBUG (( DEBUG_INFO,
"0x%08x: Controller closed gEfiTcp4ServiceBindingProtocolGuid protocol\r\n",
Tcp4Controller ));
pTcp4Service = NULL;
}
else {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to close the gEfiTcp4ServiceBindingProtocolGuid protocol, Status: %r\r\n",
Status ));
}
}
Tcp4Controller = NULL;
bTcp4Connecting = TRUE;
//
// Mark the connection as closed
//
Status = EFI_SUCCESS;
//
// Return the operation status
//
return Status;
}
/**
Locate TCP protocol
@retval EFI_SUCCESS Protocol found
@retval other Protocl not found
**/
EFI_STATUS
Tcp4Locate (
)
{
UINTN HandleCount;
EFI_HANDLE * pHandles;
UINT8 * pIpAddress;
EFI_STATUS Status;
//
// Use do/while and break instead of goto
//
do {
//
// Attempt to locate the next TCP adapter in the system
//
Status = gBS->LocateHandleBuffer ( ByProtocol,
&gEfiTcp4ServiceBindingProtocolGuid,
NULL,
&HandleCount,
&pHandles );
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_WARN,
"WARNING - No network controllers or TCP4 available, Status: %r\r\n",
Status ));
break;
}
//
// Wrap the index if necessary
//
if ( HandleCount <= Tcp4Index ) {
Tcp4Index = 0;
//
// Wait for the next timer tick
//
do {
} while ( !bTick );
bTick = FALSE;
}
//
// Display the connecting message
//
if ( bTcp4Connecting ) {
pIpAddress = (UINT8 *)&((struct sockaddr_in *)&RemoteHostAddress)->sin_addr.s_addr;
Print ( L"Connecting to %d.%d.%d.%d:%d\r\n",
pIpAddress[0],
pIpAddress[1],
pIpAddress[2],
pIpAddress[3],
ntohs ( ((struct sockaddr_in *)&RemoteHostAddress)->sin_port ));
bTcp4Connecting = FALSE;
}
//
// Open the network controller's service protocol
//
Tcp4Controller = pHandles[ Tcp4Index++ ];
Status = gBS->OpenProtocol (
Tcp4Controller,
&gEfiTcp4ServiceBindingProtocolGuid,
(VOID **) &pTcp4Service,
gImageHandle,
NULL,
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to open gEfiTcp4ServiceBindingProtocolGuid on controller 0x%08x\r\n",
Tcp4Controller ));
Tcp4Controller = NULL;
break;
}
DEBUG (( DEBUG_INFO,
"0x%08x: Controller opened gEfiTcp4ServiceBindingProtocolGuid protocol\r\n",
Tcp4Controller ));
//
// Connect to the TCP service
//
Status = pTcp4Service->CreateChild ( pTcp4Service,
&Tcp4Handle );
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to open TCP service, Status: %r\r\n",
Status ));
Tcp4Handle = NULL;
break;
}
DEBUG (( DEBUG_INFO,
"Ox%08x: TCP service opened\r\n",
Tcp4Handle ));
//
// Locate the TCP protcol
//
Status = gBS->OpenProtocol ( Tcp4Handle,
&gEfiTcp4ProtocolGuid,
(VOID **)&pTcp4Protocol,
gImageHandle,
NULL,
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to open the TCP protocol, Status: %r\r\n",
Status ));
pTcp4Protocol = NULL;
break;
}
DEBUG (( DEBUG_INFO,
"0x%08x: TCP4 protocol opened\r\n",
pTcp4Protocol ));
}while ( FALSE );
//
// Release the handle buffer
//
gBS->FreePool ( pHandles );
//
// Return the operation status
//
return Status;
}
/**
Send data over the TCP4 connection
@retval EFI_SUCCESS The application is running normally
@retval Other The user stopped the application
**/
EFI_STATUS
Tcp4Send (
)
{
UINTN Index;
EFI_TCP4_TRANSMIT_DATA Packet;
EFI_STATUS Status;
EFI_TPL TplPrevious;
//
// Restart the timer
//
TimerStart ( 1 * 1000 );
//
// Initialize the packet
//
Packet.DataLength = sizeof ( Buffer );
Packet.FragmentCount = 1;
Packet.Push = FALSE;
Packet.Urgent = FALSE;
Packet.FragmentTable[0].FragmentBuffer = &Buffer[0];
Packet.FragmentTable[0].FragmentLength = sizeof ( Buffer );
Tcp4TxToken.Packet.TxData = &Packet;
//
// Loop until the connection breaks or the user stops
//
do {
//
// Check for user stop request
//
Status = ControlCCheck ( );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Send some bytes
//
Status = pTcp4Protocol->Transmit ( pTcp4Protocol,
&Tcp4TxToken );
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to start the transmit, Status: %r\r\n",
Status ));
//
// Try again
//
Status = EFI_SUCCESS;
break;
}
//
// Wait for the transmit to complete
//
Status = gBS->WaitForEvent ( 1,
&Tcp4TxToken.CompletionToken.Event,
&Index );
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to wait for transmit completion, Status: %r\r\n",
Status ));
//
// Try again
//
Status = EFI_SUCCESS;
break;
}
//
// Get the transmit status
//
Status = Tcp4TxToken.CompletionToken.Status;
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_WARN,
"WARNING - Failed the transmission, Status: %r\r\n",
Status ));
//
// Try again
//
Status = EFI_SUCCESS;
//
// Exit now
//
Status = EFI_NOT_STARTED;
break;
}
//
// Synchronize with the TimerCallback routine
//
TplPrevious = gBS->RaiseTPL ( TPL_DATASOURCE );
//
// Account for the data sent
//
TotalBytesSent += Packet.DataLength;
//
// Release the TimerCallback routine synchronization
//
gBS->RestoreTPL ( TplPrevious );
} while ( !EFI_ERROR ( Status ));
//
// Return the operation status
//
return Status;
}
/**
Open the network connection and send the data.
@retval EFI_SUCCESS Continue looping
@retval other Stopped by user's Control-C input
**/
EFI_STATUS
Tcp4Open (
)
{
UINTN Index;
UINT8 * pIpAddress;
EFI_STATUS Status;
//
// Use do/while and break instead of goto
//
do {
//
// Locate the TCP protocol
//
Status = Tcp4Locate ( );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Create the necessary events
//
Status = gBS->CreateEvent ( 0,
TPL_CALLBACK,
NULL,
NULL,
&Tcp4CloseToken.CompletionToken.Event );
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to create the close event, Status: %r\r\n",
Status ));
Tcp4CloseToken.CompletionToken.Event = NULL;
break;
}
DEBUG (( DEBUG_INFO,
"0x%08x: Close event open\r\n",
Tcp4CloseToken.CompletionToken.Event ));
Status = gBS->CreateEvent ( 0,
TPL_CALLBACK,
NULL,
NULL,
&Tcp4ConnectToken.CompletionToken.Event );
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to create the connect event, Status: %r\r\n",
Status ));
Tcp4ConnectToken.CompletionToken.Event = NULL;
break;
}
DEBUG (( DEBUG_INFO,
"0x%08x: Connect event open\r\n",
Tcp4ConnectToken.CompletionToken.Event ));
Status = gBS->CreateEvent ( 0,
TPL_CALLBACK,
NULL,
NULL,
&Tcp4ListenToken.CompletionToken.Event );
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to create the listen event, Status: %r\r\n",
Status ));
Tcp4ListenToken.CompletionToken.Event = NULL;
break;
}
DEBUG (( DEBUG_INFO,
"0x%08x: Listen event open\r\n",
Tcp4ListenToken.CompletionToken.Event ));
Status = gBS->CreateEvent ( 0,
TPL_CALLBACK,
NULL,
NULL,
&Tcp4TxToken.CompletionToken.Event );
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to create the TX event, Status: %r\r\n",
Status ));
Tcp4TxToken.CompletionToken.Event = NULL;
break;
}
DEBUG (( DEBUG_INFO,
"0x%08x: TX event open\r\n",
Tcp4TxToken.CompletionToken.Event ));
//
// Configure the local TCP port
//
Tcp4ConfigData.TimeToLive = 255;
Tcp4ConfigData.TypeOfService = 0;
Tcp4ConfigData.ControlOption = NULL;
Tcp4ConfigData.AccessPoint.ActiveFlag = TRUE;
Tcp4ConfigData.AccessPoint.StationAddress.Addr[0] = 0;
Tcp4ConfigData.AccessPoint.StationAddress.Addr[1] = 0;
Tcp4ConfigData.AccessPoint.StationAddress.Addr[2] = 0;
Tcp4ConfigData.AccessPoint.StationAddress.Addr[3] = 0;
Tcp4ConfigData.AccessPoint.StationPort = 0;
Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[0] = (UINT8) ((struct sockaddr_in *)&RemoteHostAddress)->sin_addr.s_addr;
Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[1] = (UINT8)( ((struct sockaddr_in *)&RemoteHostAddress)->sin_addr.s_addr >> 8 );
Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[2] = (UINT8)( ((struct sockaddr_in *)&RemoteHostAddress)->sin_addr.s_addr >> 16 );
Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[3] = (UINT8)( ((struct sockaddr_in *)&RemoteHostAddress)->sin_addr.s_addr >> 24 );
Tcp4ConfigData.AccessPoint.RemotePort = ntohs (((struct sockaddr_in *)&RemoteHostAddress)->sin_port);
Tcp4ConfigData.AccessPoint.UseDefaultAddress = TRUE;
Tcp4ConfigData.AccessPoint.SubnetMask.Addr[0] = 0;
Tcp4ConfigData.AccessPoint.SubnetMask.Addr[1] = 0;
Tcp4ConfigData.AccessPoint.SubnetMask.Addr[2] = 0;
Tcp4ConfigData.AccessPoint.SubnetMask.Addr[3] = 0;
Status = pTcp4Protocol->Configure ( pTcp4Protocol,
&Tcp4ConfigData );
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to configure TCP port, Status: %r\r\n",
Status ));
break;
}
DEBUG (( DEBUG_INFO,
"0x%08x: TCP4 port configured\r\n",
pTcp4Protocol ));
//
// Connect to the remote TCP port
//
Status = pTcp4Protocol->Connect ( pTcp4Protocol,
&Tcp4ConnectToken );
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to start the connection to the remote system, Status: %r\r\n",
Status ));
break;
}
Status = gBS->WaitForEvent ( 1,
&Tcp4ConnectToken.CompletionToken.Event,
&Index );
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_ERROR,
"ERROR - Failed to wait for the connection, Status: %r\r\n",
Status ));
break;
}
Status = Tcp4ConnectToken.CompletionToken.Status;
if ( EFI_ERROR ( Status )) {
DEBUG (( DEBUG_WARN,
"WARNING - Failed to connect to the remote system, Status: %r\r\n",
Status ));
break;
}
DEBUG (( DEBUG_INFO,
"0x%08x: TCP4 port connected\r\n",
pTcp4Protocol ));
bTcp4Connected = TRUE;
//
// Display the connection
//
pIpAddress = (UINT8 *)&((struct sockaddr_in *)&RemoteHostAddress)->sin_addr.s_addr;
Print ( L"Connected to %d.%d.%d.%d:%d\r\n",
pIpAddress[0],
pIpAddress[1],
pIpAddress[2],
pIpAddress[3],
ntohs ( ((struct sockaddr_in *)&RemoteHostAddress)->sin_port ));
} while ( 0 );
if ( EFI_ERROR ( Status )) {
//
// Try again
//
Status = EFI_SUCCESS;
}
else {
//
// Semd data until the connection breaks
//
Status = Tcp4Send ( );
}
//
// Return the operation 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;
UINT32 Index;
UINT64 TotalBytes;
//
// Notify the other code of the timer tick
//
bTick = TRUE;
//
// Update the average bytes per second
//
if ( 0 != TotalBytesSent ) {
BytesSent[ In ] = TotalBytesSent;
TotalBytesSent = 0;
In += 1;
if ( DATA_SAMPLES <= In ) {
In = 0;
}
//
// Separate the samples
//
if ( DATA_SAMPLES == Samples ) {
Print ( L"---------- Stable average ----------\r\n" );
}
Samples += 1;
//
// Compute the data rate
//
TotalBytes = 0;
for ( Index = 0; DATA_SAMPLES > Index; Index++ ) {
TotalBytes += BytesSent[ Index ];
}
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_DATASOURCE,
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;
}
/**
Send data to the DataSink 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
)
{
EFI_STATUS (* pClose) ();
EFI_STATUS (* pOpen) ();
EFI_STATUS Status;
DEBUG (( DEBUG_INFO,
"DataSource starting\r\n" ));
//
// Validate the command line
//
if ( 2 > Argc ) {
Print ( L"%s <remote IP address> [Use TCP]\r\n", Argv[0] );
return -1;
}
//
// Determine if TCP should be used
//
bTcp4 = (BOOLEAN)( 2 < Argc );
//
// Determine the support routines
//
if ( bTcp4 ) {
pOpen = Tcp4Open;
pClose = Tcp4Close;
bTcp4Connecting = TRUE;
}
else {
pOpen = SocketOpen;
pClose = SocketClose;
}
//
// Use for/break instead of goto
//
for ( ; ; ) {
//
// No bytes sent so far
//
TotalBytesSent = 0;
Samples = 0;
memset ( &BytesSent, 0, sizeof ( BytesSent ));
//
// Get the IP address
//
pRemoteHost = Argv[1];
Status = IpAddress ( );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Create the timer
//
bTick = TRUE;
Status = TimerCreate ( );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Loop forever abusing the specified system
//
do {
//
// Start a timer to perform connection polling and display updates
//
Status = TimerStart ( 2 * 1000 );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Open the network connection and send the data
//
Status = pOpen ( );
if ( EFI_ERROR ( Status )) {
break;
}
//
// Done with the network connection
//
Status = pClose ( );
} while ( !EFI_ERROR ( Status ));
//
// Close the network connection if necessary
//
pClose ( );
//
// All done
//
break;
}
//
// Stop the timer if necessary
//
TimerStop ( );
TimerDestroy ( );
//
// Return the operation status
//
DEBUG (( DEBUG_INFO,
"DataSource exiting, Status: %r\r\n",
Status ));
return Status;
}