Implemented first part of http proxy ability.
[bpdyndnsd] / src / updater.cpp
1 /** @file
2  * @brief The updater class implementation. This class implements the updater logic.
3  *
4  *
5  *
6  * @copyright Intra2net AG
7  * @license GPLv2
8 */
9
10 #include "updater.h"
11
12 #include "serviceholder.h"
13 #include "dhs.h"
14 #include "ods.h"
15
16 #include <boost/foreach.hpp>
17
18
19 // Following boost macros are needed for serialization of derived classes through a base class pointer (Service *).
20 BOOST_CLASS_EXPORT_GUID(ODS, "ODS")
21 BOOST_CLASS_EXPORT_GUID(DHS, "DHS")
22
23 namespace fs = boost::filesystem;
24
25 using namespace std;
26
27 /**
28  * Default constructor which initializes the member Conf.
29  */
30 Updater::Updater()
31     : IPHelp(new IPHelper)
32 {
33     // Initialize program wide Logger, at this point we don't know where to log and with which loglevel.
34     Logger::Ptr _log(new Logger);
35     Log = _log;
36     _log.reset();
37
38     // initialize Serviceholder
39     Serviceholder::Ptr _serviceholder(new Serviceholder(Log));
40     ServiceHolder = _serviceholder;
41     _serviceholder.reset();
42
43     // initialize Config
44     Config::Ptr _config(new Config(Log,ServiceHolder));
45     Conf = _config;
46     _config.reset();
47 }
48
49
50 /**
51  * Default destructor.
52  */
53 Updater::~Updater()
54 {
55 }
56
57
58 /**
59  * Parse the command line arguments and initialize corresponding options.
60  * @param argc Number command line arguments.
61  * @param argv[] Array with arguments.
62  * @return 0 if cmd options successfully parsed, 1 if usage or version.
63  */
64 int Updater::init_config_from_cmd(int argc, char *argv[])
65 {
66     // Load the command line parameters
67     if( Conf->parse_cmd_line( argc, argv) != 0)
68         return -1;
69
70     // If we have loaded the cmd options we need to init the log facility immediately in case debugging is enabled from cmd.
71     init_log_facility();
72
73     // successful parsed
74     Log->print_cmd_parsed();
75     return 0;
76 }
77
78
79 /**
80  * Load the main config and the service definition files in config path.
81  * @return 0 if all is fine, 
82  */
83 int Updater::init_config_from_files()
84 {
85     // Load the main and service config files in config path
86     if ( Conf->load_config_from_files() != 0 )
87         return -1;
88
89     // Re-init log facility, perhaps new config file options for logger are set.
90     // These config file options will only overwrite the cmd options if the SIGHUP (reload config) is caught.
91     init_log_facility();
92
93     // Here we are. All Service Objects should be initialized, so it is time to deserialize the old service objects and compare them.
94     if ( ServiceHolder->deserialize_services() != 0 )
95         return -1;
96
97     // successful loaded
98     Log->print_conf_files_parsed();
99     return 0;
100 }
101
102
103 /**
104  * Getter for member Config.
105  * @return Member Config.
106  */
107 Config::Ptr Updater::get_config() const
108 {
109     return Conf;
110 }
111
112
113 /**
114  * Getter for member Logger.
115  * @return Member Logger.
116  */
117 Logger::Ptr Updater::get_logger() const
118 {
119     return Log;
120 }
121
122
123 /**
124  * Init the IPHelp member with needed values.
125  * @return 0 if all is fine, -1 otherwise.
126  */
127 int Updater::init_ip_helper()
128 {
129     // initialize IPHelper
130     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()));
131     IPHelp = _iphelp;
132     _iphelp.reset();
133
134     return 0;
135 }
136
137
138 /**
139  * Reloading the config. Delete all Service objects and then init new Service objects from config files.
140  */
141 int Updater::reload_config()
142 {
143     // serialize all service objects
144     if ( ServiceHolder->serialize_services() != 0 )
145         return -1;
146
147     // delete all service objects
148     ServiceHolder->delete_services();
149
150     // delete the actual Variables_map, perhaps with old cmd options which would overwrite new config file options.
151     Conf->delete_variables_map();
152
153     // load only config files
154     if ( init_config_from_files() != 0 )
155         return -1;
156
157     return 0;
158 }
159
160
161 /**
162  * Initialize the logging facility with loglevel and syslog.
163  */
164 void Updater::init_log_facility()
165 {
166     Log->set_log_facility(Conf->get_loglevel(),Conf->get_syslog());
167     Log->print_init_log_facility();
168 }
169
170
171 /**
172  * Update all configured services.
173  */
174 void Updater::update_services()
175 {
176     list<Service::Ptr> services = ServiceHolder->get_services();
177
178     string ip = IPHelp->get_actual_ip();
179
180     if ( !ip.empty() )
181     {
182         BOOST_FOREACH(Service::Ptr &service, services )
183         {
184             string dns_recheck_ip = ip;
185             int current_time = time(NULL);
186
187             int lastupdated = 0;
188             if ( service->get_last_updates()->size() > 0 )
189                 lastupdated = service->get_last_updates()->front();
190
191             // If the dns cache ttl is expired, then get the actual ip of the dns record (this should be the IP in the last update)
192             if ( (lastupdated != 0) && ((lastupdated + service->get_dns_cache_ttl()) < current_time) )
193             {
194                 Log->print_recheck_dns_entry(service->get_hostname(),lastupdated,service->get_dns_cache_ttl(),current_time);
195                 string _dns_recheck_ip = IPHelp->dns_query(service->get_hostname());
196                 Log->print_cached_dns_entry(service->get_hostname(), _dns_recheck_ip, service->get_actual_ip());
197                 if (!_dns_recheck_ip.empty())
198                     dns_recheck_ip = _dns_recheck_ip;
199             }
200
201             // In case the local hosts IP (ip) differ from the IP set in the last update (actual_ip) or
202             // the IP of the dns record (dns_recheck_ip) differs from the IP of the local host (ip)
203             // then perform an update. This implies that the update is not performed if actual_ip == dns_recheck_ip.
204             if ( (service->get_actual_ip() != ip) || (dns_recheck_ip != ip)  )
205                 service->update(ip,current_time);
206         }
207     }
208 }
209
210
211 /**
212  * Getter for member ServiceHolder.
213  * @return ServiceHolder
214  */
215 Serviceholder::Ptr Updater::get_service_holder() const
216 {
217     return ServiceHolder;
218 }