Add some basic configuration checks

Avoid some segmentation faults caused by ill-formatted configuration files
This commit is contained in:
Carles Fernandez 2021-01-25 00:49:36 +01:00
parent a21c60ecb2
commit cd1c9e46ba
No known key found for this signature in database
GPG Key ID: 4C583C52B0C3877D
6 changed files with 132 additions and 4 deletions

View File

@ -81,3 +81,23 @@ int INIReader::ValueHandler(void* user, const char* section, const char* name,
reader->_values[MakeKey(section, name)] = value;
return 1;
}
bool INIReader::HasSection(const std::string& section) const
{
const std::string key = MakeKey(section, "");
auto pos = _values.lower_bound(key);
if (pos == _values.end())
{
return false;
}
// Does the key at the lower_bound pos start with "section"?
return pos->first.compare(0, key.length(), key) == 0;
}
bool INIReader::HasValue(const std::string& section, const std::string& name) const
{
std::string key = MakeKey(section, name);
return _values.count(key);
}

View File

@ -58,6 +58,12 @@ public:
//! Get an integer (long) value from INI file, returning default_value if not found.
int64_t GetInteger(const std::string& section, const std::string& name, int64_t default_value);
//! Return true if the given section exists (section must contain at least one name=value pair).
bool HasSection(const std::string& section) const;
//! Return true if a value exists with the given section and field names.
bool HasValue(const std::string& section, const std::string& name) const;
private:
static std::string MakeKey(const std::string& section, const std::string& name);
static int ValueHandler(void* user, const char* section, const char* name,

View File

@ -83,6 +83,41 @@ ControlThread::ControlThread()
{
configuration_ = std::make_shared<FileConfiguration>(FLAGS_c);
}
// Basic configuration checks
auto aux = std::dynamic_pointer_cast<FileConfiguration>(configuration_);
conf_file_has_section_ = aux->has_section();
conf_file_has_mandatory_globals_ = (configuration_->property("GNSS-SDR.internal_fs_sps", 0) == 0 ? false : true);
const std::string empty_implementation;
std::string src_impl = configuration_->property("SignalSource.implementation", empty_implementation);
int src_count = configuration_->property("Receiver.sources_count", 1);
if (src_impl.empty() && (src_count != 1))
{
int num_src = 0;
for (int i = 0; i < src_count; i++)
{
std::string src_impl_multiple = configuration_->property("SignalSource" + std::to_string(i) + ".implementation", empty_implementation);
if (!src_impl_multiple.empty())
{
num_src++;
}
}
if (num_src != src_count)
{
src_impl = std::string("");
}
}
conf_has_signal_sources_ = !src_impl.empty();
std::string pvt_impl = configuration_->property("PVT.implementation", empty_implementation);
conf_has_pvt_ = !pvt_impl.empty();
std::string obs_impl = configuration_->property("Observables.implementation", empty_implementation);
conf_has_observables_ = !obs_impl.empty();
well_formatted_configuration_ = conf_file_has_section_ && conf_file_has_mandatory_globals_ && conf_has_signal_sources_ && conf_has_observables_ && conf_has_pvt_;
restart_ = false;
init();
}
@ -91,6 +126,12 @@ ControlThread::ControlThread()
ControlThread::ControlThread(std::shared_ptr<ConfigurationInterface> configuration)
{
configuration_ = std::move(configuration);
conf_file_has_section_ = true;
conf_file_has_mandatory_globals_ = true;
conf_has_signal_sources_ = true;
conf_has_observables_ = true;
conf_has_pvt_ = true;
well_formatted_configuration_ = true;
restart_ = false;
init();
}
@ -104,14 +145,22 @@ void ControlThread::init()
// Instantiates a control queue, a GNSS flowgraph, and a control message factory
control_queue_ = std::make_shared<Concurrent_Queue<pmt::pmt_t>>();
cmd_interface_.set_msg_queue(control_queue_); // set also the queue pointer for the telecommand thread
try
if (well_formatted_configuration_)
{
flowgraph_ = std::make_shared<GNSSFlowgraph>(configuration_, control_queue_);
try
{
flowgraph_ = std::make_shared<GNSSFlowgraph>(configuration_, control_queue_);
}
catch (const boost::bad_lexical_cast &e)
{
std::cout << "Caught bad lexical cast with error " << e.what() << '\n';
}
}
catch (const boost::bad_lexical_cast &e)
else
{
std::cout << "Caught bad lexical cast with error " << e.what() << '\n';
flowgraph_ = nullptr;
}
stop_ = false;
processed_control_messages_ = 0;
applied_actions_ = 0;
@ -285,6 +334,11 @@ void ControlThread::event_dispatcher(bool &valid_event, pmt::pmt_t &msg)
int ControlThread::run()
{
// Connect the flowgraph
if (!flowgraph_)
{
print_help_at_exit();
return 0;
}
try
{
flowgraph_->connect();
@ -1145,3 +1199,37 @@ void ControlThread::keyboard_listener()
}
}
}
void ControlThread::print_help_at_exit() const
{
std::cerr << "Error: the configuration file is not well formatted\n";
if (!conf_file_has_section_)
{
std::cerr << " * The section label has not been found if the configuration file\n"
<< " Please add the [GNSS-SDR] label at the top of your configuration file\n"
<< " A configuration example is available at https://gnss-sdr.org/my-first-fix/\n";
return;
}
if (!conf_file_has_mandatory_globals_)
{
std::cerr << " * Have you forgotten to set the mandatory global parameter GNSS-SDR.internal_fs_sps in your conf file?\n"
<< " Documentation about this parameter at https://gnss-sdr.org/docs/sp-blocks/global-parameters/\n"
<< " A configuration example is available at https://gnss-sdr.org/my-first-fix/\n";
}
if (!conf_has_signal_sources_)
{
std::cerr << " * The configuration file must define at least one SignalSource.implementation\n"
<< " Documentation of SignalSource block implementations at https://gnss-sdr.org/docs/sp-blocks/signal-source/\n";
}
if (!conf_has_observables_)
{
std::cerr << " * The configuration file must define an Observables.implementation\n"
<< " Documentation of the Observables block at https://gnss-sdr.org/docs/sp-blocks/observables/\n";
}
if (!conf_has_pvt_)
{
std::cerr << " * The configuration file must define a PVT.implementation\n"
<< " Documentation of the PVT block at https://gnss-sdr.org/docs/sp-blocks/pvt/\n";
}
}

View File

@ -153,6 +153,7 @@ private:
void telecommand_listener();
void keyboard_listener();
void sysv_queue_listener();
void print_help_at_exit() const;
// default filename for assistance data
const std::string eph_default_xml_filename_ = "./gps_ephemeris.xml";
@ -203,6 +204,12 @@ private:
unsigned int applied_actions_;
int msqid_;
bool well_formatted_configuration_;
bool conf_file_has_section_;
bool conf_file_has_mandatory_globals_;
bool conf_has_signal_sources_;
bool conf_has_observables_;
bool conf_has_pvt_;
bool receiver_on_standby_;
bool stop_;
bool restart_;

View File

@ -60,6 +60,12 @@ void FileConfiguration::init()
}
bool FileConfiguration::has_section() const
{
return ini_reader_->HasSection("GNSS-SDR");
}
std::string FileConfiguration::property(std::string property_name, std::string default_value) const
{
if (overrided_->is_present(property_name))

View File

@ -63,6 +63,7 @@ public:
double property(std::string property_name, double default_value) const override;
void set_property(std::string property_name, std::string value) override;
bool is_present(const std::string& property_name) const;
bool has_section() const;
private:
void init();