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 * @author Nathan Evans
30 #include "gnunet_util_lib.h"
32 #include <mysql/mysql.h>
35 #define DEBUG_DHTLOG GNUNET_YES
38 * Maximum number of supported parameters for a prepared
39 * statement. Increase if needed.
44 * A generic statement handle to use
45 * for prepared statements. This way,
46 * once the statement is initialized
49 struct StatementHandle
54 MYSQL_STMT *statement;
62 * Whether or not the handle is valid
68 * Type of a callback that will be called for each
69 * data set returned from MySQL.
71 * @param cls user-defined argument
72 * @param num_values number of elements in values
73 * @param values values returned by MySQL
74 * @return GNUNET_OK to continue iterating, GNUNET_SYSERR to abort
76 typedef int (*GNUNET_MysqlDataProcessor) (void *cls,
77 unsigned int num_values,
80 static unsigned long max_varchar_len;
83 * The configuration the DHT service is running with
85 static const struct GNUNET_CONFIGURATION_Handle *cfg;
87 static unsigned long long current_trial = 0; /* I like to assign 0, just to remember */
90 * Connection to the MySQL Server.
94 #define INSERT_QUERIES_STMT "INSERT INTO queries (trialuid, querytype, hops, dhtkeyuid, dhtqueryid, succeeded, nodeuid) "\
95 "VALUES (?, ?, ?, ?, ?, ?, ?)"
96 static struct StatementHandle *insert_query;
98 #define INSERT_ROUTES_STMT "INSERT INTO routes (trialuid, querytype, hops, dhtkeyuid, dhtqueryid, succeeded, nodeuid, from_node, to_node) "\
99 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"
100 static struct StatementHandle *insert_route;
102 #define INSERT_NODES_STMT "INSERT INTO nodes (trialuid, nodeid, nodebits) "\
104 static struct StatementHandle *insert_node;
106 #define INSERT_TRIALS_STMT "INSERT INTO trials"\
107 "(starttime, other_trial_identifier, numnodes, topology,"\
108 "topology_percentage, topology_probability,"\
109 "blacklist_topology, connect_topology, connect_topology_option,"\
110 "connect_topology_option_modifier, puts, gets, "\
111 "concurrent, settle_time, num_rounds, malicious_getters,"\
112 "malicious_putters, malicious_droppers, malicious_get_frequency,"\
113 "malicious_put_frequency, stop_closest, stop_found, strict_kademlia, "\
114 "gets_succeeded, message) "\
115 "VALUES (NOW(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
117 static struct StatementHandle *insert_trial;
119 #define INSERT_STAT_STMT "INSERT INTO node_statistics"\
120 "(trialuid, nodeuid, route_requests,"\
121 "route_forwards, result_requests,"\
122 "client_results, result_forwards, gets,"\
123 "puts, data_inserts, find_peer_requests, "\
124 "find_peers_started, gets_started, puts_started, find_peer_responses_received,"\
125 "get_responses_received, find_peer_responses_sent, get_responses_sent) "\
126 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
128 static struct StatementHandle *insert_stat;
130 #define INSERT_GENERIC_STAT_STMT "INSERT INTO generic_stats" \
131 "(trialuid, nodeuid, section, name, value)"\
132 "VALUES (?, ?, ?, ?, ?)"
133 static struct StatementHandle *insert_generic_stat;
135 #define INSERT_DHTKEY_STMT "INSERT INTO dhtkeys (dhtkey, trialuid, keybits) "\
137 static struct StatementHandle *insert_dhtkey;
139 #define UPDATE_TRIALS_STMT "UPDATE trials set endtime=NOW(), gets_succeeded = ? where trialuid = ?"
140 static struct StatementHandle *update_trial;
142 #define UPDATE_CONNECTIONS_STMT "UPDATE trials set totalConnections = ? where trialuid = ?"
143 static struct StatementHandle *update_connection;
145 #define GET_TRIAL_STMT "SELECT MAX( trialuid ) FROM trials"
146 static struct StatementHandle *get_trial;
148 #define GET_TOPOLOGY_STMT "SELECT MAX( topology_uid ) FROM topology"
149 static struct StatementHandle *get_topology;
151 #define GET_DHTKEYUID_STMT "SELECT dhtkeyuid FROM dhtkeys where dhtkey = ? and trialuid = ?"
152 static struct StatementHandle *get_dhtkeyuid;
154 #define GET_NODEUID_STMT "SELECT nodeuid FROM nodes where trialuid = ? and nodeid = ?"
155 static struct StatementHandle *get_nodeuid;
157 #define INSERT_TOPOLOGY_STMT "INSERT INTO topology (trialuid, date, connections) "\
158 "VALUES (?, NOW(), ?)"
159 static struct StatementHandle *insert_topology;
161 #define EXTEND_TOPOLOGY_STMT "INSERT INTO extended_topology (topology_uid, uid_first, uid_second) "\
163 static struct StatementHandle *extend_topology;
165 #define SET_MALICIOUS_STMT "update nodes set malicious_dropper = 1 where trialuid = ? and nodeid = ?"
166 static struct StatementHandle *update_node_malicious;
168 #define UPDATE_TOPOLOGY_STMT "update topology set connections = ? where topology_uid = ?"
169 static struct StatementHandle *update_topology;
172 * Run a query (not a select statement)
174 * @return GNUNET_OK if executed, GNUNET_SYSERR if an error occurred
177 run_statement (const char *statement)
179 mysql_query (conn, statement);
180 if (mysql_error (conn)[0])
182 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
184 return GNUNET_SYSERR;
190 * Creates tables if they don't already exist for dht logging
195 #define MRUNS(a) (GNUNET_OK != run_statement (a) )
197 if (MRUNS ("CREATE TABLE IF NOT EXISTS `dhtkeys` ("
198 "dhtkeyuid int(10) unsigned NOT NULL auto_increment COMMENT 'Unique Key given to each query',"
199 "`dhtkey` varchar(255) NOT NULL COMMENT 'The ASCII value of the key being searched for',"
200 "trialuid int(10) unsigned NOT NULL,"
201 "keybits blob NOT NULL,"
202 "UNIQUE KEY `dhtkeyuid` (`dhtkeyuid`)"
203 ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
204 return GNUNET_SYSERR;
206 if (MRUNS ("CREATE TABLE IF NOT EXISTS `nodes` ("
207 "`nodeuid` int(10) unsigned NOT NULL auto_increment,"
208 "`trialuid` int(10) unsigned NOT NULL,"
209 "`nodeid` varchar(255) NOT NULL,"
210 "`nodebits` blob NOT NULL,"
211 "PRIMARY KEY (`nodeuid`)"
212 ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
213 return GNUNET_SYSERR;
215 if (MRUNS ("CREATE TABLE IF NOT EXISTS `queries` ("
216 "`trialuid` int(10) unsigned NOT NULL,"
217 "`queryuid` int(10) unsigned NOT NULL auto_increment,"
218 "`dhtqueryid` bigint(20) NOT NULL,"
219 "`querytype` enum('1','2','3','4','5') NOT NULL,"
220 "`hops` int(10) unsigned NOT NULL,"
221 "`succeeded` tinyint NOT NULL,"
222 "`nodeuid` int(10) unsigned NOT NULL,"
223 "`time` timestamp NOT NULL default CURRENT_TIMESTAMP,"
224 "`dhtkeyuid` int(10) unsigned NOT NULL,"
225 "PRIMARY KEY (`queryuid`)"
226 ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
227 return GNUNET_SYSERR;
229 if (MRUNS ("CREATE TABLE IF NOT EXISTS `routes` ("
230 "`trialuid` int(10) unsigned NOT NULL,"
231 "`queryuid` int(10) unsigned NOT NULL auto_increment,"
232 "`dhtqueryid` bigint(20) NOT NULL,"
233 "`querytype` enum('1','2','3','4','5') NOT NULL,"
234 "`hops` int(10) unsigned NOT NULL,"
235 "`succeeded` tinyint NOT NULL,"
236 "`nodeuid` int(10) unsigned NOT NULL,"
237 "`time` timestamp NOT NULL default CURRENT_TIMESTAMP,"
238 "`dhtkeyuid` int(10) unsigned NOT NULL,"
239 "`from_node` int(10) unsigned NOT NULL,"
240 "`to_node` int(10) unsigned NOT NULL,"
241 "PRIMARY KEY (`queryuid`)"
242 ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
243 return GNUNET_SYSERR;
245 if (MRUNS ("CREATE TABLE IF NOT EXISTS `trials` ("
246 "`trialuid` int(10) unsigned NOT NULL auto_increment,"
247 "`other_trial_identifier` int(10) unsigned NOT NULL default '0',"
248 "`numnodes` int(10) unsigned NOT NULL,"
249 "`topology` int(10) NOT NULL,"
250 "`blacklist_topology` int(11) NOT NULL,"
251 "`connect_topology` int(11) NOT NULL,"
252 "`connect_topology_option` int(11) NOT NULL,"
253 "`topology_percentage` float NOT NULL,"
254 "`topology_probability` float NOT NULL,"
255 "`connect_topology_option_modifier` float NOT NULL,"
256 "`starttime` datetime NOT NULL,"
257 "`endtime` datetime NOT NULL,"
258 "`puts` int(10) unsigned NOT NULL,"
259 "`gets` int(10) unsigned NOT NULL,"
260 "`concurrent` int(10) unsigned NOT NULL,"
261 "`settle_time` int(10) unsigned NOT NULL,"
262 "`totalConnections` int(10) unsigned NOT NULL,"
263 "`message` text NOT NULL,"
264 "`num_rounds` int(10) unsigned NOT NULL,"
265 "`malicious_getters` int(10) unsigned NOT NULL,"
266 "`malicious_putters` int(10) unsigned NOT NULL,"
267 "`malicious_droppers` int(10) unsigned NOT NULL,"
268 "`topology_modifier` double NOT NULL,"
269 "`malicious_get_frequency` int(10) unsigned NOT NULL,"
270 "`malicious_put_frequency` int(10) unsigned NOT NULL,"
271 "`stop_closest` int(10) unsigned NOT NULL,"
272 "`stop_found` int(10) unsigned NOT NULL,"
273 "`strict_kademlia` int(10) unsigned NOT NULL,"
274 "`gets_succeeded` int(10) unsigned NOT NULL,"
275 "PRIMARY KEY (`trialuid`),"
276 "UNIQUE KEY `trialuid` (`trialuid`)"
277 ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
278 return GNUNET_SYSERR;
280 if (MRUNS ("CREATE TABLE IF NOT EXISTS `topology` ("
281 "`topology_uid` int(10) unsigned NOT NULL AUTO_INCREMENT,"
282 "`trialuid` int(10) unsigned NOT NULL,"
283 "`date` datetime NOT NULL,"
284 "`connections` int(10) unsigned NOT NULL,"
285 "PRIMARY KEY (`topology_uid`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
286 return GNUNET_SYSERR;
288 if (MRUNS ("CREATE TABLE IF NOT EXISTS `extended_topology` ("
289 "`extended_uid` int(10) unsigned NOT NULL AUTO_INCREMENT,"
290 "`topology_uid` int(10) unsigned NOT NULL,"
291 "`uid_first` int(10) unsigned NOT NULL,"
292 "`uid_second` int(10) unsigned NOT NULL,"
293 "PRIMARY KEY (`extended_uid`)"
294 ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"))
295 return GNUNET_SYSERR;
297 if (MRUNS ("CREATE TABLE IF NOT EXISTS `node_statistics` ("
298 "`stat_uid` int(10) unsigned NOT NULL AUTO_INCREMENT,"
299 "`trialuid` int(10) unsigned NOT NULL,"
300 "`nodeuid` int(10) unsigned NOT NULL,"
301 "`route_requests` int(10) unsigned NOT NULL,"
302 "`route_forwards` int(10) unsigned NOT NULL,"
303 "`result_requests` int(10) unsigned NOT NULL,"
304 "`client_results` int(10) unsigned NOT NULL,"
305 "`result_forwards` int(10) unsigned NOT NULL,"
306 "`gets` int(10) unsigned NOT NULL,"
307 "`puts` int(10) unsigned NOT NULL,"
308 "`data_inserts` int(10) unsigned NOT NULL,"
309 "`find_peer_requests` int(10) unsigned NOT NULL,"
310 "`find_peers_started` int(10) unsigned NOT NULL,"
311 "`gets_started` int(10) unsigned NOT NULL,"
312 "`puts_started` int(10) unsigned NOT NULL,"
313 "`find_peer_responses_received` int(10) unsigned NOT NULL,"
314 "`get_responses_received` int(10) unsigned NOT NULL,"
315 "`find_peer_responses_sent` int(10) unsigned NOT NULL,"
316 "`get_responses_sent` int(10) unsigned NOT NULL,"
317 "PRIMARY KEY (`stat_uid`)"
318 ") ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;"))
319 return GNUNET_SYSERR;
321 if (MRUNS ("SET AUTOCOMMIT = 1"))
322 return GNUNET_SYSERR;
329 * Create a prepared statement.
331 * @return NULL on error
333 struct StatementHandle *
334 prepared_statement_create (const char *statement)
336 struct StatementHandle *ret;
338 ret = GNUNET_malloc (sizeof (struct StatementHandle));
339 ret->query = GNUNET_strdup (statement);
344 * Close a prepared statement.
346 * @return NULL on error
349 prepared_statement_close (struct StatementHandle *s)
356 GNUNET_free_non_null(s->query);
358 if (s->valid == GNUNET_YES)
359 mysql_stmt_close(s->statement);
364 * Initialize the prepared statements for use with dht test logging
367 iopen (struct GNUNET_DHTLOG_Plugin *plugin)
371 unsigned int timeout;
376 unsigned long long port;
378 conn = mysql_init (NULL);
380 return GNUNET_SYSERR;
382 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
386 database = GNUNET_strdup("gnunet");
389 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
390 "MYSQL", "USER", &user))
392 user = GNUNET_strdup("dht");
395 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
396 "MYSQL", "PASSWORD", &password))
398 password = GNUNET_strdup("dhttest**");
401 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (plugin->cfg,
402 "MYSQL", "SERVER", &server))
404 server = GNUNET_strdup("localhost");
407 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (plugin->cfg,
408 "MYSQL", "MYSQL_PORT", &port))
413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to mysql with: user %s, pass %s, server %s, database %s, port %d\n",
414 user, password, server, database, port);
417 timeout = 60; /* in seconds */
418 mysql_options (conn, MYSQL_OPT_RECONNECT, &reconnect);
420 MYSQL_OPT_CONNECT_TIMEOUT, (const void *) &timeout);
421 mysql_options(conn, MYSQL_SET_CHARSET_NAME, "UTF8");
422 mysql_options (conn, MYSQL_OPT_READ_TIMEOUT, (const void *) &timeout);
423 mysql_options (conn, MYSQL_OPT_WRITE_TIMEOUT, (const void *) &timeout);
424 mysql_real_connect (conn, server, user, password,
425 database, (unsigned int) port, NULL, CLIENT_IGNORE_SIGPIPE);
427 GNUNET_free_non_null(server);
428 GNUNET_free_non_null(password);
429 GNUNET_free_non_null(user);
430 GNUNET_free_non_null(database);
432 if (mysql_error (conn)[0])
434 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
435 "mysql_real_connect");
436 return GNUNET_SYSERR;
440 db = GNUNET_MYSQL_database_open (coreAPI->ectx, coreAPI->cfg);
442 return GNUNET_SYSERR;
447 #define PINIT(a,b) (NULL == (a = prepared_statement_create(b)))
448 if (PINIT (insert_query, INSERT_QUERIES_STMT) ||
449 PINIT (insert_route, INSERT_ROUTES_STMT) ||
450 PINIT (insert_trial, INSERT_TRIALS_STMT) ||
451 PINIT (insert_stat, INSERT_STAT_STMT) ||
452 PINIT (insert_generic_stat, INSERT_GENERIC_STAT_STMT) ||
453 PINIT (insert_node, INSERT_NODES_STMT) ||
454 PINIT (insert_dhtkey, INSERT_DHTKEY_STMT) ||
455 PINIT (update_trial, UPDATE_TRIALS_STMT) ||
456 PINIT (get_dhtkeyuid, GET_DHTKEYUID_STMT) ||
457 PINIT (get_nodeuid, GET_NODEUID_STMT) ||
458 PINIT (update_connection, UPDATE_CONNECTIONS_STMT) ||
459 PINIT (get_trial, GET_TRIAL_STMT) ||
460 PINIT (get_topology, GET_TOPOLOGY_STMT) ||
461 PINIT (insert_topology, INSERT_TOPOLOGY_STMT) ||
462 PINIT (update_topology, UPDATE_TOPOLOGY_STMT) ||
463 PINIT (extend_topology, EXTEND_TOPOLOGY_STMT) ||
464 PINIT (update_node_malicious, SET_MALICIOUS_STMT) )
466 return GNUNET_SYSERR;
474 return_ok (void *cls, unsigned int num_values, MYSQL_BIND * values)
480 * Prepare a statement for running.
482 * @return GNUNET_OK on success
485 prepare_statement (struct StatementHandle *ret)
487 if (GNUNET_YES == ret->valid)
490 ret->statement = mysql_stmt_init (conn);
491 if (ret->statement == NULL)
492 return GNUNET_SYSERR;
494 if (mysql_stmt_prepare (ret->statement, ret->query, strlen (ret->query)))
496 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
497 "mysql_stmt_prepare `%s', %s", ret->query, mysql_error(conn));
498 mysql_stmt_close (ret->statement);
499 ret->statement = NULL;
500 return GNUNET_SYSERR;
502 ret->valid = GNUNET_YES;
507 * Bind the parameters for the given MySQL statement
510 * @param s statement to bind and run
511 * @param ap arguments for the binding
512 * @return GNUNET_SYSERR on error, GNUNET_OK on success
515 init_params (struct StatementHandle *s, va_list ap)
517 MYSQL_BIND qbind[MAX_PARAM];
520 enum enum_field_types ft;
522 pc = mysql_stmt_param_count (s->statement);
525 /* increase internal constant! */
527 return GNUNET_SYSERR;
529 memset (qbind, 0, sizeof (qbind));
532 while ((pc > 0) && (-1 != (ft = va_arg (ap, enum enum_field_types))))
534 qbind[off].buffer_type = ft;
537 case MYSQL_TYPE_FLOAT:
538 qbind[off].buffer = va_arg (ap, float *);
540 case MYSQL_TYPE_LONGLONG:
541 qbind[off].buffer = va_arg (ap, unsigned long long *);
542 qbind[off].is_unsigned = va_arg (ap, int);
544 case MYSQL_TYPE_LONG:
545 qbind[off].buffer = va_arg (ap, unsigned int *);
546 qbind[off].is_unsigned = va_arg (ap, int);
548 case MYSQL_TYPE_VAR_STRING:
549 case MYSQL_TYPE_STRING:
550 case MYSQL_TYPE_BLOB:
551 qbind[off].buffer = va_arg (ap, void *);
552 qbind[off].buffer_length = va_arg (ap, unsigned long);
553 qbind[off].length = va_arg (ap, unsigned long *);
556 /* unsupported type */
558 return GNUNET_SYSERR;
563 if (!((pc == 0) && (ft != -1) && (va_arg (ap, int) == -1)))
566 return GNUNET_SYSERR;
568 if (mysql_stmt_bind_param (s->statement, qbind))
570 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
571 _("`%s' failed at %s:%d with error: %s\n"),
572 "mysql_stmt_bind_param",
573 __FILE__, __LINE__, mysql_stmt_error (s->statement));
574 return GNUNET_SYSERR;
577 if (mysql_stmt_execute (s->statement))
579 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
580 _("`%s' failed at %s:%d with error: %s\n"),
581 "mysql_stmt_execute",
582 __FILE__, __LINE__, mysql_stmt_error (s->statement));
583 return GNUNET_SYSERR;
590 * Run a prepared SELECT statement.
592 * @param s handle to the statement we should execute
593 * @param result_size number of results in set
594 * @param results pointer to already initialized MYSQL_BIND
595 * array (of sufficient size) for passing results
596 * @param processor function to call on each result
597 * @param processor_cls extra argument to processor
598 * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
599 * values (size + buffer-reference for pointers); terminated
602 * @return GNUNET_SYSERR on error, otherwise
603 * the number of successfully affected (or queried) rows
606 prepared_statement_run_select (struct StatementHandle *s,
607 unsigned int result_size,
608 MYSQL_BIND * results,
609 GNUNET_MysqlDataProcessor
610 processor, void *processor_cls,
618 if (GNUNET_OK != prepare_statement (s))
621 return GNUNET_SYSERR;
623 va_start (ap, processor_cls);
624 if (GNUNET_OK != init_params (s, ap))
628 return GNUNET_SYSERR;
631 rsize = mysql_stmt_field_count (s->statement);
632 if (rsize > result_size)
635 return GNUNET_SYSERR;
637 if (mysql_stmt_bind_result (s->statement, results))
639 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
640 _("`%s' failed at %s:%d with error: %s\n"),
641 "mysql_stmt_bind_result",
642 __FILE__, __LINE__, mysql_stmt_error (s->statement));
643 return GNUNET_SYSERR;
649 ret = mysql_stmt_fetch (s->statement);
650 if (ret == MYSQL_NO_DATA)
654 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
655 _("`%s' failed at %s:%d with error: %s\n"),
657 __FILE__, __LINE__, mysql_stmt_error (s->statement));
658 return GNUNET_SYSERR;
660 if (processor != NULL)
661 if (GNUNET_OK != processor (processor_cls, rsize, results))
665 mysql_stmt_reset (s->statement);
671 get_node_uid (unsigned long long *nodeuid, const GNUNET_HashCode * peerHash)
674 struct GNUNET_CRYPTO_HashAsciiEncoded encPeer;
675 unsigned long long p_len;
678 memset (rbind, 0, sizeof (rbind));
679 rbind[0].buffer_type = MYSQL_TYPE_LONGLONG;
680 rbind[0].buffer = nodeuid;
681 rbind[0].is_unsigned = GNUNET_YES;
683 GNUNET_CRYPTO_hash_to_enc (peerHash, &encPeer);
684 p_len = strlen ((char *) &encPeer);
686 if (1 != (ret = prepared_statement_run_select (get_nodeuid,
694 MYSQL_TYPE_VAR_STRING,
700 fprintf (stderr, "FAILED\n");
702 return GNUNET_SYSERR;
708 get_current_trial (unsigned long long *trialuid)
712 memset (rbind, 0, sizeof (rbind));
713 rbind[0].buffer_type = MYSQL_TYPE_LONG;
714 rbind[0].is_unsigned = 1;
715 rbind[0].buffer = trialuid;
718 prepared_statement_run_select (get_trial,
721 return_ok, NULL, -1)))
723 return GNUNET_SYSERR;
730 get_current_topology (unsigned long long *topologyuid)
734 memset (rbind, 0, sizeof (rbind));
735 rbind[0].buffer_type = MYSQL_TYPE_LONGLONG;
736 rbind[0].is_unsigned = 1;
737 rbind[0].buffer = topologyuid;
740 prepared_statement_run_select (get_topology,
743 return_ok, NULL, -1)))
745 return GNUNET_SYSERR;
752 get_dhtkey_uid (unsigned long long *dhtkeyuid, const GNUNET_HashCode * key)
755 struct GNUNET_CRYPTO_HashAsciiEncoded encKey;
756 unsigned long long k_len;
757 memset (rbind, 0, sizeof (rbind));
758 rbind[0].buffer_type = MYSQL_TYPE_LONG;
759 rbind[0].is_unsigned = 1;
760 rbind[0].buffer = dhtkeyuid;
761 GNUNET_CRYPTO_hash_to_enc (key, &encKey);
762 k_len = strlen ((char *) &encKey);
764 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Searching for dhtkey `%s' in trial %llu\n", GNUNET_h2s(key), current_trial);
767 prepared_statement_run_select (get_dhtkeyuid,
771 MYSQL_TYPE_VAR_STRING,
779 return GNUNET_SYSERR;
786 * Run a prepared statement that does NOT produce results.
788 * @param s handle to the statement we should execute
789 * @param insert_id NULL or address where to store the row ID of whatever
790 * was inserted (only for INSERT statements!)
791 * @param ... pairs and triplets of "MYSQL_TYPE_XXX" keys and their respective
792 * values (size + buffer-reference for pointers); terminated
795 * @return GNUNET_SYSERR on error, otherwise
796 * the number of successfully affected rows
799 prepared_statement_run (struct StatementHandle *s,
800 unsigned long long *insert_id, ...)
805 if (GNUNET_OK != prepare_statement(s))
808 return GNUNET_SYSERR;
810 GNUNET_assert(s->valid == GNUNET_YES);
811 if (s->statement == NULL)
812 return GNUNET_SYSERR;
814 va_start (ap, insert_id);
816 if (GNUNET_OK != init_params (s, ap))
819 return GNUNET_SYSERR;
823 affected = mysql_stmt_affected_rows (s->statement);
824 if (NULL != insert_id)
825 *insert_id = (unsigned long long) mysql_stmt_insert_id (s->statement);
826 mysql_stmt_reset (s->statement);
832 * Inserts the specified trial into the dhttests.trials table
834 * @param trial_info struct containing the data to insert about this trial
836 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
838 int add_trial (struct GNUNET_DHTLOG_TrialInfo *trial_info)
842 unsigned long long m_len;
843 m_len = strlen (trial_info->message);
845 stmt = mysql_stmt_init(conn);
847 (ret = prepared_statement_run (insert_trial, &trial_info->trialuid,
848 MYSQL_TYPE_LONG, &trial_info->other_identifier, GNUNET_YES,
849 MYSQL_TYPE_LONG, &trial_info->num_nodes, GNUNET_YES,
850 MYSQL_TYPE_LONG, &trial_info->topology, GNUNET_YES,
851 MYSQL_TYPE_FLOAT, &trial_info->topology_percentage,
852 MYSQL_TYPE_FLOAT, &trial_info->topology_probability,
853 MYSQL_TYPE_LONG, &trial_info->blacklist_topology, GNUNET_YES,
854 MYSQL_TYPE_LONG, &trial_info->connect_topology, GNUNET_YES,
855 MYSQL_TYPE_LONG, &trial_info->connect_topology_option, GNUNET_YES,
856 MYSQL_TYPE_FLOAT, &trial_info->connect_topology_option_modifier,
857 MYSQL_TYPE_LONG, &trial_info->puts, GNUNET_YES,
858 MYSQL_TYPE_LONG, &trial_info->gets, GNUNET_YES,
859 MYSQL_TYPE_LONG, &trial_info->concurrent, GNUNET_YES,
860 MYSQL_TYPE_LONG, &trial_info->settle_time, GNUNET_YES,
861 MYSQL_TYPE_LONG, &trial_info->num_rounds, GNUNET_YES,
862 MYSQL_TYPE_LONG, &trial_info->malicious_getters, GNUNET_YES,
863 MYSQL_TYPE_LONG, &trial_info->malicious_putters, GNUNET_YES,
864 MYSQL_TYPE_LONG, &trial_info->malicious_droppers, GNUNET_YES,
865 MYSQL_TYPE_LONG, &trial_info->malicious_get_frequency, GNUNET_YES,
866 MYSQL_TYPE_LONG, &trial_info->malicious_put_frequency, GNUNET_YES,
867 MYSQL_TYPE_LONG, &trial_info->stop_closest, GNUNET_YES,
868 MYSQL_TYPE_LONG, &trial_info->stop_found, GNUNET_YES,
869 MYSQL_TYPE_LONG, &trial_info->strict_kademlia, GNUNET_YES,
870 MYSQL_TYPE_LONG, &trial_info->gets_succeeded, GNUNET_YES,
871 MYSQL_TYPE_BLOB, trial_info->message, max_varchar_len +
872 max_varchar_len, &m_len,
875 if (ret == GNUNET_SYSERR)
877 mysql_stmt_close(stmt);
878 return GNUNET_SYSERR;
882 get_current_trial (¤t_trial);
884 mysql_stmt_close(stmt);
890 * Inserts the specified stats into the dhttests.node_statistics table
892 * @param peer the peer inserting the statistic
893 * @param route_requests route requests seen
894 * @param route_forwards route requests forwarded
895 * @param result_requests route result requests seen
896 * @param client_requests client requests initiated
897 * @param result_forwards route results forwarded
898 * @param gets get requests handled
899 * @param puts put requests handle
900 * @param data_inserts data inserted at this node
901 * @param find_peer_requests find peer requests seen
902 * @param find_peers_started find peer requests initiated at this node
903 * @param gets_started get requests initiated at this node
904 * @param puts_started put requests initiated at this node
905 * @param find_peer_responses_received find peer responses received locally
906 * @param get_responses_received get responses received locally
907 * @param find_peer_responses_sent find peer responses sent from this node
908 * @param get_responses_sent get responses sent from this node
910 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
913 add_stat (const struct GNUNET_PeerIdentity *peer, unsigned int route_requests,
914 unsigned int route_forwards, unsigned int result_requests,
915 unsigned int client_requests, unsigned int result_forwards,
916 unsigned int gets, unsigned int puts,
917 unsigned int data_inserts, unsigned int find_peer_requests,
918 unsigned int find_peers_started, unsigned int gets_started,
919 unsigned int puts_started, unsigned int find_peer_responses_received,
920 unsigned int get_responses_received, unsigned int find_peer_responses_sent,
921 unsigned int get_responses_sent)
925 unsigned long long peer_uid;
926 unsigned long long return_uid;
928 return GNUNET_SYSERR;
930 if (GNUNET_OK != get_node_uid (&peer_uid, &peer->hashPubKey))
932 return GNUNET_SYSERR;
935 stmt = mysql_stmt_init(conn);
937 (ret = prepared_statement_run (insert_stat,
939 MYSQL_TYPE_LONGLONG, ¤t_trial, GNUNET_YES,
940 MYSQL_TYPE_LONGLONG, &peer_uid, GNUNET_YES,
941 MYSQL_TYPE_LONG, &route_requests, GNUNET_YES,
942 MYSQL_TYPE_LONG, &route_forwards, GNUNET_YES,
943 MYSQL_TYPE_LONG, &result_requests, GNUNET_YES,
944 MYSQL_TYPE_LONG, &client_requests, GNUNET_YES,
945 MYSQL_TYPE_LONG, &result_forwards, GNUNET_YES,
946 MYSQL_TYPE_LONG, &gets, GNUNET_YES,
947 MYSQL_TYPE_LONG, &puts, GNUNET_YES,
948 MYSQL_TYPE_LONG, &data_inserts, GNUNET_YES,
949 MYSQL_TYPE_LONG, &find_peer_requests, GNUNET_YES,
950 MYSQL_TYPE_LONG, &find_peers_started, GNUNET_YES,
951 MYSQL_TYPE_LONG, &gets_started, GNUNET_YES,
952 MYSQL_TYPE_LONG, &puts_started, GNUNET_YES,
953 MYSQL_TYPE_LONG, &find_peer_responses_received, GNUNET_YES,
954 MYSQL_TYPE_LONG, &get_responses_received, GNUNET_YES,
955 MYSQL_TYPE_LONG, &find_peer_responses_sent, GNUNET_YES,
956 MYSQL_TYPE_LONG, &get_responses_sent, GNUNET_YES,
959 if (ret == GNUNET_SYSERR)
961 mysql_stmt_close(stmt);
962 return GNUNET_SYSERR;
966 mysql_stmt_close(stmt);
971 * Inserts the specified stats into the dhttests.generic_stats table
973 * @param peer the peer inserting the statistic
974 * @param name the name of the statistic
975 * @param section the section of the statistic
976 * @param value the value of the statistic
978 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
981 add_generic_stat (const struct GNUNET_PeerIdentity *peer,
983 const char *section, uint64_t value)
985 unsigned long long peer_uid;
986 unsigned long long section_len;
987 unsigned long long name_len;
990 return GNUNET_SYSERR;
992 if (GNUNET_OK != get_node_uid (&peer_uid, &peer->hashPubKey))
994 return GNUNET_SYSERR;
997 section_len = strlen(section);
998 name_len = strlen(name);
1001 (ret = prepared_statement_run (insert_generic_stat,
1003 MYSQL_TYPE_LONGLONG, ¤t_trial, GNUNET_YES,
1004 MYSQL_TYPE_LONGLONG, &peer_uid, GNUNET_YES,
1005 MYSQL_TYPE_VAR_STRING, §ion, max_varchar_len, §ion_len,
1006 MYSQL_TYPE_VAR_STRING, &name, max_varchar_len, &name_len,
1007 MYSQL_TYPE_LONGLONG, &value, GNUNET_YES,
1010 if (ret == GNUNET_SYSERR)
1012 return GNUNET_SYSERR;
1019 * Inserts the specified dhtkey into the dhttests.dhtkeys table,
1020 * stores return value of dhttests.dhtkeys.dhtkeyuid into dhtkeyuid
1022 * @param dhtkeyuid return value
1023 * @param dhtkey hashcode of key to insert
1025 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1028 add_dhtkey (unsigned long long *dhtkeyuid, const GNUNET_HashCode * dhtkey)
1032 struct GNUNET_CRYPTO_HashAsciiEncoded encKey;
1033 unsigned long long k_len;
1034 unsigned long long h_len;
1035 unsigned long long curr_dhtkeyuid;
1036 GNUNET_CRYPTO_hash_to_enc (dhtkey, &encKey);
1037 k_len = strlen ((char *) &encKey);
1038 h_len = sizeof (GNUNET_HashCode);
1040 ret = get_dhtkey_uid(&curr_dhtkeyuid, dhtkey);
1041 if (curr_dhtkeyuid != 0) /* dhtkey already exists */
1043 if (dhtkeyuid != NULL)
1044 *dhtkeyuid = curr_dhtkeyuid;
1047 else if (ret == GNUNET_SYSERR)
1050 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Failed to get dhtkeyuid!\n");
1055 (ret = prepared_statement_run (insert_dhtkey,
1057 MYSQL_TYPE_VAR_STRING,
1066 sizeof (GNUNET_HashCode),
1069 if (ret == GNUNET_SYSERR)
1071 return GNUNET_SYSERR;
1081 * Inserts the specified node into the dhttests.nodes table
1083 * @param nodeuid the inserted node uid
1084 * @param node the node to insert
1086 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1089 add_node (unsigned long long *nodeuid, struct GNUNET_PeerIdentity * node)
1091 struct GNUNET_CRYPTO_HashAsciiEncoded encPeer;
1092 unsigned long p_len;
1093 unsigned long h_len;
1097 return GNUNET_SYSERR;
1099 GNUNET_CRYPTO_hash_to_enc (&node->hashPubKey, &encPeer);
1100 p_len = (unsigned long) strlen ((char *) &encPeer);
1101 h_len = sizeof (GNUNET_HashCode);
1103 (ret = prepared_statement_run (insert_node,
1105 MYSQL_TYPE_LONGLONG, ¤t_trial, GNUNET_YES,
1106 MYSQL_TYPE_VAR_STRING, &encPeer, max_varchar_len, &p_len,
1107 MYSQL_TYPE_BLOB, &node->hashPubKey, sizeof (GNUNET_HashCode),
1110 if (ret == GNUNET_SYSERR)
1112 return GNUNET_SYSERR;
1119 * Update dhttests.trials table with current server time as end time
1121 * @param trialuid trial to update
1122 * @param gets_succeeded how many gets did the testcase report as successful
1124 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1127 update_trials (unsigned long long trialuid,
1128 unsigned int gets_succeeded)
1133 (ret = prepared_statement_run (update_trial,
1135 MYSQL_TYPE_LONG, &gets_succeeded, GNUNET_YES,
1136 MYSQL_TYPE_LONGLONG, &trialuid, GNUNET_YES,
1139 if (ret == GNUNET_SYSERR)
1141 return GNUNET_SYSERR;
1147 return GNUNET_SYSERR;
1152 * Update dhttests.nodes table setting the identified
1153 * node as a malicious dropper.
1155 * @param peer the peer that was set to be malicious
1157 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1159 int set_malicious (struct GNUNET_PeerIdentity *peer)
1161 unsigned long long p_len;
1165 temp_str = GNUNET_strdup(GNUNET_h2s_full(&peer->hashPubKey));
1166 p_len = strlen(temp_str);
1169 (ret = prepared_statement_run (update_node_malicious,
1171 MYSQL_TYPE_LONGLONG, ¤t_trial, GNUNET_YES,
1172 MYSQL_TYPE_VAR_STRING, temp_str, max_varchar_len, &p_len,
1175 if (ret == GNUNET_SYSERR)
1177 return GNUNET_SYSERR;
1185 * Update dhttests.trials table with total connections information
1187 * @param trialuid the trialuid to update
1188 * @param totalConnections the number of connections
1190 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1193 add_connections (unsigned long long trialuid, unsigned int totalConnections)
1198 (ret = prepared_statement_run (update_connection,
1203 MYSQL_TYPE_LONGLONG,
1204 &trialuid, GNUNET_YES, -1)))
1206 if (ret == GNUNET_SYSERR)
1208 return GNUNET_SYSERR;
1214 return GNUNET_SYSERR;
1218 * Inserts the specified query into the dhttests.queries table
1220 * @param sqlqueruid inserted query uid
1221 * @param queryid dht query id
1222 * @param type type of the query
1223 * @param hops number of hops query traveled
1224 * @param succeeded whether or not query was successful
1225 * @param node the node the query hit
1226 * @param key the key of the query
1228 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1231 add_query (unsigned long long *sqlqueryuid, unsigned long long queryid,
1232 unsigned int type, unsigned int hops, int succeeded,
1233 const struct GNUNET_PeerIdentity * node, const GNUNET_HashCode * key)
1236 unsigned long long peer_uid, key_uid;
1241 && (GNUNET_OK == get_node_uid (&peer_uid, &node->hashPubKey)))
1247 return GNUNET_SYSERR;
1250 if ((key != NULL) && (GNUNET_OK == get_dhtkey_uid (&key_uid, key)))
1254 else if ((key != NULL) && (key->bits[(512 / 8 / sizeof (unsigned int)) - 1] == 42)) /* Malicious marker */
1260 return GNUNET_SYSERR;
1264 (ret = prepared_statement_run (insert_query,
1266 MYSQL_TYPE_LONGLONG,
1275 MYSQL_TYPE_LONGLONG,
1278 MYSQL_TYPE_LONGLONG,
1284 MYSQL_TYPE_LONGLONG,
1285 &peer_uid, GNUNET_YES, -1)))
1287 if (ret == GNUNET_SYSERR)
1289 return GNUNET_SYSERR;
1295 return GNUNET_SYSERR;
1299 * Inserts the specified route information into the dhttests.routes table
1301 * @param sqlqueruid inserted query uid
1302 * @param queryid dht query id
1303 * @param type type of the query
1304 * @param hops number of hops query traveled
1305 * @param succeeded whether or not query was successful
1306 * @param node the node the query hit
1307 * @param key the key of the query
1308 * @param from_node the node that sent the message to node
1309 * @param to_node next node to forward message to
1311 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1314 add_route (unsigned long long *sqlqueryuid, unsigned long long queryid,
1315 unsigned int type, unsigned int hops,
1316 int succeeded, const struct GNUNET_PeerIdentity * node,
1317 const GNUNET_HashCode * key, const struct GNUNET_PeerIdentity * from_node,
1318 const struct GNUNET_PeerIdentity * to_node)
1320 unsigned long long peer_uid = 0;
1321 unsigned long long key_uid = 0;
1322 unsigned long long from_uid = 0;
1323 unsigned long long to_uid = 0;
1326 if (from_node != NULL)
1327 get_node_uid (&from_uid, &from_node->hashPubKey);
1331 if (to_node != NULL)
1332 get_node_uid (&to_uid, &to_node->hashPubKey);
1338 if (1 != get_node_uid (&peer_uid, &node->hashPubKey))
1340 return GNUNET_SYSERR;
1344 return GNUNET_SYSERR;
1348 if (1 != get_dhtkey_uid (&key_uid, key))
1350 return GNUNET_SYSERR;
1354 return GNUNET_SYSERR;
1357 (ret = prepared_statement_run (insert_route,
1359 MYSQL_TYPE_LONGLONG,
1368 MYSQL_TYPE_LONGLONG,
1371 MYSQL_TYPE_LONGLONG,
1377 MYSQL_TYPE_LONGLONG,
1380 MYSQL_TYPE_LONGLONG,
1383 MYSQL_TYPE_LONGLONG,
1384 &to_uid, GNUNET_YES, -1)))
1386 if (ret == GNUNET_SYSERR)
1388 return GNUNET_SYSERR;
1394 return GNUNET_SYSERR;
1398 * Update dhttests.topology table with total connections information
1400 * @param totalConnections the number of connections
1402 * @return GNUNET_OK on success, GNUNET_SYSERR on failure.
1405 update_current_topology (unsigned int connections)
1408 unsigned long long topologyuid;
1410 get_current_topology(&topologyuid);
1413 (ret = prepared_statement_run (update_topology,
1418 MYSQL_TYPE_LONGLONG,
1419 &topologyuid, GNUNET_YES, -1)))
1421 if (ret == GNUNET_SYSERR)
1423 return GNUNET_SYSERR;
1429 return GNUNET_SYSERR;
1434 * Records the current topology (number of connections, time, trial)
1436 * @param num_connections how many connections are in the topology
1438 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1441 add_topology (int num_connections)
1446 (ret = prepared_statement_run (insert_topology,
1448 MYSQL_TYPE_LONGLONG,
1455 if (ret == GNUNET_SYSERR)
1457 return GNUNET_SYSERR;
1463 return GNUNET_SYSERR;
1468 * Records a connection between two peers in the current topology
1470 * @param first one side of the connection
1471 * @param second other side of the connection
1473 * @return GNUNET_OK on success, GNUNET_SYSERR on failure
1476 add_extended_topology (const struct GNUNET_PeerIdentity *first, const struct GNUNET_PeerIdentity *second)
1479 unsigned long long first_uid;
1480 unsigned long long second_uid;
1481 unsigned long long topologyuid;
1483 if (GNUNET_OK != get_current_topology(&topologyuid))
1484 return GNUNET_SYSERR;
1485 if (GNUNET_OK != get_node_uid(&first_uid, &first->hashPubKey))
1486 return GNUNET_SYSERR;
1487 if (GNUNET_OK != get_node_uid(&second_uid, &second->hashPubKey))
1488 return GNUNET_SYSERR;
1491 (ret = prepared_statement_run (extend_topology,
1493 MYSQL_TYPE_LONGLONG,
1496 MYSQL_TYPE_LONGLONG,
1499 MYSQL_TYPE_LONGLONG,
1503 if (ret == GNUNET_SYSERR)
1505 return GNUNET_SYSERR;
1511 return GNUNET_SYSERR;
1517 * Provides the dhtlog api
1519 * @param c the configuration to use to connect to a server
1521 * @return the handle to the server, or NULL on error
1524 libgnunet_plugin_dhtlog_mysql_init (void * cls)
1526 struct GNUNET_DHTLOG_Plugin *plugin = cls;
1529 max_varchar_len = 255;
1531 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MySQL DHT Logger: initializing database\n");
1534 if (iopen (plugin) != GNUNET_OK)
1536 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1537 _("Failed to initialize MySQL database connection for dhtlog.\n"));
1541 GNUNET_assert(plugin->dhtlog_api == NULL);
1542 plugin->dhtlog_api = GNUNET_malloc(sizeof(struct GNUNET_DHTLOG_Handle));
1543 plugin->dhtlog_api->insert_trial = &add_trial;
1544 plugin->dhtlog_api->insert_stat = &add_stat;
1545 plugin->dhtlog_api->add_generic_stat = &add_generic_stat;
1546 plugin->dhtlog_api->insert_query = &add_query;
1547 plugin->dhtlog_api->update_trial = &update_trials;
1548 plugin->dhtlog_api->insert_route = &add_route;
1549 plugin->dhtlog_api->insert_node = &add_node;
1550 plugin->dhtlog_api->insert_dhtkey = &add_dhtkey;
1551 plugin->dhtlog_api->update_connections = &add_connections;
1552 plugin->dhtlog_api->insert_topology = &add_topology;
1553 plugin->dhtlog_api->update_topology = &update_current_topology;
1554 plugin->dhtlog_api->insert_extended_topology = &add_extended_topology;
1555 plugin->dhtlog_api->set_malicious = &set_malicious;
1556 plugin->dhtlog_api->add_generic_stat = &add_generic_stat;
1557 get_current_trial (¤t_trial);
1563 * Shutdown the plugin.
1566 libgnunet_plugin_dhtlog_mysql_done (void * cls)
1568 struct GNUNET_DHTLOG_Handle *dhtlog_api = cls;
1570 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1571 "MySQL DHT Logger: database shutdown\n");
1572 GNUNET_assert(dhtlog_api != NULL);
1573 prepared_statement_close(insert_query);
1574 prepared_statement_close(insert_route);
1575 prepared_statement_close(insert_trial);
1576 prepared_statement_close(insert_node);
1577 prepared_statement_close(insert_dhtkey);
1578 prepared_statement_close(update_trial);
1579 prepared_statement_close(get_dhtkeyuid);
1580 prepared_statement_close(get_nodeuid);
1581 prepared_statement_close(update_connection);
1582 prepared_statement_close(get_trial);
1583 prepared_statement_close(get_topology);
1584 prepared_statement_close(insert_topology);
1585 prepared_statement_close(update_topology);
1586 prepared_statement_close(extend_topology);
1587 prepared_statement_close(update_node_malicious);
1592 mysql_library_end();
1593 GNUNET_free(dhtlog_api);
1597 /* end of plugin_dhtlog_mysql.c */