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