112 lines
3.5 KiB
C++
112 lines
3.5 KiB
C++
// Copyright 2023 The Pigweed Authors
|
|
//
|
|
// 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
|
|
//
|
|
// https://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.
|
|
|
|
// clang-format off
|
|
#include "pw_rpc/internal/log_config.h" // PW_LOG_* macros must be first.
|
|
// clang-format on
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <cstring>
|
|
|
|
#include "pw_log/log.h"
|
|
#include "pw_rpc/fuzz/argparse.h"
|
|
#include "pw_rpc/fuzz/engine.h"
|
|
#include "pw_rpc/integration_testing.h"
|
|
|
|
namespace pw::rpc::fuzz {
|
|
namespace {
|
|
|
|
// This client configures a socket read timeout to allow the RPC dispatch thread
|
|
// to exit gracefully.
|
|
constexpr timeval kSocketReadTimeout = {.tv_sec = 1, .tv_usec = 0};
|
|
|
|
int FuzzClient(int argc, char** argv) {
|
|
// TODO(aarongreen): Incorporate descriptions into usage message.
|
|
Vector<ArgParserVariant, 5> parsers{
|
|
// Enables additional logging.
|
|
BoolParser("-v", "--verbose").set_default(false),
|
|
|
|
// The number of actions to perform as part of the test. A value of 0 runs
|
|
// indefinitely.
|
|
UnsignedParser<size_t>("-n", "--num-actions").set_default(256),
|
|
|
|
// The seed value for the PRNG. A value of 0 generates a seed.
|
|
UnsignedParser<uint64_t>("-s", "--seed").set_default(0),
|
|
|
|
// The time, in milliseconds, that can elapse without triggering an error.
|
|
UnsignedParser<size_t>("-t", "--timeout").set_default(5000),
|
|
|
|
// The port use to connect to the `test_rpc_server`.
|
|
UnsignedParser<uint16_t>("port").set_default(48000)};
|
|
|
|
if (!ParseArgs(parsers, argc, argv).ok()) {
|
|
PrintUsage(parsers, argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
bool verbose;
|
|
size_t num_actions;
|
|
uint64_t seed;
|
|
size_t timeout_ms;
|
|
uint16_t port;
|
|
if (!GetArg(parsers, "--verbose", &verbose).ok() ||
|
|
!GetArg(parsers, "--num-actions", &num_actions).ok() ||
|
|
!GetArg(parsers, "--seed", &seed).ok() ||
|
|
!GetArg(parsers, "--timeout", &timeout_ms).ok() ||
|
|
!GetArg(parsers, "port", &port).ok()) {
|
|
return 1;
|
|
}
|
|
|
|
if (!seed) {
|
|
seed = chrono::SystemClock::now().time_since_epoch().count();
|
|
}
|
|
|
|
if (auto status = integration_test::InitializeClient(port); !status.ok()) {
|
|
PW_LOG_ERROR("Failed to initialize client: %s", pw_StatusString(status));
|
|
return 1;
|
|
}
|
|
|
|
// Set read timout on socket to allow
|
|
// pw::rpc::integration_test::TerminateClient() to complete.
|
|
int fd = integration_test::GetClientSocketFd();
|
|
if (setsockopt(fd,
|
|
SOL_SOCKET,
|
|
SO_RCVTIMEO,
|
|
&kSocketReadTimeout,
|
|
sizeof(kSocketReadTimeout)) != 0) {
|
|
PW_LOG_ERROR("Failed to configure socket receive timeout with errno=%d",
|
|
errno);
|
|
return 1;
|
|
}
|
|
|
|
if (num_actions == 0) {
|
|
num_actions = std::numeric_limits<size_t>::max();
|
|
}
|
|
|
|
Fuzzer fuzzer(integration_test::client(), integration_test::kChannelId);
|
|
fuzzer.set_verbose(verbose);
|
|
fuzzer.set_timeout(std::chrono::milliseconds(timeout_ms));
|
|
fuzzer.Run(seed, num_actions);
|
|
integration_test::TerminateClient();
|
|
return 0;
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace pw::rpc::fuzz
|
|
|
|
int main(int argc, char** argv) {
|
|
return pw::rpc::fuzz::FuzzClient(argc, argv);
|
|
}
|