/** @file Set the socket options Copyright (c) 2011-2012, Intel Corporation. All rights reserved. SPDX-License-Identifier: BSD-2-Clause-Patent **/ #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 ) { default: break; 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.%d", &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