Improved shared_pointer handling. Use swap instead of copy and reset().
[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 "service_dhs.h"
14 #include "service_ods.h"
15 #include "service_dyndns.h"
16 #include "service_dyns.h"
17 #include "service_easydns.h"
18 #include "service_tzo.h"
19 #include "service_zoneedit.h"
20 #include "service_gnudip.h"
21
22 #include <boost/foreach.hpp>
23
24
25 // Following boost macros are needed for serialization of derived classes through a base class pointer (Service *).
26 BOOST_CLASS_EXPORT_GUID(ServiceOds, "ServiceOds")
27 BOOST_CLASS_EXPORT_GUID(ServiceDhs, "ServiceDhs")
28 BOOST_CLASS_EXPORT_GUID(ServiceDyns, "ServiceDyns")
29 BOOST_CLASS_EXPORT_GUID(ServiceDyndns, "ServiceDyndns")
30 BOOST_CLASS_EXPORT_GUID(ServiceEasydns, "ServiceEasydns")
31 BOOST_CLASS_EXPORT_GUID(ServiceTzo, "ServiceTzo")
32 BOOST_CLASS_EXPORT_GUID(ServiceZoneedit, "ServiceZoneedit")
33 BOOST_CLASS_EXPORT_GUID(ServiceGnudip, "ServiceGnudip")
34
35
36 namespace fs = boost::filesystem;
37
38 using namespace std;
39
40 /**
41  * Default constructor which initializes the member Conf.
42  */
43 Updater::Updater()
44     : IPAddrHelp(new IPAddrHelper)
45 {
46     // Initialize program wide Logger, at this point we don't know where to log and with which loglevel.
47     Logger::Ptr _log(new Logger);
48     Log.swap(_log);
49
50     // initialize Serviceholder
51     Serviceholder::Ptr _serviceholder(new Serviceholder(Log));
52     ServiceHolder.swap(_serviceholder);
53
54     // initialize Config
55     Config::Ptr _config(new Config(Log,ServiceHolder));
56     Conf.swap(_config);
57 }
58
59
60 /**
61  * Default destructor.
62  */
63 Updater::~Updater()
64 {
65 }
66
67
68
69 /**
70  * Load config and initialize helper classes.
71  * @param argc Number of arguments in array
72  * @param argv Array with cmd options
73  */
74 int Updater::load_config(int argc, char *argv[])
75 {
76     // load the cmd options
77     if ( init_config_from_cmd(argc,argv) != 0 )
78         return -1;
79
80     // load the config and service files
81     if ( init_config_from_files() != 0 )
82         return -1;
83
84     // init all helper classes
85     if ( init_helper_classes() != 0 )
86         return -1;
87
88     return 0;
89 }
90
91
92 /**
93  * Reloading the config. Delete all Service objects and then init new Service objects from config files.
94  */
95 int Updater::reload_config()
96 {
97     // serialize all service objects
98     if ( ServiceHolder->serialize_services() != 0 )
99         return -1;
100
101     // delete all service objects
102     ServiceHolder->delete_services();
103
104     // delete the actual Variables_map, perhaps with old cmd options which would overwrite new config file options.
105     Conf->delete_variables_map();
106
107     // load only config files
108     if ( init_config_from_files() != 0 )
109         return -1;
110
111     // init all helper classes
112     if ( init_helper_classes() != 0 )
113         return -1;
114
115     return 0;
116 }
117
118
119 /**
120  * Parse the command line arguments and initialize corresponding options.
121  * @param argc Number command line arguments.
122  * @param argv[] Array with arguments.
123  * @return 0 if cmd options successfully parsed, 1 if usage or version.
124  */
125 int Updater::init_config_from_cmd(int argc, char *argv[])
126 {
127     // Load the command line parameters
128     if( Conf->parse_cmd_line( argc, argv) != 0)
129         return -1;
130
131     // If we have loaded the cmd options we need to init the log facility immediately in case debugging is enabled from cmd.
132     init_log_facility();
133
134     // successful parsed
135     Log->print_cmd_parsed();
136     return 0;
137 }
138
139
140 /**
141  * Load the main config and the service definition files in config path.
142  * @return 0 if all is fine, 
143  */
144 int Updater::init_config_from_files()
145 {
146     // Load the main and service config files in config path
147     if ( Conf->load_config_from_files() != 0 )
148         return -1;
149
150     // Re-init log facility, perhaps new config file options for logger are set.
151     // These config file options will only overwrite the cmd options if the SIGHUP (reload config) is caught.
152     init_log_facility();
153
154     // Here we are. All Service Objects should be initialized, so it is time to deserialize the old service objects and compare them.
155     if ( ServiceHolder->deserialize_services() != 0 )
156         return -1;
157
158     // successful loaded
159     Log->print_conf_files_parsed();
160     return 0;
161 }
162
163
164 /**
165  * Init all Helper classes
166  * @return 
167  */
168 int Updater::init_helper_classes()
169 {
170     // Initialize IPHelper
171     if ( init_ip_helper() != 0 )
172         return -1;
173
174     return 0;
175 }
176
177
178 /**
179  * Init the IPHelp member with needed values.
180  * @return 0 if all is fine, -1 otherwise.
181  */
182 int Updater::init_ip_helper()
183 {
184     // initialize IPHelper
185     IPAddrHelper::Ptr _ipaddrhelp(new IPAddrHelper(Log,Conf->get_webcheck_ip_url(),Conf->get_webcheck_ip_url_alt(),Conf->get_enable_ipv6(),Conf->get_proxy(),Conf->get_proxy_port()));
186     IPAddrHelp.swap(_ipaddrhelp);
187
188     return 0;
189 }
190
191
192 /**
193  * Getter for member Config.
194  * @return Member Config.
195  */
196 Config::Ptr Updater::get_config() const
197 {
198     return Conf;
199 }
200
201
202 /**
203  * Getter for member Logger.
204  * @return Member Logger.
205  */
206 Logger::Ptr Updater::get_logger() const
207 {
208     return Log;
209 }
210
211
212 /**
213  * Initialize the logging facility with loglevel and syslog.
214  */
215 void Updater::init_log_facility()
216 {
217     Log->set_log_facility(Conf->get_loglevel(),Conf->get_syslog(),Conf->get_external_warning_log(),Conf->get_external_warning_level());
218     Log->print_init_log_facility();
219 }
220
221
222 /**
223  * Update all configured services.
224  */
225 void Updater::update_services()
226 {
227     list<Service::Ptr> services = ServiceHolder->get_services();
228
229     string ip = IPAddrHelp->get_actual_ip();
230
231     if ( !ip.empty() )
232     {
233         BOOST_FOREACH(Service::Ptr &service, services )
234         {
235             string dns_recheck_ip = ip;
236             int current_time = time(NULL);
237
238             int lastupdated = 0;
239             if ( service->get_last_updates()->size() > 0 )
240                 lastupdated = service->get_last_updates()->front();
241
242             // 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)
243             if ( ((lastupdated != 0) && ((lastupdated + service->get_dns_cache_ttl()) < current_time)) || (lastupdated == 0) )
244             {
245                 Log->print_recheck_dns_entry(service->get_hostname(),lastupdated,service->get_dns_cache_ttl(),current_time);
246                 string _dns_recheck_ip = IPAddrHelp->dns_query(service->get_hostname());
247                 Log->print_cached_dns_entry(service->get_hostname(), _dns_recheck_ip, service->get_actual_ip());
248                 if (!_dns_recheck_ip.empty())
249                     dns_recheck_ip = _dns_recheck_ip;
250             }
251
252             // In case the local hosts IP (ip) differ from the IP set in the last update (actual_ip) or
253             // the IP of the dns record (dns_recheck_ip) differs from the IP of the local host (ip)
254             // then perform an update. This implies that the update is not performed if actual_ip == dns_recheck_ip.
255             // Special case when latupdated == 0 then only perform the update if dns_rechek_ip differs from ip
256             if ( ((service->get_actual_ip() != ip) && (lastupdated != 0)) || (dns_recheck_ip != ip)  )
257                 service->update(ip,current_time);
258             else if ( (service->get_actual_ip() != ip) && (lastupdated == 0)  )
259                 service->set_actual_ip(ip);
260         }
261     }
262 }
263
264
265 /**
266  * Getter for member ServiceHolder.
267  * @return ServiceHolder
268  */
269 Serviceholder::Ptr Updater::get_service_holder() const
270 {
271     return ServiceHolder;
272 }