blob: 727b6a107b28f14c360e5b08e9710570a6378b5f [file] [log] [blame]
/*
*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2013-2017 Nest Labs, Inc.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* Common command-line option handling code for test applications.
*
*/
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif
#include "TestInetCommonOptions.h"
#include <assert.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <inet/InetFaultInjection.h>
#include <lib/support/CHIPFaultInjection.h>
#include <lib/support/CHIPMem.h>
#include <lib/support/CHIPMemString.h>
#include <system/SystemFaultInjection.h>
using namespace chip;
using namespace chip::ArgParser;
using namespace chip::Inet;
// Global Variables
NetworkOptions gNetworkOptions;
FaultInjectionOptions gFaultInjectionOptions;
NetworkOptions::NetworkOptions()
{
static OptionDef optionDefs[] = {
{ "local-addr", kArgumentRequired, 'a' },
{ "node-addr", kArgumentRequired, kToolCommonOpt_NodeAddr }, /* alias for local-addr */
#if CHIP_SYSTEM_CONFIG_USE_LWIP
{ "tap-device", kArgumentRequired, kToolCommonOpt_TapDevice },
{ "ipv4-gateway", kArgumentRequired, kToolCommonOpt_IPv4GatewayAddr },
{ "ipv6-gateway", kArgumentRequired, kToolCommonOpt_IPv6GatewayAddr },
{ "dns-server", kArgumentRequired, 'X' },
{ "debug-lwip", kNoArgument, kToolCommonOpt_DebugLwIP },
{ "event-delay", kArgumentRequired, kToolCommonOpt_EventDelay },
{ "tap-system-config", kNoArgument, kToolCommonOpt_TapInterfaceConfig },
#endif
{}
};
OptionDefs = optionDefs;
HelpGroupName = "NETWORK OPTIONS";
OptionHelp = " -a, --local-addr, --node-addr <ip-addr>\n"
" Local address for the node.\n"
"\n"
#if CHIP_SYSTEM_CONFIG_USE_LWIP
" --tap-device <tap-dev-name>\n"
" TAP device name for LwIP hosted OS usage. Defaults to chip-dev-<node-id>.\n"
"\n"
" --ipv4-gateway <ip-addr>\n"
" Address of default IPv4 gateway.\n"
"\n"
" --ipv6-gateway <ip-addr>\n"
" Address of default IPv6 gateway.\n"
"\n"
" -X, --dns-server <ip-addr>\n"
" IPv4 address of local DNS server.\n"
"\n"
" --debug-lwip\n"
" Enable LwIP debug messages.\n"
"\n"
" --event-delay <int>\n"
" Delay event processing by specified number of iterations. Defaults to 0.\n"
"\n"
" --tap-system-config\n"
" Use configuration on each of the Linux TAP interfaces to configure LwIP's interfaces.\n"
"\n"
#endif // CHIP_SYSTEM_CONFIG_USE_LWIP
;
// Defaults.
LocalIPv4Addr.clear();
LocalIPv6Addr.clear();
#if CHIP_SYSTEM_CONFIG_USE_LWIP
TapDeviceName.clear();
LwIPDebugFlags = 0;
EventDelay = 0;
IPv4GatewayAddr.clear();
IPv6GatewayAddr.clear();
DNSServerAddr = Inet::IPAddress::Any;
TapUseSystemConfig = false;
#endif // CHIP_SYSTEM_CONFIG_USE_LWIP
}
bool NetworkOptions::HandleOption(const char * progName, OptionSet * optSet, int id, const char * name, const char * arg)
{
Inet::IPAddress localAddr;
switch (id)
{
case 'a':
case kToolCommonOpt_NodeAddr:
if (!ParseIPAddress(arg, localAddr))
{
PrintArgError("%s: Invalid value specified for local IP address: %s\n", progName, arg);
return false;
}
#if INET_CONFIG_ENABLE_IPV4
if (localAddr.IsIPv4())
{
LocalIPv4Addr.push_back(localAddr);
}
else
{
LocalIPv6Addr.push_back(localAddr);
}
#else // INET_CONFIG_ENABLE_IPV4
LocalIPv6Addr.push_back(localAddr);
#endif // INET_CONFIG_ENABLE_IPV4
break;
#if CHIP_SYSTEM_CONFIG_USE_LWIP
case 'X':
if (!ParseIPAddress(arg, DNSServerAddr))
{
PrintArgError("%s: Invalid value specified for DNS server address: %s\n", progName, arg);
return false;
}
break;
case kToolCommonOpt_TapDevice:
TapDeviceName.push_back(arg);
break;
case kToolCommonOpt_IPv4GatewayAddr: {
if (!ParseIPAddress(arg, localAddr) || !localAddr.IsIPv4())
{
PrintArgError("%s: Invalid value specified for IPv4 gateway address: %s\n", progName, arg);
return false;
}
IPv4GatewayAddr.push_back(localAddr);
}
break;
case kToolCommonOpt_IPv6GatewayAddr: {
if (!ParseIPAddress(arg, localAddr))
{
PrintArgError("%s: Invalid value specified for IPv6 gateway address: %s\n", progName, arg);
return false;
}
IPv6GatewayAddr.push_back(localAddr);
}
break;
case kToolCommonOpt_DebugLwIP:
#if defined(LWIP_DEBUG)
#if CHIP_TARGET_STYLE_UNIX
gLwIP_DebugFlags = (LWIP_DBG_ON | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_FRESH | LWIP_DBG_HALT);
#endif
#endif
break;
case kToolCommonOpt_EventDelay:
if (!ParseInt(arg, EventDelay))
{
PrintArgError("%s: Invalid value specified for event delay: %s\n", progName, arg);
return false;
}
break;
case kToolCommonOpt_TapInterfaceConfig:
TapUseSystemConfig = true;
break;
#endif // CHIP_SYSTEM_CONFIG_USE_LWIP
default:
PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
return false;
}
return true;
}
FaultInjectionOptions::FaultInjectionOptions()
{
static OptionDef optionDefs[] = {
#if CHIP_CONFIG_TEST || CHIP_SYSTEM_CONFIG_TEST || INET_CONFIG_TEST
{ "faults", kArgumentRequired, kToolCommonOpt_FaultInjection },
{ "iterations", kArgumentRequired, kToolCommonOpt_FaultTestIterations },
{ "debug-resource-usage", kNoArgument, kToolCommonOpt_DebugResourceUsage },
{ "print-fault-counters", kNoArgument, kToolCommonOpt_PrintFaultCounters },
{ "extra-cleanup-time", kArgumentRequired, kToolCommonOpt_ExtraCleanupTime },
#endif
{}
};
OptionDefs = optionDefs;
HelpGroupName = "FAULT INJECTION OPTIONS";
OptionHelp =
#if CHIP_CONFIG_TEST || CHIP_SYSTEM_CONFIG_TEST || INET_CONFIG_TEST
" --faults <fault-string>\n"
" Inject specified fault(s) into the operation of the tool at runtime.\n"
"\n"
" --iterations <int>\n"
" Execute the program operation the given number of times\n"
"\n"
" --debug-resource-usage\n"
" Print all stats counters before exiting.\n"
"\n"
" --print-fault-counters\n"
" Print the fault-injection counters before exiting.\n"
"\n"
" --extra-cleanup-time\n"
" Allow extra time before asserting resource leaks; this is useful when\n"
" running fault-injection tests to let the system free stale ExchangeContext\n"
" instances after RMP has exhausted all retransmission; a failed RMP transmission\n"
" should fail a normal happy-sequence test, but not necessarily a fault-injection test.\n"
" The value is in milliseconds; a common value is 10000.\n"
"\n"
#endif
"";
// Defaults
TestIterations = 1;
DebugResourceUsage = false;
PrintFaultCounters = false;
ExtraCleanupTimeMsec = 0;
}
bool FaultInjectionOptions::HandleOption(const char * progName, OptionSet * optSet, int id, const char * name, const char * arg)
{
using namespace nl::FaultInjection;
GetManagerFn faultMgrFnTable[] = { Inet::FaultInjection::GetManager, System::FaultInjection::GetManager };
size_t faultMgrFnTableLen = sizeof(faultMgrFnTable) / sizeof(faultMgrFnTable[0]);
switch (id)
{
#if CHIP_CONFIG_TEST || CHIP_SYSTEM_CONFIG_TEST || INET_CONFIG_TEST
case kToolCommonOpt_FaultInjection: {
chip::Platform::ScopedMemoryString mutableArg(arg, strlen(arg));
assert(mutableArg);
bool parseRes = ParseFaultInjectionStr(mutableArg.Get(), faultMgrFnTable, faultMgrFnTableLen);
if (!parseRes)
{
PrintArgError("%s: Invalid string specified for fault injection option: %s\n", progName, arg);
return false;
}
break;
}
case kToolCommonOpt_FaultTestIterations:
if ((!ParseInt(arg, TestIterations)) || (TestIterations == 0))
{
PrintArgError("%s: Invalid value specified for the number of iterations to execute: %s\n", progName, arg);
return false;
}
break;
case kToolCommonOpt_DebugResourceUsage:
DebugResourceUsage = true;
break;
case kToolCommonOpt_PrintFaultCounters:
PrintFaultCounters = true;
break;
case kToolCommonOpt_ExtraCleanupTime:
if ((!ParseInt(arg, ExtraCleanupTimeMsec)) || (ExtraCleanupTimeMsec == 0))
{
PrintArgError("%s: Invalid value specified for the extra time to wait before checking for leaks: %s\n", progName, arg);
return false;
}
break;
#endif // CHIP_CONFIG_TEST || CHIP_SYSTEM_CONFIG_TEST || INET_CONFIG_TEST
default:
PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
return false;
}
return true;
}