mirror of
				https://github.com/gnss-sdr/gnss-sdr
				synced 2025-10-31 07:13:03 +00:00 
			
		
		
		
	Add some basic configuration checks
Avoid some segmentation faults caused by ill-formatted configuration files
This commit is contained in:
		| @@ -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); | ||||
| } | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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,6 +145,8 @@ 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 | ||||
|     if (well_formatted_configuration_) | ||||
|         { | ||||
|             try | ||||
|                 { | ||||
|                     flowgraph_ = std::make_shared<GNSSFlowgraph>(configuration_, control_queue_); | ||||
| @@ -112,6 +155,12 @@ void ControlThread::init() | ||||
|                 { | ||||
|                     std::cout << "Caught bad lexical cast with error " << e.what() << '\n'; | ||||
|                 } | ||||
|         } | ||||
|     else | ||||
|         { | ||||
|             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"; | ||||
|         } | ||||
| } | ||||
|   | ||||
| @@ -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_; | ||||
|   | ||||
| @@ -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)) | ||||
|   | ||||
| @@ -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(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Carles Fernandez
					Carles Fernandez