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