mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2025-07-13 19:31:49 +02:00
Merge pull request #1167 from slsdetectorgroup/dev/multirxr_proper_cleanup_on_ctrlc
Dev/multirxr proper cleanup on ctrl + c and versioning
This commit is contained in:
@ -152,12 +152,12 @@ int main(int argc, char *argv[]) {
|
||||
strcpy(version, APIXILINXCTB);
|
||||
#endif
|
||||
LOG(logINFO, ("SLS Detector Server Version: %s\n", version));
|
||||
exit(EXIT_SUCCESS);
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
case 'p':
|
||||
if (sscanf(optarg, "%d", &portno) != 1) {
|
||||
LOG(logERROR, ("Cannot scan port argument\n%s", helpMessage));
|
||||
exit(EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
LOG(logINFO, ("Detected port: %d\n", portno));
|
||||
break;
|
||||
@ -188,7 +188,7 @@ int main(int argc, char *argv[]) {
|
||||
ignoreConfigFileFlag = 1;
|
||||
#else
|
||||
LOG(logERROR, ("No server config files for this detector\n"));
|
||||
exit(EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
#endif
|
||||
break;
|
||||
|
||||
@ -196,11 +196,11 @@ int main(int argc, char *argv[]) {
|
||||
#if !defined(VIRTUAL) && !defined(EIGERD)
|
||||
LOG(logERROR, ("Cannot set master via the detector server for this "
|
||||
"detector\n"));
|
||||
exit(EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
#elif defined(GOTTHARD2D) || defined(EIGERD) || defined(MYTHEN3D)
|
||||
if (sscanf(optarg, "%d", &masterCommandLine) != 1) {
|
||||
LOG(logERROR, ("Cannot scan master argument\n%s", helpMessage));
|
||||
exit(EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (masterCommandLine == 1) {
|
||||
LOG(logINFO, ("Detector Master mode\n"));
|
||||
@ -209,7 +209,7 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
#else
|
||||
LOG(logERROR, ("No master implemented for this detector server\n"));
|
||||
exit(EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
#endif
|
||||
break;
|
||||
|
||||
@ -217,7 +217,7 @@ int main(int argc, char *argv[]) {
|
||||
#ifdef EIGERD
|
||||
if (sscanf(optarg, "%d", &topCommandLine) != 1) {
|
||||
LOG(logERROR, ("Cannot scan top argument\n%s", helpMessage));
|
||||
exit(EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (topCommandLine == 1) {
|
||||
LOG(logINFO, ("Detector Top mode\n"));
|
||||
@ -226,16 +226,16 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
#else
|
||||
LOG(logERROR, ("No top implemented for this detector server\n"));
|
||||
exit(EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
printf("%s", helpMessage);
|
||||
exit(EXIT_SUCCESS);
|
||||
return EXIT_SUCCESS;
|
||||
default:
|
||||
printf("\n%s", helpMessage);
|
||||
exit(EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -376,5 +376,5 @@ int main(int argc, char *argv[]) {
|
||||
#endif
|
||||
}
|
||||
LOG(logINFO, ("Goodbye!\n"));
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ int main(int argc, char *argv[]) {
|
||||
c.call(parser.command(), parser.arguments(), parser.detector_id(),
|
||||
action, std::cout, parser.receiver_id());
|
||||
} catch (sls::RuntimeError &e) {
|
||||
exit(EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
exit(EXIT_SUCCESS);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -13,6 +13,7 @@ set(SOURCES
|
||||
src/Arping.cpp
|
||||
src/MasterAttributes.cpp
|
||||
src/MasterFileUtility.cpp
|
||||
src/CommandLineOptions.cpp
|
||||
)
|
||||
|
||||
set(PUBLICHEADERS
|
||||
@ -51,6 +52,10 @@ target_link_libraries(slsReceiverObject
|
||||
slsProjectWarnings #don't propagate warnigns
|
||||
)
|
||||
|
||||
target_compile_definitions(slsReceiverObject
|
||||
PRIVATE $<$<BOOL:${SLS_USE_TESTS}>:SLS_USE_TESTS>
|
||||
)
|
||||
|
||||
# HDF5
|
||||
if (SLS_USE_HDF5)
|
||||
if (HDF5_FOUND)
|
||||
@ -86,6 +91,7 @@ set_target_properties(slsReceiverStatic PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
|
||||
PUBLIC_HEADER "${PUBLICHEADERS}"
|
||||
)
|
||||
|
||||
list(APPEND RECEIVER_LIBRARY_TARGETS slsReceiverStatic)
|
||||
|
||||
|
||||
|
@ -13,22 +13,12 @@ class Receiver : private virtual slsDetectorDefs {
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
* Starts up a Receiver server. Reads configuration file, options, and
|
||||
* assembles a Receiver using TCP and UDP detector interfaces
|
||||
* Starts up a Receiver server.
|
||||
* Assembles a Receiver using TCP and UDP detector interfaces
|
||||
* throws an exception in case of failure
|
||||
* @param argc from command line
|
||||
* @param argv from command line
|
||||
* @param port TCP/IP port number
|
||||
*/
|
||||
Receiver(int argc, char *argv[]);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* Starts up a Receiver server. Reads configuration file, options, and
|
||||
* assembles a Receiver using TCP and UDP detector interfaces
|
||||
* throws an exception in case of failure
|
||||
* @param tcpip_port_no TCP/IP port number
|
||||
*/
|
||||
Receiver(uint16_t tcpip_port_no = 1954);
|
||||
Receiver(uint16_t port = 1954);
|
||||
|
||||
~Receiver();
|
||||
|
||||
|
347
slsReceiverSoftware/src/CommandLineOptions.cpp
Normal file
347
slsReceiverSoftware/src/CommandLineOptions.cpp
Normal file
@ -0,0 +1,347 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
|
||||
#include "CommandLineOptions.h"
|
||||
#include "sls/ToString.h"
|
||||
#include "sls/logger.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#include "sls/versionAPI.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
|
||||
CommandLineOptions::CommandLineOptions(AppType app)
|
||||
: appType_(app), optString_(buildOptString()),
|
||||
longOptions_(buildOptionList()) {}
|
||||
|
||||
/** for testing */
|
||||
ParsedOptions CommandLineOptions::parse(const std::vector<std::string> &args) {
|
||||
std::vector<char *> argv;
|
||||
argv.reserve(args.size());
|
||||
for (const auto &arg : args) {
|
||||
argv.push_back(const_cast<char *>(arg.c_str()));
|
||||
}
|
||||
int argc = static_cast<int>(argv.size());
|
||||
return parse(argc, argv.data());
|
||||
}
|
||||
|
||||
ParsedOptions CommandLineOptions::parse(int argc, char *argv[]) {
|
||||
CommonOptions base;
|
||||
MultiReceiverOptions multi;
|
||||
FrameSyncOptions frame;
|
||||
base.port = DEFAULT_TCP_RX_PORTNO;
|
||||
|
||||
optind = 0; // reset getopt
|
||||
int opt, option_index = 0;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, optString_.c_str(),
|
||||
longOptions_.data(), &option_index)) != -1) {
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
case 'h':
|
||||
handleCommonOption(opt, optarg, base);
|
||||
return base; // exit after version/help
|
||||
case 'p':
|
||||
case 'u':
|
||||
handleCommonOption(opt, optarg, base);
|
||||
break;
|
||||
case 'c':
|
||||
case 'n':
|
||||
case 't':
|
||||
handleAppSpecificOption(opt, optarg, base, multi, frame);
|
||||
break;
|
||||
default:
|
||||
throw sls::RuntimeError("Invalid arguments." + getHelpMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// remaining arguments
|
||||
if (optind < argc) {
|
||||
|
||||
// deprecated and current options => invalid
|
||||
if (base.port != DEFAULT_TCP_RX_PORTNO || multi.numReceivers != 1 ||
|
||||
frame.numReceivers != 1 || multi.callbackEnabled != false ||
|
||||
frame.printHeaders != false) {
|
||||
LOG(sls::logWARNING) << "Cannot use both deprecated options and "
|
||||
"the valid options simultaneously. Please "
|
||||
"move away from the deprecated options.\n";
|
||||
}
|
||||
|
||||
// unsupported deprecated arguments
|
||||
if (appType_ == AppType::SingleReceiver) {
|
||||
throw sls::RuntimeError("Invalid arguments." + getHelpMessage());
|
||||
}
|
||||
|
||||
// parse deprecated arguments
|
||||
std::vector<std::string> args(argv, argv + argc);
|
||||
auto [p, n, o] = ParseDeprecated(args);
|
||||
// set options
|
||||
base.port = p;
|
||||
if (appType_ == AppType::MultiReceiver) {
|
||||
multi.numReceivers = n;
|
||||
multi.callbackEnabled = o;
|
||||
} else if (appType_ == AppType::FrameSynchronizer) {
|
||||
frame.numReceivers = n;
|
||||
frame.printHeaders = o;
|
||||
}
|
||||
}
|
||||
|
||||
// Logging
|
||||
LOG(sls::logINFO) << "TCP Port: " << base.port;
|
||||
if (appType_ == AppType::MultiReceiver) {
|
||||
LOG(sls::logINFO) << "Number of receivers: " << multi.numReceivers;
|
||||
LOG(sls::logINFO) << "Callback enabled: " << multi.callbackEnabled;
|
||||
} else if (appType_ == AppType::FrameSynchronizer) {
|
||||
LOG(sls::logINFO) << "Number of receivers: " << frame.numReceivers;
|
||||
LOG(sls::logINFO) << "Print headers: " << frame.printHeaders;
|
||||
}
|
||||
|
||||
switch (appType_) {
|
||||
case AppType::SingleReceiver:
|
||||
return base;
|
||||
case AppType::MultiReceiver:
|
||||
static_cast<CommonOptions &>(multi) = base;
|
||||
return multi;
|
||||
case AppType::FrameSynchronizer:
|
||||
static_cast<CommonOptions &>(frame) = base;
|
||||
return frame;
|
||||
default:
|
||||
throw sls::RuntimeError("Unknown AppType in CommandLineOptions::parse");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<option> CommandLineOptions::buildOptionList() const {
|
||||
std::vector<option> opts = {
|
||||
{"version", no_argument, nullptr, 'v'},
|
||||
{"help", no_argument, nullptr, 'h'},
|
||||
{"port", required_argument, nullptr, 'p'},
|
||||
{"uid", required_argument, nullptr, 'u'},
|
||||
};
|
||||
switch (appType_) {
|
||||
case AppType::SingleReceiver:
|
||||
opts.push_back({"rx_tcpport", required_argument, nullptr, 't'});
|
||||
break;
|
||||
case AppType::MultiReceiver:
|
||||
opts.push_back({"num-receivers", required_argument, nullptr, 'n'});
|
||||
opts.push_back({"callback", no_argument, nullptr, 'c'});
|
||||
break;
|
||||
case AppType::FrameSynchronizer:
|
||||
opts.push_back({"num-receivers", required_argument, nullptr, 'n'});
|
||||
opts.push_back({"print-headers", no_argument, nullptr, 'c'});
|
||||
break;
|
||||
}
|
||||
opts.push_back({nullptr, 0, nullptr, 0}); // null-terminator for getopt
|
||||
return opts;
|
||||
}
|
||||
|
||||
std::string CommandLineOptions::buildOptString() const {
|
||||
std::string optstr = "vhp:u:";
|
||||
if (appType_ == AppType::MultiReceiver ||
|
||||
appType_ == AppType::FrameSynchronizer)
|
||||
optstr += "cn:";
|
||||
if (appType_ == AppType::SingleReceiver)
|
||||
optstr += "t:";
|
||||
return optstr;
|
||||
}
|
||||
|
||||
uint16_t CommandLineOptions::parsePort(const char *optarg) {
|
||||
uint16_t val = 0;
|
||||
try {
|
||||
val = sls::StringTo<uint16_t>(optarg);
|
||||
} catch (...) {
|
||||
throw sls::RuntimeError("Could not parse port number " +
|
||||
std::string(optarg));
|
||||
}
|
||||
if (val < 1024) {
|
||||
throw sls::RuntimeError(
|
||||
"Invalid/ privileged port number parsed. Min: 1024.");
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
uint16_t CommandLineOptions::parseNumReceivers(const char *optarg) {
|
||||
uint16_t val = 0;
|
||||
try {
|
||||
val = sls::StringTo<uint16_t>(optarg);
|
||||
} catch (...) {
|
||||
throw sls::RuntimeError("Could not parse number of receivers " +
|
||||
std::string(optarg));
|
||||
}
|
||||
if (val == 0 || val > MAX_RECEIVERS) {
|
||||
throw sls::RuntimeError(
|
||||
"Invalid number of receivers parsed. Options: 1 - " +
|
||||
std::to_string(MAX_RECEIVERS));
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
uid_t CommandLineOptions::parseUID(const char *optarg) {
|
||||
uid_t val = -1;
|
||||
try {
|
||||
val = sls::StringTo<uid_t>(optarg);
|
||||
} catch (...) {
|
||||
throw sls::RuntimeError("Could not parse UID " + std::string(optarg));
|
||||
}
|
||||
if (val == static_cast<uid_t>(-1)) {
|
||||
throw sls::RuntimeError(
|
||||
"Could not parse UID. Expected a valid user ID." +
|
||||
std::string(optarg));
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
void CommandLineOptions::handleCommonOption(int opt, const char *optarg,
|
||||
CommonOptions &base) {
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
base.versionRequested = true;
|
||||
std::cout << getVersion() << std::endl;
|
||||
break;
|
||||
case 'h':
|
||||
base.helpRequested = true;
|
||||
std::cout << getHelpMessage() << std::endl;
|
||||
break;
|
||||
case 'p':
|
||||
base.port = parsePort(optarg);
|
||||
break;
|
||||
case 'u':
|
||||
base.userid = parseUID(optarg);
|
||||
setEffectiveUID(base.userid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CommandLineOptions::handleAppSpecificOption(int opt, const char *optarg,
|
||||
CommonOptions &base,
|
||||
MultiReceiverOptions &multi,
|
||||
FrameSyncOptions &frame) {
|
||||
switch (opt) {
|
||||
|
||||
case 'c':
|
||||
if (appType_ == AppType::MultiReceiver)
|
||||
multi.callbackEnabled = true;
|
||||
else if (appType_ == AppType::FrameSynchronizer)
|
||||
frame.printHeaders = true;
|
||||
break;
|
||||
|
||||
case 'n': {
|
||||
auto val = parseNumReceivers(optarg);
|
||||
if (appType_ == AppType::MultiReceiver)
|
||||
multi.numReceivers = val;
|
||||
else if (appType_ == AppType::FrameSynchronizer)
|
||||
frame.numReceivers = val;
|
||||
break;
|
||||
}
|
||||
|
||||
case 't':
|
||||
LOG(sls::logWARNING) << "Deprecated option '-t' and '--rx_tcport'. Use "
|
||||
"'p' or '--port' instead.";
|
||||
base.port = parsePort(optarg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* maintain backward compatibility of [start port] [num receivers] [optional
|
||||
* arg] */
|
||||
std::tuple<uint16_t, uint16_t, bool>
|
||||
CommandLineOptions::ParseDeprecated(const std::vector<std::string> &args) {
|
||||
|
||||
size_t nargs = args.size();
|
||||
if (nargs != 1 && nargs != 3 && nargs != 4) {
|
||||
throw sls::RuntimeError("Invalid number of arguments.");
|
||||
}
|
||||
|
||||
LOG(sls::logWARNING)
|
||||
<< "Deprecated options will be removed in future versions. "
|
||||
"Please use the new options.\n";
|
||||
|
||||
// default deprecated values
|
||||
if (nargs == 1) {
|
||||
return std::make_tuple(DEFAULT_TCP_RX_PORTNO, 1, false);
|
||||
}
|
||||
|
||||
// parse deprecated arguments
|
||||
uint16_t p = parsePort(args[1].c_str());
|
||||
uint16_t n = parseNumReceivers(args[2].c_str());
|
||||
bool o = false;
|
||||
if (nargs == 4) {
|
||||
try {
|
||||
o = sls::StringTo<bool>(args[3].c_str());
|
||||
} catch (...) {
|
||||
throw sls::RuntimeError("Invalid optional argument "
|
||||
"parsed. Expected 1 (true) or "
|
||||
"0 (false).");
|
||||
}
|
||||
}
|
||||
return std::make_tuple(p, n, o);
|
||||
}
|
||||
|
||||
std::string CommandLineOptions::getTypeString() const {
|
||||
switch (appType_) {
|
||||
case AppType::SingleReceiver:
|
||||
return "slsReceiver";
|
||||
case AppType::MultiReceiver:
|
||||
return "slsMultiReceiver";
|
||||
case AppType::FrameSynchronizer:
|
||||
return "slsFrameSynchronizer";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::string CommandLineOptions::getVersion() const {
|
||||
return getTypeString() + " Version: " + APIRECEIVER;
|
||||
}
|
||||
|
||||
std::string CommandLineOptions::getHelpMessage() const {
|
||||
switch (appType_) {
|
||||
case AppType::SingleReceiver:
|
||||
return std::string("\nUsage: ") + getTypeString() + " Options:\n" +
|
||||
"\t-v, --version : Version.\n" +
|
||||
"\t-p, --port : TCP port to communicate with client "
|
||||
"for "
|
||||
"configuration. Non-zero and 16 bit.\n" +
|
||||
"\t-u, --uid : Set effective user id if receiver "
|
||||
"started "
|
||||
"with privileges. \n\n";
|
||||
|
||||
case AppType::MultiReceiver:
|
||||
return std::string("\nUsage: " + getTypeString() + " Options:\n") +
|
||||
"\t-v, --version : Version.\n" +
|
||||
"\t-n, --num-receivers : Number of receivers.\n" +
|
||||
"\t-p, --port : TCP port to communicate with client "
|
||||
"for "
|
||||
"configuration. Non-zero and 16 bit.\n" +
|
||||
"\t-c, --callback : Enable dummy callbacks for debugging. "
|
||||
"Disabled by default. \n" +
|
||||
"\t-u, --uid : Set effective user id if receiver "
|
||||
"started "
|
||||
"with privileges. \n\n";
|
||||
|
||||
case AppType::FrameSynchronizer:
|
||||
return std::string("\nUsage: " + getTypeString() + " Options:\n") +
|
||||
"\t-v, --version : Version.\n" +
|
||||
"\t-n, --num-receivers : Number of receivers.\n" +
|
||||
"\t-p, --port : TCP port to communicate with client "
|
||||
"for "
|
||||
"configuration. Non-zero and 16 bit.\n" +
|
||||
"\t-c, --print-headers : Print callback headers for debugging. "
|
||||
"Disabled by default.\n" +
|
||||
"\t-u, --uid : Set effective user id if receiver "
|
||||
"started "
|
||||
"with privileges. \n\n";
|
||||
}
|
||||
throw sls::RuntimeError("Unknown AppType for help message");
|
||||
}
|
||||
|
||||
void CommandLineOptions::setEffectiveUID(uid_t uid) {
|
||||
if (geteuid() == uid) {
|
||||
LOG(sls::logINFO) << "Process already has the same Effective UID "
|
||||
<< uid;
|
||||
} else {
|
||||
if (seteuid(uid) != 0 || geteuid() != uid) {
|
||||
throw sls::RuntimeError("Could not set Effective UID");
|
||||
}
|
||||
LOG(sls::logINFO) << "Process Effective UID changed to " << uid;
|
||||
}
|
||||
}
|
63
slsReceiverSoftware/src/CommandLineOptions.h
Normal file
63
slsReceiverSoftware/src/CommandLineOptions.h
Normal file
@ -0,0 +1,63 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <getopt.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
enum class AppType { MultiReceiver, SingleReceiver, FrameSynchronizer };
|
||||
|
||||
struct CommonOptions {
|
||||
uint16_t port = -1;
|
||||
uid_t userid = -1;
|
||||
bool versionRequested = false;
|
||||
bool helpRequested = false;
|
||||
};
|
||||
|
||||
struct MultiReceiverOptions : CommonOptions {
|
||||
uint16_t numReceivers = 1;
|
||||
bool callbackEnabled = false;
|
||||
};
|
||||
|
||||
struct FrameSyncOptions : CommonOptions {
|
||||
uint16_t numReceivers = 1;
|
||||
bool printHeaders = false;
|
||||
};
|
||||
|
||||
using ParsedOptions =
|
||||
std::variant<CommonOptions, MultiReceiverOptions, FrameSyncOptions>;
|
||||
|
||||
class CommandLineOptions {
|
||||
public:
|
||||
explicit CommandLineOptions(AppType app);
|
||||
ParsedOptions parse(const std::vector<std::string> &args); // for testing
|
||||
ParsedOptions parse(int argc, char *argv[]);
|
||||
std::string getTypeString() const;
|
||||
std::string getVersion() const;
|
||||
std::string getHelpMessage() const;
|
||||
static void setEffectiveUID(uid_t uid);
|
||||
static std::tuple<uint16_t, uint16_t, bool>
|
||||
ParseDeprecated(const std::vector<std::string> &args);
|
||||
|
||||
private:
|
||||
AppType appType_;
|
||||
std::string optString_;
|
||||
std::vector<option> longOptions_;
|
||||
std::vector<option> buildOptionList() const;
|
||||
std::string buildOptString() const;
|
||||
|
||||
static uint16_t parsePort(const char *optarg);
|
||||
static uint16_t parseNumReceivers(const char *optarg);
|
||||
static uid_t parseUID(const char *optarg);
|
||||
void handleCommonOption(int opt, const char *optarg, CommonOptions &base);
|
||||
void handleAppSpecificOption(int opt, const char *optarg,
|
||||
CommonOptions &base,
|
||||
MultiReceiverOptions &multi,
|
||||
FrameSyncOptions &frame);
|
||||
|
||||
static constexpr uint16_t MAX_RECEIVERS = 1000;
|
||||
};
|
@ -5,16 +5,17 @@
|
||||
* reconstructing image. Sample python script for pull socket for this combiner
|
||||
* in python/scripts folder. TODO: Not handling empty frames from one socket
|
||||
*/
|
||||
#include "CommandLineOptions.h"
|
||||
#include "sls/Receiver.h"
|
||||
#include "sls/ToString.h"
|
||||
#include "sls/container_utils.h"
|
||||
#include "sls/logger.h"
|
||||
#include "sls/network_utils.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
|
||||
#include <csignal> //SIGINT
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <ostream>
|
||||
#include <semaphore.h>
|
||||
@ -28,9 +29,14 @@
|
||||
#include <zmq.h>
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
std::vector<sem_t *> semaphores;
|
||||
sls::TLogLevel printHeadersLevel = sls::logDEBUG;
|
||||
|
||||
// gettid added in glibc 2.30
|
||||
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 30
|
||||
#include <sys/syscall.h>
|
||||
#define gettid() syscall(SYS_gettid)
|
||||
#endif
|
||||
|
||||
/** Define Colors to print data call back in different colors for different
|
||||
* recievers */
|
||||
#define PRINT_IN_COLOR(c, f, ...) \
|
||||
@ -57,16 +63,6 @@ struct FrameStatus {
|
||||
};
|
||||
FrameStatus *global_frame_status = nullptr;
|
||||
|
||||
/**
|
||||
* Control+C Interrupt Handler
|
||||
* to let all the processes know to exit properly
|
||||
*/
|
||||
void sigInterruptHandler(int p) {
|
||||
for (size_t i = 0; i != semaphores.size(); ++i) {
|
||||
sem_post(semaphores[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
if (global_frame_status) {
|
||||
std::lock_guard<std::mutex> lock(global_frame_status->mtx);
|
||||
@ -86,19 +82,6 @@ void cleanup() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* prints usage of this example program
|
||||
*/
|
||||
std::string getHelpMessage() {
|
||||
std::ostringstream os;
|
||||
os << "\nUsage:\n"
|
||||
"./slsFrameSynchronizer [start tcp port] [num recevers] [print "
|
||||
"callback headers (optional)]\n"
|
||||
<< "\t - tcp port has to be non-zero and 16 bit\n"
|
||||
<< "\t - print callback headers option is 0 (disabled) by default\n";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
void zmq_free(void *data, void *hint) { delete[] static_cast<char *>(data); }
|
||||
|
||||
void print_frames(const PortFrameMap &frame_port_map) {
|
||||
@ -512,83 +495,46 @@ void GetDataCallback(slsDetectorDefs::sls_receiver_header &header,
|
||||
sem_post(&stat->available);
|
||||
}
|
||||
|
||||
std::vector<sem_t> semaphores;
|
||||
|
||||
/**
|
||||
* Example of main program using the Receiver class
|
||||
*
|
||||
* - Defines in file for:
|
||||
* - Default Number of receivers is 1
|
||||
* - Default Start TCP port is 1954
|
||||
* Control+C Interrupt Handler
|
||||
* to let all the processes know to exit properly
|
||||
* Only the main thread will call this handler
|
||||
*/
|
||||
void sigInterruptHandler(int p) {
|
||||
(void)signal; // suppress unused warning if needed
|
||||
for (auto &s : semaphores) {
|
||||
sem_post(&s);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
/** - set default values */
|
||||
int numReceivers = 1;
|
||||
uint16_t startTCPPort = DEFAULT_TCP_RX_PORTNO;
|
||||
bool printHeaders = false;
|
||||
|
||||
/** - get number of receivers and start tcp port from command line
|
||||
* arguments */
|
||||
if (argc > 1) {
|
||||
CommandLineOptions cli(AppType::FrameSynchronizer);
|
||||
ParsedOptions opts;
|
||||
try {
|
||||
if (argc == 3 || argc == 4) {
|
||||
startTCPPort = sls::StringTo<uint16_t>(argv[1]);
|
||||
if (startTCPPort == 0) {
|
||||
throw std::runtime_error("Invalid start tcp port");
|
||||
}
|
||||
numReceivers = std::stoi(argv[2]);
|
||||
if (numReceivers > 1024) {
|
||||
cprintf(RED,
|
||||
"Did you mix up the order of the arguments?\n%s\n",
|
||||
getHelpMessage().c_str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (numReceivers == 0) {
|
||||
cprintf(RED, "Invalid number of receivers.\n%s\n",
|
||||
getHelpMessage().c_str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (argc == 4) {
|
||||
printHeaders = sls::StringTo<bool>(argv[3]);
|
||||
if (printHeaders) {
|
||||
printHeadersLevel = sls::logINFOBLUE;
|
||||
}
|
||||
}
|
||||
} else
|
||||
throw std::runtime_error("Invalid number of arguments");
|
||||
} catch (const std::exception &e) {
|
||||
cprintf(RED, "Error: %s\n%s\n", e.what(), getHelpMessage().c_str());
|
||||
opts = cli.parse(argc, argv);
|
||||
} catch (sls::RuntimeError &e) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto &f = std::get<FrameSyncOptions>(opts);
|
||||
if (f.versionRequested || f.helpRequested) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
cprintf(RESET, "Number of Receivers: %d\n", numReceivers);
|
||||
cprintf(RESET, "Start TCP Port: %hu\n", startTCPPort);
|
||||
cprintf(RESET, "Print Callback Headers: %s\n\n",
|
||||
(printHeaders ? "Enabled" : "Disabled"));
|
||||
LOG(sls::logINFOBLUE) << "Current Process [ Tid: " << gettid() << ']';
|
||||
|
||||
/** - Catch signal SIGINT to close files and call destructors properly */
|
||||
struct sigaction sa;
|
||||
sa.sa_flags = 0; // no flags
|
||||
sa.sa_handler = sigInterruptHandler; // handler function
|
||||
sigemptyset(&sa.sa_mask); // dont block additional signals during invocation
|
||||
// of handler
|
||||
if (sigaction(SIGINT, &sa, nullptr) == -1) {
|
||||
cprintf(RED, "Could not set handler function for SIGINT\n");
|
||||
// close files on ctrl+c
|
||||
sls::setupSignalHandler(SIGINT, sigInterruptHandler);
|
||||
// handle locally on socket crash
|
||||
sls::setupSignalHandler(SIGPIPE, SIG_IGN);
|
||||
|
||||
semaphores.resize(f.numReceivers);
|
||||
for (auto &s : semaphores) {
|
||||
sem_init(&s, 0, 0);
|
||||
}
|
||||
|
||||
/** - Ignore SIG_PIPE, prevents global signal handler, handle locally,
|
||||
instead of a server crashing due to client crash when writing, it just
|
||||
gives error */
|
||||
struct sigaction asa;
|
||||
asa.sa_flags = 0; // no flags
|
||||
asa.sa_handler = SIG_IGN; // handler function
|
||||
sigemptyset(&asa.sa_mask); // dont block additional signals during
|
||||
// invocation of handler
|
||||
if (sigaction(SIGPIPE, &asa, nullptr) == -1) {
|
||||
cprintf(RED, "Could not set handler function for SIGPIPE\n");
|
||||
}
|
||||
|
||||
FrameStatus stat{true, false, numReceivers};
|
||||
FrameStatus stat{true, false, f.numReceivers};
|
||||
// store pointer for signal handler
|
||||
global_frame_status = &stat;
|
||||
|
||||
@ -596,34 +542,44 @@ int main(int argc, char *argv[]) {
|
||||
void *user_data = static_cast<void *>(&stat);
|
||||
std::thread combinerThread(Correlate, &stat);
|
||||
|
||||
for (int i = 0; i != numReceivers; ++i) {
|
||||
sem_t *semaphore = new sem_t;
|
||||
sem_init(semaphore, 1, 0);
|
||||
semaphores.push_back(semaphore);
|
||||
|
||||
uint16_t port = startTCPPort + i;
|
||||
threads.emplace_back([i, semaphore, port, user_data]() {
|
||||
std::exception_ptr threadException = nullptr;
|
||||
for (int i = 0; i != f.numReceivers; ++i) {
|
||||
uint16_t port = f.port + i;
|
||||
sem_t *semaphore = &semaphores[i];
|
||||
threads.emplace_back(
|
||||
[i, semaphore, port, user_data, &threadException]() {
|
||||
LOG(sls::logINFOBLUE)
|
||||
<< "Thread " << i << " [ Tid: " << gettid() << ']';
|
||||
try {
|
||||
sls::Receiver receiver(port);
|
||||
receiver.registerCallBackStartAcquisition(StartAcquisitionCallback,
|
||||
user_data);
|
||||
receiver.registerCallBackStartAcquisition(
|
||||
StartAcquisitionCallback, user_data);
|
||||
receiver.registerCallBackAcquisitionFinished(
|
||||
AcquisitionFinishedCallback, user_data);
|
||||
receiver.registerCallBackRawDataReady(GetDataCallback, user_data);
|
||||
/** - as long as no Ctrl+C */
|
||||
sem_wait(semaphore);
|
||||
sem_destroy(semaphore);
|
||||
delete semaphore;
|
||||
receiver.registerCallBackRawDataReady(GetDataCallback,
|
||||
user_data);
|
||||
|
||||
// clean up frames
|
||||
if (i == 0)
|
||||
cleanup();
|
||||
/** - as long as no Ctrl+C */
|
||||
// each child shares the common semaphore
|
||||
sem_wait(semaphore);
|
||||
} catch (...) {
|
||||
// capture exception and raise SIGINT to exit gracefully
|
||||
threadException = std::current_exception();
|
||||
raise(SIGINT);
|
||||
}
|
||||
LOG(sls::logINFOBLUE)
|
||||
<< "Exiting Thread " << i << " [ Tid: " << gettid() << " ]";
|
||||
});
|
||||
}
|
||||
|
||||
for (auto &thread : threads) {
|
||||
thread.join();
|
||||
for (auto &t : threads) {
|
||||
t.join();
|
||||
}
|
||||
|
||||
for (auto &s : semaphores)
|
||||
sem_destroy(&s);
|
||||
cleanup();
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(stat.mtx);
|
||||
stat.terminate = true;
|
||||
@ -632,6 +588,19 @@ int main(int argc, char *argv[]) {
|
||||
combinerThread.join();
|
||||
sem_destroy(&stat.available);
|
||||
|
||||
if (threadException) {
|
||||
try {
|
||||
std::rethrow_exception(threadException);
|
||||
} catch (const std::exception &e) {
|
||||
LOG(sls::logERROR)
|
||||
<< "Unhandled exception from thread: " << e.what();
|
||||
return EXIT_FAILURE;
|
||||
} catch (...) {
|
||||
LOG(sls::logERROR) << "Unknown exception occurred in thread";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
LOG(sls::logINFOBLUE) << "Goodbye!";
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -2,15 +2,16 @@
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
/* Creates the slsMultiReceiver for running multiple receivers form a single
|
||||
* binary */
|
||||
#include "CommandLineOptions.h"
|
||||
#include "sls/Receiver.h"
|
||||
#include "sls/ToString.h"
|
||||
#include "sls/container_utils.h"
|
||||
#include "sls/logger.h"
|
||||
#include "sls/network_utils.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
|
||||
#include <csignal> //SIGINT
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <semaphore.h>
|
||||
#include <sys/wait.h> //wait
|
||||
#include <unistd.h>
|
||||
@ -26,28 +27,6 @@
|
||||
#define PRINT_IN_COLOR(c, f, ...) \
|
||||
printf("\033[%dm" f RESET, 30 + c + 1, ##__VA_ARGS__)
|
||||
|
||||
sem_t semaphore;
|
||||
|
||||
/**
|
||||
* Control+C Interrupt Handler
|
||||
* to let all the processes know to exit properly
|
||||
*/
|
||||
void sigInterruptHandler(int p) { sem_post(&semaphore); }
|
||||
|
||||
/**
|
||||
* prints usage of this example program
|
||||
*/
|
||||
std::string getHelpMessage() {
|
||||
std::ostringstream os;
|
||||
os << "\nUsage:\n"
|
||||
<< "./slsMultiReceiver [start tcp port] [num recevers] [call back "
|
||||
"option (optional)]\n"
|
||||
<< "\t - tcp port has to be non-zero and 16 bit\n"
|
||||
<< "\t - call back option is 0 (disabled) by default, 1 prints frame "
|
||||
"header for debugging\n";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start Acquisition Call back (slsMultiReceiver writes data if file write
|
||||
* enabled) if registerCallBackRawDataReady or
|
||||
@ -146,99 +125,48 @@ void GetData(slsDetectorDefs::sls_receiver_header &header,
|
||||
// header->packetsMask.to_string().c_str(),
|
||||
((uint8_t)(*((uint8_t *)(dataPointer)))), imageSize);
|
||||
|
||||
// // example of how to use roi or modify data that is later written to file
|
||||
// slsDetectorDefs::ROI roi{0, 10, 0, 20};
|
||||
// int width = roi.xmax - roi.xmin;
|
||||
// int height = roi.ymax - roi.ymin;
|
||||
// uint8_t *destPtr = (uint8_t *)dataPointer;
|
||||
// for (int irow = roi.ymin; irow < roi.ymax; ++irow) {
|
||||
// memcpy(destPtr,
|
||||
// ((uint8_t *)(dataPointer + irow * callbackHeader.shape.x +
|
||||
// roi.xmin)),
|
||||
// width);
|
||||
// destPtr += width;
|
||||
// }
|
||||
// memcpy((uint8_t*)dataPointer, (uint8_t*)dataPointer
|
||||
// // setting roi for eg. changes size
|
||||
// imageSize = width * height;
|
||||
// if data is modified, can affect size
|
||||
// only reduction in size allowed, not increase
|
||||
// imageSize = 26000;
|
||||
}
|
||||
|
||||
sem_t semaphore;
|
||||
|
||||
/**
|
||||
* Example of main program using the Receiver class
|
||||
*
|
||||
* - Defines in file for:
|
||||
* - Default Number of receivers is 1
|
||||
* - Default Start TCP port is 1954
|
||||
* Control+C Interrupt Handler
|
||||
* to let all the processes know to exit properly
|
||||
* All child processes will call the handler (parent process set to ignore)
|
||||
*/
|
||||
void sigInterruptHandler(int signal) {
|
||||
(void)signal; // suppress unused warning if needed
|
||||
sem_post(&semaphore);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
/** - set default values */
|
||||
int numReceivers = 1;
|
||||
uint16_t startTCPPort = DEFAULT_TCP_RX_PORTNO;
|
||||
int withCallback = 0;
|
||||
CommandLineOptions cli(AppType::MultiReceiver);
|
||||
ParsedOptions opts;
|
||||
try {
|
||||
opts = cli.parse(argc, argv);
|
||||
} catch (sls::RuntimeError &e) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto &m = std::get<MultiReceiverOptions>(opts);
|
||||
if (m.versionRequested || m.helpRequested) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
LOG(sls::logINFOBLUE) << "Current Process [ Tid: " << gettid() << ']';
|
||||
|
||||
// close files on ctrl+c
|
||||
sls::setupSignalHandler(SIGINT, sigInterruptHandler);
|
||||
// handle locally on socket crash
|
||||
sls::setupSignalHandler(SIGPIPE, SIG_IGN);
|
||||
|
||||
sem_init(&semaphore, 1, 0);
|
||||
|
||||
/** - get number of receivers and start tcp port from command line
|
||||
* arguments */
|
||||
if (argc > 1) {
|
||||
try {
|
||||
if (argc == 3 || argc == 4) {
|
||||
startTCPPort = sls::StringTo<uint16_t>(argv[1]);
|
||||
if (startTCPPort == 0) {
|
||||
throw std::runtime_error("Invalid start tcp port");
|
||||
}
|
||||
numReceivers = std::stoi(argv[2]);
|
||||
if (numReceivers > 1024) {
|
||||
cprintf(RED,
|
||||
"Did you mix up the order of the arguments?\n%s\n",
|
||||
getHelpMessage().c_str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (numReceivers == 0) {
|
||||
cprintf(RED, "Invalid number of receivers.\n%s\n",
|
||||
getHelpMessage().c_str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (argc == 4) {
|
||||
withCallback = std::stoi(argv[3]);
|
||||
}
|
||||
} else
|
||||
throw std::runtime_error("Invalid number of arguments");
|
||||
} catch (const std::exception &e) {
|
||||
cprintf(RED, "Error: %s\n%s\n", e.what(), getHelpMessage().c_str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
cprintf(BLUE, "Parent Process Created [ Tid: %ld ]\n", (long)gettid());
|
||||
cprintf(RESET, "Number of Receivers: %d\n", numReceivers);
|
||||
cprintf(RESET, "Start TCP Port: %hu\n", startTCPPort);
|
||||
cprintf(RESET, "Callback Enable: %d\n", withCallback);
|
||||
|
||||
/** - Catch signal SIGINT to close files and call destructors properly */
|
||||
struct sigaction sa;
|
||||
sa.sa_flags = 0; // no flags
|
||||
sa.sa_handler = sigInterruptHandler; // handler function
|
||||
sigemptyset(&sa.sa_mask); // dont block additional signals during invocation
|
||||
// of handler
|
||||
if (sigaction(SIGINT, &sa, nullptr) == -1) {
|
||||
cprintf(RED, "Could not set handler function for SIGINT\n");
|
||||
}
|
||||
|
||||
/** - Ignore SIG_PIPE, prevents global signal handler, handle locally,
|
||||
instead of a server crashing due to client crash when writing, it just
|
||||
gives error */
|
||||
struct sigaction asa;
|
||||
asa.sa_flags = 0; // no flags
|
||||
asa.sa_handler = SIG_IGN; // handler function
|
||||
sigemptyset(&asa.sa_mask); // dont block additional signals during
|
||||
// invocation of handler
|
||||
if (sigaction(SIGPIPE, &asa, nullptr) == -1) {
|
||||
cprintf(RED, "Could not set handler function for SIGPIPE\n");
|
||||
}
|
||||
|
||||
/** - loop over number of receivers */
|
||||
for (int i = 0; i < numReceivers; ++i) {
|
||||
/** - loop over receivers */
|
||||
for (int i = 0; i < m.numReceivers; ++i) {
|
||||
|
||||
/** - fork process to create child process */
|
||||
pid_t pid = fork();
|
||||
@ -246,86 +174,89 @@ int main(int argc, char *argv[]) {
|
||||
/** - if fork failed, raise SIGINT and properly destroy all child
|
||||
* processes */
|
||||
if (pid < 0) {
|
||||
cprintf(RED, "fork() failed. Killing all the receiver objects\n");
|
||||
LOG(sls::logERROR)
|
||||
<< "fork() failed. Killing all the receiver objects";
|
||||
raise(SIGINT);
|
||||
}
|
||||
|
||||
/** - if child process */
|
||||
else if (pid == 0) {
|
||||
cprintf(BLUE, "Child process %d [ Tid: %ld ]\n", i, (long)gettid());
|
||||
|
||||
std::unique_ptr<sls::Receiver> receiver = nullptr;
|
||||
try {
|
||||
receiver = sls::make_unique<sls::Receiver>(startTCPPort + i);
|
||||
} catch (...) {
|
||||
LOG(sls::logINFOBLUE)
|
||||
<< "Exiting Child Process [ Tid: " << gettid() << " ]";
|
||||
throw;
|
||||
}
|
||||
/** - register callbacks. remember to set file write enable to 0
|
||||
* (using the client) if we should not write files and you will
|
||||
* write data using the callbacks */
|
||||
if (withCallback) {
|
||||
<< "Child process " << i << " [ Tid: " << gettid() << ']';
|
||||
|
||||
try {
|
||||
uint16_t port = m.port + i;
|
||||
sls::Receiver receiver(port);
|
||||
|
||||
/** - register callbacks. remember to set file write enable
|
||||
* to 0 (using the client) if we should not write files and you
|
||||
* will write data using the callbacks */
|
||||
if (m.callbackEnabled) {
|
||||
|
||||
/** - Call back for start acquisition */
|
||||
cprintf(BLUE, "Registering StartAcq()\n");
|
||||
receiver->registerCallBackStartAcquisition(StartAcq, nullptr);
|
||||
LOG(sls::logINFOBLUE) << "Registering StartAcq()";
|
||||
receiver.registerCallBackStartAcquisition(StartAcq,
|
||||
nullptr);
|
||||
|
||||
/** - Call back for acquisition finished */
|
||||
cprintf(BLUE, "Registering AcquisitionFinished()\n");
|
||||
receiver->registerCallBackAcquisitionFinished(
|
||||
LOG(sls::logINFOBLUE)
|
||||
<< "Registering AcquisitionFinished()";
|
||||
receiver.registerCallBackAcquisitionFinished(
|
||||
AcquisitionFinished, nullptr);
|
||||
|
||||
/* - Call back for raw data */
|
||||
cprintf(BLUE, "Registering GetData() \n");
|
||||
receiver->registerCallBackRawDataReady(GetData, nullptr);
|
||||
LOG(sls::logINFOBLUE) << "Registering GetData()";
|
||||
receiver.registerCallBackRawDataReady(GetData, nullptr);
|
||||
}
|
||||
|
||||
/** - as long as no Ctrl+C */
|
||||
// each child process gets a copy of the semaphore
|
||||
sem_wait(&semaphore);
|
||||
sem_destroy(&semaphore);
|
||||
cprintf(BLUE, "Exiting Child Process [ Tid: %ld ]\n",
|
||||
(long)gettid());
|
||||
LOG(sls::logINFOBLUE)
|
||||
<< "Exiting Child Process [ Tid: " << gettid() << ']';
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
} catch (...) {
|
||||
sem_destroy(&semaphore);
|
||||
LOG(sls::logINFOBLUE)
|
||||
<< "Exiting Child Process [ Tid: " << gettid() << " ]";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** - Parent process ignores SIGINT (exits only when all child process
|
||||
* exits) */
|
||||
sa.sa_flags = 0; // no flags
|
||||
sa.sa_handler = SIG_IGN; // handler function
|
||||
sigemptyset(&sa.sa_mask); // dont block additional signals during invocation
|
||||
// of handler
|
||||
if (sigaction(SIGINT, &sa, nullptr) == -1) {
|
||||
cprintf(RED, "Could not set handler function for SIGINT\n");
|
||||
}
|
||||
/** - Parent process ignores SIGINT and waits for all the child processes to
|
||||
* handle the signal */
|
||||
sls::setupSignalHandler(SIGINT, SIG_IGN);
|
||||
|
||||
/** - Print Ready and Instructions how to exit */
|
||||
std::cout << "Ready ... \n";
|
||||
cprintf(RESET, "\n[ Press \'Ctrl+c\' to exit ]\n");
|
||||
LOG(sls::logINFO) << "\n[ Press \'Ctrl+c\' to exit ]";
|
||||
|
||||
/** - Parent process waits for all child processes to exit */
|
||||
for (;;) {
|
||||
pid_t childPid = waitpid(-1, nullptr, 0);
|
||||
int status;
|
||||
pid_t childPid = waitpid(-1, &status, 0);
|
||||
|
||||
// no child closed
|
||||
if (childPid == -1) {
|
||||
if (errno == ECHILD) {
|
||||
cprintf(GREEN, "All Child Processes have been closed\n");
|
||||
LOG(sls::logINFOGREEN)
|
||||
<< "All Child Processes have been closed";
|
||||
break;
|
||||
} else {
|
||||
cprintf(RED, "Unexpected error from waitpid(): (%s)\n",
|
||||
strerror(errno));
|
||||
LOG(sls::logERROR)
|
||||
<< "Unexpected error from waitpid(): " << strerror(errno);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// child closed
|
||||
cprintf(BLUE, "Exiting Child Process [ Tid: %ld ]\n",
|
||||
(long int)childPid);
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
|
||||
std::cerr << "Child " << childPid << " failed\n";
|
||||
kill(0, SIGINT); // signal other children to exit
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Goodbye!\n";
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -27,106 +27,14 @@ namespace sls {
|
||||
|
||||
Receiver::~Receiver() = default;
|
||||
|
||||
Receiver::Receiver(int argc, char *argv[]) : tcpipInterface(nullptr) {
|
||||
|
||||
// options
|
||||
uint16_t tcpip_port_no = 1954;
|
||||
uid_t userid = -1;
|
||||
|
||||
// parse command line for config
|
||||
static struct option long_options[] = {
|
||||
// These options set a flag.
|
||||
//{"verbose", no_argument, &verbose_flag, 1},
|
||||
// These options don’t set a flag. We distinguish them by their indices.
|
||||
{"rx_tcpport", required_argument, nullptr,
|
||||
't'}, // TODO change or backward compatible to "port, p"?
|
||||
{"uid", required_argument, nullptr, 'u'},
|
||||
{"version", no_argument, nullptr, 'v'},
|
||||
{"help", no_argument, nullptr, 'h'},
|
||||
{nullptr, 0, nullptr, 0}};
|
||||
|
||||
// initialize global optind variable (required when instantiating multiple
|
||||
// receivers in the same process)
|
||||
optind = 1;
|
||||
// getopt_long stores the option index here.
|
||||
int option_index = 0;
|
||||
int c = 0;
|
||||
|
||||
std::string help_message =
|
||||
"\nUsage: " + std::string(argv[0]) + " [arguments]\n" +
|
||||
"Possible arguments are:\n" +
|
||||
"\t-t, --rx_tcpport <port> : TCP Communication Port with "
|
||||
"client. Non-zero and 16 bit.\n" +
|
||||
"\t-u, --uid <user id> : Set effective user id if receiver "
|
||||
"\n" +
|
||||
"\t started with privileges. \n\n";
|
||||
|
||||
while (c != -1) {
|
||||
c = getopt_long(argc, argv, "hvf:t:u:", long_options, &option_index);
|
||||
|
||||
// Detect the end of the options.
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
|
||||
case 't':
|
||||
try {
|
||||
tcpip_port_no = sls::StringTo<uint16_t>(optarg);
|
||||
validatePortNumber(tcpip_port_no);
|
||||
} catch (...) {
|
||||
throw RuntimeError("Could not scan TCP port number." +
|
||||
help_message);
|
||||
Receiver::Receiver(uint16_t port) {
|
||||
validatePortNumber(port);
|
||||
#ifdef SLS_USE_TESTS
|
||||
if (port == 65535) {
|
||||
throw sls::RuntimeError("Throwing for testing purposes. ");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
if (sscanf(optarg, "%u", &userid) != 1) {
|
||||
throw RuntimeError("Could not scan uid" + help_message);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
std::cout << "SLS Receiver Version: " << APIRECEIVER << std::endl;
|
||||
LOG(logINFOBLUE) << "Exiting [ Tid: " << gettid() << " ]";
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
case 'h':
|
||||
std::cout << help_message << std::endl;
|
||||
exit(EXIT_SUCCESS);
|
||||
default:
|
||||
throw RuntimeError(help_message);
|
||||
}
|
||||
}
|
||||
|
||||
// set effective id if provided
|
||||
if (userid != static_cast<uid_t>(-1)) {
|
||||
if (geteuid() == userid) {
|
||||
LOG(logINFO) << "Process already has the same Effective UID "
|
||||
<< userid;
|
||||
} else {
|
||||
if (seteuid(userid) != 0) {
|
||||
std::ostringstream oss;
|
||||
oss << "Could not set Effective UID to " << userid;
|
||||
throw RuntimeError(oss.str());
|
||||
}
|
||||
if (geteuid() != userid) {
|
||||
std::ostringstream oss;
|
||||
oss << "Could not set Effective UID to " << userid << ". Got "
|
||||
<< geteuid();
|
||||
throw RuntimeError(oss.str());
|
||||
}
|
||||
LOG(logINFO) << "Process Effective UID changed to " << userid;
|
||||
}
|
||||
}
|
||||
|
||||
// might throw an exception
|
||||
tcpipInterface = make_unique<ClientInterface>(tcpip_port_no);
|
||||
}
|
||||
|
||||
Receiver::Receiver(uint16_t tcpip_port_no) {
|
||||
// might throw an exception
|
||||
tcpipInterface = make_unique<ClientInterface>(tcpip_port_no);
|
||||
#endif
|
||||
tcpipInterface = make_unique<ClientInterface>(port);
|
||||
}
|
||||
|
||||
std::string Receiver::getReceiverVersion() {
|
||||
|
@ -1,9 +1,12 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
/* slsReceiver */
|
||||
#include "CommandLineOptions.h"
|
||||
#include "sls/Receiver.h"
|
||||
#include "sls/ToString.h"
|
||||
#include "sls/container_utils.h"
|
||||
#include "sls/logger.h"
|
||||
#include "sls/network_utils.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
|
||||
#include <csignal> //SIGINT
|
||||
@ -18,44 +21,49 @@
|
||||
|
||||
sem_t semaphore;
|
||||
|
||||
void sigInterruptHandler(int p) { sem_post(&semaphore); }
|
||||
/**
|
||||
* Control+C Interrupt Handler
|
||||
* to let all the other process know to exit properly
|
||||
*/
|
||||
void sigInterruptHandler(int signal) {
|
||||
(void)signal; // suppress unused warning if needed
|
||||
sem_post(&semaphore);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
CommandLineOptions cli(AppType::SingleReceiver);
|
||||
ParsedOptions opts;
|
||||
try {
|
||||
opts = cli.parse(argc, argv);
|
||||
} catch (sls::RuntimeError &e) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto &o = std::get<CommonOptions>(opts);
|
||||
if (o.versionRequested || o.helpRequested) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
LOG(sls::logINFOBLUE) << "Current Process [ Tid: " << gettid() << " ]";
|
||||
|
||||
// close files on ctrl+c
|
||||
sls::setupSignalHandler(SIGINT, sigInterruptHandler);
|
||||
// handle locally on socket crash
|
||||
sls::setupSignalHandler(SIGPIPE, SIG_IGN);
|
||||
|
||||
sem_init(&semaphore, 1, 0);
|
||||
|
||||
LOG(sls::logINFOBLUE) << "Created [ Tid: " << gettid() << " ]";
|
||||
|
||||
// Catch signal SIGINT to close files and call destructors properly
|
||||
struct sigaction sa;
|
||||
sa.sa_flags = 0; // no flags
|
||||
sa.sa_handler = sigInterruptHandler; // handler function
|
||||
sigemptyset(&sa.sa_mask); // dont block additional signals during invocation
|
||||
// of handler
|
||||
if (sigaction(SIGINT, &sa, nullptr) == -1) {
|
||||
LOG(sls::logERROR) << "Could not set handler function for SIGINT";
|
||||
}
|
||||
|
||||
// if socket crash, ignores SISPIPE, prevents global signal handler
|
||||
// subsequent read/write to socket gives error - must handle locally
|
||||
struct sigaction asa;
|
||||
asa.sa_flags = 0; // no flags
|
||||
asa.sa_handler = SIG_IGN; // handler function
|
||||
sigemptyset(&asa.sa_mask); // dont block additional signals during
|
||||
// invocation of handler
|
||||
if (sigaction(SIGPIPE, &asa, nullptr) == -1) {
|
||||
LOG(sls::logERROR) << "Could not set handler function for SIGPIPE";
|
||||
}
|
||||
|
||||
try {
|
||||
sls::Receiver r(argc, argv);
|
||||
sls::Receiver r(o.port);
|
||||
LOG(sls::logINFO) << "[ Press \'Ctrl+c\' to exit ]";
|
||||
sem_wait(&semaphore);
|
||||
sem_destroy(&semaphore);
|
||||
} catch (...) {
|
||||
// pass
|
||||
sem_destroy(&semaphore);
|
||||
LOG(sls::logINFOBLUE) << "Exiting [ Tid: " << gettid() << " ]";
|
||||
throw;
|
||||
}
|
||||
LOG(sls::logINFOBLUE) << "Exiting [ Tid: " << gettid() << " ]";
|
||||
LOG(sls::logINFO) << "Exiting Receiver";
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ target_sources(tests PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test-GeneralData.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test-CircularFifo.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test-ArrangeDataBasedOnBitList.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test-Apps.cpp
|
||||
)
|
||||
|
||||
target_include_directories(tests PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../src>")
|
||||
|
328
slsReceiverSoftware/tests/test-Apps.cpp
Normal file
328
slsReceiverSoftware/tests/test-Apps.cpp
Normal file
@ -0,0 +1,328 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#include "CommandLineOptions.h"
|
||||
#include "catch.hpp"
|
||||
#include "sls/versionAPI.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
namespace sls {
|
||||
|
||||
template <typename T, typename U> constexpr bool is_type() {
|
||||
return std::is_same_v<std::decay_t<U>, T>;
|
||||
}
|
||||
|
||||
TEST_CASE("CommandLineOption construction", "[.rxcmdcall]") {
|
||||
CommandLineOptions s(AppType::SingleReceiver);
|
||||
REQUIRE(s.getTypeString() == "slsReceiver");
|
||||
REQUIRE(s.getVersion() ==
|
||||
std::string("slsReceiver Version: ") + APIRECEIVER);
|
||||
REQUIRE_NOTHROW(s.getHelpMessage());
|
||||
|
||||
CommandLineOptions m(AppType::MultiReceiver);
|
||||
REQUIRE(m.getTypeString() == "slsMultiReceiver");
|
||||
REQUIRE(m.getVersion() ==
|
||||
std::string("slsMultiReceiver Version: ") + APIRECEIVER);
|
||||
REQUIRE_NOTHROW(m.getHelpMessage());
|
||||
|
||||
CommandLineOptions f(AppType::FrameSynchronizer);
|
||||
REQUIRE(f.getTypeString() == "slsFrameSynchronizer");
|
||||
REQUIRE(f.getVersion() ==
|
||||
std::string("slsFrameSynchronizer Version: ") + APIRECEIVER);
|
||||
REQUIRE_NOTHROW(f.getHelpMessage());
|
||||
}
|
||||
|
||||
TEST_CASE("Validate common options", "[.rxcmdcall]") {
|
||||
std::string uidStr = std::to_string(getuid());
|
||||
|
||||
for (auto app : {AppType::SingleReceiver, AppType::MultiReceiver,
|
||||
AppType::FrameSynchronizer}) {
|
||||
CommandLineOptions s(app);
|
||||
REQUIRE_NOTHROW(s.parse({}));
|
||||
REQUIRE_NOTHROW(s.parse({"", "-v"}));
|
||||
REQUIRE_NOTHROW(s.parse({"", "-h"}));
|
||||
REQUIRE_NOTHROW(s.parse({"", "-h", "gdfg"})); // ignored extra args
|
||||
REQUIRE_NOTHROW(s.parse({"", "-p", "1955"}));
|
||||
REQUIRE_NOTHROW(s.parse({"", "-u", uidStr}));
|
||||
REQUIRE_NOTHROW(s.parse({"", "-p", "1234", "-u", uidStr}));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Validate specific options", "[.rxcmdcall]") {
|
||||
std::string uidStr = std::to_string(getuid());
|
||||
|
||||
CommandLineOptions s(AppType::SingleReceiver);
|
||||
REQUIRE_NOTHROW(s.parse({"", "-t", "1955"}));
|
||||
REQUIRE_THROWS(s.parse({"", "-c"}));
|
||||
REQUIRE_THROWS(s.parse({"", "-n", "2"}));
|
||||
REQUIRE_THROWS(s.parse({"", "-m", "2"}));
|
||||
|
||||
for (auto app : {AppType::MultiReceiver, AppType::FrameSynchronizer}) {
|
||||
CommandLineOptions m(app);
|
||||
REQUIRE_NOTHROW(m.parse({"", "-c"}));
|
||||
REQUIRE_NOTHROW(m.parse({"", "-n", "2"}));
|
||||
REQUIRE_NOTHROW(
|
||||
m.parse({"", "-p", "1234", "-u", uidStr, "-c", "-n", "2"}));
|
||||
REQUIRE_THROWS(m.parse({"", "-t", "1955"}));
|
||||
REQUIRE_THROWS(m.parse({"", "-m", "2"}));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Parse version and help", "[.rxcmdcall]") {
|
||||
for (auto app : {AppType::SingleReceiver, AppType::MultiReceiver,
|
||||
AppType::FrameSynchronizer}) {
|
||||
CommandLineOptions s(app);
|
||||
auto opts = s.parse({});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
REQUIRE(o.versionRequested == false); // default
|
||||
REQUIRE(o.helpRequested == false); // default
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({"", "-v"});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
REQUIRE(o.versionRequested == true);
|
||||
REQUIRE(o.helpRequested == false);
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({"", "-h"});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
REQUIRE(o.versionRequested == false);
|
||||
REQUIRE(o.helpRequested == true);
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({"", "-h", "-v"});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
REQUIRE(o.versionRequested == false); // exits after help
|
||||
REQUIRE(o.helpRequested == true);
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({"", "-v", "-h"});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
REQUIRE(o.helpRequested == false); // exits after version
|
||||
REQUIRE(o.versionRequested == true);
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({"", "-v", "-h", "sdfsf"}); // ignores extra args
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
REQUIRE(o.helpRequested == false); // exits after version
|
||||
REQUIRE(o.versionRequested == true);
|
||||
},
|
||||
opts);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Parse port and uid", "[.rxcmdcall]") {
|
||||
uid_t uid = getuid();
|
||||
std::string uidStr = std::to_string(uid);
|
||||
uid_t invalidUid = uid + 1000;
|
||||
std::string invalidUidStr = std::to_string(invalidUid);
|
||||
|
||||
for (auto app : {AppType::SingleReceiver, AppType::MultiReceiver,
|
||||
AppType::FrameSynchronizer}) {
|
||||
CommandLineOptions s(app);
|
||||
REQUIRE_THROWS(
|
||||
s.parse({"", "-p", "1234", "-u", invalidUidStr})); // invalid uid
|
||||
REQUIRE_THROWS(s.parse({"", "-p", "500"})); // invalid port
|
||||
|
||||
auto opts = s.parse({"", "-p", "1234", "-u", uidStr});
|
||||
std::visit(
|
||||
[&](const auto &o) {
|
||||
REQUIRE(o.port == 1234);
|
||||
REQUIRE(o.userid == uid);
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({"", "-p", "5678"});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
REQUIRE(o.port == 5678);
|
||||
REQUIRE(o.userid == static_cast<uid_t>(-1)); // default
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
REQUIRE(o.port == 1954); // default
|
||||
REQUIRE(o.userid == static_cast<uid_t>(-1)); // default
|
||||
},
|
||||
opts);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Parse num receivers and opt arg (Specific opt)", "[.rxcmdcall]") {
|
||||
for (auto app : {AppType::MultiReceiver, AppType::FrameSynchronizer}) {
|
||||
CommandLineOptions s(app);
|
||||
|
||||
REQUIRE_THROWS(s.parse({"", "-n", "0"})); // invalid number of receivers
|
||||
REQUIRE_THROWS(s.parse({"", "-n", "1001"})); // exceeds max receivers
|
||||
REQUIRE_NOTHROW(s.parse({"", "-n", "10"})); // valid
|
||||
|
||||
auto opts = s.parse({""});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
using T = decltype(o);
|
||||
if constexpr (is_type<MultiReceiverOptions, T>()) {
|
||||
REQUIRE(o.numReceivers == 1); // default
|
||||
REQUIRE(o.callbackEnabled == false);
|
||||
|
||||
} else if constexpr (is_type<FrameSyncOptions, T>()) {
|
||||
REQUIRE(o.numReceivers == 1); // default
|
||||
REQUIRE(o.printHeaders == false);
|
||||
}
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({"", "-n", "5"});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
using T = decltype(o);
|
||||
if constexpr (is_type<MultiReceiverOptions, T>()) {
|
||||
REQUIRE(o.numReceivers == 5);
|
||||
REQUIRE(o.callbackEnabled == false); // default
|
||||
|
||||
} else if constexpr (is_type<FrameSyncOptions, T>()) {
|
||||
REQUIRE(o.numReceivers == 5);
|
||||
REQUIRE(o.printHeaders == false); // default
|
||||
}
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({"", "-c", "-n", "3"});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
using T = decltype(o);
|
||||
if constexpr (is_type<MultiReceiverOptions, T>()) {
|
||||
REQUIRE(o.numReceivers == 3);
|
||||
REQUIRE(o.callbackEnabled == true);
|
||||
|
||||
} else if constexpr (is_type<FrameSyncOptions, T>()) {
|
||||
REQUIRE(o.numReceivers == 3);
|
||||
REQUIRE(o.printHeaders == true);
|
||||
}
|
||||
},
|
||||
opts);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Parse deprecated options", "[.rxcmdcall]") {
|
||||
for (auto app : {AppType::SingleReceiver, AppType::MultiReceiver,
|
||||
AppType::FrameSynchronizer}) {
|
||||
CommandLineOptions s(app);
|
||||
// argc 3 or 4, invalid
|
||||
REQUIRE_THROWS(s.parse({"", "1954"}));
|
||||
REQUIRE_THROWS(s.parse({
|
||||
"",
|
||||
"1954",
|
||||
}));
|
||||
// argc 3 or 4
|
||||
if (app == AppType::SingleReceiver) {
|
||||
REQUIRE_THROWS(
|
||||
s.parse({"", "1954", "1"})); // deprecated unsupported
|
||||
} else {
|
||||
REQUIRE_THROWS(s.parse({"", "1954", "1", "1", "-p",
|
||||
"1954"})); // mix deprecated and current
|
||||
REQUIRE_THROWS(
|
||||
s.parse({"", "1954", "1", "-c"})); // mix deprecated and current
|
||||
REQUIRE_THROWS(s.parse(
|
||||
{"", "1954", "1", "-n", "34"})); // mix deprecated and current
|
||||
REQUIRE_THROWS(s.parse({"", "110", "1954"})); // mix order
|
||||
REQUIRE_THROWS(s.parse({"", "1023", "10"})); // privileged port
|
||||
REQUIRE_THROWS(s.parse({"", "2000", "0"})); // invalid num receivers
|
||||
REQUIRE_THROWS(
|
||||
s.parse({"", "2000", "1001"})); // invalid num receivers
|
||||
REQUIRE_THROWS(s.parse({"", "1954", "1", "2"})); // invalid 3rd opt
|
||||
|
||||
REQUIRE_NOTHROW(s.parse({""}));
|
||||
REQUIRE_NOTHROW(s.parse({"", "1954", "1"}));
|
||||
REQUIRE_NOTHROW(s.parse({"", "1954", "1", "0"}));
|
||||
REQUIRE_NOTHROW(s.parse({"", "1954", "1", "1"}));
|
||||
|
||||
// default
|
||||
auto opts = s.parse({""});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
using T = decltype(o);
|
||||
if constexpr (is_type<MultiReceiverOptions, T>()) {
|
||||
REQUIRE(o.port == 1954);
|
||||
REQUIRE(o.numReceivers == 1);
|
||||
REQUIRE(o.callbackEnabled == false);
|
||||
|
||||
} else if constexpr (is_type<FrameSyncOptions, T>()) {
|
||||
REQUIRE(o.port == 1954);
|
||||
REQUIRE(o.numReceivers == 1);
|
||||
REQUIRE(o.printHeaders == false); // default
|
||||
}
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({"", "1958", "10"});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
using T = decltype(o);
|
||||
if constexpr (is_type<MultiReceiverOptions, T>()) {
|
||||
REQUIRE(o.port == 1958);
|
||||
REQUIRE(o.numReceivers == 10);
|
||||
REQUIRE(o.callbackEnabled == false); // default
|
||||
|
||||
} else if constexpr (is_type<FrameSyncOptions, T>()) {
|
||||
REQUIRE(o.port == 1958);
|
||||
REQUIRE(o.numReceivers == 10);
|
||||
REQUIRE(o.printHeaders == false); // default
|
||||
}
|
||||
},
|
||||
opts);
|
||||
|
||||
opts = s.parse({"", "1958", "10", "1"});
|
||||
std::visit(
|
||||
[](const auto &o) {
|
||||
using T = decltype(o);
|
||||
if constexpr (is_type<MultiReceiverOptions, T>()) {
|
||||
REQUIRE(o.port == 1958);
|
||||
REQUIRE(o.numReceivers == 10);
|
||||
REQUIRE(o.callbackEnabled == true); // default
|
||||
|
||||
} else if constexpr (is_type<FrameSyncOptions, T>()) {
|
||||
REQUIRE(o.port == 1958);
|
||||
REQUIRE(o.numReceivers == 10);
|
||||
REQUIRE(o.printHeaders == true); // default
|
||||
}
|
||||
},
|
||||
opts);
|
||||
}
|
||||
}
|
||||
|
||||
// test function directly
|
||||
// nargs can be 1, 3 or 4
|
||||
REQUIRE_THROWS(CommandLineOptions::ParseDeprecated({"", ""}));
|
||||
REQUIRE_THROWS(CommandLineOptions::ParseDeprecated({"", "", "", "", ""}));
|
||||
|
||||
// default
|
||||
auto [p, n, o] = CommandLineOptions::ParseDeprecated({""});
|
||||
REQUIRE(p == 1954);
|
||||
REQUIRE(n == 1);
|
||||
REQUIRE(o == false);
|
||||
|
||||
std::tie(p, n, o) = CommandLineOptions::ParseDeprecated({"", "1955", "6"});
|
||||
REQUIRE(p == 1955);
|
||||
REQUIRE(n == 6);
|
||||
REQUIRE(o == false);
|
||||
|
||||
std::tie(p, n, o) =
|
||||
CommandLineOptions::ParseDeprecated({"", "1955", "6", "1"});
|
||||
REQUIRE(p == 1955);
|
||||
REQUIRE(n == 6);
|
||||
REQUIRE(o == true);
|
||||
}
|
||||
} // namespace sls
|
@ -90,4 +90,5 @@ MacAddr InterfaceNameToMac(const std::string &inf);
|
||||
IpAddr InterfaceNameToIp(const std::string &ifn);
|
||||
void validatePortNumber(uint16_t port);
|
||||
void validatePortRange(uint16_t startPort, int numPorts);
|
||||
void setupSignalHandler(int signal, void (*handler)(int));
|
||||
} // namespace sls
|
||||
|
@ -1,11 +1,12 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#include "sls/network_utils.h"
|
||||
#include "sls/sls_detector_exceptions.h"
|
||||
|
||||
#include "sls/network_utils.h"
|
||||
#include <algorithm>
|
||||
#include <arpa/inet.h>
|
||||
#include <cassert>
|
||||
#include <csignal>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ifaddrs.h>
|
||||
@ -205,17 +206,27 @@ MacAddr InterfaceNameToMac(const std::string &inf) {
|
||||
}
|
||||
|
||||
void validatePortNumber(uint16_t port) {
|
||||
// random local port. might work if internal = bad practise
|
||||
if (port == 0) {
|
||||
throw RuntimeError("Invalid port number. Must be between 1 - 65535.");
|
||||
if (port < 1024 || port > std::numeric_limits<uint16_t>::max()) {
|
||||
throw RuntimeError(std::string("Invalid port number ") +
|
||||
std::to_string(port) +
|
||||
". Must be between 1024 - 65535.");
|
||||
}
|
||||
}
|
||||
|
||||
void validatePortRange(uint16_t startPort, int numPorts) {
|
||||
validatePortNumber(startPort);
|
||||
if ((startPort + numPorts) > std::numeric_limits<uint16_t>::max()) {
|
||||
throw RuntimeError("Invalid port range. Must be between 1 - 65535.");
|
||||
}
|
||||
validatePortNumber(startPort + numPorts - 1);
|
||||
}
|
||||
|
||||
void setupSignalHandler(int signal, void (*handler)(int)) {
|
||||
// Catch signal SIGINT to close files and call destructors properly
|
||||
struct sigaction sa {};
|
||||
sa.sa_handler = handler;
|
||||
sigemptyset(&sa.sa_mask); // dont block additional signals
|
||||
sa.sa_flags = 0;
|
||||
if (sigaction(signal, &sa, nullptr) == -1) {
|
||||
throw RuntimeError("Could not set handler for " +
|
||||
std::string(strsignal(signal)));
|
||||
}
|
||||
}
|
||||
} // namespace sls
|
||||
|
Reference in New Issue
Block a user