8980aca0968a2e59d0eb077e11228d58a1cd4b0d
[rahunas] / src / rh-task-dbset.c
1 /**
2  * RahuNAS task dbset implementation 
3  * Author: Suriya  Soutmun <darksolar@gmail.com>
4  * Date:   2008-09-11
5  */
6
7 #include <stdlib.h>
8 #include <syslog.h>
9 #include <time.h>
10 #include <string.h>
11 #include <libgda/libgda.h>
12 #include "rahunasd.h"
13 #include "rh-task.h"
14 #include "rh-ipset.h"
15 #include "rh-utils.h"
16
17 struct dbset_row {
18   gchar *session_id;
19   gchar *vserver_id;
20   gchar *username;
21   gchar *ip;
22   gchar *mac;
23   time_t session_start;
24   time_t session_timeout;
25   unsigned short bandwidth_slot_id; 
26   long bandwidth_max_down;
27   long bandwidth_max_up;
28 };
29
30 static db_init = 0;
31
32 gboolean get_errors (GdaConnection * connection)
33 {
34   GList *list;
35   GList *node;
36   GdaConnectionEvent *error;
37
38   list = (GList *) gda_connection_get_events(connection);
39
40   for (node = g_list_first(list); node != NULL; node = g_list_next(node)) {
41     error = (GdaConnectionEvent *) node->data;
42     logmsg(RH_LOG_NORMAL, "DB Error no: %d", 
43              gda_connection_event_get_code(error));
44     logmsg(RH_LOG_NORMAL, "DB Desc: %s", 
45              gda_connection_event_get_description(error));
46     logmsg(RH_LOG_NORMAL, "DB Source: %s", 
47              gda_connection_event_get_source(error));
48     logmsg(RH_LOG_NORMAL, "DB SQL State: %s", 
49              gda_connection_event_get_sqlstate(error));
50   }
51 }
52
53 gboolean *parse_dm_to_struct(GList **data_list, GdaDataModel *dm) {
54   gint  row_id;
55   gint  column_id;
56   GValue *value;
57   gchar  *str;
58   gchar  *title;
59   GdaNumeric *num;
60   struct dbset_row *row;
61   struct tm tm;
62   time_t time;
63
64   char tmp[80];
65
66   for (row_id = 0; row_id < gda_data_model_get_n_rows(dm); row_id++) {
67     row = (struct dbset_row *)g_malloc(sizeof(struct dbset_row));
68     if (row == NULL) {
69       /* Do implement the row list cleanup */
70     }
71
72     *data_list = g_list_append(*data_list, row); 
73
74     for (column_id = 0; column_id < gda_data_model_get_n_columns(dm); 
75            column_id++) {
76
77       title = gda_data_model_get_column_title(dm, column_id);
78       value = gda_data_model_get_value_at (dm, column_id, row_id);
79       str = gda_value_stringify(value);
80                
81       if (strncmp("session_id", title, 10) == 0) {
82         row->session_id = g_strdup(str);
83       } else if (strncmp("vserver_id", title, 10) == 0) {
84         row->vserver_id = g_strdup(str);
85       } else if (strncmp("username", title, 8) == 0) {
86         row->username = g_strdup(str);
87       } else if (strncmp("ip", title, 2) == 0) {
88         row->ip = g_strdup(str);
89       } else if (strncmp("mac", title, 3) == 0) {
90         row->mac = g_strdup(str);
91       } else if (strncmp("session_start", title, 13) == 0) {
92         strptime(str, "%s", &tm);
93         time = mktime(&tm);
94         memcpy(&row->session_start, &time, sizeof(time_t));
95       } else if (strncmp("session_timeout", title, 15) == 0) {
96         strptime(str, "%s", &tm);
97         time = mktime(&tm);
98         memcpy(&row->session_timeout, &time, sizeof(time_t));
99       } else if (strncmp("bandwidth_slot_id", title, 17) == 0) {
100         row->bandwidth_slot_id = atoi(str);
101       } else if (strncmp("bandwidth_max_down", title, 18) == 0) {
102         row->bandwidth_max_down = atol(str);
103       } else if (strncmp("bandwidth_max_up", title, 18) == 0) {
104         row->bandwidth_max_up = atol(str);
105       }
106     }
107   }
108   
109   return TRUE;
110 }
111
112 GList *execute_sql_command(GdaConnection *connection, const gchar *buffer)
113 {
114   GdaCommand *command;
115   GList *data_list = NULL;
116   GList *list;
117   GList *node;
118   GdaDataModel *dm;
119   gboolean errors = FALSE;
120
121
122   command = gda_command_new (buffer, GDA_COMMAND_TYPE_SQL,
123                              GDA_COMMAND_OPTION_STOP_ON_ERRORS);
124
125   list = gda_connection_execute_command (connection, command, NULL, NULL);
126   if (list != NULL) {
127     for (node = list; node != NULL; node = g_list_next(node)) {
128       if (GDA_IS_DATA_MODEL(node->data)) {
129         dm = (GdaDataModel *) node->data;
130         parse_dm_to_struct(&data_list, dm);
131         g_object_unref(dm);
132       } else {
133         get_errors (connection);
134         errors = TRUE;  
135       }
136     }
137   }
138
139   gda_command_free(command);
140   
141   return errors == TRUE ? NULL : data_list;
142 }
143
144 void execute_sql(GdaConnection *connection, const gchar *buffer)
145 {
146   GdaCommand *command;
147   
148   command = gda_command_new (buffer, GDA_COMMAND_TYPE_SQL,
149                              GDA_COMMAND_OPTION_STOP_ON_ERRORS);
150   gda_connection_execute_select_command (connection, command, NULL, NULL);
151
152   gda_command_free (command);
153 }
154
155 void list_datasource (void)
156 {
157   GList *ds_list;
158   GList *node;
159   GdaDataSourceInfo *info;
160
161   ds_list = gda_config_get_data_source_list();
162
163   for (node = g_list_first(ds_list); node != NULL; node = g_list_next(node)) {
164     info = (GdaDataSourceInfo *) node->data;
165
166     if (strncmp(info->name, PROGRAM, strlen(PROGRAM)) == 0) {
167       logmsg(RH_LOG_NORMAL, "Datasource: NAME: %s PROVIDER: %s",
168              info->name, info->provider);
169       logmsg(RH_LOG_NORMAL, "  CNC: %s", info->cnc_string);
170       logmsg(RH_LOG_NORMAL, "  DESC: %s", info->description);
171     }
172   }
173
174   gda_config_free_data_source_list(ds_list);
175 }
176
177 GdaConnection *get_connection(GdaClient *client)
178 {
179   return gda_client_open_connection (client, PROGRAM, NULL, NULL,
180                                      GDA_CONNECTION_OPTIONS_NONE, NULL);
181 }
182
183 void free_data_list(GList *data_list)
184 {
185   GList *node;
186   struct dbset_row *row;
187
188   for (node = g_list_first(data_list); node != NULL; 
189          node = g_list_next (node)) {
190     row = (struct dbset_row *) node->data;
191     g_free(row->session_id);
192     g_free(row->vserver_id);
193     g_free(row->username);
194     g_free(row->ip);
195     g_free(row->mac);
196   }
197   
198   g_list_free (data_list);  
199 }
200
201 gboolean restore_set(GList **data_list, struct vserver *vs)
202 {
203   GList *node = NULL;
204   struct dbset_row *row = NULL;
205   uint32_t id;
206   GList *member_node = NULL;
207   struct rahunas_member *member = NULL;
208   struct task_req req;
209   unsigned char ethernet[ETH_ALEN] = {0,0,0,0,0,0};
210   unsigned char max_try = 3;
211  
212   node = g_list_first(*data_list);
213
214   if (node == NULL)
215     return TRUE;
216
217   DP("Get data from DB if exist");
218
219   for (node; node != NULL; node = g_list_next(node)) {
220     row = (struct dbset_row *) node->data;
221
222     if (atoi(row->vserver_id) != vs->vserver_config->vserver_id)
223       continue;
224
225     id = iptoid(vs->v_map, row->ip);
226
227     if (id < 0)
228       continue;
229
230     req.id = id;
231     req.vserver_id = atoi(row->vserver_id);
232     req.username = row->username;
233     req.session_id = row->session_id;
234     parse_mac(row->mac, &ethernet);
235     memcpy(req.mac_address, &ethernet, ETH_ALEN);
236
237     req.session_start = row->session_start;
238     req.session_timeout = row->session_timeout;
239
240     req.bandwidth_slot_id = row->bandwidth_slot_id;
241     req.bandwidth_max_down = row->bandwidth_max_down; 
242     req.bandwidth_max_up = row->bandwidth_max_up;
243
244     rh_task_startsess(vs, &req);
245   }
246   return TRUE;
247 }
248
249 /* Initialize */
250 static void init (struct vserver *vs)
251 {
252   char ds_name[] = PROGRAM;
253   char ds_provider[] = "SQLite";
254   char ds_cnc_string[] = "DB_DIR=" RAHUNAS_CONF_DIR ";DB_NAME=" DB_NAME; 
255   char ds_desc[] = "RahuNAS DB Set";
256
257   if (!(db_init++)) {
258     logmsg(RH_LOG_NORMAL, "Task DBSET init..");
259     
260     gda_init(ds_name, RAHUNAS_VERSION, NULL, NULL);
261     
262     gda_config_save_data_source(ds_name, ds_provider, 
263                                 ds_cnc_string, ds_desc,
264                                 NULL, NULL, FALSE);
265    
266     list_datasource();
267   }
268 }
269
270 /* Cleanup */
271 static void cleanup (struct vserver *vs)
272 {
273   if ((--db_init) == 0) {
274     logmsg(RH_LOG_NORMAL, "Task DBSET cleanup..");  
275   
276     gda_config_remove_data_source (PROGRAM);
277   }
278 }
279
280
281 /* Start service task */
282 static int startservice (struct vserver *vs)
283 {
284   GdaClient *client;
285   GdaConnection *connection;
286   GList *data_list;
287   GList *node;
288   struct dbset_row *row;
289   char select_cmd[256];
290
291   logmsg(RH_LOG_NORMAL, "[%s] Task DBSET start..",
292          vs->vserver_config->vserver_name);  
293
294   client = gda_client_new ();
295   connection = gda_client_open_connection (client, 
296                  PROGRAM, NULL, NULL,
297                  GDA_CONNECTION_OPTIONS_READ_ONLY, NULL);
298
299   sprintf(select_cmd, "SELECT * FROM dbset WHERE vserver_id='%d'",
300           vs->vserver_config->vserver_id);
301
302   DP("SQL: %s", select_cmd);
303
304   data_list = execute_sql_command(connection, select_cmd); 
305
306   restore_set(&data_list, vs);
307
308   free_data_list(data_list);
309
310   gda_client_close_all_connections (client);
311
312   g_object_unref(G_OBJECT(client));
313
314   return 0;
315 }
316
317 /* Stop service task */
318 static int stopservice  (struct vserver *vs)
319 {
320   /* Do nothing or need to implement */
321   logmsg(RH_LOG_NORMAL, "[%s] Task DBSET stop..",
322          vs->vserver_config->vserver_name);  
323 }
324
325 /* Start session task */
326 static int startsess (struct vserver *vs, struct task_req *req)
327 {
328   GdaClient *client;
329   GdaConnection *connection;
330   gint res;
331   char startsess_cmd[256];
332   char time_str[32];
333   char time_str2[32];
334   GList *member_node = NULL;
335   struct rahunas_member *member = NULL;
336
337   client = gda_client_new ();
338   connection = gda_client_open_connection (client, 
339                  PROGRAM, NULL, NULL,
340                  GDA_CONNECTION_OPTIONS_NONE, NULL);
341
342   strftime(&time_str, sizeof time_str, "%s", localtime(&req->session_start));
343   strftime(&time_str2, sizeof time_str2, "%s", 
344     localtime(&req->session_timeout));
345
346   member_node = member_get_node_by_id(vs, req->id);
347   if (member_node == NULL)
348     return (-1);
349
350   member = (struct rahunas_member *) member_node->data;
351
352   sprintf(startsess_cmd, "INSERT INTO dbset"
353          "(session_id,vserver_id,username,ip,mac,session_start,"
354          "session_timeout,bandwidth_slot_id,bandwidth_max_down,"
355          "bandwidth_max_up) "
356          "VALUES('%s','%d','%s','%s','%s',%s,%s,%u,%lu,%lu)",
357          req->session_id, 
358          vs->vserver_config->vserver_id, 
359          req->username, 
360          idtoip(vs->v_map, req->id), 
361          mac_tostring(req->mac_address), 
362          time_str, 
363          time_str2,
364          member->bandwidth_slot_id, 
365          req->bandwidth_max_down,
366          req->bandwidth_max_up);
367
368   DP("SQL: %s", startsess_cmd);
369
370   execute_sql(connection, startsess_cmd);
371
372   gda_client_close_all_connections (client);
373
374   g_object_unref(G_OBJECT(client)); 
375
376   return 0;
377 }
378
379 /* Stop session task */
380 static int stopsess (struct vserver *vs, struct task_req *req)
381 {
382   GdaClient *client;
383   GdaConnection *connection;
384   gint res;
385   char stopsess_cmd[256];
386   GList *member_node = NULL;
387   struct rahunas_member *member = NULL;
388
389   member_node = member_get_node_by_id(vs, req->id);
390   if (member_node == NULL)
391     return (-1);
392
393   member = (struct rahunas_member *) member_node->data;
394
395   client = gda_client_new ();
396   connection = gda_client_open_connection (client, 
397                  PROGRAM, NULL, NULL,
398                  GDA_CONNECTION_OPTIONS_NONE, NULL);
399
400   DP("Username  : %s", member->username);
401   DP("SessionID : %s", member->session_id);
402
403   sprintf(stopsess_cmd, "DELETE FROM dbset WHERE "
404          "session_id='%s' AND username='%s' AND vserver_id='%d'",
405          member->session_id, 
406          member->username,
407          vs->vserver_config->vserver_id);
408
409   DP("SQL: %s", stopsess_cmd);
410
411   execute_sql(connection, stopsess_cmd);
412
413   gda_client_close_all_connections (client);
414
415   g_object_unref(G_OBJECT(client)); 
416
417   return 0;
418 }
419
420 /* Commit start session task */
421 static int commitstartsess (struct vserver *vs, struct task_req *req)
422 {
423   /* Do nothing or need to implement */
424 }
425
426 /* Commit stop session task */
427 static int commitstopsess  (struct vserver *vs, struct task_req *req)
428 {
429   /* Do nothing or need to implement */
430 }
431
432 /* Rollback start session task */
433 static int rollbackstartsess (struct vserver *vs, struct task_req *req)
434 {
435   /* Do nothing or need to implement */
436 }
437
438 /* Rollback stop session task */
439 static int rollbackstopsess  (struct vserver *vs, struct task_req *req)
440 {
441   /* Do nothing or need to implement */
442 }
443
444 static struct task task_dbset = {
445   .taskname = "DBSET",
446   .taskprio = 10,
447   .init = &init,
448   .cleanup = &cleanup,
449   .startservice = &startservice,
450   .stopservice = &stopservice,
451   .startsess = &startsess,
452   .stopsess = &stopsess,
453   .commitstartsess = &commitstartsess,
454   .commitstopsess = &commitstopsess,
455   .rollbackstartsess = &rollbackstartsess,
456   .rollbackstopsess = &rollbackstopsess,
457 };
458
459 void rh_task_dbset_reg(struct main_server *ms) {
460   task_register(ms, &task_dbset);
461 }