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