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