Fix 'occurred' typo
[bpdyndnsd] / src / updater.cpp
index c7e6fe0..7c3b021 100644 (file)
@@ -7,54 +7,37 @@
  * @license GPLv2
 */
 
-#include "updater.h"
+#include "updater.hpp"
+
+#include "serviceholder.hpp"
 
-#include "serviceholder.h"
-#include "dhs.h"
-#include "ods.h"
-#include "dyndns.h"
-#include "dyns.h"
-#include "easydns.h"
-#include "tzo.h"
-#include "zoneedit.h"
 
 #include <boost/foreach.hpp>
+#include <boost/serialization/export.hpp>
 
 
-// Following boost macros are needed for serialization of derived classes through a base class pointer (Service *).
-BOOST_CLASS_EXPORT_GUID(ODS, "ODS")
-BOOST_CLASS_EXPORT_GUID(DHS, "DHS")
-BOOST_CLASS_EXPORT_GUID(DYNS, "DYNS")
-BOOST_CLASS_EXPORT_GUID(DYNDNS, "DYNDNS")
-BOOST_CLASS_EXPORT_GUID(EASYDNS, "EASYDNS")
-BOOST_CLASS_EXPORT_GUID(TZO, "TZO")
-BOOST_CLASS_EXPORT_GUID(ZONEEDIT, "ZONEEDIT")
+using namespace std;
 
 
-namespace fs = boost::filesystem;
+/// 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;
 
-using namespace std;
 
 /**
  * Default constructor which initializes the member Conf.
  */
 Updater::Updater()
-    : IPHelp(new IPHelper)
+    : IPAddrHelp(new IPAddrHelper)
 {
     // Initialize program wide Logger, at this point we don't know where to log and with which loglevel.
-    Logger::Ptr _log(new Logger);
-    Log = _log;
-    _log.reset();
+    Log = Logger::Ptr(new Logger);
 
     // initialize Serviceholder
-    Serviceholder::Ptr _serviceholder(new Serviceholder(Log));
-    ServiceHolder = _serviceholder;
-    _serviceholder.reset();
+    ServiceHolder = Serviceholder::Ptr(new Serviceholder(Log));
 
     // initialize Config
-    Config::Ptr _config(new Config(Log,ServiceHolder));
-    Conf = _config;
-    _config.reset();
+    Conf = Config::Ptr(new Config(Log,ServiceHolder));
 }
 
 
@@ -105,6 +88,9 @@ int Updater::reload_config()
     // 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;
@@ -123,7 +109,7 @@ int Updater::reload_config()
  * @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)
@@ -140,9 +126,9 @@ int Updater::init_config_from_cmd(int argc, char *argv[])
 
 /**
  * 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 )
@@ -164,7 +150,7 @@ int Updater::init_config_from_files()
 
 /**
  * Init all Helper classes
- * @return 
+ * @return
  */
 int Updater::init_helper_classes()
 {
@@ -182,10 +168,21 @@ int Updater::init_helper_classes()
  */
 int Updater::init_ip_helper()
 {
-    // initialize IPHelper
-    IPHelper::Ptr _iphelp(new IPHelper(Log,Conf->get_webcheck_ip_url(),Conf->get_webcheck_ip_url_alt(),Conf->get_enable_ipv6(),Conf->get_proxy(),Conf->get_proxy_port()));
-    IPHelp = _iphelp;
-    _iphelp.reset();
+    // 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;
 }
@@ -214,51 +211,104 @@ Logger::Ptr Updater::get_logger() const
 /**
  * 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(),Conf->get_external_warning_log(),Conf->get_external_warning_level());
+    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
 {
+    // Get all services from the ServiceHolder.
     list<Service::Ptr> services = ServiceHolder->get_services();
 
-    string ip = IPHelp->get_actual_ip();
+    // 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);
+    }
 
-    if ( !ip.empty() )
+    BOOST_FOREACH(Service::Ptr &service, services )
     {
-        BOOST_FOREACH(Service::Ptr &service, services )
+        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() )
         {
-            string dns_recheck_ip = ip;
-            int current_time = time(NULL);
+            Log->print_dns_lookup_failed(changed_to_online, hostname);
+            continue;
+        }
 
-            int lastupdated = 0;
-            if ( service->get_last_updates()->size() > 0 )
-                lastupdated = service->get_last_updates()->front();
+        // 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;
+        }
 
-            // If the dns cache ttl is expired or the service is updated for the first time, then get the actual ip of the dns record (this should be the IP in the last update)
-            if ( ((lastupdated != 0) && ((lastupdated + service->get_dns_cache_ttl()) < current_time)) || (lastupdated == 0) )
+        // 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
             {
-                Log->print_recheck_dns_entry(service->get_hostname(),lastupdated,service->get_dns_cache_ttl(),current_time);
-                string _dns_recheck_ip = IPHelp->dns_query(service->get_hostname());
-                Log->print_cached_dns_entry(service->get_hostname(), _dns_recheck_ip, service->get_actual_ip());
-                if (!_dns_recheck_ip.empty())
-                    dns_recheck_ip = _dns_recheck_ip;
+                // 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);
             }
 
-            // In case the local hosts IP (ip) differ from the IP set in the last update (actual_ip) or
-            // the IP of the dns record (dns_recheck_ip) differs from the IP of the local host (ip)
-            // then perform an update. This implies that the update is not performed if actual_ip == dns_recheck_ip.
-            // Special case when latupdated == 0 then only perform the update if dns_rechek_ip differs from ip
-            if ( ((service->get_actual_ip() != ip) && (lastupdated != 0)) || (dns_recheck_ip != ip)  )
-                service->update(ip,current_time);
-            else if ( (service->get_actual_ip() != ip) && (lastupdated == 0)  )
-                service->set_actual_ip(ip);
+            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);
+            }
         }
     }
 }