c793ace564d274189514629f72b3ed1158da8494
[rahunas] / src / rahunasd.c
1 /**
2  * RahuNASd
3  * Author: Neutron Soutmun <neo.neutron@gmail.com>
4  * Date:   2008-08-07
5  */
6
7 #include <sys/types.h>
8 #include <sys/wait.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <stdarg.h>
12 #include <string.h>
13 #include <errno.h>
14 #include <unistd.h>
15 #include <signal.h>
16 #include <syslog.h>
17
18 #include "rahunasd.h"
19 #include "rh-server.h"
20 #include "rh-xmlrpc-server.h"
21 #include "rh-xmlrpc-cmd.h"
22 #include "rh-ipset.h"
23 #include "rh-utils.h"
24 #include "rh-task.h"
25
26 const char *termstring = '\0';
27 pid_t pid, sid;
28
29 struct main_server rh_main_server_instance = {
30   .vserver_list = NULL,
31   .task_list = NULL,
32 };
33 struct main_server *rh_main_server = &rh_main_server_instance;
34
35 void rh_sighandler(int sig)
36 {
37   switch (sig) {
38     case SIGTERM:
39       if (pid == 0) {
40         rh_exit();
41         exit(EXIT_SUCCESS);
42       } else if (pid > 0) {
43         syslog(LOG_NOTICE, "Kill Child PID %d", pid);
44         kill(pid, SIGTERM);
45       } else {
46         syslog(LOG_ERR, "Invalid PID");
47         exit(EXIT_FAILURE);
48       }
49       break;
50     case SIGHUP:
51       if (pid == 0) {
52         rh_reload();
53       } else if (pid > 0) {
54         syslog(LOG_NOTICE, "Reloading config files");
55         kill(pid, SIGHUP);
56       } else {
57         syslog(LOG_ERR, "Invalid PID");
58       }
59       break;
60   }
61   return;
62 }
63
64 size_t expired_check(void *data)
65 {
66   struct processing_set *process = (struct processing_set *) data;
67   struct ip_set_req_rahunas *d = NULL;
68   struct task_req req;
69   unsigned int id;
70   char *ip = NULL;
71   int res  = 0;
72   GList *runner = NULL;
73   struct rahunas_member *member = NULL;
74
75   if (process == NULL)
76     return (-1);
77
78   if (process->list == NULL)
79     return (-1); 
80
81   runner = g_list_first(process->vs->v_map->members);
82
83   while (runner != NULL) {
84     member = (struct rahunas_member *)runner->data;
85     runner = g_list_next(runner);
86
87     id = member->id;
88
89     d = get_data_from_set (process->list, id, process->vs->v_map);
90     if (d == NULL)
91       continue;
92
93     DP("Processing id = %d", id);
94
95     DP("Time now: %d, Time get: %d", time(NULL), d->timestamp);
96     DP("Time diff = %d, idle_timeout=%d", (time(NULL) - d->timestamp),
97          process->vs->vserver_config->idle_timeout);
98
99     if ((time(NULL) - d->timestamp) >
100          process->vs->vserver_config->idle_timeout) {
101       // Idle Timeout
102       DP("Found IP: %s idle timeout", idtoip(process->vs->v_map, id));
103       req.id = id;
104       memcpy(req.mac_address, &d->ethernet, ETH_ALEN);
105       req.req_opt = RH_RADIUS_TERM_IDLE_TIMEOUT;
106       send_xmlrpc_stopacct(process->vs, id, 
107                            RH_RADIUS_TERM_IDLE_TIMEOUT);
108       res = rh_task_stopsess(process->vs, &req);
109     } else if (member->session_timeout != 0 && 
110                time(NULL) > member->session_timeout) {
111       // Session Timeout (Expired)
112       DP("Found IP: %s session timeout", idtoip(process->vs->v_map, id));
113       req.id = id;
114       memcpy(req.mac_address, &d->ethernet, ETH_ALEN);
115       req.req_opt = RH_RADIUS_TERM_SESSION_TIMEOUT;
116       send_xmlrpc_stopacct(process->vs, id, 
117                            RH_RADIUS_TERM_SESSION_TIMEOUT);
118       res = rh_task_stopsess(process->vs, &req);
119     }
120   }
121 }
122
123 int polling_expired_check(struct main_server *ms, struct vserver *vs) {
124   walk_through_set(&expired_check, vs);
125   return 0;
126 }
127
128 gboolean polling(gpointer data) {
129   struct main_server *ms = (struct main_server *)data;
130   struct vserver *vs = NULL;
131   
132   if (ms->polling_blocked) {
133     DP("%s", "Skip polling!");
134     return TRUE;
135   }
136   
137   DP("%s", "Start polling!");
138   walk_through_vserver(&polling_expired_check, ms);
139   return TRUE;
140 }
141
142 void rh_exit()
143 {
144   walk_through_vserver(&rh_task_cleanup, rh_main_server);
145   rh_task_stopservice(rh_main_server);
146   rh_task_unregister(rh_main_server);
147   unregister_vserver_all(rh_main_server);
148   rh_closelog(rh_main_server->main_config->log_file);
149 }
150
151 void rh_reload()
152 {
153   logmsg(RH_LOG_NORMAL, "Reloading config files");
154   /* Block polling */
155   rh_main_server->polling_blocked = 1;
156
157   if (rh_main_server->main_config->log_file != NULL) {
158     syslog(LOG_INFO, "Open log file: %s", 
159            rh_main_server->main_config->log_file);
160     rh_main_server->log_fd = rh_openlog(rh_main_server->main_config->log_file);
161
162     if (rh_main_server->log_fd == -1) {
163       syslog(LOG_ERR, "Could not open log file %s\n", 
164              rh_main_server->main_config->log_file);
165       exit(EXIT_FAILURE);
166     }
167
168     rh_logselect(rh_main_server->log_fd);
169   }
170
171   /* Get vserver(s) config, again */
172   if (rh_main_server->main_config->conf_dir != NULL) {
173     get_vservers_config(rh_main_server->main_config->conf_dir, rh_main_server);
174   } else {
175     syslog(LOG_ERR, "The main configuration file is incompleted, lack of conf_dir\n");
176     exit(EXIT_FAILURE);
177   }
178
179   walk_through_vserver(&vserver_reload, rh_main_server);
180   vserver_unused_cleanup(rh_main_server);
181   
182   /* Unblock polling */
183   rh_main_server->polling_blocked = 0;
184   DP("Config reload finished");
185   return;
186 }
187
188 static void
189 watch_child(char *argv[])
190 {
191   char *prog = NULL;
192   int failcount = 0;
193   time_t start;
194   time_t stop;
195   int status;
196   int nullfd;
197   
198   if (*(argv[0]) == '(')
199     return;
200
201   pid = fork(); 
202   if (pid < 0) {
203     syslog(LOG_ALERT, "fork failed");
204     exit(EXIT_FAILURE);
205   } else if (pid > 0) {
206     /* parent */
207     rh_writepid(DEFAULT_PID, pid);
208     exit(EXIT_SUCCESS);
209   }
210
211   /* Change the file mode mask */
212   umask(0);
213
214   if ((sid = setsid()) < 0)
215     syslog(LOG_ALERT, "setsid failed");
216
217   if ((chdir("/")) < 0) {
218     exit(EXIT_FAILURE);
219   }
220     
221   /* Close out the standard file descriptors */
222   close(STDIN_FILENO);
223   close(STDOUT_FILENO);
224   close(STDERR_FILENO);
225
226
227   while(1) {
228     pid = fork();
229     if (pid == 0) {
230       /* child */
231       prog = strdup(argv[0]);
232       argv[0] = strdup("(rahunasd)");
233       execvp(prog, argv);
234       syslog(LOG_ALERT, "execvp failed");
235     } else if (pid < 0) {
236       syslog(LOG_ERR, "Could not fork the child process");   
237       exit(EXIT_FAILURE);
238     }
239   
240     /* parent */
241     syslog(LOG_NOTICE, "RahuNASd Parent: child process %d started", pid);   
242
243     time(&start);
244
245     pid = waitpid(-1, &status, 0);
246     time(&stop);
247
248     if (WIFEXITED(status)) {
249       syslog(LOG_NOTICE,
250                "RahuNASd Parent: child process %d exited with status %d",
251                pid, WEXITSTATUS(status));
252     } else if (WIFSIGNALED(status)) {
253       syslog(LOG_NOTICE,
254                "RahuNASd Parent: child process %d exited due to signal %d",
255                pid, WTERMSIG(status));
256     } else {
257       syslog(LOG_NOTICE, "RahuNASd Parent: child process %d exited", pid);
258     }
259   
260     if (stop - start < 10)
261       failcount++;
262     else
263       failcount = 0;
264   
265     if (failcount == 5) {
266       syslog(LOG_ALERT, "Exiting due to repeated, frequent failures");
267       exit(EXIT_FAILURE);
268     }
269   
270     if (WIFEXITED(status) && (WEXITSTATUS(status) == 0)) {
271         syslog(LOG_NOTICE, "Exit Gracefully");
272         exit(EXIT_SUCCESS);
273     }
274     
275     sleep(3);
276   }
277 }
278
279 void rh_free_member (struct rahunas_member *member)
280 {
281   if (member->username && member->username != termstring)
282     free(member->username);
283
284   if (member->session_id && member->session_id != termstring)
285     free(member->session_id);
286 }
287
288
289 int main(int argc, char **argv) 
290 {
291   gchar* addr = "localhost";
292   int port    = 8123;
293   int fd_log;
294
295   char version[256];
296
297   char line[256];
298
299   union rahunas_config rh_main_config = {
300     .rh_main.conf_dir = NULL,
301     .rh_main.log_file = NULL,
302     .rh_main.dhcp = NULL,
303     .rh_main.polling_interval = POLLING,
304     .rh_main.bandwidth_shape = BANDWIDTH_SHAPE,
305   };
306
307   GNetXmlRpcServer *server = NULL;
308   GMainLoop* main_loop     = NULL;
309
310   signal(SIGTERM, &rh_sighandler);
311   signal(SIGHUP, &rh_sighandler);
312   signal(SIGINT, SIG_IGN);
313
314   watch_child(argv);
315
316   /* Get main server config */
317   get_config(CONFIG_FILE, &rh_main_config);
318   rh_main_server->main_config = (struct rahunas_main_config *) &rh_main_config;
319
320   /* Open and select main log file */
321   if (rh_main_server->main_config->log_file != NULL) {
322     syslog(LOG_INFO, "Open log file: %s", 
323            rh_main_server->main_config->log_file);
324     rh_main_server->log_fd = rh_openlog(rh_main_server->main_config->log_file);
325
326     if (rh_main_server->log_fd == -1) {
327       syslog(LOG_ERR, "Could not open log file %s\n", 
328              rh_main_server->main_config->log_file);
329       exit(EXIT_FAILURE);
330     }
331
332     rh_logselect(rh_main_server->log_fd);
333   }
334
335   syslog(LOG_INFO, "Config directory: %s", rh_main_server->main_config->conf_dir);
336
337   /* Get vserver(s) config */
338   if (rh_main_server->main_config->conf_dir != NULL) {
339     get_vservers_config(rh_main_server->main_config->conf_dir, rh_main_server);
340   } else {
341     syslog(LOG_ERR, "The main configuration file is incompleted, lack of conf_dir\n");
342     exit(EXIT_FAILURE);
343   }
344
345   snprintf(version, sizeof (version), "Starting %s - Version %s", PROGRAM, 
346            RAHUNAS_VERSION);
347   logmsg(RH_LOG_NORMAL, version);
348
349   rh_task_register(rh_main_server);
350   rh_task_startservice(rh_main_server);
351
352   walk_through_vserver(&rh_task_init, rh_main_server);
353
354   gnet_init();
355   main_loop = g_main_loop_new (NULL, FALSE);
356
357   /* XML RPC Server */
358   server = gnet_xmlrpc_server_new (addr, port);
359
360   if (!server) {
361     syslog(LOG_ERR, "Could not start XML-RPC server!");
362     walk_through_vserver(&rh_task_stopservice, rh_main_server);
363     exit (EXIT_FAILURE);
364   }
365
366   gnet_xmlrpc_server_register_command (server, 
367                                        "startsession", 
368                                        do_startsession, 
369                                        rh_main_server);
370
371   gnet_xmlrpc_server_register_command (server, 
372                                        "stopsession", 
373                                        do_stopsession, 
374                                        rh_main_server);
375
376   gnet_xmlrpc_server_register_command (server, 
377                                        "getsessioninfo", 
378                                        do_getsessioninfo, 
379                                        rh_main_server);
380
381   DP("Polling interval = %d", rh_main_server->main_config->polling_interval);
382
383   g_timeout_add_seconds (rh_main_server->main_config->polling_interval, 
384                          polling, rh_main_server);
385
386  
387   walk_through_vserver(&vserver_init_done, rh_main_server);
388   logmsg(RH_LOG_NORMAL, "Ready to serve...");
389   g_main_loop_run(main_loop);
390
391   exit(EXIT_SUCCESS);
392 }