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