/**
* This function serializes all Service objects in Services and OldServices (where the update Timeout isn't expired) into a specified file.
- * @return 0 if all is fine, -1 otherwise.
+ * @return 0 if all is fine, -1 if output file could not be opened for reading or error while serializing.
*/
int Config::serialize_services()
{
- //TODO: error handling
-
- // First of all we have to put all Service objects in a Serviceholder object.
-
+ // Put Services and OldServices into Serviceholder.
Serviceholder::Ptr service_holder(new Serviceholder());
BOOST_FOREACH(Service::Ptr service, Services)
service_holder->add_service(service);
}
- // Then we can serialize this separate Object into one file.
-
+ // Serialize Serviceholder into file.
ofstream ofs(OBJECT_FILE);
if ( ofs.is_open() )
{
ofs.close();
}
+ else
+ {
+ Log->print_error_opening_rw(OBJECT_FILE);
+ return -1;
+ }
Log->print_serialized_objects_success();
}
+/**
+ * This function de-serializes the Serviceholder (containing Services) from the object file.
+ * @return 0 if all is fine, -1 if object file couldn't be opened for reading or error while de-serializing.
+ */
int Config::deserialize_services()
{
- // TODO: error handling
- // TODO: redefine algorithm, to avoid tripple FOREACHes ;-)
+ // test if OBJECT_FILE exists
+ fs::path object_file = fs::system_complete(fs::path(OBJECT_FILE));
+ if ( !fs::exists(object_file) )
+ {
+ // There is no object file, possibly first program start, continue without recovering old Services' state.
+ Log->print_no_object_file(OBJECT_FILE);
+ return 0;
+ }
ifstream ifs(OBJECT_FILE);
if ( ifs.is_open() )
{
+ // deserialize Serviceholder
Serviceholder* _service_holder;
- boost::archive::text_iarchive ia(ifs);
- ia >> _service_holder; // ends up in default constructor call for Serviceholder
+ try
+ {
+ boost::archive::text_iarchive ia(ifs);
+ ia >> _service_holder; // ends up in default constructor call for Serviceholder
+ }
+ catch( boost::archive::archive_exception e )
+ {
+ Log->print_exception_deserialize(e.what());
+ ifs.close();
+ return -1;
+ }
Serviceholder::Ptr service_holder(_service_holder);
ifs.close();
+ // Get the list of old Services from de-serialized Serviceholder object.
list<Service::Ptr> _old_services = service_holder->get_hold_services();
+ // Put all de-serialized Services into OldServices member and
+ // compare new Services (generated from config file and cmd) with old Services (de-serialized from object file)
+ // if identical Service was found, adopt the value from old Service to recover Services' state.
BOOST_FOREACH(Service::Ptr old_service, _old_services)
{
- // Put the deserialized service into the Old_service member list.
OldServices.push_back(old_service);
Log->print_service_object("Deserialized following Service object:", old_service->get_protocol(), old_service->get_hostname(), old_service->get_login() ,old_service->get_password() ,old_service->get_actual_ip(), old_service->get_lastupdated());
- }
-
- BOOST_FOREACH(Service::Ptr service, Services)
- {
- BOOST_FOREACH(Service::Ptr old_service, OldServices)
+ BOOST_FOREACH(Service::Ptr service, Services)
{
if ( *service == *old_service )
{
}
}
}
- //TODO: debug output of OldServices (is element really removed from list if values were adopted???)
Log->print_deserialized_objects_success();
}
else
{
- Log->print_error_opening(OBJECT_FILE);
+ Log->print_error_opening_r(OBJECT_FILE);
+ return -1;
}
return 0;
else
{
// error opening service config file for reading
- Log->print_error_opening(full_filename);
+ Log->print_error_opening_r(full_filename);
return 1;
}
return 0;
else
{
// error opening main config file for reading
- Log->print_error_opening(full_filename);
+ Log->print_error_opening_r(full_filename);
return 1;
}
return 0;
service.reset();
}
Services.clear();
+
+ BOOST_FOREACH( Service::Ptr service, OldServices )
+ {
+ service.reset();
+ }
+ OldServices.clear();
}
}
+void Logger::print_conf_files_parsed()
+{
+ if ( 1 <= Loglevel )
+ {
+ ostringstream msg;
+ msg << "Config files successfully parsed." << endl;
+ log_notice(msg.str());
+ }
+}
+
+
/**
* Prints out the successful parsing of the config files.
* @param config_path The specified config path.
* A file could not be opened for reading.
* @param filename The filename.
*/
-void Logger::print_error_opening(const string& filename)
+void Logger::print_error_opening_r(const string& filename)
{
if ( 0 <= Loglevel )
{
/**
+ * A file could not be opened for writing.
+ * @param filename The filename.
+ */
+void Logger::print_error_opening_rw(const string& filename)
+{
+ if ( 0 <= Loglevel )
+ {
+ ostringstream msg;
+ msg << "Error opening file for writing: " << filename << endl;
+ log_error(msg.str());
+ }
+}
+
+
+/**
* Desctructor of specified class was called.
* @param _class Name of the class.
*/
/**
* Error while setting signal handler.
*/
-void Logger::print_error_setting_signal()
+void Logger::print_error_setting_signal(const string& signal)
{
if ( 0 <= Loglevel )
{
ostringstream msg;
- msg << "Error while setting signal handler." << endl;
+ msg << "Error while setting signal handler for: " << signal << endl;
log_error(msg.str());
}
}
*/
void Logger::print_exception_serialize(const string& exception)
{
- cout << "Error while trying to serialize Serviceholder object: " << exception << endl;
+ if ( 0 <= Loglevel )
+ {
+ ostringstream msg;
+ msg << "Error while trying to serialize Serviceholder object: " << exception << endl;
+ log_error(msg.str());
+ }
+}
+
+
+/**
+ * Caught exception while de-serialize.
+ * @param exception Exception message.
+ */
+void Logger::print_exception_deserialize(const std::string& exception)
+{
+ if ( 0 <= Loglevel )
+ {
+ ostringstream msg;
+ msg << "Error while trying to de-serialize Serviceholder object: " << exception << endl;
+ log_error(msg.str());
+ }
+}
+
+
+/**
+ * Child couldn't be killed by parent.
+ * @param pid Pid of the child.
+ */
+void Logger::print_error_kill_child(const int pid)
+{
+ if ( 0 <= Loglevel )
+ {
+ ostringstream msg;
+ msg << "Could not kill child process with PID: " << pid << endl;
+ log_error(msg.str());
+ }
+}
+
+
+/**
+ * There is no object file.
+ * @param object_file The object file.
+ */
+void Logger::print_no_object_file(const std::string& object_file)
+{
+ if ( 1 <= Loglevel )
+ {
+ ostringstream msg;
+ msg << "There is no object file: " << object_file << ". Continue without recovering state from old services!" << endl;
+ log_warning(msg.str());
+ }
}
void print_cmd_parsed();
+ void print_conf_files_parsed();
+
void print_destructor_call(const std::string&);
void print_constructor_call(const std::string&);
void print_unknown_main_conf_option(const std::string&);
- void print_error_opening(const std::string&);
+ void print_error_opening_r(const std::string&);
+
+ void print_error_opening_rw(const std::string&);
void print_error_config_path(const std::string&);
void print_caught_sighup();
- void print_error_setting_signal();
+ void print_error_setting_signal(const std::string&);
void print_init_log_facility();
void print_service_object(const std::string&, const std::string&, const std::string&, const std::string&, const std::string&, const std::string&, const int);
void print_exception_serialize(const std::string&);
+
+ void print_exception_deserialize(const std::string&);
+
+ void print_error_kill_child(const int);
+
+ void print_no_object_file(const std::string&);
};
#endif
* Writes the pid into the pidfile.
* @param pid The process's pid.
*/
-void write_pidfile(int pid)
+int write_pidfile(int pid)
{
ofstream pidfile(PIDFILE);
if ( pidfile.is_open() )
{
pidfile << pid << endl;
}
+ else
+ {
+ updater->get_logger()->print_error_opening_rw(PIDFILE);
+ return -1;
+ }
pidfile.close();
+ return 0;
}
// unfortunately we can't call serialize_services in any destructor
// cause some singleton are already destroyed !?!
- updater->get_config()->serialize_services();
+ if ( updater->get_config()->serialize_services() != 0 )
+ {
+ updater.reset();
+ exit(-1);
+ }
updater.reset();
exit(0);
}
void reload_config(int param)
{
updater->get_logger()->print_caught_sighup();
- updater->reload_config();
+ if ( updater->reload_config() != 0 )
+ exit(-1);
is_online = true;
}
sighandler_t ret_val;
ret_val = signal(SIGTERM,terminate);
if ( ret_val == SIG_ERR )
+ {
+ updater->get_logger()->print_error_setting_signal("SIGTERM");
return -1;
+ }
ret_val = signal(SIGUSR1,switch_to_offline);
if ( ret_val == SIG_ERR )
+ {
+ updater->get_logger()->print_error_setting_signal("SIGUSR1");
return -1;
+ }
ret_val = signal(SIGHUP,reload_config);
if ( ret_val == SIG_ERR )
+ {
+ updater->get_logger()->print_error_setting_signal("SIGHUP");
return -1;
+ }
return 0;
}
updater = _updater;
_updater.reset();
- // TODO: Why do errors return zero exit status?
-
// load the cmd options
if ( updater->init_config_from_cmd(argc,argv) != 0 )
- return 0;
+ return -1;
// load the config and service files
if ( updater->init_config_from_files() != 0 )
- return 0;
+ return -1;
// open pidfile and check for running process
if ( check_for_running_process() != 0)
- return 0;
+ return -1;
// init signal handling
if ( init_signals() != 0)
- {
- updater->get_logger()->print_error_setting_signal();
- return 0;
- }
+ return -1;
- // initialize daemon mode if configured
+ // initialize daemon mode if configured TODO: into separate function
updater->get_logger()->print_daemon_mode(updater->get_config()->get_daemon_mode());
if ( updater->get_config()->get_daemon_mode() == 1 )
{
{
// error fork
updater->get_logger()->print_error_fork();
- return 0;
+ return -1;
}
else if ( pid > 0 )
{
// parent
- write_pidfile(pid);
+ if ( write_pidfile(pid) != 0 )
+ {
+ if ( kill(pid,SIGTERM) != 0 )
+ updater->get_logger()->print_error_kill_child(pid);
+ return -1;
+ }
updater->get_logger()->print_runnig_as_daemon(pid);
return 0;
}
}while ( updater->get_config()->get_daemon_mode() == 1 );
- // serialize services
- updater->get_config()->serialize_services();
+ // serialize services to save their actual status
+ if ( updater->get_config()->serialize_services() != 0 )
+ return -1;
return 0;
}
{
// Load the command line parameters
if( Conf->parse_cmd_line( argc, argv ) != 0)
- return 1;
+ return -1;
// If we have loaded the cmd options we need to init the log facility immediately in case debugging is enabled from cmd.
init_log_facility();
{
// Load the main and service config files in config path
if ( Conf->load_config_from_files() != 0 )
- return 1;
+ return -1;
// Re-init log facility, perhaps new config file options for logger are set.
// These config file options will only overwrite the cmd options if the SIGHUP (reload config) is caught.
// Here we are. All Service Objects should be initialized, so it is time to deserialize the old service objects and compare them.
if ( Conf->deserialize_services() != 0 )
- return 1;
+ return -1;
// successful loaded
+ Log->print_conf_files_parsed();
return 0;
}
/**
* Reloading the config. Delete all Service objects and then init new Service objects from config files.
*/
-void Updater::reload_config()
+int Updater::reload_config()
{
// serialize all service objects
- Conf->serialize_services();
+ if ( Conf->serialize_services() != 0 )
+ return -1;
// delete all service objects
Conf->delete_services();
Conf->delete_variables_map();
// load only config files
- // TODO: Error handling?
- init_config_from_files();
+ if ( init_config_from_files() != 0 )
+ return -1;
+
+ return 0;
}
Logger::Ptr get_logger();
- void reload_config();
+ int reload_config();
void init_log_facility();
};