2 This file is part of GNUnet.
3 (C) 2006 - 2009 Christian Grothoff (and other contributing authors)
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.
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.
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.
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
34 #include "gnunet_util_lib.h"
38 #define DEBUG_DHTLOG GNUNET_NO
41 * Maximum number of supported parameters for a prepared
42 * statement. Increase if needed.
47 static unsigned long max_varchar_len;
50 * The configuration the DHT service is running with
52 static const struct GNUNET_CONFIGURATION_Handle *cfg;
54 #define INSERT_QUERIES_STMT "prepare insert_query from 'INSERT INTO queries (trialuid, querytype, hops, dhtkeyuid, dhtqueryid, succeeded, nodeuid) "\
55 "VALUES (@temp_trial, ?, ?, ?, ?, ?, ?)'"
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, ?, ?, ?, ?, ?, ?, ?, ?)'"
60 #define INSERT_NODES_STMT "prepare insert_node from 'INSERT INTO nodes (trialuid, nodeid) "\
61 "VALUES (@temp_trial, ?)'"
63 #define INSERT_TOPOLOGY_STMT "prepare insert_topology from 'INSERT INTO topology (trialuid, date, connections) "\
64 "VALUES (@temp_trial, ?, ?)'"
66 #define EXTEND_TOPOLOGY_STMT "prepare extend_topology from 'INSERT INTO extended_topology (topology_uid, uid_first, uid_second) "\
67 "VALUES (@temp_topology, ?, ?)'"
69 #define UPDATE_TOPOLOGY_STMT "prepare update_topology from 'update topology set connections = ? where topology_uid = @temp_topology'"
71 #define INSERT_TRIALS_STMT "prepare insert_trial from 'INSERT INTO trials"\
72 "(starttime, numnodes, topology,"\
73 "topology_percentage, topology_probability,"\
74 "blacklist_topology, connect_topology, connect_topology_option,"\
75 "connect_topology_option_modifier, puts, gets, "\
76 "concurrent, settle_time, num_rounds, malicious_getters,"\
77 "malicious_putters, malicious_droppers, message) "\
78 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'"
80 #define INSERT_DHTKEY_STMT "prepare insert_dhtkey from 'INSERT ignore INTO dhtkeys (dhtkey, trialuid) "\
81 "VALUES (?, @temp_trial)'"
83 #define UPDATE_TRIALS_STMT "prepare update_trial from 'UPDATE trials set endtime= ?, total_messages_dropped = ?, total_bytes_dropped = ?, unknownPeers = ? where trialuid = @temp_trial'"
85 #define UPDATE_CONNECTIONS_STMT "prepare update_conn from 'UPDATE trials set totalConnections = ? where trialuid = @temp_trial'"
87 #define GET_TRIAL_STMT "prepare select_trial from 'SELECT MAX( trialuid ) FROM trials into @temp_trial'"
89 #define GET_TOPOLOGY_STMT "prepare select_topology from 'SELECT MAX( topology_uid ) FROM topology into @temp_topology'"
91 #define GET_DHTKEYUID_STMT "prepare get_dhtkeyuid from 'SELECT dhtkeyuid FROM dhtkeys where dhtkey = ? and trialuid = @temp_trial'"
93 #define GET_NODEUID_STMT "prepare get_nodeuid from 'SELECT nodeuid FROM nodes where trialuid = @temp_trial and nodeid = ?'"
95 #define DATE_STR_SIZE 50
98 * File to dump all sql statements to.
106 static char date[DATE_STR_SIZE];
111 memset (date, 0, DATE_STR_SIZE);
112 tmptr = localtime (&timetmp);
114 strftime (date, DATE_STR_SIZE, "%Y-%m-%d %H:%M:%S", tmptr);
122 * Create a prepared statement.
124 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
127 prepared_statement_create (const char *statement)
129 if (fprintf(outfile, "%s;\n", statement) > 0)
132 return GNUNET_SYSERR;
136 * Initialize the prepared statements for use with dht test logging
141 #define PINIT(a) (GNUNET_OK != (prepared_statement_create(a)))
142 if (PINIT (INSERT_QUERIES_STMT) ||
143 PINIT (INSERT_ROUTES_STMT) ||
144 PINIT (INSERT_TRIALS_STMT) ||
145 PINIT (INSERT_NODES_STMT) ||
146 PINIT (INSERT_DHTKEY_STMT) ||
147 PINIT (UPDATE_TRIALS_STMT) ||
148 PINIT (GET_DHTKEYUID_STMT) ||
149 PINIT (GET_NODEUID_STMT) ||
150 PINIT (UPDATE_CONNECTIONS_STMT) ||
151 PINIT (INSERT_TOPOLOGY_STMT) ||
152 PINIT (EXTEND_TOPOLOGY_STMT) ||
153 PINIT (UPDATE_TOPOLOGY_STMT) ||
154 PINIT (GET_TRIAL_STMT) ||
155 PINIT (GET_TOPOLOGY_STMT))
157 return GNUNET_SYSERR;
167 * Records the current topology (number of connections, time, trial)
169 * @param num_connections how many connections are in the topology
171 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
174 add_topology (int num_connections)
178 return GNUNET_SYSERR;
180 ret = fprintf(outfile, "set @date = \"%s\", @num = %d;\n", get_sql_time(), num_connections);
183 return GNUNET_SYSERR;
184 ret = fprintf(outfile, "execute insert_topology using "
187 ret = fprintf(outfile, "execute select_topology;\n");
191 return GNUNET_SYSERR;
195 * Records a connection between two peers in the current topology
197 * @param first one side of the connection
198 * @param second other side of the connection
200 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
203 add_extended_topology (struct GNUNET_PeerIdentity *first, struct GNUNET_PeerIdentity *second)
207 return GNUNET_SYSERR;
210 ret = fprintf(outfile, "select nodeuid from nodes where trialuid = @temp_trial and nodeid = \"%s\" into @temp_first_node;\n", GNUNET_h2s_full(&first->hashPubKey));
212 ret = fprintf(outfile, "set @temp_first_node = 0;\n");
215 return GNUNET_SYSERR;
218 ret = fprintf(outfile, "select nodeuid from nodes where trialuid = @temp_trial and nodeid = \"%s\" into @temp_second_node;\n", GNUNET_h2s_full(&second->hashPubKey));
220 ret = fprintf(outfile, "set @temp_second_node = 0;\n");
223 return GNUNET_SYSERR;
225 ret = fprintf(outfile, "execute extend_topology using "
226 "@temp_first_node, @temp_second_node;\n");
230 return GNUNET_SYSERR;
235 * Inserts the specified trial into the dhttests.trials table
237 * @param trialuid return the trialuid of the newly inserted trial
238 * @param num_nodes how many nodes are in the trial
239 * @param topology integer representing topology for this trial
240 * @param blacklist_topology integer representing blacklist topology for this trial
241 * @param connect_topology integer representing connect topology for this trial
242 * @param connect_topology_option integer representing connect topology option
243 * @param connect_topology_option_modifier float to modify connect option
244 * @param topology_percentage percentage modifier for certain topologies
245 * @param topology_probability probability modifier for certain topologies
246 * @param puts number of puts to perform
247 * @param gets number of gets to perform
248 * @param concurrent number of concurrent requests
249 * @param settle_time time to wait between creating topology and starting testing
250 * @param num_rounds number of times to repeat the trial
251 * @param malicious_getters number of malicious GET peers in the trial
252 * @param malicious_putters number of malicious PUT peers in the trial
253 * @param malicious_droppers number of malicious DROP peers in the trial
254 * @param message string to put into DB for this trial
256 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
259 add_trial (unsigned long long *trialuid, int num_nodes, int topology,
260 int blacklist_topology, int connect_topology,
261 int connect_topology_option, float connect_topology_option_modifier,
262 float topology_percentage, float topology_probability,
263 int puts, int gets, int concurrent, int settle_time,
264 int num_rounds, int malicious_getters, int malicious_putters,
265 int malicious_droppers, char *message)
268 if (trialuid != NULL)
271 return GNUNET_SYSERR;
273 ret = fprintf(outfile, "set @date = \"%s\", @num = %d, @topology = %d, @bl = %d, "
274 "@connect = %d, @c_t_o = %d, @c_t_o_m = %f, @t_p = %f, "
275 "@t_pr = %f, @puts = %d, @gets = %d, "
276 "@concurrent = %d, @settle = %d, @rounds = %d, "
277 "@m_gets = %d, @m_puts = %d, @m_drops = %d, "
278 "@message = \"%s\";\n", get_sql_time(), num_nodes, topology,
279 blacklist_topology, connect_topology,
280 connect_topology_option, connect_topology_option_modifier,
281 topology_percentage, topology_probability,
282 puts, gets, concurrent, settle_time,
283 num_rounds, malicious_getters, malicious_putters,
284 malicious_droppers, message);
287 return GNUNET_SYSERR;
288 ret = fprintf(outfile, "execute insert_trial using "
289 "@date, @num, @topology, @t_p, @t_pr,"
290 " @bl, @connect, @c_t_o,"
291 "@c_t_o_m, @puts, @gets,"
292 "@concurrent, @settle, @rounds,"
293 "@m_gets, @m_puts, @m_drops,"
296 ret = fprintf(outfile, "execute select_trial;\n");
300 return GNUNET_SYSERR;
305 * Inserts the specified dhtkey into the dhttests.dhtkeys table,
306 * stores return value of dhttests.dhtkeys.dhtkeyuid into dhtkeyuid
308 * @param dhtkeyuid return value
309 * @param dhtkey hashcode of key to insert
311 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
314 add_dhtkey (unsigned long long *dhtkeyuid, const GNUNET_HashCode * dhtkey)
317 if (dhtkeyuid != NULL)
321 return GNUNET_SYSERR;
324 ret = fprintf(outfile, "set @dhtkey = \"%s\";\n", GNUNET_h2s_full(dhtkey));
326 ret = fprintf(outfile, "set @dhtkey = XXXXX;\n");
329 return GNUNET_SYSERR;
330 ret = fprintf(outfile, "execute insert_dhtkey using @dhtkey;\n");
334 return GNUNET_SYSERR;
338 * Inserts the specified node into the dhttests.nodes table
340 * @param nodeuid the inserted node uid
341 * @param node the node to insert
343 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
346 add_node (unsigned long long *nodeuid, struct GNUNET_PeerIdentity * node)
351 return GNUNET_SYSERR;
354 return GNUNET_SYSERR;
357 ret = fprintf(outfile, "set @node = \"%s\";\n", GNUNET_h2s_full(&node->hashPubKey));
359 return GNUNET_SYSERR;
362 return GNUNET_SYSERR;
364 ret = fprintf(outfile, "execute insert_node using @node;\n");
368 return GNUNET_SYSERR;
372 * Update dhttests.trials table with current server time as end time
374 * @param trialuid trial to update
375 * @param totalMessagesDropped stats value for messages dropped
376 * @param totalBytesDropped stats value for total bytes dropped
377 * @param unknownPeers stats value for unknown peers
379 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
382 update_trials (unsigned long long trialuid,
383 unsigned long long totalMessagesDropped,
384 unsigned long long totalBytesDropped,
385 unsigned long long unknownPeers)
389 if (trialuid != current_trial)
392 _("Trialuid to update is not equal to current_trial\n"));
397 return GNUNET_SYSERR;
399 ret = fprintf(outfile, "set @date = \"%s\", @m_dropped = %llu, @b_dropped = %llu, @unknown = %llu;\n", get_sql_time(), totalMessagesDropped, totalBytesDropped, unknownPeers);
402 return GNUNET_SYSERR;
404 ret = fprintf(outfile, "execute update_trial using @date, @m_dropped, @b_dropped, @unknown;\n");
409 return GNUNET_SYSERR;
414 * Update dhttests.trials table with total connections information
416 * @param trialuid the trialuid to update
417 * @param totalConnections the number of connections
419 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
422 add_connections (unsigned long long trialuid, unsigned int totalConnections)
426 if (trialuid != current_trial)
429 _("Trialuid to update is not equal to current_trial(!)(?)\n"));
433 return GNUNET_SYSERR;
435 ret = fprintf(outfile, "set @conns = %u;\n", totalConnections);
438 return GNUNET_SYSERR;
440 ret = fprintf(outfile, "execute update_conn using @conns;\n");
445 return GNUNET_SYSERR;
450 * Update dhttests.topology table with total connections information
452 * @param totalConnections the number of connections
454 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
457 update_topology (unsigned int connections)
461 return GNUNET_SYSERR;
463 ret = fprintf(outfile, "set @temp_conns = %u;\n", connections);
466 return GNUNET_SYSERR;
468 ret = fprintf(outfile, "execute update_topology using @temp_conns;\n");
473 return GNUNET_SYSERR;
477 * Inserts the specified query into the dhttests.queries table
479 * @param sqlqueruid inserted query uid
480 * @param queryid dht query id
481 * @param type type of the query
482 * @param hops number of hops query traveled
483 * @param succeeded whether or not query was successful
484 * @param node the node the query hit
485 * @param key the key of the query
487 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
490 add_query (unsigned long long *sqlqueryuid, unsigned long long queryid,
491 unsigned int type, unsigned int hops, int succeeded,
492 const struct GNUNET_PeerIdentity * node, const GNUNET_HashCode * key)
497 return GNUNET_SYSERR;
499 if (sqlqueryuid != NULL)
503 ret = fprintf(outfile, "select dhtkeyuid from dhtkeys where trialuid = @temp_trial and dhtkey = \"%s\" into @temp_dhtkey;\n", GNUNET_h2s_full(key));
505 ret = fprintf(outfile, "set @temp_dhtkey = 0;\n");
508 ret = fprintf(outfile, "select nodeuid from nodes where trialuid = @temp_trial and nodeid = \"%s\" into @temp_node;\n", GNUNET_h2s_full(&node->hashPubKey));
510 ret = fprintf(outfile, "set @temp_node = 0;\n");
512 ret = fprintf(outfile, "set @qid = %llu, @type = %u, @hops = %u, @succ = %d;\n", queryid, type, hops, succeeded);
515 return GNUNET_SYSERR;
517 ret = fprintf(outfile, "execute insert_query using @type, @hops, @temp_dhtkey, @qid, @succ, @temp_node;\n");
522 return GNUNET_SYSERR;
526 * Inserts the specified route information into the dhttests.routes table
528 * @param sqlqueruid inserted query uid
529 * @param queryid dht query id
530 * @param type type of the query
531 * @param hops number of hops query traveled
532 * @param succeeded whether or not query was successful
533 * @param node the node the query hit
534 * @param key the key of the query
535 * @param from_node the node that sent the message to node
536 * @param to_node next node to forward message to
538 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
541 add_route (unsigned long long *sqlqueryuid, unsigned long long queryid,
542 unsigned int type, unsigned int hops,
543 int succeeded, const struct GNUNET_PeerIdentity * node,
544 const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity * from_node,
545 const struct GNUNET_PeerIdentity * to_node)
550 return GNUNET_SYSERR;
552 if (sqlqueryuid != NULL)
556 ret = fprintf(outfile, "select dhtkeyuid from dhtkeys where trialuid = @temp_trial and dhtkey = \"%s\" into @temp_dhtkey;\n", GNUNET_h2s_full(key));
558 ret = fprintf(outfile, "set @temp_dhtkey = 0;\n");
561 ret = fprintf(outfile, "select nodeuid from nodes where trialuid = @temp_trial and nodeid = \"%s\" into @temp_node;\n", GNUNET_h2s_full(&node->hashPubKey));
563 ret = fprintf(outfile, "set @temp_node = 0;\n");
565 if (from_node != NULL)
566 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));
568 ret = fprintf(outfile, "set @temp_from_node = 0;\n");
571 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));
573 ret = fprintf(outfile, "set @temp_to_node = 0;\n");
575 ret = fprintf(outfile, "set @qid = %llu, @type = %u, @hops = %u, @succ = %d;\n", queryid, type, hops, succeeded);
578 return GNUNET_SYSERR;
580 ret = fprintf(outfile, "execute insert_route using @type, @hops, @temp_dhtkey, @qid, @succ, @temp_node, @temp_from_node, @temp_to_node;\n");
585 return GNUNET_SYSERR;
589 * Provides the dhtlog api
591 * @param c the configuration to use to connect to a server
593 * @return the handle to the server, or NULL on error
596 libgnunet_plugin_dhtlog_mysql_dump_init (void * cls)
598 struct GNUNET_DHTLOG_Plugin *plugin = cls;
605 max_varchar_len = 255;
608 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MySQL (DUMP) DHT Logger: initializing\n");
611 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
615 outfile_path = GNUNET_strdup("");
618 GNUNET_asprintf (&outfile_name,
624 fn = GNUNET_STRINGS_filename_expand (outfile_name);
626 dirwarn = (GNUNET_OK != GNUNET_DISK_directory_create_for_file (fn));
627 outfile = FOPEN (fn, "w");
631 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "fopen", fn);
633 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
634 _("Failed to create or access directory for log file `%s'\n"),
636 GNUNET_free(outfile_path);
637 GNUNET_free(outfile_name);
642 GNUNET_free (outfile_path);
643 GNUNET_free (outfile_name);
646 if (iopen () != GNUNET_OK)
648 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
649 _("Failed to create file for dhtlog.\n"));
652 GNUNET_assert(plugin->dhtlog_api == NULL);
653 plugin->dhtlog_api = GNUNET_malloc(sizeof(struct GNUNET_DHTLOG_Handle));
654 plugin->dhtlog_api->insert_trial = &add_trial;
655 plugin->dhtlog_api->insert_query = &add_query;
656 plugin->dhtlog_api->update_trial = &update_trials;
657 plugin->dhtlog_api->insert_route = &add_route;
658 plugin->dhtlog_api->insert_node = &add_node;
659 plugin->dhtlog_api->insert_dhtkey = &add_dhtkey;
660 plugin->dhtlog_api->update_connections = &add_connections;
661 plugin->dhtlog_api->insert_topology = &add_topology;
662 plugin->dhtlog_api->insert_extended_topology = &add_extended_topology;
663 plugin->dhtlog_api->update_topology = &update_topology;
669 * Shutdown the plugin.
672 libgnunet_plugin_dhtlog_mysql_dump_done (void * cls)
674 struct GNUNET_DHTLOG_Handle *dhtlog_api = cls;
676 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
677 "MySQL DHT Logger: database shutdown\n");
679 GNUNET_assert(dhtlog_api != NULL);
681 GNUNET_free(dhtlog_api);
685 /* end of plugin_dhtlog_mysql.c */