diff --git a/AppPkg/AppPkg.dsc b/AppPkg/AppPkg.dsc index 7bc8f85d92..59341ec963 100644 --- a/AppPkg/AppPkg.dsc +++ b/AppPkg/AppPkg.dsc @@ -41,6 +41,7 @@ # UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf ShellCEntryLib|ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf # # Common Libraries # @@ -64,45 +65,11 @@ UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf + ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf FileHandleLib|ShellPkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf SortLib|ShellPkg/Library/UefiSortLib/UefiSortLib.inf - - # - # C Standard Libraries - # - LibC|StdLib/LibC/LibC.inf - LibStdLib|StdLib/LibC/StdLib/StdLib.inf - LibString|StdLib/LibC/String/String.inf - LibWchar|StdLib/LibC/Wchar/Wchar.inf - LibCType|StdLib/LibC/Ctype/Ctype.inf - LibTime|StdLib/LibC/Time/Time.inf - LibStdio|StdLib/LibC/Stdio/Stdio.inf - LibGdtoa|StdLib/LibC/gdtoa/gdtoa.inf - LibLocale|StdLib/LibC/Locale/Locale.inf - LibUefi|StdLib/LibC/Uefi/Uefi.inf - LibMath|StdLib/LibC/Math/Math.inf - LibSignal|StdLib/LibC/Signal/Signal.inf - LibNetUtil|StdLib/LibC/NetUtil/NetUtil.inf - - # Libraries for device abstractions within the Standard C Library - # Applications should not directly access any functions defined in these libraries. - DevUtility|StdLib/LibC/Uefi/Devices/daUtility.inf - DevConsole|StdLib/LibC/Uefi/Devices/daConsole.inf - DevShell|StdLib/LibC/Uefi/Devices/daShell.inf - -[LibraryClasses.IA32] - TimerLib|PerformancePkg/Library/DxeTscTimerLib/DxeTscTimerLib.inf - # To run in an emulation environment, such as Nt32Pkg, comment out the TimerLib - # description above and un-comment the line below. -# TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf - -[LibraryClasses.X64] - TimerLib|PerformancePkg/Library/DxeTscTimerLib/DxeTscTimerLib.inf - -[LibraryClasses.IPF] - PalLib|MdePkg/Library/UefiPalLib/UefiPalLib.inf - TimerLib|MdePkg/Library/SecPeiDxeTimerLibCpu/SecPeiDxeTimerLibCpu.inf + PathLib|ShellPkg/Library/BasePathLib/BasePathLib.inf ################################################################################################### # @@ -124,44 +91,41 @@ ################################################################################################### [Components] -# BaseLib and BaseMemoryLib need to be built with the /GL- switch when using the Microsoft -# tool chain. This is required so that the library functions can be resolved during -# the second pass of the linker during Link-time-code-generation. -### - MdePkg/Library/BaseLib/BaseLib.inf { - - MSFT:*_*_*_CC_FLAGS = /X /Zc:wchar_t /GL- - } - - MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf { - - MSFT:*_*_*_CC_FLAGS = /X /Zc:wchar_t /GL- - } #### Sample Applications. AppPkg/Applications/Hello/Hello.inf # No LibC includes or functions. AppPkg/Applications/Main/Main.inf # Simple invocation. No other LibC functions. AppPkg/Applications/Enquire/Enquire.inf -# After extracting the Python distribution, un-comment the following line to build Python. +#### After extracting the Python distribution, un-comment the following line to build Python. # AppPkg/Applications/Python/PythonCore.inf -################################################################ +########## +# Socket Applications - LibC based +########## + AppPkg/Applications/Sockets/DataSink/DataSink.inf + AppPkg/Applications/Sockets/DataSource/DataSource.inf +# SocketPkg/Application/FtpNew/FTP.inf + AppPkg/Applications/Sockets/GetHostByAddr/GetHostByAddr.inf + AppPkg/Applications/Sockets/GetHostByDns/GetHostByDns.inf + AppPkg/Applications/Sockets/GetHostByName/GetHostByName.inf + AppPkg/Applications/Sockets/GetNetByAddr/GetNetByAddr.inf + AppPkg/Applications/Sockets/GetNetByName/GetNetByName.inf + AppPkg/Applications/Sockets/GetServByName/GetServByName.inf + AppPkg/Applications/Sockets/GetServByPort/GetServByPort.inf + AppPkg/Applications/Sockets/RecvDgram/RecvDgram.inf +# SocketPkg/Application/route/route.inf + AppPkg/Applications/Sockets/SetHostName/SetHostName.inf + AppPkg/Applications/Sockets/SetSockOpt/SetSockOpt.inf + AppPkg/Applications/Sockets/TftpServer/TftpServer.inf + AppPkg/Applications/Sockets/WebServer/WebServer.inf { + + gStdLibTokenSpaceGuid.WebServer_HttpPort|80 + } + +################################################################################################### # -# See the additional comments below if you plan to run applications under the -# Nt32 emulation environment. +# Include Boilerplate text required for building with the Standard Libraries. # - -[BuildOptions] - INTEL:*_*_*_CC_FLAGS = /Qfreestanding - MSFT:*_*_*_CC_FLAGS = /X /Zc:wchar_t - GCC:*_*_*_CC_FLAGS = -ffreestanding -nostdinc -nostdlib - -# The Build Options, below, are only used when building the C library -# to be run under an emulation environment, such as Nt32Pkg. The clock() -# system call is modified to return -1 indicating that it is unsupported. -# Just uncomment the lines below and select the correct TimerLib instance, above. - - # INTEL:*_*_IA32_CC_FLAGS = /D NT32dvm - # MSFT:*_*_IA32_CC_FLAGS = /D NT32dvm - # GCC:*_*_IA32_CC_FLAGS = -DNT32dvm +################################################################################################### +!include StdLib/StdLib.inc diff --git a/AppPkg/Applications/Sockets/DataSink/DataSink.c b/AppPkg/Applications/Sockets/DataSink/DataSink.c new file mode 100644 index 0000000000..911cf36940 --- /dev/null +++ b/AppPkg/Applications/Sockets/DataSink/DataSink.c @@ -0,0 +1,1029 @@ +/** @file + Data source for network testing. + + Copyright (c) 2011, 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 +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + + +#define MAX_CONNECTIONS ( 1 + 16 ) ///< Maximum number of client connections +#define RANGE_SWITCH 2048 ///< 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 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 BytesAverage; + UINT64 BytesPrevious; + UINT64 BytesTotal; + struct sockaddr_in RemoteAddress; + UINT64 Samples; +} DT_PORT; + +volatile BOOLEAN bTick; +BOOLEAN bTimerRunning; +struct sockaddr_in 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.sin_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; + Port [ Index ].BytesAverage = 0; + Port [ Index ].BytesPrevious = 0; + Port [ Index ].BytesTotal = 0; + Port [ Index ].Samples = 0; + Port [ Index ].RemoteAddress.sin_len = 0; + Port [ Index ].RemoteAddress.sin_family = 0; + Port [ Index ].RemoteAddress.sin_port = 0; + Port [ Index ].RemoteAddress.sin_addr.s_addr= 0; + } + } + + // + // 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 + + @retval EFI_SUCCESS The application is running normally + @retval Other The user stopped the application +**/ +EFI_STATUS +SocketNew ( + ) +{ + EFI_STATUS Status; + + // + // Get the port number + // + ZeroMem ( &LocalAddress, sizeof ( LocalAddress )); + LocalAddress.sin_len = sizeof ( LocalAddress ); + LocalAddress.sin_family = AF_INET; + LocalAddress.sin_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 ( AF_INET, + 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 RemoteAddress; + int Socket; + EFI_STATUS Status; + EFI_TPL TplPrevious; + + // + // Check for control-C + // + 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 + // + 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 { + DEBUG (( DEBUG_ERROR, + "ERROR - Network closed on socket %d.%d.%d.%d:%d, errno: %d\r\n", + Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff, + ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff, + ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff, + ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff, + htons ( Port [ Index ].RemoteAddress.sin_port ), + errno )); + + // + // Close the socket + // + CloseStatus = close ( PollFd [ Index ].fd ); + if ( 0 == CloseStatus ) { + bRemoveSocket = TRUE; + DEBUG (( DEBUG_INFO, + "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n", + PollFd [ Index ].fd, + Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff, + ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff, + ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff, + ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff, + htons ( Port [ Index ].RemoteAddress.sin_port ))); + } + else { + DEBUG (( DEBUG_ERROR, + "ERROR - Failed to close socket 0x%08x for %d.%d.%d.%d:%d, errno: %d\r\n", + PollFd [ Index ].fd, + Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff, + ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff, + ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff, + ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff, + htons ( Port [ Index ].RemoteAddress.sin_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 + // + Print ( L"Rejecting connection to remote system %d.%d.%d.%d:%d\r\n", + RemoteAddress.sin_addr.s_addr & 0xff, + ( RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff, + ( RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff, + ( RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff, + htons ( RemoteAddress.sin_port )); + + // + // No room for this connection + // Close the connection + // + CloseStatus = close ( Socket ); + if ( 0 == CloseStatus ) { + bRemoveSocket = TRUE; + DEBUG (( DEBUG_INFO, + "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n", + PollFd [ Index ].fd, + RemoteAddress.sin_addr.s_addr & 0xff, + ( RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff, + ( RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff, + ( RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff, + htons ( RemoteAddress.sin_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 + // + Print ( L"Connected to remote system %d.%d.%d.%d:%d\r\n", + RemoteAddress.sin_addr.s_addr & 0xff, + ( RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff, + ( RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff, + ( RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff, + htons ( RemoteAddress.sin_port )); + + // + // Allocate the client connection + // + Index = MaxPort++; + Port [ Index ].BytesAverage = 0; + Port [ Index ].BytesPrevious = 0; + Port [ Index ].BytesTotal = 0; + Port [ Index ].Samples = 0; + Port [ Index ].RemoteAddress.sin_len = RemoteAddress.sin_len; + Port [ Index ].RemoteAddress.sin_family = RemoteAddress.sin_family; + Port [ Index ].RemoteAddress.sin_port = RemoteAddress.sin_port; + Port [ Index ].RemoteAddress.sin_addr = RemoteAddress.sin_addr; + 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 + // + DEBUG (( DEBUG_INFO, + "0x%08x: Socket received 0x%08x bytes from %d.%d.%d.%d:%d\r\n", + PollFd [ Index ].fd, + BytesReceived, + Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff, + ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff, + ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff, + ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff, + htons ( Port [ Index ].RemoteAddress.sin_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 + // + DEBUG (( DEBUG_INFO, + "ERROR - Receive failure for %d.%d.%d.%d:%d, errno: %d\r\n", + Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff, + ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff, + ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff, + ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff, + htons ( Port [ Index ].RemoteAddress.sin_port ), + errno )); + CloseStatus = close ( PollFd [ Index ].fd ); + if ( 0 == CloseStatus ) { + bRemoveSocket = TRUE; + DEBUG (( DEBUG_INFO, + "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n", + PollFd [ Index ].fd, + Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff, + ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff, + ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff, + ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff, + htons ( Port [ Index ].RemoteAddress.sin_port ))); + } + else { + DEBUG (( DEBUG_ERROR, + "ERROR - Failed to close socket 0x%08x for %d.%d.%d.%d:%d, errno: %d\r\n", + PollFd [ Index ].fd, + Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff, + ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff, + ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff, + ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff, + htons ( Port [ Index ].RemoteAddress.sin_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; + Port [ EntryPrevious ].BytesAverage = Port [ Entry ].BytesAverage; + Port [ EntryPrevious ].BytesPrevious = Port [ Entry ].BytesPrevious; + Port [ EntryPrevious ].BytesTotal = Port [ Entry ].BytesTotal; + Port [ EntryPrevious ].RemoteAddress.sin_len = Port [ Entry ].RemoteAddress.sin_len; + Port [ EntryPrevious ].RemoteAddress.sin_family = Port [ Entry ].RemoteAddress.sin_family; + Port [ EntryPrevious ].RemoteAddress.sin_port = Port [ Entry ].RemoteAddress.sin_port; + Port [ EntryPrevious ].RemoteAddress.sin_addr.s_addr = Port [ Entry ].RemoteAddress.sin_addr.s_addr; + Port [ EntryPrevious ].Samples = Port [ Entry ].Samples; + 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 +TimerCallback ( + IN EFI_EVENT Event, + IN VOID * pContext + ) +{ + UINT64 Average; + UINT64 BytesReceived; + UINT32 Delta; + UINT64 DeltaBytes; + nfds_t Index; + + // + // 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 average bytes per second + // + DeltaBytes = Port [ Index ].BytesAverage >> AVERAGE_SHIFT_COUNT; + Port [ Index ].BytesAverage -= DeltaBytes; + DeltaBytes = BytesReceived - Port [ Index ].BytesPrevious; + Port [ Index ].BytesPrevious = BytesReceived; + Port [ Index ].BytesAverage += DeltaBytes; + + // + // Separate the samples + // + if (( 2 << AVERAGE_SHIFT_COUNT ) == Port [ Index ].Samples ) { + Print ( L"---------- Stable average ----------\r\n" ); + } + Port [ Index ].Samples += 1; + + // + // Display the data rate + // + Delta = (UINT32)( DeltaBytes >> DATA_RATE_UPDATE_SHIFT ); + Average = Port [ Index ].BytesAverage >> ( AVERAGE_SHIFT_COUNT + DATA_RATE_UPDATE_SHIFT ); + if ( Average < RANGE_SWITCH ) { + Print ( L"%d Bytes/sec, Ave: %d Bytes/Sec\r\n", + Delta, + (UINT32) Average ); + } + else { + Average >>= 10; + if ( Average < RANGE_SWITCH ) { + Print ( L"%d Bytes/sec, Ave: %d KiBytes/Sec\r\n", + Delta, + (UINT32) Average ); + } + else { + Average >>= 10; + if ( Average < RANGE_SWITCH ) { + Print ( L"%d Bytes/sec, Ave: %d MiBytes/Sec\r\n", + Delta, + (UINT32) Average ); + } + else { + Average >>= 10; + if ( Average < RANGE_SWITCH ) { + Print ( L"%d Bytes/sec, Ave: %d GiBytes/Sec\r\n", + Delta, + (UINT32) Average ); + } + else { + Average >>= 10; + if ( Average < RANGE_SWITCH ) { + Print ( L"%d Bytes/sec, Ave: %d TiBytes/Sec\r\n", + Delta, + Average ); + } + else { + Average >>= 10; + Print ( L"%d Bytes/sec, Ave: %d PiBytes/Sec\r\n", + Delta, + (UINT32) Average ); + } + } + } + } + } + } + } +} + + +/** + 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 + ) +{ + EFI_STATUS Status; + + DEBUG (( DEBUG_INFO, + "DataSink starting\r\n" )); + + // + // 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 ( ); + 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; + } + + // + // Send 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; +} diff --git a/AppPkg/Applications/Sockets/DataSink/DataSink.inf b/AppPkg/Applications/Sockets/DataSink/DataSink.inf new file mode 100644 index 0000000000..7c79ab28f8 --- /dev/null +++ b/AppPkg/Applications/Sockets/DataSink/DataSink.inf @@ -0,0 +1,67 @@ +#/** @file +# DataSink Application +# +# This file contains an 'Intel Peripheral Driver' and is +# licensed for Intel CPUs and chipsets under the terms of your +# license agreement with Intel or your vendor. This file may +# be modified by the user, subject to additional terms of the +# license agreement +# +# +# Copyright (c) 20011 Intel Corporation. All rights reserved +# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. Except as permitted by such +# license, no part of this software or documentation may be +# reproduced, stored in a retrieval system, or transmitted in any +# form or by any means without the express written consent of +# Intel Corporation. +# +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DataSink + FILE_GUID = A85DCA1B-198F-4e14-A673-874264687E85 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = ShellCEntryLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + DataSink.c + + +[Pcd] + gStdLibTokenSpaceGuid.DataSource_Port + + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + StdLib/StdLib.dec + + +[LibraryClasses] + BaseMemoryLib + BsdSocketLib + DebugLib + EfiSocketLib + LibC + LibMath + ShellCEntryLib + UefiBootServicesTableLib + UefiLib +# UseSocketDxe + +[BuildOptions] + INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186 + MSFT:*_*_*_CC_FLAGS = /Od + GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable + diff --git a/AppPkg/Applications/Sockets/DataSource/DataSource.c b/AppPkg/Applications/Sockets/DataSource/DataSource.c new file mode 100644 index 0000000000..d8f7f05d5c --- /dev/null +++ b/AppPkg/Applications/Sockets/DataSource/DataSource.c @@ -0,0 +1,1615 @@ +/** @file + Data source for network testing. + + Copyright (c) 2011, 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 +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + + +#define RANGE_SWITCH 2048 ///< 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 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_in RemoteHostAddress; +CHAR8 * pRemoteHost; + +// +// Traffic Data +// +UINT64 TotalBytesSent; +UINT64 PreviousBytes; +UINT64 AverageBytes; +UINT64 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 + + @returns 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 ( + ) +{ + CHAR8 * pSeparator; + INT32 RemoteAddress; + EFI_STATUS Status; + UINT32 Value1; + UINT32 Value2; + UINT32 Value3; + UINT32 Value4; + + // + // Assume failure + // + Status = EFI_INVALID_PARAMETER; + + // + // Convert the IP address from a string to a numeric value + // + pSeparator = GetDigit ( pRemoteHost, &Value1 ); + if (( 255 >= Value1 ) && ( '.' == *pSeparator )) { + pSeparator = GetDigit ( ++pSeparator, &Value2 ); + if (( 255 >= Value2 ) && ( '.' == *pSeparator )) { + pSeparator = GetDigit ( ++pSeparator, &Value3 ); + if (( 255 >= Value3 ) && ( '.' == *pSeparator )) { + pSeparator = GetDigit ( ++pSeparator, &Value4 ); + if (( 255 >= Value4 ) && ( 0 == *pSeparator )) { + RemoteAddress = Value1 + | ( Value2 << 8 ) + | ( Value3 << 16 ) + | ( Value4 << 24 ); + RemoteHostAddress.sin_addr.s_addr = (UINT32) RemoteAddress; + Status = EFI_SUCCESS; + DEBUG (( DEBUG_INFO, + "%d.%d.%d.%d: Remote host IP address\r\n", + Value1, + Value2, + Value3, + Value4 )); + } + } + } + } + if ( EFI_ERROR ( Status )) { + Print ( L"Invalid digit detected: %d\r\n", *pSeparator ); + } + + // + // 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; + UINT32 RemoteAddress; + EFI_STATUS Status; + + // + // Display the connecting message + // + RemoteAddress = RemoteHostAddress.sin_addr.s_addr; + Print ( L"Connecting to remote system %d.%d.%d.%d:%d\r\n", + RemoteAddress & 0xff, + ( RemoteAddress >> 8 ) & 0xff, + ( RemoteAddress >> 16 ) & 0xff, + ( RemoteAddress >> 24 ) & 0xff, + htons ( RemoteHostAddress.sin_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 *) &RemoteHostAddress, + RemoteHostAddress.sin_len ); + if ( -1 != ConnectStatus ) { + Print ( L"Connected to remote system %d.%d.%d.%d:%d\r\n", + RemoteAddress & 0xff, + ( RemoteAddress >> 8 ) & 0xff, + ( RemoteAddress >> 16 ) & 0xff, + ( RemoteAddress >> 24 ) & 0xff, + htons ( RemoteHostAddress.sin_port )); + } + else { + // + // Close the socket and try again + // + if ( EAGAIN != errno ) { + Status = EFI_NOT_STARTED; + break; + } + } + } while ( -1 == ConnectStatus ); + + // + // Return the operation status + // + return Status; +} + + +/** + Create the socket + + @retval EFI_SUCCESS The application is running normally + @retval Other The user stopped the application +**/ +EFI_STATUS +SocketNew ( + ) +{ + 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 ( AF_INET, + 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 ( 1000 << DATA_RATE_UPDATE_SHIFT ); + + // + // 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 )); + + // + // 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 ( ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Wait for the remote network application to start + // + Status = SocketConnect ( ); + 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 + // + 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 *)&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], + htons ( 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 *)&RemoteHostAddress.sin_addr.s_addr; + Print ( L"Connecting to %d.%d.%d.%d:%d\r\n", + pIpAddress[0], + pIpAddress[1], + pIpAddress[2], + pIpAddress[3], + htons ( 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 ( 1000 << DATA_RATE_UPDATE_SHIFT ); + + // + // 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) RemoteHostAddress.sin_addr.s_addr; + Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[1] = (UINT8)( RemoteHostAddress.sin_addr.s_addr >> 8 ); + Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[2] = (UINT8)( RemoteHostAddress.sin_addr.s_addr >> 16 ); + Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[3] = (UINT8)( RemoteHostAddress.sin_addr.s_addr >> 24 ); + Tcp4ConfigData.AccessPoint.RemotePort = 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 *)&RemoteHostAddress.sin_addr.s_addr; + Print ( L"Connected to %d.%d.%d.%d:%d\r\n", + pIpAddress[0], + pIpAddress[1], + pIpAddress[2], + pIpAddress[3], + htons ( 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 +TimerCallback ( + IN EFI_EVENT Event, + IN VOID * pContext + ) +{ + UINT64 BytesSent; + UINT64 DeltaBytes; + UINT32 Delta; + UINT64 Average; + + // + // Notify the other code of the timer tick + // + bTick = TRUE; + + // + // Update the average bytes per second + // + BytesSent = TotalBytesSent; + if ( 0 != BytesSent ) { + DeltaBytes = AverageBytes >> AVERAGE_SHIFT_COUNT; + AverageBytes -= DeltaBytes; + DeltaBytes = BytesSent - PreviousBytes; + PreviousBytes = BytesSent; + AverageBytes += DeltaBytes; + + // + // Separate the samples + // + if (( 2 << AVERAGE_SHIFT_COUNT ) == Samples ) { + Print ( L"---------- Stable average ----------\r\n" ); + } + Samples += 1; + + // + // Display the data rate + // + Delta = (UINT32)( DeltaBytes >> DATA_RATE_UPDATE_SHIFT ); + Average = AverageBytes >> ( AVERAGE_SHIFT_COUNT + DATA_RATE_UPDATE_SHIFT ); + if ( Average < RANGE_SWITCH ) { + Print ( L"%d Bytes/sec, Ave: %d Bytes/Sec\r\n", + Delta, + (UINT32) Average ); + } + else { + Average >>= 10; + if ( Average < RANGE_SWITCH ) { + Print ( L"%d Bytes/sec, Ave: %d KiBytes/Sec\r\n", + Delta, + (UINT32) Average ); + } + else { + Average >>= 10; + if ( Average < RANGE_SWITCH ) { + Print ( L"%d Bytes/sec, Ave: %d MiBytes/Sec\r\n", + Delta, + (UINT32) Average ); + } + else { + Average >>= 10; + if ( Average < RANGE_SWITCH ) { + Print ( L"%d Bytes/sec, Ave: %d GiBytes/Sec\r\n", + Delta, + (UINT32) Average ); + } + else { + Average >>= 10; + if ( Average < RANGE_SWITCH ) { + Print ( L"%d Bytes/sec, Ave: %d TiBytes/Sec\r\n", + Delta, + Average ); + } + else { + Average >>= 10; + Print ( L"%d Bytes/sec, Ave: %d PiBytes/Sec\r\n", + Delta, + (UINT32) Average ); + } + } + } + } + } + } +} + + +/** + 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 \r\n", Argv[0] ); + return -1; + } + +bTcp4 = TRUE; + + // + // 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; + AverageBytes = 0; + PreviousBytes = 0; + Samples = 0; + + // + // Get the port number + // + ZeroMem ( &RemoteHostAddress, sizeof ( RemoteHostAddress )); + RemoteHostAddress.sin_len = sizeof ( RemoteHostAddress ); + RemoteHostAddress.sin_family = AF_INET; + RemoteHostAddress.sin_port = htons ( PcdGet16 ( DataSource_Port )); + +Print ( L"Argc: %d\r\n", Argc); +Print ( L"Argv[0]: %a\r\n", Argv[0]); +Print ( L"Argv[1]: %a\r\n", Argv[1]); + + // + // 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; +} diff --git a/AppPkg/Applications/Sockets/DataSource/DataSource.inf b/AppPkg/Applications/Sockets/DataSource/DataSource.inf new file mode 100644 index 0000000000..ec9cf6c185 --- /dev/null +++ b/AppPkg/Applications/Sockets/DataSource/DataSource.inf @@ -0,0 +1,70 @@ +#/** @file +# DataSource Application +# +# This file contains an 'Intel Peripheral Driver' and is +# licensed for Intel CPUs and chipsets under the terms of your +# license agreement with Intel or your vendor. This file may +# be modified by the user, subject to additional terms of the +# license agreement +# +# +# Copyright (c) 20011 Intel Corporation. All rights reserved +# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. Except as permitted by such +# license, no part of this software or documentation may be +# reproduced, stored in a retrieval system, or transmitted in any +# form or by any means without the express written consent of +# Intel Corporation. +# +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DataSource + FILE_GUID = 30EB0F26-FC0A-4fd2-B9C9-751EA2BB1980 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = ShellCEntryLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + DataSource.c + + +[Pcd] + gStdLibTokenSpaceGuid.DataSource_Port + + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + StdLib/StdLib.dec + + +[LibraryClasses] + BaseMemoryLib + BsdSocketLib + EfiSocketLib + DebugLib + LibC + ShellCEntryLib + UefiBootServicesTableLib + UefiLib +# UseSocketDxe + +[Protocols] + gEfiTcp4ProtocolGuid + gEfiTcp4ServiceBindingProtocolGuid + +[BuildOptions] + INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186 + MSFT:*_*_*_CC_FLAGS = /Od + GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable + diff --git a/AppPkg/Applications/Sockets/GetHostByAddr/GetHostByAddr.c b/AppPkg/Applications/Sockets/GetHostByAddr/GetHostByAddr.c new file mode 100644 index 0000000000..2e626396ca --- /dev/null +++ b/AppPkg/Applications/Sockets/GetHostByAddr/GetHostByAddr.c @@ -0,0 +1,133 @@ +/** @file + Translate the port number into a service name + + Copyright (c) 2011, 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 +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +/** + Translate the IP address into a host name + + @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 + ) +{ + UINTN Index; + UINT8 IpAddress[4]; + struct hostent * pHost; + UINT8 * pIpAddress; + char ** ppName; + UINT32 RemoteAddress[4]; + + // + // Determine if the IPv4 address is specified + // + if (( 2 != Argc ) + || ( 4 != sscanf ( Argv[1], + "%d.%d.%d.%d", + &RemoteAddress[0], + &RemoteAddress[1], + &RemoteAddress[2], + &RemoteAddress[3])) + || ( 255 < RemoteAddress [0]) + || ( 255 < RemoteAddress [1]) + || ( 255 < RemoteAddress [2]) + || ( 255 < RemoteAddress [3])) { + Print ( L"%a \r\n", Argv[0]); + } + else { + // + // Translate the address into a host name + // + IpAddress[0] = (UINT8)RemoteAddress[0]; + IpAddress[1] = (UINT8)RemoteAddress[1]; + IpAddress[2] = (UINT8)RemoteAddress[2]; + IpAddress[3] = (UINT8)RemoteAddress[3]; + pHost = gethostbyaddr ( &IpAddress[0], INADDRSZ, AF_INET ); + if ( NULL == pHost ) { + Print ( L"ERROR - host not found, errno: %d\r\n", errno ); + } + else { + pIpAddress = (UINT8 *)pHost->h_addr_list [ 0 ]; + Print ( L"%d.%d.%d.%d, %a\r\n", + pIpAddress[0], + pIpAddress[1], + pIpAddress[2], + pIpAddress[3], + pHost->h_name ); + + // + // Display the other addresses + // + for ( Index = 1; NULL != pHost->h_addr_list[Index]; Index++ ) { + pIpAddress = (UINT8 *)pHost->h_addr_list[Index]; + Print ( L"%d.%d.%d.%d\r\n", + pIpAddress[0], + pIpAddress[1], + pIpAddress[2], + pIpAddress[3]); + } + + // + // Display the list of aliases + // + ppName = pHost->h_aliases; + if (( NULL == ppName ) || ( NULL == *ppName )) { + Print ( L"No aliases\r\n" ); + } + else { + Print ( L"Aliases: " ); + while ( NULL != *ppName ) { + // + // Display the alias + // + Print ( L"%a", *ppName ); + + // + // Set the next alias + // + ppName += 1; + if ( NULL != *ppName ) { + Print ( L", " ); + } + } + Print ( L"\r\n" ); + } + } + } + + // + // All done + // + return errno; +} diff --git a/AppPkg/Applications/Sockets/GetHostByAddr/GetHostByAddr.inf b/AppPkg/Applications/Sockets/GetHostByAddr/GetHostByAddr.inf new file mode 100644 index 0000000000..f31b8278dd --- /dev/null +++ b/AppPkg/Applications/Sockets/GetHostByAddr/GetHostByAddr.inf @@ -0,0 +1,65 @@ +#/** @file +# GetHostByAddr Application +# +# This file contains an 'Intel Peripheral Driver' and is +# licensed for Intel CPUs and chipsets under the terms of your +# license agreement with Intel or your vendor. This file may +# be modified by the user, subject to additional terms of the +# license agreement +# +# +# Copyright (c) 20011 Intel Corporation. All rights reserved +# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. Except as permitted by such +# license, no part of this software or documentation may be +# reproduced, stored in a retrieval system, or transmitted in any +# form or by any means without the express written consent of +# Intel Corporation. +# +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = GetHostByAddr + FILE_GUID = C31A6189-639A-458b-B040-D7D506CA8F4F + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = ShellCEntryLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + GetHostByAddr.c + + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + StdLib/StdLib.dec + + +[LibraryClasses] + BaseMemoryLib + BsdSocketLib + DebugLib + DevShell + EfiSocketLib + LibC + LibMath + LibNetUtil + ShellCEntryLib + UefiBootServicesTableLib + UefiLib +# UseSocketDxe + +[BuildOptions] + INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186 + MSFT:*_*_*_CC_FLAGS = /Od + GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable + diff --git a/AppPkg/Applications/Sockets/GetHostByDns/GetHostByDns.c b/AppPkg/Applications/Sockets/GetHostByDns/GetHostByDns.c new file mode 100644 index 0000000000..47453aced2 --- /dev/null +++ b/AppPkg/Applications/Sockets/GetHostByDns/GetHostByDns.c @@ -0,0 +1,85 @@ +/** @file + Translate the host name into an IP address + + Copyright (c) 2011, 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 +#include +#include +#include +#include + +#include +#include + +#include + +struct hostent * _gethostbydnsname(const char *, int); + +char mBuffer [65536]; + + +/** + Translate the host name into an IP address + + @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 + ) +{ + int AppStatus; + UINT8 * pIpAddress; + struct hostent * pHost; + + DEBUG (( DEBUG_INFO, + "%a starting\r\n", + Argv[0])); + + // + // Determine if the host name is specified + // + AppStatus = 0; + if ( 1 == Argc ) { + Print ( L"%a \r\n", Argv[0]); + } + else { + // + // Translate the host name + // + pHost = _gethostbydnsname ( Argv[1], AF_INET ); + if ( NULL == pHost ) { + Print ( L"ERROR - host not found, errno: %d\r\n", errno ); + } + else { + pIpAddress = (UINT8 *)pHost->h_addr; + Print ( L"%a: Type %d, %d.%d.%d.%d\r\n", + pHost->h_name, + pHost->h_addrtype, + pIpAddress[0], + pIpAddress[1], + pIpAddress[2], + pIpAddress[3]); + } + } + + // + // All done + // + return errno; +} diff --git a/AppPkg/Applications/Sockets/GetHostByDns/GetHostByDns.inf b/AppPkg/Applications/Sockets/GetHostByDns/GetHostByDns.inf new file mode 100644 index 0000000000..417eb5e228 --- /dev/null +++ b/AppPkg/Applications/Sockets/GetHostByDns/GetHostByDns.inf @@ -0,0 +1,65 @@ +#/** @file +# GetHostByDns Application +# +# This file contains an 'Intel Peripheral Driver' and is +# licensed for Intel CPUs and chipsets under the terms of your +# license agreement with Intel or your vendor. This file may +# be modified by the user, subject to additional terms of the +# license agreement +# +# +# Copyright (c) 20011 Intel Corporation. All rights reserved +# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. Except as permitted by such +# license, no part of this software or documentation may be +# reproduced, stored in a retrieval system, or transmitted in any +# form or by any means without the express written consent of +# Intel Corporation. +# +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = GetHostByDns + FILE_GUID = 3698D2B0-E727-4537-A636-A8770736ABFB + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = ShellCEntryLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + GetHostByDns.c + + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + StdLib/StdLib.dec + + +[LibraryClasses] + BaseMemoryLib + BsdSocketLib + DebugLib + DevShell + EfiSocketLib + LibC + LibMath + LibNetUtil + ShellCEntryLib + UefiBootServicesTableLib + UefiLib +# UseSocketDxe + +[BuildOptions] + INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186 + MSFT:*_*_*_CC_FLAGS = /Od + GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable + diff --git a/AppPkg/Applications/Sockets/GetHostByName/GetHostByName.c b/AppPkg/Applications/Sockets/GetHostByName/GetHostByName.c new file mode 100644 index 0000000000..d539c99481 --- /dev/null +++ b/AppPkg/Applications/Sockets/GetHostByName/GetHostByName.c @@ -0,0 +1,123 @@ +/** @file + Translate the host name into an IP address + + Copyright (c) 2011, 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 +#include +#include +#include +#include + +#include +#include + +#include + +char mBuffer [65536]; + + +/** + Translate the host name into an IP address + + @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 + ) +{ + int AppStatus; + UINTN Index; + struct hostent * pHost; + UINT8 * pIpAddress; + char ** ppName; + + DEBUG (( DEBUG_INFO, + "%a starting\r\n", + Argv[0])); + + // + // Determine if the host name is specified + // + AppStatus = 0; + if ( 1 == Argc ) { + Print ( L"%a \r\n", Argv[0]); + } + else { + // + // Translate the host name + // + pHost = gethostbyname ( Argv[1]); + if ( NULL == pHost ) { + Print ( L"ERROR - host not found, errno: %d\r\n", errno ); + } + else { + pIpAddress = (UINT8 *)pHost->h_addr; + Print ( L"%d.%d.%d.%d, Type %d, %a\r\n", + pIpAddress[0], + pIpAddress[1], + pIpAddress[2], + pIpAddress[3], + pHost->h_addrtype, + pHost->h_name ); + + // + // Display the other addresses + // + for ( Index = 1; NULL != pHost->h_addr_list[Index]; Index++ ) { + pIpAddress = (UINT8 *)pHost->h_addr_list[Index]; + Print ( L"%d.%d.%d.%d\r\n", + pIpAddress[0], + pIpAddress[1], + pIpAddress[2], + pIpAddress[3]); + } + + // + // Display the list of aliases + // + ppName = pHost->h_aliases; + if (( NULL == ppName ) || ( NULL == *ppName )) { + Print ( L"No aliases\r\n" ); + } + else { + Print ( L"Aliases: " ); + while ( NULL != *ppName ) { + // + // Display the alias + // + Print ( L"%a", *ppName ); + + // + // Set the next alias + // + ppName += 1; + if ( NULL != *ppName ) { + Print ( L", " ); + } + } + Print ( L"\r\n" ); + } + } + } + + // + // All done + // + return errno; +} diff --git a/AppPkg/Applications/Sockets/GetHostByName/GetHostByName.inf b/AppPkg/Applications/Sockets/GetHostByName/GetHostByName.inf new file mode 100644 index 0000000000..48beb2a26f --- /dev/null +++ b/AppPkg/Applications/Sockets/GetHostByName/GetHostByName.inf @@ -0,0 +1,65 @@ +#/** @file +# GetHostByName Application +# +# This file contains an 'Intel Peripheral Driver' and is +# licensed for Intel CPUs and chipsets under the terms of your +# license agreement with Intel or your vendor. This file may +# be modified by the user, subject to additional terms of the +# license agreement +# +# +# Copyright (c) 20011 Intel Corporation. All rights reserved +# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. Except as permitted by such +# license, no part of this software or documentation may be +# reproduced, stored in a retrieval system, or transmitted in any +# form or by any means without the express written consent of +# Intel Corporation. +# +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = GetHostByName + FILE_GUID = 70FB9CE0-2CB1-4fd7-80EE-AB4B6CF4B43F + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = ShellCEntryLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + GetHostByName.c + + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + StdLib/StdLib.dec + + +[LibraryClasses] + BaseMemoryLib + BsdSocketLib + DebugLib + DevShell + EfiSocketLib + LibC + LibMath + LibNetUtil + ShellCEntryLib + UefiBootServicesTableLib + UefiLib +# UseSocketDxe + +[BuildOptions] + INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186 + MSFT:*_*_*_CC_FLAGS = /Od + GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable + diff --git a/AppPkg/Applications/Sockets/GetNetByAddr/GetNetByAddr.c b/AppPkg/Applications/Sockets/GetNetByAddr/GetNetByAddr.c new file mode 100644 index 0000000000..51d8c6d101 --- /dev/null +++ b/AppPkg/Applications/Sockets/GetNetByAddr/GetNetByAddr.c @@ -0,0 +1,89 @@ +/** @file + Translate the IPv4 address into a network name + + Copyright (c) 2011, 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 +#include +#include +#include +#include +#include + +#include +#include + +#include + +/** + Translate the IPv4 address into a network name + + @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 + ) +{ + UINT32 RemoteAddress[4]; + UINT8 IpAddress[4]; + struct netent * pNetwork; + + // + // Determine if the IPv4 address is specified + // + if (( 2 != Argc ) + || ( 4 != sscanf ( Argv[1], + "%d.%d.%d.%d", + &RemoteAddress[0], + &RemoteAddress[1], + &RemoteAddress[2], + &RemoteAddress[3])) + || ( 255 < RemoteAddress [0]) + || ( 255 < RemoteAddress [1]) + || ( 255 < RemoteAddress [2]) + || ( 255 < RemoteAddress [3])) { + Print ( L"%a \r\n", Argv[0]); + } + else { + // + // Translate the address into a network name + // + IpAddress[0] = (UINT8)RemoteAddress[0]; + IpAddress[1] = (UINT8)RemoteAddress[1]; + IpAddress[2] = (UINT8)RemoteAddress[2]; + IpAddress[3] = (UINT8)RemoteAddress[3]; + pNetwork = getnetbyaddr ( *(uint32_t *)&IpAddress[0], AF_INET ); + if ( NULL == pNetwork ) { + Print ( L"ERROR - network not found, errno: %d\r\n", errno ); + } + else { + Print ( L"%a: %d.%d.%d.%d, 0x%08x\r\n", + pNetwork->n_name, + IpAddress[0], + IpAddress[1], + IpAddress[2], + IpAddress[3], + pNetwork->n_net ); + } + } + + // + // All done + // + return errno; +} diff --git a/AppPkg/Applications/Sockets/GetNetByAddr/GetNetByAddr.inf b/AppPkg/Applications/Sockets/GetNetByAddr/GetNetByAddr.inf new file mode 100644 index 0000000000..c280d186f1 --- /dev/null +++ b/AppPkg/Applications/Sockets/GetNetByAddr/GetNetByAddr.inf @@ -0,0 +1,65 @@ +#/** @file +# GetNetByAddr Application +# +# This file contains an 'Intel Peripheral Driver' and is +# licensed for Intel CPUs and chipsets under the terms of your +# license agreement with Intel or your vendor. This file may +# be modified by the user, subject to additional terms of the +# license agreement +# +# +# Copyright (c) 20011 Intel Corporation. All rights reserved +# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. Except as permitted by such +# license, no part of this software or documentation may be +# reproduced, stored in a retrieval system, or transmitted in any +# form or by any means without the express written consent of +# Intel Corporation. +# +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = GetNetByAddr + FILE_GUID = 22198FD5-4835-4842-BF31-EB957C7DD70D + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = ShellCEntryLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + GetNetByAddr.c + + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + StdLib/StdLib.dec + + +[LibraryClasses] + BaseMemoryLib + BsdSocketLib + DebugLib + DevShell + EfiSocketLib + LibC + LibMath + LibNetUtil + ShellCEntryLib + UefiBootServicesTableLib + UefiLib +# UseSocketDxe + +[BuildOptions] + INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186 + MSFT:*_*_*_CC_FLAGS = /Od + GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable + diff --git a/AppPkg/Applications/Sockets/GetNetByName/GetNetByName.c b/AppPkg/Applications/Sockets/GetNetByName/GetNetByName.c new file mode 100644 index 0000000000..b3609c9374 --- /dev/null +++ b/AppPkg/Applications/Sockets/GetNetByName/GetNetByName.c @@ -0,0 +1,83 @@ +/** @file + Translate the network name into an IP address + + Copyright (c) 2011, 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 +#include +#include +#include +#include + +#include +#include + +#include + +char mBuffer [65536]; + + +/** + Translate the network name into an IP address + + @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 + ) +{ + int AppStatus; + UINT8 * pIpAddress; + struct netent * pNetwork; + + DEBUG (( DEBUG_INFO, + "%a starting\r\n", + Argv[0])); + + // + // Determine if the network name is specified + // + AppStatus = 0; + if ( 1 == Argc ) { + Print ( L"%a \r\n", Argv[0]); + } + else { + // + // Translate the net name + // + pNetwork = getnetbyname ( Argv[1]); + if ( NULL == pNetwork ) { + Print ( L"ERROR - network not found, errno: %d\r\n", errno ); + } + else { + pIpAddress = (UINT8 *)pNetwork->n_net; + Print ( L"%a: Type %d, %d.%d.%d.%d\r\n", + pNetwork->n_name, + pNetwork->n_addrtype, + pIpAddress[0], + pIpAddress[1], + pIpAddress[2], + pIpAddress[3]); + } + } + + // + // All done + // + return errno; +} diff --git a/AppPkg/Applications/Sockets/GetNetByName/GetNetByName.inf b/AppPkg/Applications/Sockets/GetNetByName/GetNetByName.inf new file mode 100644 index 0000000000..1b9764e54b --- /dev/null +++ b/AppPkg/Applications/Sockets/GetNetByName/GetNetByName.inf @@ -0,0 +1,65 @@ +#/** @file +# GetNetByName Application +# +# This file contains an 'Intel Peripheral Driver' and is +# licensed for Intel CPUs and chipsets under the terms of your +# license agreement with Intel or your vendor. This file may +# be modified by the user, subject to additional terms of the +# license agreement +# +# +# Copyright (c) 20011 Intel Corporation. All rights reserved +# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. Except as permitted by such +# license, no part of this software or documentation may be +# reproduced, stored in a retrieval system, or transmitted in any +# form or by any means without the express written consent of +# Intel Corporation. +# +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = GetNetByName + FILE_GUID = DAF7B0E6-32DE-4619-B63A-2B9173A75B14 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = ShellCEntryLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + GetNetByName.c + + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + StdLib/StdLib.dec + + +[LibraryClasses] + BaseMemoryLib + BsdSocketLib + DebugLib + DevShell + EfiSocketLib + LibC + LibMath + LibNetUtil + ShellCEntryLib + UefiBootServicesTableLib + UefiLib +# UseSocketDxe + +[BuildOptions] + INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186 + MSFT:*_*_*_CC_FLAGS = /Od + GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable + diff --git a/AppPkg/Applications/Sockets/GetServByName/GetServByName.c b/AppPkg/Applications/Sockets/GetServByName/GetServByName.c new file mode 100644 index 0000000000..d7237d342c --- /dev/null +++ b/AppPkg/Applications/Sockets/GetServByName/GetServByName.c @@ -0,0 +1,76 @@ +/** @file + Translate the service name into a port number + + Copyright (c) 2011, 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 +#include +#include +#include +#include + +#include +#include + +#include + +char mBuffer [65536]; + + +/** + Translate the service name into a port number + + @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 + ) +{ + int AppStatus; + int PortNumber; + struct servent * pService; + + // + // Determine if the service name is specified + // + AppStatus = 0; + if ( 1 == Argc ) { + Print ( L"%a \r\n", Argv[0]); + } + else { + // + // Translate the service name + // + pService = getservbyname ( Argv[1], NULL ); + if ( NULL == pService ) { + Print ( L"ERROR - service not found, errno: %d\r\n", errno ); + } + else { + PortNumber = htons ( pService->s_port ); + Print ( L"%a: %d, %a\r\n", + pService->s_name, + PortNumber, + pService->s_proto ); + } + } + + // + // All done + // + return errno; +} diff --git a/AppPkg/Applications/Sockets/GetServByName/GetServByName.inf b/AppPkg/Applications/Sockets/GetServByName/GetServByName.inf new file mode 100644 index 0000000000..290d15e938 --- /dev/null +++ b/AppPkg/Applications/Sockets/GetServByName/GetServByName.inf @@ -0,0 +1,65 @@ +#/** @file +# GetServByName Application +# +# This file contains an 'Intel Peripheral Driver' and is +# licensed for Intel CPUs and chipsets under the terms of your +# license agreement with Intel or your vendor. This file may +# be modified by the user, subject to additional terms of the +# license agreement +# +# +# Copyright (c) 20011 Intel Corporation. All rights reserved +# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. Except as permitted by such +# license, no part of this software or documentation may be +# reproduced, stored in a retrieval system, or transmitted in any +# form or by any means without the express written consent of +# Intel Corporation. +# +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = GetServByName + FILE_GUID = 5D1F3F9E-8CEE-4299-93C2-4C64EBB58977 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = ShellCEntryLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + GetServByName.c + + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + StdLib/StdLib.dec + + +[LibraryClasses] + BaseMemoryLib + BsdSocketLib + DebugLib + DevShell + EfiSocketLib + LibC + LibMath + LibNetUtil + ShellCEntryLib + UefiBootServicesTableLib + UefiLib +# UseSocketDxe + +[BuildOptions] + INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186 + MSFT:*_*_*_CC_FLAGS = /Od + GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable + diff --git a/AppPkg/Applications/Sockets/GetServByPort/GetServByPort.c b/AppPkg/Applications/Sockets/GetServByPort/GetServByPort.c new file mode 100644 index 0000000000..6a5fc46ea7 --- /dev/null +++ b/AppPkg/Applications/Sockets/GetServByPort/GetServByPort.c @@ -0,0 +1,77 @@ +/** @file + Translate the port number into a service name + + Copyright (c) 2011, 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 +#include +#include +#include +#include +#include + +#include +#include + +#include + +char mBuffer [65536]; + + +/** + Translate the port number into a service name + + @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 + ) +{ + int AppStatus; + int PortNumber; + struct servent * pService; + + // + // Determine if the service name is specified + // + AppStatus = 0; + if (( 2 != Argc ) + || ( 1 != sscanf ( Argv[1], "%d", &PortNumber ))) { + Print ( L"%a \r\n", Argv[0]); + } + else { + // + // Translate the port number + // + pService = getservbyport ( htons ( PortNumber ), NULL ); + if ( NULL == pService ) { + Print ( L"ERROR - service not found, errno: %d\r\n", errno ); + } + else { + Print ( L"%a: %d, %a\r\n", + pService->s_name, + PortNumber, + pService->s_proto ); + } + } + + // + // All done + // + return errno; +} diff --git a/AppPkg/Applications/Sockets/GetServByPort/GetServByPort.inf b/AppPkg/Applications/Sockets/GetServByPort/GetServByPort.inf new file mode 100644 index 0000000000..1a232c0aad --- /dev/null +++ b/AppPkg/Applications/Sockets/GetServByPort/GetServByPort.inf @@ -0,0 +1,65 @@ +#/** @file +# GetServByPort Application +# +# This file contains an 'Intel Peripheral Driver' and is +# licensed for Intel CPUs and chipsets under the terms of your +# license agreement with Intel or your vendor. This file may +# be modified by the user, subject to additional terms of the +# license agreement +# +# +# Copyright (c) 20011 Intel Corporation. All rights reserved +# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. Except as permitted by such +# license, no part of this software or documentation may be +# reproduced, stored in a retrieval system, or transmitted in any +# form or by any means without the express written consent of +# Intel Corporation. +# +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = GetServByPort + FILE_GUID = 83381B06-2EEA-4cf3-9B5F-D75B9B5C93DE + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = ShellCEntryLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + GetServByPort.c + + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + StdLib/StdLib.dec + + +[LibraryClasses] + BaseMemoryLib + BsdSocketLib + DebugLib + DevShell + EfiSocketLib + LibC + LibMath + LibNetUtil + ShellCEntryLib + UefiBootServicesTableLib + UefiLib +# UseSocketDxe + +[BuildOptions] + INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186 + MSFT:*_*_*_CC_FLAGS = /Od + GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable + diff --git a/AppPkg/Applications/Sockets/RecvDgram/RecvDgram.c b/AppPkg/Applications/Sockets/RecvDgram/RecvDgram.c new file mode 100644 index 0000000000..7809e80ff8 --- /dev/null +++ b/AppPkg/Applications/Sockets/RecvDgram/RecvDgram.c @@ -0,0 +1,116 @@ +/** @file + Receive a datagram + + Copyright (c) 2011, 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 +#include +#include +#include + +#include +#include + +#include + +#include +#include + +UINT8 mBuffer [ 65536 ]; + +/** + Receive a datagram + + @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 + ) +{ + struct sockaddr_in Address; + socklen_t AddressLength; + ssize_t LengthInBytes; + int s; + int Status; + struct timeval Timeout; + + + DEBUG (( DEBUG_INFO, + "%a starting\r\n", + Argv[0])); + + // + // Get the socket + // + s = socket ( AF_INET, SOCK_DGRAM, 0 ); + if ( -1 == s ) { + Print ( L"ERROR - Unable to open the socket, errno: %d\r\n", errno ); + } + else { + Timeout.tv_sec = 5; + Timeout.tv_usec = 0; + Status = setsockopt ( s, + SOL_SOCKET, + SO_RCVTIMEO, + &Timeout, + sizeof ( Timeout )); + if ( -1 == Status ) { + Print ( L"ERROR - Unable to set the receive timeout, errno: %d\r\n", errno ); + } + else { + AddressLength = sizeof ( Address ); + LengthInBytes = recvfrom ( s, + &mBuffer[0], + sizeof ( mBuffer[0]), + 0, + (struct sockaddr *)&Address, + &AddressLength ); + if ( -1 == LengthInBytes ) { + if ( ETIMEDOUT == errno ) { + Print ( L"No datagram received\r\n" ); + } + else { + Print ( L"ERROR - No datagram received, errno: %d\r\n", errno ); + } + } + else { + Print ( L"Received %d bytes from %d.%d.%d.%d:%d\r\n", + LengthInBytes, + (UINT8)Address.sin_addr.s_addr, + (UINT8)( Address.sin_addr.s_addr >> 8 ), + (UINT8)( Address.sin_addr.s_addr >> 16 ), + (UINT8)( Address.sin_addr.s_addr >> 24 ), + htons ( Address.sin_port )); + } + } + + // + // Done with the socket + // + close ( s ); + } + + // + // All done + // + DEBUG (( DEBUG_INFO, + "%a exiting, errno: %d\r\n", + Argv[0], + errno )); + return errno; +} diff --git a/AppPkg/Applications/Sockets/RecvDgram/RecvDgram.inf b/AppPkg/Applications/Sockets/RecvDgram/RecvDgram.inf new file mode 100644 index 0000000000..bef842ad54 --- /dev/null +++ b/AppPkg/Applications/Sockets/RecvDgram/RecvDgram.inf @@ -0,0 +1,64 @@ +#/** @file +# Receive Datagram Application +# +# This file contains an 'Intel Peripheral Driver' and is +# licensed for Intel CPUs and chipsets under the terms of your +# license agreement with Intel or your vendor. This file may +# be modified by the user, subject to additional terms of the +# license agreement +# +# +# Copyright (c) 20011 Intel Corporation. All rights reserved +# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. Except as permitted by such +# license, no part of this software or documentation may be +# reproduced, stored in a retrieval system, or transmitted in any +# form or by any means without the express written consent of +# Intel Corporation. +# +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = RecvDgram + FILE_GUID = 929189C9-0670-4c0b-AF7D-135D1550C8C0 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = ShellCEntryLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + RecvDgram.c + + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + StdLib/StdLib.dec + + +[LibraryClasses] + BaseMemoryLib + BsdSocketLib + DebugLib + DevShell + EfiSocketLib + LibC + LibMath + ShellCEntryLib + UefiBootServicesTableLib + UefiLib +# UseSocketDxe + +[BuildOptions] + INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186 + MSFT:*_*_*_CC_FLAGS = /Od + GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable + diff --git a/AppPkg/Applications/Sockets/SetHostName/SetHostName.c b/AppPkg/Applications/Sockets/SetHostName/SetHostName.c new file mode 100644 index 0000000000..85dc1c43fe --- /dev/null +++ b/AppPkg/Applications/Sockets/SetHostName/SetHostName.c @@ -0,0 +1,100 @@ +/** @file + Set the host name + + Copyright (c) 2011, 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 +#include +#include +#include + +#include +#include + +#include + +char mBuffer [65536]; + + +/** + Set the host name + + @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 + ) +{ + int AppStatus; + + DEBUG (( DEBUG_INFO, + "%a starting\r\n", + Argv[0])); + + // + // Determine if the host name is specified + // + AppStatus = 0; + if ( 1 < Argc ) { + // + // Set the host name + // + AppStatus = sethostname ( Argv[1], strlen ( Argv[1])); + if ( -1 == AppStatus ) { + switch ( errno ) { + default: + Print ( L"ERROR - errno: %d\r\n", errno ); + break; + + case ENODEV: + Print ( L"WARNING - Plarform does not support permanent storage!\r\n" ); + break; + + case ENOMEM: + Print ( L"ERROR - Insufficient storage to save host name!\r\n" ); + break; + + case ENOTSUP: + Print ( L"ERROR - Platform does not support environment variable storage!\r\n" ); + break; + } + } + } + else { + // + // Display the current host name + // + AppStatus = gethostname ( &mBuffer[0], sizeof ( mBuffer )); + if ( -1 == AppStatus ) { + Print ( L"ERROR - Unable to get host name, errno: %d\r\n", errno ); + } + else { + if ( 0 == mBuffer[0]) { + Print ( L"Host name is not set!\r\n" ); + } + else { + Print ( L"Host name: %a", &mBuffer[0]); + } + } + } + + // + // All done + // + return errno; +} diff --git a/AppPkg/Applications/Sockets/SetHostName/SetHostName.inf b/AppPkg/Applications/Sockets/SetHostName/SetHostName.inf new file mode 100644 index 0000000000..2b0bdc7914 --- /dev/null +++ b/AppPkg/Applications/Sockets/SetHostName/SetHostName.inf @@ -0,0 +1,64 @@ +#/** @file +# SetHostName Application +# +# This file contains an 'Intel Peripheral Driver' and is +# licensed for Intel CPUs and chipsets under the terms of your +# license agreement with Intel or your vendor. This file may +# be modified by the user, subject to additional terms of the +# license agreement +# +# +# Copyright (c) 20011 Intel Corporation. All rights reserved +# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. Except as permitted by such +# license, no part of this software or documentation may be +# reproduced, stored in a retrieval system, or transmitted in any +# form or by any means without the express written consent of +# Intel Corporation. +# +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SetHostName + FILE_GUID = 4BC80B15-255D-4858-8072-51D6D98CF90E + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = ShellCEntryLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + SetHostName.c + + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + StdLib/StdLib.dec + + +[LibraryClasses] + BaseMemoryLib + BsdSocketLib + DebugLib + DevShell + EfiSocketLib + LibC + LibMath + ShellCEntryLib + UefiBootServicesTableLib + UefiLib +# UseSocketDxe + +[BuildOptions] + INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186 + MSFT:*_*_*_CC_FLAGS = /Od + GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable + diff --git a/AppPkg/Applications/Sockets/SetSockOpt/SetSockOpt.c b/AppPkg/Applications/Sockets/SetSockOpt/SetSockOpt.c new file mode 100644 index 0000000000..fdc4552b60 --- /dev/null +++ b/AppPkg/Applications/Sockets/SetSockOpt/SetSockOpt.c @@ -0,0 +1,379 @@ +/** @file + Set the socket options + + Copyright (c) 2011, 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 +#include +#include +#include +#include + +#include +#include + +#include +#include + +typedef enum _DATA_TYPE { + DATA_TYPE_UNKNOWN = 0, + DATA_TYPE_INT32_DECIMAL, + DATA_TYPE_SOCKET_TYPE, + DATA_TYPE_TIMEVAL +} DATA_TYPE; + +typedef struct { + char * pOptionName; + int OptionValue; + int OptionLevel; + BOOLEAN bSetAllowed; + DATA_TYPE DataType; +} OPTIONS; + +CONST OPTIONS mOptions [] = { + { "SO_ACCEPTCONN", SO_ACCEPTCONN, SOL_SOCKET, FALSE, DATA_TYPE_UNKNOWN }, + { "SO_BROADCAST", SO_BROADCAST, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN }, + { "SO_DEBUG", SO_DEBUG, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN }, + { "SO_DONTROUTE", SO_DONTROUTE, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN }, + { "SO_ERROR", SO_ERROR, SOL_SOCKET, FALSE, DATA_TYPE_UNKNOWN }, + { "SO_KEEPALIVE", SO_KEEPALIVE, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN }, + { "SO_OOBINLINE", SO_OOBINLINE, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN }, + { "SO_OVERFLOWED", SO_OVERFLOWED, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN }, + { "SO_RCVBUF", SO_RCVBUF, SOL_SOCKET, TRUE, DATA_TYPE_INT32_DECIMAL }, + { "SO_RCVLOWAT", SO_RCVLOWAT, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN }, + { "SO_RCVTIMEO", SO_RCVTIMEO, SOL_SOCKET, TRUE, DATA_TYPE_TIMEVAL }, + { "SO_REUSEADDR", SO_REUSEADDR, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN }, + { "SO_REUSEPORT", SO_REUSEPORT, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN }, + { "SO_SNDBUF", SO_SNDBUF, SOL_SOCKET, TRUE, DATA_TYPE_INT32_DECIMAL }, + { "SO_SNDLOWAT", SO_SNDLOWAT, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN }, + { "SO_SNDTIMEO", SO_SNDTIMEO, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN }, + { "SO_TIMESTAMP", SO_TIMESTAMP, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN }, + { "SO_TYPE", SO_TYPE, SOL_SOCKET, FALSE, DATA_TYPE_SOCKET_TYPE }, + { "SO_USELOOPBACK", SO_USELOOPBACK, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN } +}; + + +UINT8 mBuffer [ 65536 ]; +UINT8 mValue [ 65536 ]; +char * mSocketType [] = { + "SOCK_STREAM", + "SOCK_DGRAM", + "SOCK_RAW", + "SOCK_RDM", + "SOCK_SEQPACKET" +}; + +void +DisplayOption ( + CONST OPTIONS * pOption, + socklen_t LengthInBytes, + BOOLEAN bDisplayUpdate, + BOOLEAN bDisplayCrLf + ) +{ + UINT8 * pEnd; + char * pString; + union { + UINT8 * u8; + INT32 * i32; + struct timeval * TimeVal; + } Value; + + // + // Display the value length + // + if ( !bDisplayUpdate ) { + Print ( L"LengthInBytes: %d\r\n", LengthInBytes ); + Print ( L"%a: ", pOption->pOptionName ); + } + else { + Print ( L" --> " ); + } + + // + // Display the value + // + Value.u8 = &mBuffer[0]; + switch ( pOption->DataType ) + { + case DATA_TYPE_UNKNOWN: + Print ( L"%a:", pOption->pOptionName ); + pEnd = &Value.u8 [ LengthInBytes ]; + while ( pEnd > Value.u8 ) { + Print ( L" %02x", *Value.u8 ); + Value.u8 += 1; + } + break; + + case DATA_TYPE_INT32_DECIMAL: + if ( 4 == LengthInBytes ) { + Print ( L"%d", *Value.i32 ); + } + else { + errno = ( 4 > LengthInBytes ) ? EBUFSIZE : ERANGE; + Print ( L"\r\nERROR - Invalid length, errno: %d\r\n", errno ); + } + break; + + case DATA_TYPE_SOCKET_TYPE: + if ( 4 == LengthInBytes ) { + if (( SOCK_STREAM <= *Value.i32 ) && ( SOCK_SEQPACKET >= *Value.i32 )) { + pString = mSocketType [ *Value.i32 - SOCK_STREAM ]; + Print ( L"%a", pString ); + } + else { + Print ( L"%08x (unknown type)", *Value.i32 ); + } + } + else { + errno = ( 4 > LengthInBytes ) ? EBUFSIZE : ERANGE; + Print ( L"\r\nERROR - Invalid length, errno: %d\r\n", errno ); + } + break; + + case DATA_TYPE_TIMEVAL: + if ( sizeof ( *Value.TimeVal ) == LengthInBytes ) { + if (( 0 == Value.TimeVal->tv_sec ) + && ( 0 == Value.TimeVal->tv_usec )) { + Print ( L"Infinite" ); + } + else { + Print ( L"%d.%06d sec", + Value.TimeVal->tv_sec, + Value.TimeVal->tv_usec ); + } + } + else { + errno = ( 4 > LengthInBytes ) ? EBUFSIZE : ERANGE; + Print ( L"\r\nERROR - Invalid length, errno: %d\r\n", errno ); + } + break; + } + + // + // Terminate the line + // + if ( bDisplayCrLf ) { + Print ( L"\r\n" ); + } +} + +socklen_t +GetOptionValue ( + CONST OPTIONS * pOption, + char * pValue + ) +{ + socklen_t BytesToWrite; + union { + UINT8 * u8; + INT32 * i32; + struct timeval * TimeVal; + } Value; + int Values; + + // + // Assume failure + // + errno = EINVAL; + BytesToWrite = 0; + + // + // Determine the type of parameter + // + if ( pOption->bSetAllowed ) { + Value.u8 = &mValue[0]; + switch ( pOption->DataType ) { + case DATA_TYPE_INT32_DECIMAL: + Values = sscanf ( pValue, "%d", Value.i32 ); + if ( 1 == Values ) { + BytesToWrite = sizeof ( *Value.i32); + errno = 0; + } + break; + + case DATA_TYPE_TIMEVAL: + Values = sscanf ( pValue, "%d.%0d", + &Value.TimeVal->tv_sec, + &Value.TimeVal->tv_usec ); + if (( 2 == Values ) + && ( 0 <= Value.TimeVal->tv_sec ) + && ( 0 <= Value.TimeVal->tv_usec ) + && ( 1000000 > Value.TimeVal->tv_usec )){ + BytesToWrite = sizeof ( *Value.TimeVal ); + errno = 0; + } + } + } + + // + // Display the error + // + if ( 0 == BytesToWrite ) { + Print ( L"ERROR - Invalid value!\r\n" ); + } + + // + // Return the number of bytes to be written + // + return BytesToWrite; +} + + +/** + Set the socket options + + @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 + ) +{ + socklen_t BytesToWrite; + socklen_t LengthInBytes; + CONST OPTIONS * pEnd; + CONST OPTIONS * pOption; + int s; + int Status; + + DEBUG (( DEBUG_INFO, + "%a starting\r\n", + Argv[0])); + + // + // Parse the socket option + // + pOption = &mOptions[0]; + pEnd = &pOption[sizeof ( mOptions ) / sizeof ( mOptions[0])]; + if ( 2 <= Argc ) { + while ( pEnd > pOption ) { + if ( 0 == strcmp ( Argv[1], pOption->pOptionName )) { + break; + } + pOption += 1; + } + if ( pEnd <= pOption ) { + Print ( L"ERROR: Invalid option: %a\r\n", Argv[1]); + Argc = 1; + } + } + + // + // Display the help if necessary + // + if (( 2 > Argc ) || ( 3 < Argc )) { + Print ( L"%a