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