Added and improved some error handling.
authorBjoern Sikora <bjoern.sikora@intra2net.com>
Mon, 10 Aug 2009 14:35:06 +0000 (16:35 +0200)
committerBjoern Sikora <bjoern.sikora@intra2net.com>
Mon, 10 Aug 2009 14:35:06 +0000 (16:35 +0200)
src/config.cpp
src/logger.cpp
src/logger.h
src/main.cpp
src/updater.cpp
src/updater.h

index 392e5cf..b5f60a5 100644 (file)
@@ -105,14 +105,11 @@ Config::~Config()
 
 /**
  * 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)
@@ -128,8 +125,7 @@ int Config::serialize_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() )
     {
@@ -148,6 +144,11 @@ int Config::serialize_services()
 
         ofs.close();
     }
+    else
+    {
+        Log->print_error_opening_rw(OBJECT_FILE);
+        return -1;
+    }
 
     Log->print_serialized_objects_success();
 
@@ -155,32 +156,51 @@ int Config::serialize_services()
 }
 
 
+/**
+ * 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 )
                 {
@@ -193,12 +213,12 @@ int Config::deserialize_services()
                 }
             }
         }
-        //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;
@@ -361,7 +381,7 @@ int Config::load_service_config_file(const string& full_filename)
     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;
@@ -405,7 +425,7 @@ int Config::load_main_config_file(const string& full_filename)
     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;
@@ -521,6 +541,12 @@ void Config::delete_services()
         service.reset();
     }
     Services.clear();
+
+    BOOST_FOREACH( Service::Ptr service, OldServices )
+    {
+        service.reset();
+    }
+    OldServices.clear();
 }
 
 
index e3499b2..f8d936e 100644 (file)
@@ -173,6 +173,17 @@ void Logger::print_cmd_parsed()
 }
 
 
+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.
@@ -207,7 +218,7 @@ void Logger::print_conf_not_loaded(const string& 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 )
     {
@@ -219,6 +230,21 @@ void Logger::print_error_opening(const string& filename)
 
 
 /**
+ * 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.
  */
@@ -504,12 +530,12 @@ void Logger::print_caught_sighup()
 /**
  * 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());
     }
 }
@@ -604,5 +630,55 @@ void Logger::print_service_object(const string& message, const string& protocol,
  */
 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());
+    }
 }
index caf7083..eb1fa29 100644 (file)
@@ -55,6 +55,8 @@ public:
 
     void print_cmd_parsed();
 
+    void print_conf_files_parsed();
+
     void print_destructor_call(const std::string&);
 
     void print_constructor_call(const std::string&);
@@ -73,7 +75,9 @@ public:
 
     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&);
 
@@ -99,7 +103,7 @@ public:
 
     void print_caught_sighup();
 
-    void print_error_setting_signal();
+    void print_error_setting_signal(const std::string&);
 
     void print_init_log_facility();
 
@@ -112,6 +116,12 @@ public:
     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
index 2236b77..bd354b2 100644 (file)
@@ -76,14 +76,20 @@ int check_for_running_process()
  * 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;
 }
 
 
@@ -97,7 +103,11 @@ void terminate(int param)
 
     // 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);
 }
@@ -122,7 +132,8 @@ void switch_to_offline(int param)
 void reload_config(int param)
 {
     updater->get_logger()->print_caught_sighup();
-    updater->reload_config();
+    if ( updater->reload_config() != 0 )
+        exit(-1);
     is_online = true;
 }
 
@@ -135,13 +146,22 @@ int init_signals()
     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;
 }
@@ -160,28 +180,23 @@ int main(int argc, char *argv[])
     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 )
     {
@@ -190,12 +205,17 @@ int main(int argc, char *argv[])
         {
             // 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;
         }
@@ -221,8 +241,9 @@ int main(int argc, char *argv[])
     }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;
 }
index 94c6e00..83bf3ed 100644 (file)
@@ -46,7 +46,7 @@ int Updater::init_config_from_cmd(int argc, char *argv[])
 {
     // 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();
@@ -65,7 +65,7 @@ int Updater::init_config_from_files()
 {
     // 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.
@@ -73,9 +73,10 @@ int Updater::init_config_from_files()
 
     // 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;
 }
 
@@ -103,10 +104,11 @@ Logger::Ptr Updater::get_logger()
 /**
  * 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();
@@ -115,8 +117,10 @@ void Updater::reload_config()
     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;
 }
 
 
index cb5371d..13bec10 100644 (file)
@@ -42,7 +42,7 @@ public:
 
     Logger::Ptr get_logger();
 
-    void reload_config();
+    int reload_config();
 
     void init_log_facility();
 };