Refactoring: Class renaming. All service implementaion classes should start with...
[bpdyndnsd] / src / main.cpp
1 /** @file
2  * @brief The main function.
3  *
4  *
5  *
6  * @copyright Intra2net AG
7  * @license GPLv2
8 */
9
10 #ifdef HAVE_CONFIG_H
11 #include <config.h>
12 #endif
13
14 #define VERSION     0
15 #define REVISION    1
16 #define RELEASE     0
17
18 #define PIDFILE "/home/bjoern/intranator/bpdyndnsd/var/run/bpdyndnsd.pid"
19 #define OBJECT_FILE "/home/bjoern/intranator/bpdyndnsd/objects.ser"
20
21 #include <iostream>
22 #include <fstream>
23 #include <list>
24 #include <string>
25 #include <boost/foreach.hpp>
26 #include <sys/types.h>
27 #include <signal.h>
28
29 #include "updater.h"
30
31 #include "config.cpp"
32 #include "logger.cpp"
33 #include "service.cpp"
34 #include "serviceholder.cpp"
35 #include "updater.cpp"
36 #include "iphelper.cpp"
37 #include "httphelper.cpp"
38 #include "serializeservicecontainer.cpp"
39
40 #include "service_dyndns.cpp"
41 #include "service_dyns.cpp"
42 #include "service_ods.cpp"
43 #include "service_dhs.cpp"
44 #include "service_easydns.cpp"
45 #include "service_tzo.cpp"
46 #include "service_zoneedit.cpp"
47
48 using namespace std;
49
50 Updater::Ptr updater;
51 bool is_online = true;
52
53 /**
54  * Checks if a bpdyndnsd process is already running.
55  * @param updater Shared Pointer to updater, needed for logging.
56  * @return 0 if process not running already or pid of already running process.
57  */
58 int check_for_running_process()
59 {
60     ifstream pidfile(PIDFILE);
61     if ( pidfile.is_open() )
62     {
63         int pid;
64         pidfile >> pid;
65         if ( pid > 0 )
66             updater->get_logger()->print_pid_found(pid);
67         else
68             return 0;
69
70         // check if process still running ret_val==-1 -> not runnig, ret_val==0 -> running
71         if ( kill(pid,0) == 0)
72         {
73             updater->get_logger()->print_process_already_running(pid);
74             pidfile.close();
75             return pid;
76         }
77     }
78     pidfile.close();
79     return 0;
80 }
81
82
83 /**
84  * Writes the pid into the pidfile.
85  * @param pid The process's pid.
86  */
87 int write_pidfile(int pid)
88 {
89     ofstream pidfile(PIDFILE);
90     if ( pidfile.is_open() )
91     {
92         pidfile << pid << endl;
93     }
94     else
95     {
96         updater->get_logger()->print_error_opening_rw(PIDFILE);
97         return -1;
98     }
99     pidfile.close();
100     return 0;
101 }
102
103
104 /**
105  * Parent shutdown function
106  * @return 0 if all is fine, -1 otherwise
107  */
108 int shutdown_parent(bool remove_pid, int ret_val)
109 {
110     // starting shutdown_parent
111     updater->get_logger()->print_starting_shutdown_parent();
112
113     // remove pidfile if requested
114     if(remove_pid)
115         unlink(PIDFILE);
116
117     // shutdown parent complete
118     updater->get_logger()->print_shutdown_parent_succeeded();
119
120     // release shared pointer
121     updater.reset();
122
123     exit(ret_val);
124 }
125
126
127 /**
128  * Shutdown function
129  * @return 0 if all is fine, -1 otherwise
130  */
131 int shutdown()
132 {
133     int ret_val = 0;
134
135     // starting shutdown
136     updater->get_logger()->print_starting_shutdown();
137
138     // serialize actual service objects
139     if ( updater->get_service_holder()->serialize_services() != 0 )
140         ret_val = -1;
141
142     // unlink pidfile
143     unlink(PIDFILE);
144
145     // shutdown complete
146     updater->get_logger()->print_shutdown_succeeded();
147
148     // release shared pointer
149     updater.reset();
150
151     return ret_val;
152 }
153
154
155 /**
156  * Signal SIGTERM caught, releasing resources and exit.
157  * @param param Parameter from the signal interface.
158  */
159 void terminate(int param)
160 {
161     updater->get_logger()->print_caught_sigterm();
162
163     exit(shutdown());
164 }
165
166
167 /**
168  * Signal SIGUSR1 caught, switching to offline mode.
169  * @param param Parameter from the signal interface.
170  */
171 void switch_to_offline(int param)
172 {
173     updater->get_logger()->print_caught_siguser1();
174     is_online = false;
175 }
176
177
178 /**
179  * Signal SIGHUP caught, reloading config and switching to online mode.
180  * @param param Parameter from the signal interface.
181  */
182 void reload_config(int param)
183 {
184     updater->get_logger()->print_caught_sighup();
185     if ( updater->reload_config() != 0 )
186         exit(-1);
187     is_online = true;
188 }
189
190
191 /**
192  * Initialize the signals we handle.
193  * @return 0 if all is fine, -1 on error.
194  */
195 int init_signals()
196 {
197     sighandler_t ret_val;
198     ret_val = signal(SIGTERM,terminate);
199     if ( ret_val == SIG_ERR )
200     {
201         updater->get_logger()->print_error_setting_signal("SIGTERM");
202         return -1;
203     }
204     ret_val = signal(SIGUSR1,switch_to_offline);
205     if ( ret_val == SIG_ERR )
206     {
207         updater->get_logger()->print_error_setting_signal("SIGUSR1");
208         return -1;
209     }
210     ret_val = signal(SIGHUP,reload_config);
211     if ( ret_val == SIG_ERR )
212     {
213         updater->get_logger()->print_error_setting_signal("SIGHUP");
214         return -1;
215     }
216
217     return 0;
218 }
219
220
221 /**
222  * Try to run in daemon mode if enabled in config.
223  * @param daemon_mode True if process should detach to init (run as daemon), false if not detach to init.
224  * @return 0 if all is fine, -1 on error.
225  */
226 int init_daemon_mode(bool daemon_mode)
227 {
228     updater->get_logger()->print_daemon_mode(daemon_mode);
229     if ( daemon_mode == true )
230     {
231         int pid = fork();
232         if ( pid < 0 )
233         {
234             // error fork
235             updater->get_logger()->print_error_fork();
236             return -1;
237         }
238         else if ( pid > 0 )
239         {
240             // parent continues here
241             if ( write_pidfile(pid) != 0 )
242             {
243                 if ( kill(pid,SIGTERM) != 0 )
244                 {
245                     updater->get_logger()->print_error_kill_child(pid);
246                     shutdown_parent(false,-1); // keep pidfile
247                 }
248                 else
249                 {
250                     updater->get_logger()->print_child_killed(pid);
251                     shutdown_parent(true,-1); // remove pidfile
252                 }
253             }
254             updater->get_logger()->print_runnig_as_daemon(pid);
255             shutdown_parent(false,0); // keep pidfile
256         }
257         // child starts here
258     }
259     else
260     {
261         if ( write_pidfile(getpid()) != 0 )
262         {
263             shutdown();
264             exit(-1);
265         }
266     }
267     return 0;
268 }
269
270 /**
271  * @brief The main part.
272  * @param argc Number of arguments
273  * @param argv Command line arguments
274  * @return 0 if all is fine.
275  */
276 int main(int argc, char *argv[])
277 {
278     // initialize Updater
279     Updater::Ptr _updater(new Updater);
280     updater = _updater;
281     _updater.reset();
282
283     // load config and initialize helper classes
284     if ( updater->load_config(argc,argv) != 0 )
285         return -1;
286
287     // open pidfile and check for running process
288     if ( check_for_running_process() != 0)
289         return -1;
290
291     // init signal handling
292     if ( init_signals() != 0)
293         return -1;
294
295     // init daemon_mode if enabled
296     if ( init_daemon_mode(updater->get_config()->get_daemon_mode()) != 0 )
297         return -1;
298
299     // service processing starts here
300     do
301     {
302         if ( is_online == true )
303         {
304             // update all configured services
305             updater->update_services();
306         }
307         else
308         {
309             // We are in offline mode, do nothing, expect printing "offline mode".
310             updater->get_logger()->print_offline_mode();
311         }
312
313         // Snore, snore... don't hug the cpu if we are in daemon_mode.
314         if ( updater->get_config()->get_daemon_mode() == 1 )
315             sleep(5);
316
317     }while ( updater->get_config()->get_daemon_mode() == 1 );
318
319     // Serialize services to save their actual state.
320     if ( shutdown() != 0 )
321         return -1;
322
323     return 0;
324 }