stub
[oweals/gnunet.git] / src / dht / plugin_dhtlog_mysql_dump.c
1 /*
2      This file is part of GNUnet.
3      (C) 2006 - 2009 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 2, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file src/dht/plugin_dhtlog_mysql.c
23  * @brief MySQL logging plugin to record DHT operations to MySQL server,
24  *        but write all queries to file instead of the actual server
25  *        so that they can be imported later.  The idea is that connecting
26  *        to the MySQL server X times can be really problematic, but hopefully
27  *        writing to a single file is more reliable.
28  * @author Nathan Evans
29  *
30  * Database: MySQL
31  */
32
33 #include "platform.h"
34 #include "gnunet_util_lib.h"
35 #include "dhtlog.h"
36
37
38 #define DEBUG_DHTLOG GNUNET_NO
39
40 /**
41  * Maximum number of supported parameters for a prepared
42  * statement.  Increase if needed.
43  */
44 #define MAX_PARAM 32
45
46
47 static unsigned long max_varchar_len;
48
49 /**
50  * The configuration the DHT service is running with
51  */
52 static const struct GNUNET_CONFIGURATION_Handle *cfg;
53
54 #define INSERT_QUERIES_STMT "prepare insert_query from 'INSERT INTO queries (trialuid, querytype, hops, dhtkeyuid, dhtqueryid, succeeded, nodeuid) "\
55                           "VALUES (@temp_trial, ?, ?, ?, ?, ?, ?)'"
56
57 #define INSERT_ROUTES_STMT "prepare insert_route from 'INSERT INTO routes (trialuid, querytype, hops, dhtkeyuid, dhtqueryid, succeeded, nodeuid, from_node, to_node) "\
58                           "VALUES (@temp_trial, ?, ?, ?, ?, ?, ?, ?, ?)'"
59
60 #define INSERT_NODES_STMT "prepare insert_node from 'INSERT INTO nodes (trialuid, nodeid) "\
61                           "VALUES (@temp_trial, ?)'"
62
63 #define INSERT_TRIALS_STMT "prepare insert_trial from 'INSERT INTO trials"\
64                            "(starttime, numnodes, topology,"\
65                            "topology_percentage, topology_probability,"\
66                            "blacklist_topology, connect_topology, connect_topology_option,"\
67                            "connect_topology_option_modifier, puts, gets, "\
68                            "concurrent, settle_time, num_rounds, malicious_getters,"\
69                            "malicious_putters, malicious_droppers, message) "\
70                            "VALUES (NOW(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'"
71
72 #define INSERT_DHTKEY_STMT "prepare insert_dhtkey from 'INSERT ignore INTO dhtkeys (dhtkey, trialuid) "\
73                            "VALUES (?, @temp_trial)'"
74
75 #define UPDATE_TRIALS_STMT "prepare update_trial from 'UPDATE trials set endtime=NOW(), total_messages_dropped = ?, total_bytes_dropped = ?, unknownPeers = ? where trialuid = @temp_trial'"
76
77 #define UPDATE_CONNECTIONS_STMT "prepare update_conn from 'UPDATE trials set totalConnections = ? where trialuid = @temp_trial'"
78
79 #define GET_TRIAL_STMT "prepare select_trial from 'SELECT MAX( trialuid ) FROM trials into @temp_trial'"
80
81 #define GET_DHTKEYUID_STMT "prepare get_dhtkeyuid from 'SELECT dhtkeyuid FROM dhtkeys where dhtkey = ? and trialuid = @temp_trial'"
82
83 #define GET_NODEUID_STMT "prepare get_nodeuid from 'SELECT nodeuid FROM nodes where trialuid = @temp_trial and nodeid = ?'"
84
85 /**
86  * File to dump all sql statements to.
87  */
88 FILE *outfile;
89
90 /**
91  * Create a prepared statement.
92  *
93  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
94  */
95 static int
96 prepared_statement_create (const char *statement)
97 {
98   if (fprintf(outfile, "%s;\n", statement) > 0)
99     return GNUNET_OK;
100
101   return GNUNET_SYSERR;
102 }
103
104 /*
105  * Initialize the prepared statements for use with dht test logging
106  */
107 static int
108 iopen ()
109 {
110 #define PINIT(a) (GNUNET_OK != (prepared_statement_create(a)))
111   if (PINIT (INSERT_QUERIES_STMT) ||
112       PINIT (INSERT_ROUTES_STMT) ||
113       PINIT (INSERT_TRIALS_STMT) ||
114       PINIT (INSERT_NODES_STMT) ||
115       PINIT (INSERT_DHTKEY_STMT) ||
116       PINIT (UPDATE_TRIALS_STMT) ||
117       PINIT (GET_DHTKEYUID_STMT) ||
118       PINIT (GET_NODEUID_STMT) ||
119       PINIT (UPDATE_CONNECTIONS_STMT) ||
120       PINIT (GET_TRIAL_STMT))
121     {
122       return GNUNET_SYSERR;
123     }
124 #undef PINIT
125   return GNUNET_OK;
126 }
127
128
129 /*
130  * Inserts the specified trial into the dhttests.trials table
131  *
132  * @param trialuid return the trialuid of the newly inserted trial
133  * @param num_nodes how many nodes are in the trial
134  * @param topology integer representing topology for this trial
135  * @param blacklist_topology integer representing blacklist topology for this trial
136  * @param connect_topology integer representing connect topology for this trial
137  * @param connect_topology_option integer representing connect topology option
138  * @param connect_topology_option_modifier float to modify connect option
139  * @param topology_percentage percentage modifier for certain topologies
140  * @param topology_probability probability modifier for certain topologies
141  * @param puts number of puts to perform
142  * @param gets number of gets to perform
143  * @param concurrent number of concurrent requests
144  * @param settle_time time to wait between creating topology and starting testing
145  * @param num_rounds number of times to repeat the trial
146  * @param malicious_getters number of malicious GET peers in the trial
147  * @param malicious_putters number of malicious PUT peers in the trial
148  * @param malicious_droppers number of malicious DROP peers in the trial
149  * @param message string to put into DB for this trial
150  *
151  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
152  */
153 int
154 add_trial (unsigned long long *trialuid, int num_nodes, int topology,
155            int blacklist_topology, int connect_topology,
156            int connect_topology_option, float connect_topology_option_modifier,
157            float topology_percentage, float topology_probability,
158            int puts, int gets, int concurrent, int settle_time,
159            int num_rounds, int malicious_getters, int malicious_putters,
160            int malicious_droppers, char *message)
161 {
162   int ret;
163   *trialuid = 0;
164   if (outfile == NULL)
165     return GNUNET_SYSERR;
166
167   ret = fprintf(outfile, "set @num = %d, @topology = %d, @bl = %d, "
168                    "@connect = %d, @c_t_o = %d, @c_t_o_m = %f, @t_p = %f, "
169                    "@t_pr = %f, @puts = %d, @gets = %d, "
170                    "@concurrent = %d, @settle = %d, @rounds = %d, "
171                    "@m_gets = %d, @m_puts = %d, @m_drops = %d, "
172                    "@message = \"%s\";\n", num_nodes, topology,
173                    blacklist_topology, connect_topology,
174                    connect_topology_option, connect_topology_option_modifier,
175                    topology_percentage, topology_probability,
176                    puts, gets, concurrent, settle_time,
177                    num_rounds, malicious_getters, malicious_putters,
178                    malicious_droppers, message);
179
180   if (ret < 0)
181     return GNUNET_SYSERR;
182   ret = fprintf(outfile, "execute insert_trial using "
183                          "@num, @topology, @bl, "
184                          "@connect, @c_t_o, @c_t_o_m, @t_p, "
185                          "@t_pr, @puts, @gets, "
186                          "@concurrent, @settle, @rounds, "
187                          "@m_gets, @m_puts, @m_drops, "
188                          "@message;\n");
189
190   ret = fprintf(outfile, "execute select_trial;\n");
191
192   if (ret >= 0)
193     return GNUNET_OK;
194   return GNUNET_SYSERR;
195 }
196
197
198 /*
199  * Inserts the specified dhtkey into the dhttests.dhtkeys table,
200  * stores return value of dhttests.dhtkeys.dhtkeyuid into dhtkeyuid
201  *
202  * @param dhtkeyuid return value
203  * @param dhtkey hashcode of key to insert
204  *
205  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
206  */
207 int
208 add_dhtkey (unsigned long long *dhtkeyuid, const GNUNET_HashCode * dhtkey)
209 {
210   int ret;
211   *dhtkeyuid = 0;
212
213   if (outfile == NULL)
214     return GNUNET_SYSERR;
215
216   if (dhtkey != NULL)
217     ret = fprintf(outfile, "set @dhtkey = \"%s\";\n", GNUNET_h2s_full(dhtkey));
218   else
219     ret = fprintf(outfile, "set @dhtkey = XXXXX;\n");
220
221   if (ret < 0)
222     return GNUNET_SYSERR;
223   ret = fprintf(outfile, "execute insert_dhtkey using @dhtkey;\n");
224
225   if (ret >= 0)
226     return GNUNET_OK;
227   return GNUNET_SYSERR;
228 }
229
230 /*
231  * Inserts the specified node into the dhttests.nodes table
232  *
233  * @param nodeuid the inserted node uid
234  * @param node the node to insert
235  *
236  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
237  */
238 int
239 add_node (unsigned long long *nodeuid, struct GNUNET_PeerIdentity * node)
240 {
241   int ret;
242
243   if (node == NULL)
244     return GNUNET_SYSERR;
245
246   if (outfile == NULL)
247     return GNUNET_SYSERR;
248
249   if (node != NULL)
250     ret = fprintf(outfile, "set @node = \"%s\";\n", GNUNET_h2s_full(&node->hashPubKey));
251   else
252     return GNUNET_SYSERR;
253
254   if (ret < 0)
255     return GNUNET_SYSERR;
256
257   ret = fprintf(outfile, "execute insert_node using @node;\n");
258
259   if (ret >= 0)
260     return GNUNET_OK;
261   return GNUNET_SYSERR;
262 }
263
264 /*
265  * Update dhttests.trials table with current server time as end time
266  *
267  * @param trialuid trial to update
268  * @param totalMessagesDropped stats value for messages dropped
269  * @param totalBytesDropped stats value for total bytes dropped
270  * @param unknownPeers stats value for unknown peers
271  *
272  * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
273  */
274 int
275 update_trials (unsigned long long trialuid,
276                unsigned long long totalMessagesDropped,
277                unsigned long long totalBytesDropped,
278                unsigned long long unknownPeers)
279 {
280   int ret;
281 #if DEBUG_DHTLOG
282   if (trialuid != current_trial)
283     {
284       fprintf (stderr,
285                _("Trialuid to update is not equal to current_trial\n"));
286     }
287 #endif
288
289   if (outfile == NULL)
290     return GNUNET_SYSERR;
291
292   ret = fprintf(outfile, "set @m_dropped = %llu, @b_dropped = %llu, @unknown = %llu;\n", totalMessagesDropped, totalBytesDropped, unknownPeers);
293
294   if (ret < 0)
295     return GNUNET_SYSERR;
296
297   ret = fprintf(outfile, "execute update_trial using @m_dropped, @b_dropped, @unknown;\n");
298
299   if (ret >= 0)
300     return GNUNET_OK;
301   else
302     return GNUNET_SYSERR;
303 }
304
305
306 /*
307  * Update dhttests.trials table with total connections information
308  *
309  * @param trialuid the trialuid to update
310  * @param totalConnections the number of connections
311  *
312  * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
313  */
314 int
315 add_connections (unsigned long long trialuid, unsigned int totalConnections)
316 {
317   int ret;
318 #if DEBUG_DHTLOG
319   if (trialuid != current_trial)
320     {
321       fprintf (stderr,
322                _("Trialuid to update is not equal to current_trial(!)(?)\n"));
323     }
324 #endif
325   if (outfile == NULL)
326     return GNUNET_SYSERR;
327
328   ret = fprintf(outfile, "set @conns = %u;\n", totalConnections);
329
330   if (ret < 0)
331     return GNUNET_SYSERR;
332
333   ret = fprintf(outfile, "execute update_connections using @conns;\n");
334
335   if (ret >= 0)
336     return GNUNET_OK;
337   else
338     return GNUNET_SYSERR;
339 }
340
341 /*
342  * Inserts the specified query into the dhttests.queries table
343  *
344  * @param sqlqueruid inserted query uid
345  * @param queryid dht query id
346  * @param type type of the query
347  * @param hops number of hops query traveled
348  * @param succeeded whether or not query was successful
349  * @param node the node the query hit
350  * @param key the key of the query
351  *
352  * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
353  */
354 int
355 add_query (unsigned long long *sqlqueryuid, unsigned long long queryid,
356            unsigned int type, unsigned int hops, int succeeded,
357            const struct GNUNET_PeerIdentity * node, const GNUNET_HashCode * key)
358 {
359   int ret;
360
361   if (outfile == NULL)
362     return GNUNET_SYSERR;
363
364   *sqlqueryuid = 0;
365
366   if (key != NULL)
367     ret = fprintf(outfile, "select dhtkeyuid from dhtkeys where trialuid = @temp_trial and dhtkey = \"%s\" into @temp_dhtkey;\n", GNUNET_h2s_full(key));
368   else
369     ret = fprintf(outfile, "set @temp_dhtkey = 0;\n");
370
371   if (node != NULL)
372     ret = fprintf(outfile, "select nodeuid from nodes where trialuid = @temp_trial and nodeid = \"%s\" into @temp_node;\n", GNUNET_h2s_full(&node->hashPubKey));
373   else
374     ret = fprintf(outfile, "set @temp_node = 0;\n");
375
376   ret = fprintf(outfile, "set @qid = %llu, @type = %u, @hops = %u, @succ = %d;\n", queryid, type, hops, succeeded);
377
378   if (ret < 0)
379     return GNUNET_SYSERR;
380
381   ret = fprintf(outfile, "execute insert_query using @type, @hops, @temp_dhtkey, @qid, @succ, @temp_node;\n");
382
383   if (ret >= 0)
384     return GNUNET_OK;
385   else
386     return GNUNET_SYSERR;
387 }
388
389 /*
390  * Inserts the specified route information into the dhttests.routes table
391  *
392  * @param sqlqueruid inserted query uid
393  * @param queryid dht query id
394  * @param type type of the query
395  * @param hops number of hops query traveled
396  * @param succeeded whether or not query was successful
397  * @param node the node the query hit
398  * @param key the key of the query
399  * @param from_node the node that sent the message to node
400  * @param to_node next node to forward message to
401  *
402  * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
403  */
404 int
405 add_route (unsigned long long *sqlqueryuid, unsigned long long queryid,
406            unsigned int type, unsigned int hops,
407            int succeeded, const struct GNUNET_PeerIdentity * node,
408            const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity * from_node,
409            const struct GNUNET_PeerIdentity * to_node)
410 {
411   int ret;
412
413   if (outfile == NULL)
414     return GNUNET_SYSERR;
415
416   *sqlqueryuid = 0;
417
418   if (key != NULL)
419     ret = fprintf(outfile, "select dhtkeyuid from dhtkeys where trialuid = @temp_trial and dhtkey = \"%s\" into @temp_dhtkey;\n", GNUNET_h2s_full(key));
420   else
421     ret = fprintf(outfile, "set @temp_dhtkey = 0;\n");
422
423   if (node != NULL)
424     ret = fprintf(outfile, "select nodeuid from nodes where trialuid = @temp_trial and nodeid = \"%s\" into @temp_node;\n", GNUNET_h2s_full(&node->hashPubKey));
425   else
426     ret = fprintf(outfile, "set @temp_node = 0;\n");
427
428   if (from_node != NULL)
429     ret = fprintf(outfile, "select nodeuid from nodes where trialuid = @temp_trial and nodeid = \"%s\" into @temp_from_node;\n", GNUNET_h2s_full(&from_node->hashPubKey));
430   else
431     ret = fprintf(outfile, "set @temp_from_node = 0;\n");
432
433   if (to_node != NULL)
434     ret = fprintf(outfile, "select nodeuid from nodes where trialuid = @temp_trial and nodeid = \"%s\" into @temp_to_node;\n", GNUNET_h2s_full(&to_node->hashPubKey));
435   else
436     ret = fprintf(outfile, "set @temp_to_node = 0;\n");
437
438   ret = fprintf(outfile, "set @qid = %llu, @type = %u, @hops = %u, @succ = %d;\n", queryid, type, hops, succeeded);
439
440   if (ret < 0)
441     return GNUNET_SYSERR;
442
443   ret = fprintf(outfile, "execute insert_route using @type, @hops, @temp_dhtkey, @qid, @succ, @temp_node, @temp_from_node, @temp_to_node;\n");
444
445   if (ret >= 0)
446     return GNUNET_OK;
447   else
448     return GNUNET_SYSERR;
449 }
450
451 /*
452  * Provides the dhtlog api
453  *
454  * @param c the configuration to use to connect to a server
455  *
456  * @return the handle to the server, or NULL on error
457  */
458 void *
459 libgnunet_plugin_dhtlog_mysql_dump_init (void * cls)
460 {
461   struct GNUNET_DHTLOG_Plugin *plugin = cls;
462   char *outfile_name;
463   char *outfile_path;
464   char *fn;
465   int dirwarn;
466
467   cfg = plugin->cfg;
468   max_varchar_len = 255;
469
470 #if DEBUG_DHTLOG
471   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MySQL (DUMP) DHT Logger: initializing\n");
472 #endif
473
474   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
475                                                          "MYSQLDUMP", "PATH",
476                                                          &outfile_path))
477     {
478       outfile_path = GNUNET_strdup("");
479     }
480
481   GNUNET_asprintf (&outfile_name,
482                    "%s%s-%d",
483                    outfile_path,
484                    "mysqldump",
485                    getpid());
486
487   fn = GNUNET_STRINGS_filename_expand (outfile_name);
488
489   dirwarn = (GNUNET_OK !=  GNUNET_DISK_directory_create_for_file (fn));
490   outfile = FOPEN (fn, "w");
491
492   if (outfile == NULL)
493     {
494       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "fopen", fn);
495       if (dirwarn)
496         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
497                     _("Failed to create or access directory for log file `%s'\n"),
498                     fn);
499       GNUNET_free(outfile_path);
500       GNUNET_free(outfile_name);
501       GNUNET_free (fn);
502       return NULL;
503     }
504
505   GNUNET_free (outfile_path);
506   GNUNET_free (outfile_name);
507   GNUNET_free (fn);
508
509   if (iopen () != GNUNET_OK)
510     {
511       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
512                   _("Failed to create file for dhtlog.\n"));
513       return NULL;
514     }
515   GNUNET_assert(plugin->dhtlog_api == NULL);
516   plugin->dhtlog_api = GNUNET_malloc(sizeof(struct GNUNET_DHTLOG_Handle));
517   plugin->dhtlog_api->insert_trial = &add_trial;
518   plugin->dhtlog_api->insert_query = &add_query;
519   plugin->dhtlog_api->update_trial = &update_trials;
520   plugin->dhtlog_api->insert_route = &add_route;
521   plugin->dhtlog_api->insert_node = &add_node;
522   plugin->dhtlog_api->insert_dhtkey = &add_dhtkey;
523   plugin->dhtlog_api->update_connections = &add_connections;
524
525   return NULL;
526 }
527
528 /**
529  * Shutdown the plugin.
530  */
531 void *
532 libgnunet_plugin_dhtlog_mysql_dump_done (void * cls)
533 {
534   struct GNUNET_DHTLOG_Handle *dhtlog_api = cls;
535 #if DEBUG_DHTLOG
536   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
537               "MySQL DHT Logger: database shutdown\n");
538 #endif
539   GNUNET_assert(dhtlog_api != NULL);
540
541   GNUNET_free(dhtlog_api);
542   return NULL;
543 }
544
545 /* end of plugin_dhtlog_mysql.c */