diff --git a/examples/platform/nrfconnect/util/test/TestInetCommon.cpp b/examples/platform/nrfconnect/util/test/TestInetCommon.cpp new file mode 100644 index 00000000000000..1670b6118f772e --- /dev/null +++ b/examples/platform/nrfconnect/util/test/TestInetCommon.cpp @@ -0,0 +1,229 @@ +/* + * + * 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 implements constants, globals and interfaces common to + * and used by all CHP 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. + * + */ + +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include "TestInetCommon.h" +#include "LogUtils.h" + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#if CHIP_SYSTEM_CONFIG_USE_SOCKETS +#include +#include +#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS + +using namespace chip; +using namespace chip::Inet; + +System::Layer gSystemLayer; + +Inet::InetLayer gInet; + +char gDefaultTapDeviceName[32]; +bool gDone = false; + +void InetFailError(int32_t err, const char * msg) +{ + if (err != INET_NO_ERROR) + { + LOG_ERR("%s: %s", msg, ErrorStr(err)); + exit(-1); + } +} + +void InitTestInetCommon() +{ + chip::Platform::MemoryInit(); +} + +void InitSystemLayer() +{ + gSystemLayer.Init(nullptr); +} + +void ShutdownSystemLayer() +{ + gSystemLayer.Shutdown(); +} + +void InitNetwork() +{ + void * lContext = nullptr; + + gInet.Init(gSystemLayer, lContext); +} + +void ServiceEvents(struct ::timeval & aSleepTime) +{ + static bool printed = false; + + if (!printed) + { + { + LOG_INF("CHIP node ready to service events"); + printed = true; + } + } +#if CHIP_SYSTEM_CONFIG_USE_SOCKETS + fd_set readFDs, writeFDs, exceptFDs; + int numFDs = 0; + + FD_ZERO(&readFDs); + FD_ZERO(&writeFDs); + FD_ZERO(&exceptFDs); + +#if CHIP_SYSTEM_CONFIG_USE_SOCKETS + if (gSystemLayer.State() == System::kLayerState_Initialized) + gSystemLayer.PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs, aSleepTime); +#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS + +#if CHIP_SYSTEM_CONFIG_USE_SOCKETS + if (gInet.State == InetLayer::kState_Initialized) + gInet.PrepareSelect(numFDs, &readFDs, &writeFDs, &exceptFDs, aSleepTime); +#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS + + int selectRes = select(numFDs, &readFDs, &writeFDs, &exceptFDs, &aSleepTime); + if (selectRes < 0) + { + LOG_INF("select failed: %s", ErrorStr(System::MapErrorPOSIX(errno))); + return; + } +#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS + + if (gSystemLayer.State() == System::kLayerState_Initialized) + { + +#if CHIP_SYSTEM_CONFIG_USE_SOCKETS + + gSystemLayer.HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs); + +#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS + } + + if (gInet.State == InetLayer::kState_Initialized) + { +#if CHIP_SYSTEM_CONFIG_USE_SOCKETS + + gInet.HandleSelectResult(selectRes, &readFDs, &writeFDs, &exceptFDs); + +#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS + } +} + +void ShutdownNetwork() +{ + gInet.Shutdown(); +} + +#define DUMP_BUF_LEN 80 + +void DumpMemory(const uint8_t * mem, uint32_t len, const char * prefix, uint32_t rowWidth) +{ + int indexWidth = snprintf(nullptr, 0, "%X", len); + + if (indexWidth < 4) + indexWidth = 4; + + for (uint32_t i = 0; i < len; i += rowWidth) + { + char buf[DUMP_BUF_LEN]; + char * ptr = buf; + const char * buf_end = buf + DUMP_BUF_LEN; + uint32_t rowEnd; + uint32_t j; + int result = snprintf(ptr, DUMP_BUF_LEN, "%s%0*X: ", prefix, indexWidth, i); + if (result < 0 || result >= DUMP_BUF_LEN) + goto print_line; + + ptr += result; + rowEnd = i + rowWidth; + + j = i; + for (; j < rowEnd && j < len; j++) + { + result = snprintf(ptr, buf_end - ptr, "%02X ", mem[j]); + if (result < 0 || result >= buf_end - ptr) + goto print_line; + ptr += result; + } + + for (; j < rowEnd; j++) + { + result = snprintf(ptr, buf_end - ptr, " "); + if (result < 0 || result >= buf_end - ptr) + goto print_line; + ptr += result; + } + + for (j = i; j < rowEnd && j < len; j++) + { + if (isprint(static_cast(mem[j]))) + result = snprintf(ptr, buf_end - ptr, "%c", mem[j]); + else + result = snprintf(ptr, buf_end - ptr, "."); + if (result < 0 || result >= buf_end - ptr) + goto print_line; + ptr += result; + } + + print_line: + if (result < 0 || result >= buf_end - ptr) + { + LOG_ERR("Dump buffer overflow"); + } + if (ptr > buf && ptr < buf + DUMP_BUF_LEN) + { + *ptr = '\0'; + LOG_INF(buf); + } + } +} + +void DumpMemory(const uint8_t * mem, uint32_t len, const char * prefix) +{ + const uint32_t kRowWidth = 16; + + DumpMemory(mem, len, prefix, kRowWidth); +} diff --git a/src/inet/tests/BUILD.gn b/src/inet/tests/BUILD.gn index c97ca890294c6e..7284161466ca35 100644 --- a/src/inet/tests/BUILD.gn +++ b/src/inet/tests/BUILD.gn @@ -29,12 +29,16 @@ static_library("helpers") { output_dir = "${root_out_dir}/lib" sources = [ - "TestInetCommon.cpp", "TestInetCommon.h", "TestInetCommonOptions.cpp", "TestInetCommonOptions.h", + "TestInetCommonPosix.cpp", "TestInetLayer.cpp", "TestInetLayerCommon.cpp", + "TestSetupFaultInjection.h", + "TestSetupFaultInjectionPosix.cpp", + "TestSetupSignalling.h", + "TestSetupSignallingPosix.cpp", ] if (lwip_platform == "standalone") { diff --git a/src/inet/tests/TestInetCommon.h b/src/inet/tests/TestInetCommon.h index 24340ab235a382..7bd68f07712d53 100644 --- a/src/inet/tests/TestInetCommon.h +++ b/src/inet/tests/TestInetCommon.h @@ -35,35 +35,20 @@ #endif #include -#include -#include -#include -#include -#include -#include #include #include -#include - #include #include -#include #include -#include "TestInetCommonOptions.h" - #define CHIP_TOOL_COPYRIGHT "Copyright (c) 2020 Project CHIP Authors\nAll rights reserved.\n" #define INET_FAIL_ERROR(ERR, MSG) \ do \ { \ - if ((ERR) != INET_NO_ERROR) \ - { \ - fprintf(stderr, "%s: %s\n", (MSG), ErrorStr(ERR)); \ - exit(-1); \ - } \ + InetFailError((ERR), (MSG)); \ } while (0) extern chip::System::Layer gSystemLayer; @@ -71,28 +56,19 @@ extern chip::System::Layer gSystemLayer; extern chip::Inet::InetLayer gInet; extern bool gDone; -extern bool gSigusr1Received; - -extern void InitTestInetCommon(); -extern void SetSIGUSR1Handler(); -extern void InitSystemLayer(); -extern void ShutdownSystemLayer(); -typedef void (*SignalHandler)(int signum); +void InitTestInetCommon(); +void InitSystemLayer(); +void ShutdownSystemLayer(); +void InetFailError(int32_t err, const char * msg); -extern void SetSignalHandler(SignalHandler handler); - -extern void InitNetwork(); -extern void ServiceEvents(struct ::timeval & aSleepTime); -extern void ShutdownNetwork(); -extern void DumpMemory(const uint8_t * mem, uint32_t len, const char * prefix, uint32_t rowWidth); -extern void DumpMemory(const uint8_t * mem, uint32_t len, const char * prefix); +void InitNetwork(); +void ServiceEvents(struct ::timeval & aSleepTime); +void ShutdownNetwork(); +void DumpMemory(const uint8_t * mem, uint32_t len, const char * prefix, uint32_t rowWidth); +void DumpMemory(const uint8_t * mem, uint32_t len, const char * prefix); inline static void ServiceNetwork(struct ::timeval & aSleepTime) { ServiceEvents(aSleepTime); } - -extern void SetupFaultInjectionContext(int argc, char * argv[]); -extern void SetupFaultInjectionContext(int argc, char * argv[], int32_t (*aNumEventsAvailable)(), - void (*aInjectAsyncEvents)(int32_t index)); diff --git a/src/inet/tests/TestInetCommon.cpp b/src/inet/tests/TestInetCommonPosix.cpp similarity index 76% rename from src/inet/tests/TestInetCommon.cpp rename to src/inet/tests/TestInetCommonPosix.cpp index 14cd9793c50d0b..6dcacb4dcbe6bb 100644 --- a/src/inet/tests/TestInetCommon.cpp +++ b/src/inet/tests/TestInetCommonPosix.cpp @@ -35,7 +35,9 @@ #endif #include "TestInetCommon.h" +#include "TestInetCommonOptions.h" +#include #include #include @@ -45,11 +47,9 @@ #include #include -#include -#include #include +#include #include -#include #include #if CHIP_SYSTEM_CONFIG_USE_LWIP @@ -102,29 +102,6 @@ static void ReleaseLwIP(void) } #endif // CHIP_SYSTEM_CONFIG_USE_LWIP -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 - System::Layer gSystemLayer; Inet::InetLayer gInet; @@ -148,8 +125,16 @@ static void OnLwIPInitComplete(void * arg); #endif // CHIP_SYSTEM_CONFIG_USE_LWIP char gDefaultTapDeviceName[32]; -bool gDone = false; -bool gSigusr1Received = false; +bool gDone = false; + +void InetFailError(int32_t err, const char * msg) +{ + if (err != INET_NO_ERROR) + { + fprintf(stderr, "%s: %s\n", msg, ErrorStr(err)); + exit(-1); + } +} static void UseStdoutLineBuffering() { @@ -169,37 +154,6 @@ void InitTestInetCommon() UseStdoutLineBuffering(); } -static void ExitOnSIGUSR1Handler(int signum) -{ - // exit() allows us a slightly better clean up (gcov data) than SIGINT's exit - exit(0); -} - -// We set a hook to exit when we receive SIGUSR1, SIGTERM or SIGHUP -void SetSIGUSR1Handler() -{ - SetSignalHandler(ExitOnSIGUSR1Handler); -} - -void SetSignalHandler(SignalHandler handler) -{ - struct sigaction sa; - int signals[] = { SIGUSR1 }; - size_t i; - - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = handler; - - for (i = 0; i < sizeof(signals) / sizeof(signals[0]); i++) - { - if (sigaction(signals[i], &sa, nullptr) == -1) - { - perror("Can't catch signal"); - exit(1); - } - } -} - void InitSystemLayer() { #if CHIP_SYSTEM_CONFIG_USE_LWIP @@ -666,137 +620,3 @@ void DumpMemory(const uint8_t * mem, uint32_t len, const char * prefix) DumpMemory(mem, len, prefix, kRowWidth); } - -static void RebootCallbackFn() -{ - size_t i; - size_t j = 0; - chip::Platform::ScopedMemoryBuffer lArgv; - if (!lArgv.Alloc(static_cast(sRestartCallbackCtx.mArgc + 2))) - { - printf("** failed to allocate memory **\n"); - ExitNow(); - } - - if (gSigusr1Received) - { - printf("** skipping restart case after SIGUSR1 **\n"); - ExitNow(); - } - - 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(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()); - -exit: - return; -} - -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: %u; 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(" %d", 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%u maxArg: %u;\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); - } -} diff --git a/src/inet/tests/TestInetEndPoint.cpp b/src/inet/tests/TestInetEndPoint.cpp index 681b5d1b094153..8d10b04a9e420f 100644 --- a/src/inet/tests/TestInetEndPoint.cpp +++ b/src/inet/tests/TestInetEndPoint.cpp @@ -48,6 +48,7 @@ #include #include "TestInetCommon.h" +#include "TestSetupSignalling.h" using namespace chip; using namespace chip::Inet; diff --git a/src/inet/tests/TestInetLayer.cpp b/src/inet/tests/TestInetLayer.cpp index a75de76626686d..022b8ffc86fd86 100644 --- a/src/inet/tests/TestInetLayer.cpp +++ b/src/inet/tests/TestInetLayer.cpp @@ -37,12 +37,16 @@ #include +#include #include #include #include "TestInetCommon.h" +#include "TestInetCommonOptions.h" #include "TestInetLayerCommon.hpp" +#include "TestSetupFaultInjection.h" +#include "TestSetupSignalling.h" using namespace chip; using namespace chip::Inet; diff --git a/src/inet/tests/TestInetLayerCommon.cpp b/src/inet/tests/TestInetLayerCommon.cpp index 455acab9bc97d5..7ac9a5fec08585 100644 --- a/src/inet/tests/TestInetLayerCommon.cpp +++ b/src/inet/tests/TestInetLayerCommon.cpp @@ -29,6 +29,7 @@ #include #include +#include #include diff --git a/src/inet/tests/TestInetLayerDNS.cpp b/src/inet/tests/TestInetLayerDNS.cpp index 0c00af648f048b..d2fd741315eefe 100644 --- a/src/inet/tests/TestInetLayerDNS.cpp +++ b/src/inet/tests/TestInetLayerDNS.cpp @@ -44,6 +44,7 @@ #include #include "TestInetCommon.h" +#include "TestSetupSignalling.h" using namespace chip; using namespace chip::Inet; diff --git a/src/inet/tests/TestInetLayerMulticast.cpp b/src/inet/tests/TestInetLayerMulticast.cpp index 4b3602305a4f43..277ff0d737e90a 100644 --- a/src/inet/tests/TestInetLayerMulticast.cpp +++ b/src/inet/tests/TestInetLayerMulticast.cpp @@ -40,10 +40,15 @@ #include #include +#include +#include #include #include "TestInetCommon.h" +#include "TestInetCommonOptions.h" #include "TestInetLayerCommon.hpp" +#include "TestSetupFaultInjection.h" +#include "TestSetupSignalling.h" using namespace chip; using namespace chip::ArgParser; diff --git a/src/inet/tests/TestLwIPDNS.cpp b/src/inet/tests/TestLwIPDNS.cpp index d1bd1272dd1887..a8e8580d89b33a 100644 --- a/src/inet/tests/TestLwIPDNS.cpp +++ b/src/inet/tests/TestLwIPDNS.cpp @@ -38,9 +38,13 @@ #include +#include #include #include "TestInetCommon.h" +#include "TestInetCommonOptions.h" +#include "TestSetupFaultInjection.h" +#include "TestSetupSignalling.h" using namespace chip; using namespace chip::Inet; diff --git a/src/inet/tests/TestSetupFaultInjection.h b/src/inet/tests/TestSetupFaultInjection.h new file mode 100644 index 00000000000000..ba8d46fe485b6e --- /dev/null +++ b/src/inet/tests/TestSetupFaultInjection.h @@ -0,0 +1,39 @@ +/* + * + * 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 + * This file sets up fault injection for all 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. + * + */ + +#pragma once + +#include +#include + +extern bool gSigusr1Received; + +void SetupFaultInjectionContext(int argc, char * argv[]); +void SetupFaultInjectionContext(int argc, char * argv[], int32_t (*aNumEventsAvailable)(), + void (*aInjectAsyncEvents)(int32_t index)); diff --git a/src/inet/tests/TestSetupFaultInjectionPosix.cpp b/src/inet/tests/TestSetupFaultInjectionPosix.cpp new file mode 100644 index 00000000000000..6a525bd4b38ced --- /dev/null +++ b/src/inet/tests/TestSetupFaultInjectionPosix.cpp @@ -0,0 +1,195 @@ +/* + * + * 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 +#include +#include +#include +#include +#include + +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 lArgv; + if (!lArgv.Alloc(static_cast(sRestartCallbackCtx.mArgc + 2))) + { + printf("** failed to allocate memory **\n"); + ExitNow(); + } + + if (gSigusr1Received) + { + printf("** skipping restart case after SIGUSR1 **\n"); + ExitNow(); + } + + 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(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()); + +exit: + return; +} + +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: %u; 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(" %d", 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%u maxArg: %u;\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); + } +} diff --git a/src/inet/tests/TestSetupSignalling.h b/src/inet/tests/TestSetupSignalling.h new file mode 100644 index 00000000000000..8b8a736863664b --- /dev/null +++ b/src/inet/tests/TestSetupSignalling.h @@ -0,0 +1,34 @@ +/* + * + * 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 + * This file sets up signalling used in Linux 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. + * + */ + +#pragma once + +void SetSIGUSR1Handler(); +typedef void (*SignalHandler)(int signum); +void SetSignalHandler(SignalHandler handler); diff --git a/src/inet/tests/TestSetupSignallingPosix.cpp b/src/inet/tests/TestSetupSignallingPosix.cpp new file mode 100644 index 00000000000000..94e9e3ce39c242 --- /dev/null +++ b/src/inet/tests/TestSetupSignallingPosix.cpp @@ -0,0 +1,65 @@ +/* + * + * 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 signalling 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 "TestSetupSignalling.h" + +#include +#include +#include +#include + +static void ExitOnSIGUSR1Handler(int signum) +{ + // exit() allows us a slightly better clean up (gcov data) than SIGINT's exit + exit(0); +} + +// We set a hook to exit when we receive SIGUSR1, SIGTERM or SIGHUP +void SetSIGUSR1Handler() +{ + SetSignalHandler(ExitOnSIGUSR1Handler); +} + +void SetSignalHandler(SignalHandler handler) +{ + struct sigaction sa; + int signals[] = { SIGUSR1 }; + size_t i; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = handler; + + for (i = 0; i < sizeof(signals) / sizeof(signals[0]); i++) + { + if (sigaction(signals[i], &sa, nullptr) == -1) + { + perror("Can't catch signal"); + exit(1); + } + } +}