* @license GPLv2
*/
-#include "updater.h"
+#include "updater.hpp"
+
+#include "serviceholder.hpp"
+
+
+#include <boost/foreach.hpp>
+#include <boost/serialization/export.hpp>
+
using namespace std;
+
+/// Server error threshold: When the host IP is not current, the DNS TTL expired
+/// and we already sent an update.
+const int ServerErrorTTLExpiredThreshold = 15 * 60;
+
+
/**
* Default constructor which initializes the member Conf.
*/
Updater::Updater()
+ : IPAddrHelp(new IPAddrHelper)
{
// Initialize program wide Logger, at this point we don't know where to log and with which loglevel.
- LoggerPtr _log(new Logger);
- Log = _log;
+ Log = Logger::Ptr(new Logger);
+
+ // initialize Serviceholder
+ ServiceHolder = Serviceholder::Ptr(new Serviceholder(Log));
// initialize Config
- ConfigPtr _config(new Config(Log));
- Conf = _config;
+ Conf = Config::Ptr(new Config(Log,ServiceHolder));
}
}
+
+/**
+ * Load config and initialize helper classes.
+ * @param argc Number of arguments in array
+ * @param argv Array with cmd options
+ */
+int Updater::load_config(int argc, char *argv[])
+{
+ // load the cmd options
+ if ( init_config_from_cmd(argc,argv) != 0 )
+ return -1;
+
+ // load the config and service files
+ if ( init_config_from_files() != 0 )
+ return -1;
+
+ // init all helper classes
+ if ( init_helper_classes() != 0 )
+ return -1;
+
+ return 0;
+}
+
+
+/**
+ * Reloading the config. Delete all Service objects and then init new Service objects from config files.
+ */
+int Updater::reload_config()
+{
+ // serialize all service objects
+ if ( ServiceHolder->serialize_services() != 0 )
+ return -1;
+
+ // delete all service objects
+ ServiceHolder->delete_services();
+
+ // delete the actual Variables_map, perhaps with old cmd options which would overwrite new config file options.
+ Conf->delete_variables_map();
+
+ // clear the external send messages.
+ Log->clear_external_send_messages();
+
+ // load only config files
+ if ( init_config_from_files() != 0 )
+ return -1;
+
+ // init all helper classes
+ if ( init_helper_classes() != 0 )
+ return -1;
+
+ return 0;
+}
+
+
/**
* Parse the command line arguments and initialize corresponding options.
* @param argc Number command line arguments.
* @param argv[] Array with arguments.
* @return 0 if cmd options successfully parsed, 1 if usage or version.
*/
-int Updater::init_config_from_cmd(int argc, char *argv[])
+int Updater::init_config_from_cmd(int argc, char *argv[]) const
{
// Load the command line parameters
- if( Conf->parse_cmd_line( argc, argv ) != 0)
- return 1;
+ if( Conf->parse_cmd_line( argc, argv) != 0)
+ 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 config and the service definition files in config path.
- * @return 0 if all is fine,
+ * @return 0 if all is fine,
*/
-int Updater::init_config_from_files()
+int Updater::init_config_from_files() const
{
// 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.
init_log_facility();
// 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;
+ if ( ServiceHolder->deserialize_services() != 0 )
+ return -1;
// successful loaded
+ Log->print_conf_files_parsed();
return 0;
}
/**
- * Getter for member Config.
- * @return Member Config.
+ * Init all Helper classes
+ * @return
*/
-ConfigPtr Updater::get_config()
+int Updater::init_helper_classes()
{
- return Conf;
+ // Initialize IPHelper
+ if ( init_ip_helper() != 0 )
+ return -1;
+
+ return 0;
}
/**
- * Getter for member Logger.
- * @return Member Logger.
+ * Init the IPHelp member with needed values.
+ * @return 0 if all is fine, -1 otherwise.
*/
-LoggerPtr Updater::get_logger()
+int Updater::init_ip_helper()
{
- return Log;
+ // Try to get deserialized IPAddrHelper from ServiceHolder
+ IPAddrHelper::Ptr _ip_addr_help = ServiceHolder->get_ip_addr_helper();
+ if ( _ip_addr_help.use_count() != 0 )
+ {
+ // Initialize IPHelper
+ IPAddrHelp = IPAddrHelper::Ptr( new IPAddrHelper( Log, Conf->get_webcheck_ip_url(), Conf->get_webcheck_ip_url_alt(), Conf->get_webcheck_interval(), _ip_addr_help->get_last_webcheck(), Conf->get_enable_ipv6(), Conf->get_proxy(), Conf->get_proxy_port() ) );
+ }
+ else
+ {
+ // IPAddrHelper from ServiceHolder was not declared, so init oen with LastWebcheck 0
+ IPAddrHelp = IPAddrHelper::Ptr( new IPAddrHelper( Log, Conf->get_webcheck_ip_url(), Conf->get_webcheck_ip_url_alt(), Conf->get_webcheck_interval(), (size_t)0, Conf->get_enable_ipv6(), Conf->get_proxy(), Conf->get_proxy_port() ) );
+ }
+
+ // Put the IPAddrHelper into ServiceHolder, so the LastWebcheck state will be serialized too.
+ ServiceHolder->set_ip_addr_helper(IPAddrHelp);
+
+ return 0;
}
/**
- * Reloading the config. Delete all Service objects and then init new Service objects from config files.
+ * Getter for member Config.
+ * @return Member Config.
*/
-void Updater::reload_config()
+Config::Ptr Updater::get_config() const
{
- // serialize all service objects
- Conf->serialize_services();
-
- // delete all service objects
- Conf->delete_services();
+ return Conf;
+}
- // delete the actual Variables_map, perhaps with old cmd options which would overwrite new config file options.
- Conf->delete_variables_map();
- // load only config files
- // TODO: Error handling?
- init_config_from_files();
+/**
+ * Getter for member Logger.
+ * @return Member Logger.
+ */
+Logger::Ptr Updater::get_logger() const
+{
+ return Log;
}
/**
* Initialize the logging facility with loglevel and syslog.
*/
-void Updater::init_log_facility()
+void Updater::init_log_facility() const
{
- Log->set_log_facility(Conf->get_loglevel(),Conf->get_syslog());
+ Log->set_log_facility(Conf->get_loglevel(),Conf->get_syslog(),Conf->get_external_warning_log(),Conf->get_external_warning_level(),Conf->get_external_log_only_once());
Log->print_init_log_facility();
+
+ Log->set_log_passwords(Conf->get_log_passwords());
}
/**
* Update all configured services.
+ * @param changed_to_online True if we just changed to online, false if we were already online
*/
-void Updater::update_services()
+void Updater::update_services(bool changed_to_online) const
{
- list<ServicePtr> services = this->Conf->get_services();
+ // Get all services from the ServiceHolder.
+ list<Service::Ptr> services = ServiceHolder->get_services();
- string ip = "192.168.1.1";
+ // Get the actual IP of this host.
+ string ip_host = IPAddrHelp->get_actual_ip(Conf->get_webcheck_enabled(), changed_to_online, Conf->get_wan_ip_override());
+ if ( ip_host.empty() )
+ {
+ Log->print_no_wan_ip(changed_to_online);
+ return;
+ } else
+ {
+ Log->print_external_wan_ip(changed_to_online, ip_host);
+ }
- BOOST_FOREACH(ServicePtr &service, services )
+ BOOST_FOREACH(Service::Ptr &service, services )
{
- service->update(ip);
+ string ip_last_update = service->get_actual_ip();
+ string hostname = service->get_hostname();
+ time_t current_time = time(NULL);
+
+ // Get the last update time of the service.
+ time_t lastupdated = service->get_last_update_time();
+
+ Log->print_check_service_update(hostname, current_time, lastupdated);
+
+ // Do a DNS Query for the dynamic hostname.
+ string ip_dns_recheck = IPAddrHelp->dns_query(hostname);
+
+ Log->print_cached_dns_entry(hostname, ip_dns_recheck, ip_last_update, ip_host);
+
+ // Test if the DNS-Record could not be found.
+ // If DNS-Record was not found but service was not activated, the hostname could be deactivated, offline or not existent. In this case try a ordinary update.
+ if ( ip_dns_recheck.empty() && service->get_activated() )
+ {
+ Log->print_dns_lookup_failed(changed_to_online, hostname);
+ continue;
+ }
+
+ // Test if the actual DNS-Record differs from the host's IP.
+ if (ip_host == ip_dns_recheck )
+ {
+ Log->print_no_update_needed(changed_to_online, hostname, ip_dns_recheck, ip_last_update, ip_host, lastupdated);
+ // No update needed
+ continue;
+ }
+
+ // Check if the IP set in last update differs from the actual host's ip.
+ if ( ip_last_update != ip_host )
+ {
+ // Update
+ if ( !ip_dns_recheck.empty() )
+ {
+ Log->print_update_service(hostname, ip_dns_recheck, ip_last_update, ip_host, lastupdated);
+ }
+ else
+ {
+ // Service gets updated the first time and no DNS-Record was found. This is either a initial update or the hostname is really not available.
+ Log->print_update_service(hostname, "<NO IP SET>", ip_last_update, ip_host, lastupdated);
+ }
+
+ service->update(ip_host, current_time, changed_to_online);
+ }
+ else
+ {
+ int dns_cache_ttl = service->get_dns_cache_ttl();
+
+ // Add server error threshold so we don't jam the server with updates for the same IP
+ // in case the server doesn't hand out the already sent IP via DNS
+ // (might indicate a server error).
+ dns_cache_ttl += ServerErrorTTLExpiredThreshold;
+
+ // Check if DNS Cache TTL is expired, if so, then update the same IP again.
+ if ( (lastupdated + dns_cache_ttl) < current_time )
+ {
+ // Update
+ Log->print_update_service_ttl_expired(hostname, ip_dns_recheck, ip_last_update, ip_host, lastupdated, dns_cache_ttl, current_time);
+ service->update(ip_host, current_time, changed_to_online);
+ }
+ else
+ {
+ // DNS cache TTL isn't expired
+ Log->print_update_service_ttl_not_expired(changed_to_online, hostname, ip_dns_recheck, ip_last_update, ip_host, lastupdated, dns_cache_ttl, current_time);
+ }
+ }
}
}
+
+
+/**
+ * Getter for member ServiceHolder.
+ * @return ServiceHolder
+ */
+Serviceholder::Ptr Updater::get_service_holder() const
+{
+ return ServiceHolder;
+}