blob: 125f90b90a1f9a6aeb00a26bb078463db2a7614a [file] [log] [blame]
/*
*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2013-2018 Nest Labs, Inc.
*
* 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 sets up fault injection for all POSIX CHIP Inet layer library test
* applications and tools.
*
* NOTE: These do not comprise a public part of the CHIP API and
* are subject to change without notice.
*
*/
#include "TestInetCommonOptions.h"
#include "TestSetupFaultInjection.h"
#include <inet/InetFaultInjection.h>
#include <lib/support/CHIPFaultInjection.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/ScopedBuffer.h>
#include <system/SystemFaultInjection.h>
#include <stdio.h>
#include <unistd.h>
struct RestartCallbackContext
{
int mArgc;
char ** mArgv;
};
static void RebootCallbackFn();
static void PostInjectionCallbackFn(nl::FaultInjection::Manager * aManager, nl::FaultInjection::Identifier aId,
nl::FaultInjection::Record * aFaultRecord);
static struct RestartCallbackContext sRestartCallbackCtx;
static nl::FaultInjection::Callback sFuzzECHeaderCb;
static nl::FaultInjection::Callback sAsyncEventCb;
// clang-format off
static nl::FaultInjection::GlobalContext sFaultInjectionGlobalContext = {
{
RebootCallbackFn,
PostInjectionCallbackFn
}
};
// clang-format on
bool gSigusr1Received = false;
static void RebootCallbackFn()
{
size_t i;
size_t j = 0;
chip::Platform::ScopedMemoryBuffer<char *> lArgv;
if (!lArgv.Alloc(static_cast<size_t>(sRestartCallbackCtx.mArgc + 2)))
{
printf("** failed to allocate memory **\n");
return;
}
if (gSigusr1Received)
{
printf("** skipping restart case after SIGUSR1 **\n");
return;
}
for (i = 0; sRestartCallbackCtx.mArgv[i] != nullptr; i++)
{
if (strcmp(sRestartCallbackCtx.mArgv[i], "--faults") == 0)
{
// Skip the --faults argument for now
i++;
continue;
}
lArgv[j++] = sRestartCallbackCtx.mArgv[i];
}
lArgv[j] = nullptr;
for (size_t idx = 0; lArgv[idx] != nullptr; idx++)
{
printf("argv[%d]: %s\n", static_cast<int>(idx), lArgv[idx]);
}
// Need to close any open file descriptor above stdin/out/err.
// There is no portable way to get the max fd number.
// Given that CHIP's test apps don't open a large number of files,
// FD_SETSIZE should be a reasonable upper bound (see the documentation
// of select).
for (int fd = 3; fd < FD_SETSIZE; fd++)
{
close(fd);
}
printf("********** Restarting *********\n");
fflush(stdout);
execvp(lArgv[0], lArgv.Get());
}
static void PostInjectionCallbackFn(nl::FaultInjection::Manager * aManager, nl::FaultInjection::Identifier aId,
nl::FaultInjection::Record * aFaultRecord)
{
uint16_t numargs = aFaultRecord->mNumArguments;
uint16_t i;
printf("***** Injecting fault %s_%s, instance number: %" PRIu32 "; reboot: %s", aManager->GetName(),
aManager->GetFaultNames()[aId], aFaultRecord->mNumTimesChecked, aFaultRecord->mReboot ? "yes" : "no");
if (numargs)
{
printf(" with %u args:", numargs);
for (i = 0; i < numargs; i++)
{
printf(" %" PRIi32, aFaultRecord->mArguments[i]);
}
}
printf("\n");
}
static bool PrintFaultInjectionMaxArgCbFn(nl::FaultInjection::Manager & mgr, nl::FaultInjection::Identifier aId,
nl::FaultInjection::Record * aFaultRecord, void * aContext)
{
const char * faultName = mgr.GetFaultNames()[aId];
if (gFaultInjectionOptions.PrintFaultCounters && aFaultRecord->mNumArguments)
{
printf("FI_instance_params: %s_%s_s%" PRIu32 " maxArg: %" PRIi32 ";\n", mgr.GetName(), faultName,
aFaultRecord->mNumTimesChecked, aFaultRecord->mArguments[0]);
}
return false;
}
static bool PrintCHIPFaultInjectionMaxArgCbFn(nl::FaultInjection::Identifier aId, nl::FaultInjection::Record * aFaultRecord,
void * aContext)
{
nl::FaultInjection::Manager & mgr = chip::FaultInjection::GetManager();
return PrintFaultInjectionMaxArgCbFn(mgr, aId, aFaultRecord, aContext);
}
static bool PrintSystemFaultInjectionMaxArgCbFn(nl::FaultInjection::Identifier aId, nl::FaultInjection::Record * aFaultRecord,
void * aContext)
{
nl::FaultInjection::Manager & mgr = chip::System::FaultInjection::GetManager();
return PrintFaultInjectionMaxArgCbFn(mgr, aId, aFaultRecord, aContext);
}
void SetupFaultInjectionContext(int argc, char * argv[])
{
SetupFaultInjectionContext(argc, argv, nullptr, nullptr);
}
void SetupFaultInjectionContext(int argc, char * argv[], int32_t (*aNumEventsAvailable)(),
void (*aInjectAsyncEvents)(int32_t index))
{
nl::FaultInjection::Manager & weavemgr = chip::FaultInjection::GetManager();
nl::FaultInjection::Manager & systemmgr = chip::System::FaultInjection::GetManager();
sRestartCallbackCtx.mArgc = argc;
sRestartCallbackCtx.mArgv = argv;
nl::FaultInjection::SetGlobalContext(&sFaultInjectionGlobalContext);
memset(&sFuzzECHeaderCb, 0, sizeof(sFuzzECHeaderCb));
sFuzzECHeaderCb.mCallBackFn = PrintCHIPFaultInjectionMaxArgCbFn;
weavemgr.InsertCallbackAtFault(chip::FaultInjection::kFault_FuzzExchangeHeaderTx, &sFuzzECHeaderCb);
if (aNumEventsAvailable && aInjectAsyncEvents)
{
memset(&sAsyncEventCb, 0, sizeof(sAsyncEventCb));
sAsyncEventCb.mCallBackFn = PrintSystemFaultInjectionMaxArgCbFn;
systemmgr.InsertCallbackAtFault(chip::System::FaultInjection::kFault_AsyncEvent, &sAsyncEventCb);
chip::System::FaultInjection::SetAsyncEventCallbacks(aNumEventsAvailable, aInjectAsyncEvents);
}
}