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