3f9586f01ffc13e7fb83e45ce430fa0660976b4e
[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   parser = g_object_get_data (G_OBJECT (connection), "parser");
122
123   stmt = gda_sql_parser_parse_string (parser, buffer, NULL, NULL);
124   gda_statement_get_parameters (stmt, &params, NULL);
125
126   dm = gda_connection_statement_execute_select (connection, stmt, params, NULL);
127   if (dm) {
128     parse_dm_to_struct (&data_list, dm);
129     g_object_unref (dm);
130   }
131
132   g_object_unref (params);
133   g_object_unref (stmt);
134   
135   return errors == TRUE ? NULL : data_list;
136 }
137
138 void execute_sql(GdaConnection *connection, const gchar *buffer)
139 {
140   GdaSqlParser *parser = NULL;
141   GdaStatement *stmt   = NULL;
142   GdaSet       *params = NULL;
143   gint         res     = 0;
144
145   parser = g_object_get_data (G_OBJECT (connection), "parser");
146
147   stmt = gda_sql_parser_parse_string (parser, buffer, NULL, NULL);
148   gda_statement_get_parameters (stmt, &params, NULL);
149
150   res = gda_connection_statement_execute_non_select (connection, stmt, params,
151                                                      NULL, NULL);
152   g_object_unref (params);
153   g_object_unref (stmt);
154 }
155
156 void list_datasource (void)
157 {
158   GList *ds_list;
159   GList *node;
160   GdaDsnInfo *info;
161
162   info = gda_config_get_dsn_info (PROGRAM);
163
164   logmsg(RH_LOG_NORMAL, "Datasource: NAME: %s PROVIDER: %s",
165          info->name, info->provider);
166   logmsg(RH_LOG_NORMAL, "  CNC: %s", info->cnc_string);
167   logmsg(RH_LOG_NORMAL, "  DESC: %s", info->description);
168 }
169
170 void free_data_list(GList *data_list)
171 {
172   GList *node;
173   struct dbset_row *row;
174
175   for (node = g_list_first(data_list); node != NULL; 
176          node = g_list_next (node)) {
177     row = (struct dbset_row *) node->data;
178     g_free(row->session_id);
179     g_free(row->vserver_id);
180     g_free(row->username);
181     g_free(row->ip);
182     g_free(row->mac);
183   }
184   
185   g_list_free (data_list);  
186 }
187
188 gboolean restore_set(GList **data_list, struct vserver *vs)
189 {
190   GList *node = NULL;
191   struct dbset_row *row = NULL;
192   uint32_t id;
193   GList *member_node = NULL;
194   struct rahunas_member *member = NULL;
195   struct task_req req;
196   unsigned char ethernet[ETH_ALEN] = {0,0,0,0,0,0};
197   unsigned char max_try = 3;
198  
199   node = g_list_first(*data_list);
200
201   if (node == NULL)
202     return TRUE;
203
204   DP("Get data from DB if exist");
205
206   for (node; node != NULL; node = g_list_next(node)) {
207     row = (struct dbset_row *) node->data;
208
209     if (atoi(row->vserver_id) != vs->vserver_config->vserver_id)
210       continue;
211
212     id = iptoid(vs->v_map, row->ip);
213
214     if (id < 0)
215       continue;
216
217     req.id = id;
218     req.vserver_id = atoi(row->vserver_id);
219     req.username = row->username;
220     req.session_id = row->session_id;
221     parse_mac(row->mac, &ethernet);
222     memcpy(req.mac_address, &ethernet, ETH_ALEN);
223
224     req.session_start = row->session_start;
225     req.session_timeout = row->session_timeout;
226
227     req.bandwidth_slot_id = row->bandwidth_slot_id;
228     req.bandwidth_max_down = row->bandwidth_max_down; 
229     req.bandwidth_max_up = row->bandwidth_max_up;
230
231     rh_task_startsess(vs, &req);
232   }
233   return TRUE;
234 }
235
236
237 GdaConnection *openconn (GdaConnectionOptions options)
238 {
239   GdaConnection *connection = NULL;
240   GdaSqlParser  *parser = NULL;
241   connection = gda_connection_open_from_dsn (PROGRAM, NULL, options, NULL);
242
243   parser = gda_connection_create_parser (connection);
244   if (!parser) {
245     parser = gda_sql_parser_new ();
246   }
247
248   g_object_set_data_full (G_OBJECT (connection), "parser", parser, g_object_unref);
249
250   return connection;
251 }
252
253 /* Start service task */
254 static int startservice ()
255 {
256   GError *error = NULL;
257   GdaDsnInfo dsn_info = {
258     .name        = PROGRAM,
259     .provider    = "SQLite",
260     .cnc_string  = "DB_DIR=" RAHUNAS_DB_DIR ";DB_NAME=" DB_NAME,
261     .description = "RahuNAS DB Set",
262   };
263
264   logmsg(RH_LOG_NORMAL, "Task DBSET start..");
265    
266   gda_init();
267     
268   if (!gda_config_define_dsn (&dsn_info, &error)) {
269     logmsg (RH_LOG_ERROR, "Could not define DSN");
270     g_error_free (error);
271   }
272
273   list_datasource();
274
275   return 0;
276 }
277
278 /* Stop service task */
279 static int stopservice  ()
280 {
281   gda_config_remove_dsn (PROGRAM, NULL);
282   return 0;
283 }
284
285 /* Initialize */
286 static void init (struct vserver *vs)
287 {
288   GdaConnection *connection;
289   GList *data_list;
290   GList *node;
291   struct dbset_row *row;
292   char select_cmd[256];
293
294   if (vs->vserver_config->init_flag == VS_RELOAD)
295     return;
296
297   logmsg(RH_LOG_NORMAL, "[%s] Task DBSET initialize..",
298          vs->vserver_config->vserver_name);  
299
300   connection = openconn (GDA_CONNECTION_OPTIONS_READ_ONLY);
301
302   snprintf(select_cmd, sizeof (select_cmd), 
303            "SELECT * FROM dbset WHERE vserver_id='%d'",
304            vs->vserver_config->vserver_id);
305
306   DP("SQL: %s", select_cmd);
307
308   data_list = execute_sql_command(connection, select_cmd); 
309
310   restore_set(&data_list, vs);
311
312   free_data_list(data_list);
313
314   g_object_unref(G_OBJECT(connection));
315 }
316
317 /* Cleanup */
318 static void cleanup (struct vserver *vs)
319 {
320   /* Do nothing */
321 }
322
323 /* Start session task */
324 static int startsess (struct vserver *vs, struct task_req *req)
325 {
326   GdaConnection *connection;
327   gint res;
328   char startsess_cmd[256];
329   char time_str[32];
330   char time_str2[32];
331   GList *member_node = NULL;
332   struct rahunas_member *member = NULL;
333
334   connection = openconn (GDA_CONNECTION_OPTIONS_NONE);
335
336   strftime(&time_str, sizeof time_str, "%s", localtime(&req->session_start));
337   strftime(&time_str2, sizeof time_str2, "%s", 
338     localtime(&req->session_timeout));
339
340   member_node = member_get_node_by_id(vs, req->id);
341   if (member_node == NULL)
342     return (-1);
343
344   member = (struct rahunas_member *) member_node->data;
345
346   snprintf(startsess_cmd, sizeof (startsess_cmd), "INSERT INTO dbset"
347          "(session_id,vserver_id,username,ip,mac,session_start,"
348          "session_timeout,bandwidth_slot_id,bandwidth_max_down,"
349          "bandwidth_max_up) "
350          "VALUES('%s','%d','%s','%s','%s',%s,%s,%u,%lu,%lu)",
351          req->session_id, 
352          vs->vserver_config->vserver_id, 
353          req->username, 
354          idtoip(vs->v_map, req->id), 
355          mac_tostring(req->mac_address), 
356          time_str, 
357          time_str2,
358          member->bandwidth_slot_id, 
359          req->bandwidth_max_down,
360          req->bandwidth_max_up);
361
362   DP("SQL: %s", startsess_cmd);
363
364   execute_sql(connection, startsess_cmd);
365
366   g_object_unref(G_OBJECT(connection));
367
368   return 0;
369 }
370
371 /* Stop session task */
372 static int stopsess (struct vserver *vs, struct task_req *req)
373 {
374   GdaConnection *connection;
375   gint res;
376   char stopsess_cmd[256];
377   GList *member_node = NULL;
378   struct rahunas_member *member = NULL;
379
380   member_node = member_get_node_by_id(vs, req->id);
381   if (member_node == NULL)
382     return (-1);
383
384   member = (struct rahunas_member *) member_node->data;
385
386   connection = openconn (GDA_CONNECTION_OPTIONS_NONE);
387
388   DP("Username  : %s", member->username);
389   DP("SessionID : %s", member->session_id);
390
391   snprintf(stopsess_cmd, sizeof (stopsess_cmd), "DELETE FROM dbset WHERE "
392          "session_id='%s' AND username='%s' AND vserver_id='%d'",
393          member->session_id, 
394          member->username,
395          vs->vserver_config->vserver_id);
396
397   DP("SQL: %s", stopsess_cmd);
398
399   execute_sql(connection, stopsess_cmd);
400
401   g_object_unref(G_OBJECT(connection));
402
403   return 0;
404 }
405
406 /* Commit start session task */
407 static int commitstartsess (struct vserver *vs, struct task_req *req)
408 {
409   /* Do nothing or need to implement */
410 }
411
412 /* Commit stop session task */
413 static int commitstopsess  (struct vserver *vs, struct task_req *req)
414 {
415   /* Do nothing or need to implement */
416 }
417
418 /* Rollback start session task */
419 static int rollbackstartsess (struct vserver *vs, struct task_req *req)
420 {
421   /* Do nothing or need to implement */
422 }
423
424 /* Rollback stop session task */
425 static int rollbackstopsess  (struct vserver *vs, struct task_req *req)
426 {
427   /* Do nothing or need to implement */
428 }
429
430 static struct task task_dbset = {
431   .taskname = "DBSET",
432   .taskprio = 10,
433   .init = &init,
434   .cleanup = &cleanup,
435   .startservice = &startservice,
436   .stopservice = &stopservice,
437   .startsess = &startsess,
438   .stopsess = &stopsess,
439   .commitstartsess = &commitstartsess,
440   .commitstopsess = &commitstopsess,
441   .rollbackstartsess = &rollbackstartsess,
442   .rollbackstopsess = &rollbackstopsess,
443 };
444
445 void rh_task_dbset_reg(struct main_server *ms) {
446   task_register(ms, &task_dbset);
447 }