blob: 0282507796b5105c848349b969d3f8a0856a1585 [file] [log] [blame]
/*
*
* 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
* This file implements the Weave Mock Device command line tool.
*
* The Weave Mock Device command line tool is a used, primarily,
* as a test target for various Weave profiles, protocols, and
* server implementations.
*
*/
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <unistd.h>
// Note that the choice of namespace alias must be made up front for each and every compile unit
// This is because many include paths could set the default alias to unintended target.
#include <Weave/Profiles/data-management/Legacy/WdmManagedNamespace.h>
#include "ToolCommon.h"
#include <Weave/WeaveVersion.h>
#include <Weave/Core/WeaveTLV.h>
#include <Weave/Profiles/network-provisioning/NetworkProvisioning.h>
#include <Weave/Profiles/network-provisioning/NetworkInfo.h>
#include <Weave/Profiles/service-provisioning/ServiceProvisioning.h>
#include <Weave/Profiles/fabric-provisioning/FabricProvisioning.h>
#include <Weave/Profiles/device-description/DeviceDescription.h>
#include <Weave/Profiles/device-control/DeviceControl.h>
#include <Weave/Profiles/service-directory/ServiceDirectory.h>
#include <Weave/Profiles/data-management/ProfileDatabase.h>
#include <Weave/Profiles/heartbeat/WeaveHeartbeat.h>
#include <Weave/Support/crypto/WeaveCrypto.h>
#include "MockDCLPServer.h"
#include "MockNPServer.h"
#include "MockSPServer.h"
#include "MockFPServer.h"
#include "MockPairingServer.h"
#include "MockDDServer.h"
#include "MockDCServer.h"
#include "MockOpActions.h"
#include "TestProfile.h"
#include "MockDMPublisher.h"
#include "MockAlarmOriginator.h"
#include "MockAlarmRemote.h"
#include "MockTokenPairingServer.h"
#include "MockWdmSubscriptionInitiator.h"
#include "MockWdmSubscriptionResponder.h"
#include "MockLoggingManager.h"
#if WEAVE_CONFIG_TIME
#include "MockTimeSyncUtil.h"
#include "MockTimeSyncClient.h"
#endif // WEAVE_CONFIG_TIME
#if WEAVE_CONFIG_ENABLE_TUNNELING
#include <Weave/Profiles/weave-tunneling/WeaveTunnelAgent.h>
#endif // WEAVE_CONFIG_ENABLE_TUNNELING
using namespace nl::Weave::Profiles;
using namespace nl::Weave::TLV;
using namespace nl::Weave::Profiles::NetworkProvisioning;
using namespace nl::Weave::Profiles::ServiceProvisioning;
using namespace nl::Weave::Profiles::FabricProvisioning;
using namespace nl::Weave::Profiles::DeviceDescription;
using namespace nl::Weave::Profiles::Heartbeat;
#if WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
using namespace ::nl::Weave::Profiles::ServiceDirectory;
#endif
using namespace ::nl::Weave::Profiles::StatusReporting;
static bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg);
static void HandleEchoRequestReceived(uint64_t nodeId, IPAddress nodeAddr, PacketBuffer *payload);
static void HandleHeartbeatReceived(const WeaveMessageInfo *aMsgInfo, uint8_t nodeState, WEAVE_ERROR err);
static void HandleConnectionReceived(WeaveMessageLayer *msgLayer, WeaveConnection *con);
static void HandleSecureSessionEstablished(WeaveSecurityManager *sm, WeaveConnection *con, void *reqState, uint16_t sessionKeyId, uint64_t peerNodeId, uint8_t encType);
static void HandleSecureSessionError(WeaveSecurityManager *sm, WeaveConnection *con, void *reqState, WEAVE_ERROR localErr, uint64_t peerNodeId, StatusReport *statusReport);
static void HandleConnectionClosed(WeaveConnection *con, WEAVE_ERROR conErr);
static void InitiateConnection(System::Layer* aSystemLayer, void* aAppState, System::Error aError);
static void HandleConnectionComplete(WeaveConnection *con, WEAVE_ERROR conErr);
static void HandleWdmCompleteTest();
static WEAVE_ERROR GetRootDirectoryEntry (uint8_t *buf, uint16_t bufSize);
#if CONFIG_BLE_PLATFORM_BLUEZ
bool EnableWeaveBluezPeripheral = false;
static pthread_t sBLEThread = PTHREAD_NULL;
#endif
#if WEAVE_CONFIG_ENABLE_TUNNELING
using namespace ::nl::Weave::Profiles::WeaveTunnel;
#define DEFAULT_TFE_NODE_ID 0xC0FFEE
WeaveTunnelAgent TunAgent;
const char *TunnelConnectToAddr = NULL;
IPAddress TunnelDestAddr = IPAddress::Any;
uint64_t TunnelDestNodeId = DEFAULT_TFE_NODE_ID;
#if WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
bool UseServiceDirForTunnel = false;
ServiceDirectory::WeaveServiceManager ServiceMgr;
uint8_t ServiceDirCache[100];
#endif
int32_t tunnelingDeviceRole = 0;
#endif
// only for wdm next test
char * TestCaseId = NULL;
bool EnableStopTest = false;
char * NumDataChangeBeforeCancellation = NULL;
char * FinalStatus = NULL;
char * TimeBetweenDataChangeMsec = NULL;
bool EnableDataFlip = true;
char * TimeBetweenLivenessCheckSec = NULL;
bool EnableDictionaryTest = false;
#if CONFIG_BLE_PLATFORM_BLUEZ
// only for woble bluez peripheral
static char * BleName = NULL;
static char * BleAddress = NULL;
#endif
// events
EventGenerator * gEventGenerator = NULL;
int TimeBetweenEvents = 1000;
// only for wdm next test
#if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
uint64_t WdmPublisherNodeId = kAnyNodeId;
uint16_t WdmUseSubnetId = kWeaveSubnetId_NotSpecified;
int WdmRoleInTest = 0;
bool EnableRetry = false;
#endif // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
bool Debug = false;
bool Preconfig = false;
bool UseCASE = false;
const char *ConnectToAddr = NULL;
uint32_t ConnectIntervalMS = 2000;
WeaveEchoServer EchoServer;
WeaveHeartbeatReceiver HeartbeatReceiver;
MockNetworkProvisioningServer MockNPServer;
MockDropcamLegacyPairingServer MockDCLPServer;
MockServiceProvisioningServer MockSPServer;
MockFabricProvisioningServer MockFPServer;
MockPairingServer MockPairingEPServer;
MockDeviceDescriptionServer MockDDServer;
MockDeviceControlServer MockDCServer;
MockTokenPairingServer MockTPServer;
static bool ShouldListenToAlarm = true;
static bool ShouldSendAlarmEvents = false;
static MockAlarmOriginator MockAlarmServer;
static bool AlarmHushEnable = false;
static uint64_t AlarmHushPeerNodeId = kAnyNodeId;
static MockAlarmRemote MockAlarmRemoteHush;
#if WEAVE_CONFIG_TIME
MockTimeSync MockTimeNode;
uint64_t TimeSyncServerNodeId = kAnyNodeId;
const char *TimeSyncServerNodeAddr = NULL;
uint16_t TimeSyncServerSubnetId = kWeaveSubnetId_NotSpecified;
MockSingleSourceTimeSyncClient simpleTimeSyncClient;
bool ShouldEnableSimpleTimeSyncClient = false;
#endif // WEAVE_CONFIG_TIME
MockDMPublisher MockDMPublisher;
MockOpActions OpActions;
uint32_t RespDelayTime = 10000;
const char *PairingServer = NULL;
uint64_t PairingEndPointIdArg = kServiceEndpoint_ServiceProvisioning;
int PairingTransportArg = kPairingTransport_TCP;
#define TOOL_NAME "mock-device"
enum
{
kToolOpt_ConnectTo = 1000,
kToolOpt_ConnectToInterval = 1001,
kToolOpt_TimeSyncServer = 1003, // specify that this mock device should run a Time Sync Server
kToolOpt_TimeSyncClient = 1004, // specify that this mock device should run a Time Sync Client
kToolOpt_TimeSyncCoordinator = 1005, // specify that this mock device should run a Time Sync Coordinator
kToolOpt_TimeSyncModeLocal = 1006, // specify that the Time Client Sync mode is Local (time sync with local nodes via UDP)
kToolOpt_TimeSyncModeService = 1007, // specify that the Time Client Sync mode is Service (time sync with Service via TCP)
kToolOpt_TimeSyncModeAuto = 1008, // specify that the Time Client Sync mode is Auto (time sync via multicast)
kToolOpt_AlarmOriginator = 1009, // specify that this mock device should initiate alarm events on its own
kToolOpt_AlarmHush = 1010, // specify that this mock device should run an Alarm Remote (and not listening to alarm events)
kToolOpt_TunnelBorderGw = 1012, // specify that this mock device should run as a Border gateway capable of Tunneling
kToolOpt_TunnelMobDevice = 1013, // specify that this mock device should run as a Mobile Device capable of Tunneling
kToolOpt_TunnelConnectAddr = 1014,
kToolOpt_TunnelDestNodeId = 1015,
#if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
kToolOpt_WdmPublisherNodeId = 1016, // Specify the node ID of the WDM Publisher we should connect to
kToolOpt_WdmUseSubnetId = 1017, // True if the publisher is within the specified subnet
//kToolOpt_WdmSimpleViewClient = 1018,
//kToolOpt_WdmSimpleViewServer = 1019,
kToolOpt_WdmSubscriptionClient = 1020,
kToolOpt_WdmSubscriptionPublisher = 1021,
kToolOpt_WdmInitMutualSubscription = 1022,
kToolOpt_WdmRespMutualSubscription = 1023,
#endif // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
// only for wdm next test
kToolOpt_TestCaseId = 1024,
kToolOpt_EnableStopTest = 1025,
kToolOpt_NumDataChangeBeforeCancellation = 1026,
kToolOpt_FinalStatus = 1027,
kToolOpt_TimeBetweenDataChangeMsec = 1028,
kToolOpt_EnableDataFlip = 1031,
kToolOpt_EventGenerator = 1032,
kToolOpt_TimeBetweenEvents = 1033,
kToolOpt_TimeBetweenLivenessCheckSec = 1034,
// only for wdm next test
kToolOpt_PairViaWRM = 1035,
kToolOpt_PairingEndPointId = 1037,
kToolOpt_TimeSyncSimpleClient = 1038, // specify that this mock device should run a Simple Time Sync Client
kToolOpt_TimeSyncServerNodeId = 1039, // Specify the node ID of the Time Sync Server we should contact with
kToolOpt_TimeSyncServerSubnetId = 1040, // Specify the subnet ID of the Time Sync Server we should contact with
kToolOpt_TimeSyncServerNodeAddr = 1041, // Specify the node address of the Time Sync Server we should contact
kToolOpt_TimeSyncModeServiceOverTunnel = 1042, // specify that the Time Client Sync mode is Service (time sync with Service over a tunnel)
kToolOpt_UseServiceDir,
kToolOpt_EnableDictionaryTest,
kToolOpt_WdmEnableRetry,
kToolOpt_SuppressAccessControl,
// only for weave over bluez peripheral
#if CONFIG_BLE_PLATFORM_BLUEZ
kToolOpt_EnableWeaveBluezPeripheral,
kToolOpt_WeaveBluezPeripheralName,
kToolOpt_WeaveBluezPeripheralAddress
#endif
};
static OptionDef gToolOptionDefs[] =
{
#if WEAVE_CONFIG_ENABLE_TUNNELING
{ "tun-border-gw", kNoArgument, kToolOpt_TunnelBorderGw },
{ "tun-mob-device", kNoArgument, kToolOpt_TunnelMobDevice },
{ "tun-connect-to", kArgumentRequired, kToolOpt_TunnelConnectAddr },
{ "tun-dest-node-id", kArgumentRequired, kToolOpt_TunnelDestNodeId },
#if WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
{ "service-dir", kNoArgument, kToolOpt_UseServiceDir },
#endif // WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
#if CONFIG_BLE_PLATFORM_BLUEZ
{ "enable-bluez-peripheral", kNoArgument, kToolOpt_EnableWeaveBluezPeripheral },
{ "peripheral-name", kArgumentRequired, kToolOpt_WeaveBluezPeripheralName },
{ "peripheral-address", kArgumentRequired, kToolOpt_WeaveBluezPeripheralAddress },
#endif
#endif //WEAVE_CONFIG_ENABLE_TUNNELING
{ "pairing-server", kArgumentRequired, 'p' },
{ "wrm-pairing", kNoArgument, kToolOpt_PairViaWRM },
{ "pairing-endpoint-id", kArgumentRequired, kToolOpt_PairingEndPointId },
{ "delay", kArgumentRequired, 'r' },
{ "delay-time", kArgumentRequired, 't' },
{ "preconfig", kNoArgument, 'c' },
{ "case", kNoArgument, 'C' },
{ "suppress-ac", kNoArgument, kToolOpt_SuppressAccessControl },
{ "connect-to", kArgumentRequired, kToolOpt_ConnectTo },
{ "connect-to-interval", kArgumentRequired, kToolOpt_ConnectToInterval },
#if WEAVE_CONFIG_TIME
{ "time-sync-server", kNoArgument, kToolOpt_TimeSyncServer },
{ "time-sync-client", kNoArgument, kToolOpt_TimeSyncClient },
{ "time-sync-coordinator", kNoArgument, kToolOpt_TimeSyncCoordinator },
{ "time-sync-mode-local", kNoArgument, kToolOpt_TimeSyncModeLocal },
{ "time-sync-mode-service", kNoArgument, kToolOpt_TimeSyncModeService },
{ "time-sync-mode-service-over-tunnel", kNoArgument, kToolOpt_TimeSyncModeServiceOverTunnel },
{ "time-sync-mode-auto", kNoArgument, kToolOpt_TimeSyncModeAuto },
{ "ts-simple-client", kNoArgument, kToolOpt_TimeSyncSimpleClient },
{ "ts-server-node-id", kArgumentRequired, kToolOpt_TimeSyncServerNodeId },
{ "ts-server-node-addr", kArgumentRequired, kToolOpt_TimeSyncServerNodeAddr },
{ "ts-server-subnet-id", kArgumentRequired, kToolOpt_TimeSyncServerSubnetId },
#endif // WEAVE_CONFIG_TIME
{ "alarm-originator", kNoArgument, kToolOpt_AlarmOriginator },
{ "alarm-hush", kArgumentRequired, kToolOpt_AlarmHush },
// only for wdm next test
{ "test-case", kArgumentRequired, kToolOpt_TestCaseId },
{ "enable-stop", kNoArgument, kToolOpt_EnableStopTest },
{ "total-count", kArgumentRequired, kToolOpt_NumDataChangeBeforeCancellation },
{ "final-status", kArgumentRequired, kToolOpt_FinalStatus },
{ "timer-period", kArgumentRequired, kToolOpt_TimeBetweenDataChangeMsec },
{ "enable-flip", kArgumentRequired, kToolOpt_EnableDataFlip },
{ "enable-dictionary-test", kArgumentRequired, kToolOpt_EnableDictionaryTest },
{ "event-generator", kArgumentRequired, kToolOpt_EventGenerator },
{ "inter-event-period", kArgumentRequired, kToolOpt_TimeBetweenEvents },
// only for wdm next test
#if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
{ "wdm-publisher", kArgumentRequired, kToolOpt_WdmPublisherNodeId },
{ "wdm-subnet", kArgumentRequired, kToolOpt_WdmUseSubnetId },
//{ "wdm-simple-view-client", kNoArgument, kToolOpt_WdmSimpleViewClient },
//{ "wdm-simple-view-server", kNoArgument, kToolOpt_WdmSimpleViewServer },
{ "wdm-one-way-sub-client", kNoArgument, kToolOpt_WdmSubscriptionClient },
{ "wdm-one-way-sub-publisher", kNoArgument, kToolOpt_WdmSubscriptionPublisher },
{ "wdm-init-mutual-sub", kNoArgument, kToolOpt_WdmInitMutualSubscription },
{ "wdm-resp-mutual-sub", kNoArgument, kToolOpt_WdmRespMutualSubscription },
{ "wdm-liveness-check-period", kArgumentRequired, kToolOpt_TimeBetweenLivenessCheckSec },
{ "wdm-enable-retry", kNoArgument, kToolOpt_WdmEnableRetry },
#endif // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
{ NULL }
};
static const char *const gToolOptionHelp =
" -c, --preconfig\n"
" Initialize the mock device as if it had already been configured.\n"
"\n"
" -P, --pairing-code <code>\n"
" Pairing code to use when authenticating clients. Defaults to 'TEST'.\n"
"\n"
" -r, --delay <op-name>\n"
" Insert a delay before returning the success response for a particular\n"
" operation.\n"
"\n"
" -t, --delay-time <ms>\n"
" Set the response delay time. Defaults to 10 seconds.\n"
"\n"
" -p, --pairing-server <hostname>\n"
" Hostname/IP address of pairing server.\n"
"\n"
" --wrm-pairing\n"
" Send PairDeviceToAccount message via WRM (default is TCP).\n"
"\n"
" --pairing-endpoint-id\n"
" The node id of the pairing service endpoint.\n"
"\n"
" --connect-to <addr>[:<port>][%<interface>]\n"
" Create a Weave connection to the specified address on start up. This\n"
" can be used to initiate a passive rendezvous with remote device manager.\n"
"\n"
" --connect-to-interval <ms>\n"
" Interval at which to perform connect attempts to the connect-to address.\n"
" Defaults to 2 seconds.\n"
"\n"
#if WEAVE_CONFIG_TIME
" --time-sync-server\n"
" Enable Time Sync Server.\n"
"\n"
" --time-sync-client\n"
" Enable Time Sync Client.\n"
"\n"
" --time-sync-coordinator\n"
" Enable Time Sync Coordinator.\n"
"\n"
" --time-sync-mode-local\n"
" specify that the Time Client Sync mode is Local (time sync with local nodes via UDP)\n"
"\n"
" --time-sync-mode-service\n"
" specify that the Time Client Sync mode is Service (time sync with Service via TCP)\n"
"\n"
" --time-sync-mode-service-over-tunnel\n"
" specify that the Time Client Sync mode is Service (time sync with Service via WRM over a Tunnel)\n"
"\n"
" --time-sync-mode-auto\n"
" specify that the Time Client Sync mode is Auto (time sync with via Multicast)\n"
"\n"
" --ts-simple-client\n"
" Initiate the single source time sync client\n"
"\n"
" --ts-server-node-id\n"
" Set server node id for the time sync client to send request to\n"
"\n"
" --ts-server-node-addr\n"
" Set server node addr for the time sync client to send request to\n"
"\n"
" --ts-server-subnet-id\n"
" Set subnet id for the time sync client to send request to\n"
"\n"
#endif // WEAVE_CONFIG_TIME
" --alarm-originator\n"
" Initiate alarm events in addition to just listening and propagating.\n"
"\n"
" --alarm-hush <noide id>\n"
" Send AlarmHush request to the specified node\n"
"\n"
#if WEAVE_CONFIG_ENABLE_TUNNELING
" --tun-border-gw\n"
" Assume the role of a Border Gateway capable of Tunneling Weave data traffic.\n"
"\n"
" --tun-mob-device\n"
" Assume the role of a Mobile Device capable of Tunneling Weave data traffic.\n"
"\n"
" --tun-connect-to <addr>[:<port>][%<interface>]\n"
" Create a Tunnel Border gateway connection to the specified address on start up.\n"
"\n"
" --tun-dest-node-id <num>\n"
" Node id for Tunnel peer node. Defaults to 0xc0ffee.\n"
"\n"
#if WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
" --service-dir\n"
" Use service directory to lookup the destination node address for the tunnel server.\n"
"\n"
#endif // WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
#endif // WEAVE_CONFIG_ENABLE_TUNNELING
#if CONFIG_BLE_PLATFORM_BLUEZ
" --enable-bluez-peripheral\n"
" enable weave over bluez peripheral\n"
"\n"
" --enable-inet\n"
" enable inet\n"
"\n"
" --peripheral-name\n"
" Bluez periheral name\n"
"\n"
" --peripheral-address\n"
" Bluez peripheral mac address\n"
"\n"
#endif
" -C, --case\n"
" Use CASE to create an authenticated session and encrypt messages using\n"
" the negotiated session key.\n"
"\n"
" --suppress-ac\n"
" Suppress access controls when responding to incoming requests.\n"
"\n"
#if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
" --wdm-publisher <publisher node id>\n"
" Configure the node ID for WDM Next publisher\n"
"\n"
" --wdm-subnet <subnet of the publisher in hex>\n"
" Predefined service subnet ID is 5\n"
"\n"
" --wdm-simple-view-client\n"
" Initiate a simple WDM Next view client\n"
"\n"
" --wdm-simple-view-server\n"
" Initiate a simple WDM Next view server\n"
"\n"
" --wdm-one-way-sub-client\n"
" Initiate a subscription to some WDM Next publisher\n"
"\n"
" --wdm-one-way-sub-publisher\n"
" Respond to a number of WDM Next subscriptions as a publisher\n"
"\n"
" --wdm-init-mutual-sub\n"
" Initiate a subscription to some WDM Next publisher, while publishing at the same time \n"
"\n"
" --wdm-resp-mutual-sub\n"
" Respond to WDM Next subscription as a publisher with a mutual subscription\n"
"\n"
" --wdm-liveness-check-period\n"
" Specify the time, in seconds, between liveness check in WDM Next subscription as a publisher\n"
"\n"
" --wdm-enable-retry"
" Enable automatic retries by WDM\n"
"\n"
#endif // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
// only for wdm next test
" --event-generator [None | Debug | Liveness | Security | Telemetry | TestTrait]\n"
" Generate structured Weave events using a particular generator:"
" None: no events\n"
" Debug: Freeform strings, from helloweave-app. Uses debug_trait to emit messages at \n"
" Production level\n"
" Liveness: Liveness events, using liveness_trait at Production level.\n"
" Security: Multi-trait scenario emitting events from debug_trait, open_close_trait,\n"
" pincode_input_trait and bolt_lock_trait\n"
" Telemetry: WiFi telemetry events at Production level.\n"
" TestTrait: TestETrait events which cover a range of types.\n"
"\n"
" --inter-event-period <ms>"
" Delay between emitting consecutive events (default 1s)\n"
"\n"
" --test-case <test case id>\n"
" Further configure device behavior with this test case id\n"
"\n"
" --enable-stop\n"
" Terminate WDM Next test in advance for Happy test\n"
"\n"
" --total-count\n"
" when it is -1, mutate trait instance for unlimited iterations, when it is X,\n"
" mutate trait instance for X iterations\n"
"\n"
" --final-status\n"
" When Final Status is\n"
" 0: Client Cancel,\n"
" 1: Publisher Cancel,\n"
" 2: Client Abort,\n"
" 3: Publisher Abort,\n"
" 4: Idle\n"
"\n"
" --enable-dictionary-test\n"
" Enable/disable dictionary test\n"
"\n"
" --timer-period\n"
" Every timer-period, the mutate timer handler is triggered\n"
"\n"
" --enable-flip <true|false|yes|no|1|0>\n"
" Enable/disable flip trait data in HandleDataFlipTimeout\n"
// only for wdm next test
"\n"
;
static OptionSet gToolOptions =
{
HandleOption,
gToolOptionDefs,
"GENERAL OPTIONS",
gToolOptionHelp
};
static HelpOptions gHelpOptions(
TOOL_NAME,
"Usage: " TOOL_NAME " [<options...>]\n",
WEAVE_VERSION_STRING "\n" WEAVE_TOOL_COPYRIGHT,
"Generic Weave device simulator.\n"
);
static OptionSet *gToolOptionSets[] =
{
&gToolOptions,
&gNetworkOptions,
&gWeaveNodeOptions,
&gWRMPOptions,
&gWeaveSecurityMode,
&gCASEOptions,
&gKeyExportOptions,
&gDeviceDescOptions,
&gServiceDirClientOptions,
&gFaultInjectionOptions,
&gHelpOptions,
&gGroupKeyEncOptions,
NULL
};
int main(int argc, char *argv[])
{
WEAVE_ERROR err;
WeaveAuthMode authMode = kWeaveAuthMode_Unauthenticated;
uint32_t KeyId = WeaveKeyId::kNone;
#if CONFIG_BLE_PLATFORM_BLUEZ
Bluez_PeripheralArgs Bluez_PeripheralArgs;
#endif
#if WEAVE_CONFIG_TEST
nl::Weave::System::Stats::Snapshot before;
nl::Weave::System::Stats::Snapshot after;
const bool printStats = true;
#endif
InitToolCommon();
#if WEAVE_CONFIG_TEST
SetupFaultInjectionContext(argc, argv);
#endif
SetSignalHandler(DoneOnHandleSIGUSR1);
if (!ParseArgsFromEnvVar(TOOL_NAME, TOOL_OPTIONS_ENV_VAR_NAME, gToolOptionSets, NULL, true) ||
!ParseArgs(TOOL_NAME, argc, argv, gToolOptionSets))
{
exit(EXIT_FAILURE);
}
if (gNetworkOptions.LocalIPv6Addr != IPAddress::Any)
{
if (!gNetworkOptions.LocalIPv6Addr.IsIPv6ULA())
{
printf("ERROR: Local address must be an IPv6 ULA\n");
exit(EXIT_FAILURE);
}
gWeaveNodeOptions.FabricId = gNetworkOptions.LocalIPv6Addr.GlobalId();
if (!gWeaveNodeOptions.LocalNodeIdSet)
{
gWeaveNodeOptions.LocalNodeId = IPv6InterfaceIdToWeaveNodeId(gNetworkOptions.LocalIPv6Addr.InterfaceId());
}
gWeaveNodeOptions.SubnetId = gNetworkOptions.LocalIPv6Addr.Subnet();
}
InitSystemLayer();
InitNetwork();
InitWeaveStack(true, true);
KeyId = gGroupKeyEncOptions.GetEncKeyId();
#if WEAVE_CONFIG_ENABLE_TUNNELING
if (TunnelDestAddr == IPAddress::Any)
{
TunnelDestAddr = FabricState.SelectNodeAddress(TunnelDestNodeId);
}
printf("Weave Node Configuration:\n");
printf(" Fabric Id: %" PRIX64 "\n", FabricState.FabricId);
printf(" Subnet Number: %X\n", FabricState.DefaultSubnet);
printf(" Node Id: %" PRIX64 "\n", FabricState.LocalNodeId);
if (TunnelConnectToAddr != NULL)
{
IPAddress::FromString(TunnelConnectToAddr, TunnelDestAddr);
}
#if WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
err = ServiceMgr.init(&ExchangeMgr, ServiceDirCache, sizeof(ServiceDirCache),
GetRootDirectoryEntry, kWeaveAuthMode_CASE_ServiceEndPoint);
FAIL_ERROR(err, "ServiceMgr.Init failed");
#endif
if (UseCASE)
authMode = kWeaveAuthMode_CASE_AnyCert;
if (tunnelingDeviceRole)
{
#if WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
if (UseServiceDirForTunnel)
{
err = TunAgent.Init(&Inet, &ExchangeMgr, TunnelDestNodeId,
authMode, &ServiceMgr,
"weave-tun0", tunnelingDeviceRole);
}
else
#endif
{
err = TunAgent.Init(&Inet, &ExchangeMgr, TunnelDestNodeId, TunnelDestAddr,
authMode,
"weave-tun0", tunnelingDeviceRole);
}
FAIL_ERROR(err, "TunnelAgent.Init failed");
err = TunAgent.StartServiceTunnel();
FAIL_ERROR(err, "TunnelAgent.StartServiceTunnel failed");
}
#endif // WEAVE_CONFIG_ENABLE_TUNNELING
// Arrange to get called for various activity in the message layer.
MessageLayer.OnConnectionReceived = HandleConnectionReceived;
MessageLayer.OnReceiveError = HandleMessageReceiveError;
MessageLayer.OnAcceptError = HandleAcceptConnectionError;
SecurityMgr.OnSessionEstablished = HandleSecureSessionEstablished;
SecurityMgr.OnSessionError = HandleSecureSessionError;
// Initialize the EchoServer application.
err = EchoServer.Init(&ExchangeMgr);
FAIL_ERROR(err, "WeaveEchoServer.Init failed");
// Arrange to get a callback whenever an Echo Request is received.
EchoServer.OnEchoRequestReceived = HandleEchoRequestReceived;
// Initialize the Heartbeat receiver
err = HeartbeatReceiver.Init(&ExchangeMgr);
FAIL_ERROR(err, "WeaveHeartbeatReceiver.Init failed");
// Arrange to get a callback whenever a Heartbeat is received.
HeartbeatReceiver.OnHeartbeatReceived = HandleHeartbeatReceived;
// Initialize the mock network provisioning server
err = MockNPServer.Init(&ExchangeMgr);
FAIL_ERROR(err, "MockNetworkProvisioningServer.Init failed");
// Initialize the mock Dropcam legacy pairing server
err = MockDCLPServer.Init(&ExchangeMgr);
FAIL_ERROR(err, "MockDropcamLegacyPairingServer.Init failed");
// Initialize the mock service provisioning server
err = MockSPServer.Init(&ExchangeMgr);
FAIL_ERROR(err, "MockServiceProvisioningServer.Init failed");
MockSPServer.PairingTransport = PairingTransportArg;
MockSPServer.PairingEndPointId = PairingEndPointIdArg;
if (PairingServer != NULL)
{
MockSPServer.PairingServerAddr = PairingServer;
}
// Initialize the mock fabric provisioning server
err = MockFPServer.Init(&ExchangeMgr);
FAIL_ERROR(err, "MockFabricProvisioningServer.Init failed");
// Initialize the mock pairing server
err = MockPairingEPServer.Init(&ExchangeMgr);
FAIL_ERROR(err, "MockPairingServer.Init failed");
// Initialize the mock device description server.
err = MockDDServer.Init(&ExchangeMgr);
FAIL_ERROR(err, "MockDDServer.Init failed");
// Initialize the mock device control server.
err = MockDCServer.Init(&ExchangeMgr);
FAIL_ERROR(err, "MockDCServer.Init failed");
// Initialize the mock token pairing server.
err = MockTPServer.Init(&ExchangeMgr);
FAIL_ERROR(err, "MockTPServer.Init failed");
#if WEAVE_CONFIG_TIME
err = MockTimeNode.Init(&ExchangeMgr, TimeSyncServerNodeId, TimeSyncServerNodeAddr);
FAIL_ERROR(err, "init_mock_time_sync failed");
if (ShouldEnableSimpleTimeSyncClient)
{
err = simpleTimeSyncClient.Init(&ExchangeMgr, TimeSyncServerNodeId, TimeSyncServerSubnetId);
FAIL_ERROR(err, "init_mock_simple_time_sync failed");
}
#endif // WEAVE_CONFIG_TIME
// Initialize the mock alarm server.
if (ShouldListenToAlarm)
{
err = MockAlarmServer.Init(&ExchangeMgr, ShouldSendAlarmEvents);
// Perform second attempt to initialize the mock alarm server. The first
// initialization attempt may fail due to fault injected in the new exchange
// context allocation.
if (err == WEAVE_ERROR_NO_MEMORY)
err = MockAlarmServer.Init(&ExchangeMgr, ShouldSendAlarmEvents);
FAIL_ERROR(err, "MockAlarmServer.Init failed");
}
if (AlarmHushEnable)
{
MockAlarmRemoteHush.Init(&ExchangeMgr, AlarmHushPeerNodeId, 0xDEADBEEF);
}
InitializeEventLogging(&ExchangeMgr);
#if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
switch (WdmRoleInTest)
{
case 0:
break;
#if WEAVE_CONFIG_TEST_WDM_SIMPLE_VIEW_CLIENT
case kToolOpt_WdmSimpleViewClient:
if (WdmPublisherNodeId != kAnyNodeId)
{
err = MockWdmViewClient::GetInstance()->Init(&ExchangeMgr, TestCaseId);
FAIL_ERROR(err, "MockWdmViewClient.Init failed");
err = MockWdmViewClient::GetInstance()->StartTesting(WdmPublisherNodeId, WdmUseSubnetId);
FAIL_ERROR(err, "MockWdmViewClient.StartTesting failed");
MockWdmViewClient::GetInstance()-> onCompleteTest = HandleWdmCompleteTest;
}
else
{
err = WEAVE_ERROR_INVALID_ARGUMENT;
FAIL_ERROR(err, "Simple View Client requires node ID to some publisher");
}
break;
case kToolOpt_WdmSimpleViewServer:
err = MockWdmViewServer::GetInstance()->Init(&ExchangeMgr, TestCaseId);
FAIL_ERROR(err, "MockWdmViewServer.Init failed");
break;
#endif // WEAVE_CONFIG_TEST_WDM_SIMPLE_VIEW_CLIENT
case kToolOpt_WdmInitMutualSubscription:
case kToolOpt_WdmSubscriptionClient:
if (WdmPublisherNodeId != kAnyNodeId)
{
err = MockWdmSubscriptionInitiator::GetInstance()->Init(&ExchangeMgr,
kToolOpt_WdmInitMutualSubscription == WdmRoleInTest,
TestCaseId, NumDataChangeBeforeCancellation, FinalStatus,
TimeBetweenDataChangeMsec, EnableDataFlip,
TimeBetweenLivenessCheckSec, EnableDictionaryTest,
gWeaveSecurityMode.SecurityMode, KeyId, EnableRetry);
FAIL_ERROR(err, "MockWdmSubscriptionInitiator.Init failed");
err = MockWdmSubscriptionInitiator::GetInstance()->StartTesting(WdmPublisherNodeId, WdmUseSubnetId);
FAIL_ERROR(err, "MockWdmSubscriptionInitiator.StartTesting failed");
MockWdmSubscriptionInitiator::GetInstance()->onCompleteTest = HandleWdmCompleteTest;
}
else
{
err = WEAVE_ERROR_INVALID_ARGUMENT;
FAIL_ERROR(err, "MockWdmSubscriptionInitiator requires node ID to some publisher");
}
break;
case kToolOpt_WdmRespMutualSubscription:
case kToolOpt_WdmSubscriptionPublisher:
if (EnableRetry)
{
err = WEAVE_ERROR_INVALID_ARGUMENT;
FAIL_ERROR(err, "MockWdmSubcriptionResponder is incompatible with --wdm-enable-retry");
}
err = MockWdmSubscriptionResponder::GetInstance()->Init(&ExchangeMgr,
kToolOpt_WdmRespMutualSubscription == WdmRoleInTest,
TestCaseId, NumDataChangeBeforeCancellation, FinalStatus, TimeBetweenDataChangeMsec, EnableDataFlip, TimeBetweenLivenessCheckSec);
FAIL_ERROR(err, "MockWdmSubscriptionResponder.Init failed");
MockWdmSubscriptionResponder::GetInstance()->onCompleteTest = HandleWdmCompleteTest;
break;
default:
err = WEAVE_ERROR_INVALID_ARGUMENT;
FAIL_ERROR(err, "WdmRoleInTest is invalid");
};
#endif // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
if (Preconfig)
{
MockNPServer.Preconfig();
MockFPServer.Preconfig();
MockSPServer.Preconfig();
}
PrintNodeConfig();
printf(" Pairing Server: %s\n", MockSPServer.PairingServerAddr);
// If instructed to initiate a connection to a remote address, arm a timer that will
// fire as soon as we enter the network service loop.
if (ConnectToAddr != NULL)
{
err = SystemLayer.StartTimer(1, InitiateConnection, NULL);
FAIL_ERROR(err, "SystemLayer.StartTimer failed");
}
// always set up a mock DM publisher
err = MockDMPublisher.Init(&ExchangeMgr, kDefaultDMResponseTimeout);
FAIL_ERROR(err, "could not start DM publisher");
if (gEventGenerator != NULL)
{
printf("Starting Event Generator\n");
MockEventGenerator::GetInstance()->Init(&ExchangeMgr, gEventGenerator, TimeBetweenEvents, true);
}
#if WEAVE_CONFIG_TEST
nl::Weave::Stats::UpdateSnapshot(before);
#endif
printf("Listening for requests...\n");
#if CONFIG_BLE_PLATFORM_BLUEZ
if (EnableWeaveBluezPeripheral)
{
if (BleName != NULL && BleAddress != NULL)
{
printf("BLE Peripheral name is %s.\n", BleName);
printf("BLE Peripheral mac address is %s.\n", BleAddress);
Bluez_PeripheralArgs.BleName = BleName;
Bluez_PeripheralArgs.BleAddress = BleAddress;
int pthreadErr = 0;
pthreadErr = pthread_create(&sBLEThread, NULL, WeaveBleIOLoop, (void *)&Bluez_PeripheralArgs);
if (pthreadErr)
{
printf("pthread_create() failed for BLE IO thread, err: %d\n", pthreadErr);
exit(EXIT_FAILURE);
}
printf("Weave stack IO loops is running\n");
}
else
{
printf("Expect BLE Peripheral name and BLE mac address\n");
exit(EXIT_FAILURE);
}
}
#endif // CONFIG_BLE_PLATFORM_BLUEZ
while (!Done)
{
struct timeval sleepTime;
sleepTime.tv_sec = 0;
sleepTime.tv_usec = 100000;
ServiceNetwork(sleepTime);
#if WEAVE_CONFIG_WDM_ALLOW_PUBLISHER_SUBSCRIPTION
MockDMPublisher.Republish();
#endif //WEAVE_CONFIG_WDM_ALLOW_PUBLISHER_SUBSCRIPTION
}
#if WEAVE_CONFIG_TEST
ProcessStats(before, after, printStats, NULL);
PrintFaultInjectionCounters();
#endif
SystemLayer.CancelTimer(InitiateConnection, NULL);
MockNPServer.Shutdown();
MockDCLPServer.Shutdown();
EchoServer.Shutdown();
HeartbeatReceiver.Shutdown();
MockDCServer.Shutdown();
MockDDServer.Shutdown();
MockFPServer.Shutdown();
MockPairingEPServer.Shutdown();
MockTPServer.Shutdown();
MockSPServer.Shutdown();
MockDMPublisher.Finalize();
#if WEAVE_CONFIG_TIME
MockTimeNode.Shutdown();
#endif // WEAVE_CONFIG_TIME
if (AlarmHushEnable)
{
MockAlarmRemoteHush.Shutdown();
}
if (ShouldListenToAlarm)
{
MockAlarmServer.Shutdown();
}
#if WEAVE_CONFIG_ENABLE_TUNNELING
if (tunnelingDeviceRole)
{
TunAgent.Shutdown();
}
#endif // WEAVE_CONFIG_ENABLE_TUNNELING
ShutdownWeaveStack();
return EXIT_SUCCESS;
}
bool HandleOption(const char *progName, OptionSet *optSet, int id, const char *name, const char *arg)
{
switch (id)
{
case 'p':
PairingServer = arg;
break;
case 'c':
Preconfig = true;
break;
case 'r':
if (!OpActions.SetDelay(arg, RespDelayTime))
{
PrintArgError("%s: Invalid value specified for response delay name: %s\n", progName, arg);
return false;
}
break;
case 't':
if (!ParseInt(arg, RespDelayTime))
{
PrintArgError("%s: Invalid value specified for response delay time: %s\n", progName, arg);
return false;
}
break;
case kToolOpt_PairViaWRM:
PairingTransportArg = kPairingTransport_WRM;
break;
case kToolOpt_PairingEndPointId:
if (!ParseNodeId(arg, PairingEndPointIdArg))
{
PrintArgError("%s: Invalid value specified for pairing endpoint node id: %s\n", progName, arg);
return false;
}
break;
case kToolOpt_ConnectTo:
ConnectToAddr = arg;
break;
case kToolOpt_ConnectToInterval:
if (!ParseInt(arg, ConnectIntervalMS))
{
PrintArgError("%s: Invalid value specified for connect-to interval: %s\n", progName, arg);
return false;
}
break;
#if WEAVE_CONFIG_TIME
case kToolOpt_TimeSyncServer:
MockTimeNode.SetRole(kMockTimeSyncRole_Server);
break;
case kToolOpt_TimeSyncClient:
MockTimeNode.SetRole(kMockTimeSyncRole_Client);
break;
case kToolOpt_TimeSyncCoordinator:
MockTimeNode.SetRole(kMockTimeSyncRole_Coordinator);
break;
case kToolOpt_TimeSyncModeLocal:
MockTimeNode.SetMode(kOperatingMode_AssignedLocalNodes);
break;
case kToolOpt_TimeSyncModeService:
MockTimeNode.SetMode(kOperatingMode_Service);
break;
case kToolOpt_TimeSyncModeServiceOverTunnel:
MockTimeNode.SetMode(kOperatingMode_ServiceOverTunnel);
break;
case kToolOpt_TimeSyncModeAuto:
MockTimeNode.SetMode(kOperatingMode_Auto);
break;
case kToolOpt_TimeSyncSimpleClient:
ShouldEnableSimpleTimeSyncClient = true;
break;
case kToolOpt_TimeSyncServerNodeId:
if (!ParseNodeId(arg, TimeSyncServerNodeId))
{
PrintArgError("%s: Invalid value specified for TimeSyncServer node id: %s\n", progName, arg);
return false;
}
break;
case kToolOpt_TimeSyncServerNodeAddr:
TimeSyncServerNodeAddr = arg;
break;
case kToolOpt_TimeSyncServerSubnetId:
if (!ParseSubnetId(arg, TimeSyncServerSubnetId))
{
PrintArgError("%s: Invalid value specified for TimeSyncServer subnet id: %s\n", progName, arg);
return false;
}
break;
#endif // WEAVE_CONFIG_TIME
case kToolOpt_AlarmOriginator:
ShouldSendAlarmEvents = true;
break;
case kToolOpt_AlarmHush:
ShouldListenToAlarm = false;
if (!ParseNodeId(arg, AlarmHushPeerNodeId))
{
PrintArgError("%s: Invalid value specified for hush target node id: %s\n", progName, arg);
return false;
}
AlarmHushEnable = true;
break;
#if WEAVE_CONFIG_ENABLE_TUNNELING
case kToolOpt_TunnelBorderGw:
tunnelingDeviceRole = kClientRole_BorderGateway;
break;
case kToolOpt_TunnelMobDevice:
tunnelingDeviceRole = kClientRole_MobileDevice;
break;
case kToolOpt_TunnelConnectAddr:
TunnelConnectToAddr = arg;
break;
case kToolOpt_TunnelDestNodeId:
if (!ParseNodeId(arg, TunnelDestNodeId))
{
PrintArgError("%s: Invalid value specified for hush target node id: %s\n", progName, arg);
return false;
}
break;
#if WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
case kToolOpt_UseServiceDir:
UseServiceDirForTunnel = true;
break;
#endif // WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
#endif // WEAVE_CONFIG_ENABLE_TUNNELING
#if CONFIG_BLE_PLATFORM_BLUEZ
case kToolOpt_EnableWeaveBluezPeripheral:
EnableWeaveBluezPeripheral = true;
break;
case kToolOpt_WeaveBluezPeripheralName:
BleName = strdup(arg);
break;
case kToolOpt_WeaveBluezPeripheralAddress:
BleAddress = strdup(arg);
break;
#endif
case 'C':
UseCASE = true;
break;
case kToolOpt_SuppressAccessControl:
sSuppressAccessControls = true;
break;
#if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
case kToolOpt_WdmPublisherNodeId:
if (!ParseNodeId(arg, WdmPublisherNodeId))
{
PrintArgError("%s: Invalid value specified for WDM publisher node id: %s\n", progName, arg);
return false;
}
break;
case kToolOpt_WdmUseSubnetId:
if (!ParseSubnetId(arg, WdmUseSubnetId))
{
PrintArgError("%s: Invalid value specified for publisher subnet id: %s\n", progName, arg);
return false;
}
break;
#if WEAVE_CONFIG_TEST_WDM_SIMPLE_VIEW_CLIENT
case kToolOpt_WdmSimpleViewClient:
if (0 != WdmRoleInTest)
{
PrintArgError("%s: Mock device can only play one role in WDM tests (%s)\n", progName, arg);
return false;
}
WdmRoleInTest = kToolOpt_WdmSimpleViewClient;
break;
case kToolOpt_WdmSimpleViewServer:
if (0 != WdmRoleInTest)
{
PrintArgError("%s: Mock device can only play one role in WDM tests (%s)\n", progName, arg);
return false;
}
WdmRoleInTest = kToolOpt_WdmSimpleViewServer;
break;
#endif // WEAVE_CONFIG_TEST_WDM_SIMPLE_VIEW_CLIENT
case kToolOpt_WdmSubscriptionClient:
if (0 != WdmRoleInTest)
{
PrintArgError("%s: Mock device can only play one role in WDM tests (%s)\n", progName, arg);
return false;
}
WdmRoleInTest = kToolOpt_WdmSubscriptionClient;
break;
case kToolOpt_WdmSubscriptionPublisher:
if (0 != WdmRoleInTest)
{
PrintArgError("%s: Mock device can only play one role in WDM tests (%s)\n", progName, arg);
return false;
}
WdmRoleInTest = kToolOpt_WdmSubscriptionPublisher;
break;
case kToolOpt_WdmInitMutualSubscription:
if (0 != WdmRoleInTest)
{
PrintArgError("%s: Mock device can only play one role in WDM tests (%s)\n", progName, arg);
return false;
}
WdmRoleInTest = kToolOpt_WdmInitMutualSubscription;
break;
case kToolOpt_WdmRespMutualSubscription:
if (0 != WdmRoleInTest)
{
PrintArgError("%s: Mock device can only play one role in WDM tests (%s)\n", progName, arg);
return false;
}
WdmRoleInTest = kToolOpt_WdmRespMutualSubscription;
break;
case kToolOpt_WdmEnableRetry:
EnableRetry = true;
break;
#endif // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING
case kToolOpt_TestCaseId:
if (NULL != TestCaseId)
{
free(TestCaseId);
}
TestCaseId = strdup(arg);
break;
case kToolOpt_EnableStopTest:
EnableStopTest = true;
break;
case kToolOpt_NumDataChangeBeforeCancellation:
if (NULL != NumDataChangeBeforeCancellation)
{
free(NumDataChangeBeforeCancellation);
}
NumDataChangeBeforeCancellation = strdup(arg);
break;
case kToolOpt_FinalStatus:
if (NULL != FinalStatus)
{
free(FinalStatus);
}
FinalStatus = strdup(arg);
break;
case kToolOpt_TimeBetweenDataChangeMsec:
if (NULL != TimeBetweenDataChangeMsec)
{
free(TimeBetweenDataChangeMsec);
}
TimeBetweenDataChangeMsec = strdup(arg);
break;
case kToolOpt_EnableDataFlip:
if (!ParseBoolean(arg, EnableDataFlip))
{
PrintArgError("%s: Invalid value specified for enable data flip: %s\n", progName, arg);
return false;
}
break;
case kToolOpt_EnableDictionaryTest:
EnableDictionaryTest = true;
break;
case kToolOpt_TimeBetweenLivenessCheckSec:
if (NULL != TimeBetweenLivenessCheckSec)
{
free(TimeBetweenLivenessCheckSec);
}
TimeBetweenLivenessCheckSec = strdup(arg);
break;
case kToolOpt_EventGenerator:
if (strncmp(arg, "None", strlen("None")) == 0)
gEventGenerator = NULL;
else if (strncmp(arg, "Debug", strlen("Debug")) == 0)
gEventGenerator = GetTestDebugGenerator();
else if (strncmp(arg, "Liveness", strlen("Liveness")) == 0)
gEventGenerator = GetTestLivenessGenerator();
else if (strncmp(arg, "Security", strlen("Security")) == 0)
gEventGenerator = GetTestSecurityGenerator();
else if (strncmp(arg, "Telemetry", strlen("Telemetry")) == 0)
gEventGenerator = GetTestTelemetryGenerator();
else if (strncmp(arg, "TestTrait", strlen("TestTrait")) == 0)
gEventGenerator = GetTestTraitGenerator();
else
{
PrintArgError("%s: Unrecognized event generator name, exiting\n", progName);
return false;
}
break;
case kToolOpt_TimeBetweenEvents:
{
char *endptr;
TimeBetweenEvents = strtoul(arg, &endptr, 0);
if (endptr == arg)
{
PrintArgError("%s: Invalid inter-event timeout, exiting\n", progName);
return false;
}
break;
}
default:
PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", progName, name);
return false;
}
return true;
}
void HandleEchoRequestReceived(uint64_t nodeId, IPAddress nodeAddr, PacketBuffer *payload)
{
char ipAddrStr[64];
nodeAddr.ToString(ipAddrStr, sizeof(ipAddrStr));
printf("Echo Request from node %" PRIX64 " (%s): len=%u ... sending response.\n", nodeId, ipAddrStr,
payload->DataLength());
if (Debug)
DumpMemory(payload->Start(), payload->DataLength(), " ", 16);
}
void HandleHeartbeatReceived(const WeaveMessageInfo *aMsgInfo, uint8_t nodeState, WEAVE_ERROR err)
{
char ipAddrStr[64];
aMsgInfo->InPacketInfo->SrcAddress.ToString(ipAddrStr, sizeof(ipAddrStr));
printf("Heartbeat from node %" PRIX64 " (%s): state=%u, err=%s\n", aMsgInfo->SourceNodeId, ipAddrStr, nodeState, ErrorStr(err));
}
void HandleConnectionReceived(WeaveMessageLayer *msgLayer, WeaveConnection *con)
{
char ipAddrStr[64];
con->PeerAddr.ToString(ipAddrStr, sizeof(ipAddrStr));
printf("Connection received from node %" PRIX64 " (%s)\n", con->PeerNodeId, ipAddrStr);
con->OnConnectionClosed = HandleConnectionClosed;
}
void HandleSecureSessionEstablished(WeaveSecurityManager *sm, WeaveConnection *con, void *reqState, uint16_t sessionKeyId, uint64_t peerNodeId, uint8_t encType)
{
char ipAddrStr[64] = "";
if (con)
con->PeerAddr.ToString(ipAddrStr, sizeof(ipAddrStr));
printf("Secure session established with node %" PRIX64 " (%s)\n", peerNodeId, ipAddrStr);
}
void HandleSecureSessionError(WeaveSecurityManager *sm, WeaveConnection *con, void *reqState, WEAVE_ERROR localErr, uint64_t peerNodeId, StatusReport *statusReport)
{
char ipAddrStr[64] = "";
if (con)
{
con->PeerAddr.ToString(ipAddrStr, sizeof(ipAddrStr));
con->Close();
}
if (localErr == WEAVE_ERROR_STATUS_REPORT_RECEIVED && statusReport != NULL)
printf("FAILED to establish secure session with node %" PRIX64 " (%s): %s\n", peerNodeId, ipAddrStr, nl::StatusReportStr(statusReport->mProfileId, statusReport->mStatusCode));
else
printf("FAILED to establish secure session with node %" PRIX64 " (%s): %s\n", peerNodeId, ipAddrStr, ErrorStr(localErr));
}
void HandleConnectionClosed(WeaveConnection *con, WEAVE_ERROR conErr)
{
char ipAddrStr[64];
con->PeerAddr.ToString(ipAddrStr, sizeof(ipAddrStr));
if (conErr == WEAVE_NO_ERROR)
printf("Connection closed to node %" PRIX64 " (%s)\n", con->PeerNodeId, ipAddrStr);
else
printf("Connection ABORTED to node %" PRIX64 " (%s): %s\n", con->PeerNodeId, ipAddrStr, ErrorStr(conErr));
con->Close();
}
void InitiateConnection(System::Layer* aSystemLayer, void* aAppState, System::Error aError)
{
WEAVE_ERROR err;
WeaveConnection *con;
con = MessageLayer.NewConnection();
if (con == NULL)
FAIL_ERROR(WEAVE_ERROR_NO_MEMORY, "MessageLayer.NewConnection failed");
con->OnConnectionComplete = HandleConnectionComplete;
con->OnConnectionClosed = HandleConnectionClosed;
err = con->Connect(kNodeIdNotSpecified, kWeaveAuthMode_Unauthenticated, ConnectToAddr, strlen(ConnectToAddr), WEAVE_UNSECURED_PORT);
if (err != WEAVE_NO_ERROR)
HandleConnectionComplete(con, err);
}
void HandleConnectionComplete(WeaveConnection *con, WEAVE_ERROR err)
{
if (err == WEAVE_NO_ERROR)
{
char ipAddrStr[64];
con->PeerAddr.ToString(ipAddrStr, sizeof(ipAddrStr));
printf("Connection established to %s\n", ConnectToAddr);
ExchangeMgr.AllowUnsolicitedMessages(con);
}
else
{
printf("Failed to establish connection to %s: %s\n", ConnectToAddr, ErrorStr(err));
con->Close();
err = SystemLayer.StartTimer(ConnectIntervalMS, InitiateConnection, NULL);
FAIL_ERROR(err, "SystemLayer.StartTimer failed");
}
}
static void HandleWdmCompleteTest()
{
if (EnableStopTest)
{
Done = true;
}
}
#if WEAVE_CONFIG_ENABLE_TUNNELING & WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY
WEAVE_ERROR GetRootDirectoryEntry (uint8_t *buf, uint16_t bufSize)
{
return gServiceDirClientOptions.GetRootDirectoryEntry(buf, bufSize);
}
#endif // WEAVE_CONFIG_ENABLE_TUNNELING & WEAVE_CONFIG_ENABLE_SERVICE_DIRECTORY