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